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") | |
4d040cbc KYL |
38 | ulong_type = CachedType("unsigned long") |
39 | uint_type = CachedType("unsigned int") | |
e3c8d33e | 40 | atomic_long_type = CachedType("atomic_long_t") |
4d040cbc KYL |
41 | size_t_type = CachedType("size_t") |
42 | struct_page_type = CachedType("struct page") | |
43 | ||
44 | def get_uint_type(): | |
45 | global uint_type | |
46 | return uint_type.get_type() | |
47 | ||
48 | def get_page_type(): | |
49 | global struct_page_type | |
50 | return struct_page_type.get_type() | |
b0fecd8c JK |
51 | |
52 | def get_long_type(): | |
53 | global long_type | |
54 | return long_type.get_type() | |
55 | ||
4d040cbc KYL |
56 | def get_ulong_type(): |
57 | global ulong_type | |
58 | return ulong_type.get_type() | |
59 | ||
60 | def get_size_t_type(): | |
61 | global size_t_type | |
62 | return size_t_type.get_type() | |
63 | ||
b0fecd8c JK |
64 | def offset_of(typeobj, field): |
65 | element = gdb.Value(0).cast(typeobj) | |
66 | return int(str(element[field].address).split()[0], 16) | |
67 | ||
68 | ||
69 | def container_of(ptr, typeobj, member): | |
70 | return (ptr.cast(get_long_type()) - | |
71 | offset_of(typeobj, member)).cast(typeobj) | |
72 | ||
73 | ||
74 | class ContainerOf(gdb.Function): | |
75 | """Return pointer to containing data structure. | |
76 | ||
77 | $container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the | |
78 | data structure of the type TYPE in which PTR is the address of ELEMENT. | |
79 | Note that TYPE and ELEMENT have to be quoted as strings.""" | |
80 | ||
81 | def __init__(self): | |
82 | super(ContainerOf, self).__init__("container_of") | |
83 | ||
84 | def invoke(self, ptr, typename, elementname): | |
85 | return container_of(ptr, gdb.lookup_type(typename.string()).pointer(), | |
86 | elementname.string()) | |
87 | ||
494dbe02 | 88 | |
b0fecd8c | 89 | ContainerOf() |
7f994963 JK |
90 | |
91 | ||
92 | BIG_ENDIAN = 0 | |
93 | LITTLE_ENDIAN = 1 | |
94 | target_endianness = None | |
95 | ||
96 | ||
97 | def get_target_endianness(): | |
98 | global target_endianness | |
99 | if target_endianness is None: | |
100 | endian = gdb.execute("show endian", to_string=True) | |
101 | if "little endian" in endian: | |
102 | target_endianness = LITTLE_ENDIAN | |
103 | elif "big endian" in endian: | |
104 | target_endianness = BIG_ENDIAN | |
105 | else: | |
a2e73c48 | 106 | raise gdb.GdbError("unknown endianness '{0}'".format(str(endian))) |
7f994963 | 107 | return target_endianness |
78e87817 JK |
108 | |
109 | ||
321958d9 | 110 | def read_memoryview(inf, start, length): |
7362042f PL |
111 | m = inf.read_memory(start, length) |
112 | if type(m) is memoryview: | |
113 | return m | |
114 | return memoryview(m) | |
321958d9 DC |
115 | |
116 | ||
ca210ba3 JC |
117 | def read_u16(buffer, offset): |
118 | buffer_val = buffer[offset:offset + 2] | |
321958d9 DC |
119 | value = [0, 0] |
120 | ||
ca210ba3 JC |
121 | if type(buffer_val[0]) is str: |
122 | value[0] = ord(buffer_val[0]) | |
123 | value[1] = ord(buffer_val[1]) | |
321958d9 | 124 | else: |
ca210ba3 JC |
125 | value[0] = buffer_val[0] |
126 | value[1] = buffer_val[1] | |
321958d9 | 127 | |
78e87817 | 128 | if get_target_endianness() == LITTLE_ENDIAN: |
321958d9 | 129 | return value[0] + (value[1] << 8) |
78e87817 | 130 | else: |
321958d9 | 131 | return value[1] + (value[0] << 8) |
78e87817 JK |
132 | |
133 | ||
ca210ba3 | 134 | def read_u32(buffer, offset): |
78e87817 | 135 | if get_target_endianness() == LITTLE_ENDIAN: |
ca210ba3 | 136 | return read_u16(buffer, offset) + (read_u16(buffer, offset + 2) << 16) |
78e87817 | 137 | else: |
ca210ba3 | 138 | return read_u16(buffer, offset + 2) + (read_u16(buffer, offset) << 16) |
78e87817 JK |
139 | |
140 | ||
ca210ba3 | 141 | def read_u64(buffer, offset): |
78e87817 | 142 | if get_target_endianness() == LITTLE_ENDIAN: |
ca210ba3 | 143 | return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32) |
78e87817 | 144 | else: |
ca210ba3 | 145 | return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32) |
b24e2d21 JK |
146 | |
147 | ||
3e0d075c JO |
148 | def read_ulong(buffer, offset): |
149 | if get_long_type().sizeof == 8: | |
150 | return read_u64(buffer, offset) | |
151 | else: | |
152 | return read_u32(buffer, offset) | |
153 | ||
e3c8d33e AB |
154 | atomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos |
155 | atomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof | |
156 | ||
157 | def read_atomic_long(buffer, offset): | |
158 | global atomic_long_counter_offset | |
159 | global atomic_long_counter_sizeof | |
160 | ||
161 | if atomic_long_counter_sizeof == 8: | |
162 | return read_u64(buffer, offset + atomic_long_counter_offset) | |
163 | else: | |
164 | return read_u32(buffer, offset + atomic_long_counter_offset) | |
3e0d075c | 165 | |
b24e2d21 JK |
166 | target_arch = None |
167 | ||
168 | ||
169 | def is_target_arch(arch): | |
170 | if hasattr(gdb.Frame, 'architecture'): | |
171 | return arch in gdb.newest_frame().architecture().name() | |
172 | else: | |
173 | global target_arch | |
174 | if target_arch is None: | |
175 | target_arch = gdb.execute("show architecture", to_string=True) | |
176 | return arch in target_arch | |
a4d86792 JK |
177 | |
178 | ||
179 | GDBSERVER_QEMU = 0 | |
180 | GDBSERVER_KGDB = 1 | |
181 | gdbserver_type = None | |
182 | ||
183 | ||
184 | def get_gdbserver_type(): | |
185 | def exit_handler(event): | |
186 | global gdbserver_type | |
187 | gdbserver_type = None | |
188 | gdb.events.exited.disconnect(exit_handler) | |
189 | ||
190 | def probe_qemu(): | |
191 | try: | |
192 | return gdb.execute("monitor info version", to_string=True) != "" | |
494dbe02 | 193 | except gdb.error: |
a4d86792 JK |
194 | return False |
195 | ||
196 | def probe_kgdb(): | |
197 | try: | |
198 | thread_info = gdb.execute("info thread 2", to_string=True) | |
ec0b6d17 | 199 | return "shadowCPU" in thread_info |
494dbe02 | 200 | except gdb.error: |
a4d86792 JK |
201 | return False |
202 | ||
203 | global gdbserver_type | |
204 | if gdbserver_type is None: | |
205 | if probe_qemu(): | |
206 | gdbserver_type = GDBSERVER_QEMU | |
207 | elif probe_kgdb(): | |
208 | gdbserver_type = GDBSERVER_KGDB | |
6ad18b73 | 209 | if gdbserver_type is not None and hasattr(gdb, 'events'): |
a4d86792 JK |
210 | gdb.events.exited.connect(exit_handler) |
211 | return gdbserver_type | |
e78f3d70 KB |
212 | |
213 | ||
214 | def gdb_eval_or_none(expresssion): | |
215 | try: | |
216 | return gdb.parse_and_eval(expresssion) | |
494dbe02 | 217 | except gdb.error: |
e78f3d70 | 218 | return None |