Distinct directories for each architecture
diff --git a/Makefile b/Makefile
index cef0769..ecfa274 100644
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,7 @@
 
 OS ?= $(shell uname -s)
 
-ARCH_SRCS := arch_posix.c
+ARCH_SRCS := $(wildcard posix/*.c)
 
 ifeq ($(OS),Linux)
 	ifeq ("$(wildcard /usr/include/capstone/capstone.h)","")
@@ -46,7 +46,7 @@
 		WARN_CAPSTONE =
 	endif
 	LDFLAGS += -lcapstone -lunwind-ptrace -lunwind-generic -lbfd
-	ARCH_SRCS = arch_linux.c
+	ARCH_SRCS := $(wildcard linux/*.c)
 endif
 ifeq ($(OS),Darwin)
 	CC ?= cc
@@ -61,7 +61,7 @@
 		-framework Foundation -framework ApplicationServices -framework Symbolication \
 		-framework CoreServices -framework CrashReporterSupport -framework CoreFoundation \
 		-framework CommerceKit -lm -L/usr/include -L$(shell echo ~)/.homebrew/lib
-	ARCH_SRCS = arch_mac.c
+	ARCH_SRCS = $(wildcard mac/*.c)
 	MIG_OUTPUT = mach_exc.h mach_excUser.c mach_excServer.h mach_excServer.c
 	MIG_OBJECTS = mach_excUser.o mach_excServer.o
 	#CRASH_REPORT = third_party/CrashReport_Yosemite.o
@@ -70,10 +70,10 @@
 SRCS += $(ARCH_SRCS)
 
 all: $(BIN)
-	@echo -ne "$(WARN_CAPSTONE)"
+	@/bin/echo -ne "$(WARN_CAPSTONE)"
 
 .c.o: %.c
-	$(CC) $(CFLAGS) $<
+	$(CC) $(CFLAGS) -o $@ $<
 
 $(BIN): $(MIG_OBJECTS) $(OBJS)
 	$(LD) -o $(BIN) $(OBJS) $(MIG_OBJECTS) $(CRASH_REPORT) $(LDFLAGS)
@@ -89,7 +89,7 @@
 	$(RM) core $(OBJS) $(BIN) $(MIG_OUTPUT) $(MIG_OBJECTS)
 
 indent:
-	indent -linux -l100 -lc100 -nut -i4 -sob -c33 -cp33 *.c *.h; rm -f *~
+	indent -linux -l100 -lc100 -nut -i4 -sob -c33 -cp33 *.c *.h */*.c */*.h; rm -f *~
 
 depend:
 	makedepend -Y. -- $(SRCS)
diff --git a/common.h b/common.h
index 1d9ecc7..7293373 100644
--- a/common.h
+++ b/common.h
@@ -35,7 +35,7 @@
 #define PROG_VERSION "0.4"
 #define PROG_AUTHORS "Robert Swiecki <swiecki@google.com> and others, Copyright 2010-2015 by Google Inc. All Rights Reserved."
 
-#define FILE_PLACEHOLDER "___FILE___"
+#define _HF_FILE_PLACEHOLDER "___FILE___"
 
 typedef struct {
     char **cmdline;
@@ -70,4 +70,10 @@
     int exception;
 } fuzzer_t;
 
+#define _HF_MAX_FUNCS 200
+typedef struct {
+    void *pc;
+    char func[64];
+} funcs_t;
+
 #endif
diff --git a/honggfuzz.c b/honggfuzz.c
index fb32ed2..fdc7fbf 100644
--- a/honggfuzz.c
+++ b/honggfuzz.c
@@ -43,7 +43,7 @@
 static bool checkFor_FILE_PLACEHOLDER(char **args)
 {
     for (int x = 0; args[x]; x++) {
-        if (!strcmp(args[x], FILE_PLACEHOLDER))
+        if (!strcmp(args[x], _HF_FILE_PLACEHOLDER))
             return true;
     }
     return false;
@@ -77,7 +77,7 @@
            "           previously created process, default: '" AB "0" AC "' (none)\n"
 #endif                          /* _HAVE_ARCH_LINUX */
            "Usage:"
-           AB " " PROG_NAME " -f input_dir -- /usr/bin/tiffinfo -D " FILE_PLACEHOLDER AC "\n");
+           AB " " PROG_NAME " -f input_dir -- /usr/bin/tiffinfo -D " _HF_FILE_PLACEHOLDER AC "\n");
     /*  *INDENT-ON* */
 
     if (exit_success) {
@@ -187,7 +187,7 @@
 
     if (!hfuzz.fuzzStdin && !checkFor_FILE_PLACEHOLDER(hfuzz.cmdline)) {
         LOGMSG(l_FATAL,
-               "You must specify '" FILE_PLACEHOLDER
+               "You must specify '" _HF_FILE_PLACEHOLDER
                "' when the -s (stdin fuzzing) option is not set");
         usage(false);
     }
diff --git a/linux/arch.c b/linux/arch.c
new file mode 100644
index 0000000..554c2a5
--- /dev/null
+++ b/linux/arch.c
@@ -0,0 +1,197 @@
+/*
+
+   honggfuzz - architecture dependent code (LINUX)
+   -----------------------------------------
+
+   Author: Robert Swiecki <swiecki@google.com>
+
+   Copyright 2010-2015 by Google Inc. All Rights Reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+#include "common.h"
+#include "arch.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/cdefs.h>
+#include <sys/personality.h>
+#include <sys/ptrace.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "linux/ptrace.h"
+#include "log.h"
+#include "util.h"
+
+bool arch_launchChild(honggfuzz_t * hfuzz, char *fileName)
+{
+    if (!arch_ptraceEnable(hfuzz)) {
+        return false;
+    }
+    /*
+     * Kill a process which corrupts its own heap (with ABRT)
+     */
+    if (setenv("MALLOC_CHECK_", "3", 1) == -1) {
+        LOGMSG_P(l_ERROR, "setenv(MALLOC_CHECK_=3) failed");
+        return false;
+    }
+
+    /*
+     * Tell asan to ignore SEGVs
+     */
+    if (setenv("ASAN_OPTIONS", "handle_segv=0", 1) == -1) {
+        LOGMSG_P(l_ERROR, "setenv(ASAN_OPTIONS) failed");
+        return false;
+    }
+
+    /*
+     * Kill the children when fuzzer dies (e.g. due to Ctrl+C)
+     */
+    if (prctl(PR_SET_PDEATHSIG, (long)SIGKILL, 0L, 0L, 0L) == -1) {
+        LOGMSG_P(l_ERROR, "prctl(PR_SET_PDEATHSIG, SIGKILL) failed");
+        return false;
+    }
+
+    /*
+     * Disable ASLR
+     */
+    if (personality(ADDR_NO_RANDOMIZE) == -1) {
+        LOGMSG_P(l_ERROR, "personality(ADDR_NO_RANDOMIZE) failed");
+        return false;
+    }
+#define ARGS_MAX 512
+    char *args[ARGS_MAX + 2];
+
+    int x;
+
+    for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
+        if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER) == 0) {
+            args[x] = fileName;
+        } else {
+            args[x] = hfuzz->cmdline[x];
+        }
+    }
+
+    args[x++] = NULL;
+
+    LOGMSG(l_DEBUG, "Launching '%s' on file '%s'", args[0], fileName);
+
+    /*
+     * Set timeout (prof), real timeout (2*prof), and rlimit_cpu (2*prof)
+     */
+    if (hfuzz->tmOut) {
+        /*
+         * The hfuzz->tmOut is real CPU usage time...
+         */
+        struct itimerval it_prof = {
+            .it_interval = {.tv_sec = hfuzz->tmOut,.tv_usec = 0},
+            .it_value = {.tv_sec = 0,.tv_usec = 0}
+        };
+        if (setitimer(ITIMER_PROF, &it_prof, NULL) == -1) {
+            LOGMSG_P(l_ERROR, "Couldn't set the ITIMER_PROF timer");
+            return false;
+        }
+
+        /*
+         * ...so, if a process sleeps, this one should
+         * trigger a signal...
+         */
+        struct itimerval it_real = {
+            .it_interval = {.tv_sec = hfuzz->tmOut * 2UL,.tv_usec = 0},
+            .it_value = {.tv_sec = 0,.tv_usec = 0}
+        };
+        if (setitimer(ITIMER_REAL, &it_real, NULL) == -1) {
+            LOGMSG_P(l_ERROR, "Couldn't set the ITIMER_REAL timer");
+            return false;
+        }
+
+        /*
+         * ..if a process sleeps and catches SIGPROF/SIGALRM
+         * rlimits won't help either
+         */
+        struct rlimit rl = {
+            .rlim_cur = hfuzz->tmOut * 2,
+            .rlim_max = hfuzz->tmOut * 2,
+        };
+        if (setrlimit(RLIMIT_CPU, &rl) == -1) {
+            LOGMSG_P(l_ERROR, "Couldn't enforce the RLIMIT_CPU resource limit");
+            return false;
+        }
+    }
+
+    /*
+     * The address space limit. If big enough - roughly the size of RAM used
+     */
+    if (hfuzz->asLimit) {
+        struct rlimit rl = {
+            .rlim_cur = hfuzz->asLimit * 1024UL * 1024UL,
+            .rlim_max = hfuzz->asLimit * 1024UL * 1024UL,
+        };
+        if (setrlimit(RLIMIT_AS, &rl) == -1) {
+            LOGMSG_P(l_DEBUG, "Couldn't encforce the RLIMIT_AS resource limit, ignoring");
+        }
+    }
+
+    if (hfuzz->nullifyStdio) {
+        util_nullifyStdio();
+    }
+
+    if (hfuzz->fuzzStdin) {
+        /* Uglyyyyyy ;) */
+        if (!util_redirectStdin(fileName)) {
+            return false;
+        }
+    }
+
+    execvp(args[0], args);
+
+    util_recoverStdio();
+    LOGMSG(l_FATAL, "Failed to create new '%s' process", args[0]);
+    return false;
+}
+
+void arch_reapChild(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
+{
+    int status;
+
+    for (;;) {
+        pid_t pid;
+        while ((pid = wait3(&status, __WNOTHREAD | __WALL | WUNTRACED, NULL)) <= 0) ;
+
+        LOGMSG(l_DEBUG, "Process (pid %d) came back with status %d", pid, status);
+
+        if (arch_ptraceAnalyze(hfuzz, status, pid, fuzzer)) {
+            return;
+        }
+    }
+}
+
+bool arch_prepareParent(honggfuzz_t * hfuzz)
+{
+    return arch_ptracePrepare(hfuzz);
+}
diff --git a/linux/bfd.c b/linux/bfd.c
new file mode 100644
index 0000000..a7db513
--- /dev/null
+++ b/linux/bfd.c
@@ -0,0 +1,115 @@
+/*
+
+   honggfuzz - architecture dependent code (LINUX/BFD)
+   -----------------------------------------
+
+   Author: Robert Swiecki <swiecki@google.com>
+
+   Copyright 2010-2015 by Google Inc. All Rights Reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+#include "common.h"
+#include "linux/bfd.h"
+
+#include <bfd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include "files.h"
+#include "log.h"
+#include "util.h"
+
+static bool arch_bfdInit(pid_t pid, bfd ** bfdh, asection ** section, asymbol *** syms)
+{
+    bfd_init();
+
+    char fname[PATH_MAX];
+    snprintf(fname, sizeof(fname), "/proc/%d/exe", pid);
+
+    *bfdh = bfd_openr(fname, 0);
+    if (*bfdh == NULL) {
+        LOGMSG(l_ERROR, "bfd_openr(%s) failed", fname);
+        return false;
+    }
+
+    if (!bfd_check_format(*bfdh, bfd_object)) {
+        LOGMSG(l_ERROR, "bfd_check_format() failed");
+        return false;
+    }
+
+    int storage_needed = bfd_get_symtab_upper_bound(*bfdh);
+    if (storage_needed <= 0) {
+        LOGMSG(l_ERROR, "bfd_get_symtab_upper_bound() returned '%d'", storage_needed);
+        return false;
+    }
+
+    *syms = (asymbol **) malloc(storage_needed);
+    if (*syms == NULL) {
+        LOGMSG_P(l_ERROR, "malloc(%d) failed", storage_needed);
+        return false;
+    }
+    bfd_canonicalize_symtab(*bfdh, *syms);
+
+    *section = bfd_get_section_by_name(*bfdh, ".text");
+    if (*section == NULL) {
+        LOGMSG(l_ERROR, "bfd_get_section_by_name('.text') failed");
+        return false;
+    }
+
+    return true;
+}
+
+static void arch_bfdDestroy(asymbol ** syms)
+{
+    if (syms) {
+        free(syms);
+    }
+    return;
+}
+
+void arch_bfdResolveSyms(pid_t pid, funcs_t * funcs, size_t num)
+{
+    bfd *bfdh = NULL;
+    asection *section = NULL;
+    asymbol **syms = NULL;
+
+    if (arch_bfdInit(pid, &bfdh, &section, &syms)) {
+        arch_bfdDestroy(syms);
+    }
+
+    const char *func;
+    const char *file;
+    unsigned int line;
+    for (unsigned int i = 0; i < num; i++) {
+        snprintf(funcs[i].func, sizeof(funcs->func), "[UNKNOWN]");
+        if (funcs[i].pc == NULL) {
+            continue;
+        }
+        long offset = (long)funcs[i].pc - section->vma;
+	if ((offset < 0 || (unsigned long)offset > section->size)) {
+		continue;
+	}
+        if (bfd_find_nearest_line(bfdh, section, syms, offset, &file, &func, &line)) {
+            snprintf(funcs[i].func, sizeof(funcs->func), "%s", func);
+        }
+    }
+
+    arch_bfdDestroy(syms);
+}
diff --git a/linux/bfd.h b/linux/bfd.h
new file mode 100644
index 0000000..78f7f69
--- /dev/null
+++ b/linux/bfd.h
@@ -0,0 +1,29 @@
+/*
+
+   honggfuzz - architecture dependent code
+   -----------------------------------------
+
+   Author: Robert Swiecki <swiecki@google.com>
+
+   Copyright 2010-2015 by Google Inc. All Rights Reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+#ifndef _LINUX_BFD_H_
+#define _LINUX_BFD_H_
+
+extern void arch_bfdResolveSyms(pid_t pid, funcs_t * funcs, size_t num);
+
+#endif
diff --git a/arch_linux.c b/linux/ptrace.c
similarity index 68%
rename from arch_linux.c
rename to linux/ptrace.c
index d926c8e..d3f260c 100644
--- a/arch_linux.c
+++ b/linux/ptrace.c
@@ -22,9 +22,8 @@
 */
 
 #include "common.h"
-#include "arch.h"
+#include "ptrace.h"
 
-#include <bfd.h>
 #include <capstone/capstone.h>
 #include <ctype.h>
 #include <dirent.h>
@@ -37,7 +36,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <inttypes.h>
-#include <libunwind-ptrace.h>
 #include <sys/cdefs.h>
 #include <sys/personality.h>
 #include <sys/ptrace.h>
@@ -53,6 +51,8 @@
 #include <unistd.h>
 
 #include "files.h"
+#include "linux/bfd.h"
+#include "linux/unwind.h"
 #include "log.h"
 #include "util.h"
 
@@ -77,110 +77,7 @@
 };
 /*  *INDENT-ON* */
 
