bool UnwindPtrace::Init() {
  if (upt_info_) {
    return true;
  }

  if (addr_space_) {
    // If somehow the addr_space_ gets initialized but upt_info_ doesn't,
    // then that indicates there is some kind of failure.
    return false;
  }

  addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
  if (!addr_space_) {
    BACK_LOGW("unw_create_addr_space failed.");
    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
    return false;
  }

  UnwindMap* map = static_cast<UnwindMap*>(GetMap());
  unw_map_set(addr_space_, map->GetMapCursor());

  upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid()));
  if (!upt_info_) {
    BACK_LOGW("Failed to create upt info.");
    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
    return false;
  }

  return true;
}
bool BacktraceThread::Unwind(size_t num_ignore_frames) {
  ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
      thread_intf_, Pid(), Tid(), num_ignore_frames);
  if (!entry) {
    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;
    act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
    sigemptyset(&act.sa_mask);
    if (sigaction(SIGURG, &act, &oldact) == 0) {
      retval = TriggerUnwindOnThread(entry);
      sigaction(SIGURG, &oldact, NULL);
    } else {
      BACK_LOGW("sigaction failed %s", strerror(errno));
    }
    pthread_mutex_unlock(&g_sigaction_mutex);
  } else {
    BACK_LOGW("unable to acquire sigaction mutex.");
  }

  if (retval) {
    FinishUnwind();
  }
  delete entry;

  return retval;
}
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
  // The cursor structure is pretty large, do not put it on the stack.
  unw_cursor_t* cursor = new unw_cursor_t;
  int ret = unw_init_local(cursor, &context_);
  if (ret < 0) {
    BACK_LOGW("unw_init_local failed %d", ret);
    delete cursor;
    return false;
  }

  std::vector<backtrace_frame_data_t>* frames = GetFrames();
  frames->reserve(MAX_BACKTRACE_FRAMES);
  size_t num_frames = 0;
  do {
    unw_word_t pc;
    ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    if (num_ignore_frames == 0) {
      frames->resize(num_frames+1);
      backtrace_frame_data_t* frame = &frames->at(num_frames);
      frame->num = num_frames;
      frame->pc = static_cast<uintptr_t>(pc);
      frame->sp = static_cast<uintptr_t>(sp);
      frame->stack_size = 0;

      if (num_frames > 0) {
        // Set the stack size for the previous frame.
        backtrace_frame_data_t* prev = &frames->at(num_frames-1);
        prev->stack_size = frame->sp - prev->sp;
      }

      if (resolve) {
        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
        frame->map = FindMap(frame->pc);
      } else {
        frame->map = NULL;
        frame->func_offset = 0;
      }
      num_frames++;
    } else {
      num_ignore_frames--;
    }
    ret = unw_step (cursor);
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

  delete cursor;
  return true;
}
bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) {
  if (context == nullptr) {
    BACK_LOGW("The context is needed for offline backtracing.");
    return false;
  }
  context_ = context;

  unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0);
  unw_cursor_t cursor;
  int ret = unw_init_remote(&cursor, addr_space, this);
  if (ret != 0) {
    BACK_LOGW("unw_init_remote failed %d", ret);
    unw_destroy_addr_space(addr_space);
    return false;
  }
  size_t num_frames = 0;
  do {
    unw_word_t pc;
    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    if (num_ignore_frames == 0) {
      frames_.resize(num_frames + 1);
      backtrace_frame_data_t* frame = &frames_[num_frames];
      frame->num = num_frames;
      frame->pc = static_cast<uintptr_t>(pc);
      frame->sp = static_cast<uintptr_t>(sp);
      frame->stack_size = 0;

      if (num_frames > 0) {
        backtrace_frame_data_t* prev = &frames_[num_frames - 1];
        prev->stack_size = frame->sp - prev->sp;
      }
      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
      FillInMap(frame->pc, &frame->map);
      num_frames++;
    } else {
      num_ignore_frames--;
    }
    ret = unw_step(&cursor);
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

  unw_destroy_addr_space(addr_space);
  context_ = nullptr;
  return true;
}
bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (ucontext) {
    // Unwind using an already existing ucontext.
    return impl_->Unwind(num_ignore_frames, ucontext);
  }

  // Prevent multiple threads trying to set the trigger action on different
  // threads at the same time.
  if (pthread_mutex_lock(&g_sigaction_mutex) < 0) {
    BACK_LOGW("sigaction failed: %s", strerror(errno));
    return false;
  }

  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
  entry->Lock();

  struct sigaction act, oldact;
  memset(&act, 0, sizeof(act));
  act.sa_sigaction = SignalHandler;
  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
  sigemptyset(&act.sa_mask);
  if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
    BACK_LOGW("sigaction failed %s", strerror(errno));
    entry->Unlock();
    ThreadEntry::Remove(entry);
    pthread_mutex_unlock(&g_sigaction_mutex);
    return false;
  }

  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
    BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
    sigaction(THREAD_SIGNAL, &oldact, NULL);
    entry->Unlock();
    ThreadEntry::Remove(entry);
    pthread_mutex_unlock(&g_sigaction_mutex);
    return false;
  }

  // Wait for the thread to get the ucontext.
  entry->Wait(0);

  // After the thread has received the signal, allow other unwinders to
  // continue.
  sigaction(THREAD_SIGNAL, &oldact, NULL);
  pthread_mutex_unlock(&g_sigaction_mutex);

  bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext());

  // Tell the signal handler to exit and release the entry.
  entry->Wake();

  return unwind_done;
}
//-------------------------------------------------------------------------
// BacktraceThread functions.
//-------------------------------------------------------------------------
static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
                          void* sigcontext) {
  if (pthread_mutex_lock(&g_entry_mutex) == 0) {
    pid_t pid = getpid();
    pid_t tid = gettid();
    ThreadEntry* cur_entry = g_list;
    while (cur_entry) {
      if (cur_entry->Match(pid, tid)) {
        break;
      }
      cur_entry = cur_entry->next;
    }
    pthread_mutex_unlock(&g_entry_mutex);
    if (!cur_entry) {
      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);
    }
    android_atomic_release_store(STATE_DONE, &cur_entry->state);
  }
}
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_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.
      BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);

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

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

  return entry;
}
bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
  if (ptr & 3) {
    BACK_LOGW("invalid pointer %p", (void*)ptr);
    *out_value = (uint32_t)-1;
    return false;
  }
  return true;
}
bool UnwindCurrent::Unwind(size_t num_ignore_frames) {
  int ret = unw_getcontext(&context_);
  if (ret < 0) {
    BACK_LOGW("unw_getcontext failed %d", ret);
    return false;
  }
  return UnwindFromContext(num_ignore_frames, true);
}
bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
  entry->state = STATE_WAITING;

  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
    BACK_LOGW("tgkill failed %s", strerror(errno));
    return false;
  }

  // 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);
    if (state != STATE_WAITING) {
      break;
    }
    if (wait_millis--) {
      usleep(1000);
    } else {
      break;
    }
  }

  bool cancelled = false;
  if (state == STATE_WAITING) {
    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);
    }
  }

  // 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 {
      BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
      break;
    }
  }
  return !cancelled;
}
void ThreadEntry::Wait(int value) {
  timespec ts;
  ts.tv_sec = 10;
  ts.tv_nsec = 0;
  errno = 0;
  futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0);
  if (errno != 0 && errno != EWOULDBLOCK) {
    BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno));
  }
}
static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) {
  // ptrace() returns -1 and sets errno when the operation fails.
  // To disambiguate -1 from a valid result, we clear errno beforehand.
  errno = 0;
  *out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr);
  if (*out_value == static_cast<word_t>(-1) && errno) {
    BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
              reinterpret_cast<void*>(addr), tid, strerror(errno));
    return false;
  }
  return true;
}
bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
  if (!VerifyReadWordArgs(ptr, out_value)) {
    return false;
  }

