|
12 | 12 | """
|
13 | 13 |
|
14 | 14 | gdb.execute('file call_graph_py.out', to_string=True)
|
15 |
| -# rbreak before start to ignore dynamically linked stdlib functions. |
16 |
| -gdb.execute('set confirm off') |
17 | 15 | gdb.execute('start', to_string=True)
|
18 | 16 | depth_string = 4 * ' '
|
19 | 17 | thread = gdb.inferiors()[0].threads()[0]
|
20 |
| -while thread.is_valid(): |
| 18 | +disassembled_functions = set() |
| 19 | +while True: |
21 | 20 | frame = gdb.selected_frame()
|
22 | 21 | symtab = frame.find_sal().symtab
|
23 | 22 |
|
|
30 | 29 | # Not present for files without debug symbols.
|
31 | 30 | source_path = '???'
|
32 | 31 | if symtab:
|
33 |
| - #source_path = symtab.fullname() |
34 | 32 | source_path = symtab.filename
|
35 | 33 |
|
36 | 34 | # Not present for files without debug symbols.
|
|
46 | 44 | if symbol.is_argument:
|
47 | 45 | args += '{} = {}, '.format(symbol.name, symbol.value(frame))
|
48 | 46 |
|
49 |
| - # Mark new breakpoints. |
50 |
| - while block: |
51 |
| - if block.function: |
52 |
| - break |
| 47 | + # Put a breakpoint on the address of every funtion called from this function. |
| 48 | + # Only do that the first time we enter a function (TODO implement.) |
53 | 49 | start = block.start
|
54 |
| - end = block.end |
55 |
| - arch = frame.architecture() |
56 |
| - pc = gdb.selected_frame().pc() |
57 |
| - instructions = arch.disassemble(start, end - 1) |
58 |
| - for instruction in instructions: |
59 |
| - print('{:x} {}'.format(instruction['addr'], instruction['asm'])) |
| 50 | + if not start in disassembled_functions: |
| 51 | + disassembled_functions.add(start) |
| 52 | + end = block.end |
| 53 | + arch = frame.architecture() |
| 54 | + pc = gdb.selected_frame().pc() |
| 55 | + instructions = arch.disassemble(start, end - 1) |
| 56 | + for instruction in instructions: |
| 57 | + # This is UGLY. I wish there was a disassembly Python interface to GDB, |
| 58 | + # like https://github.com/aquynh/capstone which allows me to extract |
| 59 | + # the opcode without parsing. |
| 60 | + if instruction['asm'].split()[0] == 'callq': |
| 61 | + gdb.Breakpoint('*{}'.format(instruction['addr']), internal=True) |
60 | 62 |
|
61 | 63 | print('{}{} : {} : {}'.format(
|
62 | 64 | stack_depth * depth_string,
|
63 | 65 | source_path,
|
64 | 66 | frame.name(),
|
65 | 67 | args
|
66 | 68 | ))
|
| 69 | + # We are at the call instruction. |
67 | 70 | gdb.execute('continue', to_string=True)
|
| 71 | + if thread.is_valid(): |
| 72 | + # We are at the first instruction of the called function. |
| 73 | + gdb.execute('stepi', to_string=True) |
| 74 | + else: |
| 75 | + break |
0 commit comments