Linux tracepoint使用和理解
1.如何查看tracepoint
/sys/kernel/debug/tracing/events/
通过perf list tracepoint查看
2. tracepoint理解

因此tracepoint方式如下:
#undef TRACE_SYSTEM
#define TRACE_SYSTEM xhr_test
#if !defined(_TRACE_TE_TEST_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_TE_TEST_H
#include <linux/tracepoint.h>
TRACE_EVENT(te_test, // 定义函数trace_te_test
TP_PROTO(int num), // 函数接收参数 int 类型
TP_ARGS(num),
TP_STRUCT__entry(
__field(int, output) // 字段名
__field(int, count) // 字段名
),
TP_fast_assign(
__entry->count++;
__entry->output = num; // output 等于传入的参数 num
),
TP_printk("count=%d output=%d",
__entry->count, __entry->output)
);
#endif /* _TRACE_TE_TEST_H */
/* This part must be outside protection */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH . //定义路径,找不到你就写绝对路径
#define TRACE_INCLUDE_FILE trace_event //定义文件 trace_event.h
#include <trace/define_trace.h>
因此,只要调用 trace_te_test(int num)即可

3.快速查找tracepoint
grep -rn TRACE_EVENT(name, ...)
4.Android中的tracepoint
下面是官网的例子:
#include <linux/bpf.h>
#include <stdbool.h>
#include <stdint.h>
#include <bpf_helpers.h>
DEFINE_BPF_MAP(cpu_pid_map, ARRAY, int, uint32_t, 1024);
struct switch_args {
unsigned long long ignore;
char prev_comm[16];
int prev_pid;
int prev_prio;
long long prev_state;
char next_comm[16];
int next_pid;
int next_prio;
};
DEFINE_BPF_PROG("tracepoint/sched/sched_switch", AID_ROOT, AID_SYSTEM, tp_sched_switch)
(struct switch_args *args) {
int key;
uint32_t val;
key = bpf_get_smp_processor_id();
val = args->next_pid;
bpf_cpu_pid_map_update_elem(&key, &val, BPF_ANY);
return 1; // return 1 to avoid blocking simpleperf from receiving events
}
LICENSE("GPL");
struct switch_args是干嘛的,我可以把结构体改了吗? 假如我使用其他tracepoint,我改怎么定义这个结构体? 网上千篇一律的复制粘贴文章,总算找到个解释的. Android之TRACEPOINT
这里的switch_args结构体,构成可以从/sys/kernel/debug/tracing/events/sched/sched_switch/format得到,现在我们再来看struct switch_args就能理解了
name: sched_switch
ID: 52
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1; // 对应到 switch_args.ignore (long long 八个字节)
field:char prev_comm[16]; offset:8; size:16; signed:0; // 对应到 switch_args.prev_comm 字段 16字节
field:pid_t prev_pid; offset:24; size:4; signed:1; // 对应 switch_args.prev_pid 4字节
field:int prev_prio; offset:28; size:4; signed:1;
field:long prev_state; offset:32; size:8; signed:1;
field:char next_comm[16]; offset:40; size:16; signed:0;
field:pid_t next_pid; offset:56; size:4; signed:1;
field:int next_prio; offset:60; size:4; signed:1;
switch_args.ignore 是long long类型,共8个字节,因此对应到 format中的 common_pid,以此类推
5.实战
在设备上随便找了个task_rename跟踪点进行测试,不再是千篇一律的sched_switch
PS: 注意看自己设备有没有这个 tracepoint
# cat /sys/kernel/debug/tracing/events/task/task_rename/format
name: task_rename
ID: 27
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:pid_t pid; offset:8; size:4; signed:1;
field:char oldcomm[16]; offset:12; size:16; signed:0;
field:char newcomm[16]; offset:28; size:16; signed:0;
field:short oom_score_adj; offset:44; size:2; signed:1;
print fmt: "pid=%d oldcomm=%s newcomm=%s oom_score_adj=%hd", REC->pid, REC->oldcomm, REC->newcomm, REC->oom_score_adj
对应代码:
// bpf_trace_task_rename.c
#include <linux/bpf.h>
#include <stdbool.h>
#include <stdint.h>
#include <bpf_helpers.h>
#include <string.h>
struct task_rename_args {
unsigned long long ignore;
int pid;
char oldcomm[16];
char newcomm[16];
short oom_score_adj;
};
struct data {
int pid;
char newcomm[16];
};
DEFINE_BPF_MAP(task_rename_map, ARRAY, int, struct data, 1024);
// SEC("tracepoint/sched/sched_switch")
DEFINE_BPF_PROG("tracepoint/task/task_rename", AID_ROOT, AID_NET_ADMIN, tp_sched_switch)
(struct task_rename_args* args) {
int key = 100;
struct data data_t;
// 这行打开导致bpfload 加载prog失败,权限不足. 可能是因为我设备特殊性,真机没试过
//bpf_trace_printk("pid %ld %s %s\n", args->pid, args->oldcomm, args->newcomm);
data_t.pid = args->pid;
//data_t.newcomm = args->newcomm;
memcpy(data_t.newcomm, args->newcomm, 16);
bpf_task_rename_map_update_elem(&key, &data_t, BPF_ANY);
return 0;
}
// char _license[] SEC("license") = "GPL";
LICENSE("Apache 2.0");
cli程序
// bpf_trace_task_rename_cli.cpp
#include <android-base/macros.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <bpf/BpfMap.h> // system/bpf/libbpf_android/include/bpf/BpfMap.h
#include <bpf/BpfUtils.h>
#include <libbpf_android.h>
struct data {
int pid;
char newcomm[16];
};
int main() {
constexpr const char tp_prog_path[] = "/sys/fs/bpf/prog_bpf_trace_task_rename_tracepoint_task_task_rename";
constexpr const char tp_map_path[] = "/sys/fs/bpf/map_bpf_trace_task_rename_task_rename_map";
// Attach tracepoint and wait for 4 seconds
int mProgFd = bpf_obj_get(tp_prog_path);
// int mMapFd = bpf_obj_get(tp_map_path);
bpf_attach_tracepoint(mProgFd, "task", "task_rename");
sleep(1);
// 高版本使用fd构造BpfMap
android::bpf::BpfMap<int, struct data> myMap(tp_map_path);
pid_t pid = getpid();
printf("pid: %d\n", pid);
while(1) {
usleep(40000);
// android::base::Result<Value> 类型
data data_t = myMap.readValue(100).value();
printf("PID %d rename to %s\n", data_t.pid, data_t.newcomm);
}
exit(0);
}
bpf {
name: "bpf_task_rename.o",
srcs: ["bpf_trace_task_rename.c"],
cflags: [
"-Wall",
"-Werror",
],
}
cc_binary {
name: "bpf_trace_task_rename_cli",
cflags: [
"-Wall",
"-Werror",
"-Wthread-safety",
],
clang: true,
shared_libs: [
"libcutils",
"libbpf_android",
"libbase",
"liblog",
"libnetdutils",
"libbpf",
],
srcs: [
"bpf_trace_task_rename_cli.cpp",
],
}
最后效果


浙公网安备 33010602011771号