summaryrefslogtreecommitdiff
path: root/libunwindstack
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2021-03-12 16:36:27 +0000
committerDavid Srbecky <dsrbecky@google.com>2021-03-17 19:43:19 +0000
commitfad04881a56fc8cae98dbf8d38f2e274effdcb40 (patch)
tree24f0e15f8fba32405db75a42635dac21f2f5955b /libunwindstack
parentcd5123b49f3cd86ce3a06ddb207932b4571491ed (diff)
downloadunwinding-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.cpp290
-rw-r--r--libunwindstack/Unwinder.cpp2
-rw-r--r--libunwindstack/include/unwindstack/JitDebug.h26
-rw-r--r--libunwindstack/tests/fuzz/UnwinderFuzz.cpp2
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);