【问题标题】:Debugging without symbols?没有符号的调试?
【发布时间】:2020-04-06 21:54:50
【问题描述】:

我有一个应该失败的简单 .c 文件(我知道它失败的地方,我故意把错误放在那里):

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  if (argc != 2) {
    fprintf(stderr, "Usage: %s argument\n", argv[0]);
    return EXIT_FAILURE;
  }

  char *hello = "hello";
  *hello = 'H';

  fprintf(stdout, "%s, %s!\n", hello, argv[1]);

  return EXIT_SUCCESS;
}

第 1 部分) 我将其保存为“hello.c”并在不使用 gcc hello.c -o hello 调试标志的情况下进行编译。

然后,我希望逐行通过 main 函数。我尝试按如下方式使用 gdb:

  1. 运行gdb ./hello

  2. 通过break main设置断点

  3. 运行run 123

  4. s -> 失败

结果如下:

(gdb) info func
All defined functions:

Non-debugging symbols:
0x0000000000000568  _init
0x0000000000000590  fprintf@plt
0x00000000000005a0  __cxa_finalize@plt
0x00000000000005b0  _start
0x00000000000005e0  deregister_tm_clones
0x0000000000000620  register_tm_clones
0x0000000000000670  __do_global_dtors_aux
0x00000000000006b0  frame_dummy
0x00000000000006ba  main
0x0000000000000740  __libc_csu_init
0x00000000000007b0  __libc_csu_fini
0x00000000000007b4  _fini
(gdb) break main
Breakpoint 1 at 0x6be
(gdb) r
Starting program: /mnt/c/Users/User/Documents/Debugging/hello

Breakpoint 1, 0x00000000080006be in main ()
(gdb) s
Single stepping until exit from function main,
which has no line number information.
__fprintf (stream=0x7fffff3ec680 <_IO_2_1_stderr_>, format=0x80007c4 "Usage: %s argument\n") at fprintf.c:27
27      fprintf.c: No such file or directory.

为什么会这样?为什么通过尝试查找文件 fprintf 会失败?认为预处理的标头应该处理所需的实现代码。

第 2 部分) 但是,当我使用 -g 编译时,由于某种原因它可以工作。但是在 gdb 中运行程序并没有像预期的那样产生分段错误:/ 为什么?

再次,请参阅:

$ ./hello 123
Segmentation fault (core dumped)

但是

(gdb) run 123
Starting program: /mnt/c/Users/NichlasDesktop/Documents/uni/Compsys/Exercises/Debugging/exercise_code/hello 123
Hello, 123!
[Inferior 1 (process 632) exited normally]

【问题讨论】:

  • “但在 gdb 中运行程序不会产生预期的分段错误”。你的期望是不正确的。写入字符串常量是未定义的行为。注意,UB 并不意味着“总是会崩溃”。这意味着我们不确定行为会是什么 - 它在某些情况下可能会崩溃,在某些情况下可能会起作用,并且可能完全有其他一些行为。
  • 查看 valgrind 以检查您的内存访问和更多(内存泄漏、未初始化的内存等),它是一组非常有用的工具,即使您认为您的代码没问题
  • char *hello = "hello"; *hello = 'H'; 是未定义的行为,您不能依赖它。
  • char *hello = "hello"; 是一个文字字符串。它是只读的。
  • 你是告诉它通过输入s 进入它的人:-)。如果您不想介入,请改用n

标签: c debugging gdb


【解决方案1】:

第 1 部分)

s -&gt; fails

没有调试信息,gdb 无法将指令映射到源代码 - 文件路径和行号。 s/step 命令告诉gdb 执行与源语言中的当前语句相对应的指令。 gdb 无法分辨那是什么,所以它一直持续到代码中源位置(“SPOS”)信息可用的任何地方。这恰好在定义 fprintf 的 libc 中。但是 fprintf 的源代码在您的环境中不可用,因此该消息。

您可以使用si/stepi 命令单步执行各个指令,这不需要提供调试信息。

如果你从那一点继续执行,你没有显示会发生什么,我怀疑它最终会遇到分段错误。

为什么会这样?为什么通过尝试查找文件 fprintf 会失败?认为预处理的标头应该处理所需的实现代码。

这不是标题。它们不包含源代码。

第 2 部分)当我使用 -g 进行编译时,由于某种原因它可以工作。但是在 gdb 中运行程序并没有像预期的那样产生分段错误:/ 为什么?

gdb 或任何其他调试器将安排可执行文本段映射为私有而不是像通常的运行情况那样共享(mmapMAP_PRIVATE 而不是 MAP_SHARED)。这是因为调试器需要文本段是可写的,以便可以覆盖指令以插入断点等。

您输入的“hello”是一个常量字符串文字,存储在可执行文件的只读文本段中。这就是为什么在正常运行期间写入它会导致分段错误 - 文本段被映射共享。但是在调试器内部,文本段被映射为私有的,因此您可以对其进行写入。

【讨论】:

    猜你喜欢
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    • 2011-03-05
    • 2013-12-06
    • 1970-01-01
    相关资源
    最近更新 更多