Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support aarch64 #43

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/pgtracer/ebpf/code/perf.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ int perf_event(struct bpf_perf_event_data *ctx)
}
if (need_node)
{
capture_stack(&(ctx->regs), &(stack_sample->stack_data), MAX_STACK_READ);
capture_stack((struct pt_regs *)&(ctx->regs), &(stack_sample->stack_data), MAX_STACK_READ);
}
event_ring.ringbuf_submit(stack_sample, 0);
}
Expand Down
96 changes: 95 additions & 1 deletion src/pgtracer/ebpf/code/stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define STACK_H
#include <linux/sched.h>

#if defined(__x86_64__)
struct stack_data_t {
u64 rax;
u64 rdx;
Expand Down Expand Up @@ -61,5 +62,98 @@ static inline int capture_stack(struct pt_regs *ctx, struct stack_data_t *stack_
}
return ret;
}
#elif defined(__aarch64__)
struct stack_data_t {
u64 x0;
u64 x1;
u64 x2;
u64 x3;
u64 x4;
u64 x5;
u64 x6;
u64 x7;
u64 x8;
u64 x9;
u64 x10;
u64 x11;
u64 x12;
u64 x13;
u64 x14;
u64 x15;
u64 x16;
u64 x17;
u64 x18;
u64 x19;
u64 x20;
u64 x21;
u64 x22;
u64 x23;
u64 x24;
u64 x25;
u64 x26;
u64 x27;
u64 x28;
u64 x29; // frame pointer
u64 x30; // link register
u64 sp; // stack pointer
u64 pc; // program counter
u64 size;
u64 start_addr;
char stack[MAX_STACK_READ]; // Dynamically injected using defines
};

/*
* Capture the current stack and register values.
*/
static inline int capture_stack(struct pt_regs *ctx, struct stack_data_t *stack_data, u64 max_read)
{
int ret = 0;
stack_data->x0 = ctx->regs[0];
stack_data->x1 = ctx->regs[1];
stack_data->x2 = ctx->regs[2];
stack_data->x3 = ctx->regs[3];
stack_data->x4 = ctx->regs[4];
stack_data->x5 = ctx->regs[5];
stack_data->x6 = ctx->regs[6];
stack_data->x7 = ctx->regs[7];
stack_data->x8 = ctx->regs[8];
stack_data->x9 = ctx->regs[9];
stack_data->x10 = ctx->regs[10];
stack_data->x11 = ctx->regs[11];
stack_data->x12 = ctx->regs[12];
stack_data->x13 = ctx->regs[13];
stack_data->x14 = ctx->regs[14];
stack_data->x15 = ctx->regs[15];
stack_data->x16 = ctx->regs[16];
stack_data->x17 = ctx->regs[17];
stack_data->x18 = ctx->regs[18];
stack_data->x19 = ctx->regs[19];
stack_data->x20 = ctx->regs[20];
stack_data->x21 = ctx->regs[21];
stack_data->x22 = ctx->regs[22];
stack_data->x23 = ctx->regs[23];
stack_data->x24 = ctx->regs[24];
stack_data->x25 = ctx->regs[25];
stack_data->x26 = ctx->regs[26];
stack_data->x27 = ctx->regs[27];
stack_data->x28 = ctx->regs[28];
stack_data->x29 = ctx->regs[29];
stack_data->x30 = ctx->regs[30];
stack_data->sp = ctx->sp;
stack_data->pc = ctx->pc;
stack_data->start_addr = stack_data->sp;
stack_data->size = (STACK_TOP_ADDR - stack_data->sp);
if (stack_data->size > max_read)
stack_data->size = max_read;
ret = bpf_probe_read_user(&stack_data->stack,
stack_data->size,
(void *) (stack_data->sp));
if (ret != 0)
{
stack_data->size = 0;
}
return ret;
}
#endif // Arch

#endif
#endif // STACK_H
205 changes: 148 additions & 57 deletions src/pgtracer/ebpf/unwind.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,19 @@ def find_libunwind_version() -> Tuple[int, int]:
if libname is None:
raise ImportError(f"Cannot load libunwind-{ARCH}")
libunwind = ct.cdll.LoadLibrary(libname)

if ARCH not in ["x86_64", "aarch64"]:
raise NotImplementedError(f"Stack unwinding is not supporte for {ARCH} arch")

# same value for x86_64 and aarch64
unw_word_t = ct.c_ulonglong
UNW_WORD_T_FORMAT = "<Q"
unw_tdep_fpreg_t = ct.c_longdouble
MAX_STACK_READ = 1 << 16
stack_array = ct.c_ubyte * MAX_STACK_READ

