在GDB中,可以从函数的开始给出相对地址(以行为单位)



主题行基本上说明了一切。

如果我根据文件和行号给出位置,那么当我编辑文件时,该值可以改变。事实上,如果我在重构期间编辑多个函数,它往往会以一种不方便的方式经常更改。但是,如果它相对于函数的开头(line-),则不太可能改变。

如果不可能从函数的开始给出行偏移量,那么可能使用方便变量来模拟它吗?也就是说,如果我将声明方便变量映射到一个特定的函数的开始(一个列表,我将保持更新)?

根据help break,这两个似乎都不可用,但我想我最好问清楚。


(gdb) help break
Set breakpoint at specified line or function.
break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]
PROBE_MODIFIER shall be present if the command is to be placed in a
probe point.  Accepted values are `-probe' (for a generic, automatically
guessed probe type) or `-probe-stap' (for a SystemTap probe).
LOCATION may be a line number, function name, or "*" and an address.
If a line number is specified, break at start of code for that line.
If a function is specified, break at start of code for that function.
If an address is specified, break at that exact address.
With no LOCATION, uses current execution address of the selected
stack frame.  This is useful for breaking on return to a stack frame.
THREADNUM is the number from "info threads".
CONDITION is a boolean expression.
Multiple breakpoints at one place are permitted, and useful if their
conditions are different.
Do "help breakpoints" for info on other commands dealing with breakpoints.

将此添加到gdb是一个长期的请求。然而,它现在并不存在。对于Python来说,这可能是可能的,但可能不是完全可能的,因为Python目前无法访问所有断点重新设置事件(因此断点可能只工作一次,但不能在重新运行或库加载或其他低级更改时工作)。

然而,引用的文本显示了一种更好的方法——使用探测点。这些就是所谓的"SystemTap探测点",但实际上它们更像是一个通用的ELF + GCC特性——它们起源于SystemTap项目,但不依赖于它。这使您可以在源代码中标记一个点,并轻松地在其上放置一个断点,而不管对源代码进行了其他编辑。它们已经在linux发行版中用于标记unwind和跳远运行时例程中的特殊位置,以使调试工作在这些情况下很好地进行。

我明白这是一个老问题,但即使在2017年,我仍然找不到更好的解决方案。这里有一个Python解决方案。也许它不是最健壮/最干净的,但它在许多实际场景中工作得很好:

class RelativeFunctionBreakpoint (gdb.Breakpoint):
    def __init__(self, functionName, lineOffset):
        super().__init__(RelativeFunctionBreakpoint.calculate(functionName, lineOffset))
    def calculate(functionName, lineOffset):
        """
        Calculates an absolute breakpoint location (file:linenumber)
        based on functionName and lineOffset
        """
        # get info about the file and line number where the function is defined
        info = gdb.execute("info line "+functionName, to_string=True)
        # extract file name and line number 
        m = re.match(r'Line[^d]+(d+)[^"]+"([^"]+)', info)
        if not m:
            raise Exception('Failed to find function %s.' % functionName)
        line = int(m.group(1))+lineOffset #add the lineOffset
        fileName = m.group(2)
        return "%s:%d" % (fileName, line)
使用

:

基本:

    RelativeFunctionBreakpoint("yourFunctionName", lineOffset=5)

自定义断点:

class YourCustomBreakpoint (RelativeFunctionBreakpoint):
    def __init__(self, funcName, lineOffset, customData):
        super().__init__(funcName, lineOffset)
        self.customData = customData
    def stop(self):
        # do something
        # here you can access self.customData
        return False   #or True if you want the execution to stop

方案优点

  • 相对快,因为断点只设置一次,在执行开始之前
  • 对源文件中的更改是健壮的,如果它们不影响
  • 的功能

Disadvatages

  • 当然,它对函数本身的编辑并不健壮
  • 信息行funcName gdb命令的输出语法更改不健壮(可能有更好的方法来提取文件名和行号)
  • ?你指出

最新更新