Skip to content

Commit a451904

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

File tree

2 files changed

+196
-3
lines changed

2 files changed

+196
-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: 149 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,42 @@ 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`, `BPF_PERF_EVENT_URETPROBE`
763+
Unknown(u32),
764+
}
765+
729766
/// Information about BPF link types. Maps to the anonymous union in `struct bpf_link_info` in
730767
/// kernel uapi.
731768
#[derive(Debug, Clone)]
@@ -767,7 +804,10 @@ pub enum LinkTypeInfo {
767804
/// Link type for sockmap programs.
768805
SockMap(SockMapLinkInfo),
769806
/// Link type for perf-event programs.
770-
PerfEvent,
807+
///
808+
/// Contains information about the perf event configuration including type and config
809+
/// which can be used to identify tracepoints, kprobes, uprobes, etc.
810+
PerfEvent(PerfEventLinkInfo),
771811
/// Unknown link type.
772812
Unknown,
773813
}
@@ -874,7 +914,114 @@ impl LinkInfo {
874914
s.__bindgen_anon_1.sockmap.attach_type
875915
}),
876916
}),
877-
libbpf_sys::BPF_LINK_TYPE_PERF_EVENT => LinkTypeInfo::PerfEvent,
917+
libbpf_sys::BPF_LINK_TYPE_PERF_EVENT => {
918+
// Get the BPF perf event type (BPF_PERF_EVENT_*) from the link info.
919+
let bpf_perf_event_type = unsafe { s.__bindgen_anon_1.perf_event.type_ };
920+
921+
// Handle two-phase call for perf event string data if needed (this mimics the
922+
// behavior of bpftool).
923+
let mut buf = [0u8; 256];
924+
let need_second_call = match bpf_perf_event_type {
925+
libbpf_sys::BPF_PERF_EVENT_TRACEPOINT => {
926+
s.__bindgen_anon_1
927+
.perf_event
928+
.__bindgen_anon_1
929+
.tracepoint
930+
.tp_name = buf.as_mut_ptr() as u64;
931+
s.__bindgen_anon_1
932+
.perf_event
933+
.__bindgen_anon_1
934+
.tracepoint
935+
.name_len = buf.len() as u32;
936+
true
937+
}
938+
libbpf_sys::BPF_PERF_EVENT_KPROBE | libbpf_sys::BPF_PERF_EVENT_KRETPROBE => {
939+
s.__bindgen_anon_1
940+
.perf_event
941+
.__bindgen_anon_1
942+
.kprobe
943+
.func_name = buf.as_mut_ptr() as u64;
944+
s.__bindgen_anon_1
945+
.perf_event
946+
.__bindgen_anon_1
947+
.kprobe
948+
.name_len = buf.len() as u32;
949+
true
950+
}
951+
_ => false,
952+
};
953+
954+
if need_second_call {
955+
let item_ptr: *mut libbpf_sys::bpf_link_info = &mut s;
956+
let mut len = size_of_val(&s) as u32;
957+
let ret = unsafe {
958+
libbpf_sys::bpf_obj_get_info_by_fd(
959+
fd.as_raw_fd(),
960+
item_ptr as *mut c_void,
961+
&mut len,
962+
)
963+
};
964+
if ret != 0 {
965+
return None;
966+
}
967+
}
968+
969+
let event_type = match bpf_perf_event_type {
970+
libbpf_sys::BPF_PERF_EVENT_TRACEPOINT => {
971+
let tp_name = unsafe {
972+
s.__bindgen_anon_1
973+
.perf_event
974+
.__bindgen_anon_1
975+
.tracepoint
976+
.tp_name
977+
};
978+
let cookie = unsafe {
979+
s.__bindgen_anon_1
980+
.perf_event
981+
.__bindgen_anon_1
982+
.tracepoint
983+
.cookie
984+
};
985+
let name = (tp_name != 0)
986+
.then(|| unsafe { CStr::from_ptr(tp_name as *const i8).to_owned() });
987+
988+
PerfEventType::Tracepoint { name, cookie }
989+
}
990+
libbpf_sys::BPF_PERF_EVENT_KPROBE | libbpf_sys::BPF_PERF_EVENT_KRETPROBE => {
991+
let func_name = unsafe {
992+
s.__bindgen_anon_1
993+
.perf_event
994+
.__bindgen_anon_1
995+
.kprobe
996+
.func_name
997+
};
998+
let addr =
999+
unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.addr };
1000+
let offset =
1001+
unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.offset };
1002+
let missed =
1003+
unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.missed };
1004+
let cookie =
1005+
unsafe { s.__bindgen_anon_1.perf_event.__bindgen_anon_1.kprobe.cookie };
1006+
let func_name = (func_name != 0)
1007+
.then(|| unsafe { CStr::from_ptr(func_name as *const i8).to_owned() });
1008+
1009+
let is_retprobe =
1010+
bpf_perf_event_type == libbpf_sys::BPF_PERF_EVENT_KRETPROBE;
1011+
PerfEventType::Kprobe {
1012+
func_name,
1013+
is_retprobe,
1014+
addr,
1015+
offset,
1016+
missed,
1017+
cookie,
1018+
}
1019+
}
1020+
ty => PerfEventType::Unknown(ty),
1021+
};
1022+
1023+
LinkTypeInfo::PerfEvent(PerfEventLinkInfo { event_type })
1024+
}
8781025
_ => LinkTypeInfo::Unknown,
8791026
};
8801027

0 commit comments

Comments
 (0)