0%

How to customize GDB breakpoints

In most cases, the built-in GDB features are good enough for debugging. It guides you along the core logic of a large open-sourced project by stepping over function calls. In some cases, however, stepping in and over function calls may drive you crazy. For example, you may have function func_a() and func_b() that calls func_c() through many stack frames, and func_b() calls it much more frequent than function func_a(). What’s worse, func_a() itself rearely calls func_c() and you don’t know which part of the code called it. It would be quite hard for me to trigger the func_c() called by func_a().

I have this problem when reading some kernel codes because the functions are called via function pointers and the function is called asynchronouly. I need to know when the code calls the kernel built-in kernel queue API. Therefore I need to a breakpoint that filters out ones called by my code of interests on an older function frame.

Luckily, GDB supports using python to implement customized breakpoint. Below is my example gdb_script.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
import gdb
import argparse

class CustomizedBreakPoint(gdb.Breakpoint):
def __init__(self, spec, caller_contain: str):
super(CustomizedBreakPoint, self).__init__(spec)
self.caller_condition_ = caller_condition
def stop(self) -> bool:
# customize your condition here, return true when condition is satisfied
# this implementation checks if any function in the stack
# is named self.caller_condition_
frame = gdb.newest_frame()
while frame:
if(frame.name() == self.caller_condition_):
return True
frame = frame.older()
return False

class MyCommand(gdb.Command):
def __init__(self):
super(MyCommand, self).__init__("add_custom_break", gdb.COMMAND_NONE)
def invoke(self, arg, from_tty):
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--condition", type = str, help = "caller that must be contained")
parser.add_argument("-s", "--spec", type = str, help = "breakpoint location specification")
args = parser.parse_args(arg.split())
CustomizedBreakPoint(args.spec, args.condition)

MyCommand()

More details could be found in implementing commands and implementing new breakpoints.

To use the customized break point, first use gdb to load the executable binary file.

1
gdb -tui binary_file

Then import the command in the interactive GDB interface.

1
source gdb_script.py

Finally, tag the breakpoint using our new command. Now you are good to go!

1
2
add_custom_break -s file.c:100 -c function_name
continue