Skip to content

Commit 5c66379

Browse files
author
xialu
committed
add commands
1 parent 91bd4d3 commit 5c66379

File tree

8 files changed

+217
-30
lines changed

8 files changed

+217
-30
lines changed

commands.py renamed to commands/dt.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,6 @@
44
except ImportError as e:
55
raise ImportError("This script must be run in GDB: ", str(e))
66

7-
8-
class SampleCommand(gdb.Command):
9-
'''
10-
Your custom gdb command
11-
'''
12-
_command = "sample_command"
13-
14-
def __init__(self):
15-
gdb.Command.__init__(self, self._command, gdb.COMMAND_STACK)
16-
17-
def invoke(self, argument, from_tty):
18-
print('command is called.')
19-
20-
217
class DTCommand(gdb.Command):
228
def __init__(self):
239
# This registers our class as "simple_command"

commands/stackfold.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# From https://fy.blackhats.net.au/blog/html/2017/08/04/so_you_want_to_script_gdb_with_python.html
2+
#####################################################
3+
#
4+
# Usage: to load this to gdb run:
5+
# (gdb) source ..../path/to/debug_naughty.py
6+
#
7+
# To have this automatically load, you need to put the script
8+
# in a path related to your binary. If you make /usr/sbin/foo,
9+
# You can ship this script as:
10+
# /usr/share/gdb/auto-load/ <PATH TO BINARY>
11+
# /usr/share/gdb/auto-load/usr/sbin/foo
12+
#
13+
# This will trigger gdb to autoload the script when you start
14+
# to acces a core or the live binary from this location.
15+
#
16+
17+
import gdb
18+
19+
20+
class StackFold(gdb.Command):
21+
def __init__(self):
22+
super(StackFold, self).__init__("stackfold", gdb.COMMAND_DATA)
23+
24+
def invoke(self, arg, from_tty):
25+
# An inferior is the 'currently running applications'. In this case we only
26+
# have one.
27+
stack_maps = {}
28+
# This creates a dict where each element is keyed by backtrace.
29+
# Then each backtrace contains an array of "frames"
30+
#
31+
inferiors = gdb.inferiors()
32+
for inferior in inferiors:
33+
for thread in inferior.threads():
34+
try:
35+
# Change to our threads context
36+
thread.switch()
37+
# Get the thread IDS
38+
(tpid, lwpid, tid) = thread.ptid
39+
gtid = thread.num
40+
# Take a human readable copy of the backtrace, we'll need this for display later.
41+
o = gdb.execute('bt', to_string=True)
42+
# Build the backtrace for comparison
43+
backtrace = []
44+
gdb.newest_frame()
45+
cur_frame = gdb.selected_frame()
46+
while cur_frame is not None:
47+
if cur_frame.name() is not None:
48+
backtrace.append(cur_frame.name())
49+
50+
cur_frame = cur_frame.older()
51+
# Now we have a backtrace like ['pthread_cond_wait@@GLIBC_2.3.2', 'lazy_thread', 'start_thread', 'clone']
52+
# dicts can't use lists as keys because they are non-hashable, so we turn this into a string.
53+
# Remember, C functions can't have spaces in them ...
54+
s_backtrace = ' '.join(backtrace)
55+
# Let's see if it exists in the stack_maps
56+
if s_backtrace not in stack_maps:
57+
stack_maps[s_backtrace] = []
58+
# Now lets add this thread to the map.
59+
stack_maps[s_backtrace].append(
60+
{'gtid': gtid, 'tpid': tpid, 'bt': o})
61+
except Exception as e:
62+
print(e)
63+
# Now at this point we have a dict of traces, and each trace has a "list" of pids that match. Let's display them
64+
for smap in stack_maps:
65+
# Get our human readable form out.
66+
o = stack_maps[smap][0]['bt']
67+
for t in stack_maps[smap]:
68+
# For each thread we recorded
69+
print("Thread %s (LWP %s))" % (t['gtid'], t['tpid']))
70+
print(o)
71+
72+
73+
# This registers our class to the gdb runtime at "source" time.
74+
StackFold()

commands/stackwalk.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
# Usage: to load this to gdb run:
3+
# (gdb) source ..../path/to/debug_naughty.py
4+
#
5+
# To have this automatically load, you need to put the script
6+
# in a path related to your binary. If you make /usr/sbin/foo,
7+
# You can ship this script as:
8+
# /usr/share/gdb/auto-load/ <PATH TO BINARY>
9+
# /usr/share/gdb/auto-load/usr/sbin/foo
10+
#
11+
# This will trigger gdb to autoload the script when you start
12+
# to acces a core or the live binary from this location.
13+
#
14+
15+
import gdb
16+
17+
18+
class StackWalkWCharCommand(gdb.Command):
19+
def __init__(self):
20+
# This registers our class as "simple_command"
21+
super(StackWalkWCharCommand, self).__init__("stackwalk", gdb.COMMAND_DATA)
22+
23+
def invoke(self, arg, from_tty):
24+
# When we call "simple_command" from gdb, this is the method
25+
# that will be called.
26+
print("Hello from simple_command!")
27+
# get the register
28+
rbp = gdb.parse_and_eval('$rbp')
29+
rsp = gdb.parse_and_eval('$rsp')
30+
ptr = rsp
31+
ppwc = gdb.lookup_type('wchar_t').pointer().pointer()
32+
while ptr < rbp:
33+
try:
34+
print('pointer is {}'.format(ptr))
35+
print(gdb.execute('wc_print {}'.format(
36+
ptr.cast(ppwc).dereference())))
37+
print('===')
38+
except:
39+
pass
40+
ptr += 4
41+
42+
43+
# This registers our class to the gdb runtime at "source" time.
44+
StackWalkWCharCommand()

