Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c58086c authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "More libbacktrace fixes."

parents 36d44740 8ed46278
Loading
Loading
Loading
Loading
+12 −11
Original line number Diff line number Diff line
@@ -25,7 +25,16 @@ class BacktraceImpl;

class Backtrace {
public:
  Backtrace(BacktraceImpl* impl);
  // Create the correct Backtrace object based on what is to be unwound.
  // If pid < 0 or equals the current pid, then the Backtrace object
  // corresponds to the current process.
  // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace
  // object corresponds to a thread in the current process.
  // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a
  // different process.
  // Tracing a thread in a different process is not supported.
  static Backtrace* Create(pid_t pid, pid_t tid);

  virtual ~Backtrace();

  // Get the current stack trace and store in the backtrace_ structure.
@@ -60,17 +69,9 @@ public:
    return &backtrace_.frames[frame_num];
  }

  // Create the correct Backtrace object based on what is to be unwound.
  // If pid < 0 or equals the current pid, then the Backtrace object
  // corresponds to the current process.
  // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace
  // object corresponds to a thread in the current process.
  // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a
  // different process.
  // Tracing a thread in a different process is not supported.
  static Backtrace* Create(pid_t pid, pid_t tid);

protected:
  Backtrace(BacktraceImpl* impl);

  virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);

  BacktraceImpl* impl_;
+9 −14
Original line number Diff line number Diff line
@@ -72,10 +72,8 @@ bool Backtrace::Unwind(size_t num_ignore_frames) {
  return impl_->Unwind(num_ignore_frames);
}

__BEGIN_DECLS
extern char* __cxa_demangle (const char* mangled, char* buf, size_t* len,
extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
                                int* status);
__END_DECLS

std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
  std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
@@ -97,7 +95,7 @@ std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {

bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
  if (ptr & 3) {
    ALOGW("Backtrace::verifyReadWordArgs: invalid pointer %p", (void*)ptr);
    BACK_LOGW("invalid pointer %p", (void*)ptr);
    *out_value = (uint32_t)-1;
    return false;
  }
@@ -172,7 +170,7 @@ bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
    *out_value = *reinterpret_cast<uint32_t*>(ptr);
    return true;
  } else {
    ALOGW("BacktraceCurrent::readWord: pointer %p not in a readbale map", reinterpret_cast<void*>(ptr));
    BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
    *out_value = static_cast<uint32_t>(-1);
    return false;
  }
@@ -198,7 +196,7 @@ bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
  }

#if defined(__APPLE__)
  ALOGW("BacktracePtrace::readWord: MacOS does not support reading from another pid.\n");
  BACK_LOGW("MacOS does not support reading from another pid.");
  return false;
#else
  // ptrace() returns -1 and sets errno when the operation fails.
@@ -206,8 +204,8 @@ bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
  errno = 0;
  *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
  if (*out_value == static_cast<uint32_t>(-1) && errno) {
    ALOGW("BacktracePtrace::readWord: invalid pointer 0x%08x reading from tid %d, "
          "ptrace() errno=%d", ptr, Tid(), errno);
    BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
              reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
    return false;
  }
  return true;
