예제 #1
0
/// @brief Invokes addr2line utility to determine the function name
/// and the line information from an address in the code segment.
static char *addr2line(const char *image, void *addr, bool color_output,
                       char** memory) {
  int pipefd[2];
  if (pipe(pipefd) != 0) {
    safe_abort();
  }
  pid_t pid = fork();
  if (pid == 0) {
    close(pipefd[0]);
    dup2(pipefd[1], STDOUT_FILENO);
    dup2(pipefd[1], STDERR_FILENO);
    if (execlp("addr2line", "addr2line",
               Safe::ptoa(addr, *memory), "-f", "-C", "-e", image,
               reinterpret_cast<void*>(NULL)) == -1) {
      safe_abort();
    }
  }

  close(pipefd[1]);
  const int line_max_length = 4096;
  char* line = *memory; 
  *memory += line_max_length;
  ssize_t len = read(pipefd[0], line, line_max_length);  
  close(pipefd[0]);
  if (len == 0) {
    safe_abort();
  }
  line[len] = 0;

  if (waitpid(pid, NULL, 0) != pid) {
    safe_abort();
  }
  if (line[0] == '?') {
    char* straddr = Safe::ptoa(addr, *memory);
    if (color_output) {
      strcpy(line, "\033[32;1m");  // NOLINT(runtime/printf)
    }
    strcat(line, straddr);  // NOLINT(runtime/printf)
    if (color_output) {
      strcat(line, "\033[0m");  // NOLINT(runtime/printf)
    }
    strcat(line, " at ");  // NOLINT(runtime/printf)
    strcat(line, image);  // NOLINT(runtime/printf)
    strcat(line, " ");  // NOLINT(runtime/printf)
  } else {
    if (*(strstr(line, "\n") + 1) == '?') {
      char* straddr = Safe::ptoa(addr, *memory);
      strcpy(strstr(line, "\n") + 1, image);  // NOLINT(runtime/printf)
      strcat(line, ":");  // NOLINT(runtime/printf)
      strcat(line, straddr);  // NOLINT(runtime/printf)
      strcat(line, "\n");  // NOLINT(runtime/printf)
    }
  }
  return line;
}
예제 #2
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);
}
예제 #3
0
/// @brief Invokes addr2line utility to determine the function name
/// and the line information from an address in the code segment.
static char *addr2line(const char *image, void *addr, bool color_output,
                       char** memory) {
  int pipefd[2];
  if (pipe(pipefd) != 0) {
    safe_abort();
  }
  char* line = *memory;
  pid_t pid = fork();
  if (pid == 0) {
    close(pipefd[0]);
    dup2(pipefd[1], STDOUT_FILENO);
    dup2(pipefd[1], STDERR_FILENO);
    if (execlp("addr2line", "addr2line",
               Safe::ptoa(addr, *memory), "-f", "-C", "-e", image,
               reinterpret_cast<void*>(NULL)) == -1) {
      char* result = (char*)"??\n??:0\n";

      int32_t totalBytesWritten = 0;
	  while (totalBytesWritten < 9)
	  {
		int32_t bytesWritten = write(pipefd[1], result, 9);;
		if(bytesWritten <= 0)
		{
			if(bytesWritten == -1 && errno == EINTR) continue;
			else safe_abort();
		}
		totalBytesWritten += bytesWritten;
	  }
      safe_abort();
    }
  }
  else if(pid > 0)
  {
	  close(pipefd[1]);
	  const int line_max_length = 4096;
	  *memory += line_max_length;
	  ssize_t len = read(pipefd[0], line, line_max_length);
	  close(pipefd[0]);
	  if (len == 0) {
		safe_abort();
	  }
	  line[len] = 0;

	  if (waitpid(pid, NULL, 0) != pid) {
		safe_abort();
	  }
	  if (line[0] == '?') {
		char* straddr = Safe::ptoa(addr, *memory);
		if (color_output) {
		  strcpy(line, "\033[32;1m");  // NOLINT(runtime/printf)
		}
		strcat(line, straddr);  // NOLINT(runtime/printf)
		if (color_output) {
		  strcat(line, "\033[0m");  // NOLINT(runtime/printf)
		}
		strcat(line, " at ");  // NOLINT(runtime/printf)
		strcat(line, image);  // NOLINT(runtime/printf)
		strcat(line, " ");  // NOLINT(runtime/printf)
	  } else {
		if (*(strstr(line, "\n") + 1) == '?') {
		  char* straddr = Safe::ptoa(addr, *memory);
		  strcpy(strstr(line, "\n") + 1, image);  // NOLINT(runtime/printf)
		  strcat(line, ":");  // NOLINT(runtime/printf)
		  strcat(line, straddr);  // NOLINT(runtime/printf)
		  strcat(line, "\n");  // NOLINT(runtime/printf)
		}
	  }
  }
  return line;
}