Merge "Add BuildId to frame information." am: 3da5fcbf70
am: 95b9ea1ddd
am: 36eb80073e
Change-Id: I9805df037b12432d1daa18c1accaa68669f635aa
This commit is contained in:
commit
24e5f851da
6 changed files with 80 additions and 31 deletions
|
@ -74,6 +74,7 @@ void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
|
|||
return;
|
||||
}
|
||||
|
||||
unwinder->SetDisplayBuildID(true);
|
||||
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
|
||||
_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) {
|
||||
unwinder->SetDisplayBuildID(true);
|
||||
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
|
||||
_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) {
|
||||
if (frame_num >= frames_.size()) {
|
||||
return "";
|
||||
}
|
||||
return FormatFrame(frames_[frame_num], regs_->Is32Bit());
|
||||
}
|
||||
|
||||
std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
|
||||
std::string Unwinder::FormatFrame(const FrameData& frame) {
|
||||
std::string data;
|
||||
|
||||
if (is32bit) {
|
||||
if (regs_->Is32Bit()) {
|
||||
data += android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
|
||||
} else {
|
||||
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 += ')';
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
jit_debug->SetArch(arch);
|
||||
jit_debug_ = jit_debug;
|
||||
|
|
|
@ -88,7 +88,7 @@ class Unwinder {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -105,6 +105,8 @@ class Unwinder {
|
|||
// NOTE: This does nothing unless resolving names is enabled.
|
||||
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)
|
||||
void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
|
||||
#endif
|
||||
|
@ -130,6 +132,7 @@ class Unwinder {
|
|||
#endif
|
||||
bool resolve_names_ = true;
|
||||
bool embedded_soname_ = true;
|
||||
bool display_build_id_ = false;
|
||||
ErrorData last_error_;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
#include "Check.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
class RegsFake : public Regs {
|
||||
|
@ -47,7 +49,10 @@ class RegsFake : public Regs {
|
|||
|
||||
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; }
|
||||
|
||||
|
|
|
@ -58,7 +58,9 @@ class UnwinderTest : public ::testing::Test {
|
|||
maps_.reset(new Maps);
|
||||
|
||||
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(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
|
||||
|
@ -1102,7 +1104,15 @@ TEST_F(UnwinderTest, dex_pc_max_frames) {
|
|||
}
|
||||
|
||||
// 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;
|
||||
frame.num = 1;
|
||||
frame.rel_pc = 0x1000;
|
||||
|
@ -1117,39 +1127,61 @@ TEST_F(UnwinderTest, format_frame_static) {
|
|||
frame.map_flags = PROT_READ;
|
||||
|
||||
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)",
|
||||
Unwinder::FormatFrame(frame, true));
|
||||
unwinder32.FormatFrame(frame));
|
||||
|
||||
frame.map_elf_start_offset = 0;
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)",
|
||||
Unwinder::FormatFrame(frame, false));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)",
|
||||
Unwinder::FormatFrame(frame, true));
|
||||
unwinder64.FormatFrame(frame));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder32.FormatFrame(frame));
|
||||
|
||||
frame.function_offset = 0;
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function)",
|
||||
Unwinder::FormatFrame(frame, false));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function)", Unwinder::FormatFrame(frame, true));
|
||||
unwinder64.FormatFrame(frame));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function)", unwinder32.FormatFrame(frame));
|
||||
|
||||
// Verify the function name is demangled.
|
||||
frame.function_name = "_ZN4funcEv";
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (func())",
|
||||
Unwinder::FormatFrame(frame, false));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (func())", Unwinder::FormatFrame(frame, true));
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (func())", unwinder64.FormatFrame(frame));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (func())", unwinder32.FormatFrame(frame));
|
||||
|
||||
frame.function_name = "";
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", Unwinder::FormatFrame(frame, false));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", Unwinder::FormatFrame(frame, true));
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", unwinder64.FormatFrame(frame));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", unwinder32.FormatFrame(frame));
|
||||
|
||||
frame.map_name = "";
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", Unwinder::FormatFrame(frame, false));
|
||||
EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", Unwinder::FormatFrame(frame, true));
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", unwinder64.FormatFrame(frame));
|
||||
EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", unwinder32.FormatFrame(frame));
|
||||
|
||||
frame.map_start = 0;
|
||||
frame.map_end = 0;
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", Unwinder::FormatFrame(frame, false));
|
||||
EXPECT_EQ(" #01 pc 00001000 <unknown>", Unwinder::FormatFrame(frame, true));
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", unwinder64.FormatFrame(frame));
|
||||
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) {
|
||||
|
@ -1167,7 +1199,7 @@ static std::string ArchToString(ArchEnum arch) {
|
|||
}
|
||||
|
||||
// Verify format frame code.
|
||||
TEST_F(UnwinderTest, format_frame) {
|
||||
TEST_F(UnwinderTest, format_frame_by_arch) {
|
||||
std::vector<Regs*> reg_list;
|
||||
RegsArm* arm = new RegsArm;
|
||||
arm->set_pc(0x2300);
|
||||
|
|
Loading…
Reference in a new issue