summaryrefslogtreecommitdiff
path: root/compiler/debug/elf_debug_reader.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/debug/elf_debug_reader.h')
-rw-r--r--compiler/debug/elf_debug_reader.h104
1 files changed, 104 insertions, 0 deletions
diff --git a/compiler/debug/elf_debug_reader.h b/compiler/debug/elf_debug_reader.h
new file mode 100644
index 0000000000..91b1b3ea81
--- /dev/null
+++ b/compiler/debug/elf_debug_reader.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_
+
+#include "base/array_ref.h"
+#include "debug/dwarf/headers.h"
+#include "elf.h"
+#include "xz_utils.h"
+
+namespace art {
+namespace debug {
+
+// Trivial ELF file reader.
+//
+// It is the bare minimum needed to read mini-debug-info symbols for unwinding.
+// We use it to merge JIT mini-debug-infos together or to prune them after GC.
+// The consumed ELF file comes from ART JIT.
+template <typename ElfTypes, typename VisitSym, typename VisitFde>
+static void ReadElfSymbols(const uint8_t* elf, VisitSym visit_sym, VisitFde visit_fde) {
+ // Note that the input buffer might be misaligned.
+ typedef typename ElfTypes::Ehdr ALIGNED(1) Elf_Ehdr;
+ typedef typename ElfTypes::Shdr ALIGNED(1) Elf_Shdr;
+ typedef typename ElfTypes::Sym ALIGNED(1) Elf_Sym;
+ typedef typename ElfTypes::Addr ALIGNED(1) Elf_Addr;
+
+ // Read and check the elf header.
+ const Elf_Ehdr* header = reinterpret_cast<const Elf_Ehdr*>(elf);
+ CHECK(header->checkMagic());
+
+ // Find sections that we are interested in.
+ const Elf_Shdr* sections = reinterpret_cast<const Elf_Shdr*>(elf + header->e_shoff);
+ const Elf_Shdr* strtab = nullptr;
+ const Elf_Shdr* symtab = nullptr;
+ const Elf_Shdr* debug_frame = nullptr;
+ const Elf_Shdr* gnu_debugdata = nullptr;
+ for (size_t i = 1 /* skip null section */; i < header->e_shnum; i++) {
+ const Elf_Shdr* section = sections + i;
+ const char* name = reinterpret_cast<const char*>(
+ elf + sections[header->e_shstrndx].sh_offset + section->sh_name);
+ if (strcmp(name, ".strtab") == 0) {
+ strtab = section;
+ } else if (strcmp(name, ".symtab") == 0) {
+ symtab = section;
+ } else if (strcmp(name, ".debug_frame") == 0) {
+ debug_frame = section;
+ } else if (strcmp(name, ".gnu_debugdata") == 0) {
+ gnu_debugdata = section;
+ }
+ }
+
+ // Visit symbols.
+ if (symtab != nullptr && strtab != nullptr) {
+ const Elf_Sym* symbols = reinterpret_cast<const Elf_Sym*>(elf + symtab->sh_offset);
+ DCHECK_EQ(symtab->sh_entsize, sizeof(Elf_Sym));
+ size_t count = symtab->sh_size / sizeof(Elf_Sym);
+ for (size_t i = 1 /* skip null symbol */; i < count; i++) {
+ Elf_Sym symbol = symbols[i];
+ if (symbol.getBinding() != STB_LOCAL) { // Ignore local symbols (e.g. "$t").
+ const uint8_t* name = elf + strtab->sh_offset + symbol.st_name;
+ visit_sym(symbol, reinterpret_cast<const char*>(name));
+ }
+ }
+ }
+
+ // Visit CFI (unwind) data.
+ if (debug_frame != nullptr) {
+ const uint8_t* data = elf + debug_frame->sh_offset;
+ const uint8_t* end = data + debug_frame->sh_size;
+ while (data < end) {
+ Elf_Addr addr, size;
+ ArrayRef<const uint8_t> opcodes;
+ if (dwarf::ReadFDE<Elf_Addr>(&data, &addr, &size, &opcodes)) {
+ visit_fde(addr, size, opcodes);
+ }
+ }
+ }
+
+ // Process embedded compressed ELF file.
+ if (gnu_debugdata != nullptr) {
+ ArrayRef<const uint8_t> compressed(elf + gnu_debugdata->sh_offset, gnu_debugdata->sh_size);
+ std::vector<uint8_t> decompressed;
+ XzDecompress(compressed, &decompressed);
+ ReadElfSymbols<ElfTypes>(decompressed.data(), visit_sym, visit_fde);
+ }
+}
+
+} // namespace debug
+} // namespace art
+#endif // ART_COMPILER_DEBUG_ELF_DEBUG_READER_H_