AlexBR

Я сразу приведу список статей на которые опирался, при проведении дальнейших экпериментов:

  1. Using System Tap to test the GNU C Library
  2. Стандартные утилиты для UNIX-программиста

Список макроопределений systemtap:

Название Описание
$$vars Expands to a character string that is equivalent to sprintf("parm1=%x ... parmN=%x var1=%x ... varN=%x", parm1, ..., parmN, var1, ..., varN) for each variable in scope at the probe point. Some values may be printed as “=?” if their run-time location cannot be found.
$$locals Expands to a subset of $$vars containing only the local variables.
$$parms Expands to a subset of $$vars containing only the function parameters.
$$return Is available in return probes only. It expands to a string that is equivalent to sprintf("return=%x", $return) if the probed function has a return value, or else an empty string

Продолжу...

И так мы имеем программу memory, давайте отследим, сколько раз в ней вызывается malloc функция:

  1. Найдем сведения о фнукции malloc, необходимы для systemtap 1.1 Анализируем бинарник утилитой nm
    [probes]# nm ./memory | grep malloc
                 U malloc@@GLIBC_2.2.5

    Это нам говорит, что символ не определен U, значит он из библиотеки. 1.2 Проверим список библиотек утилитой ldd:

    [probes]# ldd ./memory
    linux-vdso.so.1 =>  (0x00007fff1fde4000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f900d6d4000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f900daaf000)

    Функция скорее всего в /lib64/libc.so.6 1.3 проверим это утилитой nm опять, но уже на файл библиотеки:

    [probes]# nm /lib64/libc.so.6 | grep malloc
    ...
    000000000007ff70 T __libc_malloc
    000000000007ff70 T malloc
    000000000007ff70 t __malloc

    Теперь то что нужно, T или t

  2. Значит дочтавляем debuginfo для glibc yum install glibc-debuginfo. И прогоняем вот такую команду:
    [probes]# stap -L 'process("/lib64/libc.so.6").statement("*malloc*")'
    process("/usr/lib64/libc-2.17.so").statement("__libc_malloc@/usr/src/debug/glibc-2.17-c758a686/malloc/malloc.c:2881") $bytes:size_t

    Вот первая попавшаяса функция, та что нам нужна, и информация о параметре - имя и размерность $bytes:size_t. Допишем наш проб, чтоб он выводил, что-нибудь при вызове функции malloc и выдавал, что она возвращает и самое интересное, где именно.

Немного покопавшись с кодом malloc.c, и поэкспериментировав с process("/lib64/libc.so.6").function("__libc_malloc"), я обнаружил, что она вызывается дважды. Поэтому в результирующем пробе, я поставил точку проверки на _int_malloc и на free:

#! /usr/bin/env stap

probe process("./memory").begin {
    printf("Test process started %d\n", pid())
}

probe process("./memory").end {
    printf("Test process ended %d\n", pid())
}

probe process("/lib64/libc.so.6").function("_int_malloc"){
    printf("%s:%s malloc called with param %d\n", pp(), ppfunc(), $bytes)
}

probe process("/lib64/libc.so.6").function("_int_malloc").return{
    printf("malloc returned %p\n", $return)
}

probe process("/lib64/libc.so.6").function("free"){
    printf("free called with param %p\n", $mem)
}

probe begin {
    printf("Waiting for even or Ctrl+C\n")
}

И работа программы:

[probes]# stap malloc.stp -c "./memory"
Waiting for even or Ctrl+C
Test process started 6231
process("/usr/lib64/libc-2.17.so").function("_int_malloc@/usr/src/debug/glibc-2.17-c758a686/malloc/malloc.c:3308"):_int_malloc malloc called with param 1024
malloc returned 0x767010
free called with param 0x767010
Test process ended 6231

А теперь промоделируем ситуация, когда malloc возвращает NULL:

#! /usr/bin/env stap

probe process("./memory").begin {
    printf("Test process started %d\n", pid())
}

probe process("./memory").end {
    printf("Test process ended %d\n", pid())
}

probe process("/lib64/libc.so.6").function("_int_malloc"){
    printf("%s:%s malloc called with param %d\n", pp(), ppfunc(), $bytes)
}

probe process("/lib64/libc.so.6").function("_int_malloc").return{
    $return = 0
}

probe process("/lib64/libc.so.6").function("free"){
    printf("free called with param %p\n", $mem)
}

probe begin {
    printf("Waiting for even or Ctrl+C\n")
}

В пробе probe process("/lib64/libc.so.6").function("_int_malloc").return я перезаписал возвращаемое значение в 0 функцией $return = 0 и вот результат:

[probes]# stap -g malloc.stp -c "./memory"
Ooops
WARNING: Child process exited with status 1
Waiting for even or Ctrl+C
Test process started 6512
process("/usr/lib64/libc-2.17.so").function("_int_malloc@/usr/src/debug/glibc-2.17-c758a686/malloc/malloc.c:3308"):_int_malloc malloc called with param 1024
process("/usr/lib64/libc-2.17.so").function("_int_malloc@/usr/src/debug/glibc-2.17-c758a686/malloc/malloc.c:3308"):_int_malloc malloc called with param 1024
Test process ended 6512
WARNING: /usr/bin/staprun exited with status: 1
Pass 5: run failed.  [man error::pass5]

Программу я запускал в guru-mode иначе stap не позволит переписать $return. По выводу видим, что дважды программа пыталась выделить память и в результате прекратила работу сообщив Ooops.