幫之前寫的指令 bt 加上參數 -s, 使用 -s 時, 會一併記錄 backtrace 每個 frame 附近的原始碼。
以下是一個範例輸出:
(gdb) bt -s #0 A::hello at b.cpp:8 | class A | { | public: | void hello(int n) | { ->| std::cout << n << std::endl; | } | | void foo(int n) | { #1 A::bar at b.cpp:18 | bar(n + 1); | } | | void bar(int n) | { ->| hello(n + 10); | } | }; | | int main(void) { #2 A::foo at b.cpp:13 | std::cout << n << std::endl; | } | | void foo(int n) | { ->| bar(n + 1); | } | | void bar(int n) | { #3 main at b.cpp:24 | } | }; | | int main(void) { | A a; ->| a.foo(5); | return 0; | }
修改後的 python script 如下:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import gdb | |
def read_source_code(filename, target_line, num_lines): | |
with open(filename, 'r') as fr: | |
target_line -= 1 | |
lines = [' | ' + line[:-1] for line in fr] | |
lines[target_line] = '->| ' + lines[target_line][4:] | |
offset = num_lines / 2 | |
return lines[target_line - offset : target_line + offset] | |
class ShorternBacktraceCommand(gdb.Command): | |
'''Show a backtrace without argument info in each frame.''' | |
def __init__(self): | |
super(ShorternBacktraceCommand, self).__init__ ("bt", | |
gdb.COMMAND_SUPPORT, | |
gdb.COMPLETE_NONE) | |
def invoke(self, arg, from_tty): | |
# Parse arguments. | |
show_source = False | |
num = 0; | |
args = arg.split() | |
for s in args: | |
if s == '-s': | |
show_source = True | |
else: | |
try: | |
num = int(s) | |
except Exception, e: | |
pass | |
# Extract frame info. | |
frames = [] | |
f = gdb.newest_frame() | |
fn = 0 | |
while f is not None: | |
symtab_and_line = gdb.Frame.find_sal(f) | |
frame_name = gdb.Frame.name(f) | |
if frame_name: | |
outs = ( | |
fn, | |
frame_name, | |
symtab_and_line.symtab.filename, | |
symtab_and_line.line, | |
) | |
else: | |
outs = (fn, '??', 'unknown', 0) | |
head = '#%-2d %s at %s:%s' % outs | |
codes = None | |
if show_source and frame_name: | |
codes = read_source_code(symtab_and_line.symtab.fullname(), | |
symtab_and_line.line, | |
10) | |
frames.append((head, codes)) | |
f = gdb.Frame.older(f) | |
fn += 1 | |
# Hold the subset. | |
if num > 0: | |
frames = frames[:num] | |
elif num < 0: | |
frames = frames[len(frames) + num:] | |
# Print the result. | |
for head, codes in frames: | |
print head | |
if codes: | |
for line in codes: | |
print line | |
ShorternBacktraceCommand() |
作法大致和 《用 python gdb 客製化 backtrace 的結果》一樣, 只是改取檔案的 fullname, 再自己讀出相關的原始碼。這部份用 python 實作, 相當地輕鬆寫意。
沒有留言:
張貼留言