LINUX.ORG.RU

трейсинг malloc/free


0

1

хочу написать тулзу использующую ptrace() для трейсинга malloc()/free().

знаю, что malloc()/free() - не сисколы, потому ptrace() не сможет их трейсить. для того чтоб определить, какие сисколы в реале используются, набросал тест и запусти его под strace:

#include <stdlib.h>

int main() {
   void *p = malloc(32);
   free(p);
}
скомпилял, запустил, получил такой вывод:
execve("./malloc", ["./malloc"], [/* 74 vars */]) = 0
brk(0)                                  = 0xd00000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f505301d000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=152675, ...}) = 0
mmap(NULL, 152675, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5052ff7000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1845024, ...}) = 0
mmap(NULL, 3953344, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5052a37000
mprotect(0x7f5052bf3000, 2093056, PROT_NONE) = 0
mmap(0x7f5052df2000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bb000) = 0x7f5052df2000
mmap(0x7f5052df8000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5052df8000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5052ff6000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5052ff4000
arch_prctl(ARCH_SET_FS, 0x7f5052ff4740) = 0
mprotect(0x7f5052df2000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f505301f000, 4096, PROT_READ) = 0
munmap(0x7f5052ff7000, 152675)          = 0
mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5052ef3000
munmap(0x7f5052ef3000, 1052672)         = 0
exit_group(1048576)                     = ?
+++ exited with 0 +++
далее, закоментил malloc()/free(), и снова скомпилял и запустил, и получил такой вывод:
execve("./malloc", ["./malloc"], [/* 74 vars */]) = 0
brk(0)                                  = 0x1aea000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72854ce000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=152675, ...}) = 0
mmap(NULL, 152675, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f72854a8000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1845024, ...}) = 0
mmap(NULL, 3953344, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7284ee8000
mprotect(0x7f72850a4000, 2093056, PROT_NONE) = 0
mmap(0x7f72852a3000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bb000) = 0x7f72852a3000
mmap(0x7f72852a9000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f72852a9000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72854a7000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f72854a5000
arch_prctl(ARCH_SET_FS, 0x7f72854a5740) = 0
mprotect(0x7f72852a3000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f72854d0000, 4096, PROT_READ) = 0
munmap(0x7f72854a8000, 152675)          = 0
exit_group(1048576)                     = ?
+++ exited with 0 +++
т.е. разница здесь в двух вызовах, которые присутствуют в первом, и отсутствуют во втором(с конца):
mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5052ef3000
munmap(0x7f5052ef3000, 1052672)         = 0

т.е. я правильно понимаю, что mmap()/munmap() используются для malloc()/free() соответственно? второй вопрос в том, каким образом я могу определить, что эти mmap()/munmap() используются именно для malloc()/free(), а не для мапинга файла, к примеру?

кто-то вообще копал в этом направлении? или, может быть, кто-то знает где есть решение похожее тому, что я пытаюсь сделать?

благодарен.

★★★

Если бы я писал такой велосипед (но я бы не стал, конечно), то сначала попробовал бы LD_PRELOAD, потом посмотрел бы, как это делает ltrace.

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

каким образом я могу определить, что эти mmap()/munmap() используются именно для malloc()/free(), а не для мапинга файла

MAP_ANONYMOUS — значит не файл. В принципе, комбинация PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS должна быть во всех malloc. А munmap только через учёт адресов

monk ★★★★★ ()

Сделай либу с маллок фри и прелоади её как тейлганнер говорит.

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

я знаю про LD_PRELOAD и про то, что могу поставить свои заглушки на malloc()/free(). но мне этот способ не подходит по ряду причин...сложно объяснить...

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

MAP_ANONYMOUS — значит не файл.

так что, можно с увереностью утверждать, что если во флагах есть MAP_ANONYMOUS, то этот вызов mmap() используется для malloc() ?

А munmap только через учёт адресов

ну да.

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

так что, можно с увереностью утверждать, что если во флагах есть MAP_ANONYMOUS, то этот вызов mmap() используется для malloc() ?

Или calloc, или realloc, или руками запущенный mmap. Можно только точно сказать, что это не файл, а какая-то аллокация памяти.

monk ★★★★★ ()

т.е. я правильно понимаю, что mmap()/munmap() используются для malloc()/free() соответственно?

Да.

второй вопрос в том, каким образом я могу определить, что эти mmap()/munmap() используются именно для malloc()/free(), а не для мапинга файла, к примеру?

Никак.

но мне этот способ не подходит по ряду причин...сложно объяснить...

Это означает что ты сам не до конца понимаешь чего хочешь.

slovazap ★★★★★ ()

Кроме mmap с MAP_PRIVATE|MAP_ANONYMOUS, еще м.б. brk

nerdogeek ()
Ответ на: комментарий от slovazap

Это означает что ты сам не до конца понимаешь чего хочешь.

ну тебе же виднее, ага.

niXman ★★★ ()

Тред не читал, но valgrind ещё никто не посоветовал?

UVV ★★★★★ ()

или, может быть, кто-то знает где есть решение похожее тому, что я пытаюсь сделать?

man malloc, mtrace; see malloc.h

MKuznetsov ★★★★★ ()

А разве есть какие-то гарантии, что malloc будет дергать сисколлы?

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

Схуя ты взял, что вызов malloc приведет к вызову mmap?

anonymous ()
Ответ на: комментарий от niXman

сложно объяснить...

не можешь объяснить == не знаешь

anonymous ()

dtrace -n 'pid$target::malloc:entry,pid$target::free:entry' -c $CMD

anonymous ()

т.е. я правильно понимаю, что mmap()/munmap() используются для malloc()/free() соответственно?

Первый вызов malloc выделяет «арену», из которой следующие вызовы будут выделять память. Когда понадобится, их будет запрошено больше. При завершении программы память арен возвращается системе. То есть в этом простом примере соответствуют, но в общем случае — нет.

i-rinat ★★★★★ ()

FreeBSD-шный malloc так умеет

Соберись с ним.

anonymous ()

отличие от файла

1) mmap вызов, который по идее должен, конвертировать смещение в байтах в смещение страниц и дернуть вызов mmap_pgoff тут написана вся последовательность

2) заглянем в системный вызов

