summaryrefslogtreecommitdiff
path: root/simpleperf/OfflineUnwinder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/OfflineUnwinder.cpp')
-rw-r--r--simpleperf/OfflineUnwinder.cpp119
1 files changed, 49 insertions, 70 deletions
diff --git a/simpleperf/OfflineUnwinder.cpp b/simpleperf/OfflineUnwinder.cpp
index 1593fb64..e166d846 100644
--- a/simpleperf/OfflineUnwinder.cpp
+++ b/simpleperf/OfflineUnwinder.cpp
@@ -16,18 +16,17 @@
#include "OfflineUnwinder.h"
-#include <inttypes.h>
#include <sys/mman.h>
#include <unordered_map>
#include <android-base/logging.h>
-#include <android-base/parseint.h>
#include <unwindstack/MachineArm.h>
#include <unwindstack/MachineArm64.h>
#include <unwindstack/MachineX86.h>
#include <unwindstack/MachineX86_64.h>
#include <unwindstack/Maps.h>
+#include <unwindstack/Regs.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
#include <unwindstack/RegsX86.h>
@@ -38,45 +37,27 @@
#include <unwindstack/UserX86.h>
#include <unwindstack/UserX86_64.h>
-#include "JITDebugReader.h"
-#include "OfflineUnwinder_impl.h"
#include "environment.h"
+#include "OfflineUnwinder_impl.h"
#include "perf_regs.h"
#include "read_apk.h"
#include "thread_tree.h"
-namespace simpleperf {
-
-// unwindstack only builds on linux. So simpleperf redefines flags in unwindstack, to use them on
-// darwin/windows. Use static_assert to make sure they are on the same page.
-static_assert(map_flags::PROT_JIT_SYMFILE_MAP == unwindstack::MAPS_FLAGS_JIT_SYMFILE_MAP);
+static_assert(simpleperf::map_flags::PROT_JIT_SYMFILE_MAP ==
+ unwindstack::MAPS_FLAGS_JIT_SYMFILE_MAP, "");
-#define CHECK_ERROR_CODE(error_code_name) \
- static_assert(UnwindStackErrorCode::error_code_name == unwindstack::ErrorCode::error_code_name)
-
-CHECK_ERROR_CODE(ERROR_NONE);
-CHECK_ERROR_CODE(ERROR_MEMORY_INVALID);
-CHECK_ERROR_CODE(ERROR_UNWIND_INFO);
-CHECK_ERROR_CODE(ERROR_UNSUPPORTED);
-CHECK_ERROR_CODE(ERROR_INVALID_MAP);
-CHECK_ERROR_CODE(ERROR_MAX_FRAMES_EXCEEDED);
-CHECK_ERROR_CODE(ERROR_REPEATED_FRAME);
-CHECK_ERROR_CODE(ERROR_INVALID_ELF);
-CHECK_ERROR_CODE(ERROR_THREAD_DOES_NOT_EXIST);
-CHECK_ERROR_CODE(ERROR_THREAD_TIMEOUT);
-CHECK_ERROR_CODE(ERROR_SYSTEM_CALL);
-CHECK_ERROR_CODE(ERROR_MAX);
+namespace simpleperf {
// Max frames seen so far is 463, in http://b/110923759.
static constexpr size_t MAX_UNWINDING_FRAMES = 512;
-unwindstack::Regs* OfflineUnwinderImpl::GetBacktraceRegs(const RegSet& regs) {
+static unwindstack::Regs* GetBacktraceRegs(const RegSet& regs) {
switch (regs.arch) {
case ARCH_ARM: {
unwindstack::arm_user_regs arm_user_regs;
memset(&arm_user_regs, 0, sizeof(arm_user_regs));
- static_assert(static_cast<int>(unwindstack::ARM_REG_R0) == static_cast<int>(PERF_REG_ARM_R0),
- "");
+ static_assert(
+ static_cast<int>(unwindstack::ARM_REG_R0) == static_cast<int>(PERF_REG_ARM_R0), "");
static_assert(
static_cast<int>(unwindstack::ARM_REG_LAST) == static_cast<int>(PERF_REG_ARM_MAX), "");
for (size_t i = unwindstack::ARM_REG_R0; i < unwindstack::ARM_REG_LAST; ++i) {
@@ -95,10 +76,7 @@ unwindstack::Regs* OfflineUnwinderImpl::GetBacktraceRegs(const RegSet& regs) {
sizeof(uint64_t) * (PERF_REG_ARM64_LR - PERF_REG_ARM64_X0 + 1));
arm64_user_regs.sp = regs.data[PERF_REG_ARM64_SP];
arm64_user_regs.pc = regs.data[PERF_REG_ARM64_PC];
- auto regs =
- static_cast<unwindstack::RegsArm64*>(unwindstack::RegsArm64::Read(&arm64_user_regs));
- regs->SetPACMask(arm64_pac_mask_);
- return regs;
+ return unwindstack::RegsArm64::Read(&arm64_user_regs);
}
case ARCH_X86_32: {
unwindstack::x86_user_regs x86_user_regs;
@@ -142,8 +120,7 @@ unwindstack::Regs* OfflineUnwinderImpl::GetBacktraceRegs(const RegSet& regs) {
}
static unwindstack::MapInfo* CreateMapInfo(const MapEntry* entry) {
- std::string name_holder;
- const char* name = entry->dso->GetDebugFilePath().data();
+ const char* name = entry->dso->GetDebugFilePath().c_str();
uint64_t pgoff = entry->pgoff;
auto tuple = SplitUrlInApk(entry->dso->GetDebugFilePath());
if (std::get<0>(tuple)) {
@@ -151,18 +128,9 @@ static unwindstack::MapInfo* CreateMapInfo(const MapEntry* entry) {
// the previous format (apk, offset).
EmbeddedElf* elf = ApkInspector::FindElfInApkByName(std::get<1>(tuple), std::get<2>(tuple));
if (elf != nullptr) {
- name = elf->filepath().data();
+ name = elf->filepath().c_str();
pgoff += elf->entry_offset();
}
- } else if (entry->flags & map_flags::PROT_JIT_SYMFILE_MAP) {
- // Remove location_in_file suffix, which isn't recognized by libunwindstack.
- const std::string& path = entry->dso->GetDebugFilePath();
- if (JITDebugReader::IsPathInJITSymFile(path)) {
- size_t colon_pos = path.rfind(':');
- CHECK_NE(colon_pos, std::string::npos);
- name_holder = path.substr(0, colon_pos);
- name = name_holder.data();
- }
}
return new unwindstack::MapInfo(nullptr, nullptr, entry->start_addr, entry->get_end_addr(), pgoff,
PROT_READ | entry->flags, name);
@@ -205,39 +173,29 @@ void UnwindMaps::UpdateMaps(const MapSet& map_set) {
maps_.begin());
}
- std::sort(entries_.begin(), entries_.end(),
- [](const auto& e1, const auto& e2) { return e1->start_addr < e2->start_addr; });
+ std::sort(entries_.begin(), entries_.end(), [](const auto& e1, const auto& e2) {
+ return e1->start_addr < e2->start_addr;
+ });
// Use Sort() to sort maps_ and create prev_real_map links.
// prev_real_map is needed by libunwindstack to find the start of an embedded lib in an apk.
// See http://b/120981155.
Sort();
}
-void OfflineUnwinder::CollectMetaInfo(std::unordered_map<std::string, std::string>* info_map
- __attribute__((unused))) {
-#if defined(__aarch64__)
- // Find pac_mask for ARMv8.3-A Pointer Authentication by below steps:
- // 1. Create a 64 bit value with every bit set, but clear bit 55. Because linux user space uses
- // TTBR0.
- // 2. Use XPACLRI to clear auth code bits.
- // 3. Flip every bit to get pac_mask, excluding bit 55.
- // We can also use ptrace(PTRACE_GETREGSET, pid, NT_ARM_PAC_MASK). But it needs a tracee.
- register uint64_t x30 __asm("x30") = ~(1ULL << 55);
- // This is XPACLRI on ARMv8.3-A, and nop on prev ARMv8.3-A.
- asm("hint 0x7" : "+r"(x30));
- uint64_t pac_mask = ~x30 & ~(1ULL << 55);
- if (pac_mask != 0) {
- (*info_map)[META_KEY_ARM64_PAC_MASK] = android::base::StringPrintf("0x%" PRIx64, pac_mask);
+class OfflineUnwinderImpl : public OfflineUnwinder {
+ public:
+ OfflineUnwinderImpl(bool collect_stat) : collect_stat_(collect_stat) {
+ unwindstack::Elf::SetCachingEnabled(true);
}
-#endif
-}
-void OfflineUnwinderImpl::LoadMetaInfo(
- const std::unordered_map<std::string, std::string>& info_map) {
- if (auto it = info_map.find(META_KEY_ARM64_PAC_MASK); it != info_map.end()) {
- CHECK(android::base::ParseUint(it->second, &arm64_pac_mask_));
- }
-}
+ bool UnwindCallChain(const ThreadEntry& thread, const RegSet& regs, const char* stack,
+ size_t stack_size, std::vector<uint64_t>* ips,
+ std::vector<uint64_t>* sps) override;
+
+ private:
+ bool collect_stat_;
+ std::unordered_map<pid_t, UnwindMaps> cached_maps_;
+};
bool OfflineUnwinderImpl::UnwindCallChain(const ThreadEntry& thread, const RegSet& regs,
const char* stack, size_t stack_size,
@@ -309,8 +267,29 @@ bool OfflineUnwinderImpl::UnwindCallChain(const ThreadEntry& thread, const RegSe
}
if (collect_stat_) {
unwinding_result_.used_time = GetSystemClock() - start_time;
- unwinding_result_.error_code = unwinder.LastErrorCode();
- unwinding_result_.error_addr = unwinder.LastErrorAddress();
+ switch (unwinder.LastErrorCode()) {
+ case unwindstack::ERROR_MAX_FRAMES_EXCEEDED:
+ unwinding_result_.stop_reason = UnwindingResult::EXCEED_MAX_FRAMES_LIMIT;
+ break;
+ case unwindstack::ERROR_MEMORY_INVALID: {
+ uint64_t addr = unwinder.LastErrorAddress();
+ // Because we don't have precise stack range here, just guess an addr is in stack
+ // if sp - 128K <= addr <= sp.
+ if (addr <= stack_addr && addr >= stack_addr - 128 * 1024) {
+ unwinding_result_.stop_reason = UnwindingResult::ACCESS_STACK_FAILED;
+ } else {
+ unwinding_result_.stop_reason = UnwindingResult::ACCESS_MEM_FAILED;
+ }
+ unwinding_result_.stop_info.addr = addr;
+ break;
+ }
+ case unwindstack::ERROR_INVALID_MAP:
+ unwinding_result_.stop_reason = UnwindingResult::MAP_MISSING;
+ break;
+ default:
+ unwinding_result_.stop_reason = UnwindingResult::UNKNOWN_REASON;
+ break;
+ }
unwinding_result_.stack_start = stack_addr;
unwinding_result_.stack_end = stack_addr + stack_size;
}