|
2 | 2 | #include "tracemgmt.h"
|
3 | 3 | #include "types.h"
|
4 | 4 |
|
| 5 | +// The number of frames to unwind per frame-unwinding eBPF program. |
| 6 | +#define FRAMES_PER_PROGRAM 8 |
| 7 | + |
5 | 8 | bpf_map_def SEC("maps") beam_procs = {
|
6 | 9 | .type = BPF_MAP_TYPE_HASH,
|
7 | 10 | .key_size = sizeof(pid_t),
|
8 | 11 | .value_size = sizeof(BEAMProcInfo),
|
9 | 12 | .max_entries = 1024,
|
10 | 13 | };
|
11 | 14 |
|
| 15 | +static inline __attribute__((__always_inline__)) |
| 16 | +ErrorCode unwind_one_frame(PerCPURecord *record, BEAMProcInfo *info, bool top) { |
| 17 | + UnwindState *state = &record->state; |
| 18 | + Trace *trace = &record->trace; |
| 19 | + unsigned long regs[2], sp = state->sp, fp = state->fp, pc = state->pc; |
| 20 | + |
| 21 | + DEBUG_PRINT("beam: pc: %lx, sp: %lx, fp: %lx", pc, sp, fp); |
| 22 | + |
| 23 | + if (fp) { |
| 24 | + unwinder_mark_nonleaf_frame(state); |
| 25 | + } |
| 26 | + _push_with_return_address(trace, 0xf00d, pc, FRAME_MARKER_BEAM, state->return_address); |
| 27 | + |
| 28 | + // Data that will be sent to HA is in these variables. |
| 29 | + //uintptr_t pointer_and_type = 0, delta_or_marker = 0; |
| 30 | + |
| 31 | +frame_done: |
| 32 | + // Unwind with frame pointer |
| 33 | + if (bpf_probe_read_user(regs, sizeof(regs), (void*)fp)) { |
| 34 | + DEBUG_PRINT("beam: --> bad frame pointer"); |
| 35 | + return ERR_UNREACHABLE; |
| 36 | + } |
| 37 | + |
| 38 | + state->sp = fp + sizeof(regs); |
| 39 | + state->fp = regs[0]; |
| 40 | + state->pc = regs[1]; |
| 41 | + if (state->fp) { |
| 42 | + unwinder_mark_nonleaf_frame(state); |
| 43 | + } |
| 44 | + |
| 45 | + DEBUG_PRINT("beam: pc: %lx, sp: %lx, fp: %lx", |
| 46 | + (unsigned long) state->pc, (unsigned long) state->sp, |
| 47 | + (unsigned long) state->fp); |
| 48 | + |
| 49 | + return ERR_OK; |
| 50 | +} |
| 51 | + |
12 | 52 | SEC("perf_event/unwind_beam")
|
13 | 53 | int unwind_beam(struct pt_regs *ctx) {
|
14 |
| - static const char fmt[] = "Unwinding BEAM stack"; |
15 |
| - bpf_trace_printk(fmt, sizeof(fmt)); |
16 |
| - DEBUG_PRINT("Unwinding BEAM stack"); |
| 54 | + DEBUG_PRINT(">>>>>>>>>>>>>>>>>Unwinding BEAM stack<<<<<<<<<<<<<<<<<"); |
17 | 55 |
|
18 | 56 | PerCPURecord *record = get_per_cpu_record();
|
19 | 57 | if (!record) {
|
20 | 58 | return -1;
|
21 | 59 | }
|
22 | 60 |
|
23 |
| - int unwinder = get_next_unwinder_after_interpreter(record); |
24 |
| - u32 pid = record->trace.pid; |
| 61 | + Trace *trace = &record->trace; |
| 62 | + u32 pid = trace->pid; |
| 63 | + DEBUG_PRINT("==== unwind_beam %d ====", trace->stack_len); |
25 | 64 |
|
26 |
| - BEAMProcInfo *beaminfo = bpf_map_lookup_elem(&beam_procs, &pid); |
27 |
| - if (!beaminfo) { |
28 |
| - DEBUG_PRINT("No BEAM introspection data"); |
| 65 | + int unwinder = PROG_UNWIND_STOP; |
| 66 | + ErrorCode error = ERR_OK; |
| 67 | + BEAMProcInfo *info = bpf_map_lookup_elem(&beam_procs, &pid); |
| 68 | + if (!info) { |
| 69 | + DEBUG_PRINT("beam: no BEAMProcInfo for this pid"); |
29 | 70 | goto exit;
|
30 | 71 | }
|
31 | 72 |
|
32 |
| - DEBUG_PRINT("==== unwind_beam stack_len: %d, pid: %d ====", record->trace.stack_len, record->trace.pid); |
| 73 | +#pragma unroll |
| 74 | + for (int i = 0; i < FRAMES_PER_PROGRAM; i++) { |
| 75 | + error = unwind_one_frame(record, info, i == 0); |
| 76 | + if (error) { |
| 77 | + break; |
| 78 | + } |
| 79 | + |
| 80 | + if (record->state.fp == 0) { |
| 81 | + unwinder = PROG_UNWIND_STOP; |
| 82 | + break; |
| 83 | + } |
| 84 | + |
| 85 | + error = get_next_unwinder_after_native_frame(record, &unwinder); |
| 86 | + if (error || unwinder != PROG_UNWIND_BEAM) { |
| 87 | + break; |
| 88 | + } |
| 89 | + } |
33 | 90 |
|
34 | 91 | exit:
|
| 92 | + record->state.unwind_error = error; |
35 | 93 | tail_call(ctx, unwinder);
|
| 94 | + DEBUG_PRINT("beam: tail call for next frame unwinder (%d) failed", unwinder); |
36 | 95 | return -1;
|
37 | 96 | }
|
0 commit comments