代码之家  ›  专栏  ›  技术社区  ›  yves Baumes

如何在gdb堆栈跟踪充满''时调试分段错误???

  •  13
  • yves Baumes  · 技术社区  · 16 年前

    我的可执行文件包含符号表。但堆栈跟踪似乎被覆盖。

    如何从核心获取更多信息?例如,有没有方法检查堆?查看填充堆的对象实例以获取一些线索。不管怎样,任何想法都是值得赞赏的。

    8 回复  |  直到 13 年前
        1
  •  14
  •   rook    16 年前

    我是一个C++程序员,我遇到这个问题的次数比我承认的要多。您的应用程序正在破坏堆栈的很大一部分。可能是损坏堆栈的函数在返回时也会崩溃。原因是因为返回地址被覆盖了,这就是gdb的堆栈跟踪被弄乱的原因。

    我就是这样调试这个问题的:

    1)逐步浏览应用程序,直到它崩溃。(查找返回时崩溃的函数)。

    2)确定函数后,在函数的第一行声明一个变量:

    int canary=0;
    

    (它必须是第一行的原因是该值必须位于堆栈的最顶端。此“canary”将在函数的返回地址之前被覆盖。)

    3)在金丝雀上放置一个变量表,跨过函数和金丝雀的时间!=0,则发现缓冲区溢出!另一种可能是它为when canary设置了一个变量断点!=0,然后正常运行程序,这稍微容易一点,但不是所有IDE的支持变量断点。

    编辑: 我已经和我办公室的一位高级程序员谈过了,为了理解核心转储,您需要解析它的内存地址。找出这些地址的一种方法是查看二进制文件的映射文件,这是人类可读的。下面是使用gcc生成映射文件的示例:

    gcc -o foo -Wl,-Map,foo.map foo.c
    

    这是一个拼图,但仍然很难获得正在崩溃的函数的地址。如果您在现代平台上运行这个应用程序,那么aslr可能会使核心转储中的地址无用。aslr的一些实现会随机化二进制文件的函数地址,这使得核心转储毫无价值。

        2
  •  4
  •   deddihp    16 年前
    1. 你得用调试器来检测,valgrind没问题
    2. 在编译代码时,请确保添加了-wall选项,这样编译器就会告诉您是否有错误(确保您的代码中有任何警告)。

    示例:g c c-wall-g-c-o oke.o oke.c
    三。确保您还有-g选项来生成调试信息。可以使用某些宏调用调试信息。以下宏对我非常有用:

    __LINE__ :告诉你线路

    __FILE__ :告诉您源文件

    __func__ :告诉您函数

    1. 我认为仅仅使用调试器是不够的,您应该习惯于最大限度地提高编译器的能力。

    希望这会有帮助

        3
  •  2
  •   Ogre Psalm33    14 年前

    DR: 函数中的超大局部变量声明是在堆栈上分配的,在某些平台和编译器组合中,这些声明可能会溢出并损坏堆栈。

    只是为了给这个问题增加另一个潜在的原因。我最近在调试一个非常相似的问题。使用应用程序和核心文件运行gdb将产生如下结果:

    Core was generated by `myExecutable myArguments'.
    Program terminated with signal 6, Aborted.
    #0  0x00002b075174ba45 in ?? ()
    (gdb)
    

    这是极其无益和令人失望的。在网上搜索了几个小时后,我找到了一个论坛,讨论我们使用的特定编译器(英特尔编译器)的默认堆栈大小比其他编译器小,并且大型局部变量可能会溢出并损坏堆栈。看着我们的密码,我找到了罪魁祸首:

    void MyClass::MyMethod {
       ...
       char charBuffer[MAX_BUFFER_SIZE];
       ...
    

    }

    答对了!我发现最大缓冲区大小设置为10000000,因此正在分配一个10MB的局部变量 在堆栈上! 在将实现更改为使用共享ptr并动态创建缓冲区之后,程序突然开始正常工作。

        4
  •  1
  •   Tronic    16 年前

    尝试使用valgrind内存调试器运行。

        5
  •  1
  •   t0mm13b    16 年前

    要确认的是,你的可执行文件是在发布模式下编译的,即没有调试符号……这可以解释为什么会有??尝试重新编译 -g 切换“包括调试信息并将其嵌入到可执行文件中”…除此之外,我不知道您为什么要这样做'?“……”

        6
  •  1
  •   Zan Lynx    16 年前

    不是真的。当然,你可以在记忆中四处挖掘,看看事情。但是如果没有堆栈跟踪,您就不知道如何到达您所在的位置或参数值是什么。

    但是,堆栈损坏的事实告诉您需要查找写入堆栈的代码。

    • 覆盖堆栈数组。这可以通过显而易见的方式来实现,也可以通过调用具有错误大小参数或错误类型指针的函数或系统调用来实现。
    • 在函数返回后使用指向函数的局部堆栈变量的指针或引用。
    • 将指向堆栈值的指针转换为大小错误的指针并使用它。

    如果你有一个unix系统,“valgrind”是一个很好的工具来发现这些问题。

        7
  •  0
  •   Mark B    16 年前

    我假设既然您说“我的可执行文件包含符号表”,那么您就编译并链接了-g,并且您的二进制文件没有被剥离。

    我们可以确认一下: 字符串-grep函数名应该存在

    还可以尝试在核心ans上使用pstack,看看它在获取调用堆栈方面是否做得更好。在这种情况下,与gcc/g++版本相比,gdb听起来已经过时了。

        8
  •  0
  •   ЯegDwight kri    13 年前

    听起来你在你的机器上使用的glibc版本与corefile在生产中崩溃时的版本不同。获取“ldd./appname”输出的文件并将其加载到您的计算机上,然后告诉gdb在哪里查找;

    set solib-absolute-prefix /path/to/libs