]>
Commit | Line | Data |
---|---|---|
261f4d6d AB |
1 | # |
2 | # This script needs to be run on startup | |
3 | # qemu -kernel ${KERNEL} -s -S | |
4 | # and then: | |
5 | # gdb ${KERNEL}.vmlinux -x ${QEMU_SRC}/tests/guest-debug/test-gdbstub.py | |
6 | ||
7 | import gdb | |
8 | ||
9 | failcount = 0 | |
10 | ||
11 | ||
12 | def report(cond, msg): | |
13 | "Report success/fail of test" | |
14 | if cond: | |
15 | print ("PASS: %s" % (msg)) | |
16 | else: | |
17 | print ("FAIL: %s" % (msg)) | |
18 | failcount += 1 | |
19 | ||
20 | ||
21 | def check_step(): | |
22 | "Step an instruction, check it moved." | |
23 | start_pc = gdb.parse_and_eval('$pc') | |
24 | gdb.execute("si") | |
25 | end_pc = gdb.parse_and_eval('$pc') | |
26 | ||
27 | return not (start_pc == end_pc) | |
28 | ||
29 | ||
30 | def 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) | |
34 | ||
35 | gdb.execute("c") | |
36 | ||
37 | # hopefully we came back | |
38 | end_pc = gdb.parse_and_eval('$pc') | |
39 | print ("%s == %s %d" % (end_pc, sym.value(), bp.hit_count)) | |
40 | bp.delete() | |
41 | ||
42 | # can we test we hit bp? | |
43 | return end_pc == sym.value() | |
44 | ||
45 | ||
46 | # We need to do hbreak manually as the python interface doesn't export it | |
47 | def check_hbreak(sym_name): | |
48 | "Setup hardware breakpoint, continue and check we stopped." | |
49 | sym, ok = gdb.lookup_symbol(sym_name) | |
50 | gdb.execute("hbreak %s" % (sym_name)) | |
51 | gdb.execute("c") | |
52 | ||
53 | # hopefully we came back | |
54 | end_pc = gdb.parse_and_eval('$pc') | |
55 | print ("%s == %s" % (end_pc, sym.value())) | |
56 | ||
57 | if end_pc == sym.value(): | |
58 | gdb.execute("d 1") | |
59 | return True | |
60 | else: | |
61 | return False | |
62 | ||
63 | ||
64 | class WatchPoint(gdb.Breakpoint): | |
65 | ||
66 | def get_wpstr(self, sym_name): | |
67 | "Setup sym and wp_str for given symbol." | |
68 | self.sym, ok = gdb.lookup_symbol(sym_name) | |
69 | wp_addr = gdb.parse_and_eval(sym_name).address | |
70 | self.wp_str = '*(%(type)s)(&%(address)s)' % dict( | |
71 | type = wp_addr.type, address = sym_name) | |
72 | ||
73 | return(self.wp_str) | |
74 | ||
75 | def __init__(self, sym_name, type): | |
76 | wp_str = self.get_wpstr(sym_name) | |
77 | super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type) | |
78 | ||
79 | def stop(self): | |
80 | end_pc = gdb.parse_and_eval('$pc') | |
81 | print ("HIT WP @ %s" % (end_pc)) | |
82 | return True | |
83 | ||
84 | ||
85 | def do_one_watch(sym, wtype, text): | |
86 | ||
87 | wp = WatchPoint(sym, wtype) | |
88 | gdb.execute("c") | |
89 | report_str = "%s for %s (%s)" % (text, sym, wp.sym.value()) | |
90 | ||
91 | if wp.hit_count > 0: | |
92 | report(True, report_str) | |
93 | wp.delete() | |
94 | else: | |
95 | report(False, report_str) | |
96 | ||
97 | ||
98 | def check_watches(sym_name): | |
99 | "Watch a symbol for any access." | |
100 | ||
101 | # Should hit for any read | |
102 | do_one_watch(sym_name, gdb.WP_ACCESS, "awatch") | |
103 | ||
104 | # Again should hit for reads | |
105 | do_one_watch(sym_name, gdb.WP_READ, "rwatch") | |
106 | ||
107 | # Finally when it is written | |
108 | do_one_watch(sym_name, gdb.WP_WRITE, "watch") | |
109 | ||
110 | ||
111 | class CatchBreakpoint(gdb.Breakpoint): | |
112 | def __init__(self, sym_name): | |
113 | super(CatchBreakpoint, self).__init__(sym_name) | |
114 | self.sym, ok = gdb.lookup_symbol(sym_name) | |
115 | ||
116 | def stop(self): | |
117 | end_pc = gdb.parse_and_eval('$pc') | |
118 | print ("CB: %s == %s" % (end_pc, self.sym.value())) | |
119 | if end_pc == self.sym.value(): | |
120 | report(False, "Hit final catchpoint") | |
121 | ||
122 | ||
123 | def run_test(): | |
124 | "Run throught the tests one by one" | |
125 | ||
126 | print ("Checking we can step the first few instructions") | |
127 | step_ok = 0 | |
128 | for i in range(3): | |
129 | if check_step(): | |
130 | step_ok += 1 | |
131 | ||
132 | report(step_ok == 3, "single step in boot code") | |
133 | ||
134 | print ("Checking HW breakpoint works") | |
135 | break_ok = check_hbreak("kernel_init") | |
136 | report(break_ok, "hbreak @ kernel_init") | |
137 | ||
138 | # Can't set this up until we are in the kernel proper | |
139 | # if we make it to run_init_process we've over-run and | |
140 | # one of the tests failed | |
141 | print ("Setup catch-all for run_init_process") | |
142 | cbp = CatchBreakpoint("run_init_process") | |
143 | cpb2 = CatchBreakpoint("try_to_run_init_process") | |
144 | ||
145 | print ("Checking Normal breakpoint works") | |
146 | break_ok = check_break("wait_for_completion") | |
147 | report(break_ok, "break @ wait_for_completion") | |
148 | ||
149 | print ("Checking watchpoint works") | |
150 | check_watches("system_state") | |
151 | ||
152 | # | |
153 | # This runs as the script it sourced (via -x) | |
154 | # | |
155 | ||
156 | try: | |
157 | print ("Connecting to remote") | |
158 | gdb.execute("target remote localhost:1234") | |
159 | ||
160 | # These are not very useful in scripts | |
161 | gdb.execute("set pagination off") | |
162 | gdb.execute("set confirm off") | |
163 | ||
164 | # Run the actual tests | |
165 | run_test() | |
166 | ||
167 | except: | |
168 | print ("GDB Exception: %s" % (sys.exc_info()[0])) | |
169 | failcount += 1 | |
170 | import code | |
171 | code.InteractiveConsole(locals=globals()).interact() | |
172 | raise | |
173 | ||
174 | # Finally kill the inferior and exit gdb with a count of failures | |
175 | gdb.execute("kill") | |
176 | exit(failcount) |