我如何让GDB告诉我记忆特性一个给定的地址

How do I get gdb to tell me memory characteristics a given address

本文关键字:一个 地址 GDB 告诉我 记忆      更新时间:2023-10-16

我有一个核心的GDB会话,它表明在阅读其成员之一时,指示器的解释中有一个segfault。该指针的价值无效。我认为这意味着该过程无法访问内存地址。如何从核心的验尸GDB会话中获取此信息?

例如,给定以下程序:

#include <iostream>
using namespace std;
int
main(int argc, char* argv[])
{
    int *ptr = new int(5);
    cout << "I can access it here: " << *ptr << endl;
    delete ptr;
    cout << "But I shouldn't do so here: " << *ptr << endl;
    return 0;
}

如果我使用GDB调试此程序:

$ g++ -g -Wall test.cc -o test
$ gdb ./test
(gdb) b 13
...
Breakpoint 1 at 0x400943: file test.cc, line 13.
(gdb) run
Starting program: /usr/home/nfs/bneradt/test/test
I can access it here: 5
Breakpoint 1, main (argc=1, argv=0x7fffffffe348) at test.cc:13
13          cout << "But I shouldn't do so here: " << *ptr << endl;
(gdb)

我可以从PTR获得哪种内存信息?我可以确定PTR指向释放内存吗?由于我要调试核心(不在上面的玩具测试中),所以我得到了SEG故障 - 即,从读取,而不是写入 - 指针,我想原来的内存位置已被淘汰,因此不是过程可访问的内存?我可以从GDB会话中确定吗?

gdb没有动态分配的概念,也不了解释放内存。它可以判断地址是否映射到过程地址空间:

gdb> info files
gdb> maintenance info sections

但是,由于您的程序已随着Sigsegv崩溃,因此您已经知道它已经尝试访问未倍率的地址。

其他工具可以检测到释放内存的访问。valgrind通常是您的朋友,但不是验尸后的调试。您需要在valgrind下运行该程序以洞悉其行为。

在删除指针时很少表示指针指向释放内存。通常,驻留在释放记忆中的指针本身被重复使用和覆盖。所以

int** ptrarr = new int*[5];
ptrarr[3] = new int(5);
// later
delete [] ptrarr;
// later still after many memory allocations
int* ptr = ptrarr[3]; // ptrarr points to freed memory; UB but no segfault
                      // ptr contains a seemingly random value
int num = *ptr;       // possible segfault

很难从非启发式可执行文件的验尸中提取此类信息。您需要熟悉mallocnew的内部工作,能够追逐其内部数据结构,并手工绘制其竞技场。这不是一项琐碎的任务。使用带有保留调试符号的标准库版本将有所帮助。

失败,您可以尝试绘制程序的内存,包括静态/全局变量,堆栈变量,上述指向的所有分配数据结构以及所有分配的数据结构中指向的所有分配数据结构。我知道没有能够从验尸转储自动执行此操作的工具,尽管从理论上讲,这种工具是可能的。

映射了程序内存,或者也许是其中的某些部分,您可以尝试找出不同类型的无关对象是否位于无效的指针所在的地址。如果是这样,您可以得出结论,两个对象之一可能是被释放后非法访问的释放记忆。