this repo has no description

wip

+1
.gitignore
···
arch
*.csv
*.json
+
*.txt
+11 -2
dune
···
+
(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
+1
dune-project
···
(lang dune 3.14)
+
(using menhir 3.0)
(name opentrace)
+3
example/dune
···
+
(executable
+
(name main)
+
(libraries eio_main))
+5
example/main.ml
···
+
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" ]
+18
filter.ml
···
+
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
+20
lexer.mll
···
+
{
+
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 }
+101 -7
opentrace.bpf.c
···
#include "vmlinux.h"
+
#include "uring.h"
#include <bpf/bpf_helpers.h>
+
#include <bpf/bpf_tracing.h>
+
#include <bpf/bpf_core_read.h>
char LICENSE[] SEC("license") = "Dual BSD/GPL";
···
#define OPEN_KIND 0
#define OPENAT_KIND 1
#define OPENAT2_KIND 2
+
#define URING_KIND 3
// An open event
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");
···
// Add it to the hash map
bpf_map_update_elem(&tmpmap, &pid, &oet, BPF_NOEXIST);
-
return 0;
}
···
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)
···
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;
+
}
+79 -31
opentrace.ml
···
"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 =
···
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"
···
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;
···
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
···
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
···
| 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
···
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 =
···
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
···
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
+56
opentrace_stubs.c
···
+
#include <stdlib.h>
+
#include <unistd.h>
+
#include <fcntl.h>
+
#include <string.h>
+
#include <errno.h>
+
+
#include <caml/mlvalues.h>
+
#include <caml/unixsupport.h>
+
#include <caml/memory.h>
+
#include <caml/custom.h>
+
#include <caml/fail.h>
+
+
#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);
+
}
+
+21
parser.mly
···
+
%token <string> FLAG
+
%token LPAREN RPAREN
+
%token OR AND
+
%token NOT
+
%token EOF
+
%left OR
+
%left AND
+
%nonassoc NOT
+
+
%start <Filter.t> 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 }
+88
spawn.ml
···
+
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)
+280
uring.h
···
+
#ifndef __URING_IO_H
+
#define __URING_IO_H
+
+
#include <stdbool.h>
+
#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