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    return memoryview(inf.read_memory(start, length))
92
93
94def read_u16(buffer, offset):
95    buffer_val = buffer[offset:offset + 2]
96    value = [0, 0]
97
98    if type(buffer_val[0]) is str:
99        value[0] = ord(buffer_val[0])
100        value[1] = ord(buffer_val[1])
101    else:
102        value[0] = buffer_val[0]
103        value[1] = buffer_val[1]
104
105    if get_target_endianness() == LITTLE_ENDIAN:
106        return value[0] + (value[1] << 8)
107    else:
108        return value[1] + (value[0] << 8)
109
110
111def read_u32(buffer, offset):
112    if get_target_endianness() == LITTLE_ENDIAN:
113        return read_u16(buffer, offset) + (read_u16(buffer, offset + 2) << 16)
114    else:
115        return read_u16(buffer, offset + 2) + (read_u16(buffer, offset) << 16)
116
117
118def read_u64(buffer, offset):
119    if get_target_endianness() == LITTLE_ENDIAN:
120        return read_u32(buffer, offset) + (read_u32(buffer, offset + 4) << 32)
121    else:
122        return read_u32(buffer, offset + 4) + (read_u32(buffer, offset) << 32)
123
124
125def read_ulong(buffer, offset):
126    if get_long_type().sizeof == 8:
127        return read_u64(buffer, offset)
128    else:
129        return read_u32(buffer, offset)
130
131atomic_long_counter_offset = atomic_long_type.get_type()['counter'].bitpos
132atomic_long_counter_sizeof = atomic_long_type.get_type()['counter'].type.sizeof
133
134def read_atomic_long(buffer, offset):
135    global atomic_long_counter_offset
136    global atomic_long_counter_sizeof
137
138    if atomic_long_counter_sizeof == 8:
139        return read_u64(buffer, offset + atomic_long_counter_offset)
140    else:
141        return read_u32(buffer, offset + atomic_long_counter_offset)
142
143target_arch = None
144
145
146def is_target_arch(arch):
147    if hasattr(gdb.Frame, 'architecture'):
148        return arch in gdb.newest_frame().architecture().name()
149    else:
150        global target_arch
151        if target_arch is None:
152            target_arch = gdb.execute("show architecture", to_string=True)
153        return arch in target_arch
154
155
156GDBSERVER_QEMU = 0
157GDBSERVER_KGDB = 1
158gdbserver_type = None
159
160
161def get_gdbserver_type():
162    def exit_handler(event):
163        global gdbserver_type
164        gdbserver_type = None
165        gdb.events.exited.disconnect(exit_handler)
166
167    def probe_qemu():
168        try:
169            return gdb.execute("monitor info version", to_string=True) != ""
170        except gdb.error:
171            return False
172
173    def probe_kgdb():
174        try:
175            thread_info = gdb.execute("info thread 2", to_string=True)
176            return "shadowCPU0" in thread_info
177        except gdb.error:
178            return False
179
180    global gdbserver_type
181    if gdbserver_type is None:
182        if probe_qemu():
183            gdbserver_type = GDBSERVER_QEMU
184        elif probe_kgdb():
185            gdbserver_type = GDBSERVER_KGDB
186        if gdbserver_type is not None and hasattr(gdb, 'events'):
187            gdb.events.exited.connect(exit_handler)
188    return gdbserver_type
189
190
191def gdb_eval_or_none(expresssion):
192    try:
193        return gdb.parse_and_eval(expresssion)
194    except gdb.error:
195        return None
196
197
198def dentry_name(d):
199    parent = d['d_parent']
200    if parent == d or parent == 0:
201        return ""
202    p = dentry_name(d['d_parent']) + "/"
203    return p + d['d_iname'].string()
204