1use crate::BpfSkel;
6use libbpf_rs::skel::Skel;
7use libbpf_rs::ProgramType;
8use std::io::Read;
9use std::io::Write;
10
11fn dump_program_stream(
12 prog_name: &str,
13 stream_name: &str,
14 mut stream: impl Read,
15 stderr: bool,
16) -> std::io::Result<bool> {
17 let mut buf = Vec::new();
18 stream.read_to_end(&mut buf)?;
19
20 let body = String::from_utf8_lossy(&buf);
21 if body.len() == 0 {
22 return Ok(false);
23 }
24
25 let stream_label = stream_name.to_ascii_uppercase();
26 if stderr {
27 eprintln!("\n===BEGIN BPF {stream_label} {prog_name}===");
28 eprint!("{body}");
29 eprintln!("\n====END BPF {stream_label} {prog_name}====");
30 std::io::stderr().flush()?;
31 } else {
32 println!("\n===BEGIN BPF {stream_label} {prog_name}===");
33 print!("{body}");
34 println!("\n====END BPF {stream_label} {prog_name}====");
35 std::io::stdout().flush()?;
36 }
37
38 Ok(!buf.is_empty())
39}
40
41pub(crate) fn dump_bpf_streams(skel: &mut BpfSkel<'_>) {
42 let mut dumped = false;
43 let mut unavailable = false;
44
45 for prog in skel
46 .object()
47 .progs_mut()
48 .filter(|prog| prog.prog_type() == ProgramType::StructOps)
49 {
50 let prog_name = prog.name().to_string_lossy();
51
52 match dump_program_stream(prog_name.as_ref(), "stdout", prog.stdout(), false) {
53 Ok(stream_dumped) => dumped |= stream_dumped,
54 Err(_) => unavailable = true,
55 }
56
57 match dump_program_stream(prog_name.as_ref(), "stderr", prog.stderr(), true) {
58 Ok(stream_dumped) => dumped |= stream_dumped,
59 Err(_) => unavailable = true,
60 }
61 }
62
63 if !dumped && unavailable {
64 eprintln!("BPF stream dump unavailable (requires kernel/libbpf support for BPF streams)");
65 }
66}