Захватите стек вызовов быстро - PullRequest
5 голосов
/ 10 декабря 2011

Я пытаюсь перехватить стек вызовов как можно быстрее. Сейчас вот что у меня есть:

void* addrs[10] = {};
DWORD hash;
RtlCaptureStackBackTrace(0, 10, addrs, &hash);

for( size_t i = 0; i <10; ++i )
{
    std::cout << addrs[i] << '\n';
}

Это для использования в системе слежения за памятью, поэтому вполне нормально, что я получаю массив адресов, если они могут позже (после какого-то пользовательского события) превратиться во что-то удобочитаемое человеком.

  • Как я могу превратить addrs во что-то понятное человеку? (см. Правку ниже)
  • Есть ли что-нибудь быстрее, чем RtlCaptureStackBackTrace?
  • Существует ли кроссплатформенный способ захвата стека вызовов?

Edit:

Я превратил адреса в удобочитаемую информацию, используя SymFromAddr и SymGetLineFromAddr64. Однако моя версия new, использующая CaptureStackBackTrace, занимает в 30 раз больше, чем оригинал, и почти все это время происходит из-за трассировки стека. Я все еще ищу более быстрое решение!

Ответы [ 2 ]

2 голосов
/ 13 декабря 2011

Существует ли кроссплатформенный способ захвата стека вызовов?

Быстрый ответ: к сожалению, это невозможно.Различные компиляторы и платформы будут организовывать стек по-разному, и без «помощи» компилятора вы не сможете точно проследить обратно через стек ... самое большее, что вы могли бы сделать на платформах, использующих стек.базовый указатель кадра будет перемещаться вверх по стеку, используя значения либо EBP, либо RBP, и даже это зависит от того, используете ли вы 32-разрядный исполняемый файл x86 или x86_64.Кроме того, правила, управляющие двоичным интерфейсом приложений (ABI) UNIX и Windows ABI, совершенно разные.В общем, в конечном итоге вам придется поддерживать как минимум четыре различных варианта:

  1. Unix 32-битный ABI
  2. Unix 64-битный ABI
  3. Windows 32-битный ABI
  4. Windows 64-битный ABI

Имейте в виду, что 64-битный ABI UNIX позволяет компиляторам выбирать, будут ли они поддерживать стек или нет- указатель базы кадра ... поэтому использование указателя базы не гарантируется;компилятор может просто выбрать ссылку на все переменные стека против самого указателя стека без использования отдельного базового указателя.Это все равно будет считаться совместимым с UNIX 64-битным ABI.

Так что, как вы видите, со всеми этими возможными вариантами вам будет очень непросто создать надежный кроссплатформенный стек.трейсера.Лучше всего использовать инструменты, доступные вам для целевой платформы.Если вам нужно поддерживать несколько платформ, то, к сожалению, будет некоторый уровень дублирования кода, поскольку вы будете использовать специальные инструменты для платформ, которые помогут вам надежно выполнять трассировку стека.

0 голосов
/ 13 декабря 2011

Не существует кроссплатформенного способа, но есть кроссплатформенные библиотеки, которые делают свое дело. Это общее требование для сборщиков мусора .

К сожалению, я не знаю достаточно об этих библиотеках, чтобы рекомендовать одну. MMgc имеет что-то встроенное (объяснено в ссылке выше). Я уверен, что у сборщика мусора Ханса Бома есть еще один.

Эти библиотеки, как правило, будут полагаться на вызовы, специфичные для платформы, например RtlCaptureStackBacktrace в Windows. Я был бы удивлен, если бы любая такая библиотека работала быстрее, чем вызовы для конкретной платформы; но я также был бы удивлен, если бы такая библиотека работала значительно медленнее. Единственный вопрос - для меня - будет ли вы предпочитать вызывать вызов Windows API напрямую или перенаправлять этот вызов через другую библиотеку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...