summaryrefslogtreecommitdiffstats
path: root/runtime/elf_file.cc
diff options
context:
space:
mode:
authorAlex Light <allight@google.com>2014-06-18 10:35:45 -0700
committerBrian Carlstrom <bdc@google.com>2014-06-27 16:46:29 -0700
commit3470ab4011b5e18d590d5375e2f13a1e3bd69222 (patch)
tree79efa1be55a16a43447f7373f0aa8722828204d5 /runtime/elf_file.cc
parentbaa1323d66a05fd2d7b9c6c131b232945b0a4ebb (diff)
downloadart-3470ab4011b5e18d590d5375e2f13a1e3bd69222.tar.gz
art-3470ab4011b5e18d590d5375e2f13a1e3bd69222.tar.bz2
art-3470ab4011b5e18d590d5375e2f13a1e3bd69222.zip
Fixed gdb support and added some ElfFile functions
Fixed gdb support so that it would continue working even when debug symbols or other sections are included in the elf file. Also made it actually read parts of the DWARF information so it should work even if there are minor changes to how and where DWARF information is written out. Added a dwarf.h file with the dwarf constants. Added a FindSectionByName function, a FindDynamicSymbol function, and the ability to specify the mmap protection and flags directly if we are mapping in the whole file. Modified elf_writer_quick.cc to use the dwarf constants from dwarf.h. Change-Id: I09e15c425fab252b331a2e4719863552e8b6b137
Diffstat (limited to 'runtime/elf_file.cc')
-rw-r--r--runtime/elf_file.cc712
1 files changed, 417 insertions, 295 deletions
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 0df8211c57..bb33978761 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -22,6 +22,8 @@
#include "base/logging.h"
#include "base/stringprintf.h"
#include "base/stl_util.h"
+#include "dwarf.h"
+#include "leb128.h"
#include "utils.h"
#include "instruction_set.h"
@@ -108,43 +110,51 @@ ElfFile::ElfFile(File* file, bool writable, bool program_header_only)
: file_(file),
writable_(writable),
program_header_only_(program_header_only),
- header_(NULL),
- base_address_(NULL),
- program_headers_start_(NULL),
- section_headers_start_(NULL),
- dynamic_program_header_(NULL),
- dynamic_section_start_(NULL),
- symtab_section_start_(NULL),
- dynsym_section_start_(NULL),
- strtab_section_start_(NULL),
- dynstr_section_start_(NULL),
- hash_section_start_(NULL),
- symtab_symbol_table_(NULL),
- dynsym_symbol_table_(NULL),
- jit_elf_image_(NULL),
- jit_gdb_entry_(NULL) {
- CHECK(file != NULL);
+ header_(nullptr),
+ base_address_(nullptr),
+ program_headers_start_(nullptr),
+ section_headers_start_(nullptr),
+ dynamic_program_header_(nullptr),
+ dynamic_section_start_(nullptr),
+ symtab_section_start_(nullptr),
+ dynsym_section_start_(nullptr),
+ strtab_section_start_(nullptr),
+ dynstr_section_start_(nullptr),
+ hash_section_start_(nullptr),
+ symtab_symbol_table_(nullptr),
+ dynsym_symbol_table_(nullptr),
+ jit_elf_image_(nullptr),
+ jit_gdb_entry_(nullptr) {
+ CHECK(file != nullptr);
}
ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only,
std::string* error_msg) {
std::unique_ptr<ElfFile> elf_file(new ElfFile(file, writable, program_header_only));
- if (!elf_file->Setup(error_msg)) {
- return nullptr;
- }
- return elf_file.release();
-}
-
-bool ElfFile::Setup(std::string* error_msg) {
int prot;
int flags;
- if (writable_) {
+ if (writable) {
prot = PROT_READ | PROT_WRITE;
flags = MAP_SHARED;
} else {
prot = PROT_READ;
flags = MAP_PRIVATE;
}
+ if (!elf_file->Setup(prot, flags, error_msg)) {
+ return nullptr;
+ }
+ return elf_file.release();
+}
+
+ElfFile* ElfFile::Open(File* file, int prot, int flags, std::string* error_msg) {
+ std::unique_ptr<ElfFile> elf_file(new ElfFile(file, (prot & PROT_WRITE) == PROT_WRITE, false));
+ if (!elf_file->Setup(prot, flags, error_msg)) {
+ return nullptr;
+ }
+ return elf_file.release();
+}
+
+bool ElfFile::Setup(int prot, int flags, std::string* error_msg) {
int64_t temp_file_length = file_->GetLength();
if (temp_file_length < 0) {
errno = -temp_file_length;
@@ -201,7 +211,7 @@ bool ElfFile::Setup(std::string* error_msg) {
// Find .dynamic section info from program header
dynamic_program_header_ = FindProgamHeaderByType(PT_DYNAMIC);
- if (dynamic_program_header_ == NULL) {
+ if (dynamic_program_header_ == nullptr) {
*error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'",
file_->GetPath().c_str());
return false;
@@ -263,14 +273,14 @@ ElfFile::~ElfFile() {
}
bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
- if (map == NULL) {
+ if (map == nullptr) {
// MemMap::Open should have already set an error.
DCHECK(!error_msg->empty());
return false;
}
map_.reset(map);
- CHECK(map_.get() != NULL) << file_->GetPath();
- CHECK(map_->Begin() != NULL) << file_->GetPath();
+ CHECK(map_.get() != nullptr) << file_->GetPath();
+ CHECK(map_->Begin() != nullptr) << file_->GetPath();
header_ = reinterpret_cast<Elf32_Ehdr*>(map_->Begin());
if ((ELFMAG0 != header_->e_ident[EI_MAG0])
@@ -397,27 +407,27 @@ bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
Elf32_Ehdr& ElfFile::GetHeader() const {
- CHECK(header_ != NULL);
+ CHECK(header_ != nullptr);
return *header_;
}
byte* ElfFile::GetProgramHeadersStart() const {
- CHECK(program_headers_start_ != NULL);
+ CHECK(program_headers_start_ != nullptr);
return program_headers_start_;
}
byte* ElfFile::GetSectionHeadersStart() const {
- CHECK(section_headers_start_ != NULL);
+ CHECK(section_headers_start_ != nullptr);
return section_headers_start_;
}
Elf32_Phdr& ElfFile::GetDynamicProgramHeader() const {
- CHECK(dynamic_program_header_ != NULL);
+ CHECK(dynamic_program_header_ != nullptr);
return *dynamic_program_header_;
}
Elf32_Dyn* ElfFile::GetDynamicSectionStart() const {
- CHECK(dynamic_section_start_ != NULL);
+ CHECK(dynamic_section_start_ != nullptr);
return dynamic_section_start_;
}
@@ -435,10 +445,10 @@ Elf32_Sym* ElfFile::GetSymbolSectionStart(Elf32_Word section_type) const {
}
default: {
LOG(FATAL) << section_type;
- symbol_section_start = NULL;
+ symbol_section_start = nullptr;
}
}
- CHECK(symbol_section_start != NULL);
+ CHECK(symbol_section_start != nullptr);
return symbol_section_start;
}
@@ -456,17 +466,17 @@ const char* ElfFile::GetStringSectionStart(Elf32_Word section_type) const {
}
default: {
LOG(FATAL) << section_type;
- string_section_start = NULL;
+ string_section_start = nullptr;
}
}
- CHECK(string_section_start != NULL);
+ CHECK(string_section_start != nullptr);
return string_section_start;
}
const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const {
CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
if (i == 0) {
- return NULL;
+ return nullptr;
}
const char* string_section_start = GetStringSectionStart(section_type);
const char* string = string_section_start + i;
@@ -474,7 +484,7 @@ const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const {
}
Elf32_Word* ElfFile::GetHashSectionStart() const {
- CHECK(hash_section_start_ != NULL);
+ CHECK(hash_section_start_ != nullptr);
return hash_section_start_;
}
@@ -516,7 +526,7 @@ Elf32_Phdr* ElfFile::FindProgamHeaderByType(Elf32_Word type) const {
return &program_header;
}
}
- return NULL;
+ return nullptr;
}
Elf32_Word ElfFile::GetSectionHeaderNum() const {
@@ -543,7 +553,7 @@ Elf32_Shdr* ElfFile::FindSectionByType(Elf32_Word type) const {
return &section_header;
}
}
- return NULL;
+ return nullptr;
}
// from bionic
@@ -565,6 +575,15 @@ Elf32_Shdr& ElfFile::GetSectionNameStringSection() const {
}
const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
+ const Elf32_Sym* sym = FindDynamicSymbol(symbol_name);
+ if (sym != nullptr) {
+ return base_address_ + sym->st_value;
+ } else {
+ return nullptr;
+ }
+}
+
+const Elf32_Sym* ElfFile::FindDynamicSymbol(const std::string& symbol_name) const {
Elf32_Word hash = elfhash(symbol_name.c_str());
Elf32_Word bucket_index = hash % GetHashBucketNum();
Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index);
@@ -572,11 +591,11 @@ const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) co
Elf32_Sym& symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
const char* name = GetString(SHT_DYNSYM, symbol.st_name);
if (symbol_name == name) {
- return base_address_ + symbol.st_value;
+ return &symbol;
}
symbol_and_chain_index = GetHashChain(symbol_and_chain_index);
}
- return NULL;
+ return nullptr;
}
bool ElfFile::IsSymbolSectionType(Elf32_Word section_type) {
@@ -606,7 +625,7 @@ ElfFile::SymbolTable** ElfFile::GetSymbolTable(Elf32_Word section_type) {
}
default: {
LOG(FATAL) << section_type;
- return NULL;
+ return nullptr;
}
}
}
@@ -618,12 +637,12 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type,
CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
SymbolTable** symbol_table = GetSymbolTable(section_type);
- if (*symbol_table != NULL || build_map) {
- if (*symbol_table == NULL) {
+ if (*symbol_table != nullptr || build_map) {
+ if (*symbol_table == nullptr) {
DCHECK(build_map);
*symbol_table = new SymbolTable;
Elf32_Shdr* symbol_section = FindSectionByType(section_type);
- CHECK(symbol_section != NULL) << file_->GetPath();
+ CHECK(symbol_section != nullptr) << file_->GetPath();
Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
Elf32_Sym& symbol = GetSymbol(section_type, i);
@@ -632,7 +651,7 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type,
continue;
}
const char* name = GetString(string_section, symbol.st_name);
- if (name == NULL) {
+ if (name == nullptr) {
continue;
}
std::pair<SymbolTable::iterator, bool> result =
@@ -647,36 +666,36 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type,
}
}
}
- CHECK(*symbol_table != NULL);
+ CHECK(*symbol_table != nullptr);
SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name);
if (it == (*symbol_table)->end()) {
- return NULL;
+ return nullptr;
}
return it->second;
}
// Fall back to linear search
Elf32_Shdr* symbol_section = FindSectionByType(section_type);
- CHECK(symbol_section != NULL) << file_->GetPath();
+ CHECK(symbol_section != nullptr) << file_->GetPath();
Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
Elf32_Sym& symbol = GetSymbol(section_type, i);
const char* name = GetString(string_section, symbol.st_name);
- if (name == NULL) {
+ if (name == nullptr) {
continue;
}
if (symbol_name == name) {
return &symbol;
}
}
- return NULL;
+ return nullptr;
}
Elf32_Addr ElfFile::FindSymbolAddress(Elf32_Word section_type,
const std::string& symbol_name,
bool build_map) {
Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map);
- if (symbol == NULL) {
+ if (symbol == nullptr) {
return 0;
}
return symbol->st_value;
@@ -688,7 +707,7 @@ const char* ElfFile::GetString(Elf32_Shdr& string_section, Elf32_Word i) const {
CHECK_EQ(static_cast<Elf32_Word>(SHT_STRTAB), string_section.sh_type) << file_->GetPath();
CHECK_LT(i, string_section.sh_size) << file_->GetPath();
if (i == 0) {
- return NULL;
+ return nullptr;
}
byte* strings = Begin() + string_section.sh_offset;
byte* string = strings + i;
@@ -846,7 +865,7 @@ bool ElfFile::Load(bool executable, std::string* error_msg) {
std::string reservation_name("ElfFile reservation for ");
reservation_name += file_->GetPath();
std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),
- NULL, GetLoadedSize(), PROT_NONE, false,
+ nullptr, GetLoadedSize(), PROT_NONE, false,
error_msg));
if (reserve.get() == nullptr) {
*error_msg = StringPrintf("Failed to allocate %s: %s",
@@ -970,29 +989,323 @@ bool ElfFile::ValidPointer(const byte* start) const {
return false;
}
-static bool check_section_name(ElfFile& file, int section_num, const char *name) {
- Elf32_Shdr& section_header = file.GetSectionHeader(section_num);
- const char *section_name = file.GetString(SHT_SYMTAB, section_header.sh_name);
- return strcmp(name, section_name) == 0;
+
+Elf32_Shdr* ElfFile::FindSectionByName(const std::string& name) const {
+ CHECK(!program_header_only_);
+ Elf32_Shdr& shstrtab_sec = GetSectionNameStringSection();
+ for (uint32_t i = 0; i < GetSectionHeaderNum(); i++) {
+ Elf32_Shdr& shdr = GetSectionHeader(i);
+ const char* sec_name = GetString(shstrtab_sec, shdr.sh_name);
+ if (sec_name == nullptr) {
+ continue;
+ }
+ if (name == sec_name) {
+ return &shdr;
+ }
+ }
+ return nullptr;
}
-static void IncrementUint32(byte *p, uint32_t increment) {
- uint32_t *u = reinterpret_cast<uint32_t *>(p);
- *u += increment;
+struct PACKED(1) FDE {
+ uint32_t raw_length_;
+ uint32_t GetLength() {
+ return raw_length_ + sizeof(raw_length_);
+ }
+ uint32_t CIE_pointer;
+ uint32_t initial_location;
+ uint32_t address_range;
+ uint8_t instructions[0];
+};
+
+static FDE* NextFDE(FDE* frame) {
+ byte* fde_bytes = reinterpret_cast<byte*>(frame);
+ fde_bytes += frame->GetLength();
+ return reinterpret_cast<FDE*>(fde_bytes);
}
-static void RoundAndClear(byte *image, uint32_t& offset, int pwr2) {
- uint32_t mask = pwr2 - 1;
- while (offset & mask) {
- image[offset++] = 0;
+static bool IsFDE(FDE* frame) {
+ // TODO This seems to be the constant everyone uses (for the .debug_frame
+ // section at least), however we should investigate this further.
+ const uint32_t kDwarfCIE_id = 0xffffffff;
+ const uint32_t kReservedLengths[] = {0xffffffff, 0xfffffff0};
+ return frame->CIE_pointer != kDwarfCIE_id &&
+ frame->raw_length_ != kReservedLengths[0] && frame->raw_length_ != kReservedLengths[1];
+}
+
+// TODO This only works for 32-bit Elf Files.
+static bool FixupDebugFrame(uintptr_t text_start, byte* dbg_frame, size_t dbg_frame_size) {
+ FDE* last_frame = reinterpret_cast<FDE*>(dbg_frame + dbg_frame_size);
+ FDE* frame = NextFDE(reinterpret_cast<FDE*>(dbg_frame));
+ for (; frame < last_frame; frame = NextFDE(frame)) {
+ if (!IsFDE(frame)) {
+ return false;
+ }
+ frame->initial_location += text_start;
}
+ return true;
}
-// Simple macro to bump a point to a section header to the next one.
-#define BUMP_SHENT(sp) \
- sp = reinterpret_cast<Elf32_Shdr *> (\
- reinterpret_cast<byte*>(sp) + elf_hdr.e_shentsize);\
- offset += elf_hdr.e_shentsize
+struct PACKED(1) DebugInfoHeader {
+ uint32_t unit_length; // TODO 32-bit specific size
+ uint16_t version;
+ uint32_t debug_abbrev_offset; // TODO 32-bit specific size
+ uint8_t address_size;
+};
+
+// Returns -1 if it is variable length, which we will just disallow for now.
+static int32_t FormLength(uint32_t att) {
+ switch (att) {
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_flag_present:
+ case DW_FORM_ref1:
+ return 1;
+
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ return 2;
+
+ case DW_FORM_addr: // TODO 32-bit only
+ case DW_FORM_ref_addr: // TODO 32-bit only
+ case DW_FORM_sec_offset: // TODO 32-bit only
+ case DW_FORM_strp: // TODO 32-bit only
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ return 4;
+
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ return 8;
+
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_exprloc:
+ case DW_FORM_indirect:
+ case DW_FORM_ref_udata:
+ case DW_FORM_sdata:
+ case DW_FORM_string:
+ case DW_FORM_udata:
+ default:
+ return -1;
+ }
+}
+
+class DebugTag {
+ public:
+ const uint32_t index_;
+ ~DebugTag() {}
+ // Creates a new tag and moves data pointer up to the start of the next one.
+ // nullptr means error.
+ static DebugTag* Create(const byte** data_pointer) {
+ const byte* data = *data_pointer;
+ uint32_t index = DecodeUnsignedLeb128(&data);
+ std::unique_ptr<DebugTag> tag(new DebugTag(index));
+ tag->size_ = static_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(data) - reinterpret_cast<uintptr_t>(*data_pointer));
+ // skip the abbrev
+ tag->tag_ = DecodeUnsignedLeb128(&data);
+ tag->has_child_ = (*data == 0);
+ data++;
+ while (true) {
+ uint32_t attr = DecodeUnsignedLeb128(&data);
+ uint32_t form = DecodeUnsignedLeb128(&data);
+ if (attr == 0 && form == 0) {
+ break;
+ } else if (attr == 0 || form == 0) {
+ // Bad abbrev.
+ return nullptr;
+ }
+ int32_t size = FormLength(form);
+ if (size == -1) {
+ return nullptr;
+ }
+ tag->AddAttribute(attr, static_cast<uint32_t>(size));
+ }
+ *data_pointer = data;
+ return tag.release();
+ }
+
+ uint32_t GetSize() const {
+ return size_;
+ }
+
+ bool HasChild() {
+ return has_child_;
+ }
+
+ uint32_t GetTagNumber() {
+ return tag_;
+ }
+
+ // Gets the offset of a particular attribute in this tag structure.
+ // Interpretation of the data is left to the consumer. 0 is returned if the
+ // tag does not contain the attribute.
+ uint32_t GetOffsetOf(uint32_t dwarf_attribute) const {
+ auto it = off_map_.find(dwarf_attribute);
+ if (it == off_map_.end()) {
+ return 0;
+ } else {
+ return it->second;
+ }
+ }
+
+ // Gets the size of attribute
+ uint32_t GetAttrSize(uint32_t dwarf_attribute) const {
+ auto it = size_map_.find(dwarf_attribute);
+ if (it == size_map_.end()) {
+ return 0;
+ } else {
+ return it->second;
+ }
+ }
+
+ private:
+ explicit DebugTag(uint32_t index) : index_(index) {}
+ void AddAttribute(uint32_t type, uint32_t attr_size) {
+ off_map_.insert(std::pair<uint32_t, uint32_t>(type, size_));
+ size_map_.insert(std::pair<uint32_t, uint32_t>(type, attr_size));
+ size_ += attr_size;
+ }
+ std::map<uint32_t, uint32_t> off_map_;
+ std::map<uint32_t, uint32_t> size_map_;
+ uint32_t size_;
+ uint32_t tag_;
+ bool has_child_;
+};
+
+class DebugAbbrev {
+ public:
+ ~DebugAbbrev() {}
+ static DebugAbbrev* Create(const byte* dbg_abbrev, size_t dbg_abbrev_size) {
+ std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev);
+ const byte* last = dbg_abbrev + dbg_abbrev_size;
+ while (dbg_abbrev < last) {
+ std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev));
+ if (tag.get() == nullptr) {
+ return nullptr;
+ } else {
+ abbrev->tags_.insert(std::pair<uint32_t, uint32_t>(tag->index_, abbrev->tag_list_.size()));
+ abbrev->tag_list_.push_back(std::move(tag));
+ }
+ }
+ return abbrev.release();
+ }
+
+ DebugTag* ReadTag(const byte* entry) {
+ uint32_t tag_num = DecodeUnsignedLeb128(&entry);
+ auto it = tags_.find(tag_num);
+ if (it == tags_.end()) {
+ return nullptr;
+ } else {
+ CHECK_GT(tag_list_.size(), it->second);
+ return tag_list_.at(it->second).get();
+ }
+ }
+
+ private:
+ DebugAbbrev() {}
+ std::map<uint32_t, uint32_t> tags_;
+ std::vector<std::unique_ptr<DebugTag>> tag_list_;
+};
+
+class DebugInfoIterator {
+ public:
+ static DebugInfoIterator* Create(DebugInfoHeader* header, size_t frame_size,
+ DebugAbbrev* abbrev) {
+ std::unique_ptr<DebugInfoIterator> iter(new DebugInfoIterator(header, frame_size, abbrev));
+ if (iter->GetCurrentTag() == nullptr) {
+ return nullptr;
+ } else {
+ return iter.release();
+ }
+ }
+ ~DebugInfoIterator() {}
+
+ // Moves to the next DIE. Returns false if at last entry.
+ // TODO Handle variable length attributes.
+ bool next() {
+ if (current_entry_ == nullptr || current_tag_ == nullptr) {
+ return false;
+ }
+ current_entry_ += current_tag_->GetSize();
+ if (current_entry_ >= last_entry_) {
+ current_entry_ = nullptr;
+ return false;
+ }
+ current_tag_ = abbrev_->ReadTag(current_entry_);
+ if (current_tag_ == nullptr) {
+ current_entry_ = nullptr;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ const DebugTag* GetCurrentTag() {
+ return const_cast<DebugTag*>(current_tag_);
+ }
+ byte* GetPointerToField(uint8_t dwarf_field) {
+ if (current_tag_ == nullptr || current_entry_ == nullptr || current_entry_ >= last_entry_) {
+ return nullptr;
+ }
+ uint32_t off = current_tag_->GetOffsetOf(dwarf_field);
+ if (off == 0) {
+ // tag does not have that field.
+ return nullptr;
+ } else {
+ DCHECK_LT(off, current_tag_->GetSize());
+ return current_entry_ + off;
+ }
+ }
+
+ private:
+ DebugInfoIterator(DebugInfoHeader* header, size_t frame_size, DebugAbbrev* abbrev)
+ : abbrev_(abbrev),
+ last_entry_(reinterpret_cast<byte*>(header) + frame_size),
+ current_entry_(reinterpret_cast<byte*>(header) + sizeof(DebugInfoHeader)),
+ current_tag_(abbrev_->ReadTag(current_entry_)) {}
+ DebugAbbrev* abbrev_;
+ byte* last_entry_;
+ byte* current_entry_;
+ DebugTag* current_tag_;
+};
+
+static bool FixupDebugInfo(uint32_t text_start, DebugInfoIterator* iter) {
+ do {
+ if (iter->GetCurrentTag()->GetAttrSize(DW_AT_low_pc) != sizeof(int32_t) ||
+ iter->GetCurrentTag()->GetAttrSize(DW_AT_high_pc) != sizeof(int32_t)) {
+ return false;
+ }
+ uint32_t* PC_low = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_low_pc));
+ uint32_t* PC_high = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_high_pc));
+ if (PC_low != nullptr && PC_high != nullptr) {
+ *PC_low += text_start;
+ *PC_high += text_start;
+ }
+ } while (iter->next());
+ return true;
+}
+
+static bool FixupDebugSections(const byte* dbg_abbrev, size_t dbg_abbrev_size,
+ uintptr_t text_start,
+ byte* dbg_info, size_t dbg_info_size,
+ byte* dbg_frame, size_t dbg_frame_size) {
+ std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(dbg_abbrev, dbg_abbrev_size));
+ if (abbrev.get() == nullptr) {
+ return false;
+ }
+ std::unique_ptr<DebugInfoIterator> iter(
+ DebugInfoIterator::Create(reinterpret_cast<DebugInfoHeader*>(dbg_info),
+ dbg_info_size, abbrev.get()));
+ if (iter.get() == nullptr) {
+ return false;
+ }
+ return FixupDebugInfo(text_start, iter.get())
+ && FixupDebugFrame(text_start, dbg_frame, dbg_frame_size);
+}
void ElfFile::GdbJITSupport() {
// We only get here if we only are mapping the program header.
@@ -1000,18 +1313,25 @@ void ElfFile::GdbJITSupport() {
// Well, we need the whole file to do this.
std::string error_msg;
- std::unique_ptr<ElfFile> ptr(Open(const_cast<File*>(file_), false, false, &error_msg));
- ElfFile& all = *ptr;
-
- // Do we have interesting sections?
- // Is this an OAT file with interesting sections?
- if (all.GetSectionHeaderNum() != kExpectedSectionsInOATFile) {
+ // Make it MAP_PRIVATE so we can just give it to gdb if all the necessary
+ // sections are there.
+ std::unique_ptr<ElfFile> all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, &error_msg));
+ if (all_ptr.get() == nullptr) {
return;
}
- if (!check_section_name(all, 8, ".debug_info") ||
- !check_section_name(all, 9, ".debug_abbrev") ||
- !check_section_name(all, 10, ".debug_frame") ||
- !check_section_name(all, 11, ".debug_str")) {
+ ElfFile& all = *all_ptr;
+
+ // Do we have interesting sections?
+ const Elf32_Shdr* debug_info = all.FindSectionByName(".debug_info");
+ const Elf32_Shdr* debug_abbrev = all.FindSectionByName(".debug_abbrev");
+ const Elf32_Shdr* debug_frame = all.FindSectionByName(".debug_frame");
+ const Elf32_Shdr* debug_str = all.FindSectionByName(".debug_str");
+ const Elf32_Shdr* strtab_sec = all.FindSectionByName(".strtab");
+ const Elf32_Shdr* symtab_sec = all.FindSectionByName(".symtab");
+ Elf32_Shdr* text_sec = all.FindSectionByName(".text");
+ if (debug_info == nullptr || debug_abbrev == nullptr || debug_frame == nullptr ||
+ debug_str == nullptr || text_sec == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
return;
}
#ifdef __LP64__
@@ -1019,227 +1339,29 @@ void ElfFile::GdbJITSupport() {
return; // No ELF debug support in 64bit.
}
#endif
- // This is not needed if we have no .text segment.
- uint32_t text_start_addr = 0;
- for (uint32_t i = 0; i < segments_.size(); i++) {
- if (segments_[i]->GetProtect() & PROT_EXEC) {
- // We found the .text section.
- text_start_addr = PointerToLowMemUInt32(segments_[i]->Begin());
- break;
- }
- }
- if (text_start_addr == 0U) {
- return;
- }
-
- // Okay, we are good enough. Fake up an ELF image and tell GDB about it.
- // We need some extra space for the debug and string sections, the ELF header, and the
- // section header.
- uint32_t needed_size = KB;
-
- for (Elf32_Word i = 1; i < all.GetSectionHeaderNum(); i++) {
- Elf32_Shdr& section_header = all.GetSectionHeader(i);
- if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
- // Debug section: we need it.
- needed_size += section_header.sh_size;
- } else if (section_header.sh_type == SHT_STRTAB &&
- strcmp(".shstrtab",
- all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
- // We also need the shared string table.
- needed_size += section_header.sh_size;
-
- // We also need the extra strings .symtab\0.strtab\0
- needed_size += 16;
- }
- }
-
- // Start creating our image.
- jit_elf_image_ = new byte[needed_size];
-
- // Create the Elf Header by copying the old one
- Elf32_Ehdr& elf_hdr =
- *reinterpret_cast<Elf32_Ehdr*>(jit_elf_image_);
-
- elf_hdr = all.GetHeader();
+ // We need to add in a strtab and symtab to the image.
+ // all is MAP_PRIVATE so it can be written to freely.
+ // We also already have strtab and symtab so we are fine there.
+ Elf32_Ehdr& elf_hdr = all.GetHeader();
elf_hdr.e_entry = 0;
elf_hdr.e_phoff = 0;
elf_hdr.e_phnum = 0;
elf_hdr.e_phentsize = 0;
elf_hdr.e_type = ET_EXEC;
- uint32_t offset = sizeof(Elf32_Ehdr);
-
- // Copy the debug sections and string table.
- uint32_t debug_offsets[kExpectedSectionsInOATFile];
- memset(debug_offsets, '\0', sizeof debug_offsets);
- Elf32_Shdr *text_header = nullptr;
- int extra_shstrtab_entries = -1;
- int text_section_index = -1;
- int section_index = 1;
- for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
- Elf32_Shdr& section_header = all.GetSectionHeader(i);
- // Round up to multiple of 4, ensuring zero fill.
- RoundAndClear(jit_elf_image_, offset, 4);
- if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
- // Debug section: we need it. Unfortunately, it wasn't mapped in.
- debug_offsets[i] = offset;
- // Read it from the file.
- lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
- read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
- offset += section_header.sh_size;
- section_index++;
- offset += 16;
- } else if (section_header.sh_type == SHT_STRTAB &&
- strcmp(".shstrtab",
- all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
- // We also need the shared string table.
- debug_offsets[i] = offset;
- // Read it from the file.
- lseek(file_->Fd(), section_header.sh_offset, SEEK_SET);
- read(file_->Fd(), jit_elf_image_ + offset, section_header.sh_size);
- offset += section_header.sh_size;
- // We also need the extra strings .symtab\0.strtab\0
- extra_shstrtab_entries = section_header.sh_size;
- memcpy(jit_elf_image_+offset, ".symtab\0.strtab\0", 16);
- offset += 16;
- section_index++;
- } else if (section_header.sh_flags & SHF_EXECINSTR) {
- DCHECK(strcmp(".text", all.GetString(SHT_SYMTAB,
- section_header.sh_name)) == 0);
- text_header = &section_header;
- text_section_index = section_index++;
- }
- }
- DCHECK(text_header != nullptr);
- DCHECK_NE(extra_shstrtab_entries, -1);
-
- // We now need to update the addresses for debug_info and debug_frame to get to the
- // correct offset within the .text section.
- byte *p = jit_elf_image_+debug_offsets[8];
- byte *end = p + all.GetSectionHeader(8).sh_size;
-
- // For debug_info; patch compilation using low_pc @ offset 13, high_pc at offset 17.
- IncrementUint32(p + 13, text_start_addr);
- IncrementUint32(p + 17, text_start_addr);
-
- // Now fix the low_pc, high_pc for each method address.
- // First method starts at offset 0x15, each subsequent method is 1+3*4 bytes further.
- for (p += 0x15; p < end; p += 1 /* attr# */ + 3 * sizeof(uint32_t) /* addresses */) {
- IncrementUint32(p + 1 + sizeof(uint32_t), text_start_addr);
- IncrementUint32(p + 1 + 2 * sizeof(uint32_t), text_start_addr);
- }
-
- // Now we have to handle the debug_frame method start addresses
- p = jit_elf_image_+debug_offsets[10];
- end = p + all.GetSectionHeader(10).sh_size;
-
- // Skip past the CIE.
- p += *reinterpret_cast<uint32_t *>(p) + 4;
-
- // And walk the FDEs.
- for (; p < end; p += *reinterpret_cast<uint32_t *>(p) + sizeof(uint32_t)) {
- IncrementUint32(p + 2 * sizeof(uint32_t), text_start_addr);
- }
-
- // Create the data for the symbol table.
- const int kSymbtabAlignment = 16;
- RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
- uint32_t symtab_offset = offset;
-
- // First entry is empty.
- memset(jit_elf_image_+offset, 0, sizeof(Elf32_Sym));
- offset += sizeof(Elf32_Sym);
-
- // Symbol 1 is the real .text section.
- Elf32_Sym& sym_ent = *reinterpret_cast<Elf32_Sym*>(jit_elf_image_+offset);
- sym_ent.st_name = 1; /* .text */
- sym_ent.st_value = text_start_addr;
- sym_ent.st_size = text_header->sh_size;
- SetBindingAndType(&sym_ent, STB_LOCAL, STT_SECTION);
- sym_ent.st_other = 0;
- sym_ent.st_shndx = text_section_index;
- offset += sizeof(Elf32_Sym);
-
- // Create the data for the string table.
- RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
- const int kTextStringSize = 7;
- uint32_t strtab_offset = offset;
- memcpy(jit_elf_image_+offset, "\0.text", kTextStringSize);
- offset += kTextStringSize;
-
- // Create the section header table.
- // Round up to multiple of kSymbtabAlignment, ensuring zero fill.
- RoundAndClear(jit_elf_image_, offset, kSymbtabAlignment);
- elf_hdr.e_shoff = offset;
- Elf32_Shdr *sp =
- reinterpret_cast<Elf32_Shdr *>(jit_elf_image_ + offset);
-
- // Copy the first empty index.
- *sp = all.GetSectionHeader(0);
- BUMP_SHENT(sp);
-
- elf_hdr.e_shnum = 1;
- for (Elf32_Word i = 1; i < kExpectedSectionsInOATFile; i++) {
- Elf32_Shdr& section_header = all.GetSectionHeader(i);
- if (section_header.sh_addr == 0 && section_header.sh_type != SHT_DYNSYM) {
- // Debug section: we need it.
- *sp = section_header;
- sp->sh_offset = debug_offsets[i];
- sp->sh_addr = 0;
- elf_hdr.e_shnum++;
- BUMP_SHENT(sp);
- } else if (section_header.sh_type == SHT_STRTAB &&
- strcmp(".shstrtab",
- all.GetString(SHT_SYMTAB, section_header.sh_name)) == 0) {
- // We also need the shared string table.
- *sp = section_header;
- sp->sh_offset = debug_offsets[i];
- sp->sh_size += 16; /* sizeof ".symtab\0.strtab\0" */
- sp->sh_addr = 0;
- elf_hdr.e_shstrndx = elf_hdr.e_shnum;
- elf_hdr.e_shnum++;
- BUMP_SHENT(sp);
- }
+ text_sec->sh_type = SHT_NOBITS;
+ text_sec->sh_offset = 0;
+
+ if (!FixupDebugSections(
+ all.Begin() + debug_abbrev->sh_offset, debug_abbrev->sh_size, text_sec->sh_addr,
+ all.Begin() + debug_info->sh_offset, debug_info->sh_size,
+ all.Begin() + debug_frame->sh_offset, debug_frame->sh_size)) {
+ LOG(ERROR) << "Failed to load GDB data";
+ return;
}
- // Add a .text section for the matching code section.
- *sp = *text_header;
- sp->sh_type = SHT_NOBITS;
- sp->sh_offset = 0;
- sp->sh_addr = text_start_addr;
- elf_hdr.e_shnum++;
- BUMP_SHENT(sp);
-
- // .symtab section: Need an empty index and the .text entry
- sp->sh_name = extra_shstrtab_entries;
- sp->sh_type = SHT_SYMTAB;
- sp->sh_flags = 0;
- sp->sh_addr = 0;
- sp->sh_offset = symtab_offset;
- sp->sh_size = 2 * sizeof(Elf32_Sym);
- sp->sh_link = elf_hdr.e_shnum + 1; // Link to .strtab section.
- sp->sh_info = 0;
- sp->sh_addralign = 16;
- sp->sh_entsize = sizeof(Elf32_Sym);
- elf_hdr.e_shnum++;
- BUMP_SHENT(sp);
-
- // .strtab section: Enough for .text\0.
- sp->sh_name = extra_shstrtab_entries + 8;
- sp->sh_type = SHT_STRTAB;
- sp->sh_flags = 0;
- sp->sh_addr = 0;
- sp->sh_offset = strtab_offset;
- sp->sh_size = kTextStringSize;
- sp->sh_link = 0;
- sp->sh_info = 0;
- sp->sh_addralign = 16;
- sp->sh_entsize = 0;
- elf_hdr.e_shnum++;
- BUMP_SHENT(sp);
-
- // We now have enough information to tell GDB about our file.
- jit_gdb_entry_ = CreateCodeEntry(jit_elf_image_, offset);
+ jit_gdb_entry_ = CreateCodeEntry(all.Begin(), all.Size());
+ gdb_file_mapping_.reset(all_ptr.release());
}
} // namespace art