Oracle® Developer Studio 12.5:使用 dbx 调试程序

退出打印视图

更新时间: 2016 年 6 月
 
 

在断点上设置过滤器

dbx 中,大多数事件管理命令都支持可选的事件过滤器修饰符。最简单的过滤器是指示 dbx 在程序执行到断点或跟踪处理程序处后或出现数据更改断点后测试条件。

如果相应过滤器条件的求值结果为 true(非 0),则会应用事件命令,且程序在断点处停止执行。如果条件的求值结果为 false (0),dbx 会继续执行程序,就好像从未发生过事件。

要设置包含过滤器的断点,请将可选的 - if condition 修饰符语句添加到 stoptrace 命令的末尾。

条件可以是任何有效的表达式(包括函数调用),其返回值是布尔值或输入命令时所用语言表示的整数值。

对于像 inat 这样基于位置的断点,用来解析条件的作用域便是断点位置的作用域。否则,条件的作用域是输入时的作用域,而不是事件发生时的作用域。可能必须使用反引号操作符(请参见反引号操作符)来精确指定作用域。

以下两个过滤器是不一样的:

stop in foo -if a>5
stop cond a>5

前者在 foo 处中断并测试条件。后者自动单步执行并测试条件。

使用条件过滤器限定断点

要设置包含过滤器的断点,请将可选的 -if condition 修饰符语句添加到 stoptrace 命令的末尾。condition 可以是任何有效的表达式(包括函数调用),其返回值是布尔值或输入命令时所用语言表示的整数值。

可以将函数调用用作断点过滤器。在以下示例中,如果字符串 str 中的值是 abcde,则在函数 foo() 中停止执行:

(dbx) stop in foo -if !strcmp(“abcde”,str)

您可以使用包含函数调用的 –if 选项:

stop in lookup –if strcmp(name, "troublesome")==0

下面是使用包含监视点的条件过滤器示例:

(dbx) stop access w &speed -if speed==fast_enough

使用调用方过滤器限定断点

没有经验的用户有时会将设置条件事件命令(监视类型命令)与使用过滤器混淆。从概念上来说,“监视”会创建在执行每行代码前必须检查的前提条件(在监视的作用域内)。但即便是有条件触发的断点命令也可以连接过滤器。

假设有这样一个示例:

(dbx) stop access w &speed -if speed==fast_enough

此命令指示 dbx 监视变量 speed;如果变量 speed 已写入(“监视”部分),则 -if 过滤器生效。dbx 检查 speed 的新值是否等于 fast_enough。如果不等,程序会继续执行,而“忽略”stop 命令。

dbx 语法中,过滤器以命令末尾处的 [-if condition] 形式表示。

stop in function [-if condition]

假设有一个包含以下代码的简单示例:

44:     if(open(filename, ...) == -1)
45:          return "Error";

您可以使用以下命令在出现某一特定故障时停止执行,例如,open()ENOENT

(dbx) stop at 45 -if errno == 2

使用过滤器,可以非常方便地在局部变量上放置数据更改断点。在以下示例中,当前作用域处在函数 foo() 中,而相关变量 index 处在函数 bar() 中。

(dbx) stop access w &bar`index -in bar

bar`index 用于确保选取的是函数 bar() 中的 index 变量,而不是函数 foo 中的 index 变量或名为 index 的全局变量。

    -in bar 表示以下内容:

  • 进入函数 bar() 时自动启用断点。

  • 在执行 bar()(包括所调用的任何函数)期间,断点保持启用状态。

  • bar() 返回时自动禁用断点。

某些其他函数的其他局部变量可能会重用与 index 对应的堆栈位置。-in 用于确保仅当访问 bar`index 时触发断点。

过滤器和多线程

如果在多线程程序中设置的断点中使用了包含多个函数调用的过滤器,dbx 将在到达断点时停止所有线程的执行,然后对条件求值。 如果满足条件且调用了函数, dbx 便会恢复执行调用期间内的所有线程。

例如,可以在多线程应用程序中许多线程调用 lookup() 之处设置以下断点:

(dbx) stop in lookup -if strcmp(name, “troublesome”) == 0

dbx 会在线程 t@1 调用 lookup() 时停止,并对条件求值,然后调用恢复所有线程的 strcmp()。如果在函数调用期间 dbx 在另一个线程中遇到断点,便会发出警告,例如:

event infinite loop causes missed events in the following handlers:
...
Event reentrancy
first event BPT(VID 6m TID 6, PC echo+0x8)
second event BPT*VID 10, TID 10, PC echo+0x8)
the following handlers will miss events:
...

在这种情况下,如果可以确定条件表达式中调用的函数不会抓取互斥锁,则可使用 -resumeone 事件规范修饰符强制 dbx 只恢复在其中遇到断点的第一个线程。 例如,可设置以下断点:

(dbx) stop in lookup -resumeone -if strcmp(name, “troublesome”) == 0

    在有些情况下,-resumeone 修饰符并不能防止出现问题。例如,它在以下情况下不起作用:

  • 由于条件以递归方式调用 lookup(),所以 lookup() 上的第二个断点与第一个断点出现在同一个线程中。

  • 运行条件的线程放弃控制权,将其交给另一个线程。

有关详细信息,请参见事件规范修饰符