ARM debugging with the simulator

The simulator and debugger can be very helpful when working with v8 code generation.

Please note that this simulator is designed for v8 purposes. Only the features used by v8 are implemented, and you might encounter unimplemented features or instructions. In this case, feel free to implement them and submit the code!

Details on the ARM debugger

Compile the ARM simulator shell with:

make arm.debug

…on an x86 host using your regular compiler.

Starting the debugger

There are different ways of starting the debugger:

out/arm.debug/d8 --stop_sim_at <n>

The simulator starts the debugger after executing n instructions.

out/arm.debug/d8 --stop_at <function name>

The simulator stops at the given JavaScript function.

Also you can directly generate 'stop' instructions in the ARM code. Stops are generated with

Assembler::stop(const char* msg, Condition cond, int32_t code)

When the simulator hits a stop, it prints msg and starts the debugger.

Debugging commands

Usual commands

Enter help in the debugger prompt to get details on available commands. These include usual gdb-like commands, such as stepi, cont, disasm, etc. If the Simulator is run under gdb, the “gdb” debugger command will give control to gdb. You can then use cont from gdb to go back to the debugger.

Debugger-specific commands

Here's a list of the ARM debugger-specific commands, along with examples.
The JavaScript file func.js used below contains:

function test() {
print('In function test.');
}
test();

The first argument is a help message, the second is the condition, and the third is the stop code. If a code is specified, and is less than 256, the stop is said to be “watched”, and can be disabled/enabled; a counter also keeps track of how many times the Simulator hits this code.

Imagine we are working on this V8 C++ code, which is reached when running our JavaScript file.

__ stop("My stop.", al, 123);
__ mov(r0, r0);
__ mov(r0, r0);
__ mov(r0, r0);
__ mov(r0, r0);
__ mov(r0, r0);
__ stop("My second stop.", al, 0x1);
__ mov(r1, r1);
__ mov(r1, r1);
__ mov(r1, r1);
__ mov(r1, r1);
__ mov(r1, r1);

Here's a sample debugging session:

We hit the first stop.

Simulator hit My stop.
  0xb53559e8  e1a00000       mov r0, r0

We can see the following stop using disasm. The address of the message string is inlined in the code after the svc stop instruction.

sim> disasm
  0xb53559e8  e1a00000       mov r0, r0
  0xb53559ec  e1a00000       mov r0, r0
  0xb53559f0  e1a00000       mov r0, r0
  0xb53559f4  e1a00000       mov r0, r0
  0xb53559f8  e1a00000       mov r0, r0
  0xb53559fc  ef800001       stop 1 - 0x1
  0xb5355a00  08338a97       stop message: My second stop
  0xb5355a04  e1a00000       mov r1, r1
  0xb5355a08  e1a00000       mov r1, r1
  0xb5355a0c  e1a00000       mov r1, r1

Information can be printed for all (watched) stops which were hit at least once.

sim> stop info all
Stop information:
stop 123 - 0x7b:      Enabled,      counter = 1,      My stop.
sim> cont
Simulator hit My second stop
  0xb5355a04  e1a00000       mov r1, r1
sim> stop info all
Stop information:
stop 1 - 0x1:         Enabled,      counter = 1,      My second stop
stop 123 - 0x7b:      Enabled,      counter = 1,      My stop.

Stops can be disabled or enabled. (Only available for watched stops.)

sim> stop disable 1
sim> cont
Simulator hit My stop.
  0xb5356808  e1a00000       mov r0, r0
sim> cont
Simulator hit My stop.
  0xb5356c28  e1a00000       mov r0, r0
sim> stop info all
Stop information:
stop 1 - 0x1:         Disabled,     counter = 2,      My second stop
stop 123 - 0x7b:      Enabled,      counter = 3,      My stop.
sim> stop enable 1
sim> cont
Simulator hit My second stop
  0xb5356c44  e1a00000       mov r1, r1
sim> stop disable all
sim> con
In function test.