Получение указателя на нижнюю часть стека вызовов и разрешение символа по адресу (например, dladdr) под Windows?


Я хочу реализовать аналог утилиты backtrace под windows, чтобы добавить эту информацию в исключение, например.

Мне нужно записать обратные адреса, а затем перевести их в имена символов.

Я знаю о StackWalk64 и о проекте StackWalker, но, к сожалению, у него есть несколько важных недостатков:

  • известно, что он очень медленный (StackWalk64), и я не хочу тратить много времени на сбор следов, которые в принципе могут быть сделано так же быстро, как ходить по связанному списку.
  • известно, что функция StackWalk64 не является потокобезопасной.

Я хочу поддерживать только x86 и возможные архитектуры x86_64

Основная идея у меня следующая:

  1. запуск на стеке с использованием регистров esp/ebp аналогично тому, что GCC __builtin_return_address(x)/__builtin_frame_address(x) doe, пока я не достигну нижней части стека (это то, что делает glibc).
  2. перевести адреса в символы
  3. Demangle их.

Проблемы / Вопросы:

  1. Как я узнаю, что я достигаю вершины стопки? Например, реализация glibc имеет __libc_stack_end, поэтому легко найти, где остановиться. Есть ли аналог такой штуки под окнами? Как я могу получить Нижний адрес стека?
  2. каковы аналоги функциональности dladdr. Теперь я знаю, что в отличие от платформы ELF, которая сохраняет большинство имен символов, формат PE этого не делает. Так что он должен каким-то образом считывать отладочную информацию. Есть идеи?
2 2

2 ответа:

  • Захват Трассировки Стека: RtlCaptureStackBackTrace
  • Получение символов: использование библиотеки справки DBG (только MSVC). Ключевые функции:

    // Initialization
    hProcess = GetCurrentProcess()
    SymSetOptions(SYMOPT_DEFERRED_LOADS)
    SymInitialize(hProcess, NULL, TRUE)
    // Fetching symbol
    SymFromAddr(...)
    

    Реализация может быть найдена там

Вы используете StackWalk, но разрешите символы позже.