Дамп стека при возникновении исключения
От: Аноним  
Дата: 26.11.03 11:05
Оценка:
Люди, помогите. Замучался уже.
Работаю в MS VC++6.
Нужно в версии "release" с оптимизацией получить:
— список вызовов функций и их названия;
— номер последней выполненной строки программы;
— список загруженных модулей.

Все это нужно для локализации места ошибки после возникновения исключения (Structured Exceprion и C++).
Все, что мог — перепробовал. Топики на этом форуме перечитал. интернет обшарил. Пробовал использовать BugslayerUtil — не работает (точнее работает, но выдает только адреса и параметры, а остальную информацию — нет). Смотрел исходники, но, не смог найти причину.
AfxDumpSteck — не выдает функций моего приложения и номер строки.
Пробовал StackWalk — ничего не выходит.
Такое ощущение, что я что-то недопонимаю или не так делаю. Или что-то нужно правильно проинициализировать, прежде чем получить нужную мне информацию.

В общем, если кто знает, как мне помочь, помогите, пожалуйста. А то я на этом скончаюсь скоро.

Заранее благодарен, Александр.

26.11.03 14:14: Перенесено модератором из 'C/C++' — ПК
Re: Дамп стека при возникновении исключения
От: Павел Кузнецов  
Дата: 26.11.03 11:13
Оценка:
Здравствуйте, Вы писали:

> Работаю в MS VC++6.

> Нужно в версии "release" с оптимизацией получить:
> — список вызовов функций и их названия; <...>
> Все, что мог — перепробовал.

Включить генерацию Debug Info не забыл?
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Дамп стека при возникновении исключения
От: lav03  
Дата: 26.11.03 12:07
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Здравствуйте, Вы писали:


>> Работаю в MS VC++6.

>> Нужно в версии "release" с оптимизацией получить:
>> — список вызовов функций и их названия; <...>
>> Все, что мог — перепробовал.

ПК>Включить генерацию Debug Info не забыл?


Нет,стоит.
Re[3]: Дамп стека при возникновении исключения
От: Pavel Dvorkin Россия  
Дата: 26.11.03 12:15
Оценка:
Привет!

lav03 wrote:
>
> ПК>Включить генерацию Debug Info не забыл?
>
> Нет,стоит.

А Program Database ?

--
С наилучшими пожеланиями
Дворкин Павел
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[4]: Дамп стека при возникновении исключения
От: lav03  
Дата: 26.11.03 13:06
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Привет!


PD>lav03 wrote:

>>
>> ПК>Включить генерацию Debug Info не забыл?
>>
>> Нет,стоит.

PD>А Program Database ?


PD>--

PD>С наилучшими пожеланиями
PD> Дворкин Павел

нет:

/nologo /MT /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fp"Release/TestErr.pch" /Yu"stdafx.h" /Fo"Release/" /Fd"Release/" /FD /c

/nologo /subsystem:windows /incremental:no /pdb:"Release/TestErr.pdb" /debug /machine:I386 /out:"Release/TestErr.exe"
Re[4]: Дамп стека при возникновении исключения
От: lav03  
Дата: 26.11.03 13:10
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Привет!


PD>lav03 wrote:

>>
>> ПК>Включить генерацию Debug Info не забыл?
>>
>> Нет,стоит.

PD>А Program Database ?


PD>--

PD>С наилучшими пожеланиями
PD> Дворкин Павел

void CTestErrDlg::OnButton1()
{
AfxDumpStack(AFX_STACK_DUMP_TARGET_CLIPBOARD);
}

Вот что мне AfxDampSteck выдает:

=== begin AfxDumpStack output ===
7FFE0304: <no module><no symbol>
00401335: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
004242BE: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
00424702: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
00426B89: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
004265BF: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
00426571: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
0042545D: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
00425666: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
77D33A5F: WINDOWS\system32\USER32.dll! CreateWindowExA + 9611 bytes
77D33B2E: WINDOWS\system32\USER32.dll! CreateWindowExA + 9818 bytes
77D35E1D: WINDOWS\system32\USER32.dll! GetWindowThreadProcessId + 353 bytes
77D35E7E: WINDOWS\system32\USER32.dll! SendMessageW + 71 bytes
77D4F7FA: WINDOWS\system32\USER32.dll! InvertRect + 483 bytes
77D4F4BA: WINDOWS\system32\USER32.dll! IsDialogMessageA + 56 bytes
004288F0: Projects\MSVC++6\Test\TestErr\Release\TestErr.exe! <no symbol>
=== end AfxDumpStack() output ===

