]>
Commit | Line | Data |
---|---|---|
4daa187d AK |
1 | #!/usr/bin/python |
2 | ||
3 | # GDB debugging support | |
4 | # | |
5 | # Copyright 2012 Red Hat, Inc. and/or its affiliates | |
6 | # | |
7 | # Authors: | |
8 | # Avi Kivity <[email protected]> | |
9 | # | |
10 | # This work is licensed under the terms of the GNU GPL, version 2. See | |
11 | # the COPYING file in the top-level directory. | |
12 | # | |
13 | # Contributions after 2012-01-13 are licensed under the terms of the | |
14 | # GNU GPL, version 2 or (at your option) any later version. | |
15 | ||
16 | ||
17 | import gdb | |
18 | ||
93b1b365 | 19 | import os, sys |
4daa187d | 20 | |
93b1b365 PM |
21 | # Annoyingly, gdb doesn't put the directory of scripts onto the |
22 | # module search path. Do it manually. | |
23 | ||
24 | sys.path.append(os.path.dirname(__file__)) | |
25 | ||
26 | from qemugdb import mtree | |
4daa187d | 27 | |
9eddd6a4 SH |
28 | def get_fs_base(): |
29 | '''Fetch %fs base value using arch_prctl(ARCH_GET_FS)''' | |
30 | # %rsp - 120 is scratch space according to the SystemV ABI | |
31 | old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)') | |
32 | gdb.execute('call arch_prctl(0x1003, $rsp - 120)', False, True) | |
33 | fs_base = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)') | |
34 | gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True) | |
35 | return fs_base | |
36 | ||
37 | def get_glibc_pointer_guard(): | |
38 | '''Fetch glibc pointer guard value''' | |
39 | fs_base = get_fs_base() | |
40 | return gdb.parse_and_eval('*(uint64_t*)((uint64_t)%s + 0x30)' % fs_base) | |
41 | ||
42 | def glibc_ptr_demangle(val, pointer_guard): | |
43 | '''Undo effect of glibc's PTR_MANGLE()''' | |
44 | return gdb.parse_and_eval('(((uint64_t)%s >> 0x11) | ((uint64_t)%s << (64 - 0x11))) ^ (uint64_t)%s' % (val, val, pointer_guard)) | |
45 | ||
46 | def bt_jmpbuf(jmpbuf): | |
47 | '''Backtrace a jmpbuf''' | |
48 | JB_RBX = 0 | |
49 | JB_RBP = 1 | |
50 | JB_R12 = 2 | |
51 | JB_R13 = 3 | |
52 | JB_R14 = 4 | |
53 | JB_R15 = 5 | |
54 | JB_RSP = 6 | |
55 | JB_PC = 7 | |
56 | ||
57 | old_rbx = gdb.parse_and_eval('(uint64_t)$rbx') | |
58 | old_rbp = gdb.parse_and_eval('(uint64_t)$rbp') | |
59 | old_rsp = gdb.parse_and_eval('(uint64_t)$rsp') | |
60 | old_r12 = gdb.parse_and_eval('(uint64_t)$r12') | |
61 | old_r13 = gdb.parse_and_eval('(uint64_t)$r13') | |
62 | old_r14 = gdb.parse_and_eval('(uint64_t)$r14') | |
63 | old_r15 = gdb.parse_and_eval('(uint64_t)$r15') | |
64 | old_rip = gdb.parse_and_eval('(uint64_t)$rip') | |
65 | ||
66 | pointer_guard = get_glibc_pointer_guard() | |
67 | gdb.execute('set $rbx = %s' % jmpbuf[JB_RBX]) | |
68 | gdb.execute('set $rbp = %s' % glibc_ptr_demangle(jmpbuf[JB_RBP], pointer_guard)) | |
69 | gdb.execute('set $rsp = %s' % glibc_ptr_demangle(jmpbuf[JB_RSP], pointer_guard)) | |
70 | gdb.execute('set $r12 = %s' % jmpbuf[JB_R12]) | |
71 | gdb.execute('set $r13 = %s' % jmpbuf[JB_R13]) | |
72 | gdb.execute('set $r14 = %s' % jmpbuf[JB_R14]) | |
73 | gdb.execute('set $r15 = %s' % jmpbuf[JB_R15]) | |
74 | gdb.execute('set $rip = %s' % glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard)) | |
75 | ||
76 | gdb.execute('bt') | |
77 | ||
78 | gdb.execute('set $rbx = %s' % old_rbx) | |
79 | gdb.execute('set $rbp = %s' % old_rbp) | |
80 | gdb.execute('set $rsp = %s' % old_rsp) | |
81 | gdb.execute('set $r12 = %s' % old_r12) | |
82 | gdb.execute('set $r13 = %s' % old_r13) | |
83 | gdb.execute('set $r14 = %s' % old_r14) | |
84 | gdb.execute('set $r15 = %s' % old_r15) | |
85 | gdb.execute('set $rip = %s' % old_rip) | |
86 | ||
4daa187d AK |
87 | class QemuCommand(gdb.Command): |
88 | '''Prefix for QEMU debug support commands''' | |
89 | def __init__(self): | |
90 | gdb.Command.__init__(self, 'qemu', gdb.COMMAND_DATA, | |
91 | gdb.COMPLETE_NONE, True) | |
92 | ||
9eddd6a4 SH |
93 | class CoroutineCommand(gdb.Command): |
94 | '''Display coroutine backtrace''' | |
95 | def __init__(self): | |
96 | gdb.Command.__init__(self, 'qemu coroutine', gdb.COMMAND_DATA, | |
97 | gdb.COMPLETE_NONE) | |
98 | ||
99 | def invoke(self, arg, from_tty): | |
100 | argv = gdb.string_to_argv(arg) | |
101 | if len(argv) != 1: | |
102 | gdb.write('usage: qemu coroutine <coroutine-pointer>\n') | |
103 | return | |
104 | ||
105 | coroutine_pointer = gdb.parse_and_eval(argv[0]).cast(gdb.lookup_type('CoroutineUContext').pointer()) | |
106 | bt_jmpbuf(coroutine_pointer['env']['__jmpbuf']) | |
107 | ||
4daa187d | 108 | QemuCommand() |
9eddd6a4 | 109 | CoroutineCommand() |
93b1b365 | 110 | mtree.MtreeCommand() |