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