#if defined(__APPLE__)
  BACK_LOGW("MacOS does not support reading from another pid.");
  return false;
#else
  // ptrace() returns -1 and sets errno when the operation fails.
  // To disambiguate -1 from a valid result, we clear errno beforehand.
  errno = 0;
  *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
  if (*out_value == static_cast<uint32_t>(-1) && 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;
#endif
}
size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
#if defined(__APPLE__)
  BACK_LOGW("MacOS does not support reading from another pid.");
  return 0;
#else
  backtrace_map_t map;
  FillInMap(addr, &map);
  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
    return 0;
  }

  bytes = MIN(map.end - addr, bytes);
  size_t bytes_read = 0;
  word_t data_word;
  size_t align_bytes = addr & (sizeof(word_t) - 1);
  if (align_bytes != 0) {
    if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
      return 0;
    }
    align_bytes = sizeof(word_t) - align_bytes;
    memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes,
           align_bytes);
    addr += align_bytes;
    buffer += align_bytes;
    bytes -= align_bytes;
    bytes_read += align_bytes;
  }

  size_t num_words = bytes / sizeof(word_t);
  for (size_t i = 0; i < num_words; i++) {
    if (!PtraceRead(Tid(), addr, &data_word)) {
      return bytes_read;
    }
    memcpy(buffer, &data_word, sizeof(word_t));
    buffer += sizeof(word_t);
    addr += sizeof(word_t);
    bytes_read += sizeof(word_t);
  }

  size_t left_over = bytes & (sizeof(word_t) - 1);
  if (left_over) {
    if (!PtraceRead(Tid(), addr, &data_word)) {
      return bytes_read;
    }
    memcpy(buffer, &data_word, left_over);
    bytes_read += left_over;
  }
  return bytes_read;
