在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 << " ";
}
}现在,我如何知道我的进程内存空间是从哪个地址开始的,所有变量都存储在哪里?我现在该怎么做,这个区域有多长?
例如:
MyDump(0x0000 /* <-- Starts from here? */, 0x1000 /* <-- This much? */);诚挚的问候,
nhaa123
发布于 2010-04-09 14:53:57
概述
你尝试做的事情是完全可能的,甚至有工具可以帮助你,但你必须做比我认为你期望的更多的跑腿工作。
在您的例子中,您特别感兴趣的是“变量位于何处”。Windows上的system heap API将会给你带来难以置信的帮助。这个引用真的很好,虽然它不是一个连续的区域,但是API会告诉你变量在哪里。
不过,通常情况下,如果不知道内存放在哪里,就必须对进程的整个地址空间进行清理。如果您只想要数据,则还必须对其进行一些过滤,因为代码和堆栈的无用信息也在那里。最后,为了避免在转储地址空间时出现seg-faulting,您可能需要添加一个段错误信号处理程序,以便在转储时跳过未映射的内存。
进程内存布局
在一个正在运行的进程中,您需要打印的是多个互不相交的内存。这些措施包括:
malloc或data的所有内容合理转储内存的关键是能够分辨出哪个地址范围属于哪个系列。这是你的主要工作,当你转储程序的时候。其中一些可以通过读取函数(1)和变量(2、3和4)的地址来完成,但如果要打印更多内容,则需要一些帮助。
为此,我们有..。
有用的工具
而不是盲目地搜索从0到2^64的地址空间(我们都知道,这是非常巨大的),您将希望使用操作系统和编译器开发人员工具来缩小搜索范围。外面有人需要这些工具,也许比你更需要;这只是找到它们的问题。下面是我知道的几个例子。
免责声明:我不知道这些东西中的许多Windows等价物,但我确信它们存在于某个地方。
我已经提到了Windows system heap API。这对您来说是最好的情况。在这个脉络中你能找到的东西越多,你的转储就越准确和容易。实际上,OS和C运行时对您的程序非常了解。这是提取信息的问题。
在Linux上,可以通过/proc/pid/map等实用程序访问内存类型1和3。在/proc/pid/map中,您可以看到为库和程序代码保留的地址空间的范围。您还可以看到保护位;例如,只读范围可能是代码,而不是数据。
对于Windows提示,Mark Russinovich在written some articles上介绍了如何了解Windows进程的地址空间以及不同内容的存储位置。我想他可能有一些很好的建议。
发布于 2010-04-09 08:37:55
这个问题的简短答案是你不能用这种方式来解决这个问题。进程在内存中的布局方式在很大程度上依赖于编译器和操作系统,而且很难确定所有代码和变量所在的位置。为了准确而完整地找到所有变量,您需要自己编写调试器的大部分内容(或者从真正的调试器代码中借用它们)。
但是,您也许可以将您的问题的范围缩小一点。如果您真正想要的只是一个堆栈跟踪,那么生成它们并不太难:How can one grab a stack trace in C?
或者,如果您想检查堆栈本身,可以很容易地获得指向堆栈当前顶部的指针(只需声明一个局部变量,然后获取它的地址)。获取堆栈底部的最简单方法是在main中声明一个变量,将其地址存储在全局变量中,然后将该地址用作“底部”(这很容易,但不是真正的“干净”)。
了解堆的情况要困难得多,因为您需要广泛了解堆的内部工作原理,才能知道它的哪些部分当前已分配。由于堆的大小基本上是“无限制的”,因此如果只打印所有数据,即使是未使用的部分,打印的数据量也相当大。我不知道有什么方法可以做到这一点,我强烈建议你不要浪费时间去尝试。
了解静态全局变量并不像堆那么糟糕,但也很困难。它们位于可执行文件的数据段中,除非您想要进行一些可执行文件格式的汇编和解析,否则也要避免这样做。
发布于 2010-04-09 08:38:04
AFAIK,这取决于操作系统,你应该看看例如内存分段。
https://stackoverflow.com/questions/2604358
复制相似问题