From dbdee1417c83a22d1b09f1296cb2e9cb3d794f11 Mon Sep 17 00:00:00 2001 From: Patrick Ferris Date: Tue, 3 Jun 2025 17:30:40 +0100 Subject: [PATCH] wip --- .gitignore | 1 + dune | 13 ++- dune-project | 1 + example/dune | 3 + example/main.ml | 5 + filter.ml | 18 +++ lexer.mll | 20 ++++ opentrace.bpf.c | 108 ++++++++++++++++-- opentrace.ml | 110 +++++++++++++----- opentrace_stubs.c | 56 ++++++++++ parser.mly | 21 ++++ spawn.ml | 88 +++++++++++++++ uring.h | 280 ++++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 684 insertions(+), 40 deletions(-) create mode 100644 example/dune create mode 100644 example/main.ml create mode 100644 filter.ml create mode 100644 lexer.mll create mode 100644 opentrace_stubs.c create mode 100644 parser.mly create mode 100644 spawn.ml create mode 100644 uring.h diff --git a/.gitignore b/.gitignore index deda60f..2d358c5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ vmlinux.h arch *.csv *.json +*.txt diff --git a/dune b/dune index fda4449..366b044 100644 --- a/dune +++ b/dune @@ -1,12 +1,21 @@ +(menhir + (modules parser)) + +(ocamllex lexer) + (executable (name opentrace) (public_name opentrace) - (modules opentrace config) + (modules opentrace config parser filter lexer spawn) + (foreign_stubs + (language c) + (flags :standard -D_LARGEFILE64_SOURCE) + (names opentrace_stubs)) (preprocess (pps ppx_blob)) (preprocessor_deps (file opentrace.bpf.o)) - (libraries eio_main jsonm cmdliner unix libbpf libbpf_maps)) + (libraries eio_posix jsonm cmdliner unix libbpf libbpf_maps)) (rule (mode diff --git a/dune-project b/dune-project index 6ea46fa..cef4a36 100644 --- a/dune-project +++ b/dune-project @@ -1,4 +1,5 @@ (lang dune 3.14) +(using menhir 3.0) (name opentrace) diff --git a/example/dune b/example/dune new file mode 100644 index 0000000..58ec1ff --- /dev/null +++ b/example/dune @@ -0,0 +1,3 @@ +(executable + (name main) + (libraries eio_main)) diff --git a/example/main.ml b/example/main.ml new file mode 100644 index 0000000..83c124a --- /dev/null +++ b/example/main.ml @@ -0,0 +1,5 @@ +let () = + Eio_main.run @@ fun env -> + Eio.Path.(save ~create:(`Or_truncate 0o664) (env#fs / "hello.txt") "hello"); + Eio.Process.run env#process_mgr + [ "/bin/bash"; "-c"; "echo 'heya' > heya.txt" ] diff --git a/filter.ml b/filter.ml new file mode 100644 index 0000000..d967f1b --- /dev/null +++ b/filter.ml @@ -0,0 +1,18 @@ +type t = Flag of int | And of t * t | Or of t * t | Not of t + +let rec pp ppf = function + | Flag s -> Fmt.string ppf (Config.to_string s) + | And (e1, e2) -> Fmt.pf ppf "%a&%a" pp e1 pp e2 + | Or (e1, e2) -> Fmt.pf ppf "%a|%a" pp e1 pp e2 + | Not e1 -> Fmt.pf ppf "~%a" pp e1 + +let check_flag i t = Int.equal (t land i) i + +let satisfies (expr : t) flags = + let rec loop = function + | Flag s -> check_flag s flags + | Not e -> not (loop e) + | And (e1, e2) -> loop e1 && loop e2 + | Or (e1, e2) -> loop e1 || loop e2 + in + loop expr diff --git a/lexer.mll b/lexer.mll new file mode 100644 index 0000000..0fe4d52 --- /dev/null +++ b/lexer.mll @@ -0,0 +1,20 @@ +{ +open Parser + +exception SyntaxError of string +} + +let white = [' ' '\t']+ +let id = ['a'-'z' 'A'-'Z' '_'] ['a'-'z' 'A'-'Z' '0'-'9' '_']* + +rule read = + parse + | white { read lexbuf } + | id as s { FLAG s } + | '(' { LPAREN } + | ')' { RPAREN } + | '&' { AND } + | '|' { OR } + | '~' { NOT } + | _ { raise (SyntaxError ("Unexpected char: " ^ Lexing.lexeme lexbuf)) } + | eof { EOF } diff --git a/opentrace.bpf.c b/opentrace.bpf.c index 3f2cf92..adf5ba9 100644 --- a/opentrace.bpf.c +++ b/opentrace.bpf.c @@ -1,5 +1,8 @@ #include "vmlinux.h" +#include "uring.h" #include +#include +#include char LICENSE[] SEC("license") = "Dual BSD/GPL"; @@ -16,6 +19,7 @@ struct { #define OPEN_KIND 0 #define OPENAT_KIND 1 #define OPENAT2_KIND 2 +#define URING_KIND 3 // An open event struct open_event @@ -35,7 +39,7 @@ struct open_event struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 10240); - __type(key, u32); // PID + __type(key, u32); // PID/User Data __type(value, struct open_event); // The event } tmpmap SEC(".maps"); @@ -75,7 +79,6 @@ int tracepoint__syscalls__sys_enter_openat2(struct trace_event_raw_sys_enter* ct // Add it to the hash map bpf_map_update_elem(&tmpmap, &pid, &oet, BPF_NOEXIST); - return 0; } @@ -99,11 +102,6 @@ int tracepoint__syscalls__sys_enter_open(struct trace_event_raw_sys_enter* ctx) return 0; } -// SEC("tracepoint/syscalls/sys_exit_open") -// int tracepoint__syscalls__sys_exit_open(struct syscall_trace_exit* ctx) -// { -// return complete_event(OPEN_KIND, ctx); -// } SEC("tracepoint/syscalls/sys_exit_openat") int tracepoint__syscalls__sys_exit_openat(struct syscall_trace_exit* ctx) @@ -147,5 +145,101 @@ int tracepoint__syscalls__sys_exit_openat(struct syscall_trace_exit* ctx) SEC("tracepoint/syscalls/sys_exit_openat2") int tracepoint__syscalls__sys_exit_openat2(struct syscall_trace_exit* ctx) { + struct open_event *ev; + u64 id = bpf_get_current_pid_tgid(); + u32 pid = id >> 32; + + struct open_event *oet; + oet = bpf_ringbuf_reserve(&rb, sizeof(struct open_event), 0); + if (!oet) + return 0; + + // Find our event + ev = bpf_map_lookup_elem(&tmpmap, &pid); + if (!ev) { + // Tidy up + bpf_ringbuf_discard(oet, 0); + bpf_map_delete_elem(&tmpmap, &pid); + return 0; + } + + oet->e_ret = ctx->ret; + oet->e_cgid = bpf_get_current_cgroup_id(); + bpf_probe_read_str(&oet->e_filename, sizeof(oet->e_filename), ev->e_filename); + bpf_get_current_comm(oet->e_comm, TASK_COMM_LEN); + oet->e_flags = ev->e_flags; + oet->e_pid = pid; + oet->e_mode = ev->e_mode; + oet->e_kind = OPENAT2_KIND; + + // Tidy up + bpf_map_delete_elem(&tmpmap, &pid); + + /* emit event */ + bpf_ringbuf_submit(oet, 0); + return 0; } + +/* IO_URING is not so clean :S */ +SEC("kprobe/io_openat2") +int BPF_KPROBE(trace_io_uring_openat_entry, struct io_kiocb *req, int issue_flags) +{ + struct io_open open; + int res = bpf_probe_read(&open, sizeof(open), req); + if (res != 0) { + static const char fmt[] = "openat read failed %i\n"; + bpf_trace_printk(fmt, sizeof(fmt), res); + return 0; + } + struct task_struct *task = (struct task_struct *)bpf_get_current_task_btf(); + char commit[TASK_COMM_LEN]; + + bpf_get_current_comm(&commit, TASK_COMM_LEN); + + u64 pid_tgid = bpf_get_current_pid_tgid(); + + struct open_event oet = {0}; + struct open_how how = {0}; + bpf_probe_read_user(&how, sizeof(how), (void *)&open.how); + oet.e_flags = (int)open.how.flags; + oet.e_mode = (__u32)open.how.mode; + oet.e_filename[0] = '\0'; + + bpf_map_update_elem(&tmpmap, &pid_tgid, &oet, BPF_ANY); + return 0; +} + +// Return probe +SEC("kretprobe/io_openat2") +int BPF_KRETPROBE(trace_io_uring_openat_ret) +{ + u64 pid_tgid = bpf_get_current_pid_tgid(); + + struct open_event *ev = bpf_map_lookup_elem(&tmpmap, &pid_tgid); + if (!ev) { + static const char fmt[] = "no event\n"; + bpf_trace_printk(fmt, sizeof(fmt)); + return 0; + } + + struct open_event *oet = bpf_ringbuf_reserve(&rb, sizeof(struct open_event), 0); + if (!oet) + return 0; + + bpf_get_current_comm(oet->e_comm, TASK_COMM_LEN); + static const char fmt[] = "opening %s\n"; + bpf_trace_printk(fmt, sizeof(fmt), ev->e_filename); + + oet->e_ret = 0; // TODO: PT_REGS_RC(ctx); + oet->e_cgid = bpf_get_current_cgroup_id(); + bpf_probe_read_str(&oet->e_filename, sizeof(oet->e_filename), ev->e_filename); + oet->e_flags = ev->e_flags; + oet->e_mode = ev->e_mode; + oet->e_kind = URING_KIND; + oet->e_pid = pid_tgid >> 32; + + bpf_ringbuf_submit(oet, 0); + bpf_map_delete_elem(&tmpmap, &pid_tgid); + return 0; +} diff --git a/opentrace.ml b/opentrace.ml index 7458853..3026738 100644 --- a/opentrace.ml +++ b/opentrace.ml @@ -12,6 +12,8 @@ let program_names = "tracepoint__syscalls__sys_enter_openat2"; "tracepoint__syscalls__sys_exit_openat"; "tracepoint__syscalls__sys_exit_openat2"; + "trace_io_uring_openat_entry"; + "trace_io_uring_openat_ret"; ] let json_to_lexemes json : Jsonm.lexeme list = @@ -29,28 +31,44 @@ let json_to_lexemes json : Jsonm.lexeme list = loop [] json |> List.rev module Flags = struct - type t = int - include Config - - let mem (v : t) i = Int.equal (i land (v :> int)) (v :> int) end +let print_position ppf lexbuf = + let open Lexing in + let pos = lexbuf.lex_curr_p in + Fmt.pf ppf "%s:%d:%d" pos.pos_fname pos.pos_lnum + (pos.pos_cnum - pos.pos_bol + 1) + +let parse_with_error lexbuf = + try Ok (Parser.filter Lexer.read lexbuf) with + | Lexer.SyntaxError msg -> + Error (Fmt.str "%a: %s\n" print_position lexbuf msg) + | Parser.Error -> Error (Fmt.str "%a: syntax error\n" print_position lexbuf) + +let filter_of_string s = + let lex = Lexing.from_string s in + let filter = parse_with_error lex in + Result.iter (Fmt.pr "filter: %a\n%!" Filter.pp) filter; + filter + module Open_event = struct open Ctypes type t - type kind = Open_ | Openat | Openat2 + type kind = Open_ | Openat | Openat2 | Uring let kind_to_string = function | Open_ -> "open" | Openat -> "openat" | Openat2 -> "openat2" + | Uring -> "Uring" let kind_of_int = function | 0 -> Open_ | 1 -> Openat | 2 -> Openat2 + | 3 -> Uring | n -> failwith ("Invalid kind of open syscall: " ^ string_of_int n) let t : t structure typ = Ctypes.structure "event" @@ -138,10 +156,9 @@ let ringbuffer_polling_callback ~poll rb_cb exit_cb = bpf_callback let filter_event_by_flag event flags = - flags = [] - || - let fs = Open_event.get_flags event in - List.for_all (fun flag -> Flags.mem flag fs) flags + match flags with + | None -> true + | Some f -> Filter.satisfies f (Open_event.get_flags event) let all poll no_header open_flags = if no_header then () else Format.printf "%s" Open_event.csv_header; @@ -153,7 +170,17 @@ let all poll no_header open_flags = let bpf_callback = ringbuffer_polling_callback ~poll callback (fun _ -> ()) in run_ring_buffer bpf_callback -let exec format output user poll (prog, args) open_flags_filter = +let with_cgroup flag fn = + if not flag then fn None + else + let filename = + Filename.temp_dir ~temp_dir:"/sys/fs/cgroup" "opentrace-" "" + in + Fun.protect + ~finally:(fun () -> Sys.rmdir filename) + (fun () -> fn (Some (Filename.concat filename "cgroup.procs"))) + +let exec format output user poll (prog, args) open_flags_filter cgroups = let output = match output with | Some file -> file @@ -174,18 +201,32 @@ let exec format output user poll (prog, args) open_flags_filter = let mutex = Mutex.create () in let pid = Atomic.make None in let exit_status = Atomic.make None in + let cgroup = Atomic.make None in let _domain = Domain.spawn @@ fun () -> - Eio_main.run @@ fun env -> - Mutex.lock mutex; - Condition.wait start_process mutex; - Eio.Switch.run @@ fun sw -> - let p = - Eio.Process.spawn ~sw ~uid (Eio.Stdenv.process_mgr env) (prog :: args) - in - Atomic.set pid (Some (Eio.Process.pid p)); - let status = Eio.Process.await p in - Atomic.set exit_status (Some status) + Eio_posix.run @@ fun env -> + try + Mutex.lock mutex; + Condition.wait start_process mutex; + Eio.Switch.run @@ fun sw -> + with_cgroup cgroups @@ fun group -> + let process = Spawn.make_process group (Some uid) in + let p = Eio.Process.spawn process ~sw (prog :: args) in + Atomic.set pid (Some (Eio.Process.pid p)); + let stat = + Option.map + (fun c -> + Eio.Path.stat ~follow:true Eio.Path.(env#fs / Filename.dirname c)) + group + in + Option.iter (fun v -> Fmt.pr "INO %Ld\n" v.Eio.File.Stat.ino) stat; + Atomic.set cgroup (Option.map (fun v -> v.Eio.File.Stat.ino) stat); + let status = Eio.Process.await p in + Atomic.set exit_status (Some status) + with e -> + Mutex.unlock mutex; + Fmt.epr "Error creating process %s\n" (Printexc.to_string e); + Atomic.set exit_status (Some (`Exited (-1))) in Out_channel.with_open_bin output @@ fun oc -> let encoder = Jsonm.encoder ~minify:false (`Channel oc) in @@ -202,11 +243,15 @@ let exec format output user poll (prog, args) open_flags_filter = | Json -> encode `As in let callback event = - match Atomic.get pid with - | None -> 0 - | Some pid -> + match (Atomic.get cgroup, Atomic.get pid) with + | _, None -> 0 + | _, Some pid -> (if - Int.equal (Open_event.get_pid event) pid + (if cgroups then + Int64.equal + (Open_event.get_cgid event) + (Option.get (Atomic.get cgroup)) + else Int.equal (Open_event.get_pid event) pid) && filter_event_by_flag event open_flags_filter then match format with @@ -246,12 +291,14 @@ let no_header = let doc = "Disable printing the CSV header" in Arg.(value & flag & info [ "no-header" ] ~doc) +let cgroups = + let doc = "Enable cgroup creation and tracing" in + Arg.(value & flag & info [ "cgroups" ] ~doc) + let flag_conv = - let of_string s = - try Ok (Flags.of_string s) with Invalid_argument m -> Error (`Msg m) - in - let pp ppf v = Format.pp_print_string ppf (Flags.to_string v) in - Arg.conv (of_string, pp) + let of_string s = filter_of_string s in + let pp = Filter.pp in + Arg.conv' (of_string, pp) let open_flags_filter = let doc = @@ -259,7 +306,7 @@ let open_flags_filter = Note the filter wants ALL of the flags to be present not just one of \ them." in - Arg.(value & opt (list flag_conv) [] & info [ "flags" ] ~doc) + Arg.(value & opt (some flag_conv) None & info [ "flags" ] ~doc) let user = let doc = "Username or UID to execute program as" in @@ -323,8 +370,9 @@ let exec_cmd = and+ output = output and+ args = Arg.(value & pos_right 0 string [] & Arg.info [] ~docv:"ARGS") and+ open_flags_filter = open_flags_filter + and+ cgroups = cgroups and+ poll = polling in - exec format output user poll (prog, args) open_flags_filter + exec format output user poll (prog, args) open_flags_filter cgroups let opentrace_cmd = let doc = "Trace all open system calls" in diff --git a/opentrace_stubs.c b/opentrace_stubs.c new file mode 100644 index 0000000..c63499f --- /dev/null +++ b/opentrace_stubs.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "include/fork_action.h" + +static void action_setuid(int errors, value v_config) { + #ifdef _WIN32 + eio_unix_fork_error(errors, "action_setuid", "Unsupported operation on windows"); + #else + value v_uid = Field(v_config, 1); + int r; + r = setuid(Int_val(v_uid)); + if (r != 0) { + eio_unix_fork_error(errors, "setuid", strerror(errno)); + _exit(1); + } + #endif +} + +CAMLprim value eio_unix_fork_setuid(value v_unit) { + return Val_fork_fn(action_setuid); +} + +static void action_setcgroup(int errors, value v_config) { + value v_path = Field(v_config, 1); + + int r; + pid_t pid = getpid(); + FILE *f = fopen(String_val(v_path), "w"); + if (f == NULL) { + eio_unix_fork_error(errors, "cgroup", strerror(errno)); + _exit(1); + } + + if (fprintf(f, "%d\n", pid) < 0) { + fclose(f); + eio_unix_fork_error(errors, "cgroup", strerror(errno)); + _exit(1); + } + + fclose(f); +} + +CAMLprim value eio_unix_fork_setcgroup(value v_unit) { + return Val_fork_fn(action_setcgroup); +} + diff --git a/parser.mly b/parser.mly new file mode 100644 index 0000000..7ccac77 --- /dev/null +++ b/parser.mly @@ -0,0 +1,21 @@ +%token FLAG +%token LPAREN RPAREN +%token OR AND +%token NOT +%token EOF +%left OR +%left AND +%nonassoc NOT + +%start filter +%% + +filter: + | f = expr; EOF { f } + +expr: + | f = FLAG { Filter.Flag (Config.of_string f) } + | LPAREN; e = expr; RPAREN { e } + | e1 = expr; AND; e2 = expr { Filter.And (e1, e2) } + | e1 = expr; OR; e2 = expr { Filter.Or (e1, e2) } + | NOT; e = expr { Filter.Not e } diff --git a/spawn.ml b/spawn.ml new file mode 100644 index 0000000..878de81 --- /dev/null +++ b/spawn.ml @@ -0,0 +1,88 @@ +open Eio_posix +open Eio.Std + +type (_, _, _) Eio.Resource.pi += + | Posix_dir : ('t, 't -> Low_level.dir_fd, [> `Posix_dir ]) Eio.Resource.pi + +let as_posix_dir (Eio.Resource.T (t, ops)) = + match Eio.Resource.get_opt ops Posix_dir with + | None -> None + | Some fn -> Some (fn t) + +module Process_impl = struct + type t = Low_level.Process.t + type tag = [ `Generic | `Unix ] + + let pid = Low_level.Process.pid + + let await t = + match Eio.Promise.await @@ Low_level.Process.exit_status t with + | Unix.WEXITED i -> `Exited i + | Unix.WSIGNALED i -> `Signaled i + | Unix.WSTOPPED _ -> assert false + + let signal = Low_level.Process.signal +end + +let process = + let handler = Eio.Process.Pi.process (module Process_impl) in + fun proc -> Eio.Resource.T (proc, handler) + +module T = struct + type t = unit + + external action_setuid : unit -> Eio_unix.Private.Fork_action.fork_fn + = "eio_unix_fork_setuid" + + let action_setuid = action_setuid () + + let setuid (uid : int) = + Eio_unix.Private.Fork_action. + { run = (fun k -> k (Obj.repr (action_setuid, uid))) } + + external action_setcgroup : unit -> Eio_unix.Private.Fork_action.fork_fn + = "eio_unix_fork_setcgroup" + + let action_setcgroup = action_setcgroup () + + let setcgroup group = + Eio_unix.Private.Fork_action. + { run = (fun k -> k (Obj.repr (action_setcgroup, group))) } + + let spawn_unix () ~group ~uid ~sw ?cwd ~env ~fds ~executable args = + let actions = + Low_level.Process.Fork_action. + [ inherit_fds fds; execve executable ~argv:(Array.of_list args) ~env ] + in + let actions = + match uid with None -> actions | Some uid -> setuid uid :: actions + in + let actions = + match group with None -> actions | Some g -> setcgroup g :: actions + in + let with_actions cwd fn = + match cwd with + | None -> fn actions + | Some ((dir, path) : Eio.Fs.dir_ty Eio.Path.t) -> ( + match as_posix_dir dir with + | None -> Fmt.invalid_arg "cwd is not an OS directory!" + | Some dirfd -> + Switch.run ~name:"spawn_unix" @@ fun launch_sw -> + let cwd = + Low_level.openat ~sw:launch_sw ~mode:0 dirfd path + Low_level.Open_flags.(rdonly + directory) + in + fn (Low_level.Process.Fork_action.fchdir cwd :: actions)) + in + with_actions cwd @@ fun actions -> + process (Low_level.Process.spawn ~sw actions) +end + +let make_process group uid = + let module T = struct + type t = unit + + let spawn_unix = T.spawn_unix ~group ~uid + end in + let h = Eio_unix.Process.Pi.mgr_unix (module Eio_unix.Process.Make_mgr (T)) in + Eio.Resource.T ((), h) diff --git a/uring.h b/uring.h new file mode 100644 index 0000000..8ec51d7 --- /dev/null +++ b/uring.h @@ -0,0 +1,280 @@ +#ifndef __URING_IO_H +#define __URING_IO_H + +#include +#define TASK_COMM_LEN 16 +#define MAX_OP_STR_LEN 127 + +enum tracepoint_t { + IO_URING_CREATE, + IO_URING_REGISTER, + IO_URING_FILE_GET, + IO_URING_SUBMIT_SQE, + IO_URING_QUEUE_ASYNC_WORK, + IO_URING_POLL_ARM, + IO_URING_TASK_ADD, + IO_URING_TASK_WORK_RUN, + IO_URING_SHORT_WRITE, + IO_URING_LOCAL_WORK_RUN, + IO_URING_DEFER, + IO_URING_LINK, + IO_URING_FAIL_LINK, + IO_URING_CQRING_WAIT, + IO_URING_REQ_FAILED, + IO_URING_CQE_OVERFLOW, + IO_URING_COMPLETE, + KPROBE_IO_INIT_NEW_WORKER, + SYS_ENTER_IO_URING_SETUP, + SYS_EXIT_IO_URING_SETUP, + SYS_ENTER_IO_URING_REGISTER, + SYS_EXIT_IO_URING_REGISTER, + SYS_ENTER_IO_URING_ENTER, + SYS_EXIT_IO_URING_ENTER +}; + +struct io_uring_create { + int fd; + void *ctx; + unsigned long sq_entries; + unsigned long cq_entries; + unsigned long flags; +}; + +struct io_uring_register { + void *ctx; + unsigned opcode; + unsigned nr_files; + unsigned nr_bufs; + long ret; +}; + +struct io_uring_file_get { + void *ctx; + void *req; + /* unsigned long long user_data; */ + int fd; +}; + +struct io_uring_submit_sqe { + void *ctx; + void *req; + /* unsigned long long user_data; */ + unsigned char opcode; + unsigned long flags; + bool force_nonblock; + bool sq_thread; + /* unsigned long __data_loc_op_str; */ + char op_str[MAX_OP_STR_LEN]; +}; + +struct io_uring_queue_async_work { + void *ctx; + void *req; + /* unsigned long long user_data; */ + unsigned char opcode; + unsigned int flags; + void *work; + /* int rw; */ + /* unsigned long __data_loc_op_str; */ + char op_str[MAX_OP_STR_LEN]; +}; + +struct io_uring_poll_arm { + void *ctx; + void *req; + /* unsigned long long user_data; */ + unsigned char opcode; + int mask; + int events; + char op_str[MAX_OP_STR_LEN]; +}; + +struct io_uring_task_add { + void *ctx; + void *req; + /* unsigned long long user_data; */ + unsigned char opcode; + int mask; + char op_str[MAX_OP_STR_LEN]; +}; + +struct io_uring_task_work_run { + void *tctx; + unsigned int count; + unsigned int loops; +}; + +struct io_uring_short_write { + void *ctx; + unsigned long long fpos; + unsigned long long wanted; + unsigned long long got; +}; + +struct io_uring_local_work_run { + void *ctx; + int count; + unsigned int loops; +}; + +struct io_uring_defer { + void *ctx; + void *req; + /* unsigned long long data; */ + unsigned char opcode; + char op_str[MAX_OP_STR_LEN]; +}; + +struct io_uring_link { + + void *ctx; + void *req; + void *target_req; +}; + +struct io_uring_fail_link { + void *ctx; + void *req; + /* unsigned long long user_data; */ + unsigned char opcode; + void *link; + char op_str[MAX_OP_STR_LEN]; +}; + +struct io_uring_cqring_wait { + void *ctx; + int min_events; +}; + +struct io_uring_req_failed { + void *ctx; + void *req; + /* unsigned long long user_data; */ + unsigned char opcode; + unsigned char flags; + unsigned char ioprio; + unsigned long long off; + unsigned long long addr; + unsigned long len; + unsigned long op_flags; + unsigned int buf_index; + unsigned int personality; + unsigned long file_index; + unsigned long long pad1; + unsigned long long addr3; + int error; + char op_str[MAX_OP_STR_LEN]; +}; + +struct io_uring_cqe_overflow { + void *ctx; + unsigned long long user_data; + long res; + unsigned long cflags; + void *ocqe; +}; + +struct io_uring_complete { + void *ctx; + void *req; + /* unsigned long long user_data; */ + int res; + unsigned int cflags; + /* unsigned long long extra1; */ + /* unsigned long long extra2; */ +}; + +struct io_init_new_worker { + int io_worker_tid; +}; + +/* struct sys_enter_io_uring_enter { */ +/* unsigned int fd; */ +/* unsigned long to_submit; */ +/* unsigned long min_complete; */ +/* unsigned long flags; */ +/* unsigned */ +/* } */ + +struct event { + enum tracepoint_t ty; + int pid; + int tid; + unsigned long long ts; + char comm[TASK_COMM_LEN]; + union { + struct io_uring_create io_uring_create; + struct io_uring_register io_uring_register; + struct io_uring_file_get io_uring_file_get; + struct io_uring_submit_sqe io_uring_submit_sqe; + struct io_uring_queue_async_work io_uring_queue_async_work; + struct io_uring_poll_arm io_uring_poll_arm; + struct io_uring_task_add io_uring_task_add; + struct io_uring_task_work_run io_uring_task_work_run; + struct io_uring_short_write io_uring_short_write; + struct io_uring_local_work_run io_uring_local_work_run; + struct io_uring_defer io_uring_defer; + struct io_uring_link io_uring_link; + struct io_uring_fail_link io_uring_fail_link; + struct io_uring_cqring_wait io_uring_cqring_wait; + struct io_uring_req_failed io_uring_req_failed; + struct io_uring_cqe_overflow io_uring_cqe_overflow; + struct io_uring_complete io_uring_complete; + struct io_init_new_worker io_init_new_worker; + }; +}; + +/* enum io_uring_op { */ +/* IORING_OP_NOP = 0, */ +/* IORING_OP_READV = 1, */ +/* IORING_OP_WRITEV = 2, */ +/* IORING_OP_FSYNC = 3, */ +/* IORING_OP_READ_FIXED = 4, */ +/* IORING_OP_WRITE_FIXED = 5, */ +/* IORING_OP_POLL_ADD = 6, */ +/* IORING_OP_POLL_REMOVE = 7, */ +/* IORING_OP_SYNC_FILE_RANGE = 8, */ +/* IORING_OP_SENDMSG = 9, */ +/* IORING_OP_RECVMSG = 10, */ +/* IORING_OP_TIMEOUT = 11, */ +/* IORING_OP_TIMEOUT_REMOVE = 12, */ +/* IORING_OP_ACCEPT = 13, */ +/* IORING_OP_ASYNC_CANCEL = 14, */ +/* IORING_OP_LINK_TIMEOUT = 15, */ +/* IORING_OP_CONNECT = 16, */ +/* IORING_OP_FALLOCATE = 17, */ +/* IORING_OP_OPENAT = 18, */ +/* IORING_OP_CLOSE = 19, */ +/* IORING_OP_FILES_UPDATE = 20, */ +/* IORING_OP_STATX = 21, */ +/* IORING_OP_READ = 22, */ +/* IORING_OP_WRITE = 23, */ +/* IORING_OP_FADVISE = 24, */ +/* IORING_OP_MADVISE = 25, */ +/* IORING_OP_SEND = 26, */ +/* IORING_OP_RECV = 27, */ +/* IORING_OP_OPENAT2 = 28, */ +/* IORING_OP_EPOLL_CTL = 29, */ +/* IORING_OP_SPLICE = 30, */ +/* IORING_OP_PROVIDE_BUFFERS = 31, */ +/* IORING_OP_REMOVE_BUFFERS = 32, */ +/* IORING_OP_TEE = 33, */ +/* IORING_OP_SHUTDOWN = 34, */ +/* IORING_OP_RENAMEAT = 35, */ +/* IORING_OP_UNLINKAT = 36, */ +/* IORING_OP_MKDIRAT = 37, */ +/* IORING_OP_SYMLINKAT = 38, */ +/* IORING_OP_LINKAT = 39, */ +/* IORING_OP_MSG_RING = 40, */ +/* IORING_OP_FSETXATTR = 41, */ +/* IORING_OP_SETXATTR = 42, */ +/* IORING_OP_FGETXATTR = 43, */ +/* IORING_OP_GETXATTR = 44, */ +/* IORING_OP_SOCKET = 45, */ +/* IORING_OP_URING_CMD = 46, */ +/* IORING_OP_SEND_ZC = 47, */ +/* IORING_OP_SENDMSG_ZC = 48, */ +/* IORING_OP_LAST = 49, */ +/* }; */ + +#endif -- 2.51.2