参考stackplz实现对syscall进行栈回溯的时候不知道为什么回溯出来的堆栈不完整,但是成功回溯的部分都是准确的,具体情况如下第一个是期望的结果,是stackplz生成的,下面那个是实际结果,检查过sp,pc的值也是对的,这里两个例子不是同一处函数调用代码贴这里,采集栈的时候试了很多种办法,试过bpf_get_stack和直接用bpf_read_user从sp开始读16kb的栈数据,但是结果都是一样的,栈都是只能回溯2到3层,不清楚是采集的问题还是unwindstack设置错了,如果是采集的问题有没有不用patch libbpf后用perf_event_submit的方法,主要是不是很想用perf_buffer传递数据//+build ignore
#include "common.h"
#include "vmlinux.h"
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
const struct sysEnterData *unusedsysEnterData __attribute__((unused));
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, PAGE_SIZE * 65536);
} sysEnterRb SEC(".maps");
static void bufRead(struct sysEnterData *data) {
switch (data->syscall_id) {
case OPENAT:
case READ:
case WRITE:
case PREAD64:
case PWRITE64:
case NEWFSTATAT:
case EXECVEAT:
case OPENAT2:
case READLINKAT:
bpf_probe_read_user_str(data->argBuf[0], sizeof(data->argBuf[0]),
(void *)data->regs[1]);
break;
case EXECVE:
bpf_probe_read_user_str(data->argBuf[0], sizeof(data->argBuf[0]),
(void *)data->regs[0]);
break;
default:
break;
#define MAX_MEMORY_RANGE 128
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, MAX_MEMORY_RANGE);
__type(key, u32);
__type(value, struct memoryRange);
} targetMemoryRange SEC(".maps");
struct memoryCheckCtx {
bool found;
int pc;
static int memory_check(u64 idx, void *ctx) {
struct memoryCheckCtx *checkCtx = ctx;
struct memoryRange *range = bpf_map_lookup_elem(&targetMemoryRange, &idx);
if (range == NULL || (range->start == 0)) {
return 1; // skip empty or invalid ranges
if (checkCtx->pc >= range->start && checkCtx->pc <= range->end) {
checkCtx->found = true;
return 1; // stop iterating
return 0; // continue iterating
bool filter_MemoryRange(uint64_t pc) {
bpf_loop(MAX_MEMORY_RANGE, memory_check, &checkCtx, 0);
return checkCtx.found;
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 0x1c3);
__type(key, u32);
__type(value, u8);
} targetSyscalls SEC(".maps");
bool filter_syscall(long id) {
bool *isTarget = bpf_map_lookup_elem(&targetSyscalls, &id);
if (isTarget == NULL) {
return false;
return *isTarget;
SEC("tp_btf/sys_enter")
int BPF_PROG(sys_enter, struct pt_regs *regs, long id) {
// bpf_printk("pid : %d target : %d \n", (bpf_get_current_pid_tgid() >> 32),
// targetPid);
if ((bpf_get_current_pid_tgid() >> 32) != targetPid) {
return 0;
if (!filter_syscall(id))
return 0;
// if (!filter_MemoryRange(regs->pc))
// return 0;
bpf_printk("pid: %d nr: %d \n", bpf_get_current_pid_tgid() >> 32, id);
// prepare the stack data
struct sysEnterData *data =
bpf_ringbuf_reserve(&sysEnterRb, sizeof(struct sysEnterData), 0);
if (data == NULL) {
bpf_printk("Failed to reser
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288158.htm
ebpf/unwindstack栈回溯不完整
378 浏览
2 回复
tql
1c1K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6e0k6h3g2r3L8r3!0%4k6i4u0j5i4K6u0r3k6h3u0H3k6W2)9J5c8X3u0D9L8$3u0Q4x3V1j5$3x3h3y4T1j5K6c8S2x3K6N6W2z5o6t1$3y4r3x3K6y4K6R3^5y4o6V1@1j5e0M7@1k6r3y4W2j5K6V1&6x3X3x3$3x3K6k6T1z5e0p5^5i4K6u0r3M7r3g2J5k6W2)9J5c8Y4u0A6L8X3N6Q4x3X3g2Y4L8#2)9J5x3@1H3I4y4e0t1`.
两种采集方式有差异,正是因为基于stack frame的效果不好,才用的dwarf的模式
可以阅读这位作者写的文章 https://bbs.kanxue.com/thread-274546.htm
两种采集方式有差异,正是因为基于stack frame的效果不好,才用的dwarf的模式
可以阅读这位作者写的文章 https://bbs.kanxue.com/thread-274546.htm