1376 SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
1377                 unsigned long, prot, unsigned long, flags,
1378                 unsigned long, fd, unsigned long, pgoff)
1379 {
1380         struct file *file = NULL;
1381         unsigned long retval = -EBADF;
1382 
1383         if (!(flags & MAP_ANONYMOUS)) {
1384                 audit_mmap_fd(fd, flags);
1385                 file = fget(fd);
1386                 if (!file)
1387                         goto out;
если пункт 1 верен, то прихожу к выводу, наличие флага MAP_ANONYMOUS исключает использование внешних файлов, открытах в рамках процесса

conquistador ()

man mmap

3) ну и в мане сказано по поводу -1 в качестве fd

MAP_ANONYMOUS The mapping is not backed by any file; its contents are initialized to zero. The fd and offset arguments are ignored; however, some implementations require fd to be -1 if MAP_ANONYMOUS (or MAP_ANON) is specified, and portable applications should ensure this. The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is supported on Linux only since kernel 2.4.

conquistador ()

т.е. я правильно понимаю, что mmap()/munmap() используются для malloc()/free() соответственно?

Нет. malloc()/free() может проксировать твои вызовы на свой враппер к mmap(MAP_ANONYMOUS). Это происходит в гнутом маллоке при аллокации больше M_MMAP_THRESHOLD.

Вызовы маллока по mmap() ты не отследишь.

второй вопрос в том, каким образом я могу определить, что эти mmap()/munmap() используются именно для malloc()/free(), а не для мапинга файла, к примеру?

Для маллока «никак». Что такое MAP_ANONYMOUS тебе уже сказали - сходи в мануал.

кто-то вообще копал в этом направлении? или, может быть, кто-то знает где есть решение похожее тому, что я пытаюсь сделать?

Нету - оно не возможно в принципе. Маллок может юзать что угодно и когда угодно. Делай через трейс вшитый в маллок, либо через LD_PRELOAD.

Carb_blog7 ()

зачем писать велосипед, если можно использовать, например, tcmalloc

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