Skip to main content

profile_bee_common/
lib.rs

1#![no_std]
2
3use core::mem::size_of;
4
5/// Stack trace information shared between eBPF and userspace
6///
7/// Contains the process ID, stack trace IDs for both kernel and user stacks,
8/// process name, and CPU ID for a single stack sample collected by the profiler.
9#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
10#[repr(C)]
11pub struct StackInfo {
12    pub tgid: u32,
13    pub user_stack_id: i32,
14    pub kernel_stack_id: i32,
15    pub cmd: [u8; 16],
16    pub cpu: u32,
17    // for dev debugging
18    pub bp: u64,
19    pub ip: u64,
20    pub sp: u64,
21}
22
23impl StackInfo {
24    pub const STRUCT_SIZE: usize = size_of::<StackInfo>();
25}
26
27pub static EVENT_TRACE_ALWAYS: u8 = 1;
28pub static EVENT_TRACE_NEW: u8 = 2;
29pub static EVENT_TRACE_NONE: u8 = 3;
30
31#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
32#[repr(C)]
33pub struct FramePointers {
34    /// Maximum stack depth supported (1024 frames * 8 bytes = 8KB)
35    pub pointers: [u64; 1024],
36    /// Describes depth of stack trace (number of frames)
37    /// This could be optional because the array is 0 terminated
38    pub len: usize,
39}
40
41impl FramePointers {
42    pub const STRUCT_SIZE: usize = size_of::<FramePointers>();
43}
44
45/// Currently not used, but this would be used for
46/// sending events to UserSpace via RingBuf
47#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
48#[repr(C)]
49pub struct ProbeEvent {
50    pub stack_info: StackInfo,
51    pub frame_pointers: Option<FramePointers>,
52}
53
54impl ProbeEvent {
55    pub const STRUCT_SIZE: usize = size_of::<ProbeEvent>();
56}
57
58// --- DWARF Unwind Table Types (used by eBPF-side unwinding) ---
59
60/// How to compute the CFA (Canonical Frame Address)
61pub const CFA_REG_RSP: u8 = 0;
62pub const CFA_REG_RBP: u8 = 1;
63pub const CFA_REG_EXPRESSION: u8 = 2;
64/// PLT stub: CFA = RSP + offset + ((RIP & 15) >= 11 ? offset : 0)
65pub const CFA_REG_PLT: u8 = 3;
66/// Signal frame: CFA = *(RSP + offset)  (dereference)
67pub const CFA_REG_DEREF_RSP: u8 = 4;
68
69/// How to recover a register value
70pub const REG_RULE_OFFSET: u8 = 0;
71pub const REG_RULE_SAME_VALUE: u8 = 1;
72pub const REG_RULE_UNDEFINED: u8 = 2;
73pub const REG_RULE_REGISTER: u8 = 3;
74pub const REG_RULE_EXPRESSION: u8 = 4;
75
76/// Compact unwind table entry for eBPF-side stack unwinding.
77///
78/// On x86_64, the return address is always at CFA-8, so we don't store RA
79/// rule/offset. Using u32 for PC (file-relative addresses fit in 4GB) and
80/// i16 offsets gives us 12 bytes per entry.
81#[derive(Copy, Clone, Debug, Eq, PartialEq)]
82#[repr(C)]
83pub struct UnwindEntry {
84    pub pc: u32,
85    pub cfa_offset: i16,
86    pub rbp_offset: i16,
87    pub cfa_type: u8,
88    pub rbp_type: u8,
89    pub _pad: [u8; 2],
90}
91
92impl UnwindEntry {
93    pub const STRUCT_SIZE: usize = size_of::<UnwindEntry>();
94}
95
96pub const MAX_DWARF_STACK_DEPTH: usize = 21;
97pub const MAX_PROC_MAPS: usize = 8;
98
99/// Number of per-binary Array shard maps in eBPF (shard_0 .. shard_7)
100pub const MAX_UNWIND_SHARDS: usize = 8;
101/// Maximum unwind entries per shard (2^16, covered by 16 binary search iterations)
102pub const MAX_SHARD_ENTRIES: u32 = 65_536;
103/// Sentinel value: no shard assigned to this mapping
104pub const SHARD_NONE: u8 = 0xFF;
105
106#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
107#[repr(C)]
108pub struct ProcInfoKey {
109    pub tgid: u32,
110    pub _pad: u32,
111}
112
113#[derive(Copy, Clone, Debug, Eq, PartialEq)]
114#[repr(C)]
115pub struct ExecMapping {
116    pub begin: u64,
117    pub end: u64,
118    pub load_bias: u64,
119    pub shard_id: u8, // Which shard Array to search (0..MAX_UNWIND_SHARDS-1, or SHARD_NONE)
120    pub _pad1: [u8; 3],
121    pub table_count: u32, // Number of entries in this shard for this binary
122}
123
124#[derive(Copy, Clone, Debug)]
125#[repr(C)]
126pub struct ProcInfo {
127    pub mapping_count: u32,
128    pub _pad: u32,
129    pub mappings: [ExecMapping; MAX_PROC_MAPS],
130}