А где же моя CTestErrDlg::OnButton1()
Re[5]: Дамп стека при возникновении исключения
От: Pavel Dvorkin Россия  
Дата: 26.11.03 13:17
Оценка:
Привет!

lav03 wrote:
>
> А где же моя CTestErrDlg::OnButton1()

А вообще-то файл .pdb есть в release версии ?

--
С наилучшими пожеланиями
Дворкин Павел
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[6]: Дамп стека при возникновении исключения
От: lav03  
Дата: 26.11.03 13:42
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Привет!


PD>lav03 wrote:

>>
>> А где же моя CTestErrDlg::OnButton1()

PD>А вообще-то файл .pdb есть в release версии ?


PD>--

PD>С наилучшими пожеланиями
PD> Дворкин Павел

Есть.
Может какие-то директивы компилятора нужно добавить? Такое ощущение, что AfxDumpStack не всю инфу вкуривает. А тогда зачем она, такая дорогая, нужна? В МСДН ничего не написано ни про дополнительную инициализацию, ни про опции компиллета для этой функции. В дебаг-версии тоже самое примерно получается. Н понимаю
Re[7]: Дамп стека при возникновении исключения
От: Pavel Dvorkin Россия  
Дата: 26.11.03 14:05
Оценка:
Привет!

lav03 wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:

> Может какие-то директивы компилятора нужно добавить? Такое ощущение, что AfxDumpStack не всю инфу вкуривает. А тогда зачем она, такая дорогая, нужна? В МСДН ничего не написано ни про дополнительную инициализацию, ни про опции компиллета для этой функции. В дебаг-версии тоже самое примерно получается. Н понимаю



Я сейчас проверил у себя. Значит, так

Под VC6 Debug выдается Error 126 — (module not found, если это
GetLastError). После этого дамп, но без моих имен.
Под VC6 Release выдается одна строчка, не моя
Под VC7 Debug все замечательно.
Под VC7 Release тоже все прекрасно.

ИМХО что-то связано с imghelp.dll. Как бы мне ее VC7 не переписал при
установке.

--
С наилучшими пожеланиями
Дворкин Павел
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[8]: Дамп стека при возникновении исключения
От: lav03  
Дата: 26.11.03 14:33
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Привет!


PD>lav03 wrote:

>>
>> Здравствуйте, Pavel Dvorkin, Вы писали:

>> Может какие-то директивы компилятора нужно добавить? Такое ощущение, что AfxDumpStack не всю инфу вкуривает. А тогда зачем она, такая дорогая, нужна? В МСДН ничего не написано ни про дополнительную инициализацию, ни про опции компиллета для этой функции. В дебаг-версии тоже самое примерно получается. Н понимаю



PD>Я сейчас проверил у себя. Значит, так


PD>Под VC6 Debug выдается Error 126 — (module not found, если это

PD>GetLastError). После этого дамп, но без моих имен.
PD>Под VC6 Release выдается одна строчка, не моя
PD>Под VC7 Debug все замечательно.
PD>Под VC7 Release тоже все прекрасно.

PD>ИМХО что-то связано с imghelp.dll. Как бы мне ее VC7 не переписал при

PD>установке.

Точно! У меня тоже VC7 стоит. Я чейчас проверил — на VC7 работает. Это что же тогда получается, мне сосвоей программой нужно и imghelp.dll от VC7 распространять? А если я ее подменю, другие проги, юзающие старые версии, отъедут?


PD>--

PD>С наилучшими пожеланиями
PD> Дворкин Павел
Re[9]: Дамп стека при возникновении исключения
От: lav03  
Дата: 26.11.03 14:45
Оценка:
Здравствуйте, lav03, Вы писали:

L>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Привет!


PD>>lav03 wrote:

>>>
>>> Здравствуйте, Pavel Dvorkin, Вы писали:

>>> Может какие-то директивы компилятора нужно добавить? Такое ощущение, что AfxDumpStack не всю инфу вкуривает. А тогда зачем она, такая дорогая, нужна? В МСДН ничего не написано ни про дополнительную инициализацию, ни про опции компиллета для этой функции. В дебаг-версии тоже самое примерно получается. Н понимаю



PD>>Я сейчас проверил у себя. Значит, так


