Oracle® Solaris Studio 12.4:使用 dbx 调试程序

退出打印视图

更新时间: 2015 年 1 月
 
 

缺省情况下,选定的表达式在求值前扩展宏,包括使用以下项指定的表达式:printdisplay watch 命令,stoptracewhen 命令的 –if 选项,以及 $[] 构造。宏扩展还适用于 IDE 或 dbxtool 中的气球表达式求值和监视。

宏扩展的其他用途

宏扩展适用于 assign 命令中的变量和表达式。

call 命令中,宏扩展适用于正被调用的函数的名称以及正在传递的参数。

macro 命令可以采用任意表达式和宏,并可以扩展宏。 例如:

(dbx) macro D(1, 2)
    Expansion of: D(1, 2)
              is: d(1,2)

如果赋予 whatis 命令一个宏,则它显示宏的定义。 例如:

(dbx) whatis B
    #define B(x) b(x)

如果赋予 which 命令一个宏,则它显示作用域中当前活动的宏在何处定义。 例如:

(dbx) which B2
    `a.out`macro_wh.c`B2    # defined at defs2.h:3
            # included from defs1.h:3
            # included from macro_wh.c:23

如果赋予 whereis 命令一个宏,则它显示已定义宏的所有位置。 该列表只限于 dbx 已读取调试信息的模块。例如:

(dbx) whereis U
    macro:          U       # defined at macro_wh.c:21
    macro:          U       # undefined at defs1.h:5

dbxenv 变量 macro_expand 控制这些命令是否扩展宏。 缺省情况下,它设置为 on

一般情况下,dbx 命令中的 +m 选项会导致命令跳过宏扩展。–m 选项强制进行宏扩展,即使 dbxenv 变量 macro_expand 设置为 off 也是如此。$[] 构造中的 –m 选项是一个例外,其中 –m 仅使宏被扩展,不进行求值。该例外有助于 shell 脚本中的宏扩展。

宏定义

dbx 可以采用两种方法识别宏定义:

  • 如果使用缺省 DWARF 格式调试信息,在以 –g3 选项进行编译时,编译器会提供定义。如果编译时指定 –xdebugformat=stabs 选项,则不提供定义。

  • dbx 可以通过略读源文件及其包含文件来重新创建定义。准确的重新创建取决于对原始源文件及包含文件的访问情况。这还取决于所使用编译器的路径名的可用性以及编译器选项(如 –D–I)。可以从 Oracle Solaris Studio 编译器(但不能从 GNU 编译器)以 DWARF 和 stabs 格式提供该信息。有关确保成功略读的信息,请参见略读 (skimming) 错误使用 pathmap 命令改进略读 (skimming)

dbxenv 变量 macro_source(请参见Chapter 3, 定制 dbx 中的 Table 3–1)可控制 dbx 使用两种方法中的哪一种来识别宏定义。

在选择希望 dbx 使用的方法时,需要考虑多种因素。

编译器和编译器选项

选择宏定义方法时要考虑的一个因素是不同类型信息的可用性,这些信息取决于用于生成代码的编译器和编译器选项。下表显示了可根据编译器和调试信息选项选择的方法。

表 C-1  可用于各种生成选项的宏定义方法
编译器
–g 选项
调试信息格式
起作用的方法
Oracle Solaris Studio
–g
DWARF
略读
Oracle Solaris Studio
–g
stabs
略读
Oracle Solaris Studio
–g3
DWARF
略读和通过编译器
Oracle Solaris Studio
–g3
stabs
略读(不支持 –g3 选项与 –xdebugformat=stabs 选项)
GNU
–g
DWARF
两者均无
GNU
–g
stabs
N/A
GNU
–g3
DWARF
通过编译器
GNU
–g3
stabs
N/A

功能方面的权衡

选择宏定义方法时另一个要考虑的因素是根据选择的方法在功能方面进行权衡:

  • 可执行文件的大小。略读方法的主要优点是不需要使用 –g3 选项进行编译,因为该方法适用于使用 –g 选项编译而生成的较小可执行文件。

  • 调试格式。略读适用于 DWARF 和 stabs。使用 –g3 选项进行编译以通过编译器获得定义仅适用于 DWARF。

  • 速度。第一次针对 dbx 尚未读取调试信息的模块对表达式求值时,略读最多需要一秒钟。

  • 精确度。使用 –g3 选项进行编译时,编译器提供的信息比略读提供的信息更稳定、更准确。

  • 生成环境的可用性。略读要求编译器、源代码文件以及包含文件在调试过程中可用。dbx 不会检查这些过期的项,因此,如果这些项有可能发生更改,准确性可能会下降,所以使用 –g3 选项进行编译可能好于依靠略读。

  • 在与编译代码的系统不同的系统上进行调试。如果在系统 A 上编译代码而在系统 B 上进行调试,则 dbx 使用 NFS 并借助 pathmap 命令访问系统 A 上的文件。

    pathmap 命令还有助于在略读期间访问文件。尽管,它适用于程序的源文件和包含文件,但它可能不适用于系统包含文件,这是因为 /usr/include 通常不通过 NFS 来提供。因此,宏定义将从调试系统(而不是生成系统)的 /usr/include 中提取。

    您可以选择了解并容许系统包含文件之间可能存在的差异,或者选择使用 –g3 选项进行编译。

限制

  • 虽然 Fortran 编译器通过 cpp(1) 函数或 fpp(1) 函数支持宏,但 dbx 不支持 Fortran 的宏扩展。

  • dbx 会忽略使用 –g3 选项和 –xdebugformat=stabs 选项进行编译而生成的宏信息。

    有关 stabs 索引的更多信息,请参见 Stab 接口指南(可在 install-dir/solarisstudio12.4/READMEs/stabs.pdf 路径中找到)。

  • 略读适用于使用 –g 选项和 –xdebugformat=stabs 选项编译的代码。

略读 (skimming) 错误

如果不使用 –g3 选项编译代码,而且将 macro_source dbxenv 变量设置为 skim_unless_compilerskim,则您将依赖宏略读。

若要针对模块成功进行略读,需要满足以下条件:

  • 必须使用 –g 选项通过 Oracle Solaris Studio 编译器编译了模块。

  • 用于编译模块的编译器必须可由 dbx 访问。

  • 模块的源文件必须可由 dbx 访问。

  • 模块源代码所含的文件必须可用,即,编译模块时指定给 –I 选项的路径必须可由 dbx 访问。

  • 源代码的语法必须合理。例如,代码的注释不能包含未结束的字符串,或是代码不能缺少 #endif

如果源代码或包含文件不可由 dbx 访问,可以使用 pathmap 命令使其可以访问。

使用 pathmap 命令改进略读 (skimming)

如果在编译后移动源文件,或是在一台计算机上生成而在另一台计算机上进行调试,或是发生查找源文件和对象文件中所述的其他情况之一,则宏略读可能无法在其略读的文件中找到包含文件。与无法找到文件的其他情况一样,解决方案是使用 pathmap 命令帮助宏略读器定位包含目录。 例如,假设使用选项 –I/export/home/proj1/include 进行编译,而且代码中包含语句 #include "module1/api.h"。然后,如果将 proj1 重命名为 proj2,则以下 pathmap 命令将帮助宏略读器定位文件:

pathmap /export/home/proj1 /export/home/proj2

pathmap 不适用于用来编译原始代码的编译器。

处理宏时,必须重新装入应用程序,以使路径映射生效,与找不到文件时的其他情况不同,可以使用 pathmap 命令在路径映射过程中进行更改,这些更改会立即生效。

在一台计算机上生成而在另一台计算机上进行调试时,pathmap 命令可帮助 dbx 找到正确的文件。然而,系统包含文件(如 /usr/include/stdio.h)通常不会从生成计算机中导出,因此宏略读器可能会使用调试计算机中的文件。在某些情况下,系统包含文件可能在调试计算机上不可用。而且,特定于系统的宏和与系统相关的宏的值在调试计算机和生成计算机中也可能不相同。

如果 pathmap 命令不能解决略读问题,则考虑使用 –g3 选项编译代码,并将 macro_source dbxenv 变量设置为 skim_unless_compilercompiler