2017-01-01 3 views
0

При внедрении хоста стека для отладчика, над которым я работаю, я достиг точки, чтобы извлечь аргументы для вызова функции и отобразить их. Чтобы упростить это, я начал с соглашения cdecl в чистом 32-битном (как отладчике, так и в debuggee) и функции, которая принимает 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.
Я также проверил google много (включая страницы wiki wsdev, сообщения в блоге msdn и т. Д.) И проверил мои (к настоящему времени устаревшие) книги по 32-битовому программированию на сборке x86 (которые были выпущены до 64-разрядных процессоров существовало).

Благодарим вас за любые объяснения или ссылки!

+0

Это, вероятно, поможет, если вы явно задали вопрос, вместо того, чтобы просто объяснить, что вы не понимаете. Вы можете улучшить свой вопрос, добавив информацию о том, что вы ожидали от стека. – IInspectable

+0

Извинения, я думал, что это подразумевалось мной, заявляя, что я работаю с соглашениями о вызовах cdecl, вот что я получаю за предположения. Я уточню вопрос. – Warepire

+2

Ум, вы смотрите на местных жителей, а не на параметры. Это, вероятно, оставшиеся параметры printf. –

ответ

0

Я как-то неправильно понял, где аргументы вызова функции заканчиваются в памяти по сравнению с базой кадра стека, как указал Раймонд. Это фиксированный фрагмент кода:

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); /* <-- Read before the stack frame */ 
    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 */ 
    } 

}

+0

вместо вызова 'ReadProcessMemory' N-time для' sizeof (DWORD_PTR) '- нужно вызвать' ReadProcessMemory' только один раз для 'N * sizeof (DWORD_PTR)' – RbMm

Смежные вопросы