Repository navigation
Expand file tree
/
Copy path.pygdbinit
More file actions
98 lines (91 loc) · 3.71 KB
/
Copy path.pygdbinit
File metadata and controls
98 lines (91 loc) · 3.71 KB
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
define pyframe
set $__self = (PyObject *) 0
if ($__func->ob_type == &PyMethod_Type)
set $__self = (((PyCFunctionObject *)$__func)->m_self)
set $__func = (((PyCFunctionObject *)$__func)->m_ml->ml_meth)
end
set $__context = (char *)((PyStringObject *)$__co->co_name)->ob_sval
set $__funcname = PyEval_GetFuncName($__func)
set $__funcdesc = PyEval_GetFuncDesc($__func)
set $__fn = (char *)((PyStringObject *)$__co->co_filename)->ob_sval
printf "== %s > %s%s%s%s at %s:%d\n", $__context, \
($__self ? $__self->ob_type->tp_name : ""), \
($__self ? ":" : ""), $__funcname, $__funcdesc, \
$__fn, PyCode_Addr2Line($__co, $__f->f_lasti)
end
# Walk the stack from innermost to outermost frame. If we hit a python call
# frame, extract python caller/callee pair and print it out too. This is
# *extremely* fragile and likely works with only specific python builds;
# this script is for python 2.6.8 built for x86-64 with gcc 4.6+.
#
# When walking up the call chain, we will first see maybe fast_function,
# then maybe call_function frame, then PyEval_EvalFrameEx. All three are
# actually inlined frames inside PyEval_EvalFrameEx, and $rsp remains
# unchanged even if we walk up the stack. PyEval_EvalCodeEx follows them.
#
# Many variables in these call frames are optimised out so we need to wander
# around the stack to pick out the ones we need: called function 'func' from
# {call,fast}_function, calling code object 'co' from PyEval_EvalFrameEx and
# call frame object 'tstate->frame' from PyEval_EvalCodeEx.
#
# A generator call chain has the usual call_function, PyEval_EvalFrameEx,
# but then gen_send_ex and PyEval_EvalFrameEx again, with slightly changed
# meaning from above.
#
# If and only if we locate all three required parts we dump the python info.
define pystack_thread
set $__ctr = 0
while $__ctr < 200
frame
if ($pc >= PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx)
# The first frame we find is fast_function or call_function.
# Pick up the 'func' variable here, and remember $rsp so we
# can figure how long we're staying inside PyEval_EvalFrameEx.
# Then move to the next frame, remembering to print it out.
set $__rsp = $rsp
set $__func = func
up-silently 1
frame
if $pc >= PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx && $rsp == $__rsp
# If the first frame was fast_function, we're now in call_function,
# otherwise we've made it to PyEval_EvalFrameEx; step up once more
# and see if $rsp changes. If it does, we left to PyEval_EvalCodeEx
# and there was no fast_function.
up-silently 1
frame
if $pc >= PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx && $rsp == $__rsp
set $__co = co
up-silently 1
frame
else
down-silently 1
set $__co = co
up-silently 1
end
# We're now either in gen_send_ex or at PyEval_EvalCodeEx. If the former
# record this frame as a generator, get 'f' from it, and fish out the
# function object from frame above (PyEval_EvalFrameEx) python stack.
# Otherwise in PyEval_EvalCodeEx get frame object from 'tstate->frame'.
if $pc >= gen_send_ex && $pc < gen_iternext
set $__f = f
up-silently 1
frame
set $__func = stack_pointer[-1]
else
set $__f = tstate->frame
end
# Print this frame.
pyframe
end
end
# Quit if it looks like we've come to end of stack.
if ($pc >= __libc_start_main && $pc < gnu_get_libc_release) || ($pc >= __clone && $pc < __umount)
loop_break
end
up-silently 1
set $__ctr = $__ctr + 1
end
end
define pystack
thread apply all pystack_thread
end