-static bool arch_bfdInit(pid_t pid, bfd ** bfdh, asection ** section, asymbol *** syms)
-{
-    bfd_init();
-
-    char fname[PATH_MAX];
-    snprintf(fname, sizeof(fname), "/proc/%d/exe", pid);
-
-    *bfdh = bfd_openr(fname, 0);
-    if (*bfdh == NULL) {
-        LOGMSG(l_ERROR, "bfd_openr(%s) failed", fname);
-        return false;
-    }
-
-    if (!bfd_check_format(*bfdh, bfd_object)) {
-        LOGMSG(l_ERROR, "bfd_check_format() failed");
-        return false;
-    }
-
-    int storage_needed = bfd_get_symtab_upper_bound(*bfdh);
-    if (storage_needed <= 0) {
-        LOGMSG(l_ERROR, "bfd_get_symtab_upper_bound() returned '%d'", storage_needed);
-        return false;
-    }
-
-    *syms = (asymbol **) malloc(storage_needed);
-    if (*syms == NULL) {
-        LOGMSG_P(l_ERROR, "malloc(%d) failed", storage_needed);
-        return false;
-    }
-    bfd_canonicalize_symtab(*bfdh, *syms);
-
-    *section = bfd_get_section_by_name(*bfdh, ".text");
-    if (*section == NULL) {
-        LOGMSG(l_ERROR, "bfd_get_section_by_name(.text) failed");
-        return false;
-    }
-
-    return true;
-}
-
-static void arch_unwindPid(pid_t pid, char *newname)
-{
-    unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
-    if (!as) {
-        LOGMSG(l_ERROR, "unw_create_addr_space() failed");
-        return;
-    }
-
-    void *ui = _UPT_create(pid);
-    if (ui == NULL) {
-        LOGMSG(l_ERROR, "_UPT_create(%d) failed", pid);
-        return;
-    }
-
-    unw_cursor_t c;
-    int ret = unw_init_remote(&c, as, ui);
-    if (ret != 0) {
-        LOGMSG(l_ERROR, "unw_init_remote() failed");
-        return;
-    }
-
-    bfd *bfdh;
-    asection *section;
-    asymbol **syms;
-    bool bfdInitialized = arch_bfdInit(pid, &bfdh, &section, &syms);
-
-    int fd = open("HONGGFUZZ.REPORT.txt", O_CREAT | O_APPEND | O_WRONLY, 0644);
-    if (fd == -1) {
-        LOGMSG_P(l_ERROR, "Couldn't open 'HONGGFUZZ.REPORT.txt'");
-        return;
-    }
-
-    dprintf(fd, "===========================================\n");
-    dprintf(fd, "Input file: %s\n", newname);
-
-    while (unw_step(&c) > 0) {
-        unw_word_t ip;
-        unw_get_reg(&c, UNW_REG_IP, &ip);
-
-        dprintf(fd, "[0x%016lx]", (unsigned long)ip);
-        if (bfdInitialized) {
-            const char *func;
-            const char *file;
-            unsigned int line;
-            long offset = ((long)ip) - section->vma;
-            bfd_find_nearest_line(bfdh, section, syms, offset, &file, &func, &line);
-            dprintf(fd, " <%s> (line:%d)", func, line);
-        }
-        dprintf(fd, "\n");
-    }
-    dprintf(fd, "===========================================\n");
-    close(fd);
-
-    unw_destroy_addr_space(as);
-    _UPT_destroy(ui);
-
-    if (syms) {
-        free(syms);
-    }
-
-    return;
-}
-
-static bool arch_enablePtrace(honggfuzz_t * hfuzz)
+bool arch_ptraceEnable(honggfuzz_t * hfuzz)
 {
     // We're fuzzing an external process, so just return true
     if (hfuzz->pid) {
@@ -468,7 +365,7 @@
     }
 }
 
