| 1 | # |
| 2 | # Test some of the system debug features with the multiarch memory |
| 3 | # test. It is a port of the original vmlinux focused test case but |
| 4 | # using the "memory" test instead. |
| 5 | # |
| 6 | # This is launched via tests/guest-debug/run-test.py |
| 7 | # |
| 8 | |
| 9 | import gdb |
| 10 | import sys |
| 11 | from test_gdbstub import main, report |
| 12 | |
| 13 | |
| 14 | def check_step(): |
| 15 | "Step an instruction, check it moved." |
| 16 | start_pc = gdb.parse_and_eval('$pc') |
| 17 | gdb.execute("si") |
| 18 | end_pc = gdb.parse_and_eval('$pc') |
| 19 | |
| 20 | return not (start_pc == end_pc) |
| 21 | |
| 22 | |
| 23 | # |
| 24 | # Currently it's hard to create a hbreak with the pure python API and |
| 25 | # manually matching PC to symbol address is a bit flaky thanks to |
| 26 | # function prologues. However internally QEMU's gdbstub treats them |
| 27 | # the same as normal breakpoints so it will do for now. |
| 28 | # |
| 29 | def check_break(sym_name): |
| 30 | "Setup breakpoint, continue and check we stopped." |
| 31 | sym, ok = gdb.lookup_symbol(sym_name) |
| 32 | bp = gdb.Breakpoint(sym_name, gdb.BP_BREAKPOINT) |
| 33 | |
| 34 | gdb.execute("c") |
| 35 | |
| 36 | # hopefully we came back |
| 37 | end_pc = gdb.parse_and_eval('$pc') |
| 38 | report(bp.hit_count == 1, |
| 39 | "break @ %s (%s %d hits)" % (end_pc, sym.value(), bp.hit_count)) |
| 40 | |
| 41 | bp.delete() |
| 42 | |
| 43 | |
| 44 | def do_one_watch(sym, wtype, text): |
| 45 | |
| 46 | wp = gdb.Breakpoint(sym, gdb.BP_WATCHPOINT, wtype) |
| 47 | gdb.execute("c") |
| 48 | report_str = "%s for %s" % (text, sym) |
| 49 | |
| 50 | if wp.hit_count > 0: |
| 51 | report(True, report_str) |
| 52 | wp.delete() |
| 53 | else: |
| 54 | report(False, report_str) |
| 55 | |
| 56 | |
| 57 | def check_watches(sym_name): |
| 58 | "Watch a symbol for any access." |
| 59 | |
| 60 | # Should hit for any read |
| 61 | do_one_watch(sym_name, gdb.WP_ACCESS, "awatch") |
| 62 | |
| 63 | # Again should hit for reads |
| 64 | do_one_watch(sym_name, gdb.WP_READ, "rwatch") |
| 65 | |
| 66 | # Finally when it is written |
| 67 | do_one_watch(sym_name, gdb.WP_WRITE, "watch") |
| 68 | |
| 69 | |
| 70 | def run_test(): |
| 71 | "Run through the tests one by one" |
| 72 | |
| 73 | print("Checking we can step the first few instructions") |
| 74 | step_ok = 0 |
| 75 | for i in range(3): |
| 76 | if check_step(): |
| 77 | step_ok += 1 |
| 78 | |
| 79 | report(step_ok == 3, "single step in boot code") |
| 80 | |
| 81 | # If we get here we have missed some of the other breakpoints. |
| 82 | print("Setup catch-all for _exit") |
| 83 | cbp = gdb.Breakpoint("_exit", gdb.BP_BREAKPOINT) |
| 84 | |
| 85 | check_break("main") |
| 86 | check_watches("test_data[128]") |
| 87 | |
| 88 | report(cbp.hit_count == 0, "didn't reach backstop") |
| 89 | |
| 90 | |
| 91 | main(run_test) |