【问题标题】:How to debug standard c library functions like printf?如何调试像 printf 这样的标准 c 库函数?
【发布时间】:2018-01-21 13:19:46
【问题描述】:

我想调试 printf 函数,所以当我进入 printf 函数(gdb 调试器)时,它显示了这个:

__printf (format=0x80484d0 " my name is Adam") at printf.c:28
28  printf.c: No such file or directory.

这是什么意思?

当我再次开始 step 时,就会有更多这样的语句。

请帮助我理解这一点。

【问题讨论】:

  • 为什么要调试printf?你认为那里隐藏着错误吗?
  • 您应该假设系统提供的函数,尤其是诸如printf() 之类的核心函数是没有故障的,并且问题出在您使用它的代码中,而不是函数本身。如果您使用的是现代编译器,请确保您使用尽可能多的警告选项进行编译,并且在出现任何警告时甚至不要尝试运行代码。 (使用 GCC,我要求 gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes … 干净,即使是来自 SO 问题的代码。有时来自 SO 的代码必须区别对待,但不经常。)
  • 没有调试版本的库吗?
  • 你的操作系统是什么?您需要安装“glibc-debug”包。确切的包名称取决于您使用的操作系统。
  • 如果您仍然好奇(并且稍微偏离主题),请阅读此博客:blog.hostilefork.com/where-printf-rubber-meets-road 非常详细地了解printf 最终如何写出一个字符。

标签: c linux debugging gdb libc


【解决方案1】:

我认为这很清楚。 gdb 有一个地方期望源代码在,所以下载 glibc 的源代码并放在那里。我认为错误消息包含完整路径。

如果它是一个 linux 发行版,事实上它相当简单,因为通常也会提供源包。否则您需要自己查找源代码,注意它必须与用于编译 c 库组件的版本完全相同,而不仅仅是相同的版本,因为分销商经常会更改源代码。

【讨论】:

  • 不像听起来那么容易:需要与用于编译库的源代码完全相同相同。通常,这意味着您需要获取操作系统/发行版的调试符号和源代码包:)
  • @MarcusMüller 如果它是一个 linux 发行版,实际上它相当简单,因为通常也会提供源包。它hitnk我会将这条评论的第一部分放在答案中,我并没有说这很容易,只是错误消息清楚地说明了问题所在。
  • 听起来很困难... :( 我在 Ubuntu 上使用 Clion,然后单击“step into”给我汇编代码。
【解决方案2】:

好吧,为了让调试器向您显示编译到您正在使用的二进制文件中的代码,您需要在某个地方使用原始代码。

你似乎没有,所以你的调试器找不到它。

请注意,您通常想调试 std 库函数的源代码,而只想调试它们被调用的方式。为此,操作系统的常用“调试符号”包是最佳选择。

【讨论】:

  • 好话。就像 OP 怀疑错误在标准库中一样,而在他的代码中很有可能。但是,也许 OP 想要检查这些功能是如何工作的。
  • @IharobAlAsimi @Marcus Müller 大家好,想在这里问一个问题。如果我理解正确的话,这里有 3 种文件: 1. C 文本源代码 2. C 二进制源代码 3. 带有调试信息的 C 二进制源代码。所以我可以调试类型 1 和 3 但不能调试 2,对吗?
  • 不,你没有正确理解:“二进制源代码”不存在。这是自相矛盾的。您的意思是“1. C 源代码,2. 机器代码 3. 带有调试信息的机器代码”。您可以调试所有三个,但方式不同。
【解决方案3】:

正如其他人回答的那样,GDB 无法找到源文件。

对于 C 运行时库,Linux 发行版可能提供您可以安装的 debuginfo RPM,它可能允许 GDB 查看文件。例如:

$ yum search glibc-debuginfo

...

glibc-debuginfo.x86_64 : Debug information for package glibc
glibc-debuginfo-common.x86_64 : Debug information for package glibc

...

glibc 包和glibc-debuginfo 是一对匹配的。没有显式的依赖,但是glibc-debuginfo包除非和glibc的同一个版本匹配,否则是不行的。

如果您在某处解压了源文件,但不是 GDB 期望的位置,您可以尝试使用 directoryset substitute-path 命令让 GDB 知道源文件的位置。

directory 命令告诉 GDB 在它试图查找的任何源文件路径之前添加一个前缀。例如,如果源代码树实际上位于/tmp 下,您可以使用:

(gdb) directory /tmp

set substitute-path 命令用于告诉 GDB 用不同的路径前缀替换源文件路径中的匹配前缀。例如,如果编译后的源文件在/build/path/source.c,但在调试时源文件实际上在/usr/home/alice/release-1.1/source.c,那么你可以使用:

(gdb) set substitute-path /build/path /usr/home/alice/release-1.1

该命令假定您仅指定了完整的路径名,因此它不会对 /build/pathological/source.c 执行替换。

【讨论】:

    猜你喜欢
    • 2019-11-25
    • 2011-10-25
    • 1970-01-01
    • 2015-03-15
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 2012-02-24
    相关资源
    最近更新 更多