【问题标题】:Does GDB in RISC-V support Program Context aware breakpoint?RISC-V 中的 GDB 是否支持程序上下文感知断点?
【发布时间】:2021-02-14 17:06:30
【问题描述】:

我想了解现有 GDB for RISC-V 是否支持程序上下文感知断点?

通过程序上下文感知断点:我的意思是,当有 JAL 或 JALR 指令时,当有函数调用时,PC 会发生变化。在其他情况下,函数调用 ==> PC = PC + (Current Program Counter + 4) in Function Return : PC = PC - (Return address (ra register value) ).

我已经在我的 ubuntu(虚拟机)上安装了 fedora(risc-V)。由于它是虚拟机,我无法打印 PC 寄存器值,这就是为什么我无法检查它是否支持程序上下文感知断点?

我的第二个问题是:如何在我的 qemu risc-v 虚拟机上打印 PC 寄存器值?

#include<stdio.h>

int check_prime(int a)
{
int c; 
    for (c=2;c<a;c++)
    {
        if (a%c == 0 ) return 0; 
        if (c == a-1 ) return 1; 
    }
}

void oddn(int a)
{
    printf("oddn --> %d is an odd number \n",a);
    if (check_prime(a)) printf("oddn --> %d is a prime number\n",a);
}

int main()
{
    int a;
    a=7;
    if (check_prime(a)) printf("%d is a prime number \n",a);
        if (a%2==1) oddn(a);    

}

这是我尝试使用 GDB 断点的程序。

正如您在图片上看到的那样,它会中断两次(应该只中断一次)。 它也给出了错误:

Error in testing breakpoint condition:
Invalid data type for function to be called

【问题讨论】:

  • 即使有您的描述,也不清楚您所说的“程序上下文感知断点”是什么意思。 GDB 最终会在地址处放置断点。 GDB 可以根据文件和行号或函数名找出合适的地址,但在内部这些都映射到一个地址,即放置断点的位置。如果需要,您还可以在特定地址放置断点。 “程序上下文感知断点”有何不同?
  • 如果程序按顺序运行(在一个没有跳转的函数中)则程序计数器始终为 PC=PC+4,但只要有 JAL 或 JALR 程序计数器值变化超过 4(PC =PC+100 例如)。每当它进入 evenn 函数时,PC = PC + evenn_address,并且每当它返回 PC=PC - evenn_address 时。通过计算这些地址,我想在它从 functionD 到达 functionC 时设置断点。例如: 1. main --> functionD(不需要断点) 2. main --> functionC --> functionD(这里我要设置断点)(这是程序上下文)
  • 我可以重现您看到的错误。我认为有两件事可能会导致这个问题,(1)旧的 gdb 版本。这些函数是在 GDB 7.9 中添加的,因此如果您使用的是旧版本(show version 在 gdb 提示符下),或者 (2) 这些函数实际上是作为 GDB 附带的 Python 扩展实现的,请考虑更新。因此,您需要使用 Python 支持构建并正确安装的 GDB。在 gdb 提示符下键入 python print ("hello") 以检查您是否支持 Python。
  • 版本为:GNU gdb (GDB) 10.1,不支持python。据我所知,从 GDB 7.3 开始,它应该支持 python,但它不支持。
  • 如果您现在有一个支持 Python 的 GDB 版本,这是否意味着您遇到的 $_caller_is 问题现在已经解决了?

标签: gdb breakpoints fedora qemu riscv


【解决方案1】:

您要查找的内容记录在这里:

https://sourceware.org/gdb/current/onlinedocs/gdb/Convenience-Funs.html#index-_0024_005fstreq_002c-convenience-function

您应该查看$_caller_is$_caller_matches$_any_caller_is$_any_caller_matches

例如,要检查直接调用者是否是特定函数,我们可以这样做:

break functionD if ($_caller_is ("functionC"))

那么main -&gt; functionD不会触发断点,而main -&gt; functionC -&gt; functionD会触发断点。

我列出的便利函数都采用帧偏移量,可用于指定 GDB 将检查的帧($_caller_is$_caller_matches)或限制检查的帧范围($_any_caller_is 和 @987654332 @)。

【讨论】:

    【解决方案2】:

    https://sourceware.org/gdb/onlinedocs/gdb/Functions-In-Python.html

    编写新的便利函数 您可以在 Python 中实现新的便利功能。便利函数是 gdb.Function 类的子类的实例。

    函数:函数。init(名称) Function 的初始化程序向 GDB 注册新函数。参数名称是函数的名称,一个字符串。该函数将作为内部函数类型的便利变量对用户可见,其名称与给定名称相同。

    新函数的文档取自新类的文档字符串。

    *函数:Function.invoke (args) 当一个便利函数被求值时,它的参数被转换为 gdb.Value 的实例,然后函数的调用方法被调用。请注意,GDB 并没有预先确定便利函数的数量。相反,所有可用的参数都被传递给调用,遵循标准的 Python 调用约定。特别是,便利函数可以为参数设置默认值而不会产生不良影响。

    此方法的返回值用作其在封闭表达式中的值。如果返回一个普通的 Python 值,则按照通常的规则将其转换为 gdb.Value。

    以下代码 sn-p 显示了如何在 Python 中实现一个简单的便利函数:

    class Greet (gdb.Function):
      """Return string to greet someone.
    Takes a name as argument."""
    
      def __init__ (self):
        super (Greet, self).__init__ ("greet")
    
      def invoke (self, name):
        return "Hello, %s!" % name.string ()
    
    Greet ()
    

    最后一行实例化了类,并且是触发向 GDB 注册函数所必需的。根据 Python 代码读入 GDB 的方式,您可能需要显式导入 gdb 模块。

    现在你可以在表达式中使用函数了:

    (gdb) print $greet("Bob")
    $1 = "Hello, Bob!"
    

    【讨论】:

    • 我已经实现了greet.py 便利函数并将其复制到``` ~/gdb/python/lib/gdb/function/ ``` 但该函数仍然无法运行。它给出了 ``` Invalid data type for function to be called ``` 错误。可能是什么错误?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-12
    • 2023-04-09
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    相关资源
    最近更新 更多