-static void arch_savePtraceData(honggfuzz_t * hfuzz, pid_t pid, fuzzer_t * fuzzer)
+static void arch_ptraceSaveData(honggfuzz_t * hfuzz, pid_t pid, fuzzer_t * fuzzer)
 {
     uint64_t pc = NULL;
 
@@ -517,14 +414,25 @@
         }
     }
 
-    arch_unwindPid(pid, newname);
+    funcs_t funcs[_HF_MAX_FUNCS] = {
+        [0 ... (_HF_MAX_FUNCS - 1)].pc = NULL,
+        [0 ... (_HF_MAX_FUNCS - 1)].func = {'\0'}
+        ,
+    };
+
+    size_t num = arch_unwindStack(pid, funcs);
+    arch_bfdResolveSyms(pid, funcs, num);
+
+    for (size_t i = 0; i < num; i++) {
+        LOGMSG(l_ERROR, "PC: %p FUNC: %s", funcs[i].pc, funcs[i].func);
+    }
 }
 
 /*
  * Returns true if a process exited (so, presumably, we can delete an input
  * file)
  */
-static bool arch_analyzePtrace(honggfuzz_t * hfuzz, int status, pid_t pid, fuzzer_t * fuzzer)
+bool arch_ptraceAnalyze(honggfuzz_t * hfuzz, int status, pid_t pid, fuzzer_t * fuzzer)
 {
     /*
      * If it's an uninteresting signal (even SIGTRAP), let it run and relay the
@@ -541,7 +449,7 @@
      * the tracer (relay the signal as well)
      */
     if (WIFSTOPPED(status) && arch_sigs[WSTOPSIG(status)].important) {
-        arch_savePtraceData(hfuzz, pid, fuzzer);
+        arch_ptraceSaveData(hfuzz, pid, fuzzer);
         ptrace(PT_CONTINUE, pid, 0, WSTOPSIG(status));
         return false;
     }
@@ -564,149 +472,6 @@
     return true;
 }
 
