Взять имя вызываемой функции в eBPF - PullRequest
0 голосов
/ 19 ноября 2018

Я бы хотел отследить функции конкретного PID и собрать некоторую статистику (общее количество вызовов, общее время и т. Д.), И мне не совсем ясно, как создать BPF_HASH с парами funcname + my_struct.

Есть ли способ получить имена вызываемых функций в программе BPF?

Полагаю, мне следует прочитать регистр IP с помощью «PT_REGS_IP (ctx)», но я не совсем понимаю, как преобразовать значение в читаемую человеком строку.

На данный момент программа BPF выглядит следующим образом:

#include <uapi/linux/ptrace.h>
#include <linux/sched.h>

struct data_t {
    u32 pid;
    u64 delta;
    u64 start;
} __attribute__((packed));

BPF_HASH(faddr, u64, struct data_t);
BPF_PERF_OUTPUT(events);

int do_entry(struct pt_regs *ctx) {
    struct data_t *data;
    data->start = bpf_ktime_get_ns();
    u64 ip = PT_REGS_IP(ctx);
    faddr.update(&ip, data);

    return 0;
}

int do_return(struct pt_regs *ctx) {
    struct data_t *data;
    u64 ip = PT_REGS_IP(ctx);
    data = faddr.lookup(&ip);

    if (data->start == 0)
        return 0;       // missed start

    data->delta = bpf_ktime_get_ns() - data->start;
    data->pid = bpf_get_current_pid_tgid();

    events.perf_submit(ctx, &data, sizeof(data));
    faddr.delete(&ip);

    return 0;
}

Но при запуске я получил:

error: <unknown>:0:0: in function do_entry i32 (%struct.pt_regs*): A call to built-in function 'abort' is not supported.

1 Ответ

0 голосов
/ 20 ноября 2018

У вас есть ошибка в вашей функции do_entry. Вы пытаетесь разыменовать нулевой указатель:

struct data_t *data;
data->start = bpf_ktime_get_ns();

Следующее должно работать лучше:

int do_entry(struct pt_regs *ctx) {
    struct data_t data = {}; // initializes data with zeros.
    data.start = bpf_ktime_get_ns();
    u64 ip = PT_REGS_IP(ctx);
    faddr.update(&ip, &data);
    return 0;
}

Я не понимаю, почему в сообщении об ошибке упоминается abort. Я спрошу вокруг.


Как преобразовать адреса памяти в имена функций будет зависеть от используемой вами библиотеки пользовательского пространства. Если вы используете bcc, вы можете использовать метод ksym. Я не знаю, есть ли эквивалент в gobpf.


У вас есть по крайней мере еще одна ошибка, в do_return:

data = faddr.lookup(&ip);
if (data->start == 0)
    return 0;       // missed start

Вам нужно будет проверить, не является ли значение data нулевым, перед разыменованием В противном случае верификатор отклонит вашу программу.

data = faddr.lookup(&ip);
if (!data || data->start == 0)
    return 0;       // missed start
...