1open Libbpf
2open Libbpf_maps
3open Ctypes
4
5let obj_path = "bootstrap.bpf.o"
6let program_names = [ "handle_exec"; "handle_exit" ]
7let rb_name = "rb"
8
9(* event structure layout from bootstrap.h *)
10let event : [ `Event ] structure typ = Ctypes.structure "event"
11let ( -: ) ty label = field event label ty
12let pid = int -: "pid"
13let ppid = int -: "ppid"
14let exit_code = uint -: "exit_code"
15let duration = ullong -: "duration_ns"
16let comm = array 16 char -: "comm"
17let filename = array 127 char -: "filename"
18let exit_event = bool -: "exit_event"
19let _ = seal event
20
21let char_array_as_string a =
22 let len = CArray.length a in
23 let b = Buffer.create len in
24 try
25 for i = 0 to len - 1 do
26 let c = CArray.get a i in
27 if c = '\x00' then raise Exit else Buffer.add_char b c
28 done;
29 Buffer.contents b
30 with Exit -> Buffer.contents b
31
32(* Describe User callback event handler *)
33let handle_event _ctx data _sz =
34 let ev = !@(from_voidp event data) in
35 let pid = getf ev pid in
36 let ppid = getf ev ppid in
37 let exit_code = getf ev exit_code |> Unsigned.UInt.to_string in
38 let duration = getf ev duration |> Unsigned.ULLong.to_int64 in
39 let comm = getf ev comm |> char_array_as_string in
40 let filename = getf ev filename |> char_array_as_string in
41 let exit_event = getf ev exit_event in
42 let tm = Unix.time () |> Unix.localtime in
43 let ts = Printf.sprintf "%d:%d:%d" tm.tm_hour tm.tm_min tm.tm_sec in
44 if exit_event then (
45 Printf.printf "%-8s %-5s %-16s %-7d %-7d [%s]" ts "EXIT" comm pid ppid
46 exit_code;
47 if duration >= 0L then
48 Printf.printf " (%Lums)" (Int64.div duration 1000000L);
49 print_newline ())
50 else
51 Printf.printf "%-8s %-5s %-16s %-7d %-7d %s\n" ts "EXEC" comm pid ppid
52 filename;
53 0
54
55let () =
56 (* Set signal handlers *)
57 let exitting = ref true in
58 let sig_handler = Sys.Signal_handle (fun _ -> exitting := false) in
59 Sys.(set_signal sigint sig_handler);
60 Sys.(set_signal sigterm sig_handler);
61
62 (* Use auto open/load/link helper *)
63 with_bpf_object_open_load_link ~obj_path ~program_names (fun obj _links ->
64 (* Load ringbuffer map *)
65 let map = bpf_object_find_map_by_name obj rb_name in
66
67 (* Set up ring buffer *)
68 RingBuffer.init map ~callback:handle_event (fun rb ->
69 Printf.printf "%-8s %-5s %-16s %-7s %-7s %s\n%!" "TIME" "EVENT" "COMM"
70 "PID" "PPID" "FILENAME/EXIT CODE";
71
72 while !exitting do
73 ignore
74 (try RingBuffer.poll rb ~timeout:100
75 with _ ->
76 exitting := false;
77 -1)
78 done))