Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/test/ptrace/scescx.c
39507 views
1
/*-
2
* Copyright (c) 2011, 2012 Konstantin Belousov <[email protected]>
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
6
* are met:
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
*
13
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
* SUCH DAMAGE.
24
*/
25
26
#include <sys/types.h>
27
#include <sys/ptrace.h>
28
#include <sys/syscall.h>
29
#include <sys/sysctl.h>
30
#include <sys/wait.h>
31
#include <assert.h>
32
#include <errno.h>
33
#include <signal.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38
39
#define TRACE ">>>> "
40
41
static const char *
42
decode_wait_status(int status)
43
{
44
static char c[128];
45
char b[32];
46
int first;
47
48
c[0] = '\0';
49
first = 1;
50
if (WIFCONTINUED(status)) {
51
first = 0;
52
strlcat(c, "CONT", sizeof(c));
53
}
54
if (WIFEXITED(status)) {
55
if (first)
56
first = 0;
57
else
58
strlcat(c, ",", sizeof(c));
59
snprintf(b, sizeof(b), "EXIT(%d)", WEXITSTATUS(status));
60
strlcat(c, b, sizeof(c));
61
}
62
if (WIFSIGNALED(status)) {
63
if (first)
64
first = 0;
65
else
66
strlcat(c, ",", sizeof(c));
67
snprintf(b, sizeof(b), "SIG(%s)", strsignal(WTERMSIG(status)));
68
strlcat(c, b, sizeof(c));
69
if (WCOREDUMP(status))
70
strlcat(c, ",CORE", sizeof(c));
71
}
72
if (WIFSTOPPED(status)) {
73
if (first)
74
first = 0;
75
else
76
strlcat(c, ",", sizeof(c));
77
snprintf(b, sizeof(b), "SIG(%s)", strsignal(WSTOPSIG(status)));
78
strlcat(c, b, sizeof(c));
79
}
80
return (c);
81
}
82
83
static const char *
84
decode_pl_flags(struct ptrace_lwpinfo *lwpinfo)
85
{
86
static char c[128];
87
static struct decode_tag {
88
int flag;
89
const char *desc;
90
} decode[] = {
91
{ PL_FLAG_SA, "SA" },
92
{ PL_FLAG_BOUND, "BOUND" },
93
{ PL_FLAG_SCE, "SCE" },
94
{ PL_FLAG_SCX, "SCX" },
95
{ PL_FLAG_EXEC, "EXEC" },
96
{ PL_FLAG_SI, "SI" },
97
{ PL_FLAG_FORKED, "FORKED" },
98
{ PL_FLAG_CHILD, "CHILD" },
99
{ PL_FLAG_BORN, "LWPBORN" },
100
{ PL_FLAG_EXITED, "LWPEXITED" },
101
{ PL_FLAG_VFORKED, "VFORKED" },
102
{ PL_FLAG_VFORK_DONE, "VFORKDONE" },
103
};
104
char de[32];
105
unsigned first, flags, i;
106
107
c[0] = '\0';
108
first = 1;
109
flags = lwpinfo->pl_flags;
110
for (i = 0; i < sizeof(decode) / sizeof(decode[0]); i++) {
111
if ((flags & decode[i].flag) != 0) {
112
if (first)
113
first = 0;
114
else
115
strlcat(c, ",", sizeof(c));
116
strlcat(c, decode[i].desc, sizeof(c));
117
flags &= ~decode[i].flag;
118
}
119
}
120
for (i = 0; i < sizeof(flags) * NBBY; i++) {
121
if ((flags & (1 << i)) != 0) {
122
if (first)
123
first = 0;
124
else
125
strlcat(c, ",", sizeof(c));
126
snprintf(de, sizeof(de), "<%d>", i);
127
strlcat(c, de, sizeof(c));
128
}
129
}
130
return (c);
131
}
132
133
static const char *
134
decode_pl_event(struct ptrace_lwpinfo *lwpinfo)
135
{
136
137
switch (lwpinfo->pl_event) {
138
case PL_EVENT_NONE:
139
return ("NONE");
140
141
case PL_EVENT_SIGNAL:
142
return ("SIG");
143
144
default:
145
return ("UNKNOWN");
146
}
147
}
148
149
static void
150
get_pathname(pid_t pid)
151
{
152
char pathname[PATH_MAX];
153
int error, name[4];
154
size_t len;
155
156
name[0] = CTL_KERN;
157
name[1] = KERN_PROC;
158
name[2] = KERN_PROC_PATHNAME;
159
name[3] = pid;
160
161
len = sizeof(pathname);
162
error = sysctl(name, 4, pathname, &len, NULL, 0);
163
if (error < 0) {
164
if (errno != ESRCH) {
165
fprintf(stderr, "sysctl kern.proc.pathname.%d: %s\n",
166
pid, strerror(errno));
167
return;
168
}
169
fprintf(stderr, "pid %d exited\n", pid);
170
return;
171
}
172
if (len == 0 || strlen(pathname) == 0) {
173
fprintf(stderr, "No cached pathname for process %d\n", pid);
174
return;
175
}
176
printf(TRACE "pid %d path %s\n", pid, pathname);
177
}
178
179
static void
180
wait_info(int pid, int status, struct ptrace_lwpinfo *lwpinfo)
181
{
182
long *args;
183
int error, i;
184
185
printf(TRACE "pid %d wait %s", pid,
186
decode_wait_status(status));
187
if (lwpinfo != NULL) {
188
printf(" event %s flags %s",
189
decode_pl_event(lwpinfo), decode_pl_flags(lwpinfo));
190
if ((lwpinfo->pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) != 0) {
191
printf(" sc%d", lwpinfo->pl_syscall_code);
192
args = calloc(lwpinfo->pl_syscall_narg, sizeof(long));
193
error = ptrace(PT_GET_SC_ARGS, lwpinfo->pl_lwpid,
194
(caddr_t)args, lwpinfo->pl_syscall_narg *
195
sizeof(long));
196
if (error == 0) {
197
printf("(");
198
for (i = 0; i < (int)lwpinfo->pl_syscall_narg;
199
i++) {
200
printf("%s%#lx", i == 0 ? "" : ",",
201
args[i]);
202
}
203
printf(")");
204
} else {
205
fprintf(stderr, "PT_GET_SC_ARGS failed: %s",
206
strerror(errno));
207
}
208
free(args);
209
}
210
}
211
printf("\n");
212
}
213
214
static int trace_syscalls = 1;
215
static int remote_getpid = 0;
216
217
static int
218
trace_sc(int pid)
219
{
220
struct ptrace_sc_remote pscr;
221
struct ptrace_lwpinfo lwpinfo;
222
int status;
223
224
if (ptrace(PT_TO_SCE, pid, (caddr_t)1, 0) < 0) {
225
perror("PT_TO_SCE");
226
ptrace(PT_KILL, pid, NULL, 0);
227
return (-1);
228
}
229
230
if (waitpid(pid, &status, 0) == -1) {
231
perror("waitpid");
232
return (-1);
233
}
234
if (WIFEXITED(status) || WIFSIGNALED(status)) {
235
wait_info(pid, status, NULL);
236
return (-1);
237
}
238
assert(WIFSTOPPED(status));
239
assert(WSTOPSIG(status) == SIGTRAP);
240
241
if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
242
perror("PT_LWPINFO");
243
ptrace(PT_KILL, pid, NULL, 0);
244
return (-1);
245
}
246
wait_info(pid, status, &lwpinfo);
247
assert(lwpinfo.pl_flags & PL_FLAG_SCE);
248
249
if (ptrace(PT_TO_SCX, pid, (caddr_t)1, 0) < 0) {
250
perror("PT_TO_SCX");
251
ptrace(PT_KILL, pid, NULL, 0);
252
return (-1);
253
}
254
255
if (waitpid(pid, &status, 0) == -1) {
256
perror("waitpid");
257
return (-1);
258
}
259
if (WIFEXITED(status) || WIFSIGNALED(status)) {
260
wait_info(pid, status, NULL);
261
return (-1);
262
}
263
assert(WIFSTOPPED(status));
264
assert(WSTOPSIG(status) == SIGTRAP);
265
266
if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
267
perror("PT_LWPINFO");
268
ptrace(PT_KILL, pid, NULL, 0);
269
return (-1);
270
}
271
wait_info(pid, status, &lwpinfo);
272
assert(lwpinfo.pl_flags & PL_FLAG_SCX);
273
274
if (remote_getpid) {
275
memset(&pscr, 0, sizeof(pscr));
276
pscr.pscr_syscall = SYS_getpid;
277
pscr.pscr_nargs = 0;
278
if (ptrace(PT_SC_REMOTE, pid, (caddr_t)&pscr,
279
sizeof(pscr)) < 0) {
280
perror("PT_SC_REMOTE");
281
ptrace(PT_KILL, pid, NULL, 0);
282
return (-1);
283
} else {
284
printf(TRACE "remote getpid %ld errno %d\n",
285
pscr.pscr_ret.sr_retval[0], pscr.pscr_ret.sr_error);
286
if (waitpid(pid, &status, 0) == -1) {
287
perror("waitpid");
288
return (-1);
289
}
290
}
291
}
292
if (lwpinfo.pl_flags & PL_FLAG_EXEC)
293
get_pathname(pid);
294
295
if (lwpinfo.pl_flags & PL_FLAG_FORKED) {
296
printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
297
return (lwpinfo.pl_child_pid);
298
}
299
return (0);
300
}
301
302
static int
303
trace_cont(int pid)
304
{
305
struct ptrace_lwpinfo lwpinfo;
306
int status;
307
308
if (ptrace(PT_CONTINUE, pid, (caddr_t)1, 0) < 0) {
309
perror("PT_CONTINUE");
310
ptrace(PT_KILL, pid, NULL, 0);
311
return (-1);
312
}
313
314
if (waitpid(pid, &status, 0) == -1) {
315
perror("waitpid");
316
return (-1);
317
}
318
if (WIFEXITED(status) || WIFSIGNALED(status)) {
319
wait_info(pid, status, NULL);
320
return (-1);
321
}
322
assert(WIFSTOPPED(status));
323
assert(WSTOPSIG(status) == SIGTRAP);
324
325
if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
326
perror("PT_LWPINFO");
327
ptrace(PT_KILL, pid, NULL, 0);
328
return (-1);
329
}
330
wait_info(pid, status, &lwpinfo);
331
332
if ((lwpinfo.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
333
(PL_FLAG_EXEC | PL_FLAG_SCX))
334
get_pathname(pid);
335
336
if ((lwpinfo.pl_flags & (PL_FLAG_FORKED | PL_FLAG_SCX)) ==
337
(PL_FLAG_FORKED | PL_FLAG_SCX)) {
338
printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
339
return (lwpinfo.pl_child_pid);
340
}
341
342
return (0);
343
}
344
345
static int
346
trace(pid_t pid)
347
{
348
349
return (trace_syscalls ? trace_sc(pid) : trace_cont(pid));
350
}
351
352
353
int
354
main(int argc, char *argv[])
355
{
356
struct ptrace_lwpinfo lwpinfo;
357
int c, status, use_vfork;
358
pid_t pid, pid1;
359
360
trace_syscalls = 1;
361
remote_getpid = 0;
362
use_vfork = 0;
363
while ((c = getopt(argc, argv, "crsv")) != -1) {
364
switch (c) {
365
case 'c':
366
trace_syscalls = 0;
367
break;
368
case 'r':
369
remote_getpid = 1;
370
break;
371
case 's':
372
trace_syscalls = 1;
373
break;
374
case 'v':
375
use_vfork = 1;
376
break;
377
default:
378
case '?':
379
fprintf(stderr, "Usage: %s [-c] [-r] [-s] [-v]\n",
380
argv[0]);
381
return (2);
382
}
383
}
384
385
if ((pid = fork()) < 0) {
386
perror("fork");
387
return 1;
388
}
389
else if (pid == 0) {
390
if (ptrace(PT_TRACE_ME, 0, NULL, 0) < 0) {
391
perror("PT_TRACE_ME");
392
_exit(1);
393
}
394
kill(getpid(), SIGSTOP);
395
getpid();
396
if ((pid1 = use_vfork ? vfork() : fork()) < 0) {
397
perror("fork1");
398
return (1);
399
} else if (pid1 == 0) {
400
printf("Hi from child %d\n", getpid());
401
execl("/bin/ls", "ls", "/", (char *)NULL);
402
}
403
}
404
else { /* parent */
405
if (waitpid(pid, &status, 0) == -1) {
406
perror("waitpid");
407
return (-1);
408
}
409
assert(WIFSTOPPED(status));
410
assert(WSTOPSIG(status) == SIGSTOP);
411
412
if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo,
413
sizeof(lwpinfo)) < 0) {
414
perror("PT_LWPINFO");
415
ptrace(PT_KILL, pid, NULL, 0);
416
return (-1);
417
}
418
wait_info(pid, status, &lwpinfo);
419
420
if (ptrace(PT_FOLLOW_FORK, pid, 0, 1) < 0) {
421
perror("PT_FOLLOW_FORK");
422
ptrace(PT_KILL, pid, NULL, 0);
423
return (2);
424
}
425
426
while ((pid1 = trace(pid)) >= 0) {
427
if (pid1 != 0) {
428
printf(TRACE "attached to pid %d\n", pid1);
429
#if 0
430
kill(pid1, SIGCONT);
431
#endif
432
if (waitpid(pid1, &status, 0) == -1) {
433
perror("waitpid");
434
return (-1);
435
}
436
printf(TRACE "nested loop, pid %d status %s\n",
437
pid1, decode_wait_status(status));
438
assert(WIFSTOPPED(status));
439
assert(WSTOPSIG(status) == SIGSTOP);
440
if (ptrace(PT_LWPINFO, pid1, (caddr_t)&lwpinfo,
441
sizeof(lwpinfo)) < 0) {
442
perror("PT_LWPINFO");
443
ptrace(PT_KILL, pid1, NULL, 0);
444
return (-1);
445
}
446
wait_info(pid1, status, &lwpinfo);
447
448
while (trace(pid1) >= 0)
449
;
450
}
451
}
452
453
ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
454
}
455
return (0);
456
}
457
458