Merge "Add BuildId to frame information."
This commit is contained in:
commit
3da5fcbf70
6 changed files with 80 additions and 31 deletions
|
|
@ -74,6 +74,7 @@ void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unwinder->SetDisplayBuildID(true);
|
||||||
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
|
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
|
||||||
_LOG(&log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(i).c_str());
|
_LOG(&log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(i).c_str());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,7 @@ static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
|
void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
|
||||||
|
unwinder->SetDisplayBuildID(true);
|
||||||
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
|
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
|
||||||
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
|
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -284,17 +284,9 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Unwinder::FormatFrame(size_t frame_num) {
|
std::string Unwinder::FormatFrame(const FrameData& frame) {
|
||||||
if (frame_num >= frames_.size()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return FormatFrame(frames_[frame_num], regs_->Is32Bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
|
|
||||||
std::string data;
|
std::string data;
|
||||||
|
if (regs_->Is32Bit()) {
|
||||||
if (is32bit) {
|
|
||||||
data += android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
|
data += android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
|
||||||
} else {
|
} else {
|
||||||
data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
|
data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
|
||||||
|
|
@ -320,9 +312,24 @@ std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
|
||||||
}
|
}
|
||||||
data += ')';
|
data += ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MapInfo* map_info = maps_->Find(frame.map_start);
|
||||||
|
if (map_info != nullptr && display_build_id_) {
|
||||||
|
std::string build_id = map_info->GetPrintableBuildID();
|
||||||
|
if (!build_id.empty()) {
|
||||||
|
data += " (BuildId: " + build_id + ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Unwinder::FormatFrame(size_t frame_num) {
|
||||||
|
if (frame_num >= frames_.size()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return FormatFrame(frames_[frame_num]);
|
||||||
|
}
|
||||||
|
|
||||||
void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
|
void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
|
||||||
jit_debug->SetArch(arch);
|
jit_debug->SetArch(arch);
|
||||||
jit_debug_ = jit_debug;
|
jit_debug_ = jit_debug;
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ class Unwinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FormatFrame(size_t frame_num);
|
std::string FormatFrame(size_t frame_num);
|
||||||
static std::string FormatFrame(const FrameData& frame, bool is32bit);
|
std::string FormatFrame(const FrameData& frame);
|
||||||
|
|
||||||
void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
|
void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
|
||||||
|
|
||||||
|
|
@ -105,6 +105,8 @@ class Unwinder {
|
||||||
// NOTE: This does nothing unless resolving names is enabled.
|
// NOTE: This does nothing unless resolving names is enabled.
|
||||||
void SetEmbeddedSoname(bool embedded_soname) { embedded_soname_ = embedded_soname; }
|
void SetEmbeddedSoname(bool embedded_soname) { embedded_soname_ = embedded_soname; }
|
||||||
|
|
||||||
|
void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
|
||||||
|
|
||||||
#if !defined(NO_LIBDEXFILE_SUPPORT)
|
#if !defined(NO_LIBDEXFILE_SUPPORT)
|
||||||
void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
|
void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -130,6 +132,7 @@ class Unwinder {
|
||||||
#endif
|
#endif
|
||||||
bool resolve_names_ = true;
|
bool resolve_names_ = true;
|
||||||
bool embedded_soname_ = true;
|
bool embedded_soname_ = true;
|
||||||
|
bool display_build_id_ = false;
|
||||||
ErrorData last_error_;
|
ErrorData last_error_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
#include <unwindstack/Memory.h>
|
#include <unwindstack/Memory.h>
|
||||||
#include <unwindstack/Regs.h>
|
#include <unwindstack/Regs.h>
|
||||||
|
|
||||||
|
#include "Check.h"
|
||||||
|
|
||||||
namespace unwindstack {
|
namespace unwindstack {
|
||||||
|
|
||||||
class RegsFake : public Regs {
|
class RegsFake : public Regs {
|
||||||
|
|
@ -47,7 +49,10 @@ class RegsFake : public Regs {
|
||||||
|
|
||||||
void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
|
void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
|
||||||
|
|
||||||
bool Is32Bit() { return false; }
|
bool Is32Bit() {
|
||||||
|
CHECK(fake_arch_ != ARCH_UNKNOWN);
|
||||||
|
return fake_arch_ == ARCH_ARM || fake_arch_ == ARCH_X86 || fake_arch_ == ARCH_MIPS;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t GetPcAdjustment(uint64_t, Elf*) override { return 2; }
|
uint64_t GetPcAdjustment(uint64_t, Elf*) override { return 2; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,9 @@ class UnwinderTest : public ::testing::Test {
|
||||||
maps_.reset(new Maps);
|
maps_.reset(new Maps);
|
||||||
|
|
||||||
ElfFake* elf = new ElfFake(new MemoryFake);
|
ElfFake* elf = new ElfFake(new MemoryFake);
|
||||||
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
|
ElfInterfaceFake* interface_fake = new ElfInterfaceFake(nullptr);
|
||||||
|
interface_fake->FakeSetBuildID("FAKE");
|
||||||
|
elf->FakeSetInterface(interface_fake);
|
||||||
AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
|
AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
|
||||||
|
|
||||||
AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
|
AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
|
||||||
|
|
@ -1102,7 +1104,15 @@ TEST_F(UnwinderTest, dex_pc_max_frames) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify format frame code.
|
// Verify format frame code.
|
||||||
TEST_F(UnwinderTest, format_frame_static) {
|
TEST_F(UnwinderTest, format_frame) {
|
||||||
|
RegsFake regs_arm(10);
|
||||||
|
regs_arm.FakeSetArch(ARCH_ARM);
|
||||||
|
Unwinder unwinder32(10, maps_.get(), ®s_arm, process_memory_);
|
||||||
|
|
||||||
|
RegsFake regs_arm64(10);
|
||||||
|
regs_arm64.FakeSetArch(ARCH_ARM64);
|
||||||
|
Unwinder unwinder64(10, maps_.get(), ®s_arm64, process_memory_);
|
||||||
|
|
||||||
FrameData frame;
|
FrameData frame;
|
||||||
frame.num = 1;
|
frame.num = 1;
|
||||||
frame.rel_pc = 0x1000;
|
frame.rel_pc = 0x1000;
|
||||||
|
|
@ -1117,39 +1127,61 @@ TEST_F(UnwinderTest, format_frame_static) {
|
||||||
frame.map_flags = PROT_READ;
|
frame.map_flags = PROT_READ;
|
||||||
|
|
||||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (offset 0x2000) (function+100)",
|
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (offset 0x2000) (function+100)",
|
||||||
Unwinder::FormatFrame(frame, false));
|
unwinder64.FormatFrame(frame));
|
||||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (offset 0x2000) (function+100)",
|
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (offset 0x2000) (function+100)",
|
||||||
Unwinder::FormatFrame(frame, true));
|
unwinder32.FormatFrame(frame));
|
||||||
|
|
||||||
frame.map_elf_start_offset = 0;
|
frame.map_elf_start_offset = 0;
|
||||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)",
|
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)",
|
||||||
Unwinder::FormatFrame(frame, false));
|
unwinder64.FormatFrame(frame));
|
||||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)",
|
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder32.FormatFrame(frame));
|
||||||
Unwinder::FormatFrame(frame, true));
|
|
||||||
|
|
||||||
frame.function_offset = 0;
|
frame.function_offset = 0;
|
||||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function)",
|
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function)",
|
||||||
Unwinder::FormatFrame(frame, false));
|
unwinder64.FormatFrame(frame));
|
||||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function)", Unwinder::FormatFrame(frame, true));
|
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function)", unwinder32.FormatFrame(frame));
|
||||||
|
|
||||||
// Verify the function name is demangled.
|
// Verify the function name is demangled.
|
||||||
frame.function_name = "_ZN4funcEv";
|
frame.function_name = "_ZN4funcEv";
|
||||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (func())",
|
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (func())", unwinder64.FormatFrame(frame));
|
||||||
Unwinder::FormatFrame(frame, false));
|
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (func())", unwinder32.FormatFrame(frame));
|
||||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (func())", Unwinder::FormatFrame(frame, true));
|
|
||||||
|
|
||||||
frame.function_name = "";
|
frame.function_name = "";
|
||||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", Unwinder::FormatFrame(frame, false));
|
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", unwinder64.FormatFrame(frame));
|
||||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", Unwinder::FormatFrame(frame, true));
|
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", unwinder32.FormatFrame(frame));
|
||||||
|
|
||||||
frame.map_name = "";
|
frame.map_name = "";
|
||||||
EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", Unwinder::FormatFrame(frame, false));
|
EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", unwinder64.FormatFrame(frame));
|
||||||
EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", Unwinder::FormatFrame(frame, true));
|
EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", unwinder32.FormatFrame(frame));
|
||||||
|
|
||||||
frame.map_start = 0;
|
frame.map_start = 0;
|
||||||
frame.map_end = 0;
|
frame.map_end = 0;
|
||||||
EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", Unwinder::FormatFrame(frame, false));
|
EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", unwinder64.FormatFrame(frame));
|
||||||
EXPECT_EQ(" #01 pc 00001000 <unknown>", Unwinder::FormatFrame(frame, true));
|
EXPECT_EQ(" #01 pc 00001000 <unknown>", unwinder32.FormatFrame(frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UnwinderTest, format_frame_build_id) {
|
||||||
|
RegsFake regs(10);
|
||||||
|
regs.FakeSetArch(ARCH_ARM);
|
||||||
|
Unwinder unwinder(10, maps_.get(), ®s, process_memory_);
|
||||||
|
|
||||||
|
FrameData frame;
|
||||||
|
frame.num = 1;
|
||||||
|
frame.rel_pc = 0x1000;
|
||||||
|
frame.pc = 0x4000;
|
||||||
|
frame.sp = 0x1000;
|
||||||
|
frame.function_name = "function";
|
||||||
|
frame.function_offset = 100;
|
||||||
|
frame.map_name = "/fake/libfake.so";
|
||||||
|
frame.map_elf_start_offset = 0;
|
||||||
|
frame.map_start = 0x3000;
|
||||||
|
frame.map_end = 0x6000;
|
||||||
|
frame.map_flags = PROT_READ;
|
||||||
|
|
||||||
|
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder.FormatFrame(frame));
|
||||||
|
unwinder.SetDisplayBuildID(true);
|
||||||
|
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100) (BuildId: 46414b45)",
|
||||||
|
unwinder.FormatFrame(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string ArchToString(ArchEnum arch) {
|
static std::string ArchToString(ArchEnum arch) {
|
||||||
|
|
@ -1167,7 +1199,7 @@ static std::string ArchToString(ArchEnum arch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify format frame code.
|
// Verify format frame code.
|
||||||
TEST_F(UnwinderTest, format_frame) {
|
TEST_F(UnwinderTest, format_frame_by_arch) {
|
||||||
std::vector<Regs*> reg_list;
|
std::vector<Regs*> reg_list;
|
||||||
RegsArm* arm = new RegsArm;
|
RegsArm* arm = new RegsArm;
|
||||||
arm->set_pc(0x2300);
|
arm->set_pc(0x2300);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue