Commit | Line | Data |
---|---|---|
2b514827 JK |
1 | # |
2 | # gdb helper commands and functions for Linux kernel debugging | |
3 | # | |
4 | # common utilities | |
5 | # | |
6 | # Copyright (c) Siemens AG, 2011-2013 | |
7 | # | |
8 | # Authors: | |
9 | # Jan Kiszka <jan.kiszka@siemens.com> | |
10 | # | |
11 | # This work is licensed under the terms of the GNU GPL version 2. | |
12 | # | |
13 | ||
14 | import gdb | |
15 | ||
16 | ||
17 | class CachedType: | |
18 | def __init__(self, name): | |
19 | self._type = None | |
20 | self._name = name | |
21 | ||
22 | def _new_objfile_handler(self, event): | |
23 | self._type = None | |
24 | gdb.events.new_objfile.disconnect(self._new_objfile_handler) | |
25 | ||
26 | def get_type(self): | |
27 | if self._type is None: | |
28 | self._type = gdb.lookup_type(self._name) | |
29 | if self._type is None: | |
30 | raise gdb.GdbError( | |
31 | "cannot resolve type '{0}'".format(self._name)) | |
32 | if hasattr(gdb, 'events') and hasattr(gdb.events, 'new_objfile'): | |
33 | gdb.events.new_objfile.connect(self._new_objfile_handler) | |
34 | return self._type | |
b0fecd8c JK |
35 | |
36 | ||
37 | long_type = CachedType("long") | |
38 | ||
39 | ||
40 | def get_long_type(): | |
41 | global long_type | |
42 | return long_type.get_type() | |
43 | ||
44 | ||
45 | def offset_of(typeobj, field): | |
46 | element = gdb.Value(0).cast(typeobj) | |
47 | return int(str(element[field].address).split()[0], 16) | |
48 | ||
49 | ||
50 | def container_of(ptr, typeobj, member): | |
51 | return (ptr.cast(get_long_type()) - | |
52 | offset_of(typeobj, member)).cast(typeobj) | |
53 | ||
54 | ||
55 | class ContainerOf(gdb.Function): | |
56 | """Return pointer to containing data structure. | |
57 | ||
58 | $container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the | |
59 | data structure of the type TYPE in which PTR is the address of ELEMENT. | |
60 | Note that TYPE and ELEMENT have to be quoted as strings.""" | |
61 | ||
62 | def __init__(self): | |
63 | super(ContainerOf, self).__init__("container_of") | |
64 | ||
65 | def invoke(self, ptr, typename, elementname): | |
66 | return container_of(ptr, gdb.lookup_type(typename.string()).pointer(), | |
67 | elementname.string()) | |
68 | ||
69 | ContainerOf() | |
7f994963 JK |
70 | |
71 | ||
72 | BIG_ENDIAN = 0 | |
73 | LITTLE_ENDIAN = 1 | |
74 | target_endianness = None | |
75 | ||
76 | ||
77 | def get_target_endianness(): | |
78 | global target_endianness | |
79 | if target_endianness is None: | |
80 | endian = gdb.execute("show endian", to_string=True) | |
81 | if "little endian" in endian: | |
82 | target_endianness = LITTLE_ENDIAN | |
83 | elif "big endian" in endian: | |
84 | target_endianness = BIG_ENDIAN | |
85 | else: | |
a2e73c48 | 86 | raise gdb.GdbError("unknown endianness '{0}'".format(str(endian))) |
7f994963 | 87 | return target_endianness |
78e87817 JK |
88 | |
89 | ||
90 | def read_u16(buffer): | |
91 | if get_target_endianness() == LITTLE_ENDIAN: | |
92 | return ord(buffer[0]) + (ord(buffer[1]) << 8) | |
93 | else: | |
94 | return ord(buffer[1]) + (ord(buffer[0]) << 8) | |
95 | ||
96 | ||
97 | def read_u32(buffer): | |
98 | if get_target_endianness() == LITTLE_ENDIAN: | |
99 | return read_u16(buffer[0:2]) + (read_u16(buffer[2:4]) << 16) | |
100 | else: | |
101 | return read_u16(buffer[2:4]) + (read_u16(buffer[0:2]) << 16) | |
102 | ||
103 | ||
104 | def read_u64(buffer): | |
105 | if get_target_endianness() == LITTLE_ENDIAN: | |
106 | return read_u32(buffer[0:4]) + (read_u32(buffer[4:8]) << 32) | |
107 | else: | |
108 | return read_u32(buffer[4:8]) + (read_u32(buffer[0:4]) << 32) | |
b24e2d21 JK |
109 | |
110 | ||
111 | target_arch = None | |
112 | ||
113 | ||
114 | def is_target_arch(arch): | |
115 | if hasattr(gdb.Frame, 'architecture'): | |
116 | return arch in gdb.newest_frame().architecture().name() | |
117 | else: | |
118 | global target_arch | |
119 | if target_arch is None: | |
120 | target_arch = gdb.execute("show architecture", to_string=True) | |
121 | return arch in target_arch | |
a4d86792 JK |
122 | |
123 | ||
124 | GDBSERVER_QEMU = 0 | |
125 | GDBSERVER_KGDB = 1 | |
126 | gdbserver_type = None | |
127 | ||
128 | ||
129 | def get_gdbserver_type(): | |
130 | def exit_handler(event): | |
131 | global gdbserver_type | |
132 | gdbserver_type = None | |
133 | gdb.events.exited.disconnect(exit_handler) | |
134 | ||
135 | def probe_qemu(): | |
136 | try: | |
137 | return gdb.execute("monitor info version", to_string=True) != "" | |
138 | except: | |
139 | return False | |
140 | ||
141 | def probe_kgdb(): | |
142 | try: | |
143 | thread_info = gdb.execute("info thread 2", to_string=True) | |
144 | return "shadowCPU0" in thread_info | |
145 | except: | |
146 | return False | |
147 | ||
148 | global gdbserver_type | |
149 | if gdbserver_type is None: | |
150 | if probe_qemu(): | |
151 | gdbserver_type = GDBSERVER_QEMU | |
152 | elif probe_kgdb(): | |
153 | gdbserver_type = GDBSERVER_KGDB | |
6ad18b73 | 154 | if gdbserver_type is not None and hasattr(gdb, 'events'): |
a4d86792 JK |
155 | gdb.events.exited.connect(exit_handler) |
156 | return gdbserver_type | |
e78f3d70 KB |
157 | |
158 | ||
159 | def gdb_eval_or_none(expresssion): | |
160 | try: | |
161 | return gdb.parse_and_eval(expresssion) | |
162 | except: | |
163 | return None |