-
Notifications
You must be signed in to change notification settings - Fork 251
/
Copy pathgdbinit.py
113 lines (94 loc) · 3.59 KB
/
gdbinit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/bin/env python3
# Copyright 2021 Rémi Bernon for CodeWeavers
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
from __future__ import print_function
import gdb
import re
import subprocess
import sys
class LoadSymbolFiles(gdb.Command):
'Command to load symbol files directly from /proc/<pid>/maps.'
def __init__(self):
sup = super(LoadSymbolFiles, self)
sup.__init__('load-symbol-files', gdb.COMMAND_FILES, gdb.COMPLETE_NONE,
False)
self.libs = {}
gdb.execute('alias -a lsf = load-symbol-files', True)
def invoke(self, arg, from_tty):
pid = gdb.selected_inferior().pid
if not pid in self.libs: self.libs[pid] = {}
def command(cmd, confirm=from_tty, to_string=not from_tty):
gdb.execute(cmd, from_tty=confirm, to_string=to_string)
def execute(cmd):
return subprocess.check_output(cmd, stderr=subprocess.STDOUT) \
.decode('utf-8')
# load mappings addresses
libs = {}
with open('/proc/{}/maps'.format(pid), 'r') as maps:
for line in maps:
addr, _, _, _, node, path = re.split(r'\s+', line, 5)
path = path.strip()
if node == '0': continue
if path in libs: continue
libs[path] = int(addr.split('-')[0], 16)
# unload symbol file if address changed
for k in set(libs) & set(self.libs[pid]):
if libs[k] != self.libs[pid][k]:
command('remove-symbol-file "{}"'.format(k), confirm=False)
del self.libs[k]
# load symbol file for new mappings
for k in set(libs) - set(self.libs[pid]):
if arg is not None and re.search(arg, k) is None: continue
addr = self.libs[pid][k] = libs[k]
has_debug = False
offs = None
try:
out = execute(['file', k])
except:
continue
# try loading mapping as ELF
try:
out = execute(['readelf', '-l', k])
for line in out.split('\n'):
if not 'LOAD' in line: continue
base = int(line.split()[2], 16)
break
except:
# assume mapping is PE
base = -1
try:
name = None
cmd = 'add-symbol-file "{}"'.format(k)
out = execute(['objdump', '-h', k])
for line in out.split('\n'):
if '2**' in line:
_, name, _, vma, _, off, _ = line.split(maxsplit=6)
if base < 0: offs = int(off, 16)
else: offs = int(vma, 16) - base
if 'ALLOC' in line:
cmd += ' -s {} 0x{:x}'.format(name, addr + offs)
elif name in ['.gnu_debuglink', '.debug_info']:
has_debug = True
elif 'DEBUGGING' in line:
has_debug = True
except:
continue
if not has_debug:
print('no debugging info found in {}'.format(k))
continue
print('loading symbols for {}'.format(k))
command(cmd, confirm=False, to_string=True)
LoadSymbolFiles()