if ARCH == "x86_64":
UNW_TDEP_CURSOR_LEN = 127
unw_word_t = ct.c_ulonglong
UNW_WORD_T_FORMAT = "<Q"
unw_tdep_fpreg_t = ct.c_longdouble
MAX_STACK_READ = 1 << 16
stack_array = ct.c_ubyte * MAX_STACK_READ
REG_NAMES = [
"rax",
"rdx",
Expand All @@ -111,64 +117,149 @@ def find_libunwind_version() -> Tuple[int, int]:
"rip",
]
UNW_REG_IP = REG_NAMES.index("rip")
stack_data_fields_list = [
("rax", ct.c_ulong),
("rdx", ct.c_ulong),
("rcx", ct.c_ulong),
("rbx", ct.c_ulong),
("rsi", ct.c_ulong),
("rdi", ct.c_ulong),
("rbp", ct.c_ulong),
("rsp", ct.c_ulong),
("r8", ct.c_ulong),
("r9", ct.c_ulong),
("r10", ct.c_ulong),
("r11", ct.c_ulong),
("r12", ct.c_ulong),
("r13", ct.c_ulong),
("r14", ct.c_ulong),
("r15", ct.c_ulong),
("rip", ct.c_ulong),
("size", ct.c_ulong),
("start_addr", ct.c_ulong),
("stack", stack_array),
]

# This corresponds to the stack and registers captured from ebpf,
# and is architecture specific
class stack_data_t(ct.Structure):
"""
Mapping of stack_data_t type, defined in ebpf code.
"""

_fields_ = [
("rax", ct.c_ulong),
("rdx", ct.c_ulong),
("rcx", ct.c_ulong),
("rbx", ct.c_ulong),
("rsi", ct.c_ulong),
("rdi", ct.c_ulong),
("rbp", ct.c_ulong),
("rsp", ct.c_ulong),
("r8", ct.c_ulong),
("r9", ct.c_ulong),
("r10", ct.c_ulong),
("r11", ct.c_ulong),
("r12", ct.c_ulong),
("r13", ct.c_ulong),
("r14", ct.c_ulong),
("r15", ct.c_ulong),
("rip", ct.c_ulong),
("size", ct.c_ulong),
("start_addr", ct.c_ulong),
("stack", stack_array),
]
elif ARCH == "aarch64":
UNW_TDEP_CURSOR_LEN = 256 # Placeholder value, adapt as needed
REG_NAMES = [
"x0",
"x1",
"x2",
"x3",
"x4",
"x5",
"x6",
"x7",
"x8",
"x9",
"x10",
"x11",
"x12",
"x13",
"x14",
"x15",
"x16",
"x17",
"x18",
"x19",
"x20",
"x21",
"x22",
"x23",
"x24",
"x25",
"x26",
"x27",
"x28",
"x29",
"x30",
"sp",
"pc",
]
UNW_REG_IP = REG_NAMES.index("pc")
stack_data_fields_list = [(reg, ct.c_ulong) for reg in REG_NAMES] + [
("size", ct.c_ulong),
("start_addr", ct.c_ulong),
("stack", stack_array),
]

class unw_tdep_proc_info_t(ct.Structure):
"""
Mapping of unw_tdep_proc_info_t
"""
elif ARCH == "aarch64":
UNW_TDEP_CURSOR_LEN = 256 # Placeholder value, adapt as needed
REG_NAMES = [
"x0",
"x1",
"x2",
"x3",
"x4",
"x5",
"x6",
"x7",
"x8",
"x9",
"x10",
"x11",
"x12",
"x13",
"x14",
"x15",
"x16",
"x17",
"x18",
"x19",
"x20",
"x21",
"x22",
"x23",
"x24",
"x25",
"x26",
"x27",
"x28",
"x29",
"x30",
"sp",
"pc",
]
UNW_REG_IP = REG_NAMES.index("pc")

_fields_ = [("unused", ct.c_char)]

class unw_proc_info_t(ct.Structure):
"""
Mapping of unw_proc_info_t type
"""
# This corresponds to the stack and registers captured from ebpf,
# and is architecture specific
class stack_data_t(ct.Structure):
"""
Mapping of stack_data_t type, defined in ebpf code.
"""

_fields_ = [
("start_ip", unw_word_t),
("end_ip", unw_word_t),
("lsda", unw_word_t),
("handler", unw_word_t),
("gp", unw_word_t),
("flags", unw_word_t),
("format", ct.c_int),
("unwind_info_size", ct.c_int),
("unwind_info", ct.c_void_p),
("extra", unw_tdep_proc_info_t),
] # FIXME; this type
_fields_ = stack_data_fields_list


class unw_tdep_proc_info_t(ct.Structure):
"""
Mapping of unw_tdep_proc_info_t
"""

_fields_ = [("unused", ct.c_char)]


class unw_proc_info_t(ct.Structure):
"""
Mapping of unw_proc_info_t type
"""

_fields_ = [
("start_ip", unw_word_t),
("end_ip", unw_word_t),
("lsda", unw_word_t),
("handler", unw_word_t),
("gp", unw_word_t),
("flags", unw_word_t),
("format", ct.c_int),
("unwind_info_size", ct.c_int),
("unwind_info", ct.c_void_p),
("extra", unw_tdep_proc_info_t),
]

else:
raise NotImplementedError(f"Stack unwinding is not supporte for {ARCH} arch")

UNW_INFO_FORMAT_REMOTE_TABLE = 2
UNW_ENOINFO = 10
Expand Down