PD>>Под VC6 Debug выдается Error 126 — (module not found, если это

PD>>GetLastError). После этого дамп, но без моих имен.
PD>>Под VC6 Release выдается одна строчка, не моя
PD>>Под VC7 Debug все замечательно.
PD>>Под VC7 Release тоже все прекрасно.

PD>>ИМХО что-то связано с imghelp.dll. Как бы мне ее VC7 не переписал при

PD>>установке.

L>Точно! У меня тоже VC7 стоит. Я чейчас проверил — на VC7 работает. Это что же тогда получается, мне сосвоей программой нужно и imghelp.dll от VC7 распространять? А если я ее подменю, другие проги, юзающие старые версии, отъедут?


На другом компе поробовал запустить программу — получил скудное содержание стека. Подсунул свою imagehelp.dll — тот же результат. Не работает.

PD>>--

PD>>С наилучшими пожеланиями
PD>> Дворкин Павел
Re[10]: Дамп стека при возникновении исключения
От: Sergey Россия  
Дата: 26.11.03 16:03
Оценка: +1
Hello, lav03!
You wrote on Wed, 26 Nov 2003 14:45:19 GMT:

PD>>> ИМХО что-то связано с imghelp.dll. Как бы мне ее VC7 не переписал при

PD>>> установке.

L>> Точно! У меня тоже VC7 стоит. Я чейчас проверил — на VC7 работает. Это

L>> что же тогда получается, мне сосвоей программой нужно и imghelp.dll от
L>> VC7 распространять? А если я ее подменю, другие проги, юзающие старые
L>> версии, отъедут?

l> На другом компе поробовал запустить программу — получил скудное

l> содержание стека. Подсунул свою imagehelp.dll — тот же результат. Не
l> работает.

А зачем тебе имена функций на компьютере клиента? Достаточно транслировать адреса в логические, а имена функций брать из map-файла на своей машине (ну, при этом, правда, придется хранить map-файлы и pdb для всех версий программы — зато pdb никому отдавать не придется). Или без map-файла — сразу бинарник+pdb в IDA грузить.

Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[11]: Дамп стека при возникновении исключения
От: lav03  
Дата: 26.11.03 16:43
Оценка:
Здравствуйте, Sergey, Вы писали:

S>А зачем тебе имена функций на компьютере клиента? Достаточно транслировать адреса в логические, а имена функций брать из map-файла на своей машине (ну, при этом, правда, придется хранить map-файлы и pdb для всех версий программы — зато pdb никому отдавать не придется). Или без map-файла — сразу бинарник+pdb в IDA грузить.


S>Best regards,

S> Sergey.

Дело в том, что на другой машине она мне вообще не выдает даже адреса моей функции OnButton1.
Re[9]: Дамп стека при возникновении исключения
От: Pavel Dvorkin Россия  
Дата: 27.11.03 05:27
Оценка:
Привет!

lav03 wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:
> PD>ИМХО что-то связано с imghelp.dll. Как бы мне ее VC7 не переписал при
> PD>установке.
>
> Точно! У меня тоже VC7 стоит. Я чейчас проверил — на VC7 работает. Это что же тогда получается, мне сосвоей программой нужно и imghelp.dll от VC7 распространять? А если я ее подменю, другие проги, юзающие старые версии, отъедут?

Хуже. imghelp.dll не есть re-distributable .

Но вообще-то ИМХО нужно просто правильную версию сунуть в каталог, где
EXE. По общим правилам поиск сначала идет в этом каталоге, а потом в
system32 (см. LoadLibrary). Насколько я помню, к well-known dll она не
относится (а вообще-то проверь)


--
С наилучшими пожеланиями
Дворкин Павел
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[10]: Дамп стека при возникновении исключения
От: lav03  
Дата: 27.11.03 09:14
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Привет!


PD>lav03 wrote:

>>
>> Здравствуйте, Pavel Dvorkin, Вы писали:
>> PD>ИМХО что-то связано с imghelp.dll. Как бы мне ее VC7 не переписал при
>> PD>установке.
>>
>> Точно! У меня тоже VC7 стоит. Я чейчас проверил — на VC7 работает. Это что же тогда получается, мне сосвоей программой нужно и imghelp.dll от VC7 распространять? А если я ее подменю, другие проги, юзающие старые версии, отъедут?

PD>Хуже. imghelp.dll не есть re-distributable .


PD>Но вообще-то ИМХО нужно просто правильную версию сунуть в каталог, где

