LINUX.ORG.RU

Выяснить в runtime по backtrace, из какого исходного файла была вызвана функция

 ,


3

2

Есть один бинарник, который использует несколько библиотек и подозревается в чрезмерной растрате памяти (не утечке — динамика роста RSS не такая взрывная). Хочется выяснить, какая библиотека за это ответственна. Для этого можно взять jemalloc, добавить вручную арен и средствами jemalloc уже вести учет выделенной памяти. Но появляется важный нюанс: как выяснить, кто позвал *alloc?

Для динамической линковки есть довольно надежный способ: сначала через backtrace, а в релизной версии грязными ассемблерными хаками получаем адрес возврата, через `/proc/$pid/map` понимаем, к какой so-шке относится этот адрес и дальше ведем себя соответственно.

Как быть при статической линковке? Есть ли способ отредактировать объектный файл, переопределив имя внешнего символа? Я знаю трюк с частичной линковкой (ld -r), когда можно подставить заглушку, которая будет вызывать нужный метод (так, например, можно все аллокации из libfoo.a заставить использовать malloc_foo/free_foo ценой одного косвенного перехода), но вдруг есть способ лучше?

На всякий случай уточню: исходники трогать нельзя, потому что: 1) так может каждый; 2) хочется странного

Я знаю трюк с частичной линковкой (ld -r),

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

alysnix ★★★
()

Ох, наконец-то я нашел эту волшебную штуковину: https://github.com/j-h-k/Mod-ELF-Symbol

Меняем имена всех malloc/calloc/free/operator new/operator new[]/operator delete/operator []delete на свои => PROFIT

kawaii_neko ★★★★
() автор топика

Используй макрос MALLOC, который будет передавать файл/строку/функцию реальной функции-обёртке malloc-а.

Legioner ★★★★★
()

Есть ли способ отредактировать объектный файл, переопределив имя внешнего символа?

https://github.com/lief-project/LIEF - The purpose of this project is to provide a cross platform library which can parse, modify and abstract ELF, PE and MachO formats.

А еще можно objconv:
https://www.agner.org/optimize/objconv-instructions.pdf#[{%22num%22%3A22%2C%22gen%22%3A0}%2C{%22name%22%3A%22XYZ%22}%2C87%2C734%2C0]

5. Modifying symbols

А еще objcopy
https://sourceware.org/binutils/docs/binutils/objcopy.html

--redefine-sym old=new

Change the name of a symbol old, to new. This can be useful when one is trying link two things together for which you have no source, and there are name collisions.

--redefine-syms=filename

Apply --redefine-sym to each symbol pair «old new» listed in the file filename. filename is simply a flat file, with one symbol pair per line. Line comments may be introduced by the hash character. This option may be given more than once.

SZT ★★★★★
()

А не проще ли взять heaptrack или massif?

сначала через backtrace, а в релизной версии грязными ассемблерными хаками получаем адрес возврата

Не нужны никакие хаки, backtrace и для релизных сборок работает, а если этого мало, то можно собрать релиз с -g и отделить дебажную инфу в отдельные файлы, которые никому не выдавать и использовать для отладки и тестирования

annulen ★★★★★
()

#define malloc(x) _malloc(x,__FILE__,__LINE__,__PRETTY_FUNCTION__)
И сохраняй где-то эту информацию

mittorn ★★★★★
()

Это не странное.

Это у Вас вполне нормальное желание.

Прочёл ранее выступавших ораторов, могу только добавить что я бы пользовался несколько иными инструментами:

  • Если чисто по системным вызовам пробежаться, то я бы использовал как-то типа вот так – strace -e trace=memory -T -o memory_trace.log -fp PID. -T это длительность обработки системного вызова, -е trace это какие сисколлы смотрим, там можно и работу с сетью, файлами и каталогами трассировать, -f это поддержка самого процесса и его потомков, ну и остальное понятно даже без чтения man strace.

  • Если чисто по библиотечным вызовам побегать, то ltrace you_app. Собственно, тут man ltrace и, заодно, гляньте что там у Вас творится в /etc/ltrace.conf или ~/.ltrace.conf. Я имеб в виду то, что сконфигурировать работу этой утилиты можно весьма гибко.

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

Moisha_Liberman ★★
()
Ответ на: Это не странное. от Moisha_Liberman

strace -e trace=memory

Это, на секундочку, всего лишь mmap/munmap/mremap/sbrk

ltrace

Принципиально не работает на статически слинкованных бинарниках. Да и вызов у него весьма странный — всегда проще ручками для LD_PRELOAD-а написать костылик.

kawaii_neko ★★★★
() автор топика
Ответ на: комментарий от kawaii_neko

Уточню.

Это, на секундочку, всего лишь mmap/munmap/mremap/sbrk

Да, но вообще-то, strace позволяет совать нос в любые функции, важно только правильно указать ему куда смотреть надо. Например, вот тут мы с уважаемым @Toxo2 гонялись за execve()Есть ли настоящий C shell, а не csh? Укажите через -e какие функции именно Вас интересуют и вперёд. Если выхлоп не будет помещаться в одну строку, то можете через -s 10000 указать строку вывода в 10000 символов. Должно хватить, на мой взгляд. Писать здесь man strace я не стал ибо это несколько унизительно, как на мой взгляд. Очевидная вообщем-то вещь.

Принципиально не работает на статически слинкованных бинарниках.

Да, Вы правы. Но у меня почему-то сложилось впечатление что у Вас есть и статически и динамически слинкованный код. Возможно я и не прав, извините.

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

Я так же не стал Вам рекомендовать использовать gdb или ptrace для наблюдения за процессом извне, т.к. код может быть тщательно соптимизирован и картину работы с памятью возможно придётся долго восстанавливать. Хотя, в моём случае в gdb том же есть поддержка скриптования на python и скриптами проще искать проблему бывает.

всегда проще ручками для LD_PRELOAD-а написать костылик.

Не всегда возможно, по этой причине я лично на свой вкус и цвет это вариант как правило избегаю.

Moisha_Liberman ★★
()
Последнее исправление: Moisha_Liberman (всего исправлений: 1)

Собрать с отладочными символами, запустить с профилировкой аллокаций, обработать профили pprof-ом, получить картинку.

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