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

Commit 6b7b6541 authored by Christopher Ferris's avatar Christopher Ferris Committed by Android Git Automerger
Browse files

am b5c24e09: am 8c58086c: Merge "More libbacktrace fixes."

* commit 'b5c24e09':
  More libbacktrace fixes.
parents 39f18c9e b5c24e09
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