nha*_*123 5 c++ memory pointers
在Windows平台上,我试图从我的变量所在的应用程序中转储内存.这是功能:
void MyDump(const void *m, unsigned int n)
{
const unsigned char *p = reinterpret_cast<const unsigned char *>(m);
char buffer[16];
unsigned int mod = 0;
for (unsigned int i = 0; i < n; ++i, ++mod) {
if (mod % 16 == 0) {
mod = 0;
std::cout << " | ";
for (unsigned short j = 0; j < 16; ++j) {
switch (buffer[j]) {
case 0xa:
case 0xb:
case 0xd:
case 0xe:
case 0xf:
std::cout << " ";
break;
default: std::cout << buffer[j];
}
}
std::cout << "\n0x" << std::setfill('0') << std::setw(8) << std::hex << (long)i << " | ";
}
buffer[i % 16] = p[i];
std::cout << std::setw(2) << std::hex << static_cast<unsigned int>(p[i]) << " ";
if (i % 4 == 0 && i != 1)
std::cout << " ";
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我怎么知道从哪个地址开始我的进程内存空间,所有变量都存储在哪里?我现在怎么样,这个区域有多长?
例如:
MyDump(0x0000 /* <-- Starts from here? */, 0x1000 /* <-- This much? */);
Run Code Online (Sandbox Code Playgroud)
最好的问候,
nhaa123
对这个问题的简短回答是你不能这样解决这个问题.进程在内存中的布局方式非常依赖于编译器和操作系统,并且不容易确定所有代码和变量所在的位置.要准确,完整地找到所有变量,您需要自己编写大部分调试器(或者从实际的调试器代码中借用它们).
但是,您可以稍微缩小问题的范围.如果你真正想要的只是一个堆栈跟踪,那么这些不是很难生成:如何在C中获取堆栈跟踪?
或者,如果您想检查堆栈本身,很容易获得指向堆栈当前顶部的指针(只需声明一个局部变量然后获取它的地址).获取堆栈底部的最简单方法是在main中声明一个变量,将其地址存储在全局变量中,然后将该地址用作"底部"(这很容易,但不是真正"干净").
获取堆的图片要困难得多,因为您需要了解堆的内部工作方式,以了解当前分配的堆的哪些部分.由于堆的大小基本上是"无限制的",如果您只是打印所有数据,即使是未使用的部分,那么要打印的数据非常多.我不知道有办法做到这一点,我强烈建议你不要浪费时间去尝试.
获取静态全局变量的图片并不像堆那么糟糕,但也很困难.它们存在于可执行文件的数据段中,除非您想要进行某些程序集和解析可执行格式,否则也要避免这样做.
你想要做的事情绝对是可能的,甚至还有工具可以提供帮助,但你必须做比我想象的更多的跑腿工作。
就您而言,您对“变量所在”特别感兴趣。Windows 上的系统堆 API将为您提供难以置信的帮助。该参考确实非常好,尽管它不是一个连续的区域,但 API 会告诉您变量在哪里。
但一般来说,由于不知道内存的布局位置,您将必须扫描进程的整个地址空间。如果您只想要数据,则还必须对其进行一些过滤,因为代码和堆栈废话也在那里。最后,为了避免转储地址空间时出现段错误,您可能需要添加一个段错误信号处理程序,以便您在转储时跳过未映射的内存。
在运行的进程中,您将拥有要打印的多个不相交的内存段。它们将包括:
malloc或 的所有数据new)。合理转储内存的关键是能够判断哪个地址范围属于哪个系列。当你转储程序时,这是你的主要工作。其中一些操作,您可以通过读取函数 (1) 和变量(2、3 和 4)的地址来完成,但如果您想打印多个内容,则需要一些帮助。
为此,我们有...
您将需要使用操作系统和编译器开发工具来缩小搜索范围,而不是盲目地搜索从 0 到 2^64 的地址空间(众所周知,地址空间非常大)。有人需要这些工具,甚至可能比你更需要;只需找到它们即可。以下是我所知道的一些。
免责声明:我不知道其中许多东西的 Windows 等效项,尽管我确信它们存在于某个地方。
我已经提到过 Windows系统堆 API。这对您来说是最好的情况。您在这种情况下找到的东西越多,您的转储就会越准确和容易。实际上,操作系统和 C 运行时对您的程序了解很多。这是提取信息的问题。
在 Linux 上,内存类型 1 和 3 可以通过 /proc/pid/maps 等实用程序访问。在 /proc/pid/maps 中,您可以看到为库和程序代码保留的地址空间范围。您还可以看到保护位;例如,只读范围可能是代码,而不是数据。
对于 Windows 技巧,Mark Russinovich撰写了一些关于如何了解 Windows 进程的地址空间以及不同内容的存储位置的文章。我想他可能有一些很好的指导。
| 归档时间: |
|
| 查看次数: |
1762 次 |
| 最近记录: |