diff --git a/bpf/process/bpf_generic_tracepoint.c b/bpf/process/bpf_generic_tracepoint.c index cdba68cbe5d..49a15497163 100644 --- a/bpf/process/bpf_generic_tracepoint.c +++ b/bpf/process/bpf_generic_tracepoint.c @@ -206,7 +206,7 @@ generic_tracepoint_event(struct generic_tracepoint_event_arg *ctx) get_ctx_ul((char *)ctx + ctx_off, ty); }); - generic_process_init(msg, MSG_OP_GENERIC_TRACEPOINT, config); + generic_process_init(msg, MSG_OP_GENERIC_TRACEPOINT); msg->common.op = MSG_OP_GENERIC_TRACEPOINT; msg->sel.curr = 0; diff --git a/bpf/process/generic_calls.h b/bpf/process/generic_calls.h index 023303fea9c..67ee03cdd2c 100644 --- a/bpf/process/generic_calls.h +++ b/bpf/process/generic_calls.h @@ -449,6 +449,17 @@ FUNC_INLINE int arg_idx(int index) return config->idx[index]; } +FUNC_INLINE long get_pt_regs_arg(struct pt_regs *ctx, struct config_reg_arg *reg) +{ + __u8 shift = 64 - reg->size*8; + unsigned long *val; + + val = (unsigned long *) ctx + (reg->offset / sizeof(unsigned long)); + *val <<= shift; + *val >>= shift; + return *val; +} + FUNC_INLINE long generic_read_arg(void *ctx, int index, long off, struct bpf_map_def *tailcals) { struct msg_generic_kprobe *e; @@ -483,9 +494,12 @@ FUNC_INLINE long generic_read_arg(void *ctx, int index, long off, struct bpf_map /* Getting argument data based on the source attribute, which is encoded * in argument meta data, so far it's either: * + * - pt_regs register * - current task object * - real argument value */ + if (am & ARGM_PT_REGS) + a = get_pt_regs_arg(ctx, &config->reg_arg[arg_index]); if (am & ARGM_CURRENT_TASK) a = get_current_task(); else @@ -543,7 +557,7 @@ generic_process_event(void *ctx, struct bpf_map_def *tailcals) } FUNC_INLINE void -generic_process_init(struct msg_generic_kprobe *e, u8 op, struct event_config *config) +generic_process_init(struct msg_generic_kprobe *e, u8 op) { e->common.op = op; @@ -693,7 +707,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal e->a4 = PT_REGS_PARM5_CORE(ctx); } - generic_process_init(e, MSG_OP_GENERIC_KPROBE, config); + generic_process_init(e, MSG_OP_GENERIC_KPROBE); e->retprobe_id = retprobe_map_get_key(ctx); @@ -711,7 +725,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal e->a2 = BPF_CORE_READ(raw_args, args[2]); e->a3 = BPF_CORE_READ(raw_args, args[3]); e->a4 = BPF_CORE_READ(raw_args, args[4]); - generic_process_init(e, MSG_OP_GENERIC_LSM, config); + generic_process_init(e, MSG_OP_GENERIC_LSM); #endif #ifdef GENERIC_UPROBE @@ -720,7 +734,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal e->a2 = PT_REGS_PARM3_CORE(ctx); e->a3 = PT_REGS_PARM4_CORE(ctx); e->a4 = PT_REGS_PARM5_CORE(ctx); - generic_process_init(e, MSG_OP_GENERIC_UPROBE, config); + generic_process_init(e, MSG_OP_GENERIC_UPROBE); e->retprobe_id = retprobe_map_get_key(ctx); @@ -731,7 +745,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal #endif #ifdef GENERIC_USDT - generic_process_init(e, MSG_OP_GENERIC_USDT, config); + generic_process_init(e, MSG_OP_GENERIC_USDT); #endif #ifdef GENERIC_RAWTP @@ -742,7 +756,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal e->a2 = BPF_CORE_READ(raw_args, args[2]); e->a3 = BPF_CORE_READ(raw_args, args[3]); e->a4 = BPF_CORE_READ(raw_args, args[4]); - generic_process_init(e, MSG_OP_GENERIC_TRACEPOINT, config); + generic_process_init(e, MSG_OP_GENERIC_TRACEPOINT); #endif #ifdef GENERIC_USDT diff --git a/bpf/process/types/basic.h b/bpf/process/types/basic.h index 23c6aa9ee40..f5efe861fdc 100644 --- a/bpf/process/types/basic.h +++ b/bpf/process/types/basic.h @@ -181,6 +181,12 @@ struct config_usdt_arg { __u32 pad1; } __attribute__((packed)); +struct config_reg_arg { + __u16 offset; + __u8 size; + __u8 pad; +} __attribute__((packed)); + struct extract_arg_data { struct config_btf_arg *btf_config; unsigned long *arg; @@ -189,6 +195,7 @@ struct extract_arg_data { #define MAX_BTF_ARG_DEPTH 10 #define EVENT_CONFIG_MAX_ARG 5 #define EVENT_CONFIG_MAX_USDT_ARG 8 +#define EVENT_CONFIG_MAX_REG_ARG 8 struct event_config { __u32 func_id; @@ -212,6 +219,7 @@ struct event_config { __u32 pad; struct config_btf_arg btf_arg[EVENT_CONFIG_MAX_ARG][MAX_BTF_ARG_DEPTH]; struct config_usdt_arg usdt_arg[EVENT_CONFIG_MAX_USDT_ARG]; + struct config_reg_arg reg_arg[EVENT_CONFIG_MAX_REG_ARG]; } __attribute__((packed)); #define MAX_ARGS_SIZE 80 @@ -574,6 +582,7 @@ FUNC_INLINE long copy_kernel_module(char *args, unsigned long arg) #define ARGM_RETURN_COPY BIT(4) #define ARGM_MAX_DATA BIT(5) #define ARGM_CURRENT_TASK BIT(6) +#define ARGM_PT_REGS BIT(7) FUNC_INLINE bool has_return_copy(unsigned long argm) { diff --git a/bpf/process/uprobe_offload.h b/bpf/process/uprobe_offload.h index 60d01377fdc..9a30cd929ce 100644 --- a/bpf/process/uprobe_offload.h +++ b/bpf/process/uprobe_offload.h @@ -9,7 +9,8 @@ struct reg_assignment { __u8 pad1; __u16 src; __u16 dst; - __u16 pad2; + __u8 src_size; + __u8 dst_size; __u64 off; }; @@ -59,8 +60,8 @@ FUNC_INLINE void do_uprobe_override(void *ctx, __u32 idx) map_update_elem(&sleepable_offload, &id, &idx, BPF_ANY); } -FUNC_INLINE int -write_reg(struct pt_regs *ctx, __u32 dst, __u64 val) +FUNC_LOCAL int +write_reg(struct pt_regs *ctx, __u32 dst, __u8 size, __u64 val) { /* * Using inlined asm to make sure we access context via 'ctx-reg + offset'. @@ -69,36 +70,72 @@ write_reg(struct pt_regs *ctx, __u32 dst, __u64 val) * * Using clang-20 seems to work, but we need to upgrade first ;-) */ -#define WRITE_REG(reg) \ - asm volatile("if %[dst] != %[off] goto +1\n" \ - "*(u64 *)(%[ctx] + %[off]) = %[val]\n" \ - : [ctx] "+r"(ctx), [dst] "+r"(dst), [val] "+r"(val) \ - : [off] "i"(offsetof(struct pt_regs, reg)) \ - :); - - WRITE_REG(r15); - WRITE_REG(r14); - WRITE_REG(r13); - WRITE_REG(r12); - WRITE_REG(r11); - WRITE_REG(r10); - WRITE_REG(r9); - WRITE_REG(r8); - WRITE_REG(ax); - WRITE_REG(cx); - WRITE_REG(dx); - WRITE_REG(si); - WRITE_REG(di); - WRITE_REG(ip); - WRITE_REG(sp); + +#define WRITE_REG(reg) ({ \ + asm volatile("if %[size] != 8 goto +2\n" \ + "*(u64 *)(%[ctx] + %[off]) = %[val]\n" \ + "goto +8\n" \ + "if %[size] != 4 goto +2\n" \ + "*(u32 *)(%[ctx] + %[off]) = %[val]\n" \ + "goto +5\n" \ + "if %[size] != 2 goto +2\n" \ + "*(u16 *)(%[ctx] + %[off]) = %[val]\n" \ + "goto +2\n" \ + "if %[size] != 1 goto +1\n" \ + "*(u8 *)(%[ctx] + %[off]) = %[val]\n" \ + : [ctx] "+r"(ctx), [val] "+r"(val), [size] "+r"(size) \ + : [off] "i"(offsetof(struct pt_regs, reg)) \ + :); \ + 0; \ +}) + + switch (dst) { + case offsetof(struct pt_regs, r15): + return WRITE_REG(r15); + case offsetof(struct pt_regs, r14): + return WRITE_REG(r14); + case offsetof(struct pt_regs, r13): + return WRITE_REG(r13); + case offsetof(struct pt_regs, r12): + return WRITE_REG(r12); + case offsetof(struct pt_regs, bp): + return WRITE_REG(bp); + case offsetof(struct pt_regs, bx): + return WRITE_REG(bx); + case offsetof(struct pt_regs, r11): + return WRITE_REG(r11); + case offsetof(struct pt_regs, r10): + return WRITE_REG(r10); + case offsetof(struct pt_regs, r9): + return WRITE_REG(r9); + case offsetof(struct pt_regs, r8): + return WRITE_REG(r8); + case offsetof(struct pt_regs, ax): + return WRITE_REG(ax); + case offsetof(struct pt_regs, cx): + return WRITE_REG(cx); + case offsetof(struct pt_regs, dx): + return WRITE_REG(dx); + case offsetof(struct pt_regs, si): + return WRITE_REG(si); + case offsetof(struct pt_regs, di): + return WRITE_REG(di); + case offsetof(struct pt_regs, ip): + return WRITE_REG(ip); + case offsetof(struct pt_regs, sp): + return WRITE_REG(sp); + } #undef WRITE_REG return 0; } FUNC_INLINE __u64 -read_reg(struct pt_regs *ctx, __u32 src) +read_reg(struct pt_regs *ctx, struct reg_assignment *ass) { + __u32 src = ass->src; + __u8 shift = 64 - ass->src_size*8; + /* Using inlined asm for same reason we use WRITE_REG above. */ #define READ_REG(reg) ({ \ __u64 val; \ @@ -106,6 +143,8 @@ read_reg(struct pt_regs *ctx, __u32 src) : [ctx] "+r"(ctx), [val] "+r"(val) \ : [off] "i"(offsetof(struct pt_regs, reg)) \ :); \ + val <<= shift; \ + val >>= shift; \ val; \ }) @@ -173,22 +212,22 @@ uprobe_offload_x86(struct pt_regs *ctx) switch (ass->type) { case ASM_ASSIGNMENT_TYPE_CONST: - write_reg(ctx, ass->dst, ass->off); + write_reg(ctx, ass->dst, ass->dst_size, ass->off); break; case ASM_ASSIGNMENT_TYPE_REG: - val = read_reg(ctx, ass->src); - write_reg(ctx, ass->dst, val); + val = read_reg(ctx, ass); + write_reg(ctx, ass->dst, ass->dst_size, val); break; case ASM_ASSIGNMENT_TYPE_REG_OFF: - val = read_reg(ctx, ass->src); + val = read_reg(ctx, ass); val += ass->off; - write_reg(ctx, ass->dst, val); + write_reg(ctx, ass->dst, ass->dst_size, val); break; case ASM_ASSIGNMENT_TYPE_REG_DEREF: - val = read_reg(ctx, ass->src); + val = read_reg(ctx, ass); err = probe_read_user(&val, sizeof(val), (void *)val + ass->off); if (!err) - write_reg(ctx, ass->dst, val); + write_reg(ctx, ass->dst, ass->dst_size, val); break; case ASM_ASSIGNMENT_TYPE_NONE: default: diff --git a/contrib/tester-progs/regs-override.c b/contrib/tester-progs/regs-override.c index 82b3ada9010..87bad8c6202 100644 --- a/contrib/tester-progs/regs-override.c +++ b/contrib/tester-progs/regs-override.c @@ -16,16 +16,35 @@ static __naked int test_1() ); } +static __naked unsigned long test_2() +{ + asm( + "push %rbp\n" /* +0 55 */ + "mov %rsp,%rbp\n" /* +1 48 89 e5 */ + "mov $0xdeadbeefdeadbeef,%rax\n" /* +4 48 b8 00 00 00 00 ef be ad de */ + "pop %rbp\n" /* +14 5d */ + "ret\n" /* +15 c3 */ + ); +} + int main(int argc, char **argv) { int num; - if (argc != 2) + if (argc < 2) return -1; num = atoi(argv[1]); if (num == 1) return test_1(); + if (num == 2) { + unsigned long val; + + if (argc != 3) + return -1; + val = strtoul(argv[2], NULL, 0); + return test_2() == val ? 0 : -1; + } return -1; } diff --git a/pkg/api/processapi/processapi.go b/pkg/api/processapi/processapi.go index 3fce7e427a1..71ea52ce2db 100644 --- a/pkg/api/processapi/processapi.go +++ b/pkg/api/processapi/processapi.go @@ -273,10 +273,11 @@ type CgroupRateOptions struct { } type RegAssignment struct { - Type uint8 - Pad1 uint8 - Src uint16 - Dst uint16 - Pad2 uint16 - Off uint64 + Type uint8 + Pad1 uint8 + Src uint16 + Dst uint16 + SrcSize uint8 + DstSize uint8 + Off uint64 } diff --git a/pkg/api/tracingapi/client_kprobe.go b/pkg/api/tracingapi/client_kprobe.go index d1c4a308614..904402f091a 100644 --- a/pkg/api/tracingapi/client_kprobe.go +++ b/pkg/api/tracingapi/client_kprobe.go @@ -630,9 +630,16 @@ type ConfigUsdtArg struct { Pad1 uint32 `align:"pad1"` } +type ConfigRegArg struct { + Offset uint16 `align:"offset"` + Size uint8 `align:"size"` + Pad uint8 `align:"pad"` +} + const ( EventConfigMaxArgs = 5 EventConfigMaxUsdtArgs = 8 + EventConfigMaxRegArgs = 8 MaxBTFArgDepth = 10 // Artificial value for compilation, may be extended ) @@ -651,4 +658,5 @@ type EventConfig struct { Pad uint32 `align:"pad"` BTFArg [EventConfigMaxArgs][MaxBTFArgDepth]ConfigBTFArg `align:"btf_arg"` UsdtArg [EventConfigMaxUsdtArgs]ConfigUsdtArg `align:"usdt_arg"` + RegArg [EventConfigMaxRegArgs]ConfigRegArg `align:"reg_arg"` } diff --git a/pkg/asm/assignment_linux_amd64.go b/pkg/asm/assignment_linux_amd64.go index 553cff84b7a..e544de53625 100644 --- a/pkg/asm/assignment_linux_amd64.go +++ b/pkg/asm/assignment_linux_amd64.go @@ -21,12 +21,13 @@ const ( var errNext = errors.New("next") type Assignment struct { - Type uint8 - Pad1 uint8 - Src uint16 - Dst uint16 - Pad2 uint16 - Off uint64 + Type uint8 + Pad uint8 + Src uint16 + Dst uint16 + SrcSize uint8 + DstSize uint8 + Off uint64 } type fn func(str string, ass *Assignment) error @@ -77,7 +78,7 @@ func parseRegDeref(str string, ass *Assignment) error { ass.Type = ASM_ASSIGNMENT_TYPE_REG_DEREF ass.Off = uint64(off) - ass.Src, ok = RegOffset(reg.name) + ass.Src, ass.SrcSize, ok = RegOffsetSize(reg.name) if !ok { return fmt.Errorf("failed to parse register '%s'", reg.name) } @@ -100,7 +101,7 @@ func parseRegOff(str string, ass *Assignment) error { ass.Type = ASM_ASSIGNMENT_TYPE_REG_OFF ass.Off = uint64(off) - ass.Src, ok = RegOffset(reg.name) + ass.Src, ass.SrcSize, ok = RegOffsetSize(reg.name) if !ok { return fmt.Errorf("failed to parse register '%s'", reg.name) } @@ -120,7 +121,7 @@ func parseReg(str string, ass *Assignment) error { ass.Type = ASM_ASSIGNMENT_TYPE_REG ass.Off = 0 - ass.Src, ok = RegOffset(reg.name) + ass.Src, ass.SrcSize, ok = RegOffsetSize(reg.name) if !ok { return fmt.Errorf("failed to parse register '%s'", reg.name) } @@ -162,7 +163,7 @@ func ParseAssignment(str string) (*Assignment, error) { var ok bool - ass.Dst, ok = RegOffset(s[0] /* dst */) + ass.Dst, ass.DstSize, ok = RegOffsetSize(s[0] /* dst */) if !ok { return nil, fmt.Errorf("failed to parse register '%s'", s[0]) } diff --git a/pkg/asm/regoffset_linux_amd64.go b/pkg/asm/regoffset_linux_amd64.go index 8707ed14860..946edd7d185 100644 --- a/pkg/asm/regoffset_linux_amd64.go +++ b/pkg/asm/regoffset_linux_amd64.go @@ -46,3 +46,28 @@ func RegOffset(name string) (uint16, bool) { } return 0, false } + +func RegOffsetSize(name string) (uint16, uint8, bool) { + size := func(idx int) uint8 { + switch idx { + case 0: + return 8 // index 0: 8 bytes + case 1: + return 4 // index 1: 4 bytes + case 2: + return 2 // index 2: 2 bytes + case 3: + return 1 // index 3: 1 byte + } + return 0 + } + + for _, off := range offsets { + for idx, n := range off.name { + if n == name { + return off.val, size(idx), true + } + } + } + return 0, 0, false +} diff --git a/pkg/selectors/kernel_regs_amd64.go b/pkg/selectors/kernel_regs_amd64.go index 40ab536e8b0..f923767cfd3 100644 --- a/pkg/selectors/kernel_regs_amd64.go +++ b/pkg/selectors/kernel_regs_amd64.go @@ -37,10 +37,12 @@ func parseOverrideRegs(k *KernelSelectorState, values []string, errValue uint64) } regs = append(regs, processapi.RegAssignment{ - Type: ass.Type, - Src: ass.Src, - Dst: ass.Dst, - Off: ass.Off, + Type: ass.Type, + Src: ass.Src, + Dst: ass.Dst, + SrcSize: ass.SrcSize, + DstSize: ass.DstSize, + Off: ass.Off, }) } diff --git a/pkg/sensors/tracing/args_linux.go b/pkg/sensors/tracing/args_linux.go index ee4bb94d908..04c6234017c 100644 --- a/pkg/sensors/tracing/args_linux.go +++ b/pkg/sensors/tracing/args_linux.go @@ -35,6 +35,7 @@ const ( argReturnCopyBit = 1 << 4 argMaxDataBit = 1 << 5 argCurrentTaskBit = 1 << 6 + argPtRegsBit = 1 << 7 ) func argReturnCopy(meta int) bool { @@ -66,6 +67,9 @@ func getMetaValue(arg *v1alpha1.KProbeArg) (int, error) { if hasCurrentTaskSource(arg) { meta = meta | argCurrentTaskBit } + if hasPtRegsSource(arg) { + meta = meta | argCurrentTaskBit + } return meta, nil } diff --git a/pkg/sensors/tracing/generic.go b/pkg/sensors/tracing/generic.go index fd113df3c51..9bcfd96a4bc 100644 --- a/pkg/sensors/tracing/generic.go +++ b/pkg/sensors/tracing/generic.go @@ -32,6 +32,10 @@ func hasCurrentTaskSource(arg *v1alpha1.KProbeArg) bool { return arg.Source == "current_task" } +func hasPtRegsSource(arg *v1alpha1.KProbeArg) bool { + return arg.Source == "pt_regs" +} + func resolveBTFType(arg *v1alpha1.KProbeArg, ty ebtf.Type) (*ebtf.Type, [api.MaxBTFArgDepth]api.ConfigBTFArg, error) { btfArg := [api.MaxBTFArgDepth]api.ConfigBTFArg{} pathBase := strings.Split(arg.Resolve, ".") diff --git a/pkg/sensors/tracing/generickprobe.go b/pkg/sensors/tracing/generickprobe.go index 80455b11d43..d7aa7f6fc72 100644 --- a/pkg/sensors/tracing/generickprobe.go +++ b/pkg/sensors/tracing/generickprobe.go @@ -25,6 +25,7 @@ import ( "github.com/cilium/tetragon/pkg/api/processapi" api "github.com/cilium/tetragon/pkg/api/tracingapi" "github.com/cilium/tetragon/pkg/arch" + "github.com/cilium/tetragon/pkg/asm" "github.com/cilium/tetragon/pkg/bpf" "github.com/cilium/tetragon/pkg/btf" "github.com/cilium/tetragon/pkg/cgtracker" @@ -792,7 +793,17 @@ func addKprobe(funcName string, instance int, f *v1alpha1.KProbeSpec, in *addKpr argType = gt.GenericTypeFromString(a.Type) } - if a.Resolve != "" && j < api.EventConfigMaxArgs { + var ( + regArg api.ConfigRegArg + ok bool + ) + + if hasPtRegsSource(a) { + regArg.Offset, regArg.Size, ok = asm.RegOffsetSize(a.Resolve) + if !ok { + return fmt.Errorf("error: Failed to retrieve register argument '%s'", a.Resolve) + } + } else if a.Resolve != "" && j < api.EventConfigMaxArgs { if !bpf.HasProgramLargeSize() { return errors.New("error: Resolve flag can't be used for your kernel version. Please update to version 5.4 or higher or disable Resolve flag") } @@ -831,6 +842,7 @@ func addKprobe(funcName string, instance int, f *v1alpha1.KProbeSpec, in *addKpr eventConfig.ArgType[j] = int32(argType) eventConfig.ArgMeta[j] = uint32(argMValue) eventConfig.ArgIndex[j] = int32(a.Index) + eventConfig.RegArg[j] = regArg argP := argPrinter{ index: int(a.Index), diff --git a/pkg/sensors/tracing/uprobe_amd64_test.go b/pkg/sensors/tracing/uprobe_amd64_test.go index 3c8c2edb3ea..040b37531bb 100644 --- a/pkg/sensors/tracing/uprobe_amd64_test.go +++ b/pkg/sensors/tracing/uprobe_amd64_test.go @@ -153,3 +153,87 @@ spec: err = jsonchecker.JsonTestCheck(t, checker) require.NoError(t, err) } + +func testUprobeOverrideRegsActionSize(t *testing.T, ass, num string) { + if !bpf.HasUprobeRegsChange() { + t.Skip("skipping regs override action test, regs override is not supported in kernel") + } + + testBinary := testutils.RepoRootPath("contrib/tester-progs/regs-override") + + // Put uprobe in test_2 function at: + // + // "push %rbp\n" /* +0 55 */ + // "mov %rsp,%rbp\n" /* +1 48 89 e5 */ + // "mov $0xdeadbeef00000000,%rax\n" /* +4 48 b8 00 00 00 00 ef be ad de */ + // --> "pop %rbp\n" /* +14 5d */ + // "ret\n" /* +15 c3 */ + // + // Make sure uprobe overrides test_1 return value (with 11) + // and the rest of the function is not executed. + + pathHook := ` +apiVersion: cilium.io/v1alpha1 +kind: TracingPolicy +metadata: + name: "uprobe" +spec: + uprobes: + - path: "` + testBinary + `" + symbols: + - "test_2+14" + selectors: + - matchActions: + - action: Override + argRegs: + - "` + ass + `" +` + + pathConfigHook := []byte(pathHook) + err := os.WriteFile(testConfigFile, pathConfigHook, 0644) + if err != nil { + t.Fatalf("writeFile(%s): err %s", testConfigFile, err) + } + + upChecker := ec.NewProcessUprobeChecker("UPROBE_BINARIES_MATCH"). + WithProcess(ec.NewProcessChecker(). + WithBinary(sm.Full(testBinary))). + WithSymbol(sm.Full("test_2+14")) + checker := ec.NewUnorderedEventChecker(upChecker) + + var doneWG, readyWG sync.WaitGroup + defer doneWG.Wait() + + ctx, cancel := context.WithTimeout(context.Background(), tus.Conf().CmdWaitTime) + defer cancel() + + obs, err := observertesthelper.GetDefaultObserverWithFile(t, ctx, testConfigFile, tus.Conf().TetragonLib, observertesthelper.WithMyPid()) + if err != nil { + t.Fatalf("GetDefaultObserverWithFile error: %s", err) + } + observertesthelper.LoopEvents(ctx, t, &doneWG, &readyWG, obs) + readyWG.Wait() + + cmd := exec.Command(testBinary, "2", num) + require.NoError(t, cmd.Run()) + require.Equal(t, 0, cmd.ProcessState.ExitCode()) + + err = jsonchecker.JsonTestCheck(t, checker) + require.NoError(t, err) +} + +func TestUprobeOverrideRegsAction_8bytes(t *testing.T) { + testUprobeOverrideRegsActionSize(t, "rax=0x1234567887654321", "0x1234567887654321") +} + +func TestUprobeOverrideRegsAction_4bytes(t *testing.T) { + testUprobeOverrideRegsActionSize(t, "eax=0x12345678", "0xdeadbeef12345678") +} + +func TestUprobeOverrideRegsAction_2bytes(t *testing.T) { + testUprobeOverrideRegsActionSize(t, "ax=0x1234", "0xdeadbeefdead1234") +} + +func TestUprobeOverrideRegsAction_1byte(t *testing.T) { + testUprobeOverrideRegsActionSize(t, "al=0x12", "0xdeadbeefdeadbe12") +}