• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
14import gdb
15
16
17class 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
35
36
37long_type = CachedType("long")
38atomic_long_type = CachedType("atomic_long_t")
39
40def get_long_type():
41    global long_type
42    return long_type.get_type()
43
44def offset_of(typeobj, field):
45    element = gdb.Value(0).cast(typeobj)
46    return int(str(element[field].address).split()[0], 16)
47
48
49def container_of(ptr, typeobj, member):
50    return (ptr.cast(get_long_type()) -
51            offset_of(typeobj, member)).cast(typeobj)
52
53
54class ContainerOf(gdb.Function):
55    """Return pointer to containing data structure.
56
57$container_of(PTR, "TYPE", "ELEMENT"): Given PTR, return a pointer to the
58data structure of the type TYPE in which PTR is the address of ELEMENT.
59Note that TYPE and ELEMENT have to be quoted as strings."""
60
61    def __init__(self):
62        super(ContainerOf, self).__init__("container_of")
63
64    def invoke(self, ptr, typename, elementname):
65        return container_of(ptr, gdb.lookup_type(typename.string()).pointer(),
66                            elementname.string())
67
68
69ContainerOf()
70
71
72BIG_ENDIAN = 0
73LITTLE_ENDIAN = 1
74target_endianness = None
75
76
77def 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:
86            raise gdb.GdbError("unknown endianness '{0}'".format(str(endian)))
87    return target_endianness
88
89
90def read_memoryview(inf, start, length):
91    m = inf.read_memory(start, length)
92    if type(m) is memoryview:
93        return m
94    return memoryview(m)
95
96
97def read_u16(buffer, offset):
98    buffer_val = buffer[offset:offset + 2]
99    value = [0, 0]
100
101    if type(buffer_val[0]) is str:
102        value[0] = ord(buffer_val[0])
103        value[1] = ord(buffer_val[1])
104    else:
105        value[0] = buffer_val[0]
106        value[1] = buffer_val[1]
107
108    if get_target_endianness() == LITTLE_ENDIAN:
109        return value[0] + (value[1] << 8)
110    else:
111        return value[1] + (value[0] << 8)
112
113
114def read_u32(buffer, offset):
115    if get_target_endianness() == LITTLE_ENDIAN:
116        return read_u16(buffer, offset) + (read_u16(buffer, offset + 2) << 16)
117    else:
118        return read_u16(buffer, offset + 2) + (read_u16(buffer, offset) << 16)
119
120
121def read_u64(buffer, offset):
122    if get_target_endianness() == LITTLE_ENDIAN:
123        return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32)
124    else:
125        return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32)
126
127
128def read_ulong(buffer, offset):
129    if get_long_type().sizeof == 8:
130        return read_u64(buffer, offset)
131    else:
132        return read_u32(buffer, offset)
133
134atomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos
135atomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof
136
137def read_atomic_long(buffer, offset):
138    global atomic_long_counter_offset
139    global atomic_long_counter_sizeof
140
141    if atomic_long_counter_sizeof == 8:
142        return read_u64(buffer, offset + atomic_long_counter_offset)
143    else:
144        return read_u32(buffer, offset + atomic_long_counter_offset)
145
146target_arch = None
147
148
149def is_target_arch(arch):
150    if hasattr(gdb.Frame, 'architecture'):
151        return arch in gdb.newest_frame().architecture().name()
152    else:
153        global target_arch
154        if target_arch is None:
155            target_arch = gdb.execute("show architecture", to_string=True)
156        return arch in target_arch
157
158
159GDBSERVER_QEMU = 0
160GDBSERVER_KGDB = 1
161gdbserver_type = None
162
163
164def get_gdbserver_type():
165    def exit_handler(event):
166        global gdbserver_type
167        gdbserver_type = None
168        gdb.events.exited.disconnect(exit_handler)
169
170    def probe_qemu():
171        try:
172            return gdb.execute("monitor info version", to_string=True) != ""
173        except gdb.error:
174            return False
175
176    def probe_kgdb():
177        try:
178            thread_info = gdb.execute("info thread 2", to_string=True)
179            return "shadowCPU0" in thread_info
180        except gdb.error:
181            return False
182
183    global gdbserver_type
184    if gdbserver_type is None:
185        if probe_qemu():
186            gdbserver_type = GDBSERVER_QEMU
187        elif probe_kgdb():
188            gdbserver_type = GDBSERVER_KGDB
189        if gdbserver_type is not None and hasattr(gdb, 'events'):
190            gdb.events.exited.connect(exit_handler)
191    return gdbserver_type
192
193
194def gdb_eval_or_none(expresssion):
195    try:
196        return gdb.parse_and_eval(expresssion)
197    except gdb.error:
198        return None
199
200
201def dentry_name(d):
202    parent = d['d_parent']
203    if parent == d or parent == 0:
204        return ""
205    p = dentry_name(d['d_parent']) + "/"
206    return p + d['d_iname'].string()
207