Skip to content

Commit 1e610b0

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

File tree

2 files changed

+197
-3
lines changed

2 files changed

+197
-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={:x}", addr);
137+
}
138+
if let Some(func_name) = func_name {
139+
print!(" func={}", func_name);
140+
}
141+
if *offset != 0 {
142+
print!(" offset={:#x}", offset);
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: 150 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,42 @@ pub struct UprobeMultiLinkInfo {
726726
pub pid: u32,
727727
}
728728

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

0 commit comments

Comments
 (0)