在为调试器实现堆栈步行器时我正在努力达到了将参数提取到函数调用并显示它们的目的。为了简单起见,我开始使用纯32位(包括调试器和调试器)的cdecl约定和一个带3个参数的函数。然而,我不明白为什么堆栈跟踪中的参数与cdecl定义的参数(从右到左,没有任何寄存器)相比没有规律,尽管现在试图找出它几天。需要帮助了解堆栈帧布局
下面是函数调用我试图堆栈跟踪的表示:
void Function(unsigned long long a, const void * b, unsigned int c) {
printf("a=0x%llX, b=%p, c=0x%X\n", a, b, c);
_asm { int 3 }; /* Because I don't have stepping or dynamic breakpoints implemented yet */
}
int main(int argc, char* argv[]) {
Function(2, (void*)0x7A3FE8, 0x2004);
return 0;
}
这是(不出所料)打印到控制台哪些功能:
a=0x2, c=0x7a3fe8, c=0x2004
这是在断点处生成的堆栈跟踪(调试器捕获断点并在那里尝试走栈):
0x3EF5E0: 0x10004286 /* previous pc */
0x3EF5DC: 0x3EF60C /* previous fp */
0x3EF5D8: 0x7A3FE8 /* arg b --> Wait... why is b _above_ c here? */
0x3EF5D4: 0x2004 /* arg c */
0x3EF5D0: 0x0 /* arg a, upper 32 bit */
0x3EF5CC: 0x2 /* arg a, lower 32 bit */
这是负责反倾销的堆栈帧代码(使用DIA SDK实现的,不过,我不认为这是有关我的问题)是这样的:
ULONGLONG stackframe_top = 0;
m_frame->get_base(&stackframe_top); /* IDiaStackFrame */
/* dump 30 * 4 bytes */
for (DWORD i = 0; i < 30; i++)
{
ULONGLONG address = stackframe_top - (i * 4);
DWORD value;
SIZE_T read_bytes;
if (ReadProcessMemory(m_process, reinterpret_cast<LPVOID>(address), &value, sizeof(value), &read_bytes) == TRUE)
{
debugprintf(L"0x%llX: 0x%X\n", address, value); /* wrapper around OutputDebugString */
}
}
我编译测试程序没有任何优化在vs2015更新3.
我已经验证,我确实编译它为cdecl通过查看pdb与dia2dump
示例应用程序。 我不明白是什么导致堆栈看起来像这样,它不符合我学到的任何东西,也不匹配documentation provided by Microsoft。
我也检查了一大堆谷歌(包括osdev维基页面,msdn博客文章等),并检查了我的(现在可能已经过时的)关于32位x86汇编程序设计(在64位CPU之前发布的)存在)。
非常感谢您提前任何解释或链接!
它可能会帮助,如果你明确地提出了一个问题,而不是仅仅解释,你不明白的东西。您可以通过添加关于预期堆栈的样子的信息来改善您的问题。 – IInspectable
道歉,我认为这是隐含的,我说我正在与cdecl调用约定,这就是我得到的假设。我会更新这个问题。 – Warepire
嗯,你正在看当地人,而不是参数。这些可能是来自printf的剩余参数。 –