Posts SpiderMonkey Workflow Setup
Post
Cancel

SpiderMonkey Workflow Setup

I wanted to take a few notes about my SpiderMonkey debugging and code review setup so that this can be a reference for the future me :). This short post will be about that only.

Code Review

My favorite editor is Atom and I use the ccls language-server to go through the source code. Some atom packages I use -

  • atom-ide-ccls: language-client for ccls
  • cursor-history: To easily navigate back to the original position after looking up a (say) function definition.
  • hyperclick: For jumping to definitions

I use bear to generate the compilation database for ccls. Thus doing a bear make while compiling the code generates the compilation database (in compile_commands.json)

1
2
3
4
5
6
7
cd js/src/
cp configure.in configure && autoconf2.13
mkdir build_debug.OBJ
cd build_debug.OBJ
../configure --enable-debug --enable-optimize --enable-ion
bear make -j4
cd dist/bin/

The generated compilation database should be placed in the root folder of the project, and the text editor should be started from this root folder. It takes some time (and a lot of CPU usage) for ccls to index the whole code, but once it’s done it makes code navigation a whole lot easier.

I usually have one debug (in build_debug.OBJ) and one non-debug build (in build_nondebug.OBJ). I use the non-debug build while building and testing the exploit as sometimes assertions in the debug build break the exploit. For the non-debug build just use ../configure --disable-debug --enable-optimize --enable-ion.

Debugging

For debugging, I use gdb with gef. Also, this nice article on MDN docs about SpiderMonkey debugging tips is pretty useful.

While trying to set a breakpoint in JIT compiled code, using the method method mentioned in the MDN page, I got the message saying that the masm.breakpoint has been ‘optimized out’. I guess it got inlined by gcc. So what I did was to place breakpoint on a function that was going to be inlined.

For eg,

1
2
3
4
5
6
7
8
9
10
11
array = [1,2,3,4,5,6]

function test(){
  if (array.length == 0)
    array[3]=1
  const value = array.pop();
  for (let y = 0; y < 10000; y++) {}  // JIT compile this function
  return value+0x1234;
}

for (let i=0; i< 100; i++) test()

While JIT compiling this and generating the code for calling Array.pop, js::jit::CodeGenerator::visitArrayPopShiftT function is called.

1
2
3
4
5
6
7
8
9
void
CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir)
{
    Register obj = ToRegister(lir->object());
    Register elements = ToRegister(lir->temp0());
    Register length = ToRegister(lir->temp1());
    TypedOrValueRegister out(lir->mir()->type(), ToAnyRegister(lir->output()));
    emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
}

This is calling emitArrayPopShift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void
CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
                                 Register elementsTemp, Register lengthTemp, TypedOrValueRegister out)
{
    OutOfLineCode* ool;

    if (mir->mode() == MArrayPopShift::Pop) {
        ool = oolCallVM(ArrayPopDenseInfo, lir, ArgList(obj), StoreValueTo(out));
    } else {
        MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
        ool = oolCallVM(ArrayShiftDenseInfo, lir, ArgList(obj), StoreValueTo(out));
    }
  :
  :
}

Now this is basically emiting code that calls a VM function js::jit::ArrayPopDense. Thus we can set a breakpoint here. and then hit fin in gdb to continue execution till the end of this function. Here is a backtrace when this breakpoint is hit

The code at address 0x3ff959cc1f1c is the one generated by Ion. Thus we just hit fin and the control stops when it starts executing the Ion code and we can now step through Ion code.

Thus for stepping through Ion generated code, I usually put a call to some function (like Array.pop, slice, push etc) that calls a VM function in the Ion code.

I’ll keep updating this post whenever I come across new stuff related to code review/debugging as these act as notes for the future :)

This post is licensed under CC BY 4.0 by the author.