Example #1
0
static void _log_stack(int32_t logLev,int32_t start,char *str) {
	void*                   bt[64];
	char**                  strings;
	size_t                  sz;
	int32_t                 i,f;
	int32_t 				size = 0;	
	char 					logbuf[MAX_LOG_SIZE];
	char                    addr[32],buf[1024];
	char 				   *ptr;		
	sz      = backtrace(bt, 64);
	strings = backtrace_symbols(bt, sz);
	size   += snprintf(logbuf,MAX_LOG_SIZE,"%s",str);	    		    			
	for(i = start,f = 0; i < sz; ++i) {
		if(strstr(strings[i],"main+")) break;
		ptr  = logbuf + size;
		if(getaddr(strings[i],addr,32) && !addr2line(addr,buf,1024))
			size += snprintf(ptr,MAX_LOG_SIZE-size,
				"\t% 2d: %s %s\n",++f,strings[i],buf);
		else
			size += snprintf(ptr,MAX_LOG_SIZE-size,
				"\t% 2d: %s\n",++f,strings[i]);		
	}
	SYS_LOG(logLev,"%s",logbuf);
	free(strings);	
}
Example #2
0
  void windows_print_stacktrace(CONTEXT* context)
  {
    SymInitialize(GetCurrentProcess(), 0, true);

    STACKFRAME frame = { 0 };

    /* setup initial stack frame */
    frame.AddrPC.Offset         = context->Eip;
    frame.AddrPC.Mode           = AddrModeFlat;
    frame.AddrStack.Offset      = context->Esp;
    frame.AddrStack.Mode        = AddrModeFlat;
    frame.AddrFrame.Offset      = context->Ebp;
    frame.AddrFrame.Mode        = AddrModeFlat;

    while (StackWalk(IMAGE_FILE_MACHINE_I386 ,
                     GetCurrentProcess(),
                     GetCurrentThread(),
                     &frame,
                     context,
                     0,
                     SymFunctionTableAccess,
                     SymGetModuleBase,
                     0 ) )
    {
      addr2line(icky_global_program_name, (void*)frame.AddrPC.Offset);
    }

    SymCleanup( GetCurrentProcess() );
  }
Example #3
0
static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
					struct dso *dso, struct symbol *sym)
{
	struct inline_node *node;

	node = zalloc(sizeof(*node));
	if (node == NULL) {
		perror("not enough memory for the inline node");
		return NULL;
	}

	INIT_LIST_HEAD(&node->val);
	node->addr = addr;

	addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym);
	return node;
}
  void posix_print_stack_trace()
  {
    int i, trace_size = 0;
    char **messages = (char **)NULL;

    trace_size = backtrace(stack_traces, MAX_STACK_FRAMES);
    messages = backtrace_symbols(stack_traces, trace_size);

    /* skip the first couple stack frames (as they are this function and
     our handler) and also skip the last frame as it's (always?) junk. */
    // for (i = 3; i < (trace_size - 1); ++i)
    for (i = 0; i < trace_size; ++i) // we'll use this for now so you can see what's going on
    {
      if (addr2line(icky_global_program_name, stack_traces[i]) != 0)
      {
        printf("  error determining line # for: %s\n", messages[i]);
      }

    }
    if (messages) { free(messages); } 
  }
