diff --git a/host/host.go b/host/host.go index 77dc65045..120d334fc 100644 --- a/host/host.go +++ b/host/host.go @@ -38,6 +38,7 @@ type Frame struct { File FileID Lineno libpf.AddressOrLineno Type libpf.FrameType + Extra libpf.AddressOrLineno ReturnAddress bool } diff --git a/support/ebpf/tracemgmt.h b/support/ebpf/tracemgmt.h index ce212de7e..6123d9fcd 100644 --- a/support/ebpf/tracemgmt.h +++ b/support/ebpf/tracemgmt.h @@ -328,7 +328,7 @@ static inline EBPF_INLINE bool unwinder_unwind_frame_pointer(UnwindState *state) // calc_line). This should probably be renamed to something like "frame type // specific data". static inline EBPF_INLINE ErrorCode _push_with_max_frames( - Trace *trace, u64 file, u64 line, u8 frame_type, u8 return_address, u32 max_frames) + Trace *trace, u64 file, u64 line, u64 extra, u8 frame_type, u8 return_address, u32 max_frames) { if (trace->stack_len >= max_frames) { DEBUG_PRINT("unable to push frame: stack is full"); @@ -336,19 +336,24 @@ static inline EBPF_INLINE ErrorCode _push_with_max_frames( return ERR_STACK_LENGTH_EXCEEDED; } + u64 extra_addr = (u64)extra & 0x0000FFFFFFFFFFFFULL; #ifdef TESTING_COREDUMP // tools/coredump uses CGO to build the eBPF code. This dispatches // the frame information directly to helper implemented in ebpfhelpers.go. - int __push_frame(u64, u64, u64, u8, u8); + int __push_frame(u64, u64, u64, u64, u8, u8); trace->stack_len++; - return __push_frame(__cgo_ctx->id, file, line, frame_type, return_address); + return __push_frame(__cgo_ctx->id, file, line, extra_addr, frame_type, return_address); #else - trace->frames[trace->stack_len++] = (Frame){ + Frame frame = { .file_id = file, .addr_or_line = line, .kind = frame_type, .return_address = return_address, }; + if (extra_addr != 0) { + __builtin_memcpy(frame.pad, &extra_addr, 6); + } + trace->frames[trace->stack_len++] = frame; return ERR_OK; #endif @@ -359,19 +364,27 @@ static inline EBPF_INLINE ErrorCode _push_with_return_address(Trace *trace, u64 file, u64 line, u8 frame_type, bool return_address) { return _push_with_max_frames( - trace, file, line, frame_type, return_address, MAX_NON_ERROR_FRAME_UNWINDS); + trace, file, line, 0, frame_type, return_address, MAX_NON_ERROR_FRAME_UNWINDS); } // Push the file ID, line number and frame type into FrameList static inline EBPF_INLINE ErrorCode _push(Trace *trace, u64 file, u64 line, u8 frame_type) { - return _push_with_max_frames(trace, file, line, frame_type, 0, MAX_NON_ERROR_FRAME_UNWINDS); + return _push_with_max_frames(trace, file, line, 0, frame_type, 0, MAX_NON_ERROR_FRAME_UNWINDS); +} + +// Push the file ID, line number and frame type with an extra address into FrameList +static inline EBPF_INLINE ErrorCode +_push_with_extra(Trace *trace, u64 file, u64 line, u64 extra, u8 frame_type) +{ + return _push_with_max_frames( + trace, file, line, extra, frame_type, 0, MAX_NON_ERROR_FRAME_UNWINDS); } // Push a critical error frame. static inline EBPF_INLINE ErrorCode push_error(Trace *trace, ErrorCode error) { - return _push_with_max_frames(trace, 0, error, FRAME_MARKER_ABORT, 0, MAX_FRAME_UNWINDS); + return _push_with_max_frames(trace, 0, error, 0, FRAME_MARKER_ABORT, 0, MAX_FRAME_UNWINDS); } // Send a trace to user-land via the `trace_events` perf event buffer. diff --git a/support/ebpf/tracer.ebpf.amd64 b/support/ebpf/tracer.ebpf.amd64 index 904f01500..7532d8466 100644 Binary files a/support/ebpf/tracer.ebpf.amd64 and b/support/ebpf/tracer.ebpf.amd64 differ diff --git a/support/ebpf/tracer.ebpf.arm64 b/support/ebpf/tracer.ebpf.arm64 index 4ece634dd..ed201e013 100644 Binary files a/support/ebpf/tracer.ebpf.arm64 and b/support/ebpf/tracer.ebpf.arm64 differ diff --git a/tools/coredump/ebpfhelpers.go b/tools/coredump/ebpfhelpers.go index 73a30d005..5da10daba 100644 --- a/tools/coredump/ebpfhelpers.go +++ b/tools/coredump/ebpfhelpers.go @@ -36,13 +36,14 @@ func __bpf_log(buf unsafe.Pointer, sz C.int) { } //export __push_frame -func __push_frame(id, file, line C.u64, frameType, returnAddress C.uchar) C.int { +func __push_frame(id, file, line, extra C.u64, frameType, returnAddress C.uchar) C.int { ctx := ebpfContextMap[id] ctx.trace.Frames = append(ctx.trace.Frames, host.Frame{ File: host.FileID(file), Lineno: libpf.AddressOrLineno(line), Type: libpf.FrameType(frameType), + Extra: libpf.AddressOrLineno(extra), ReturnAddress: returnAddress != 0, }) diff --git a/tracer/tracer.go b/tracer/tracer.go index ddbd86c37..181645e13 100644 --- a/tracer/tracer.go +++ b/tracer/tracer.go @@ -8,6 +8,7 @@ import ( "bufio" "bytes" "context" + "encoding/binary" "errors" "fmt" "math" @@ -857,6 +858,13 @@ func (t *Tracer) eBPFMetricsCollector( return metricsUpdates } +func reconstruct48BitAddress(bytes [6]uint8) uint64 { + // Pad to 8 bytes for binary.LittleEndian + padded := [8]uint8{} + copy(padded[:], bytes[:]) + return binary.LittleEndian.Uint64(padded[:]) +} + // loadBpfTrace parses a raw BPF trace into a `host.Trace` instance. // // If the raw trace contains a kernel stack ID, the kernel stack is also @@ -930,6 +938,10 @@ func (t *Tracer) loadBpfTrace(raw []byte, cpu int) *host.Trace { Type: libpf.FrameType(rawFrame.Kind), ReturnAddress: rawFrame.Return_address != 0, } + // If there is additional data in the padding, append it as an extra value + if rawFrame.Pad[0] != 0 { + trace.Frames[i].Extra = libpf.AddressOrLineno(reconstruct48BitAddress(rawFrame.Pad)) + } } return trace }