LINUX.ORG.RU

Проблема с анализом стека в самодельном профайлере

 ,


0

1

Привет! Я тут писал, что собираюсь делать что-то вроде профилировщика для программ на сях под x86/x86-64. Работает пока только под фрёй и драгонфлаем (это то, чем я пользуюсь) Вот что вышло:

https://github.com/shamazmazum/vsprofiler

Профайлер анализирует instruction pointer и стек (используя регистр ebp/rbp, т.е. компилировать надо с -fno-omit-frame-pointer) по сигналу таймера. Он пока не строит граф вызовов, а печатает flat report. Там 2 важных поля: self - количество семплов, когда instruction pointer был внутри данной функции и cumul - когда выполняется эта функция и когда выполняются функции, вызванные из неё (а сама она лежит на стеке).

Там на жидхабе есть пример использования (и за одно тест) - программа, которая хитро наполняет некий буфер и считает для него CRC. Дерево вызовов такое (написал в виде списка-копипасты, будет непонятно, пишите):

("main" ("get_value" ("factor")) ("crc8"))

Тест заключается в проверке значений

CUMUL(main) - SELF(main) - CUMUL(get_value) - CUMUL (crc8)
CUMUL(get_value) - SELF(get_value) - CUMUL(factor)
CUMUL(factor) - SELF(factor)
CUMUL(crc8) - SELF(crc8)

Понятно, что в идеале они должны быть равны 0 (так как у main 2 вызывающиеся функции - get_value и crc8, итд)

Но я получаю это (по gmake test): http://pastebin.com/Ntf37Gyc

Т.е. значения 38 и -54 для первых двух выражений.

Предположил, что ошибка из-за того, что instruction pointer находится где-то в прелюдии или эпилоге функций. clang генерирует такое:

00000000004008c0 <get_value>:
  4008c0:	55                     	push   %rbp (Вот тут RIP уже в get_value, а кадр на стеке не создан)
  4008c1:	48 89 e5             	mov    %rsp,%rbp (Аналогично)
  4008c4:	48 83 ec 10          	sub    $0x10,%rsp (Тут уже всё OK)
  4008e7:	48 83 c4 10          	add    $0x10,%rsp
  4008eb:	5d                   	pop    %rbp
  4008ec:	c3                   	retq (тут кадра уже нет, а RIP всё ещё в функции)

Изменил программу в соответствии со сказанным (чтобы она уходила с таких мест): перед сохранением бектрейса проверяю, где находится выполнение (функция restore_frame_if_needed):

https://github.com/shamazmazum/vsprofiler/commit/c2dcb87633a27f596bc96516761f...

И получаю непонятный результат в тесте:

(C-S)(main) - C(get_value) - C(crc8) = 23
(C-S)(get_value) - C(factor) = -23
(C-S)(factor) -  = 0
(C-S)(crc8) -  = 0

Т.е. значения 23 и -23, которые из раза в раз всегда противоположные, как будто get_value не попадает в бектрейс.

Какие у вас есть мысли? Пропустил я ещё какие-то краевые случаи или как? Посмотрите, если можете, тот коммит, понять там можно. А запустить у вас может и не выйдет, там анализатор на CL

mashina

Ты в тот раз так помог, что скастану ещё и сюда ;)

avc_fan ()

Спасибо всем откликнувшимся! Я просто ССЗБ. instruction pointer я поправил, а писал старое значение. Теперь в тесте одни нули, как и надо.

прелюдии

Оказывается, правильно называть «пролог». А вот вам вопрос, дорогие ЛОРовцы, может ли шланг/gcc сделать другой пролог, вместо

push %rbp
mov %rsp,%rbp
sub $N,%rsp

Мне казалось, что я видел ещё что-то между push и mov как-то, но пока ничего не нагуглю

avc_fan ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.