Example #5
0
void print_trace(void)
{
	void *array[10];
	size_t size;
	char **strings;
	size_t i;
#ifndef __mips__

	size = backtrace(array, 10);

	LOGL(0, "Obtained %zd stack frames.\n", size);

	for (i = 0; i < size; i++)
	{
		LOGL(0, "%p : ", array[i]);
		if (addr2line(pn, array[i]))
			LOGL(0, "\n");
	}
#else
	LOGL(0, " No backtrace defined\n");
#endif
}
Example #6
0
void
Cache :: line_get(Addr addr, uint8_t line_state_req, size_t &latency, uint8_t *&pdata)
{
    //////////////////////////////////////////////////////////////////
    //
    //  proudly serving cache requests
    //  since september 2008
    //
    //////////////////////////////////////////////////////////////////
    //
    // line_state_req(uest) values:
    // LINE_SHR - request a read
    // LINE_EXC - request an exclusive access (invalidate other readers)
    // LINE_MOD - perform a write (invalidate other readers and mark line as dirty)

    bool set_overflow = false;
    Line *overflow_line = NULL;
    // this adds a line (if it's not already in the cache) but with LINE_INV state
    Line *line = addr2line(addr, set_overflow, overflow_line);
    // if some line has been replaced, get the value and evict/invalidate the same line and its parts
    // in all child caches
    if (set_overflow) {
        NVLOG1("%s\tline_get overflow 0x%lx\n", _name.c_str(), overflow_line->addr);
        this->line_evict(overflow_line);
    }
    uint8_t __attribute__((unused)) line_state_orig = line->state;
    uint64_t __attribute__((unused)) line_sharers_orig = line->sharers;

    bool hit = true;
    size_t old_ticks = latency;

    if (line->state & LINE_MOD)
    {
        switch (line_state_req) {
            case LINE_MOD:
            case LINE_EXC:
            case LINE_SHR:
                break;
            default:
                assert(!"invalid line_state request!");
        }
    }
    else if (line->state & LINE_EXC)
    { // line is EXCLUSIVE when it is not modified and there is no other line sharer
        // TODO update the functionality to reflect this;
        // first line sharer should automatically get exclusive access;
        // this exclusive access should be reduced to shared when another core requests line copy (for read)
        switch (line_state_req) {
            case LINE_MOD:
                if (_is_writeback_cache || !_parent_cache) {
                    // mark line as dirty (for writeback)
                    line->state |= line_state_req;
                } else {
                    // write latency should include writing to the parent
                    _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line);
                    // TODO should also write data to the parent cache
                    hit = false;
                    break;
                }
            case LINE_EXC:
            case LINE_SHR:
                break;
            default:
                assert(!"invalid line_state request!");
        }
    }
    else if (line->state & LINE_SHR)
    {
        switch (line_state_req) {
            case LINE_MOD:
            case LINE_EXC:
                if (_parent_cache) {
                    if (_is_writeback_cache) {
                        _parent->line_get_intercache(addr, LINE_EXC, latency, _index_in_parent, line->parent_line);
                    } else {
                        _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line);
                    }
                    hit = false;
                }
                line->state |= line_state_req;
                break;
            case LINE_SHR:
                break;
            default:
                assert(!"invalid line_state request!");
        }
    }
    else if (line->state == LINE_INV)
    {
        hit = false;
        switch (line_state_req) {
            case LINE_TXW:
            case LINE_TXR:
                _parent->line_get_intercache(addr, LINE_SHR, latency, _index_in_parent, line->parent_line);
                line->state |= line->parent_line->state & ( LINE_TXR | LINE_TXW);
                line->state |= (LINE_SHR | line_state_req);
                break;
            case LINE_MOD:
            case LINE_EXC:
                if (_is_writeback_cache) {
                    _parent->line_get_intercache(addr, LINE_EXC, latency, _index_in_parent, line->parent_line);
                } else {
                    _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line);
                }
                line->state |= line_state_req;
                break;
            case LINE_SHR:
                _parent->line_get_intercache(addr, LINE_SHR, latency, _index_in_parent, line->parent_line);
                line->state |= line_state_req;
                break;
            default:
                assert(!"invalid line_state request!");
        }
    }
    else
    {
        NVLOG_ERROR("invalid current line_state %x\n", line->state);
        assert(false && "invalid current line_state!");
    }


    if (line->pdata == NULL) {
        line->pdata = (uint8_t*)malloc(get_line_size());
        if (_parent_cache && line->parent_line) { // if data found in parent cache
            NVLOG1("%s\tline_get data copy from %s 0x%lx data 0x%lx -> 0x%lx\n", this->_name.c_str(), _parent_cache->_name.c_str(), line->addr, (Addr)line->parent_line->pdata, (Addr)line->pdata);
            memcpy(line->pdata, line->parent_line->pdata+(line->addr - line->parent_line->addr), get_line_size());
        } else {
            // get the data from the memory
            NVLOG1("%s\tline_get data copy from memory 0x%lx data -> 0x%lx\n", this->_name.c_str(), line->addr, (Addr)line->pdata);
	    //Fault fault = rw_array_silent(line->addr, get_line_size(), line->pdata, false/*READ*/);
	    //assert(fault == NoFault);
        }
    }
    pdata = line->pdata;

    latency += _hit_latency;
    // update statistics
    if (hit) {
        this->stats.hits_inc();
    } else {
        this->stats.misses_inc();
        if (line_state_req & LINE_MOD || line_state_req & LINE_EXC)
        { this->stats.misses_st_inc(); }
        else
        { this->stats.misses_ld_inc(); }
    }
    this->stats.ticks_inc(latency - old_ticks);
    NVLOG1("%s\tline_get 0x%lx\t state %s->%s sharers 0x%lx->0x%lx\n",  _name.c_str(),  line->addr,  state2str(line_state_orig).c_str(), state2str(line->state).c_str(), line_sharers_orig, line->sharers);
    assert(! ((line->state & (LINE_MOD | LINE_EXC)) && (line->state & LINE_TXW)) );
}
Example #7
0
void
Cache :: line_get_intercache(Addr addr, uint8_t line_state_req, size_t &latency, unsigned child_index, Line *&parent_line)
{
    //////////////////////////////////////////////////////////////////////
    // serving line relocations inside the cache hierarchy
    //////////////////////////////////////////////////////////////////////

    bool set_overflow = false;
    Line *overflow_line = NULL;
    // this adds a line (if it's not already in the cache) but with LINE_INV state
    Line *line = addr2line(addr, set_overflow, overflow_line);
    if (set_overflow) {
        // if some line has been replaced, get the value and invalidate the same line and its parts
        // in all child caches
        NVLOG1("%s\tline_get overflow 0x%lx\n", _name.c_str(), overflow_line->addr);
        this->line_evict(overflow_line);
    }
    uint8_t __attribute__((unused)) line_state_orig = line->state;
    uint64_t __attribute__((unused)) line_sharers_orig = line->sharers;

    bool hit = true;
    size_t old_ticks = latency;

    if (line->state & (LINE_MOD | LINE_EXC))
    {
        // this directory already owns a line (exclusively)
        // just in case we'll invalidate the line in
        // all other child-caches
        switch (line_state_req) {
            case LINE_MOD:
                if (line->sharers != (1ULL<<child_index)) {
                    this->line_make_owner_in_child_caches(line, child_index);
                    setbit(line->sharers, child_index);
                }
                if (_is_writeback_cache || !_parent_cache) {
                    line->state |= line_state_req;
                } else {
                    _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line);
                    hit = false;
                    break;
                }
                break;
            case LINE_EXC:
                // this processor wants to have an exclusive copy
                // (and it didn't have it until now, as we got an intercache request)
                if (line->sharers != (1ULL<<child_index)) {
                    this->line_make_owner_in_child_caches(line, child_index);
                    setbit(line->sharers, child_index);
                }
                break;
            case LINE_SHR:
                if (line->sharers != (1ULL<<child_index)) {
                    this->line_writer_to_sharer(line, latency);
                    // and do not write the data up in the memory hierarchy
                    setbit(line->sharers, child_index);
                }
                break;
            default:
                assert(!"invalid line_state request!");
        }
        //assert(line_state_req == LINE_SHR || line_state_req == LINE_EXC || line_state_req == LINE_MOD);
        line->state |= line_state_req; // we might also reduce from writer to LINE_SHR in this cache
    }
    else if (line->state & LINE_SHR)
    {
        switch (line_state_req) {
            case LINE_MOD:
            case LINE_EXC:
                this->line_make_owner_in_child_caches(line, child_index);
                setbit(line->sharers, child_index);
                if (_parent_cache) {
                    if (_is_writeback_cache) {
                        _parent->line_get_intercache(addr, LINE_EXC, latency, _index_in_parent, line->parent_line);
                    } else {
                        _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line);
                    }
                    hit = false;
                }
                line->state |= line_state_req;
                break;
            case LINE_SHR:
                setbit(line->sharers, child_index);
                break;
            default:
                assert(!"invalid line_state request!");
        }
    }
    else if (line->state == LINE_INV)
    {
        hit = false;
        switch (line_state_req) {
            case LINE_MOD:
            case LINE_EXC:
                if (_is_writeback_cache) {
                    _parent->line_get_intercache(addr, LINE_EXC, latency, _index_in_parent, line->parent_line);
                } else {
                    _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line);
                }
                if (line->parent_line) { line->state = line->parent_line->state; }
                line->state |= line_state_req;
                setbit(line->sharers, child_index);
                break;
            case LINE_SHR:
                _parent->line_get_intercache(addr, LINE_SHR, latency, _index_in_parent, line->parent_line);
                if (line->parent_line) { line->state = line->parent_line->state; }
                line->state |= line_state_req;
                setbit(line->sharers, child_index);
                break;
            default:
                assert(!"invalid line_state request!");
        }
    }
    else
    {
        NVLOG_ERROR("invalid current line_state %x\n", line->state);
        assert(false && "invalid current line_state!");
    }

    if (line->pdata == NULL) {
        line->pdata = (uint8_t*)malloc(get_line_size());
        if (_parent_cache && line->parent_line) { // if data found in any parent cache
            NVLOG1("%s\tline_get data copy from %s 0x%lx data 0x%lx -> 0x%lx\n", this->_name.c_str(), _parent_cache->_name.c_str(), line->addr, (Addr)line->parent_line->pdata, (Addr)line->pdata);
            memcpy(line->pdata, line->parent_line->pdata+(line->addr - line->parent_line->addr), get_line_size());
        } else {
            // get the data from the memory
            NVLOG1("%s\tline_get data copy from memory 0x%lx data 0x%lx\n", this->_name.c_str(), line->addr, (Addr)line->pdata);
//            Fault fault = rw_array_silent(line->addr, get_line_size(), line->pdata, false/*READ*/);
//            assert(fault == NoFault);
        }
    }
    parent_line = line;

    latency += _hit_latency;
    // update statistics
    if (hit) {
        this->stats.hits_inc();
    } else {
        this->stats.misses_inc();
        if (line_state_req & LINE_MOD || line_state_req & LINE_EXC)
        { this->stats.misses_st_inc(); }
        else
        { this->stats.misses_ld_inc(); }
    }
    this->stats.ticks_inc(latency - old_ticks);
    NVLOG1("%s\tline_get 0x%lx\t state %s->%s sharers 0x%lx->0x%lx\n",  _name.c_str(),  line->addr,  state2str(line_state_orig).c_str(), state2str(line->state).c_str(), line_sharers_orig, line->sharers);
    assert(! ((line->state & (LINE_MOD | LINE_EXC)) && (line->state & LINE_TXW)) );
}
Example #8
0
void DeathHandler::HandleSignal(int sig, void * /* info */, void *secret) {
  // Stop all other running threads by forking
  pid_t forkedPid = fork();
  if (forkedPid != 0) {
    int status;
    if (thread_safe_) {
      // Freeze the original process, until it's child prints the stack trace
      kill(getpid(), SIGSTOP);
      // Wait for the child without blocking and exit as soon as possible,
      // so that no zombies are left.
      waitpid(forkedPid, &status, WNOHANG);
    } else {
      // Wait for the child, blocking only the current thread.
      // All other threads will continue to run, potentially crashing the parent.
      waitpid(forkedPid, &status, 0);
    }
#ifdef QUICK_EXIT
    if (quick_exit_) {
      ::quick_exit(EXIT_FAILURE);
    }
#endif
    if (generate_core_dump_) {
      struct sigaction sa;
      sigaction(SIGABRT, NULL, &sa);
      sa.sa_handler = SIG_DFL;
      sigaction(SIGABRT, &sa, NULL);
      abort();
    } else {
      if (cleanup_) {
        exit(EXIT_FAILURE);
      } else {
        _Exit(EXIT_FAILURE);
      }
    }
  }

  ucontext_t *uc = reinterpret_cast<ucontext_t *>(secret);

  if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1) {  // redirect stdout to stderr
    print("Failed to redirect stdout to stderr\n");
  }
  char* memory = memory_;
  {
    char* msg = memory;
    const int msg_max_length = 128;
    if (color_output_) {
      // \033[31;1mSegmentation fault\033[0m \033[33;1m(%i)\033[0m\n
      strcpy(msg, "\033[31;1m");  // NOLINT(runtime/printf)
    } else {
      msg[0] = '\0';
    }
    switch (sig) {
      case SIGSEGV:
        strcat(msg, "Segmentation fault");  // NOLINT(runtime/printf)
        break;
      case SIGABRT:
        strcat(msg, "Aborted");  // NOLINT(runtime/printf)
        break;
      case SIGFPE:
        strcat(msg, "Floating point exception");  // NOLINT(runtime/printf)
        break;
      default:
        strcat(msg, "Caught signal ");  // NOLINT(runtime/printf)
        strcat(msg, Safe::itoa(sig, msg + msg_max_length));  // NOLINT(*)
        break;
    }
    if (color_output_) {
      strcat(msg, "\033[0m");  // NOLINT(runtime/printf)
    }
    strcat(msg, " (thread ");  // NOLINT(runtime/printf)
    if (color_output_) {
      strcat(msg, "\033[33;1m");  // NOLINT(runtime/printf)
    }
  #ifndef __APPLE__
    strcat(msg, Safe::utoa(pthread_self(), msg + msg_max_length));  // NOLINT(*)
  #else
    strcat(msg, Safe::ptoa(pthread_self(), msg + msg_max_length));  // NOLINT(*)
  #endif
    if (color_output_) {
      strcat(msg, "\033[0m");  // NOLINT(runtime/printf)
    }
    strcat(msg, ", pid ");  // NOLINT(runtime/printf)
    if (color_output_) {
      strcat(msg, "\033[33;1m");  // NOLINT(runtime/printf)
    }
    strcat(msg, Safe::itoa(getppid(), msg + msg_max_length));  // NOLINT(*)
    if (color_output_) {
      strcat(msg, "\033[0m");  // NOLINT(runtime/printf)
    }
    strcat(msg, ")");  // NOLINT(runtime/printf)
    print(msg);
  }

  print("\nStack trace:\n");
  void **trace = reinterpret_cast<void**>(memory);
  memory += (frames_count_ + 2) * sizeof(void*);
  // Workaround malloc() inside backtrace()
  heap_trap_active_ = true;
  int trace_size = backtrace(trace, frames_count_ + 2);
  heap_trap_active_ = false;
  if (trace_size <= 2) {
    safe_abort();
  }

  // Overwrite sigaction with caller's address