#endif
}
bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
  if (!VerifyReadWordArgs(ptr, out_value)) {
    return false;
  }

  const backtrace_map_t* map = FindMap(ptr);
  if (map && map->flags & PROT_READ) {
    *out_value = *reinterpret_cast<uint32_t*>(ptr);
    return true;
  } else {
    BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
    *out_value = static_cast<uint32_t>(-1);
    return false;
  }
}
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) {
    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) {
      memcpy(buf, line.c_str(), buf_size-1);
      buf[buf_size] = '\0';
    } else {
      memcpy(buf, line.c_str(), line.size()+1);
    }
  }
}
static void SignalHandler(int, siginfo_t*, void* sigcontext) {
  ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
  if (!entry) {
    BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid());
    return;
  }

  entry->CopyUcontext(reinterpret_cast<ucontext_t*>(sigcontext));

  // Indicate the ucontext is now valid.
  entry->Wake();

  // Pause the thread until the unwind is complete. This avoids having
  // the thread run ahead causing problems.
  entry->Wait(1);

  ThreadEntry::Remove(entry);
}
bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
#if defined(__APPLE__)
  BACK_LOGW("MacOS does not support reading from another pid.");
  return false;
#else
  if (!VerifyReadWordArgs(ptr, out_value)) {
    return false;
  }

  backtrace_map_t map;
  FillInMap(ptr, &map);
  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
    return false;
  }

  return PtraceRead(Tid(), ptr, out_value);