common.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,41 @@ def not_handle_SIGSEGV():
1515
def enable_logging(logging_file):
1616
gdb.execute('set logging file ' + logging_file)
1717
gdb.execute('set logging on')
18+
19+
20+
def dynamic_value(val):
21+
'''val must be pointer or a reference'''
22+
return val.cast(val.dynamic_type)
23+
24+
25+
def norm_type(tp):
26+
'''return the pointee type if the type is pointter'''
27+
if tp.code == gdb.TYPE_CODE_PTR:
28+
pointee_type = tp.target()
29+
if pointee_type.code == gdb.TYPE_CODE_PTR:
30+
return norm_type(pointee_type)
31+
return pointee_type
32+
return tp
33+
34+
35+
def is_null(val):
36+
if val.type.code == gdb.TYPE_CODE_PTR:
37+
return int(val) == 0
38+
return False
39+
40+
41+
def deref(pointer):
42+
'''dereference pointer to get value'''
43+
val = pointer
44+
if val.type.code == gdb.TYPE_CODE_PTR:
45+
if is_null(val):
46+
raise Exception("nullptr")
47+
val = dynamic_value(val)
48+
val = val.referenced_value()
49+
if val.type.code == gdb.TYPE_CODE_PTR:
50+
if is_null(val):
51+
raise Exception("nullptr")
52+
val = dynamic_value(val)
53+
val = val.referenced_value()
54+
return val
55+

prelude.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ def add_paths():
77
scripts_folder = os.path.dirname(__file__)
88

99
print('add to the python sys.path: '+ scripts_folder)
10-
sys.path.append(scripts_folder)
10+
sys.path.insert(0, scripts_folder)
1111

1212
add_paths()

pretty_printers/pointer.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# # printer is to pretty print the variable
2+
# # 1 create a printer with to_string method
3+
# # 2 create a printer matcher
4+
# # 3 register the printer to the gdb.
5+
6+
import re
7+
import gdb.printing
8+
import gdb
9+
import traceback
10+
import common
11+
gPrinters = {}
12+
13+
def lookup_pretty_printer(val):
14+
try:
15+
tp = val.type
16+
if val.type.code == gdb.TYPE_CODE_PTR:
17+
tp = common.norm_type(val.type)
18+
if int(val) == 0:
19+
return None
20+
for k, v in gPrinters.items():
21+
if k.search(str(tp)):
22+
return v(val)
23+
except Exception as e:
24+
print(traceback.format_exc())
25+
return None
26+
27+
28+
print('register disptacher for pointer.')
29+
gdb.printing.register_pretty_printer(
30+
gdb.current_objfile(),
31+
lookup_pretty_printer, replace=True
32+
)

process.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
try:
3+
import gdb
4+
except ImportError as e:
5+
raise ImportError("This script must be run in GDB: ", str(e))
6+
7+
gProcess = None
8+
class Process:
9+
def __init__(self):
10+
self._inferior = gdb.selected_inferior()
11+
self.types = {}
12+
13+
def read_memory(self, addr, size):
14+
return self._inferior.read_memory(addr, size)
15+
16+
def lookup_type(self, tp):
17+
if tp in self.types:
18+
return self.types[tp]
19+
_tp = gdb.lookup_type(tp)
20+
self.types[tp] = _tp
21+
return _tp
22+
23+
def get_process():
24+
global gProcess
25+
if not gProcess:
26+
gProcess = Process()
27+
return gProcess

util.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,14 @@
22
import gdb
33
except ImportError as e:
44
raise ImportError("This script must be run in GDB: ", str(e))
5-
5+
66
from libstdcxx.v6.printers import StdMapPrinter, StdVectorPrinter, StdListPrinter
77
import re
88

99

1010
def print_stack_trace():
1111
gdb.execute('bt')
1212

13-
def dynamic_type(val):
14-
'''val must be pointer or a reference'''
15-
return val.cast(val.dynamic_type)
16-
17-
18-
def norm_type(tp):
19-
'''return the pointee type if the type is pointter'''
20-
if tp.code == gdb.TYPE_CODE_PTR:
21-
pointee_type = tp.target()
22-
if pointee_type.code == gdb.TYPE_CODE_PTR:
23-
return norm_type(pointee_type)
24-
return pointee_type
25-
return tp
26-
2713

2814
def StdMapToDict(iMap):
2915
it = StdMapPrinter('map', iMap).children()

0 commit comments

Comments
 (0)