#ifdef __linux__
#if defined(__arm__)
  trace[1] = reinterpret_cast<void *>(uc->uc_mcontext.arm_pc);
#elif defined(__aarch64__)
  trace[1] = reinterpret_cast<void *>(uc->uc_mcontext.pc);
#else
#if !defined(__i386__) && !defined(__x86_64__)
#error Only ARM, AARCH64, x86 and x86-64 are supported
#endif
#if defined(__x86_64__)
  trace[1] = reinterpret_cast<void *>(uc->uc_mcontext.gregs[REG_RIP]);
#else
  trace[1] = reinterpret_cast<void *>(uc->uc_mcontext.gregs[REG_EIP]);
#endif
#endif

  const int path_max_length = 2048;
  char* name_buf = memory;
  ssize_t name_buf_length = readlink("/proc/self/exe", name_buf,
                                     path_max_length - 1);
  if (name_buf_length < 1) {
    safe_abort();
  }
  name_buf[name_buf_length] = 0;
  memory += name_buf_length + 1;
  char* cwd = memory;
  if (getcwd(cwd, path_max_length) == NULL) {
    safe_abort();
  }
  strcat(cwd, "/");  // NOLINT(runtime/printf)
  memory += strlen(cwd) + 1;
  char* prev_memory = memory;

  int stackOffset = trace[2] == trace[1]? 2 : 1;
  for (int i = stackOffset; i < trace_size; i++) {
    memory = prev_memory;
    char *line;
    Dl_info dlinf;
    if (dladdr(trace[i], &dlinf) == 0 || dlinf.dli_fname[0] != '/' ||
        !strcmp(name_buf, dlinf.dli_fname)) {
      line = addr2line(name_buf, trace[i], color_output_, &memory);
    } else {
      line = addr2line(dlinf.dli_fname, reinterpret_cast<void *>(
          reinterpret_cast<char *>(trace[i]) -
          reinterpret_cast<char *>(dlinf.dli_fbase)),
          color_output_, &memory);
    }

    char *function_name_end = strstr(line, "\n");
    if (function_name_end != NULL) {
      *function_name_end = 0;
      {
        // "\033[34;1m[%s]\033[0m \033[33;1m(%i)\033[0m\n
        char* msg = memory;
        const int msg_max_length = 512;
        if (color_output_) {
          strcpy(msg, "\033[34;1m");  // NOLINT(runtime/printf)
        } else {
          msg[0] = 0;
        }
        strcat(msg, "[");  // NOLINT(runtime/printf)
        strcat(msg, line);  // NOLINT(runtime/printf)
        strcat(msg, "]");  // NOLINT(runtime/printf)
        if (append_pid_) {
          if (color_output_) {
            strcat(msg, "\033[0m\033[33;1m");  // NOLINT(runtime/printf)
          }
          strcat(msg, " (");  // NOLINT(runtime/printf)
          strcat(msg, Safe::itoa(getppid(), msg + msg_max_length));  // NOLINT(*)
          strcat(msg, ")");  // NOLINT(runtime/printf)
          if (color_output_) {
            strcat(msg, "\033[0m");  // NOLINT(runtime/printf)
          }
          strcat(msg, "\n");  // NOLINT(runtime/printf)
        } else {
          if (color_output_) {
            strcat(msg, "\033[0m");  // NOLINT(runtime/printf)
          }
          strcat(msg, "\n");  // NOLINT(runtime/printf)
        }
        print(msg);
      }
      line = function_name_end + 1;

      // Remove the common path root
      if (cut_common_path_root_) {
        int cpi;
        for (cpi = 0; cwd[cpi] == line[cpi]; cpi++) {};
        if (line[cpi - 1] != '/') {
          for (; line[cpi - 1] != '/'; cpi--) {};
        }
        if (cpi > 1) {
          line = line + cpi;
        }
      }

      // Remove relative path root
      if (cut_relative_paths_) {
        char *path_cut_pos = strstr(line, "../");
        if (path_cut_pos != NULL) {
          path_cut_pos += 3;
          while (!strncmp(path_cut_pos, "../", 3)) {
            path_cut_pos += 3;
          }
          line = path_cut_pos;
        }
      }

      // Mark line number
      if (color_output_) {
        char* number_pos = strstr(line, ":");
        if (number_pos != NULL) {
          char* line_number = memory;  // 128
          strcpy(line_number, number_pos);  // NOLINT(runtime/printf)
          // Overwrite the new line char
          line_number[strlen(line_number) - 1] = 0;
          // \033[32;1m%s\033[0m\n
          strcpy(number_pos, "\033[32;1m");  // NOLINT(runtime/printf)
          strcat(line, line_number);  // NOLINT(runtime/printf)
          strcat(line, "\033[0m\n");  // NOLINT(runtime/printf)
        }
      }
    }

    // Overwrite the new line char
    line[strlen(line) - 1] = 0;

    // Append pid
    if (append_pid_) {
      // %s\033[33;1m(%i)\033[0m\n
      strcat(line, " ");  // NOLINT(runtime/printf)
      if (color_output_) {
        strcat(line, "\033[33;1m");  // NOLINT(runtime/printf)
      }
      strcat(line, "(");  // NOLINT(runtime/printf)
      strcat(line, Safe::itoa(getppid(), memory));  // NOLINT(runtime/printf)
      strcat(line, ")");  // NOLINT(runtime/printf)
      if (color_output_) {
        strcat(line, "\033[0m");  // NOLINT(runtime/printf)
      }
    }

    strcat(line, "\n");  // NOLINT(runtime/printf)
    print(line);
  }

  // Write '\0' to indicate the end of the output
  char end = '\0';
  write(STDERR_FILENO, &end, 1);

