summaryrefslogtreecommitdiffstats
path: root/tests/guest-debug/test-gdbstub.py
blob: 98a5df4d4241b92316b363870e2f7b223ed9e1d4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#
# This script needs to be run on startup
# qemu -kernel ${KERNEL} -s -S
# and then:
# gdb ${KERNEL}.vmlinux -x ${QEMU_SRC}/tests/guest-debug/test-gdbstub.py

import gdb

failcount = 0


def report(cond, msg):
    "Report success/fail of test"
    if cond:
        print ("PASS: %s" % (msg))
    else:
        print ("FAIL: %s" % (msg))
        global failcount
        failcount += 1


def check_step():
    "Step an instruction, check it moved."
    start_pc = gdb.parse_and_eval('$pc')
    gdb.execute("si")
    end_pc = gdb.parse_and_eval('$pc')

    return not (start_pc == end_pc)


def check_break(sym_name):
    "Setup breakpoint, continue and check we stopped."
    sym, ok = gdb.lookup_symbol(sym_name)
    bp = gdb.Breakpoint(sym_name)

    gdb.execute("c")

    # hopefully we came back
    end_pc = gdb.parse_and_eval('$pc')
    print ("%s == %s %d" % (end_pc, sym.value(), bp.hit_count))
    bp.delete()

    # can we test we hit bp?
    return end_pc == sym.value()


# We need to do hbreak manually as the python interface doesn't export it
def check_hbreak(sym_name):
    "Setup hardware breakpoint, continue and check we stopped."
    sym, ok = gdb.lookup_symbol(sym_name)
    gdb.execute("hbreak %s" % (sym_name))
    gdb.execute("c")

    # hopefully we came back
    end_pc = gdb.parse_and_eval('$pc')
    print ("%s == %s" % (end_pc, sym.value()))

    if end_pc == sym.value():
        gdb.execute("d 1")
        return True
    else:
        return False


class WatchPoint(gdb.Breakpoint):

    def get_wpstr(self, sym_name):
        "Setup sym and wp_str for given symbol."
        self.sym, ok = gdb.lookup_symbol(sym_name)
        wp_addr = gdb.parse_and_eval(sym_name).address
        self.wp_str = '*(%(type)s)(&%(address)s)' % dict(
            type = wp_addr.type, address = sym_name)

        return(self.wp_str)

    def __init__(self, sym_name, type):
        wp_str = self.get_wpstr(sym_name)
        super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type)

    def stop(self):
        end_pc = gdb.parse_and_eval('$pc')
        print ("HIT WP @ %s" % (end_pc))
        return True


def do_one_watch(sym, wtype, text):

    wp = WatchPoint(sym, wtype)
    gdb.execute("c")
    report_str = "%s for %s (%s)" % (text, sym, wp.sym.value())

    if wp.hit_count > 0:
        report(True, report_str)
        wp.delete()
    else:
        report(False, report_str)


def check_watches(sym_name):
    "Watch a symbol for any access."

    # Should hit for any read
    do_one_watch(sym_name, gdb.WP_ACCESS, "awatch")

    # Again should hit for reads
    do_one_watch(sym_name, gdb.WP_READ, "rwatch")

    # Finally when it is written
    do_one_watch(sym_name, gdb.WP_WRITE, "watch")


class CatchBreakpoint(gdb.Breakpoint):
    def __init__(self, sym_name):
        super(CatchBreakpoint, self).__init__(sym_name)
        self.sym, ok = gdb.lookup_symbol(sym_name)

    def stop(self):
        end_pc = gdb.parse_and_eval('$pc')
        print ("CB: %s == %s" % (end_pc, self.sym.value()))
        if end_pc == self.sym.value():
            report(False, "Hit final catchpoint")


def run_test():
    "Run through the tests one by one"

    print ("Checking we can step the first few instructions")
    step_ok = 0
    for i in range(3):
        if check_step():
            step_ok += 1

    report(step_ok == 3, "single step in boot code")

    print ("Checking HW breakpoint works")
    break_ok = check_hbreak("kernel_init")
    report(break_ok, "hbreak @ kernel_init")

    # Can't set this up until we are in the kernel proper
    # if we make it to run_init_process we've over-run and
    # one of the tests failed
    print ("Setup catch-all for run_init_process")
    cbp = CatchBreakpoint("run_init_process")
    cpb2 = CatchBreakpoint("try_to_run_init_process")

    print ("Checking Normal breakpoint works")
    break_ok = check_break("wait_for_completion")
    report(break_ok, "break @ wait_for_completion")

    print ("Checking watchpoint works")
    check_watches("system_state")

#
# This runs as the script it sourced (via -x)
#

try:
    print ("Connecting to remote")
    gdb.execute("target remote localhost:1234")

    # These are not very useful in scripts
    gdb.execute("set pagination off")
    gdb.execute("set confirm off")

    # Run the actual tests
    run_test()

except:
    print ("GDB Exception: %s" % (sys.exc_info()[0]))
    failcount += 1
    import code
    code.InteractiveConsole(locals=globals()).interact()
    raise

# Finally kill the inferior and exit gdb with a count of failures
gdb.execute("kill")
exit(failcount)