Skip to content

Commit 2c37073

Browse files
committed
query: Extract tracepoint & k(ret)probe from perf_event links
1 parent 9779cdc commit 2c37073

File tree

2 files changed

+199
-3
lines changed

2 files changed

+199
-3
lines changed

examples/bpf_query/src/main.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ fn link() {
9494
query::LinkTypeInfo::KprobeMulti(_) => "kprobemulti",
9595
query::LinkTypeInfo::UprobeMulti(_) => "uprobemulti",
9696
query::LinkTypeInfo::SockMap(_) => "sockmap",
97-
query::LinkTypeInfo::PerfEvent => "perf_event",
97+
query::LinkTypeInfo::PerfEvent(_) => "perf_event",
9898
};
9999

100100
println!(
@@ -107,6 +107,52 @@ fn link() {
107107
" attach_type={:?} target_obj_id={} target_btf_id={}",
108108
tracing.attach_type, tracing.target_obj_id, tracing.target_btf_id
109109
);
110+
} else if let query::LinkTypeInfo::PerfEvent(ref perf_event) = link.info {
111+
match &perf_event.event_type {
112+
query::PerfEventType::Tracepoint { name, cookie } => {
113+
let Some(name) = name else {
114+
continue;
115+
};
116+
117+
print!(" tracepoint {}", name.to_string_lossy());
118+
if *cookie != 0 {
119+
print!(" cookie={cookie}");
120+
}
121+
println!();
122+
}
123+
query::PerfEventType::Kprobe {
124+
func_name,
125+
is_retprobe,
126+
addr,
127+
offset,
128+
missed,
129+
cookie,
130+
} => {
131+
let probe_type = if *is_retprobe { "kretprobe" } else { "kprobe" };
132+
let func_name = func_name.as_ref().map(|s| s.to_string_lossy());
133+
134+
print!(" {probe_type}");
135+
if *addr != 0 {
136+
print!(" addr={addr:x}");
137+
}
138+
if let Some(func_name) = func_name {
139+
print!(" func={func_name}");
140+
}
141+
if *offset != 0 {
142+
print!(" offset={offset:#x}");
143+
}
144+
if *missed != 0 {
145+
print!(" missed={missed}");
146+
}
147+
if *cookie != 0 {
148+
print!(" cookie={cookie}");
149+
}
150+
println!();
151+
}
152+
query::PerfEventType::Unknown(ty) => {
153+
println!(" unknown perf event type: {ty}");
154+
}
155+
}
110156
}
111157
}
112158
}

libbpf-rs/src/query.rs

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//! ```
1212
1313
use std::ffi::c_void;
14+
use std::ffi::CStr;
1415
use std::ffi::CString;
1516
use std::io;
1617
use std::mem::size_of_val;
@@ -726,6 +727,43 @@ pub struct UprobeMultiLinkInfo {
726727
pub pid: u32,
727728
}
728729