#elif defined(__APPLE__)
  for (int i = 0; i < trace_size; i++) {
    Safe::ptoa(trace[i], memory);
    strcat(memory, "\n");
    print(memory);
  }
#endif
  if (thread_safe_) {
    // Resume the parent process
    kill(getppid(), SIGCONT);
  }

  // This is called in the child process
  _Exit(EXIT_SUCCESS);
}
  LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS * ExceptionInfo)
  {
    switch(ExceptionInfo->ExceptionRecord->ExceptionCode)
    {
      case EXCEPTION_ACCESS_VIOLATION:
        fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);
        break;
      case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
        fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
        break;
      case EXCEPTION_BREAKPOINT:
        fputs("Error: EXCEPTION_BREAKPOINT\n", stderr);
        break;
      case EXCEPTION_DATATYPE_MISALIGNMENT:
        fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
        break;
      case EXCEPTION_FLT_DENORMAL_OPERAND:
        fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
        break;
      case EXCEPTION_FLT_DIVIDE_BY_ZERO:
        fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
        break;
      case EXCEPTION_FLT_INEXACT_RESULT:
        fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
        break;
      case EXCEPTION_FLT_INVALID_OPERATION:
        fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
        break;
      case EXCEPTION_FLT_OVERFLOW:
        fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr);
        break;
      case EXCEPTION_FLT_STACK_CHECK:
        fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr);
        break;
      case EXCEPTION_FLT_UNDERFLOW:
        fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr);
        break;
      case EXCEPTION_ILLEGAL_INSTRUCTION:
        fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
        break;
      case EXCEPTION_IN_PAGE_ERROR:
        fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr);
        break;
      case EXCEPTION_INT_DIVIDE_BY_ZERO:
        fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
        break;
      case EXCEPTION_INT_OVERFLOW:
        fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr);
        break;
      case EXCEPTION_INVALID_DISPOSITION:
        fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr);
        break;
      case EXCEPTION_NONCONTINUABLE_EXCEPTION:
        fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
        break;
      case EXCEPTION_PRIV_INSTRUCTION:
        fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr);
        break;
      case EXCEPTION_SINGLE_STEP:
        fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr);
        break;
      case EXCEPTION_STACK_OVERFLOW:
        fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr);
        break;
      default:
        fputs("Error: Unrecognized Exception\n", stderr);
        break;
    }
    fflush(stderr);
    /* If this is a stack overflow then we can't walk the stack, so just show
      where the error happened */
    if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode)
    {
        windows_print_stacktrace(ExceptionInfo->ContextRecord);
    }
    else
    {
#ifdef AMD64
        addr2line(icky_global_program_name, (void*)ExceptionInfo->ContextRecord->Rip);
#else
        addr2line(icky_global_program_name, (void*)ExceptionInfo->ContextRecord->Eip);
#endif
    }

    return EXCEPTION_EXECUTE_HANDLER;
  }