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