PD>EXE. По общим правилам поиск сначала идет в этом каталоге, а потом в
PD>system32 (см. LoadLibrary). Насколько я помню, к well-known dll она не
PD>относится (а вообще-то проверь)


PD>--

PD>С наилучшими пожеланиями
PD> Дворкин Павел

Сунул. Не работает.
Вот гадость какая. Вся идея рушится. А так хотелось сделать хорошо.
Re[11]: Дамп стека при возникновении исключения
От: Pavel Dvorkin Россия  
Дата: 27.11.03 09:37
Оценка:
Привет!

lav03 wrote:

> Сунул. Не работает.


Уверен, что именно ту, что нужно сунул ?
Эта библиотека записывается в system32 при инсталляции VC (ИМХО). Я бы
на твоем месте поискал бы ее в system32 машины, на которой VC7 никогда
не ставился.

Работало же оно в конце концов до того, как VC7 на свет появился.
AfxDump.. ИМХО еще в 4.2 была, а то и раньше.


--
С наилучшими пожеланиями
Дворкин Павел
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[12]: Дамп стека при возникновении исключения
От: lav03  
Дата: 28.11.03 11:09
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

Ха! Я понял. AfxDumpStack() без файла .pdb не работает (точнеее работает, но не так). Прчем, интересно получается.
Если я имею .pdb, я получу примерно такой дамп:

=== begin AfxDumpStack output ===
7FFE0304: <no module>! <no symbol>
004171C6: \SUPERPUPS\Guest\1\ErrHndlTest.exe! AfxDumpStack + 37 bytes
00401057: \SUPERPUPS\Guest\1\ErrHndlTest.exe! CEhsTerminalErrHandler::MakeStructuredExceptionReport + 7 bytes
0040157F: \SUPERPUPS\Guest\1\ErrHndlTest.exe! CEhsTerminalErrHandler::HandleStructuredException + 31 bytes
0040195D: \SUPERPUPS\Guest\1\ErrHndlTest.exe! foo + 349 bytes
00417E00: \SUPERPUPS\Guest\1\ErrHndlTest.exe! _AfxDispatchCmdMsg + 61 bytes
. . . . . . .
=== end AfxDumpStack() output ===

где foo — моя функция, где произошло, в данном случае структурнре, исключение, а CEhsTerminalErrHandler::HandleStructuredException() и CEhsTerminalErrHandler::MakeStructuredExceptionReport() вызываются из foo() для обработки исключения.

Если же программа не находит .pdb файл, дамп содержит меньше строк. А самое обидное, что в нем нет адресов функций:
0040157F: \SUPERPUPS\Guest\1\ErrHndlTest.exe! CEhsTerminalErrHandler::HandleStructuredException + 31 bytes
0040195D: \SUPERPUPS\Guest\1\ErrHndlTest.exe! foo + 349 bytes

Это видно ниже:

=== begin AfxDumpStack output ===
7FFE0304: <no module>! <no symbol>
004171C6: \SUPERPUPS\Guest\1\ErrHndlTest.exe! <no symbol>
00401057: \SUPERPUPS\Guest\1\ErrHndlTest.exe! <no symbol>
00417E00: \SUPERPUPS\Guest\1\ErrHndlTest.exe! <no symbol>
. . . . . . .
=== end AfxDumpStack() output ===

Причем, такая фича имеет место, если AfxDumpStack() вызвана в теле ф-ции
CEhsTerminalErrHandler::MakeStructuredExceptionReport().

Но, если AfxDumpStack() вызвать непосредственно из foo, то строки
0040157F: \SUPERPUPS\Guest\1\ErrHndlTest.exe! <no symbol>
0040195D: \SUPERPUPS\Guest\1\ErrHndlTest.exe! <no symbol>

соотсет-щие ф-циям CEhsTerminalErrHandler::HandleStructuredException() и foo() появятся.
AfxDumpStack() использует API для "прогулок по стеку". Может там и есть где-то ошибка, но, посмотрев исходник, почитав описания ф-ций и различных структур, ей испольуемых, для меня работа со стеком с помощью API не стала много прозрачней. По крайней мере ошибку в исходнике я не в состоянии найти.

Распространять .pdb я не хочу. Как же мне тогда получить правильный список вызовов функций? Может через ассемблер в стек залезть? Не подскажет ли кто, где можно почитать о том, как получить информацию из стека с помощью ассемблера, где что там жранится и как его правильно просматривать. А уж получив адреса я по .map файлу смогу названия функций определить.

