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, 70 insertions, 49 deletions
diff --git a/simpleperf/OfflineUnwinder.cpp b/simpleperf/OfflineUnwinder.cpp
index e166d846..1593fb64 100644
--- a/simpleperf/OfflineUnwinder.cpp
+++ b/simpleperf/OfflineUnwinder.cpp
@@ -16,17 +16,18 @@
#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>
@@ -37,27 +38,45 @@
#include <unwindstack/UserX86.h>
#include <unwindstack/UserX86_64.h>
-#include "environment.h"
+#include "JITDebugReader.h"
#include "OfflineUnwinder_impl.h"
+#include "environment.h"
#include "perf_regs.h"
#include "read_apk.h"
#include "thread_tree.h"
-static_assert(simpleperf::map_flags::PROT_JIT_SYMFILE_MAP ==
- unwindstack::MAPS_FLAGS_JIT_SYMFILE_MAP, "");
-
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);
+
+#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);
+
// Max frames seen so far is 463, in http://b/110923759.
static constexpr size_t MAX_UNWINDING_FRAMES = 512;
-static unwindstack::Regs* GetBacktraceRegs(const RegSet& regs) {
+unwindstack::Regs* OfflineUnwinderImpl::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) {
@@ -76,7 +95,10 @@ static unwindstack::Regs* 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];
- return unwindstack::RegsArm64::Read(&arm64_user_regs);
+ auto regs =
+ static_cast<unwindstack::RegsArm64*>(unwindstack::RegsArm64::Read(&arm64_user_regs));
+ regs->SetPACMask(arm64_pac_mask_);
+ return regs;
}
case ARCH_X86_32: {
unwindstack::x86_user_regs x86_user_regs;
@@ -120,7 +142,8 @@ static unwindstack::Regs* GetBacktraceRegs(const RegSet& regs) {
}
static unwindstack::MapInfo* CreateMapInfo(const MapEntry* entry) {
- const char* name = entry->dso->GetDebugFilePath().c_str();
+ std::string name_holder;
+ const char* name = entry->dso->GetDebugFilePath().data();
uint64_t pgoff = entry->pgoff;
auto tuple = SplitUrlInApk(entry->dso->GetDebugFilePath());
if (std::get<0>(tuple)) {
@@ -128,9 +151,18 @@ 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().c_str();
+ name = elf->filepath().data();
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);
@@ -173,29 +205,39 @@ 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();
}
-class OfflineUnwinderImpl : public OfflineUnwinder {
- public:
- OfflineUnwinderImpl(bool collect_stat) : collect_stat_(collect_stat) {
- unwindstack::Elf::SetCachingEnabled(true);
+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);
}
+#endif
+}
- 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_;
-};
+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 OfflineUnwinderImpl::UnwindCallChain(const ThreadEntry& thread, const RegSet& regs,
const char* stack, size_t stack_size,
@@ -267,29 +309,8 @@ bool OfflineUnwinderImpl::UnwindCallChain(const ThreadEntry& thread, const RegSe
}
if (collect_stat_) {
unwinding_result_.used_time = GetSystemClock() - start_time;
- 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_.error_code = unwinder.LastErrorCode();
+ unwinding_result_.error_addr = unwinder.LastErrorAddress();
unwinding_result_.stack_start = stack_addr;
unwinding_result_.stack_end = stack_addr + stack_size;
}