NOTE: You will have to land this as I don’t have write perms to this repo. BUG=none R=hablich@chromium.org Review URL: https://codereview.chromium.org/1347153006 Cr-Commit-Position: refs/heads/master@{#30972}
5.9 KiB
ARM debugging with the simulator
The simulator and debugger can be very helpful when working with v8 code generation.
- It is convenient as it allows you to test code generation without access to actual hardware.
- No cross or native compilation is needed.
- The simulator fully supports the debugging of generated code.
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 will start the debugger after executing n instructions.
$ out/arm.debug/d8 --stop_at <function name>
The simulator will stop 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 will print msg and start 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();
- printobject
<
register>
(alias po), will describe an object held in a register.
$ out/arm.debug/d8 func.js --stop_at test
Simulator hit stop-at
0xb544d6a8 e92d4902 stmdb sp!, {r1, r8, fp, lr}
sim> print r0
r0: 0xb547ec15 -1253577707
sim> printobject r0
r0:
0xb547ec15: [Function]
- map = 0x0xb540ff01
- initial_map =
- shared_info = 0xb547eb2d <SharedFunctionInfo>
- name = #test
- context = 0xb60083f1 <FixedArray[52]>
- code = 0xb544d681 <Code>
#arguments: 0xb545a15d <Proxy> (callback)
#length: 0xb545a14d <Proxy> (callback)
#name: 0xb545a155 <Proxy> (callback)
#prototype: 0xb545a145 <Proxy> (callback)
#caller: 0xb545a165 <Proxy> (callback)
-
break
<
address>
, will insert a breakpoint at the specified address. -
del, will delete the current breakpoint.
You can have only one such breakpoint. This is useful if you want to insert a breakpoint at runtime.
$ out/arm.debug/d8 func.js --stop_at test
Simulator hit stop-at
0xb53a1ee8 e92d4902 stmdb sp!, {r1, r8, fp, lr}
sim> disasm 5
0xb53a1ee8 e92d4902 stmdb sp!, {r1, r8, fp, lr}
0xb53a1eec e28db008 add fp, sp, #8
0xb53a1ef0 e59a200c ldr r2, [r10, #+12]
0xb53a1ef4 e28fe004 add lr, pc, #4
0xb53a1ef8 e15d0002 cmp sp, r2
sim> break 0xb53a1ef8
sim> cont
0xb53a1ef8 e15d0002 cmp sp, r2
sim> disasm 5
0xb53a1ef8 e15d0002 cmp sp, r2
0xb53a1efc 359ff034 ldrcc pc, [pc, #+52]
0xb53a1f00 e5980017 ldr r0, [r8, #+23]
0xb53a1f04 e59f1030 ldr r1, [pc, #+48]
0xb53a1f08 e52d0004 str r0, [sp, #-4]!
sim> break 0xb53a1f08
setting breakpoint failed
sim> del
sim> break 0xb53a1f08
sim> cont
0xb53a1f08 e52d0004 str r0, [sp, #-4]!
sim> del
sim> cont
In function test.
- Generated
stop
instuctions, will work as breakpoints with a few additional features.
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.
If 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.