1from __future__ import print_function 2# 3# Test some of the softmmu debug features with the multiarch memory 4# test. It is a port of the original vmlinux focused test case but 5# using the "memory" test instead. 6# 7# This is launched via tests/guest-debug/run-test.py 8# 9 10import gdb 11import sys 12 13failcount = 0 14 15 16def report(cond, msg): 17 "Report success/fail of test" 18 if cond: 19 print("PASS: %s" % (msg)) 20 else: 21 print("FAIL: %s" % (msg)) 22 global failcount 23 failcount += 1 24 25 26def check_step(): 27 "Step an instruction, check it moved." 28 start_pc = gdb.parse_and_eval('$pc') 29 gdb.execute("si") 30 end_pc = gdb.parse_and_eval('$pc') 31 32 return not (start_pc == end_pc) 33 34 35# 36# Currently it's hard to create a hbreak with the pure python API and 37# manually matching PC to symbol address is a bit flaky thanks to 38# function prologues. However internally QEMU's gdbstub treats them 39# the same as normal breakpoints so it will do for now. 40# 41def check_break(sym_name): 42 "Setup breakpoint, continue and check we stopped." 43 sym, ok = gdb.lookup_symbol(sym_name) 44 bp = gdb.Breakpoint(sym_name, gdb.BP_BREAKPOINT) 45 46 gdb.execute("c") 47 48 # hopefully we came back 49 end_pc = gdb.parse_and_eval('$pc') 50 report(bp.hit_count == 1, 51 "break @ %s (%s %d hits)" % (end_pc, sym.value(), bp.hit_count)) 52 53 bp.delete() 54 55 56def do_one_watch(sym, wtype, text): 57 58 wp = gdb.Breakpoint(sym, gdb.BP_WATCHPOINT, wtype) 59 gdb.execute("c") 60 report_str = "%s for %s" % (text, sym) 61 62 if wp.hit_count > 0: 63 report(True, report_str) 64 wp.delete() 65 else: 66 report(False, report_str) 67 68 69def check_watches(sym_name): 70 "Watch a symbol for any access." 71 72 # Should hit for any read 73 do_one_watch(sym_name, gdb.WP_ACCESS, "awatch") 74 75 # Again should hit for reads 76 do_one_watch(sym_name, gdb.WP_READ, "rwatch") 77 78 # Finally when it is written 79 do_one_watch(sym_name, gdb.WP_WRITE, "watch") 80 81 82def run_test(): 83 "Run through the tests one by one" 84 85 print("Checking we can step the first few instructions") 86 step_ok = 0 87 for i in range(3): 88 if check_step(): 89 step_ok += 1 90 91 report(step_ok == 3, "single step in boot code") 92 93 # If we get here we have missed some of the other breakpoints. 94 print("Setup catch-all for _exit") 95 cbp = gdb.Breakpoint("_exit", gdb.BP_BREAKPOINT) 96 97 check_break("main") 98 check_watches("test_data[128]") 99 100 report(cbp.hit_count == 0, "didn't reach backstop") 101 102# 103# This runs as the script it sourced (via -x, via run-test.py) 104# 105try: 106 inferior = gdb.selected_inferior() 107 arch = inferior.architecture() 108 print("ATTACHED: %s" % arch.name()) 109except (gdb.error, AttributeError): 110 print("SKIPPING (not connected)", file=sys.stderr) 111 exit(0) 112 113if gdb.parse_and_eval('$pc') == 0: 114 print("SKIP: PC not set") 115 exit(0) 116 117try: 118 # These are not very useful in scripts 119 gdb.execute("set pagination off") 120 121 # Run the actual tests 122 run_test() 123except (gdb.error): 124 print("GDB Exception: %s" % (sys.exc_info()[0])) 125 failcount += 1 126 pass 127 128# Finally kill the inferior and exit gdb with a count of failures 129gdb.execute("kill") 130exit(failcount) 131