730+
/// Information about a perf event link.
731+
#[derive(Debug, Clone)]
732+
pub struct PerfEventLinkInfo {
733+
/// The specific type of perf event with decoded information.
734+
pub event_type: PerfEventType,
735+
}
736+
737+
/// Specific types of perf events with decoded information.
738+
#[derive(Debug, Clone)]
739+
pub enum PerfEventType {
740+
/// A tracepoint event.
741+
Tracepoint {
742+
/// The tracepoint name.
743+
name: Option<CString>,
744+
/// Attach cookie value for this link.
745+
cookie: u64,
746+
},
747+
/// A kprobe event (includes both kprobe and kretprobe).
748+
Kprobe {
749+
/// The function being probed.
750+
func_name: Option<CString>,
751+
/// Whether this is a return probe (kretprobe).
752+
is_retprobe: bool,
753+
/// Address of the probe.
754+
addr: u64,
755+
/// Offset from the function.
756+
offset: u32,
757+
/// Number of missed events.
758+
missed: u64,
759+
/// Cookie value for the kprobe.
760+
cookie: u64,
761+
},
762+
/// TODO: Add support for `BPF_PERF_EVENT_EVENT`, `BPF_PERF_EVENT_UPROBE`
763+
/// `BPF_PERF_EVENT_URETPROBE`
764+
Unknown(u32),
765+
}
766+
729767
/// Information about BPF link types. Maps to the anonymous union in `struct bpf_link_info` in
730768
/// kernel uapi.
731769
#[derive(Debug, Clone)]
@@ -767,7 +805,10 @@ pub enum LinkTypeInfo {
767805
/// Link type for sockmap programs.
768806
SockMap(SockMapLinkInfo),
769807
/// Link type for perf-event programs.
770-
PerfEvent,
808+
///
809+
/// Contains information about the perf event configuration including type and config
810+
/// which can be used to identify tracepoints, kprobes, uprobes, etc.
811+
PerfEvent(PerfEventLinkInfo),
771812
/// Unknown link type.
772813
Unknown,
773814
}
@@ -874,7 +915,116 @@ impl LinkInfo {
874915
s.__bindgen_anon_1.sockmap.attach_type
875916
}),
876917
}),
877-
libbpf_sys::BPF_LINK_TYPE_PERF_EVENT => LinkTypeInfo::PerfEvent,
918+
libbpf_sys::BPF_LINK_TYPE_PERF_EVENT => {
919+
// Get the BPF perf event type (BPF_PERF_EVENT_*) from the link info.
920+
let bpf_perf_event_type = unsafe { s.__bindgen_anon_1.perf_event.type_ };
921+
922+
// Handle two-phase call for perf event string data if needed (this mimics the
923+
// behavior of bpftool).
924+
let mut buf = [0u8; 256];
925+
let need_second_call = match bpf_perf_event_type {
926+
libbpf_sys::BPF_PERF_EVENT_TRACEPOINT => {
927+
s.__bindgen_anon_1
928+
.perf_event
929+
.__bindgen_anon_1
930+
.tracepoint
931+
.tp_name = buf.as_mut_ptr() as u64;
932+
s.__bindgen_anon_1
933+
.perf_event
934+
.__bindgen_anon_1
935+
.tracepoint
936+
.name_len = buf.len() as u32;
937+
true
938+
}
939+
libbpf_sys::BPF_PERF_EVENT_KPROBE | libbpf_sys::BPF_PERF_EVENT_KRETPROBE => {
940+
s.__bindgen_anon_1
941+
.perf_event
942+
.__bindgen_anon_1
943+
.kprobe
944+
.func_name = buf.as_mut_ptr() as u64;
945+
s.__bindgen_anon_1
946+
.perf_event
947+
.__bindgen_anon_1
948+
.kprobe
949+
.name_len = buf.len() as u32;
950+
true
951+
}
952+
_ => false,
953+
};
954+
955+
if need_second_call {
956+
let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
957+
let mut len = size_of_val(&s) as u32;
958+
let ret = unsafe {
959+
libbpf_sys::bpf_obj_get_info_by_fd(
960+
fd.as_raw_fd(),
961+
item_ptr as *mut c_void,
962+
&mut len,
963+
)
964+
};
965+
if ret != 0 {
966+
return None;
967+
}
968+
}
969+
970+
let event_type = match bpf_perf_event_type {
971+
libbpf_sys::BPF_PERF_EVENT_TRACEPOINT => {
972+
let tp_name = unsafe {
973+
s.__bindgen_anon_1
974+
.perf_event
975+
.__bindgen_anon_1
976+
.tracepoint
977+
.tp_name
978+
};
979+
let cookie = unsafe {
980+
s.__bindgen_anon_1
981+
.perf_event
982+
.__bindgen_anon_1
983+
.tracepoint
984+
.cookie
985+
};
986+
let name = (tp_name != 0).then(|| unsafe {
987+
CStr::from_ptr(tp_name as *const c_char).to_owned()
988+
});
989+
990+
PerfEventType::Tracepoint { name, cookie }
991+
}
992+
libbpf_sys::BPF_PERF_EVENT_KPROBE | libbpf_sys::BPF_PERF_EVENT_KRETPROBE => {
993+
let func_name = unsafe {
994+
s.__bindgen_anon_1
995+
.perf_event
996+
.__bindgen_anon_1
997+
.kprobe
998+
.func_name
999+
};
1000+
let addr =
1001+
unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.addr };
1002+
let offset =
1003+
unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.offset };
1004+
let missed =
1005+
unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.missed };
1006+
let cookie =
1007+
unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.cookie };
1008+
let func_name = (func_name != 0).then(|| unsafe {
1009+
CStr::from_ptr(func_name as *const c_char).to_owned()
1010+
});
1011+
1012+
let is_retprobe =
1013+
bpf_perf_event_type == libbpf_sys::BPF_PERF_EVENT_KRETPROBE;
1014+
PerfEventType::Kprobe {
1015+
func_name,
1016+
is_retprobe,
1017+
addr,
1018+
offset,
1019+
missed,
1020+
cookie,
1021+
}
1022+
}
1023+
ty => PerfEventType::Unknown(ty),
1024+
};
1025+
1026+
LinkTypeInfo::PerfEvent(PerfEventLinkInfo { event_type })
1027+
}
8781028
_ => LinkTypeInfo::Unknown,
8791029
};
8801030

0 commit comments

Comments
 (0)