"Fossies" - the Fresh Open Source Software Archive

Member "honggfuzz-2.2/netbsd/trace.c" (23 Apr 2020, 20326 Bytes) of package /linux/privat/honggfuzz-2.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "trace.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.1_vs_2.2.

    1 /*
    2  *
    3  * honggfuzz - architecture dependent code (NETBSD/PTRACE)
    4  * -----------------------------------------
    5  *
    6  * Author: Kamil Rytarowski <n54@gmx.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 "netbsd/trace.h"
   25 
   26 // clang-format off
   27 #include <sys/param.h>
   28 #include <sys/types.h>
   29 // clang-format on
   30 
   31 #include <sys/ptrace.h>
   32 #include <sys/resource.h>
   33 #include <sys/stat.h>
   34 #include <sys/syscall.h>
   35 #include <sys/time.h>
   36 #include <sys/types.h>
   37 #include <sys/uio.h>
   38 #include <sys/wait.h>
   39 
   40 #include <ctype.h>
   41 #include <dirent.h>
   42 #include <elf.h>
   43 #include <endian.h>
   44 #include <errno.h>
   45 #include <fcntl.h>
   46 #include <inttypes.h>
   47 #include <signal.h>
   48 #include <stdio.h>
   49 #include <stdlib.h>
   50 #include <string.h>
   51 #include <time.h>
   52 #include <unistd.h>
   53 
   54 #include "libhfcommon/common.h"
   55 #include "libhfcommon/files.h"
   56 #include "libhfcommon/log.h"
   57 #include "libhfcommon/util.h"
   58 #include "netbsd/unwind.h"
   59 #include "report.h"
   60 #include "sanitizers.h"
   61 #include "subproc.h"
   62 
   63 #include <capstone/capstone.h>
   64 
   65 /*
   66  * Size in characters required to store a string representation of a
   67  * register value (0xdeadbeef style))
   68  */
   69 #define REGSIZEINCHAR (2 * sizeof(register_t) + 3)
   70 
   71 #define _HF_INSTR_SZ 64
   72 
   73 #if defined(__i386__) || defined(__x86_64__)
   74 #define MAX_INSTR_SZ 16
   75 #elif defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)
   76 #define MAX_INSTR_SZ 4
   77 #elif defined(__aarch64__)
   78 #define MAX_INSTR_SZ 8
   79 #elif defined(__mips__) || defined(__mips64__)
   80 #define MAX_INSTR_SZ 8
   81 #endif
   82 
   83 static struct {
   84     const char* descr;
   85     bool important;
   86 } arch_sigs[_NSIG + 1] = {
   87     [0 ...(_NSIG)].important = false,
   88     [0 ...(_NSIG)].descr = "UNKNOWN",
   89 
   90     [SIGTRAP].important = false,
   91     [SIGTRAP].descr = "SIGTRAP",
   92 
   93     [SIGILL].important = true,
   94     [SIGILL].descr = "SIGILL",
   95 
   96     [SIGFPE].important = true,
   97     [SIGFPE].descr = "SIGFPE",
   98 
   99     [SIGSEGV].important = true,
  100     [SIGSEGV].descr = "SIGSEGV",
  101 
  102     [SIGBUS].important = true,
  103     [SIGBUS].descr = "SIGBUS",
  104 
  105     [SIGABRT].important = true,
  106     [SIGABRT].descr = "SIGABRT",
  107 
  108     /* Is affected from tmoutVTALRM flag */
  109     [SIGVTALRM].important = false,
  110     [SIGVTALRM].descr = "SIGVTALRM-TMOUT",
  111 
  112     /* seccomp-bpf kill */
  113     [SIGSYS].important = true,
  114     [SIGSYS].descr = "SIGSYS",
  115 };
  116 
  117 #ifndef SI_FROMUSER
  118 #define SI_FROMUSER(siptr) ((siptr)->si_code == SI_USER)
  119 #endif /* SI_FROMUSER */
  120 
  121 static size_t arch_getProcMem(pid_t pid, uint8_t* buf, size_t len, register_t pc) {
  122     struct ptrace_io_desc io;
  123     size_t bytes_read;
  124 
  125     bytes_read = 0;
  126     io.piod_op = PIOD_READ_D;
  127     io.piod_len = len;
  128 
  129     do {
  130         io.piod_offs = (void*)(pc + bytes_read);
  131         io.piod_addr = buf + bytes_read;
  132 
  133         if (ptrace(PT_IO, pid, &io, 0) == -1) {
  134             PLOG_W("Couldn't read process memory on pid %d, "
  135                    "piod_op: %d offs: %p addr: %p piod_len: %zu",
  136                 pid, io.piod_op, io.piod_offs, io.piod_addr, io.piod_len);
  137             break;
  138         }
  139 
  140         bytes_read = io.piod_len;
  141         io.piod_len = len - bytes_read;
  142     } while (bytes_read < len);
  143 
  144     return bytes_read;
  145 }
  146 
  147 static size_t arch_getPC(
  148     pid_t pid, lwpid_t lwp, register_t* pc, register_t* status_reg HF_ATTR_UNUSED) {
  149     struct reg r;
  150 
  151     if (ptrace(PT_GETREGS, pid, &r, lwp) != 0) {
  152         PLOG_D("ptrace(PT_GETREGS) failed");
  153         return 0;
  154     }
  155     *pc = PTRACE_REG_PC(&r);
  156 #if defined(__i386__)
  157     *status_reg = r.regs[_REG_EFLAGS];
  158 #elif defined(__x86_64__)
  159     *status_reg = r.regs[_REG_RFLAGS];
  160 #else
  161 #error unsupported CPU architecture
  162 #endif
  163 
  164     return sizeof(r);
  165 }
  166 
  167 static void arch_getInstrStr(pid_t pid, lwpid_t lwp, register_t* pc, char* instr) {
  168     /*
  169      * We need a value aligned to 8
  170      * which is sizeof(long) on 64bit CPU archs (on most of them, I hope;)
  171      */
  172     uint8_t buf[MAX_INSTR_SZ];
  173     size_t memsz;
  174     register_t status_reg = 0;
  175 
  176     snprintf(instr, _HF_INSTR_SZ, "%s", "[UNKNOWN]");
  177 
  178     size_t pcRegSz = arch_getPC(pid, lwp, pc, &status_reg);
  179     if (!pcRegSz) {
  180         LOG_W("Current architecture not supported for disassembly");
  181         return;
  182     }
  183 
  184     if ((memsz = arch_getProcMem(pid, buf, sizeof(buf), *pc)) == 0) {
  185         snprintf(instr, _HF_INSTR_SZ, "%s", "[NOT_MMAPED]");
  186         return;
  187     }
  188 
  189     cs_arch arch;
  190     cs_mode mode;
  191 
  192 #if defined(__i386__)
  193     arch = CS_ARCH_X86;
  194     mode = CS_MODE_32;
  195 #elif defined(__x86_64__)
  196     arch = CS_ARCH_X86;
  197     mode = CS_MODE_64;
  198 #else
  199 #error Unsupported CPU architecture
  200 #endif
  201 
  202     csh handle;
  203     cs_err err = cs_open(arch, mode, &handle);
  204     if (err != CS_ERR_OK) {
  205         LOG_W("Capstone initialization failed: '%s'", cs_strerror(err));
  206         return;
  207     }
  208 
  209     cs_insn* insn;
  210     size_t count = cs_disasm(handle, buf, sizeof(buf), *pc, 0, &insn);
  211 
  212     if (count < 1) {
  213         LOG_W("Couldn't disassemble the assembler instructions' stream: '%s'",
  214             cs_strerror(cs_errno(handle)));
  215         cs_close(&handle);
  216         return;
  217     }
  218 
  219     snprintf(instr, _HF_INSTR_SZ, "%s %s", insn[0].mnemonic, insn[0].op_str);
  220     cs_free(insn, count);
  221     cs_close(&handle);
  222 
  223     for (int x = 0; instr[x] && x < _HF_INSTR_SZ; x++) {
  224         if (instr[x] == '/' || instr[x] == '\\' || isspace((unsigned char)instr[x]) ||
  225             !isprint((unsigned char)instr[x])) {
  226             instr[x] = '_';
  227         }
  228     }
  229 
  230     return;
  231 }
  232 
  233 static void arch_traceAnalyzeData(run_t* run, pid_t pid) {
  234     ptrace_siginfo_t info;
  235     register_t pc = 0, status_reg = 0;
  236 
  237     if (ptrace(PT_GET_SIGINFO, pid, &info, sizeof(info)) == -1) {
  238         PLOG_W("Couldn't get siginfo for pid %d", pid);
  239     }
  240 
  241     size_t pcRegSz = arch_getPC(pid, info.psi_lwpid, &pc, &status_reg);
  242     if (!pcRegSz) {
  243         LOG_W("ptrace arch_getPC failed");
  244         return;
  245     }
  246 
  247     /*
  248      * Unwind and resolve symbols
  249      */
  250     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
  251     defer {
  252         free(funcs);
  253     };
  254     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
  255 
  256     size_t funcCnt = 0;
  257 
  258     /*
  259      * Use PC from ptrace GETREGS if not zero.
  260      * If PC reg zero return and callers should handle zero hash case.
  261      */
  262     if (pc) {
  263         /* Manually update major frame PC & frames counter */
  264         funcs[0].pc = (void*)(uintptr_t)pc;
  265         funcCnt = 1;
  266     } else {
  267         return;
  268     }
  269 
  270     /*
  271      * Calculate backtrace callstack hash signature
  272      */
  273     run->backtrace = sanitizers_hashCallstack(run, funcs, funcCnt, false);
  274 }
  275 
  276 static void arch_traceSaveData(run_t* run, pid_t pid) {
  277     register_t pc = 0;
  278 
  279     /* Local copy since flag is overridden for some crashes */
  280     bool saveUnique = run->global->io.saveUnique;
  281 
  282     char instr[_HF_INSTR_SZ] = "\x00";
  283     struct ptrace_siginfo info;
  284     memset(&info, 0, sizeof(info));
  285 
  286     if (ptrace(PT_GET_SIGINFO, pid, &info, sizeof(info)) == -1) {
  287         PLOG_W("Couldn't get siginfo for pid %d", pid);
  288     }
  289 
  290     arch_getInstrStr(pid, info.psi_lwpid, &pc, instr);
  291 
  292     LOG_D("Pid: %d, signo: %d, errno: %d, code: %d, addr: %p, pc: %" PRIxREGISTER ", instr: '%s'",
  293         pid, info.psi_siginfo.si_signo, info.psi_siginfo.si_errno, info.psi_siginfo.si_code,
  294         info.psi_siginfo.si_addr, pc, instr);
  295 
  296     if (!SI_FROMUSER(&info.psi_siginfo) && pc &&
  297         info.psi_siginfo.si_addr < run->global->arch_netbsd.ignoreAddr) {
  298         LOG_I("Input is interesting (%s), but the si.si_addr is %p (below %p), skipping",
  299             util_sigName(info.psi_siginfo.si_signo), info.psi_siginfo.si_addr,
  300             run->global->arch_netbsd.ignoreAddr);
  301         return;
  302     }
  303 
  304     /*
  305      * Unwind and resolve symbols
  306      */
  307     funcs_t* funcs = util_Malloc(_HF_MAX_FUNCS * sizeof(funcs_t));
  308     defer {
  309         free(funcs);
  310     };
  311     memset(funcs, 0, _HF_MAX_FUNCS * sizeof(funcs_t));
  312 
  313     size_t funcCnt = 0;
  314 
  315     /*
  316      * Use PC from ptrace GETREGS if not zero.
  317      * If PC reg zero, temporarily disable uniqueness flag since callstack
  318      * hash will be also zero, thus not safe for unique decisions.
  319      */
  320     if (pc) {
  321         /* Manually update major frame PC & frames counter */
  322         funcs[0].pc = (void*)(uintptr_t)pc;
  323         funcCnt = 1;
  324     } else {
  325         saveUnique = false;
  326     }
  327 
  328     /*
  329      * Temp local copy of previous backtrace value in case worker hit crashes into multiple
  330      * tids for same target master thread. Will be 0 for first crash against target.
  331      */
  332     uint64_t oldBacktrace = run->backtrace;
  333 
  334     /*
  335      * Calculate backtrace callstack hash signature
  336      */
  337     run->backtrace = sanitizers_hashCallstack(run, funcs, funcCnt, saveUnique);
  338 
  339     /*
  340      * If unique flag is set and single frame crash, disable uniqueness for this crash
  341      * to always save (timestamp will be added to the filename)
  342      */
  343     if (saveUnique && (funcCnt == 1)) {
  344         saveUnique = false;
  345     }
  346 
  347     /*
  348      * If worker crashFileName member is set, it means that a tid has already crashed
  349      * from target master thread.
  350      */
  351     if (run->crashFileName[0] != '\0') {
  352         LOG_D("Multiple crashes detected from worker against attached tids group");
  353 
  354         /*
  355          * If stackhashes match, don't re-analyze. This will avoid duplicates
  356          * and prevent verifier from running multiple passes. Depth of check is
  357          * always 1 (last backtrace saved only per target iteration).
  358          */
  359         if (oldBacktrace == run->backtrace) {
  360             return;
  361         }
  362     }
  363 
  364     /* Increase global crashes counter */
  365     ATOMIC_POST_INC(run->global->cnts.crashesCnt);
  366 
  367     /*
  368      * Check if backtrace contains whitelisted symbol. Whitelist overrides
  369      * both stackhash and symbol blacklist. Crash is always kept regardless
  370      * of the status of uniqueness flag.
  371      */
  372     if (run->global->arch_netbsd.symsWl) {
  373         char* wlSymbol = arch_btContainsSymbol(
  374             run->global->arch_netbsd.symsWlCnt, run->global->arch_netbsd.symsWl, funcCnt, funcs);
  375         if (wlSymbol != NULL) {
  376             saveUnique = false;
  377             LOG_D("Whitelisted symbol '%s' found, skipping blacklist checks", wlSymbol);
  378         }
  379     } else {
  380         /*
  381          * Check if stackhash is blacklisted
  382          */
  383         if (run->global->feedback.blacklist &&
  384             (fastArray64Search(run->global->feedback.blacklist, run->global->feedback.blacklistCnt,
  385                  run->backtrace) != -1)) {
  386             LOG_I("Blacklisted stack hash '%" PRIx64 "', skipping", run->backtrace);
  387             ATOMIC_POST_INC(run->global->cnts.blCrashesCnt);
  388             return;
  389         }
  390 
  391         /*
  392          * Check if backtrace contains blacklisted symbol
  393          */
  394         char* blSymbol = arch_btContainsSymbol(
  395             run->global->arch_netbsd.symsBlCnt, run->global->arch_netbsd.symsBl, funcCnt, funcs);
  396         if (blSymbol != NULL) {
  397             LOG_I("Blacklisted symbol '%s' found, skipping", blSymbol);
  398             ATOMIC_POST_INC(run->global->cnts.blCrashesCnt);
  399             return;
  400         }
  401     }
  402 
  403     /* If non-blacklisted crash detected, zero set two MSB */
  404     ATOMIC_POST_ADD(run->global->cfg.dynFileIterExpire, _HF_DYNFILE_SUB_MASK);
  405 
  406     void* sig_addr = info.psi_siginfo.si_addr;
  407     pc = 0UL;
  408     sig_addr = NULL;
  409 
  410     /* User-induced signals don't set si.si_addr */
  411     if (SI_FROMUSER(&info.psi_siginfo)) {
  412         sig_addr = NULL;
  413     }
  414 
  415     /* If dry run mode, copy file with same name into workspace */
  416     if (run->global->mutate.mutationsPerRun == 0U && run->global->cfg.useVerifier) {
  417         snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir,
  418             run->dynfile->path);
  419     } else if (saveUnique) {
  420         snprintf(run->crashFileName, sizeof(run->crashFileName),
  421             "%s/%s.PC.%" PRIxREGISTER ".STACK.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s",
  422             run->global->io.crashDir, util_sigName(info.psi_siginfo.si_signo), pc, run->backtrace,
  423             info.psi_siginfo.si_code, sig_addr, instr, run->global->io.fileExtn);
  424     } else {
  425         char localtmstr[PATH_MAX];
  426         util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
  427         snprintf(run->crashFileName, sizeof(run->crashFileName),
  428             "%s/%s.PC.%" PRIxREGISTER ".STACK.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s",
  429             run->global->io.crashDir, util_sigName(info.psi_siginfo.si_signo), pc, run->backtrace,
  430             info.psi_siginfo.si_code, sig_addr, instr, localtmstr, pid, run->global->io.fileExtn);
  431     }
  432 
  433     if (files_exists(run->crashFileName)) {
  434         LOG_I("Crash (dup): '%s' already exists, skipping", run->crashFileName);
  435         // Clear filename so that verifier can understand we hit a duplicate
  436         memset(run->crashFileName, 0, sizeof(run->crashFileName));
  437         return;
  438     }
  439 
  440     if (!files_writeBufToFile(run->crashFileName, run->dynfile->data, run->dynfile->size,
  441             O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC)) {
  442         LOG_E("Couldn't write to '%s'", run->crashFileName);
  443         return;
  444     }
  445 
  446     LOG_I("Crash: saved as '%s'", run->crashFileName);
  447 
  448     ATOMIC_POST_INC(run->global->cnts.uniqueCrashesCnt);
  449     /* If unique crash found, reset dynFile counter */
  450     ATOMIC_CLEAR(run->global->cfg.dynFileIterExpire);
  451 
  452     report_appendReport(pid, run, funcs, funcCnt, pc, (uint64_t)info.psi_siginfo.si_addr,
  453         info.psi_siginfo.si_signo, instr, "");
  454 }
  455 
  456 static void arch_traceEvent(run_t* run HF_ATTR_UNUSED, pid_t pid) {
  457     ptrace_state_t state;
  458     ptrace_siginfo_t info;
  459     int sig = 0;
  460 
  461     if (ptrace(PT_GET_SIGINFO, pid, &info, sizeof(info)) == -1) {
  462         PLOG_E("ptrace(PT_GET_SIGINFO, pid=%d)", (int)pid);
  463     } else {
  464         switch (info.psi_siginfo.si_code) {
  465             case TRAP_BRKPT:
  466                 /* Software breakpoint trap, pass it over to tracee */
  467                 sig = SIGTRAP;
  468                 LOG_D("PID: %d breakpoint software trap (TRAP_BRKPT)", pid);
  469                 break;
  470             case TRAP_TRACE:
  471                 /* Single step unused */
  472                 LOG_E("PID: %d unexpected single step trace trap (TRAP_TRACE)", pid);
  473                 break;
  474             case TRAP_EXEC:
  475                 /* exec(3) trap, ignore */
  476                 LOG_D("PID: %d breakpoint software trap (TRAP_EXEC)", pid);
  477                 break;
  478             case TRAP_CHLD:
  479             case TRAP_LWP:
  480                 /* Child/LWP trap, ignore */
  481                 if (ptrace(PT_GET_PROCESS_STATE, pid, &state, sizeof(state)) != -1) {
  482                     switch (state.pe_report_event) {
  483                         case PTRACE_FORK:
  484                             LOG_D("PID: %d child trap (TRAP_CHLD) : fork", (int)pid);
  485                             break;
  486                         case PTRACE_VFORK:
  487                             LOG_D("PID: %d child trap (TRAP_CHLD) : vfork", (int)pid);
  488                             break;
  489                         case PTRACE_VFORK_DONE:
  490                             LOG_D("PID: %d child trap (TRAP_CHLD) : vfork (PTRACE_VFORK_DONE)",
  491                                 (int)pid);
  492                             break;
  493                         case PTRACE_LWP_CREATE:
  494                             LOG_E("PID: %d unexpected lwp trap (TRAP_LWP) : create "
  495                                   "(PTRACE_LWP_CREATE)",
  496                                 (int)pid);
  497                             break;
  498                         case PTRACE_LWP_EXIT:
  499                             LOG_E("PID: %d unexpected lwp trap (TRAP_LWP) : exit (PTRACE_LWP_EXIT)",
  500                                 (int)pid);
  501                             break;
  502                         default:
  503                             LOG_D("PID: %d unknown child/lwp trap (TRAP_LWP/TRAP_CHLD) : unknown "
  504                                   "pe_report_event=%d",
  505                                 (int)pid, state.pe_report_event);
  506                             break;
  507                     }
  508                 }
  509                 break;
  510             case TRAP_DBREG:
  511                 /* Debug Register trap unused */
  512                 LOG_E("PID: %d unexpected debug register trap (TRAP_DBREG)", pid);
  513                 break;
  514             case TRAP_SCE:
  515                 /* Syscall Enter trap unused */
  516                 LOG_E("PID: %d unexpected syscall enter trap (TRAP_SCE)", pid);
  517                 break;
  518             case TRAP_SCX:
  519                 /* Syscall Exit trap unused */
  520                 LOG_E("PID: %d unexpected syscall exit trap (TRAP_SCX)", pid);
  521                 break;
  522             default:
  523                 /* Other trap, pass it over to tracee */
  524                 sig = SIGTRAP;
  525                 LOG_D("PID: %d other trap si_code=%d", pid, info.psi_siginfo.si_code);
  526                 break;
  527         }
  528     }
  529 
  530     ptrace(PT_CONTINUE, pid, (void*)1, sig);
  531 }
  532 
  533 void arch_traceAnalyze(run_t* run, int status, pid_t pid) {
  534     /*
  535      * It's a ptrace event, deal with it elsewhere
  536      */
  537     if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
  538         return arch_traceEvent(run, pid);
  539     }
  540 
  541     if (WIFSTOPPED(status)) {
  542         /*
  543          * If it's an interesting signal, save the testcase
  544          */
  545         if (arch_sigs[WSTOPSIG(status)].important) {
  546             /*
  547              * If fuzzer worker is from core fuzzing process run full
  548              * analysis. Otherwise just unwind and get stack hash signature.
  549              */
  550             if (run->mainWorker) {
  551                 arch_traceSaveData(run, pid);
  552             } else {
  553                 arch_traceAnalyzeData(run, pid);
  554             }
  555         }
  556         /* Do not deliver SIGSTOP */
  557         int sig = (WSTOPSIG(status) != SIGSTOP) ? WSTOPSIG(status) : 0;
  558         ptrace(PT_CONTINUE, pid, (void*)1, sig);
  559         return;
  560     }
  561 
  562     /*
  563      * Resumed by delivery of SIGCONT
  564      */
  565     if (WIFCONTINUED(status)) {
  566         return;
  567     }
  568 
  569     /*
  570      * Process exited
  571      */
  572     if (WIFEXITED(status)) {
  573         return;
  574     }
  575 
  576     if (WIFSIGNALED(status)) {
  577         return;
  578     }
  579 
  580     abort(); /* NOTREACHED */
  581 }
  582 
  583 bool arch_traceWaitForPidStop(pid_t pid) {
  584     LOG_D("Waiting for pid=%d to stop", (int)pid);
  585 
  586     for (;;) {
  587         int status;
  588         pid_t ret = wait4(pid, &status, __WALL | WUNTRACED | WTRAPPED, NULL);
  589         if (ret == -1 && errno == EINTR) {
  590             continue;
  591         }
  592         if (ret == -1) {
  593             PLOG_W("wait4(pid=%d) failed", pid);
  594             return false;
  595         }
  596         if (!WIFSTOPPED(status)) {
  597             LOG_W("PID %d not in a stopped state - status:%d", pid, status);
  598             return false;
  599         }
  600 
  601         LOG_D("pid=%d stopped", (int)pid);
  602         return true;
  603     }
  604 }
  605 
  606 bool arch_traceAttach(run_t* run) {
  607     if (!arch_traceWaitForPidStop(run->pid)) {
  608         return false;
  609     }
  610     if (ptrace(PT_ATTACH, run->pid, NULL, 0) == -1) {
  611         PLOG_W("Couldn't ptrace(PT_ATTACH) to pid: %d", (int)run->pid);
  612         return false;
  613     }
  614     if (!arch_traceWaitForPidStop(run->pid)) {
  615         return false;
  616     }
  617 
  618     ptrace_event_t event = {
  619         /*
  620          * NetBSD 8.0 seems to support PTRACE_FORK only:
  621          *          .pe_set_event = PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE,
  622          */
  623         .pe_set_event = PTRACE_FORK,
  624     };
  625     if (ptrace(PT_SET_EVENT_MASK, run->pid, &event, sizeof(event)) == -1) {
  626         PLOG_W("Couldn't ptrace(PT_SET_EVENT_MASK) to pid: %d", (int)run->pid);
  627         return false;
  628     }
  629 
  630     LOG_D("Attached to PID: %d", run->pid);
  631 
  632     if (ptrace(PT_CONTINUE, run->pid, (void*)1, 0) == -1) {
  633         PLOG_W("Couldn't ptrace(PT_CONTINUE) to pid: (int)%d", run->pid);
  634         return false;
  635     }
  636 
  637     return true;
  638 }
  639 
  640 void arch_traceDetach(pid_t pid) {
  641     if (ptrace(PT_DETACH, pid, NULL, 0) == -1) {
  642         PLOG_E("PID: %d ptrace(PT_DETACH) failed", pid);
  643     }
  644 }
  645 
  646 void arch_traceSignalsInit(honggfuzz_t* hfuzz) {
  647     /* Default is false */
  648     arch_sigs[SIGVTALRM].important = hfuzz->timing.tmoutVTALRM;
  649 }