#endif
}
bool ThreadEntry::Wait(int value) {
  timespec ts;
  clock_gettime(CLOCK_MONOTONIC, &ts);
  ts.tv_sec += 5;

  bool wait_completed = true;
  pthread_mutex_lock(&wait_mutex_);
  while (wait_value_ != value) {
    int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
    if (ret != 0) {
      BACK_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
      wait_completed = false;
      break;
    }
  }
  pthread_mutex_unlock(&wait_mutex_);

  return wait_completed;
}
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (ucontext == nullptr) {
    int ret = unw_getcontext(&context_);
    if (ret < 0) {
      BACK_LOGW("unw_getcontext failed %d", ret);
      return false;
    }
  } else {
    GetUnwContextFromUcontext(ucontext);
  }

  // The cursor structure is pretty large, do not put it on the stack.
  std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
  int ret = unw_init_local(cursor.get(), &context_);
  if (ret < 0) {
    BACK_LOGW("unw_init_local failed %d", ret);
    return false;
  }

  size_t num_frames = 0;
  do {
    unw_word_t pc;
    ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    frames_.resize(num_frames+1);
    backtrace_frame_data_t* frame = &frames_.at(num_frames);
    frame->num = num_frames;
    frame->pc = static_cast<uintptr_t>(pc);
    frame->sp = static_cast<uintptr_t>(sp);
    frame->stack_size = 0;

    FillInMap(frame->pc, &frame->map);
    // Check to see if we should skip this frame because it's coming
    // from within the library, and we are doing a local unwind.
    if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
      if (num_ignore_frames == 0) {
        // GetFunctionName is an expensive call, only do it if we are
        // keeping the frame.
        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
        if (num_frames > 0) {
          // Set the stack size for the previous frame.
          backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
          prev->stack_size = frame->sp - prev->sp;
        }
        num_frames++;
      } else {
        num_ignore_frames--;
      }
    }
    ret = unw_step (cursor.get());
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

  return true;
}
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (GetMap() == nullptr) {
    // Without a map object, we can't do anything.
    return false;
  }

  if (ucontext) {
    BACK_LOGW("Unwinding from a specified context not supported yet.");
    return false;
  }

  addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
  if (!addr_space_) {
    BACK_LOGW("unw_create_addr_space failed.");
    return false;
  }

  UnwindMap* map = static_cast<UnwindMap*>(GetMap());
  unw_map_set(addr_space_, map->GetMapCursor());

  upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid()));
  if (!upt_info_) {
    BACK_LOGW("Failed to create upt info.");
    return false;
  }

  unw_cursor_t cursor;
  int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
  if (ret < 0) {
    BACK_LOGW("unw_init_remote failed %d", ret);
    return false;
  }

  size_t num_frames = 0;
  do {
    unw_word_t pc;
    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    if (num_ignore_frames == 0) {
      frames_.resize(num_frames+1);
      backtrace_frame_data_t* frame = &frames_.at(num_frames);
      frame->num = num_frames;
      frame->pc = static_cast<uintptr_t>(pc);
      frame->sp = static_cast<uintptr_t>(sp);
      frame->stack_size = 0;

      if (num_frames > 0) {
        backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
        prev->stack_size = frame->sp - prev->sp;
      }

      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);

      FillInMap(frame->pc, &frame->map);

      num_frames++;
    } else {
      num_ignore_frames--;
    }
    ret = unw_step (&cursor);
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

  return true;
}
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (ucontext == nullptr) {
    int ret = unw_getcontext(&context_);
    if (ret < 0) {
      BACK_LOGW("unw_getcontext failed %d", ret);
      error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
      return false;
    }
  } else {
    GetUnwContextFromUcontext(ucontext);
  }

  // The cursor structure is pretty large, do not put it on the stack.
  std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
  int ret = unw_init_local(cursor.get(), &context_);
  if (ret < 0) {
    BACK_LOGW("unw_init_local failed %d", ret);
    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
    return false;
  }
  initialized_ = true;

  size_t num_frames = 0;
  do {
    unw_word_t pc;
    ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    frames_.resize(num_frames+1);
    backtrace_frame_data_t* frame = &frames_.at(num_frames);
    frame->num = num_frames;
    frame->pc = static_cast<uintptr_t>(pc);
    frame->sp = static_cast<uintptr_t>(sp);
    frame->stack_size = 0;

    FillInMap(frame->pc, &frame->map);
    // Check to see if we should skip this frame because it's coming
    // from within the library, and we are doing a local unwind.
    if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
      if (num_ignore_frames == 0) {
        // GetFunctionName is an expensive call, only do it if we are
        // keeping the frame.
        frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
        if (num_frames > 0) {
          // Set the stack size for the previous frame.
          backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
          prev->stack_size = frame->sp - prev->sp;
        }
        if (BacktraceMap::IsValid(frame->map)) {
          frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias;
        } else {
          frame->rel_pc = frame->pc;
        }
        num_frames++;
      } else {
        num_ignore_frames--;
        // Set the number of frames to zero to remove the frame added
        // above. By definition, if we still have frames to ignore
        // there should only be one frame in the vector.
        CHECK(num_frames == 0);
        frames_.resize(0);
      }
    }
    // If the pc is in a device map, then don't try to step.
    if (frame->map.flags & PROT_DEVICE_MAP) {
      break;
    }
    // Verify the sp is not in a device map too.
    backtrace_map_t map;
    FillInMap(frame->sp, &map);
    if (map.flags & PROT_DEVICE_MAP) {
      break;
    }
    ret = unw_step (cursor.get());
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

  return true;
}
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (GetMap() == nullptr) {
    // Without a map object, we can't do anything.
    error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
    return false;
  }

  error_ = BACKTRACE_UNWIND_NO_ERROR;

  if (ucontext) {
    BACK_LOGW("Unwinding from a specified context not supported yet.");
    error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
    return false;
  }

  if (!Init()) {
    return false;
  }

  unw_cursor_t cursor;
  int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
  if (ret < 0) {
    BACK_LOGW("unw_init_remote failed %d", ret);
    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
    return false;
  }

  size_t num_frames = 0;
  do {
    unw_word_t pc;
    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    if (num_ignore_frames == 0) {
      frames_.resize(num_frames+1);
      backtrace_frame_data_t* frame = &frames_.at(num_frames);
      frame->num = num_frames;
      frame->pc = static_cast<uintptr_t>(pc);
      frame->sp = static_cast<uintptr_t>(sp);
      frame->stack_size = 0;

      if (num_frames > 0) {
        backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
        prev->stack_size = frame->sp - prev->sp;
      }

      FillInMap(frame->pc, &frame->map);
      if (BacktraceMap::IsValid(frame->map)) {
        frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias;
      } else {
        frame->rel_pc = frame->pc;
      }

      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);

      num_frames++;
      // If the pc is in a device map, then don't try to step.
      if (frame->map.flags & PROT_DEVICE_MAP) {
        break;
      }
    } else {
      // If the pc is in a device map, then don't try to step.
      backtrace_map_t map;
      FillInMap(pc, &map);
      if (map.flags & PROT_DEVICE_MAP) {
        break;
      }
      num_ignore_frames--;
    }
    // Verify the sp is not in a device map.
    backtrace_map_t map;
    FillInMap(sp, &map);
    if (map.flags & PROT_DEVICE_MAP) {
      break;
    }
    ret = unw_step (&cursor);
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

  return true;
}
Exemple #24
0
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (ucontext) {
    BACK_LOGW("Unwinding from a specified context not supported yet.");
    return false;
  }

  addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
  if (!addr_space_) {
    BACK_LOGW("unw_create_addr_space failed.");
    return false;
  }

  UnwindMap* map = static_cast<UnwindMap*>(GetMap());
  if (NULL == map) {
    BACK_LOGW("GetMap before unwinding failed.");
    return false;
  }
  unw_map_set(addr_space_, map->GetMapCursor());

  upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid()));
  if (!upt_info_) {
    BACK_LOGW("Failed to create upt info.");
    return false;
  }

  unw_cursor_t cursor;
  if(num_ignore_frames==0xdeaddead)
  	{
  		cursor.opaque[0]=0xdeaddead; //add for tell libunwind to unwind for kernel unwind userspace backtrace,lhd
  		BACK_LOGW(" K2U_bt call into UnwindPtrace::Unwind.");
		num_ignore_frames=0;
  	}
  int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
  if (ret < 0) {
    BACK_LOGW("unw_init_remote failed %d", ret);
    return false;
  }

  std::vector<backtrace_frame_data_t>* frames = GetFrames();
  frames->reserve(MAX_BACKTRACE_FRAMES);
  size_t num_frames = 0;
  do {
    unw_word_t pc;
    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    if (num_ignore_frames == 0) {
      frames->resize(num_frames+1);
      backtrace_frame_data_t* frame = &frames->at(num_frames);
      frame->num = num_frames;
      frame->pc = static_cast<uintptr_t>(pc);
      frame->sp = static_cast<uintptr_t>(sp);
      frame->stack_size = 0;

      if (num_frames > 0) {
        backtrace_frame_data_t* prev = &frames->at(num_frames-1);
        prev->stack_size = frame->sp - prev->sp;
      }

      frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);

      frame->map = FindMap(frame->pc);

      num_frames++;
    } else {
      num_ignore_frames--;
    }
    ret = unw_step (&cursor);
  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);

  return true;
}
bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
  addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
  if (!addr_space_) {
    BACK_LOGW("unw_create_addr_space failed.");
    return false;
  }

  upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid()));
  if (!upt_info_) {
    BACK_LOGW("Failed to create upt info.");
    return false;
  }

  backtrace_t* backtrace = GetBacktraceData();
  backtrace->num_frames = 0;

  unw_cursor_t cursor;
  int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
  if (ret < 0) {
    BACK_LOGW("unw_init_remote failed %d", ret);
    return false;
  }

  do {
    unw_word_t pc;
    ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (ret < 0) {
      BACK_LOGW("Failed to read IP %d", ret);
      break;
    }
    unw_word_t sp;
    ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
    if (ret < 0) {
      BACK_LOGW("Failed to read SP %d", ret);
      break;
    }

    if (num_ignore_frames == 0) {
      size_t num_frames = backtrace->num_frames;
      backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
      frame->pc = static_cast<uintptr_t>(pc);
      frame->sp = static_cast<uintptr_t>(sp);
      frame->stack_size = 0;
      frame->map_name = NULL;
      frame->map_offset = 0;
      frame->func_name = NULL;
      frame->func_offset = 0;

      if (num_frames > 0) {
        backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
        prev->stack_size = frame->sp - prev->sp;
      }

      std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
      if (!func_name.empty()) {
        frame->func_name = strdup(func_name.c_str());
      }

      uintptr_t map_start;
      frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
      if (frame->map_name) {
        frame->map_offset = frame->pc - map_start;
      }

      backtrace->num_frames++;
    } else {
      num_ignore_frames--;
    }
    ret = unw_step (&cursor);
  } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);

  return true;
}