diff options
author | David Srbecky <dsrbecky@google.com> | 2021-03-12 16:36:27 +0000 |
---|---|---|
committer | David Srbecky <dsrbecky@google.com> | 2021-03-17 19:43:19 +0000 |
commit | fad04881a56fc8cae98dbf8d38f2e274effdcb40 (patch) | |
tree | 24f0e15f8fba32405db75a42635dac21f2f5955b /libunwindstack | |
parent | cd5123b49f3cd86ce3a06ddb207932b4571491ed (diff) | |
download | unwinding-fad04881a56fc8cae98dbf8d38f2e274effdcb40.tar.gz |
Simplify JitDebug implementation with templates.
Reduce the amount of repeated code using templates.
Test: libunwindstack_unit_test
Change-Id: I92ab53b050bcb877974dff95496a1fc41cbb41c0
Diffstat (limited to 'libunwindstack')
-rw-r--r-- | libunwindstack/JitDebug.cpp | 290 | ||||
-rw-r--r-- | libunwindstack/Unwinder.cpp | 2 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/JitDebug.h | 26 | ||||
-rw-r--r-- | libunwindstack/tests/fuzz/UnwinderFuzz.cpp | 2 |
4 files changed, 128 insertions, 192 deletions
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp index 1dd4e11..cd957c7 100644 --- a/libunwindstack/JitDebug.cpp +++ b/libunwindstack/JitDebug.cpp @@ -32,200 +32,156 @@ namespace unwindstack { -struct JITCodeEntry32Pack { - uint32_t next; - uint32_t prev; - uint32_t symfile_addr; - uint64_t symfile_size; -} __attribute__((packed)); - -struct JITCodeEntry32Pad { - uint32_t next; - uint32_t prev; - uint32_t symfile_addr; - uint32_t pad; - uint64_t symfile_size; -}; - -struct JITCodeEntry64 { - uint64_t next; - uint64_t prev; - uint64_t symfile_addr; - uint64_t symfile_size; -}; - -struct JITDescriptorHeader { - uint32_t version; - uint32_t action_flag; -}; - -struct JITDescriptor32 { - JITDescriptorHeader header; - uint32_t relevant_entry; - uint32_t first_entry; -}; - -struct JITDescriptor64 { - JITDescriptorHeader header; - uint64_t relevant_entry; - uint64_t first_entry; -}; - -JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {} - -JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs) - : Global(memory, search_libs) {} - -JitDebug::~JitDebug() { - for (auto* elf : elf_list_) { - delete elf; - } -} - -uint64_t JitDebug::ReadDescriptor32(uint64_t addr) { - JITDescriptor32 desc; - if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { - return 0; +template <typename Uintptr_T, typename Uint64_T> +class JitDebugImpl : public JitDebug, public Global { + public: + struct JITCodeEntry { + Uintptr_T next; + Uintptr_T prev; + Uintptr_T symfile_addr; + Uint64_T symfile_size; + }; + + struct JITDescriptor { + uint32_t version; + uint32_t action_flag; + Uintptr_T relevant_entry; + Uintptr_T first_entry; + }; + + JitDebugImpl(ArchEnum arch, std::shared_ptr<Memory>& memory, + std::vector<std::string>& search_libs) + : Global(memory, search_libs) { + SetArch(arch); } - if (desc.header.version != 1 || desc.first_entry == 0) { - // Either unknown version, or no jit entries. - return 0; - } - - return desc.first_entry; -} - -uint64_t JitDebug::ReadDescriptor64(uint64_t addr) { - JITDescriptor64 desc; - if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { - return 0; - } - - if (desc.header.version != 1 || desc.first_entry == 0) { - // Either unknown version, or no jit entries. - return 0; - } - - return desc.first_entry; -} - -uint64_t JitDebug::ReadEntry32Pack(uint64_t* start, uint64_t* size) { - JITCodeEntry32Pack code; - if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { - return 0; + ~JitDebugImpl() { + for (auto* elf : elf_list_) { + delete elf; + } } - *start = code.symfile_addr; - *size = code.symfile_size; - return code.next; -} - -uint64_t JitDebug::ReadEntry32Pad(uint64_t* start, uint64_t* size) { - JITCodeEntry32Pad code; - if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { - return 0; - } + uint64_t ReadDescriptor(uint64_t addr) { + JITDescriptor desc; + if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { + return 0; + } - *start = code.symfile_addr; - *size = code.symfile_size; - return code.next; -} + if (desc.version != 1 || desc.first_entry == 0) { + // Either unknown version, or no jit entries. + return 0; + } -uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) { - JITCodeEntry64 code; - if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { - return 0; + return desc.first_entry; } - *start = code.symfile_addr; - *size = code.symfile_size; - return code.next; -} - -void JitDebug::ProcessArch() { - switch (arch()) { - case ARCH_X86: - read_descriptor_func_ = &JitDebug::ReadDescriptor32; - read_entry_func_ = &JitDebug::ReadEntry32Pack; - break; - - case ARCH_ARM: - case ARCH_MIPS: - read_descriptor_func_ = &JitDebug::ReadDescriptor32; - read_entry_func_ = &JitDebug::ReadEntry32Pad; - break; + uint64_t ReadEntry(uint64_t* start, uint64_t* size) { + JITCodeEntry code; + if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { + return 0; + } - case ARCH_ARM64: - case ARCH_X86_64: - case ARCH_MIPS64: - read_descriptor_func_ = &JitDebug::ReadDescriptor64; - read_entry_func_ = &JitDebug::ReadEntry64; - break; - case ARCH_UNKNOWN: - abort(); + *start = code.symfile_addr; + *size = code.symfile_size.value; + return code.next; } -} -bool JitDebug::ReadVariableData(uint64_t ptr) { - entry_addr_ = (this->*read_descriptor_func_)(ptr); - return entry_addr_ != 0; -} + void ProcessArch() {} -void JitDebug::Init(Maps* maps) { - if (initialized_) { - return; + bool ReadVariableData(uint64_t ptr) { + entry_addr_ = ReadDescriptor(ptr); + return entry_addr_ != 0; } - // Regardless of what happens below, consider the init finished. - initialized_ = true; - FindAndReadVariable(maps, "__jit_debug_descriptor"); -} + void Init(Maps* maps) { + if (initialized_) { + return; + } + // Regardless of what happens below, consider the init finished. + initialized_ = true; -Elf* JitDebug::Find(Maps* maps, uint64_t pc) { - // Use a single lock, this object should be used so infrequently that - // a fine grain lock is unnecessary. - std::lock_guard<std::mutex> guard(lock_); - if (!initialized_) { - Init(maps); + FindAndReadVariable(maps, "__jit_debug_descriptor"); } - // Search the existing elf object first. - for (Elf* elf : elf_list_) { - if (elf->IsValidPc(pc)) { - return elf; + Elf* Find(Maps* maps, uint64_t pc) { + // Use a single lock, this object should be used so infrequently that + // a fine grain lock is unnecessary. + std::lock_guard<std::mutex> guard(lock_); + if (!initialized_) { + Init(maps); } - } - while (entry_addr_ != 0) { - uint64_t start; - uint64_t size; - entry_addr_ = (this->*read_entry_func_)(&start, &size); - - Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0)); - elf->Init(); - if (!elf->valid()) { - // The data is not formatted in a way we understand, do not attempt - // to process any other entries. - entry_addr_ = 0; - delete elf; - return nullptr; + // Search the existing elf object first. + for (Elf* elf : elf_list_) { + if (elf->IsValidPc(pc)) { + return elf; + } } - elf_list_.push_back(elf); - if (elf->IsValidPc(pc)) { - return elf; + while (entry_addr_ != 0) { + uint64_t start; + uint64_t size; + entry_addr_ = ReadEntry(&start, &size); + + Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0)); + elf->Init(); + if (!elf->valid()) { + // The data is not formatted in a way we understand, do not attempt + // to process any other entries. + entry_addr_ = 0; + delete elf; + return nullptr; + } + elf_list_.push_back(elf); + + if (elf->IsValidPc(pc)) { + return elf; + } } + return nullptr; } - return nullptr; -} +}; std::unique_ptr<JitDebug> CreateJitDebug(ArchEnum arch, std::shared_ptr<Memory>& memory, std::vector<std::string> search_libs) { + // uint64_t values on x86 are not naturally aligned, + // but uint64_t values on ARM are naturally aligned. + struct Uint64_P { + uint64_t value; + } __attribute__((packed)); + struct Uint64_A { + uint64_t value; + } __attribute__((aligned(8))); + CHECK(arch != ARCH_UNKNOWN); - std::unique_ptr<JitDebug> jit_debug(new JitDebug(memory, search_libs)); - jit_debug->SetArch(arch); - return jit_debug; + switch (arch) { + case ARCH_X86: { + using Impl = JitDebugImpl<uint32_t, Uint64_P>; + static_assert(offsetof(typename Impl::JITCodeEntry, symfile_size) == 12, "layout"); + static_assert(sizeof(typename Impl::JITCodeEntry) == 20, "layout"); + static_assert(sizeof(typename Impl::JITDescriptor) == 16, "layout"); + return std::unique_ptr<JitDebug>(new Impl(arch, memory, search_libs)); + } + case ARCH_ARM: + case ARCH_MIPS: { + using Impl = JitDebugImpl<uint32_t, Uint64_A>; + static_assert(offsetof(typename Impl::JITCodeEntry, symfile_size) == 16, "layout"); + static_assert(sizeof(typename Impl::JITCodeEntry) == 24, "layout"); + static_assert(sizeof(typename Impl::JITDescriptor) == 16, "layout"); + return std::unique_ptr<JitDebug>(new Impl(arch, memory, search_libs)); + } + case ARCH_ARM64: + case ARCH_X86_64: + case ARCH_MIPS64: { + using Impl = JitDebugImpl<uint64_t, Uint64_A>; + static_assert(offsetof(typename Impl::JITCodeEntry, symfile_size) == 24, "layout"); + static_assert(sizeof(typename Impl::JITCodeEntry) == 32, "layout"); + static_assert(sizeof(typename Impl::JITDescriptor) == 24, "layout"); + return std::unique_ptr<JitDebug>(new Impl(arch, memory, search_libs)); + } + default: + abort(); + } } } // namespace unwindstack diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index fb55944..ac118c7 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -365,8 +365,6 @@ std::string Unwinder::FormatFrame(size_t frame_num) const { } void Unwinder::SetJitDebug(JitDebug* jit_debug) { - CHECK(arch_ != ARCH_UNKNOWN); - jit_debug->SetArch(arch_); jit_debug_ = jit_debug; } diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h index d8c04e0..c4944d7 100644 --- a/libunwindstack/include/unwindstack/JitDebug.h +++ b/libunwindstack/include/unwindstack/JitDebug.h @@ -34,31 +34,13 @@ class Elf; class Maps; enum ArchEnum : uint8_t; -class JitDebug : public Global { +class JitDebug { public: - explicit JitDebug(std::shared_ptr<Memory>& memory); - JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs); - virtual ~JitDebug(); + virtual ~JitDebug() {} - Elf* Find(Maps* maps, uint64_t pc); - - private: - void Init(Maps* maps); - - uint64_t (JitDebug::*read_descriptor_func_)(uint64_t) = nullptr; - uint64_t (JitDebug::*read_entry_func_)(uint64_t*, uint64_t*) = nullptr; - - uint64_t ReadDescriptor32(uint64_t); - uint64_t ReadDescriptor64(uint64_t); - - uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size); - uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size); - uint64_t ReadEntry64(uint64_t* start, uint64_t* size); - - bool ReadVariableData(uint64_t ptr_offset) override; - - void ProcessArch() override; + virtual Elf* Find(Maps* maps, uint64_t pc) = 0; + protected: uint64_t entry_addr_ = 0; bool initialized_ = false; std::vector<Elf*> elf_list_; diff --git a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp index 1600547..f926ce7 100644 --- a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp +++ b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp @@ -81,7 +81,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { size_t max_frames = data_provider.ConsumeIntegralInRange<size_t>(0, 5000); - std::unique_ptr<JitDebug> jit_debug_ptr = std::make_unique<JitDebug>(memory); + std::unique_ptr<JitDebug> jit_debug_ptr = CreateJitDebug(arch, memory); // Create instance Unwinder unwinder(max_frames, maps.get(), regs.get(), memory); |