Спасибо, Александр.
Re[13]: Дамп стека при возникновении исключения
От: Pavel Dvorkin Россия  
Дата: 28.11.03 11:38
Оценка:
Привет!

lav03 wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:
>
> Ха! Я понял. AfxDumpStack() без файла .pdb не работает

Именно так. Я полагал, что ты это знаешь.

>

> Распространять .pdb я не хочу. Как же мне тогда получить правильный список вызовов функций?

Никак. Как говорил один литературный герой, "при наличии отсутствия".
Именно в .pdb (можно еще в .dbg, но я не знаю, как их делать) и лежит
вся требуемая информация.

>Может через ассемблер в стек залезть? Не подскажет ли кто, где можно почитать о том, как получить информацию из стека с помощью ассемблера, где что там жранится и как его правильно просматривать. А уж получив адреса я по .map файлу смогу названия функций определить.


Хм, а чем тебе map файл лучше pdb ?

А насчет того, что хранится в стеке — ответ прост. Адреса возвратов,
локальные переменные, фактические парметры и фреймы SEH. В стековом
порядке

--
С наилучшими пожеланиями
Дворкин Павел
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[13]: Дамп стека при возникновении исключения
От: Sergey Россия  
Дата: 28.11.03 11:38
Оценка: 12 (1)
Hello, lav03!
You wrote on Fri, 28 Nov 2003 11:09:21 GMT:

l> Распространять .pdb я не хочу. Как же мне тогда получить правильный

l> список вызовов функций? Может через ассемблер в стек залезть? Не
l> подскажет ли кто, где можно почитать о том, как получить информацию из
l> стека с помощью ассемблера, где что там жранится и как его правильно
l> просматривать. А уж получив адреса я по .map файлу смогу названия
l> функций определить.

В общем-то, без pdb полноценно гулять по стеку, имхо, невозможно. Метод гуляния по стеку без pdb очень простой — предполагается, что компилятор в начале каждой функции генерирует некоторый пролог, формирующий так называемый stack frame:

push ebp
move ebp, esp
sub esp, local_vars_size


Соответственно, и сделать дамп стека не представляет особого труда (пример из какой-то статьи Питрека, хотя я его вроде под свои цели чуть-чуть переделывал):

void CCrashHandler::IntelStackWalk(PCONTEXT pContext)
{
    _tprintf( _T("\r\nCall stack:\r\n") );
    _tprintf( _T("Address   Frame     Logical addr  Module\r\n") );

    DWORD pc = pContext->Eip;
    PDWORD pFrame, pPrevFrame;
    
    pFrame = (PDWORD)pContext->Ebp;

    do
    {
        TCHAR szModule[MAX_PATH] = _T("");
        DWORD section = 0, offset = 0;

        GetLogicalAddress((PVOID)pc, szModule, sizeof(szModule), section, offset);

        _tprintf(_T("%08X  %08X  %04X:%08X %s\r\n"), pc, pFrame, section, offset, szModule);

        pc = pFrame[1];
        pPrevFrame = pFrame;
        pFrame = (PDWORD)pFrame[0]; // precede to next higher frame on stack
        if ((DWORD)pFrame & 3)    // Frame pointer must be aligned on a
            break;                  // DWORD boundary.  Bail if not so.
        if (pFrame <= pPrevFrame)
            break;
        // Can two DWORDs be read from the supposed frame address?          
        if (IsBadReadPtr(pFrame, sizeof(PVOID)*2))
            break;
    } while (1);
}


Однако все так здорово ровно до тех пор, пока компилятор не пользуется т.н. FPO — оптимизацию (Frame-Pointer Omission). Через код без кадров стека так просто не погуляешь, так что придется быть готовым к тому, что не всегда удастся сделать полноценный дамп стека (для увеличиния вероятности успеха можно выключить FPO при компиляции (опция /Oy- после опций оптимизации)), или использовать pdb (лучше ее слегка почикать с помощью /PDBSTRIPPED, если у тебя VC 7).

Best regards,
Sergey.
Posted via RSDN NNTP Server 1.8 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[14]: Дамп стека при возникновении исключения
От: lav03  
Дата: 28.11.03 12:46
Оценка:
Здравствуйте, Sergey, Вы писали:

Понятно. А что это за ф-ция GetLogicalAddress(..)? Это не апишная, ее в МСДМН нет. Ты не мог бы мне ее код дать?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.