@@ -295,11 +293,8 @@ void backtrace_format_frame_data(
    const backtrace_context_t* context, size_t frame_num, char* buf,
    size_t buf_size) {
  if (buf_size == 0 || buf == NULL) {
    ALOGW("backtrace_format_frame_data: bad call buf %p buf_size %zu\n",
          buf, buf_size);
    return;
  }
  if (context->data) {
    BACK_LOGW("bad call buf %p buf_size %zu", buf, buf_size);
  } else if (context->data) {
    Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
    std::string line = backtrace->FormatFrameData(frame_num);
    if (line.size() > buf_size) {
+4 −0
Original line number Diff line number Diff line
@@ -21,6 +21,10 @@

#include <sys/types.h>

// Macro to log the function name along with the warning message.
#define BACK_LOGW(format, ...) \
  ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)

class BacktraceImpl {
public:
  virtual ~BacktraceImpl() { }
+55 −51
Original line number Diff line number Diff line
@@ -31,55 +31,55 @@
// ThreadEntry implementation.
//-------------------------------------------------------------------------
static ThreadEntry* g_list = NULL;
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;

ThreadEntry::ThreadEntry(
    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
    : thread_intf_(intf), pid_(pid), tid_(tid), next_(NULL), prev_(NULL),
      state_(STATE_WAITING), num_ignore_frames_(num_ignore_frames) {
    : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL),
      state(STATE_WAITING), num_ignore_frames(num_ignore_frames) {
}

ThreadEntry::~ThreadEntry() {
  pthread_mutex_lock(&g_mutex);
  pthread_mutex_lock(&g_entry_mutex);
  if (g_list == this) {
    g_list = next_;
    g_list = next;
  } else {
    if (next_) {
      next_->prev_ = prev_;
    if (next) {
      next->prev = prev;
    }
    prev_->next_ = next_;
    prev->next = next;
  }
  pthread_mutex_unlock(&g_mutex);
  pthread_mutex_unlock(&g_entry_mutex);

  next_ = NULL;
  prev_ = NULL;
  next = NULL;
  prev = NULL;
}

ThreadEntry* ThreadEntry::AddThreadToUnwind(
    BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
  ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);

  pthread_mutex_lock(&g_mutex);
  pthread_mutex_lock(&g_entry_mutex);
  ThreadEntry* cur_entry = g_list;
  while (cur_entry != NULL) {
    if (cur_entry->Match(pid, tid)) {
      // There is already an entry for this pid/tid, this is bad.
      ALOGW("%s::%s(): Entry for pid %d tid %d already exists.\n",
            __FILE__, __FUNCTION__, pid, tid);
      BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);

      pthread_mutex_unlock(&g_mutex);
      pthread_mutex_unlock(&g_entry_mutex);
      return NULL;
    }
    cur_entry = cur_entry->next_;
    cur_entry = cur_entry->next;
  }

  // Add the entry to the list.
  entry->next_ = g_list;
  entry->next = g_list;
  if (g_list) {
    g_list->prev_ = entry;
    g_list->prev = entry;
  }
  g_list = entry;
  pthread_mutex_unlock(&g_mutex);
  pthread_mutex_unlock(&g_entry_mutex);

  return entry;
}
@@ -89,7 +89,7 @@ ThreadEntry* ThreadEntry::AddThreadToUnwind(
//-------------------------------------------------------------------------
static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
                          void* sigcontext) {
  if (pthread_mutex_lock(&g_mutex) == 0) {
  if (pthread_mutex_lock(&g_entry_mutex) == 0) {
    pid_t pid = getpid();
    pid_t tid = gettid();
    ThreadEntry* cur_entry = g_list;
@@ -97,20 +97,19 @@ static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
      if (cur_entry->Match(pid, tid)) {
        break;
      }
      cur_entry = cur_entry->next_;
      cur_entry = cur_entry->next;
    }
    pthread_mutex_unlock(&g_mutex);
    pthread_mutex_unlock(&g_entry_mutex);
    if (!cur_entry) {
      ALOGW("%s::%s(): Unable to find pid %d tid %d information\n",
            __FILE__, __FUNCTION__, pid, tid);
      BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
      return;
    }

    if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state_) == 0) {
      cur_entry->thread_intf_->ThreadUnwind(siginfo, sigcontext,
                                            cur_entry->num_ignore_frames_);
    if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) {
      cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext,
                                           cur_entry->num_ignore_frames);
    }
    android_atomic_release_store(STATE_DONE, &cur_entry->state_);
    android_atomic_release_store(STATE_DONE, &cur_entry->state);
  }
}

@@ -143,18 +142,18 @@ void BacktraceThread::FinishUnwind() {
}

bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
  entry->state_ = STATE_WAITING;
  entry->state = STATE_WAITING;

  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
    ALOGW("%s::%s(): tgkill failed %s\n", __FILE__, __FUNCTION__, strerror(errno));
    BACK_LOGW("tgkill failed %s", strerror(errno));
    return false;
  }

  // Allow up to a second for the dump to occur.
  int wait_millis = 1000;
  // Allow up to ten seconds for the dump to start.
  int wait_millis = 10000;
  int32_t state;
  while (true) {
    state = android_atomic_acquire_load(&entry->state_);
    state = android_atomic_acquire_load(&entry->state);
    if (state != STATE_WAITING) {
      break;
    }
@@ -167,24 +166,22 @@ bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {

  bool cancelled = false;
  if (state == STATE_WAITING) {
    if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state_) == 0) {
      ALOGW("%s::%s(): Cancelled dump of thread %d\n", __FILE__, __FUNCTION__,
            entry->tid_);
    if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
      BACK_LOGW("Cancelled dump of thread %d", entry->tid);
      state = STATE_CANCEL;
      cancelled = true;
    } else {
      state = android_atomic_acquire_load(&entry->state_);
      state = android_atomic_acquire_load(&entry->state);
    }
  }

  // Wait for at most one minute for the dump to finish.
  wait_millis = 60000;
  while (android_atomic_acquire_load(&entry->state_) != STATE_DONE) {
  // Wait for at most ten seconds for the cancel or dump to finish.
  wait_millis = 10000;
  while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
    if (wait_millis--) {
      usleep(1000);
    } else {
      ALOGW("%s::%s(): Didn't finish thread unwind in 60 seconds.\n",
            __FILE__, __FUNCTION__);
      BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
      break;
    }
  }
@@ -202,7 +199,10 @@ bool BacktraceThread::Unwind(size_t num_ignore_frames) {
    return false;
  }

  // Prevent multiple threads trying to set the trigger action on different
  // threads at the same time.
  bool retval = false;
  if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
    struct sigaction act, oldact;
    memset(&act, 0, sizeof(act));
    act.sa_sigaction = SignalHandler;
@@ -212,7 +212,11 @@ bool BacktraceThread::Unwind(size_t num_ignore_frames) {
      retval = TriggerUnwindOnThread(entry);
      sigaction(SIGURG, &oldact, NULL);
    } else {
    ALOGW("%s::%s(): sigaction failed %s\n", __FILE__, __FUNCTION__, strerror(errno));
      BACK_LOGW("sigaction failed %s", strerror(errno));
    }
    pthread_mutex_unlock(&g_sigaction_mutex);
  } else {
    BACK_LOGW("unable to acquire sigaction mutex.");
  }

  if (retval) {
+9 −10
Original line number Diff line number Diff line
@@ -32,26 +32,25 @@ typedef enum {

class BacktraceThreadInterface;

class ThreadEntry {
public:
struct ThreadEntry {
  ThreadEntry(
      BacktraceThreadInterface* impl, pid_t pid, pid_t tid,
      size_t num_ignore_frames);
  ~ThreadEntry();

  bool Match(pid_t pid, pid_t tid) { return (pid == pid_ && tid == tid_); }
  bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid && chk_tid == tid); }

  static ThreadEntry* AddThreadToUnwind(
      BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid,
      size_t num_ignored_frames);

  BacktraceThreadInterface* thread_intf_;
  pid_t pid_;
  pid_t tid_;
  ThreadEntry* next_;
  ThreadEntry* prev_;
  int32_t state_;
  int num_ignore_frames_;
  BacktraceThreadInterface* thread_intf;
  pid_t pid;
  pid_t tid;
  ThreadEntry* next;
  ThreadEntry* prev;
  int32_t state;
  int num_ignore_frames;
};

// Interface class that does not contain any local storage, only defines
Loading