-bool arch_launchChild(honggfuzz_t * hfuzz, char *fileName)
-{
-    if (!arch_enablePtrace(hfuzz)) {
-        return false;
-    }
-    /*
-     * Kill a process which corrupts its own heap (with ABRT)
-     */
-    if (setenv("MALLOC_CHECK_", "3", 1) == -1) {
-        LOGMSG_P(l_ERROR, "setenv(MALLOC_CHECK_=3) failed");
-        return false;
-    }
-
-    /*
-     * Tell asan to ignore SEGVs
-     */
-    if (setenv("ASAN_OPTIONS", "handle_segv=0", 1) == -1) {
-        LOGMSG_P(l_ERROR, "setenv(ASAN_OPTIONS) failed");
-        return false;
-    }
-
-    /*
-     * Kill the children when fuzzer dies (e.g. due to Ctrl+C)
-     */
-    if (prctl(PR_SET_PDEATHSIG, (long)SIGKILL, 0L, 0L, 0L) == -1) {
-        LOGMSG_P(l_ERROR, "prctl(PR_SET_PDEATHSIG, SIGKILL) failed");
-        return false;
-    }
-
-    /*
-     * Disable ASLR
-     */
-    if (personality(ADDR_NO_RANDOMIZE) == -1) {
-        LOGMSG_P(l_ERROR, "personality(ADDR_NO_RANDOMIZE) failed");
-        return false;
-    }
-#define ARGS_MAX 512
-    char *args[ARGS_MAX + 2];
-
-    int x;
-
-    for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
-        if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], FILE_PLACEHOLDER) == 0) {
-            args[x] = fileName;
-        } else {
-            args[x] = hfuzz->cmdline[x];
-        }
-    }
-
-    args[x++] = NULL;
-
-    LOGMSG(l_DEBUG, "Launching '%s' on file '%s'", args[0], fileName);
-
-    /*
-     * Set timeout (prof), real timeout (2*prof), and rlimit_cpu (2*prof)
-     */
-    if (hfuzz->tmOut) {
-        /*
-         * The hfuzz->tmOut is real CPU usage time...
-         */
-        struct itimerval it_prof = {
-            .it_interval = {.tv_sec = hfuzz->tmOut,.tv_usec = 0},
-            .it_value = {.tv_sec = 0,.tv_usec = 0}
-        };
-        if (setitimer(ITIMER_PROF, &it_prof, NULL) == -1) {
-            LOGMSG_P(l_ERROR, "Couldn't set the ITIMER_PROF timer");
-            return false;
-        }
-
-        /*
-         * ...so, if a process sleeps, this one should
-         * trigger a signal...
-         */
-        struct itimerval it_real = {
-            .it_interval = {.tv_sec = hfuzz->tmOut * 2UL,.tv_usec = 0},
-            .it_value = {.tv_sec = 0,.tv_usec = 0}
-        };
-        if (setitimer(ITIMER_REAL, &it_real, NULL) == -1) {
-            LOGMSG_P(l_ERROR, "Couldn't set the ITIMER_REAL timer");
-            return false;
-        }
-
-        /*
-         * ..if a process sleeps and catches SIGPROF/SIGALRM
-         * rlimits won't help either
-         */
-        struct rlimit rl = {
-            .rlim_cur = hfuzz->tmOut * 2,
-            .rlim_max = hfuzz->tmOut * 2,
-        };
-        if (setrlimit(RLIMIT_CPU, &rl) == -1) {
-            LOGMSG_P(l_ERROR, "Couldn't enforce the RLIMIT_CPU resource limit");
-            return false;
-        }
-    }
-
-    /*
-     * The address space limit. If big enough - roughly the size of RAM used
-     */
-    if (hfuzz->asLimit) {
-        struct rlimit rl = {
-            .rlim_cur = hfuzz->asLimit * 1024UL * 1024UL,
-            .rlim_max = hfuzz->asLimit * 1024UL * 1024UL,
-        };
-        if (setrlimit(RLIMIT_AS, &rl) == -1) {
-            LOGMSG_P(l_DEBUG, "Couldn't encforce the RLIMIT_AS resource limit, ignoring");
-        }
-    }
-
-    if (hfuzz->nullifyStdio) {
-        util_nullifyStdio();
-    }
-
-    if (hfuzz->fuzzStdin) {
-        /* Uglyyyyyy ;) */
-        if (!util_redirectStdin(fileName)) {
-            return false;
-        }
-    }
-
-    execvp(args[0], args);
-
-    util_recoverStdio();
-    LOGMSG(l_FATAL, "Failed to create new '%s' process", args[0]);
-    return false;
-}
-
-void arch_reapChild(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
-{
-    int status;
-
-    for (;;) {
-        pid_t pid;
-        while ((pid = wait3(&status, __WNOTHREAD | __WALL | WUNTRACED, NULL)) <= 0) ;
-
-        LOGMSG(l_DEBUG, "Process (pid %d) came back with status %d", pid, status);
-
-        if (arch_analyzePtrace(hfuzz, status, pid, fuzzer)) {
-            return;
-        }
-    }
-}
-
 static bool arch_listThreads(int tasks[], size_t thrSz, int pid)
 {
     size_t count = 0;
@@ -753,7 +518,7 @@
     return true;
 }
 
-bool arch_prepareParent(honggfuzz_t * hfuzz)
+bool arch_ptracePrepare(honggfuzz_t * hfuzz)
 {
     if (!hfuzz->pid) {
         return true;
diff --git a/linux/ptrace.h b/linux/ptrace.h
new file mode 100644
index 0000000..75f8200
--- /dev/null
+++ b/linux/ptrace.h
@@ -0,0 +1,31 @@
+/*
+
+   honggfuzz - architecture dependent code
+   -----------------------------------------
+
+   Author: Robert Swiecki <swiecki@google.com>
+
+   Copyright 2010-2015 by Google Inc. All Rights Reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+#ifndef _LINUX_PTRACE_H_
+#define _LINUX_PTRACE_H_
+
+extern bool arch_ptraceEnable(honggfuzz_t * fuzz);
+extern bool arch_ptracePrepare(honggfuzz_t * fuzz);
+extern bool arch_ptraceAnalyze(honggfuzz_t * fuzz, int status, pid_t pid, fuzzer_t * fuzzer);
+
+#endif
diff --git a/linux/unwind.c b/linux/unwind.c
new file mode 100644
index 0000000..1a26b1e
--- /dev/null
+++ b/linux/unwind.c
@@ -0,0 +1,62 @@
+/*
+
+   honggfuzz - architecture dependent code (LINUX/UNWIND)
+   -----------------------------------------
+
+   Author: Robert Swiecki <swiecki@google.com>
+
+   Copyright 2010-2015 by Google Inc. All Rights Reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+#include "common.h"
+#include "linux/unwind.h"
+
+#include <libunwind-ptrace.h>
+
+#include "log.h"
+
+size_t arch_unwindStack(pid_t pid, funcs_t * funcs)
+{
+    unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
+    if (!as) {
+        LOGMSG(l_ERROR, "unw_create_addr_space() failed");
+        return 0U;
+    }
+
+    void *ui = _UPT_create(pid);
+    if (ui == NULL) {
+        LOGMSG(l_ERROR, "_UPT_create(%d) failed", pid);
+        return 0U;
+    }
+
+    unw_cursor_t c;
+    if (unw_init_remote(&c, as, ui) != 0) {
+        LOGMSG(l_ERROR, "unw_init_remote() failed");
+        return 0U;
+    }
+
+    size_t ret = 0;
+    for (ret = 0; unw_step(&c) > 0; ret++) {
+        unw_word_t ip;
+        unw_get_reg(&c, UNW_REG_IP, &ip);
+        funcs[ret].pc = (void *)ip;
+    }
+
+    unw_destroy_addr_space(as);
+    _UPT_destroy(ui);
+
+    return ret;
+}
diff --git a/linux/unwind.h b/linux/unwind.h
new file mode 100644
index 0000000..079570b
--- /dev/null
+++ b/linux/unwind.h
@@ -0,0 +1,29 @@
+/*
+
+   honggfuzz - architecture dependent code
+   -----------------------------------------
+
+   Author: Robert Swiecki <swiecki@google.com>
+
+   Copyright 2010-2015 by Google Inc. All Rights Reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+#ifndef _LINUX_UNWIND_H_
+#define _LINUX_UNWIND_H_
+
+extern size_t arch_unwindStack(pid_t pid, funcs_t * funcs);
+
+#endif
diff --git a/arch_mac.c b/mac/arch_mac.c
similarity index 99%
rename from arch_mac.c
rename to mac/arch_mac.c
index 906569c..4fcf2d4 100644
--- a/arch_mac.c
+++ b/mac/arch_mac.c
@@ -224,7 +224,7 @@
     int x;
 
     for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
-        if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], FILE_PLACEHOLDER) == 0) {
+        if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER) == 0) {
             args[x] = fileName;
         } else {
             args[x] = hfuzz->cmdline[x];
diff --git a/arch_posix.c b/posix/arch_posix.c
similarity index 98%
rename from arch_posix.c
rename to posix/arch_posix.c
index 4d14797..847eaa7 100644
--- a/arch_posix.c
+++ b/posix/arch_posix.c
@@ -128,7 +128,7 @@
     int x;
 
     for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
-        if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], FILE_PLACEHOLDER) == 0) {
+        if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER) == 0) {
             args[x] = fileName;
         } else {
             args[x] = hfuzz->cmdline[x];