|
2 | 2 | /* Copyright (c) 2023 Hengqi Chen */ |
3 | 3 |
|
4 | 4 | #include <test_progs.h> |
| 5 | +#include <asm/ptrace.h> |
5 | 6 | #include "test_uprobe.skel.h" |
6 | 7 |
|
7 | 8 | static FILE *urand_spawn(int *pid) |
@@ -33,7 +34,7 @@ static int urand_trigger(FILE **urand_pipe) |
33 | 34 | return exit_code; |
34 | 35 | } |
35 | 36 |
|
36 | | -void test_uprobe(void) |
| 37 | +static void test_uprobe_attach(void) |
37 | 38 | { |
38 | 39 | LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts); |
39 | 40 | struct test_uprobe *skel; |
@@ -93,3 +94,156 @@ void test_uprobe(void) |
93 | 94 | pclose(urand_pipe); |
94 | 95 | test_uprobe__destroy(skel); |
95 | 96 | } |
| 97 | + |
| 98 | +#ifdef __x86_64__ |
| 99 | +__naked __maybe_unused unsigned long uprobe_regs_change_trigger(void) |
| 100 | +{ |
| 101 | + asm volatile ( |
| 102 | + "ret\n" |
| 103 | + ); |
| 104 | +} |
| 105 | + |
| 106 | +static __naked void uprobe_regs_change(struct pt_regs *before, struct pt_regs *after) |
| 107 | +{ |
| 108 | + asm volatile ( |
| 109 | + "movq %r11, 48(%rdi)\n" |
| 110 | + "movq %r10, 56(%rdi)\n" |
| 111 | + "movq %r9, 64(%rdi)\n" |
| 112 | + "movq %r8, 72(%rdi)\n" |
| 113 | + "movq %rax, 80(%rdi)\n" |
| 114 | + "movq %rcx, 88(%rdi)\n" |
| 115 | + "movq %rdx, 96(%rdi)\n" |
| 116 | + "movq %rsi, 104(%rdi)\n" |
| 117 | + "movq %rdi, 112(%rdi)\n" |
| 118 | + |
| 119 | + /* save 2nd argument */ |
| 120 | + "pushq %rsi\n" |
| 121 | + "call uprobe_regs_change_trigger\n" |
| 122 | + |
| 123 | + /* save return value and load 2nd argument pointer to rax */ |
| 124 | + "pushq %rax\n" |
| 125 | + "movq 8(%rsp), %rax\n" |
| 126 | + |
| 127 | + "movq %r11, 48(%rax)\n" |
| 128 | + "movq %r10, 56(%rax)\n" |
| 129 | + "movq %r9, 64(%rax)\n" |
| 130 | + "movq %r8, 72(%rax)\n" |
| 131 | + "movq %rcx, 88(%rax)\n" |
| 132 | + "movq %rdx, 96(%rax)\n" |
| 133 | + "movq %rsi, 104(%rax)\n" |
| 134 | + "movq %rdi, 112(%rax)\n" |
| 135 | + |
| 136 | + /* restore return value and 2nd argument */ |
| 137 | + "pop %rax\n" |
| 138 | + "pop %rsi\n" |
| 139 | + |
| 140 | + "movq %rax, 80(%rsi)\n" |
| 141 | + "ret\n" |
| 142 | + ); |
| 143 | +} |
| 144 | + |
| 145 | +static void regs_common(void) |
| 146 | +{ |
| 147 | + struct pt_regs before = {}, after = {}, expected = { |
| 148 | + .rax = 0xc0ffe, |
| 149 | + .rcx = 0xbad, |
| 150 | + .rdx = 0xdead, |
| 151 | + .r8 = 0x8, |
| 152 | + .r9 = 0x9, |
| 153 | + .r10 = 0x10, |
| 154 | + .r11 = 0x11, |
| 155 | + .rdi = 0x12, |
| 156 | + .rsi = 0x13, |
| 157 | + }; |
| 158 | + LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts); |
| 159 | + struct test_uprobe *skel; |
| 160 | + |
| 161 | + skel = test_uprobe__open_and_load(); |
| 162 | + if (!ASSERT_OK_PTR(skel, "skel_open")) |
| 163 | + return; |
| 164 | + |
| 165 | + skel->bss->my_pid = getpid(); |
| 166 | + skel->bss->regs = expected; |
| 167 | + |
| 168 | + uprobe_opts.func_name = "uprobe_regs_change_trigger"; |
| 169 | + skel->links.test_regs_change = bpf_program__attach_uprobe_opts(skel->progs.test_regs_change, |
| 170 | + -1, |
| 171 | + "/proc/self/exe", |
| 172 | + 0 /* offset */, |
| 173 | + &uprobe_opts); |
| 174 | + if (!ASSERT_OK_PTR(skel->links.test_regs_change, "bpf_program__attach_uprobe_opts")) |
| 175 | + goto cleanup; |
| 176 | + |
| 177 | + uprobe_regs_change(&before, &after); |
| 178 | + |
| 179 | + ASSERT_EQ(after.rax, expected.rax, "ax"); |
| 180 | + ASSERT_EQ(after.rcx, expected.rcx, "cx"); |
| 181 | + ASSERT_EQ(after.rdx, expected.rdx, "dx"); |
| 182 | + ASSERT_EQ(after.r8, expected.r8, "r8"); |
| 183 | + ASSERT_EQ(after.r9, expected.r9, "r9"); |
| 184 | + ASSERT_EQ(after.r10, expected.r10, "r10"); |
| 185 | + ASSERT_EQ(after.r11, expected.r11, "r11"); |
| 186 | + ASSERT_EQ(after.rdi, expected.rdi, "rdi"); |
| 187 | + ASSERT_EQ(after.rsi, expected.rsi, "rsi"); |
| 188 | + |
| 189 | +cleanup: |
| 190 | + test_uprobe__destroy(skel); |
| 191 | +} |
| 192 | + |
| 193 | +static noinline unsigned long uprobe_regs_change_ip_1(void) |
| 194 | +{ |
| 195 | + return 0xc0ffee; |
| 196 | +} |
| 197 | + |
| 198 | +static noinline unsigned long uprobe_regs_change_ip_2(void) |
| 199 | +{ |
| 200 | + return 0xdeadbeef; |
| 201 | +} |
| 202 | + |
| 203 | +static void regs_ip(void) |
| 204 | +{ |
| 205 | + LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts); |
| 206 | + struct test_uprobe *skel; |
| 207 | + unsigned long ret; |
| 208 | + |
| 209 | + skel = test_uprobe__open_and_load(); |
| 210 | + if (!ASSERT_OK_PTR(skel, "skel_open")) |
| 211 | + return; |
| 212 | + |
| 213 | + skel->bss->my_pid = getpid(); |
| 214 | + skel->bss->ip = (unsigned long) uprobe_regs_change_ip_2; |
| 215 | + |
| 216 | + uprobe_opts.func_name = "uprobe_regs_change_ip_1"; |
| 217 | + skel->links.test_regs_change_ip = bpf_program__attach_uprobe_opts( |
| 218 | + skel->progs.test_regs_change_ip, |
| 219 | + -1, |
| 220 | + "/proc/self/exe", |
| 221 | + 0 /* offset */, |
| 222 | + &uprobe_opts); |
| 223 | + if (!ASSERT_OK_PTR(skel->links.test_regs_change_ip, "bpf_program__attach_uprobe_opts")) |
| 224 | + goto cleanup; |
| 225 | + |
| 226 | + ret = uprobe_regs_change_ip_1(); |
| 227 | + ASSERT_EQ(ret, 0xdeadbeef, "ret"); |
| 228 | + |
| 229 | +cleanup: |
| 230 | + test_uprobe__destroy(skel); |
| 231 | +} |
| 232 | + |
| 233 | +static void test_uprobe_regs_change(void) |
| 234 | +{ |
| 235 | + if (test__start_subtest("regs_change_common")) |
| 236 | + regs_common(); |
| 237 | + if (test__start_subtest("regs_change_ip")) |
| 238 | + regs_ip(); |
| 239 | +} |
| 240 | +#else |
| 241 | +static void test_uprobe_regs_change(void) { } |
| 242 | +#endif |
| 243 | + |
| 244 | +void test_uprobe(void) |
| 245 | +{ |
| 246 | + if (test__start_subtest("attach")) |
| 247 | + test_uprobe_attach(); |
| 248 | + test_uprobe_regs_change(); |
| 249 | +} |
0 commit comments