diff options
author | Christopher Ferris <cferris@google.com> | 2019-03-14 13:44:38 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2019-03-26 08:04:40 -0700 |
commit | 8dbfa97631b6570d56575e838811da854a5faa6c (patch) | |
tree | 2cb79f348bfd3356b8c07c7b889f8537f1d967bb | |
parent | 5b51e8c1250b3c1d346020803b9bf182f6eaa20d (diff) | |
download | unwinding-8dbfa97631b6570d56575e838811da854a5faa6c.tar.gz |
Add BuildId to frame information.
Update debuggerd to print BuildId information by default.
Bug: 120975492
Test: New unit tests pass.
Test: debuggerd -b <PID> shows build id information.
Test: tombstones include build id information.
Change-Id: I019b031113d0b77385516223c63455b868924440
-rw-r--r-- | libunwindstack/Unwinder.cpp | 27 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Unwinder.h | 5 | ||||
-rw-r--r-- | libunwindstack/tests/RegsFake.h | 7 | ||||
-rw-r--r-- | libunwindstack/tests/UnwinderTest.cpp | 70 |
4 files changed, 78 insertions, 31 deletions
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index a1c58dd..3f2e1c1 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -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; diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h index a0554e2..8b01654 100644 --- a/libunwindstack/include/unwindstack/Unwinder.h +++ b/libunwindstack/include/unwindstack/Unwinder.h @@ -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_; }; diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h index d6ca9b7..207d46e 100644 --- a/libunwindstack/tests/RegsFake.h +++ b/libunwindstack/tests/RegsFake.h @@ -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; } diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index 504b57a..48e038e 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -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); |