Merge "Add BuildId to frame information." am: 3da5fcbf70 am: 95b9ea1ddd

am: 36eb80073e

Change-Id: I9805df037b12432d1daa18c1accaa68669f635aa
This commit is contained in:
Christopher Ferris 2019-03-26 18:16:37 -07:00 committed by android-build-merger
commit 24e5f851da
6 changed files with 80 additions and 31 deletions

View file

@ -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());
}

View file

@ -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());
}

View file

@ -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;

View file

@ -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_;
};

View file

@ -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; }

View file

@ -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(), &regs_arm, process_memory_);
RegsFake regs_arm64(10);
regs_arm64.FakeSetArch(ARCH_ARM64);
Unwinder unwinder64(10, maps_.get(), &regs_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(), &regs, 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);