Печать стека вызовов

Тема в разделе "WASM.BEGINNERS", создана пользователем MikhailKM, 4 фев 2010.

  1. MikhailKM

    MikhailKM New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2010
    Сообщения:
    18
    Пишу для Windows на VC++, использую следующую функцию для печати стека вызовов

    void PrintCallStack( int __ebp ) {
    int *_ebp = (int*) (__int64) __ebp;
    if ( _ebp == 0 ) {
    __asm {
    mov _ebp, ebp
    }
    }
    LogFile << "----------------" << endl;

    for (;;) {
    if ( IsBadReadPtr( _ebp, sizeof(int*) ) ) break;
    if ( IsBadReadPtr( _ebp + 1, sizeof(int*) ) ) break;
    int* call = *(int**) ( _ebp + 1 );
    LogFile << "0x" << call << endl;
    _ebp = *(int**) _ebp;
    }
    LogFile << "----------------" << endl;
    }

    PrintCallStack( 0 ) - печать текущего стека
    PrintCallStack( __ebp ) - использую для печати стека с нужного места (например, в фильтре исключений печатаю стек с места возникновения исключения).

    Просьба к опытным людям высказать свое мнение.
    Может быть можно что-то улучшить?

    Спасибо.
     
  2. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    MikhailKM
    если я не ошибаюсь на стек указывает esp
     
  3. Ursus

    Ursus Member

    Публикаций:
    0
    Регистрация:
    15 мар 2006
    Сообщения:
    238
    Адрес:
    Russia
    Используй Dbhelp.dll
     
  4. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    max7C4
    Это бактрейс. На конец цепочки стековых фреймов ссылается регистр Ebp.
     
  5. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    Clerk
    т.к. это Си, а не асм, то не возможно это утверждение не достоверно т.к. это зависит как от версии компилятора, так и от используемых ключей и т.д и т.п. к тому же если использовать классы, то там вообще произвол и ebp может спокойно использоваться как this (если я не ошибаюсь именно VC++ мною за подобным замечался)
     
  6. MikhailKM

    MikhailKM New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2010
    Сообщения:
    18
    Печатаемые стеки правильны, за исключением иногда пропускаемых уровней.
    Например точка возврата main() в __tmainCRTStartup() может пропечататься, а может и нет.
    Есть предложения по улучшению?
     
  7. MikhailKM

    MikhailKM New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2010
    Сообщения:
    18
    Не хочу цеплять целую dll ради одной функции.
     
  8. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    многие компиляторы не используют фреймы с ebp, в целях оптимизации сразу же используют esp.
     
  9. make

    make New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2009
    Сообщения:
    59
    в VC ecx == this
     
  10. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    Тут есть один нюанс: если тебе нужно тупо стек весь, то да, так как ты делаешь -- ок, но полезности в этом почти нет т.к. файл, если я правильно понимаю будет просматриваться после того, как программа отработает, что тебе дадут адреса-цифры, если ты уже не сможешь восстановить базы всех длл? если даже у тебя есть базы всех длл, тебе все равно придется руками восстанавливать стек вызовов, что является занятием не самым приятным и интересным, это по опыту =) dbghelp дает возможность мало того, что напечатать только стек вызовов, так еще и напечатать не только адреса, а и названия функций, при наличии символов(а вот без них -- гораздо хуже =) ), (кстати самому подобный функционал реализовать совсем не так просто, как может казаться) а они же есть, если приложение твое. Ну а про тащить библиотеку -- вообе непонятно, тебе жалко что ли, или какие-то очень жесткие требования к потребляемым ресурсам =) ?
     
  11. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    что значит цеплять? есть такая штука - виртуальная память, если ты беспокоишься об оперативке.
     
  12. maksim_

    maksim_ New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2009
    Сообщения:
    263
    и ещё. кодес твой не будет работать под x64, что в данное время довольно ущербно. самое неприятное, конечно, то, что не печатает имена функций.

    если ты действительно пишешь на Си++, то должен понимать насколько бесполезна информация об адресах стека вызовов.
     
  13. MikhailKM

    MikhailKM New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2010
    Сообщения:
    18
    Программа работает у клиента, никакой отладочной информация нет, стек вызова в логе нужен при анализе сбоев.

    Код (Text):
    1. файл, если я правильно понимаю будет просматриваться после того, как программа отработает
    Правильно.

    Код (Text):
    1. не сможешь восстановить базы всех длл
    Системные dll обычно грузятся на одинаковые адреса, само приложение тоже. Наибольший интерес представляет код в exe.

    Код (Text):
    1. придется руками восстанавливать стек вызовов
    Будет очень легко определить иерархию вызовов.

    Код (Text):
    1. Ну а про тащить библиотеку -- вообе непонятно, тебе жалко что ли, или какие-то очень жесткие требования к потребляемым ресурсам =) ?
    Жестких требований нет. Однако без символов польза от dbghelp.dll не больше чем от моей функции (имхо). Так что лучше - грузить dll или вписать 20 строк в код?

    Код (Text):
    1. кодес твой не будет работать под x64
    Я в этом пока не разбирался. Наверное код можно переписать для x64?
     
  14. MikhailKM

    MikhailKM New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2010
    Сообщения:
    18
    Почему нельзя править сообщение?
    Очень неудобно...

    "Код:" читайте как "Цитата:"
     
  15. Velheart

    Velheart New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2008
    Сообщения:
    526
    MikhailKM
    Если для анализа сбоев -- то почему не делать минидамп? Гораздо информативней =)
     
  16. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    если прога весит 2 кб, то да. очень легко. возможно, проще даже OutputDebugString.
     
  17. MikhailKM

    MikhailKM New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2010
    Сообщения:
    18
    Velheart
    Я это упустил, спасибо. Дамп тоже буду делать. Вот и польза от дискуссии получилась.

    Размер не имеет значения. Загружаете проект и смотрите, что оказалось по указанному адресу. Или вы что-то другое имеете ввиду?
     
  18. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    я имею ввиду как по адресам узнать имена функций? если у меня в стеке 50 вызовов, а там ещё рекурсия и где-то посреди рекурсии залез косяк - что толку от одних адресов?
     
  19. MikhailKM

    MikhailKM New Member

    Публикаций:
    0
    Регистрация:
    4 фев 2010
    Сообщения:
    18
    Я вижу в отладчике инструкции одновременно со своим кодом.

    Код (Text):
    1.     case WM_SHOWWINDOW: {
    2.         gui.SetWin( hwnd );
    3. 00411BDD  push        ebx  
    4. 00411BDE  mov         esi,offset gui (466E40h)
    5. 00411BE3  call        GUI_CLASS::SetWin (4031A0h)
    6.         gui.PrintLastError( "Нет ошибок" );
    7. 00411BE8  mov         edi,offset string "\xcd\xe5\xf2 \xee\xf8\xe8\xe1\xee\xea" (421F44h)
    8. 00411BED  mov         ecx,esi
    9. 00411BEF  call        GUI_CLASS::PrintLastError (403390h)
     
  20. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    MikhailKM ты пробовал находить в ольке ошибки в проекте больше, чем 1Мб?