Home | History | Annotate | Download | only in linux
      1 /*
      2  *
      3  * honggfuzz - architecture dependent code (LINUX/PTRACE)
      4  * -----------------------------------------
      5  *
      6  * Author: Robert Swiecki <swiecki (at) google.com>
      7  *
      8  * Copyright 2010-2018 by Google Inc. All Rights Reserved.
      9  *
     10  * Licensed under the Apache License, Version 2.0 (the "License"); you may
     11  * not use this file except in compliance with the License. You may obtain
     12  * a copy of the License at
     13  *
     14  * http://www.apache.org/licenses/LICENSE-2.0
     15  *
     16  * Unless required by applicable law or agreed to in writing, software
     17  * distributed under the License is distributed on an "AS IS" BASIS,
     18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
     19  * implied. See the License for the specific language governing
     20  * permissions and limitations under the License.
     21  *
     22  */
     23 
     24 #include "linux/trace.h"
     25 
     26 #include <ctype.h>
     27 #include <dirent.h>
     28 #include <elf.h>
     29 #include <endian.h>
     30 #include <errno.h>
     31 #include <fcntl.h>
     32 #include <inttypes.h>
     33 #include <signal.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <sys/cdefs.h>
     38 #include <sys/personality.h>
     39 #include <sys/ptrace.h>
     40 #include <sys/resource.h>
     41 #include <sys/stat.h>
     42 #include <sys/syscall.h>
     43 #include <sys/time.h>
     44 #include <sys/types.h>
     45 #include <sys/uio.h>
     46 #include <sys/user.h>
     47 #include <sys/wait.h>
     48 #include <time.h>
     49 #include <unistd.h>
     50 
     51 #include "libhfcommon/common.h"
     52 #include "libhfcommon/files.h"
     53 #include "libhfcommon/log.h"
     54 #include "libhfcommon/util.h"
     55 #include "linux/bfd.h"
     56 #include "linux/unwind.h"
     57 #include "sanitizers.h"
     58 #include "socketfuzzer.h"
     59 #include "subproc.h"
     60 
     61 #if defined(__ANDROID__)
     62 #include "capstone.h"
     63 #endif
     64 
     65 #if defined(__i386__) || defined(__arm__) || defined(__powerpc__)
     66 #define REG_TYPE uint32_t
     67 #define REG_PM PRIx32
     68 #define REG_PD "0x%08"
     69 #elif defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) || \
     70     defined(__mips__) || defined(__mips64__)
     71 #define REG_TYPE uint64_t
     72 #define REG_PM PRIx64
     73 #define REG_PD "0x%016"
     74 #endif
     75 
     76 /*
     77  * Size in characters required to store a string representation of a
     78  * register value (0xdeadbeef style))
     79  */
     80 #define REGSIZEINCHAR (2 * sizeof(REG_TYPE) + 3)
     81 
     82 #if defined(__i386__) || defined(__x86_64__)
     83 #define MAX_INSTR_SZ 16
     84 #elif defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)
     85 #define MAX_INSTR_SZ 4
     86 #elif defined(__aarch64__)
     87 #define MAX_INSTR_SZ 8
     88 #elif defined(__mips__) || defined(__mips64__)
     89 #define MAX_INSTR_SZ 8
     90 #endif
     91 
     92 #if defined(__i386__) || defined(__x86_64__)
     93 struct user_regs_struct_32 {
     94     uint32_t ebx;
     95     uint32_t ecx;
     96     uint32_t edx;
     97     uint32_t esi;
     98     uint32_t edi;
     99     uint32_t ebp;
    100     uint32_t eax;
    101     uint16_t ds, __ds;
    102     uint16_t es, __es;
    103     uint16_t fs, __fs;
    104     uint16_t gs, __gs;
    105     uint32_t orig_eax;
    106     uint32_t eip;
    107     uint16_t cs, __cs;
    108     uint32_t eflags;
    109     uint32_t esp;
    110     uint16_t ss, __ss;
    111 };
    112 
    113 struct user_regs_struct_64 {
    114     uint64_t r15;
    115     uint64_t r14;
    116     uint64_t r13;
    117     uint64_t r12;
    118     uint64_t bp;
    119     uint64_t bx;
    120     uint64_t r11;
    121     uint64_t r10;
    122     uint64_t r9;
    123     uint64_t r8;
    124     uint64_t ax;
    125     uint64_t cx;
    126     uint64_t dx;
    127     uint64_t si;
    128     uint64_t di;
    129     uint64_t orig_ax;
    130     uint64_t ip;
    131     uint64_t cs;
    132     uint64_t flags;
    133     uint64_t sp;
    134     uint64_t ss;
    135     uint64_t fs_base;
    136     uint64_t gs_base;
    137     uint64_t ds;
    138     uint64_t es;
    139     uint64_t fs;
    140     uint64_t gs;
    141 };
    142 #define HEADERS_STRUCT struct user_regs_struct_64
    143 #endif /* defined(__i386__) || defined(__x86_64__) */
    144 
    145 #if defined(__arm__) || defined(__aarch64__)
    146 #ifndef ARM_pc
    147 #ifdef __ANDROID__ /* Building with NDK headers */
    148 #define ARM_pc uregs[15]
    149 #else /* Building with glibc headers */
    150 #define ARM_pc 15
    151 #endif
    152 #endif /* ARM_pc */
    153 #ifndef ARM_cpsr
    154 #ifdef __ANDROID__ /* Building with NDK headers */
    155 #define ARM_cpsr uregs[16]
    156 #else /* Building with glibc headers */
    157 #define ARM_cpsr 16
    158 #endif
    159 #endif /* ARM_cpsr */
    160 struct user_regs_struct_32 {
    161     uint32_t uregs[18];
    162 };
    163 
    164 struct user_regs_struct_64 {
    165     uint64_t regs[31];
    166     uint64_t sp;
    167     uint64_t pc;
    168     uint64_t pstate;
    169 };
    170 #define HEADERS_STRUCT struct user_regs_struct_64
    171 #endif /* defined(__arm__) || defined(__aarch64__) */
    172 
    173 #if defined(__powerpc64__) || defined(__powerpc__)
    174 #define HEADERS_STRUCT struct pt_regs
    175 struct user_regs_struct_32 {
    176     uint32_t gpr[32];
    177     uint32_t nip;
    178     uint32_t msr;
    179     uint32_t orig_gpr3;
    180     uint32_t ctr;
    181     uint32_t link;
    182     uint32_t xer;
    183     uint32_t ccr;
    184     uint32_t mq;
    185     uint32_t trap;
    186     uint32_t dar;
    187     uint32_t dsisr;
    188     uint32_t result;
    189     /*
    190      * elf.h's ELF_NGREG says it's 48 registers, so kernel fills it in
    191      * with some zeros
    192      */
    193     uint32_t zero0;
    194     uint32_t zero1;
    195     uint32_t zero2;
    196     uint32_t zero3;
    197 };
    198 struct user_regs_struct_64 {
    199     uint64_t gpr[32];
    200     uint64_t nip;
    201     uint64_t msr;
    202     uint64_t orig_gpr3;
    203     uint64_t ctr;
    204     uint64_t link;
    205     uint64_t xer;
    206     uint64_t ccr;
    207     uint64_t softe;
    208     uint64_t trap;
    209     uint64_t dar;
    210     uint64_t dsisr;
    211     uint64_t result;
    212     /*
    213      * elf.h's ELF_NGREG says it's 48 registers, so kernel fills it in
    214      * with some zeros
    215      */
    216     uint64_t zero0;
    217     uint64_t zero1;
    218     uint64_t zero2;
    219     uint64_t zero3;
    220 };
    221 #endif /* defined(__powerpc64__) || defined(__powerpc__) */
    222 
    223 #if defined(__mips__) || defined(__mips64__)
    224 struct user_regs_struct {
    225     uint64_t regs[32];
    226 
    227     uint64_t lo;
    228     uint64_t hi;
    229     uint64_t cp0_epc;
    230     uint64_t cp0_badvaddr;
    231     uint64_t cp0_status;
    232     uint64_t cp0_cause;
    233 };
    234 #define HEADERS_STRUCT struct user_regs_struct
    235 #endif /* defined(__mips__) || defined(__mips64__) */
    236 
    237 #if defined(__ANDROID__)
    238 /*
    239  * Some Android ABIs don't implement PTRACE_GETREGS (e.g. aarch64)
    240  */
    241 #if defined(PTRACE_GETREGS)
    242 #define PTRACE_GETREGS_AVAILABLE 1
    243 #else
    244 #define PTRACE_GETREGS_AVAILABLE 0
    245 #endif /* defined(PTRACE_GETREGS) */
    246 #endif /* defined(__ANDROID__) */
    247 
    248 static struct {
    249     const char* descr;
    250     bool important;
    251 } arch_sigs[_NSIG + 1] = {
    252     [0 ...(_NSIG)].important = false,
    253     [0 ...(_NSIG)].descr = "UNKNOWN",
    254 
    255     [SIGTRAP].important = false,
    256     [SIGTRAP].descr = "SIGTRAP",
    257 
    258     [SIGILL].important = true,
    259     [SIGILL].descr = "SIGILL",
    260 
    261     [SIGFPE].important = true,
    262     [SIGFPE].descr = "SIGFPE",
    263 
    264     [SIGSEGV].important = true,
    265     [SIGSEGV].descr = "SIGSEGV",
    266 
    267     [SIGBUS].important = true,
    268     [SIGBUS].descr = "SIGBUS",
    269 
    270     /* Is affected from monitorSIGABRT flag */
    271     [SIGABRT].important = false,
    272     [SIGABRT].descr = "SIGABRT",
    273 
    274     /* Is affected from tmoutVTALRM flag */
    275     [SIGVTALRM].important = false,
    276     [SIGVTALRM].descr = "SIGVTALRM-TMOUT",
    277 
    278     /* seccomp-bpf kill */
    279     [SIGSYS].important = true,
    280     [SIGSYS].descr = "SIGSYS",
    281 };
    282 
    283 #ifndef SI_FROMUSER
    284 #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
    285 #endif /* SI_FROMUSER */
    286 
    287 extern const char* sys_sigabbrev[];
    288 
    289 static __thread char arch_signame[32];
    290 static const char* arch_sigName(int signo) {
    291     if (signo < 0 || signo > _NSIG) {
    292         snprintf(arch_signame, sizeof(arch_signame), "UNKNOWN-%d", signo);
    293         return arch_signame;
    294     }
    295     if (signo > __SIGRTMIN) {
    296         snprintf(arch_signame, sizeof(arch_signame), "SIG%d-RTMIN+%d", signo, signo - __SIGRTMIN);
    297         return arch_signame;
    298     }
    299 #ifdef __ANDROID__
    300     return arch_sigs[signo].descr;
    301 #else
    302     if (sys_sigabbrev[signo] == NULL) {
    303         snprintf(arch_signame, sizeof(arch_signame), "SIG%d", signo);
    304     } else {
    305         snprintf(arch_signame, sizeof(arch_signame), "SIG%s", sys_sigabbrev[signo]);
    306     }
    307     return arch_signame;
    308 #endif /* __ANDROID__ */
    309 }
    310 
    311 static size_t arch_getProcMem(pid_t pid, uint8_t* buf, size_t len, REG_TYPE pc) {
    312     /*
    313      * Let's try process_vm_readv first
    314      */
    315     const struct iovec local_iov = {
    316         .iov_base = buf,
    317         .iov_len = len,
    318     };
    319     const struct iovec remote_iov = {
    320         .iov_base = (void*)(uintptr_t)pc,
    321         .iov_len = len,
    322     };
    323     if (process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0) == (ssize_t)len) {
    324         return len;
    325     }
    326     // Debug if failed since it shouldn't happen very often
    327     PLOG_D("process_vm_readv() failed");
    328 
    329     /*
    330      * Ok, let's do it via ptrace() then.
    331      * len must be aligned to the sizeof(long)
    332      */
    333     int cnt = len / sizeof(long);
    334     size_t memsz = 0;
    335 
    336     for (int x = 0; x < cnt; x++) {
    337         uint8_t* addr = (uint8_t*)(uintptr_t)pc + (int)(x * sizeof(long));
    338         long ret = ptrace(PTRACE_PEEKDATA, pid, addr, NULL);
    339 
    340         if (errno != 0) {
    341             PLOG_W("Couldn't PT_READ_D on pid %d, addr: %p", pid, addr);
    342             break;
    343         }
    344 
    345         memsz += sizeof(long);
    346         memcpy(&buf[x * sizeof(long)], &ret, sizeof(long));
    347     }
    348     return memsz;
    349 }
    350 
    351 static size_t arch_getPC(pid_t pid, REG_TYPE* pc, REG_TYPE* status_reg HF_ATTR_UNUSED) {
    352 /*
    353  * Some old ARM android kernels are failing with PTRACE_GETREGS to extract
    354  * the correct register values if struct size is bigger than expected. As such the
    355  * 32/64-bit multiplexing trick is not working for them in case PTRACE_GETREGSET
    356  * fails or is not implemented. To cover such cases we explicitly define
    357  * the struct size to 32bit version for arm CPU.
    358  */
    359 #if defined(__arm__)
    360     struct user_regs_struct_32 regs;
    361 #else
    362     HEADERS_STRUCT regs;
    363 #endif
    364     const struct iovec pt_iov = {
    365         .iov_base = &regs,
    366         .iov_len = sizeof(regs),
    367     };
    368 
    369     if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &pt_iov) == -1L) {
    370         PLOG_D("ptrace(PTRACE_GETREGSET) failed");
    371 
    372 // If PTRACE_GETREGSET fails, try PTRACE_GETREGS if available
    373 #if PTRACE_GETREGS_AVAILABLE
    374         if (ptrace(PTRACE_GETREGS, pid, 0, &regs)) {
    375             PLOG_D("ptrace(PTRACE_GETREGS) failed");
    376             LOG_W("ptrace PTRACE_GETREGSET & PTRACE_GETREGS failed to extract target registers");
    377             return 0;
    378         }
    379 #else
    380         return 0;
    381 #endif
    382     }
    383 #if defined(__i386__) || defined(__x86_64__)
    384     /*
    385      * 32-bit
    386      */
    387     if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
    388         struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)&regs;
    389         *pc = r32->eip;
    390         *status_reg = r32->eflags;
    391         return pt_iov.iov_len;
    392     }
    393 
    394     /*
    395      * 64-bit
    396      */
    397     if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
    398         struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)&regs;
    399         *pc = r64->ip;
    400         *status_reg = r64->flags;
    401         return pt_iov.iov_len;
    402     }
    403     LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len);
    404     return 0;
    405 #endif /* defined(__i386__) || defined(__x86_64__) */
    406 
    407 #if defined(__arm__) || defined(__aarch64__)
    408     /*
    409      * 32-bit
    410      */
    411     if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
    412         struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)&regs;
    413 #ifdef __ANDROID__
    414         *pc = r32->ARM_pc;
    415         *status_reg = r32->ARM_cpsr;
    416 #else
    417         *pc = r32->uregs[ARM_pc];
    418         *status_reg = r32->uregs[ARM_cpsr];
    419 #endif
    420         return pt_iov.iov_len;
    421     }
    422 
    423     /*
    424      * 64-bit
    425      */
    426     if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
    427         struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)&regs;
    428         *pc = r64->pc;
    429         *status_reg = r64->pstate;
    430         return pt_iov.iov_len;
    431     }
    432     LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len);
    433     return 0;
    434 #endif /* defined(__arm__) || defined(__aarch64__) */
    435 
    436 #if defined(__powerpc64__) || defined(__powerpc__)
    437     /*
    438      * 32-bit
    439      */
    440     if (pt_iov.iov_len == sizeof(struct user_regs_struct_32)) {
    441         struct user_regs_struct_32* r32 = (struct user_regs_struct_32*)&regs;
    442         *pc = r32->nip;
    443         return pt_iov.iov_len;
    444     }
    445 
    446     /*
    447      * 64-bit
    448      */
    449     if (pt_iov.iov_len == sizeof(struct user_regs_struct_64)) {
    450         struct user_regs_struct_64* r64 = (struct user_regs_struct_64*)&regs;
    451         *pc = r64->nip;
    452         return pt_iov.iov_len;
    453     }
    454 
    455     LOG_W("Unknown registers structure size: '%zd'", pt_iov.iov_len);
    456     return 0;
    457 #endif /* defined(__powerpc64__) || defined(__powerpc__) */
    458 
    459 #if defined(__mips__) || defined(__mips64__)
    460     *pc = regs.cp0_epc;
    461     return pt_iov.iov_len;
    462 #endif /* defined(__mips__) || defined(__mips64__) */
    463 
    464     LOG_D("Unknown/unsupported CPU architecture");
    465     return 0;
    466 }
    467 
    468 static void arch_getInstrStr(pid_t pid, REG_TYPE* pc, char* instr) {
    469     /*
    470      * We need a value aligned to 8
    471      * which is sizeof(long) on 64bit CPU archs (on most of them, I hope;)
    472      */
    473     uint8_t buf[MAX_INSTR_SZ];
    474     size_t memsz;
    475     REG_TYPE status_reg = 0;
    476 
    477     snprintf(instr, _HF_INSTR_SZ, "%s", "[UNKNOWN]");
    478 
    479     size_t pcRegSz = arch_getPC(pid, pc, &status_reg);
    480     if (!pcRegSz) {
    481         LOG_W("Current architecture not supported for disassembly");
    482         return;
    483     }
    484 
    485     if ((memsz = arch_getProcMem(pid, buf, sizeof(buf), *pc)) == 0) {
    486         snprintf(instr, _HF_INSTR_SZ, "%s", "[NOT_MMAPED]");
    487         return;
    488     }
    489 #if !defined(__ANDROID__)
    490     arch_bfdDisasm(pid, buf, memsz, instr);
    491 #else
    492     cs_arch arch;
    493     cs_mode mode;
    494 #if defined(__arm__) || defined(__aarch64__)
    495     arch = (pcRegSz == sizeof(struct user_regs_struct_64)) ? CS_ARCH_ARM64 : CS_ARCH_ARM;
    496     if (arch == CS_ARCH_ARM) {
    497         mode = (status_reg & 0x20) ? CS_MODE_THUMB : CS_MODE_ARM;
    498     } else {
    499         mode = CS_MODE_ARM;
    500     }
    501 #elif defined(__i386__) || defined(__x86_64__)
    502     arch = CS_ARCH_X86;
    503     mode = (pcRegSz == sizeof(struct user_regs_struct_64)) ? CS_MODE_64 : CS_MODE_32;
    504 #else
    505     LOG_E("Unknown/Unsupported Android CPU architecture");
    506 #endif
    507 
    508     csh handle;
    509     cs_err err = cs_open(arch, mode, &handle);
    510     if (err != CS_ERR_OK) {
    511         LOG_W("Capstone initialization failed: '%s'", cs_strerror(err));
    512         return;
    513     }
    514 
    515     cs_insn* insn;
    516     size_t count = cs_disasm(handle, buf, sizeof(buf), *pc, 0, &insn);
    517 
    518     if (count < 1) {
    519         LOG_W("Couldn't disassemble the assembler instructions' stream: '%s'",
    520             cs_strerror(cs_errno(handle)));
    521         cs_close(&handle);
    522         return;
    523     }
    524 
    525     snprintf(instr, _HF_INSTR_SZ, "%s %s", insn[0].mnemonic, insn[0].op_str);
    526     cs_free(insn, count);
    527     cs_close(&handle);
    528 #endif /* defined(__ANDROID__) */
    529 
    530     for (int x = 0; instr[x] && x < _HF_INSTR_SZ; x++) {
    531         if (instr[x] == '/' || instr[x] == '\\' || isspace(instr[x]) || !isprint(instr[x])) {
    532             instr[x] = '_';
    533         }
    534     }
    535 
    536     return;
    537 }
    538 
    539 static void arch_hashCallstack(run_t* run, funcs_t* funcs, size_t funcCnt, bool enableMasking) {
    540     uint64_t hash = 0;
    541     for (size_t i = 0; i < funcCnt && i < run->global->linux.numMajorFrames; i++) {
    542         /*
    543          * Convert PC to char array to be compatible with hash function
    544          */
    545         char pcStr[REGSIZEINCHAR] = {0};
    546         snprintf(pcStr, REGSIZEINCHAR, REG_PD REG_PM, (REG_TYPE)(long)funcs[i].pc);
    547 
    548         /*
    549          * Hash the last three nibbles
    550          */
    551         hash ^= util_hash(&pcStr[strlen(pcStr) - 3], 3);
    552     }
    553 
    554     /*
    555      * If only one frame, hash is not safe to be used for uniqueness. We mask it
    556      * here with a constant prefix, so analyzers can pick it up and create filenames
    557      * accordingly. 'enableMasking' is controlling masking for cases where it should
    558      * not be enabled (e.g. fuzzer worker is from verifier).
    559      */
    560     if (enableMasking && funcCnt == 1) {
    561         hash |= _HF_SINGLE_FRAME_MASK;
    562     }
    563     run->backtrace = hash;
    564 }
    565 
    566 static void arch_traceGenerateReport(
    567     pid_t pid, run_t* run, funcs_t* funcs, size_t funcCnt, siginfo_t* si, const char* instr) {
    568     run->report[0] = '\0';
    569     util_ssnprintf(run->report, sizeof(run->report), "ORIG_FNAME: %s\n", run->origFileName);
    570     util_ssnprintf(run->report, sizeof(run->report), "FUZZ_FNAME: %s\n", run->crashFileName);
    571     util_ssnprintf(run->report, sizeof(run->report), "PID: %d\n", pid);
    572     util_ssnprintf(run->report, sizeof(run->report), "SIGNAL: %s (%d)\n",
    573         arch_sigName(si->si_signo), si->si_signo);
    574     util_ssnprintf(run->report, sizeof(run->report), "FAULT ADDRESS: %p\n",
    575         SI_FROMUSER(si) ? NULL : si->si_addr);
    576     util_ssnprintf(run->report, sizeof(run->report), "INSTRUCTION: %s\n", instr);
    577     util_ssnprintf(
    578         run->report, sizeof(run->report), "STACK HASH: %016" PRIx64 "\n", run->backtrace);
    579     util_ssnprintf(run->report, sizeof(run->report), "STACK:\n");
    580     for (size_t i = 0; i < funcCnt; i++) {
    581 #ifdef __HF_USE_CAPSTONE__
    582         util_ssnprintf(
    583             run->report, sizeof(run->report), " <" REG_PD REG_PM "> ", (REG_TYPE)(long)funcs[i].pc);
    584         if (funcs[i].func[0] != '\0')
    585             util_ssnprintf(run->report, sizeof(run->report), "[%s() + 0x%x at %s]\n", funcs[i].func,
    586                 funcs[i].line, funcs[i].mapName);
    587         else
    588             util_ssnprintf(run->report, sizeof(run->report), "[]\n");
    589 #else
    590         util_ssnprintf(run->report, sizeof(run->report), " <" REG_PD REG_PM "> [%s():%zu at %s]\n",
    591             (REG_TYPE)(long)funcs[i].pc, funcs[i].func, funcs[i].line, funcs[i].mapName);
    592 #endif
    593     }
    594 
    595 // libunwind is not working for 32bit targets in 64bit systems
    596 #if defined(__aarch64__)
    597     if (funcCnt == 0) {
    598         util_ssnprintf(run->report, sizeof(run->report),
    599             " !ERROR: If 32bit fuzz target"
    600             " in aarch64 system, try ARM 32bit build\n");
    601     }
    602 #endif
    603 
    604     return;
    605 }
    606 
    607 static void arch_traceAnalyzeData(run_t* run, pid_t pid) {
    608     REG_TYPE pc = 0, status_reg = 0;
    609     size_t pcRegSz = arch_getPC(pid, &pc, &status_reg);
    610     if (!pcRegSz) {
    611         LOG_W("ptrace arch_getPC failed");
    612         return;
    613     }
    614 
    615     /*
    616      * Unwind and resolve symbols
    617      */
    618     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
    619     defer {
    620         free(funcs);
    621     };
    622     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
    623 
    624 #if !defined(__ANDROID__)
    625     size_t funcCnt = arch_unwindStack(pid, funcs);
    626     arch_bfdResolveSyms(pid, funcs, funcCnt);
    627 #else
    628     size_t funcCnt = arch_unwindStack(pid, funcs);
    629 #endif
    630 
    631     /*
    632      * If unwinder failed (zero frames), use PC from ptrace GETREGS if not zero.
    633      * If PC reg zero return and callers should handle zero hash case.
    634      */
    635     if (funcCnt == 0) {
    636         if (pc) {
    637             /* Manually update major frame PC & frames counter */
    638             funcs[0].pc = (void*)(uintptr_t)pc;
    639             funcCnt = 1;
    640         } else {
    641             return;
    642         }
    643     }
    644 
    645     /*
    646      * Calculate backtrace callstack hash signature
    647      */
    648     arch_hashCallstack(run, funcs, funcCnt, false);
    649 }
    650 
    651 static void arch_traceSaveData(run_t* run, pid_t pid) {
    652     REG_TYPE pc = 0;
    653 
    654     /* Local copy since flag is overridden for some crashes */
    655     bool saveUnique = run->global->io.saveUnique;
    656 
    657     char instr[_HF_INSTR_SZ] = "\x00";
    658     siginfo_t si;
    659     bzero(&si, sizeof(si));
    660 
    661     if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == -1) {
    662         PLOG_W("Couldn't get siginfo for pid %d", pid);
    663     }
    664 
    665     arch_getInstrStr(pid, &pc, instr);
    666 
    667     LOG_D("Pid: %d, signo: %d, errno: %d, code: %d, addr: %p, pc: %" REG_PM ", instr: '%s'", pid,
    668         si.si_signo, si.si_errno, si.si_code, si.si_addr, pc, instr);
    669 
    670     if (!SI_FROMUSER(&si) && pc && si.si_addr < run->global->linux.ignoreAddr) {
    671         LOG_I("Input is interesting (%s), but the si.si_addr is %p (below %p), skipping",
    672             arch_sigName(si.si_signo), si.si_addr, run->global->linux.ignoreAddr);
    673         return;
    674     }
    675 
    676     /*
    677      * Unwind and resolve symbols
    678      */
    679     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
    680     defer {
    681         free(funcs);
    682     };
    683     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
    684 
    685 #if !defined(__ANDROID__)
    686     size_t funcCnt = arch_unwindStack(pid, funcs);
    687     arch_bfdResolveSyms(pid, funcs, funcCnt);
    688 #else
    689     size_t funcCnt = arch_unwindStack(pid, funcs);
    690 #endif
    691 
    692     /*
    693      * If unwinder failed (zero frames), use PC from ptrace GETREGS if not zero.
    694      * If PC reg zero, temporarily disable uniqueness flag since callstack
    695      * hash will be also zero, thus not safe for unique decisions.
    696      */
    697     if (funcCnt == 0) {
    698         if (pc) {
    699             /* Manually update major frame PC & frames counter */
    700             funcs[0].pc = (void*)(uintptr_t)pc;
    701             funcCnt = 1;
    702         } else {
    703             saveUnique = false;
    704         }
    705     }
    706 
    707     /*
    708      * Temp local copy of previous backtrace value in case worker hit crashes into multiple
    709      * tids for same target master thread. Will be 0 for first crash against target.
    710      */
    711     uint64_t oldBacktrace = run->backtrace;
    712 
    713     /*
    714      * Calculate backtrace callstack hash signature
    715      */
    716     arch_hashCallstack(run, funcs, funcCnt, saveUnique);
    717 
    718     /*
    719      * If unique flag is set and single frame crash, disable uniqueness for this crash
    720      * to always save (timestamp will be added to the filename)
    721      */
    722     if (saveUnique && (funcCnt == 1)) {
    723         saveUnique = false;
    724     }
    725 
    726     /*
    727      * If worker crashFileName member is set, it means that a tid has already crashed
    728      * from target master thread.
    729      */
    730     if (run->crashFileName[0] != '\0') {
    731         LOG_D("Multiple crashes detected from worker against attached tids group");
    732 
    733         /*
    734          * If stackhashes match, don't re-analyze. This will avoid duplicates
    735          * and prevent verifier from running multiple passes. Depth of check is
    736          * always 1 (last backtrace saved only per target iteration).
    737          */
    738         if (oldBacktrace == run->backtrace) {
    739             return;
    740         }
    741     }
    742 
    743     /* Increase global crashes counter */
    744     ATOMIC_POST_INC(run->global->cnts.crashesCnt);
    745 
    746     /*
    747      * Check if backtrace contains whitelisted symbol. Whitelist overrides
    748      * both stackhash and symbol blacklist. Crash is always kept regardless
    749      * of the status of uniqueness flag.
    750      */
    751     if (run->global->linux.symsWl) {
    752         char* wlSymbol = arch_btContainsSymbol(
    753             run->global->linux.symsWlCnt, run->global->linux.symsWl, funcCnt, funcs);
    754         if (wlSymbol != NULL) {
    755             saveUnique = false;
    756             LOG_D("Whitelisted symbol '%s' found, skipping blacklist checks", wlSymbol);
    757         }
    758     } else {
    759         /*
    760          * Check if stackhash is blacklisted
    761          */
    762         if (run->global->feedback.blacklist &&
    763             (fastArray64Search(run->global->feedback.blacklist, run->global->feedback.blacklistCnt,
    764                  run->backtrace) != -1)) {
    765             LOG_I("Blacklisted stack hash '%" PRIx64 "', skipping", run->backtrace);
    766             ATOMIC_POST_INC(run->global->cnts.blCrashesCnt);
    767             return;
    768         }
    769 
    770         /*
    771          * Check if backtrace contains blacklisted symbol
    772          */
    773         char* blSymbol = arch_btContainsSymbol(
    774             run->global->linux.symsBlCnt, run->global->linux.symsBl, funcCnt, funcs);
    775         if (blSymbol != NULL) {
    776             LOG_I("Blacklisted symbol '%s' found, skipping", blSymbol);
    777             ATOMIC_POST_INC(run->global->cnts.blCrashesCnt);
    778             return;
    779         }
    780     }
    781 
    782     /* If non-blacklisted crash detected, zero set two MSB */
    783     ATOMIC_POST_ADD(run->global->cfg.dynFileIterExpire, _HF_DYNFILE_SUB_MASK);
    784 
    785     void* sig_addr = si.si_addr;
    786     if (!run->global->linux.disableRandomization) {
    787         pc = 0UL;
    788         sig_addr = NULL;
    789     }
    790 
    791     /* User-induced signals don't set si.si_addr */
    792     if (SI_FROMUSER(&si)) {
    793         sig_addr = NULL;
    794     }
    795 
    796     /* If dry run mode, copy file with same name into workspace */
    797     if (run->global->mutate.mutationsPerRun == 0U && run->global->cfg.useVerifier) {
    798         snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir,
    799             run->origFileName);
    800     } else if (saveUnique) {
    801         snprintf(run->crashFileName, sizeof(run->crashFileName),
    802             "%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s",
    803             run->global->io.crashDir, arch_sigName(si.si_signo), pc, run->backtrace, si.si_code,
    804             sig_addr, instr, run->global->io.fileExtn);
    805     } else {
    806         char localtmstr[PATH_MAX];
    807         util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
    808         snprintf(run->crashFileName, sizeof(run->crashFileName),
    809             "%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s",
    810             run->global->io.crashDir, arch_sigName(si.si_signo), pc, run->backtrace, si.si_code,
    811             sig_addr, instr, localtmstr, pid, run->global->io.fileExtn);
    812     }
    813 
    814     /* Target crashed (no duplicate detection yet) */
    815     if (run->global->socketFuzzer.enabled) {
    816         LOG_D("SocketFuzzer: trace: Crash Identified");
    817     }
    818 
    819     if (files_exists(run->crashFileName)) {
    820         LOG_I("Crash (dup): '%s' already exists, skipping", run->crashFileName);
    821         // Clear filename so that verifier can understand we hit a duplicate
    822         memset(run->crashFileName, 0, sizeof(run->crashFileName));
    823         return;
    824     }
    825 
    826     if (!files_writeBufToFile(run->crashFileName, run->dynamicFile, run->dynamicFileSz,
    827             O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC)) {
    828         LOG_E("Couldn't write to '%s'", run->crashFileName);
    829         return;
    830     }
    831 
    832     /* Unique new crash, notify fuzzer */
    833     if (run->global->socketFuzzer.enabled) {
    834         LOG_D("SocketFuzzer: trace: New Uniqu Crash");
    835         fuzz_notifySocketFuzzerCrash(run);
    836     }
    837     LOG_I("Crash: saved as '%s'", run->crashFileName);
    838 
    839     ATOMIC_POST_INC(run->global->cnts.uniqueCrashesCnt);
    840     /* If unique crash found, reset dynFile counter */
    841     ATOMIC_CLEAR(run->global->cfg.dynFileIterExpire);
    842 
    843     arch_traceGenerateReport(pid, run, funcs, funcCnt, &si, instr);
    844 }
    845 
    846 /* TODO: Add report parsing support for other sanitizers too */
    847 static int arch_parseAsanReport(
    848     run_t* run, pid_t pid, funcs_t* funcs, void** crashAddr, char** op) {
    849     char crashReport[PATH_MAX] = {0};
    850     const char* const crashReportCpy = crashReport;
    851     snprintf(
    852         crashReport, sizeof(crashReport), "%s/%s.%d", run->global->io.workDir, kLOGPREFIX, pid);
    853 
    854     FILE* fReport = fopen(crashReport, "rb");
    855     if (fReport == NULL) {
    856         PLOG_D("Couldn't open '%s' - R/O mode", crashReport);
    857         return -1;
    858     }
    859     defer {
    860         fclose(fReport);
    861     };
    862     defer {
    863         unlink(crashReportCpy);
    864     };
    865 
    866     char header[35] = {0};
    867     snprintf(header, sizeof(header), "==%d==ERROR: AddressSanitizer:", pid);
    868     size_t headerSz = strlen(header);
    869     bool headerFound = false;
    870 
    871     uint8_t frameIdx = 0;
    872     char framePrefix[5] = {0};
    873     snprintf(framePrefix, sizeof(framePrefix), "#%" PRIu8, frameIdx);
    874 
    875     char *lineptr = NULL, *cAddr = NULL;
    876     size_t n = 0;
    877     defer {
    878         free(lineptr);
    879     };
    880     for (;;) {
    881         if (getline(&lineptr, &n, fReport) == -1) {
    882             break;
    883         }
    884 
    885         /* First step is to identify header */
    886         if (!headerFound) {
    887             if ((strlen(lineptr) > headerSz) && (strncmp(header, lineptr, headerSz) == 0)) {
    888                 headerFound = true;
    889 
    890                 /* Parse crash address */
    891                 cAddr = strstr(lineptr, "address 0x");
    892                 if (cAddr) {
    893                     cAddr = cAddr + strlen("address ");
    894                     char* endOff = strchr(cAddr, ' ');
    895                     cAddr[endOff - cAddr] = '\0';
    896                     *crashAddr = (void*)((size_t)strtoull(cAddr, NULL, 16));
    897                 } else {
    898                     *crashAddr = 0x0;
    899                 }
    900             }
    901             continue;
    902         } else {
    903             char* pLineLC = lineptr;
    904             /* Trim leading spaces */
    905             while (*pLineLC != '\0' && isspace(*pLineLC)) {
    906                 ++pLineLC;
    907             }
    908 
    909             /* End separator for crash thread stack trace is an empty line */
    910             if ((*pLineLC == '\0') && (frameIdx != 0)) {
    911                 break;
    912             }
    913 
    914             /* Basic length checks */
    915             if (strlen(pLineLC) < 10) {
    916                 continue;
    917             }
    918 
    919             /* If available parse the type of error (READ/WRITE) */
    920             if (cAddr && strstr(pLineLC, cAddr)) {
    921                 if (strncmp(pLineLC, "READ", 4) == 0) {
    922                     *op = "READ";
    923                 } else if (strncmp(pLineLC, "WRITE", 5) == 0) {
    924                     *op = "WRITE";
    925                 }
    926                 cAddr = NULL;
    927             }
    928 
    929             /* Check for crash thread frames */
    930             if (strncmp(pLineLC, framePrefix, strlen(framePrefix)) == 0) {
    931                 /* Abort if max depth */
    932                 if (frameIdx >= _HF_MAX_FUNCS) {
    933                     break;
    934                 }
    935 
    936                 /*
    937                  * Frames have following format:
    938                  #0 0xaa860177  (/system/lib/libc.so+0x196177)
    939                  */
    940                 char* savePtr = NULL;
    941                 strtok_r(pLineLC, " ", &savePtr);
    942                 funcs[frameIdx].pc =
    943                     (void*)((size_t)strtoull(strtok_r(NULL, " ", &savePtr), NULL, 16));
    944 
    945                 /* DSO & code offset parsing */
    946                 char* targetStr = strtok_r(NULL, " ", &savePtr);
    947                 char* startOff = strchr(targetStr, '(') + 1;
    948                 char* plusOff = strchr(targetStr, '+');
    949                 char* endOff = strrchr(targetStr, ')');
    950                 targetStr[endOff - startOff] = '\0';
    951                 if ((startOff == NULL) || (endOff == NULL) || (plusOff == NULL)) {
    952                     LOG_D("Invalid ASan report entry (%s)", lineptr);
    953                 } else {
    954                     size_t dsoSz =
    955                         MIN(sizeof(funcs[frameIdx].mapName), (size_t)(plusOff - startOff));
    956                     memcpy(funcs[frameIdx].mapName, startOff, dsoSz);
    957                     char* codeOff = targetStr + (plusOff - startOff) + 1;
    958                     funcs[frameIdx].line = strtoull(codeOff, NULL, 16);
    959                 }
    960 
    961                 frameIdx++;
    962                 snprintf(framePrefix, sizeof(framePrefix), "#%" PRIu8, frameIdx);
    963             }
    964         }
    965     }
    966 
    967     return frameIdx;
    968 }
    969 
    970 /*
    971  * Special book keeping for cases where crashes are detected based on exitcode and not
    972  * a raised signal. Such case is the ASan fuzzing for Android. Crash file name maintains
    973  * the same format for compatibility with post campaign tools.
    974  */
    975 static void arch_traceExitSaveData(run_t* run, pid_t pid) {
    976     REG_TYPE pc = 0;
    977     void* crashAddr = 0;
    978     char* op = "UNKNOWN";
    979 
    980     /* Save only the first hit for each worker */
    981     if (run->crashFileName[0] != '\0') {
    982         return;
    983     }
    984 
    985     /* Increase global crashes counter */
    986     ATOMIC_POST_INC(run->global->cnts.crashesCnt);
    987     ATOMIC_POST_AND(run->global->cfg.dynFileIterExpire, _HF_DYNFILE_SUB_MASK);
    988 
    989     /* If sanitizer produces reports with stack traces (e.g. ASan), they're parsed manually */
    990     int funcCnt = 0;
    991     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
    992     defer {
    993         free(funcs);
    994     };
    995     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
    996 
    997     /* Sanitizers save reports against parent PID */
    998     if (run->pid != pid) {
    999         return;
   1000     }
   1001     funcCnt = arch_parseAsanReport(run, pid, funcs, &crashAddr, &op);
   1002 
   1003     /*
   1004      * -1 error indicates a file not found for report. This is expected to happen often since
   1005      * ASan report is generated once for crashing TID. Ptrace arch is not guaranteed to parse
   1006      * that TID first. Not setting the 'crashFileName' variable will ensure that this branch
   1007      * is executed again for all TIDs until the matching report is found
   1008      */
   1009     if (funcCnt == -1) {
   1010         return;
   1011     }
   1012 
   1013     /* Since crash address is available, apply ignoreAddr filters */
   1014     if (crashAddr < run->global->linux.ignoreAddr) {
   1015         LOG_I("Input is interesting, but the crash addr is %p (below %p), skipping", crashAddr,
   1016             run->global->linux.ignoreAddr);
   1017         return;
   1018     }
   1019 
   1020     /* If frames successfully recovered, calculate stack hash & populate crash PC */
   1021     arch_hashCallstack(run, funcs, funcCnt, false);
   1022     pc = (uintptr_t)funcs[0].pc;
   1023 
   1024     /*
   1025      * Check if stackhash is blacklisted
   1026      */
   1027     if (run->global->feedback.blacklist &&
   1028         (fastArray64Search(run->global->feedback.blacklist, run->global->feedback.blacklistCnt,
   1029              run->backtrace) != -1)) {
   1030         LOG_I("Blacklisted stack hash '%" PRIx64 "', skipping", run->backtrace);
   1031         ATOMIC_POST_INC(run->global->cnts.blCrashesCnt);
   1032         return;
   1033     }
   1034 
   1035     /* If dry run mode, copy file with same name into workspace */
   1036     if (run->global->mutate.mutationsPerRun == 0U && run->global->cfg.useVerifier) {
   1037         snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir,
   1038             run->origFileName);
   1039     } else {
   1040         /* Keep the crashes file name format identical */
   1041         if (run->backtrace != 0ULL && run->global->io.saveUnique) {
   1042             snprintf(run->crashFileName, sizeof(run->crashFileName),
   1043                 "%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%s.ADDR.%p.INSTR.%s.%s",
   1044                 run->global->io.crashDir, "SAN", pc, run->backtrace, op, crashAddr, "[UNKNOWN]",
   1045                 run->global->io.fileExtn);
   1046         } else {
   1047             /* If no stack hash available, all crashes treated as unique */
   1048             char localtmstr[PATH_MAX];
   1049             util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
   1050             snprintf(run->crashFileName, sizeof(run->crashFileName),
   1051                 "%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%s.ADDR.%p.INSTR.%s.%s.%s",
   1052                 run->global->io.crashDir, "SAN", pc, run->backtrace, op, crashAddr, "[UNKNOWN]",
   1053                 localtmstr, run->global->io.fileExtn);
   1054         }
   1055     }
   1056 
   1057     int fd = open(run->crashFileName, O_WRONLY | O_EXCL | O_CREAT, 0600);
   1058     if (fd == -1 && errno == EEXIST) {
   1059         LOG_I("It seems that '%s' already exists, skipping", run->crashFileName);
   1060         return;
   1061     } else if (fd == -1) {
   1062         PLOG_E("Cannot create output file '%s'", run->crashFileName);
   1063         return;
   1064     } else {
   1065         defer {
   1066             close(fd);
   1067         };
   1068         if (files_writeToFd(fd, run->dynamicFile, run->dynamicFileSz)) {
   1069             LOG_I("Ok, that's interesting, saved new crash as '%s'", run->crashFileName);
   1070             /* Clear stack hash so that verifier can understand we hit a duplicate */
   1071             run->backtrace = 0ULL;
   1072             /* Increase unique crashes counters */
   1073             ATOMIC_POST_INC(run->global->cnts.uniqueCrashesCnt);
   1074             ATOMIC_CLEAR(run->global->cfg.dynFileIterExpire);
   1075         } else {
   1076             LOG_E("Couldn't save crash to '%s'", run->crashFileName);
   1077             /* In case of write error, clear crashFileName to so that other monitored TIDs can retry
   1078              */
   1079             memset(run->crashFileName, 0, sizeof(run->crashFileName));
   1080             return;
   1081         }
   1082     }
   1083 
   1084     /* Generate report */
   1085     run->report[0] = '\0';
   1086     util_ssnprintf(run->report, sizeof(run->report), "EXIT_CODE: %d\n", HF_SAN_EXIT_CODE);
   1087     util_ssnprintf(run->report, sizeof(run->report), "ORIG_FNAME: %s\n", run->origFileName);
   1088     util_ssnprintf(run->report, sizeof(run->report), "FUZZ_FNAME: %s\n", run->crashFileName);
   1089     util_ssnprintf(run->report, sizeof(run->report), "PID: %d\n", pid);
   1090     util_ssnprintf(run->report, sizeof(run->report), "OPERATION: %s\n", op);
   1091     util_ssnprintf(run->report, sizeof(run->report), "FAULT ADDRESS: %p\n", crashAddr);
   1092     if (funcCnt > 0) {
   1093         util_ssnprintf(
   1094             run->report, sizeof(run->report), "STACK HASH: %016" PRIx64 "\n", run->backtrace);
   1095         util_ssnprintf(run->report, sizeof(run->report), "STACK:\n");
   1096         for (int i = 0; i < funcCnt; i++) {
   1097             util_ssnprintf(run->report, sizeof(run->report), " <" REG_PD REG_PM "> ",
   1098                 (REG_TYPE)(long)funcs[i].pc);
   1099             if (funcs[i].mapName[0] != '\0') {
   1100                 util_ssnprintf(run->report, sizeof(run->report), "[%s + 0x%zx]\n", funcs[i].mapName,
   1101                     funcs[i].line);
   1102             } else {
   1103                 util_ssnprintf(run->report, sizeof(run->report), "[]\n");
   1104             }
   1105         }
   1106     }
   1107 }
   1108 
   1109 static void arch_traceExitAnalyzeData(run_t* run, pid_t pid) {
   1110     void* crashAddr = 0;
   1111     char* op = "UNKNOWN";
   1112     int funcCnt = 0;
   1113     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
   1114     defer {
   1115         free(funcs);
   1116     };
   1117     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
   1118 
   1119     funcCnt = arch_parseAsanReport(run, pid, funcs, &crashAddr, &op);
   1120 
   1121     /*
   1122      * -1 error indicates a file not found for report. This is expected to happen often since
   1123      * ASan report is generated once for crashing TID. Ptrace arch is not guaranteed to parse
   1124      * that TID first. Not setting the 'crashFileName' variable will ensure that this branch
   1125      * is executed again for all TIDs until the matching report is found
   1126      */
   1127     if (funcCnt == -1) {
   1128         return;
   1129     }
   1130 
   1131     /* If frames successfully recovered, calculate stack hash & populate crash PC */
   1132     arch_hashCallstack(run, funcs, funcCnt, false);
   1133 }
   1134 
   1135 void arch_traceExitAnalyze(run_t* run, pid_t pid) {
   1136     if (run->mainWorker) {
   1137         /* Main fuzzing threads */
   1138         arch_traceExitSaveData(run, pid);
   1139     } else {
   1140         /* Post crash analysis (e.g. crashes verifier) */
   1141         arch_traceExitAnalyzeData(run, pid);
   1142     }
   1143 }
   1144 
   1145 #define __WEVENT(status) ((status & 0xFF0000) >> 16)
   1146 static void arch_traceEvent(run_t* run, int status, pid_t pid) {
   1147     LOG_D("PID: %d, Ptrace event: %d", pid, __WEVENT(status));
   1148     switch (__WEVENT(status)) {
   1149         case PTRACE_EVENT_EXIT: {
   1150             unsigned long event_msg;
   1151             if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &event_msg) == -1) {
   1152                 PLOG_E("ptrace(PTRACE_GETEVENTMSG,%d) failed", pid);
   1153                 return;
   1154             }
   1155 
   1156             if (WIFEXITED(event_msg)) {
   1157                 LOG_D("PID: %d exited with exit_code: %lu", pid,
   1158                     (unsigned long)WEXITSTATUS(event_msg));
   1159                 if (WEXITSTATUS(event_msg) == (unsigned long)HF_SAN_EXIT_CODE) {
   1160                     arch_traceExitAnalyze(run, pid);
   1161                 }
   1162             } else if (WIFSIGNALED(event_msg)) {
   1163                 LOG_D(
   1164                     "PID: %d terminated with signal: %lu", pid, (unsigned long)WTERMSIG(event_msg));
   1165             } else {
   1166                 LOG_D("PID: %d exited with unknown status: %lu", pid, event_msg);
   1167             }
   1168         } break;
   1169         default:
   1170             break;
   1171     }
   1172 
   1173     ptrace(PTRACE_CONT, pid, 0, 0);
   1174 }
   1175 
   1176 void arch_traceAnalyze(run_t* run, int status, pid_t pid) {
   1177     /*
   1178      * It's a ptrace event, deal with it elsewhere
   1179      */
   1180     if (WIFSTOPPED(status) && __WEVENT(status)) {
   1181         return arch_traceEvent(run, status, pid);
   1182     }
   1183 
   1184     if (WIFSTOPPED(status)) {
   1185         /*
   1186          * If it's an interesting signal, save the testcase
   1187          */
   1188         if (arch_sigs[WSTOPSIG(status)].important) {
   1189             /*
   1190              * If fuzzer worker is from core fuzzing process run full
   1191              * analysis. Otherwise just unwind and get stack hash signature.
   1192              */
   1193             if (run->mainWorker) {
   1194                 arch_traceSaveData(run, pid);
   1195             } else {
   1196                 arch_traceAnalyzeData(run, pid);
   1197             }
   1198         }
   1199         /* Do not deliver SIGSTOP, as we don't support PTRACE_LISTEN anyway */
   1200         int sig = (WSTOPSIG(status) != SIGSTOP) ? WSTOPSIG(status) : 0;
   1201         ptrace(PTRACE_CONT, pid, 0, sig);
   1202         return;
   1203     }
   1204 
   1205     /*
   1206      * Resumed by delivery of SIGCONT
   1207      */
   1208     if (WIFCONTINUED(status)) {
   1209         return;
   1210     }
   1211 
   1212     /*
   1213      * Process exited
   1214      */
   1215     if (WIFEXITED(status)) {
   1216         /*
   1217          * Target exited with sanitizer defined exitcode (used when SIGABRT is not monitored)
   1218          */
   1219         if (WEXITSTATUS(status) == (unsigned long)HF_SAN_EXIT_CODE) {
   1220             arch_traceExitAnalyze(run, pid);
   1221         }
   1222         return;
   1223     }
   1224 
   1225     if (WIFSIGNALED(status)) {
   1226         return;
   1227     }
   1228 
   1229     abort(); /* NOTREACHED */
   1230 }
   1231 
   1232 static bool arch_listThreads(int tasks[], size_t thrSz, int pid) {
   1233     char path[512];
   1234     snprintf(path, sizeof(path), "/proc/%d/task", pid);
   1235 
   1236     /* An optimization, the number of threads is st.st_nlink - 2 (. and ..) */
   1237     struct stat st;
   1238     if (stat(path, &st) != -1) {
   1239         if (st.st_nlink == 3) {
   1240             tasks[0] = pid;
   1241             tasks[1] = 0;
   1242             return true;
   1243         }
   1244     }
   1245 
   1246     size_t count = 0;
   1247     DIR* dir = opendir(path);
   1248     if (!dir) {
   1249         PLOG_E("Couldn't open dir '%s'", path);
   1250         return false;
   1251     }
   1252     defer {
   1253         closedir(dir);
   1254     };
   1255 
   1256     for (;;) {
   1257         errno = 0;
   1258         const struct dirent* res = readdir(dir);
   1259         if (res == NULL && errno != 0) {
   1260             PLOG_E("Couldn't read contents of '%s'", path);
   1261             return false;
   1262         }
   1263 
   1264         if (res == NULL) {
   1265             break;
   1266         }
   1267 
   1268         pid_t pid = (pid_t)strtol(res->d_name, (char**)NULL, 10);
   1269         if (pid == 0) {
   1270             LOG_D("The following dir entry couldn't be converted to pid_t '%s'", res->d_name);
   1271             continue;
   1272         }
   1273 
   1274         tasks[count++] = pid;
   1275         LOG_D("Added pid '%d' from '%s/%s'", pid, path, res->d_name);
   1276 
   1277         if (count >= thrSz) {
   1278             break;
   1279         }
   1280     }
   1281     PLOG_D("Total number of threads in pid '%d': '%zd'", pid, count);
   1282     tasks[count + 1] = 0;
   1283     if (count < 1) {
   1284         return false;
   1285     }
   1286     return true;
   1287 }
   1288 
   1289 bool arch_traceWaitForPidStop(pid_t pid) {
   1290     for (;;) {
   1291         int status;
   1292         pid_t ret = wait4(pid, &status, __WALL | WUNTRACED, NULL);
   1293         if (ret == -1 && errno == EINTR) {
   1294             continue;
   1295         }
   1296         if (ret == -1) {
   1297             PLOG_W("wait4(pid=%d) failed", pid);
   1298             return false;
   1299         }
   1300         if (!WIFSTOPPED(status)) {
   1301             LOG_W("PID %d not in a stopped state - status:%d", pid, status);
   1302             return false;
   1303         }
   1304         return true;
   1305     }
   1306 }
   1307 
   1308 #define MAX_THREAD_IN_TASK 4096
   1309 bool arch_traceAttach(run_t* run) {
   1310 /*
   1311  * It should be present since, at least, Linux kernel 3.8, but
   1312  * not always defined in kernel-headers
   1313  */
   1314 #if !defined(PTRACE_O_EXITKILL)
   1315 #define PTRACE_O_EXITKILL (1 << 20)
   1316 #endif /* !defined(PTRACE_O_EXITKILL) */
   1317     long seize_options =
   1318         PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_EXITKILL;
   1319     /* The event is only used with sanitizers */
   1320     if (run->global->sanitizer.enable) {
   1321         seize_options |= PTRACE_O_TRACEEXIT;
   1322     }
   1323 
   1324     if (!arch_traceWaitForPidStop(run->pid)) {
   1325         return false;
   1326     }
   1327 
   1328     if (ptrace(PTRACE_SEIZE, run->pid, NULL, seize_options) == -1) {
   1329         PLOG_W("Couldn't ptrace(PTRACE_SEIZE) to pid: %d", (int)run->pid);
   1330         return false;
   1331     }
   1332 
   1333     LOG_D("Attached to PID: %d", (int)run->pid);
   1334 
   1335     int tasks[MAX_THREAD_IN_TASK + 1] = {0};
   1336     if (!arch_listThreads(tasks, MAX_THREAD_IN_TASK, run->pid)) {
   1337         LOG_E("Couldn't read thread list for pid '%d'", run->pid);
   1338         return false;
   1339     }
   1340 
   1341     for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
   1342         if (tasks[i] == run->pid) {
   1343             continue;
   1344         }
   1345         if (ptrace(PTRACE_SEIZE, tasks[i], NULL, seize_options) == -1) {
   1346             PLOG_W("Couldn't ptrace(PTRACE_SEIZE) to pid: %d", tasks[i]);
   1347             continue;
   1348         }
   1349         LOG_D("Attached to PID: %d (thread_group:%d)", tasks[i], run->pid);
   1350     }
   1351 
   1352     if (ptrace(PTRACE_CONT, run->pid, NULL, NULL) == -1) {
   1353         PLOG_W("ptrace(PTRACE_CONT) to pid: %d", (int)run->pid);
   1354     }
   1355 
   1356     return true;
   1357 }
   1358 
   1359 void arch_traceDetach(pid_t pid) {
   1360     if (syscall(__NR_kill, pid, 0) == -1 && errno == ESRCH) {
   1361         LOG_D("PID: %d no longer exists", pid);
   1362         return;
   1363     }
   1364 
   1365     int tasks[MAX_THREAD_IN_TASK + 1] = {0};
   1366     if (!arch_listThreads(tasks, MAX_THREAD_IN_TASK, pid)) {
   1367         LOG_E("Couldn't read thread list for pid '%d'", pid);
   1368         return;
   1369     }
   1370 
   1371     for (int i = 0; i < MAX_THREAD_IN_TASK && tasks[i]; i++) {
   1372         ptrace(PTRACE_INTERRUPT, tasks[i], NULL, NULL);
   1373         arch_traceWaitForPidStop(tasks[i]);
   1374         ptrace(PTRACE_DETACH, tasks[i], NULL, NULL);
   1375     }
   1376 }
   1377 
   1378 void arch_traceSignalsInit(honggfuzz_t* hfuzz) {
   1379     /* Default is true for all platforms except Android */
   1380     arch_sigs[SIGABRT].important = hfuzz->cfg.monitorSIGABRT;
   1381 
   1382     /* Default is false */
   1383     arch_sigs[SIGVTALRM].important = hfuzz->timing.tmoutVTALRM;
   1384 }
   1385