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