summaryrefslogtreecommitdiffstats
path: root/compiler/elf_writer_quick.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/elf_writer_quick.cc')
-rw-r--r--compiler/elf_writer_quick.cc906
1 files changed, 636 insertions, 270 deletions
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index bb5f7e0f9d..e45eb61030 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -16,11 +16,14 @@
#include "elf_writer_quick.h"
+#include <unordered_map>
+
#include "base/logging.h"
#include "base/unix_file/fd_file.h"
#include "buffered_output_stream.h"
#include "driver/compiler_driver.h"
#include "dwarf.h"
+#include "elf_file.h"
#include "elf_utils.h"
#include "file_output_stream.h"
#include "globals.h"
@@ -39,6 +42,30 @@ static uint8_t MakeStInfo(uint8_t binding, uint8_t type) {
return ((binding) << 4) + ((type) & 0xf);
}
+static void PushByte(std::vector<uint8_t>* buf, int data) {
+ buf->push_back(data & 0xff);
+}
+
+static uint32_t PushStr(std::vector<uint8_t>* buf, const char* str, const char* def = nullptr) {
+ if (str == nullptr) {
+ str = def;
+ }
+
+ uint32_t offset = buf->size();
+ for (size_t i = 0; str[i] != '\0'; ++i) {
+ buf->push_back(str[i]);
+ }
+ buf->push_back('\0');
+ return offset;
+}
+
+static uint32_t PushStr(std::vector<uint8_t>* buf, const std::string &str) {
+ uint32_t offset = buf->size();
+ buf->insert(buf->end(), str.begin(), str.end());
+ buf->push_back('\0');
+ return offset;
+}
+
static void UpdateWord(std::vector<uint8_t>* buf, int offset, int data) {
(*buf)[offset+0] = data;
(*buf)[offset+1] = data >> 8;
@@ -51,7 +78,7 @@ static void PushHalf(std::vector<uint8_t>* buf, int data) {
buf->push_back((data >> 8) & 0xff);
}
-bool ElfWriterQuick::ElfBuilder::Write() {
+bool ElfWriterQuick::ElfBuilder::Init() {
// The basic layout of the elf file. Order may be different in final output.
// +-------------------------+
// | Elf32_Ehdr |
@@ -120,16 +147,19 @@ bool ElfWriterQuick::ElfBuilder::Write() {
// | .debug_str\0 | (Optional)
// | .debug_info\0 | (Optional)
// | .eh_frame\0 | (Optional)
+ // | .debug_line\0 | (Optional)
// | .debug_abbrev\0 | (Optional)
// +-------------------------+ (Optional)
- // | .debug_str | (Optional)
- // +-------------------------+ (Optional)
// | .debug_info | (Optional)
// +-------------------------+ (Optional)
+ // | .debug_abbrev | (Optional)
+ // +-------------------------+ (Optional)
// | .eh_frame | (Optional)
// +-------------------------+ (Optional)
- // | .debug_abbrev | (Optional)
- // +-------------------------+
+ // | .debug_line | (Optional)
+ // +-------------------------+ (Optional)
+ // | .debug_str | (Optional)
+ // +-------------------------+ (Optional)
// | Elf32_Shdr NULL |
// | Elf32_Shdr .dynsym |
// | Elf32_Shdr .dynstr |
@@ -138,173 +168,117 @@ bool ElfWriterQuick::ElfBuilder::Write() {
// | Elf32_Shdr .rodata |
// | Elf32_Shdr .dynamic |
// | Elf32_Shdr .shstrtab |
- // | Elf32_Shdr .debug_str | (Optional)
// | Elf32_Shdr .debug_info | (Optional)
- // | Elf32_Shdr .eh_frame | (Optional)
// | Elf32_Shdr .debug_abbrev| (Optional)
+ // | Elf32_Shdr .eh_frame | (Optional)
+ // | Elf32_Shdr .debug_line | (Optional)
+ // | Elf32_Shdr .debug_str | (Optional)
// +-------------------------+
-
if (fatal_error_) {
return false;
}
// Step 1. Figure out all the offsets.
- // What phdr is.
- uint32_t phdr_offset = sizeof(Elf32_Ehdr);
- const uint8_t PH_PHDR = 0;
- const uint8_t PH_LOAD_R__ = 1;
- const uint8_t PH_LOAD_R_X = 2;
- const uint8_t PH_LOAD_RW_ = 3;
- const uint8_t PH_DYNAMIC = 4;
- const uint8_t PH_NUM = 5;
- uint32_t phdr_size = sizeof(Elf32_Phdr) * PH_NUM;
if (debug_logging_) {
- LOG(INFO) << "phdr_offset=" << phdr_offset << std::hex << " " << phdr_offset;
- LOG(INFO) << "phdr_size=" << phdr_size << std::hex << " " << phdr_size;
+ LOG(INFO) << "phdr_offset=" << PHDR_OFFSET << std::hex << " " << PHDR_OFFSET;
+ LOG(INFO) << "phdr_size=" << PHDR_SIZE << std::hex << " " << PHDR_SIZE;
}
- Elf32_Phdr program_headers[PH_NUM];
- memset(&program_headers, 0, sizeof(program_headers));
- program_headers[PH_PHDR].p_type = PT_PHDR;
- program_headers[PH_PHDR].p_offset = phdr_offset;
- program_headers[PH_PHDR].p_vaddr = phdr_offset;
- program_headers[PH_PHDR].p_paddr = phdr_offset;
- program_headers[PH_PHDR].p_filesz = sizeof(program_headers);
- program_headers[PH_PHDR].p_memsz = sizeof(program_headers);
- program_headers[PH_PHDR].p_flags = PF_R;
- program_headers[PH_PHDR].p_align = sizeof(Elf32_Word);
-
- program_headers[PH_LOAD_R__].p_type = PT_LOAD;
- program_headers[PH_LOAD_R__].p_offset = 0;
- program_headers[PH_LOAD_R__].p_vaddr = 0;
- program_headers[PH_LOAD_R__].p_paddr = 0;
- program_headers[PH_LOAD_R__].p_flags = PF_R;
-
- program_headers[PH_LOAD_R_X].p_type = PT_LOAD;
- program_headers[PH_LOAD_R_X].p_flags = PF_R | PF_X;
-
- program_headers[PH_LOAD_RW_].p_type = PT_LOAD;
- program_headers[PH_LOAD_RW_].p_flags = PF_R | PF_W;
-
- program_headers[PH_DYNAMIC].p_type = PT_DYNAMIC;
- program_headers[PH_DYNAMIC].p_flags = PF_R | PF_W;
+
+ memset(&program_headers_, 0, sizeof(program_headers_));
+ program_headers_[PH_PHDR].p_type = PT_PHDR;
+ program_headers_[PH_PHDR].p_offset = PHDR_OFFSET;
+ program_headers_[PH_PHDR].p_vaddr = PHDR_OFFSET;
+ program_headers_[PH_PHDR].p_paddr = PHDR_OFFSET;
+ program_headers_[PH_PHDR].p_filesz = sizeof(program_headers_);
+ program_headers_[PH_PHDR].p_memsz = sizeof(program_headers_);
+ program_headers_[PH_PHDR].p_flags = PF_R;
+ program_headers_[PH_PHDR].p_align = sizeof(Elf32_Word);
+
+ program_headers_[PH_LOAD_R__].p_type = PT_LOAD;
+ program_headers_[PH_LOAD_R__].p_offset = 0;
+ program_headers_[PH_LOAD_R__].p_vaddr = 0;
+ program_headers_[PH_LOAD_R__].p_paddr = 0;
+ program_headers_[PH_LOAD_R__].p_flags = PF_R;
+
+ program_headers_[PH_LOAD_R_X].p_type = PT_LOAD;
+ program_headers_[PH_LOAD_R_X].p_flags = PF_R | PF_X;
+
+ program_headers_[PH_LOAD_RW_].p_type = PT_LOAD;
+ program_headers_[PH_LOAD_RW_].p_flags = PF_R | PF_W;
+
+ program_headers_[PH_DYNAMIC].p_type = PT_DYNAMIC;
+ program_headers_[PH_DYNAMIC].p_flags = PF_R | PF_W;
// Get the dynstr string.
- std::string dynstr(dynsym_builder_.GenerateStrtab());
+ dynstr_ = dynsym_builder_.GenerateStrtab();
// Add the SONAME to the dynstr.
- uint32_t dynstr_soname_offset = dynstr.size();
+ dynstr_soname_offset_ = dynstr_.size();
std::string file_name(elf_file_->GetPath());
size_t directory_separator_pos = file_name.rfind('/');
if (directory_separator_pos != std::string::npos) {
file_name = file_name.substr(directory_separator_pos + 1);
}
- dynstr += file_name;
- dynstr += '\0';
+ dynstr_ += file_name;
+ dynstr_ += '\0';
if (debug_logging_) {
- LOG(INFO) << "dynstr size (bytes) =" << dynstr.size()
- << std::hex << " " << dynstr.size();
+ LOG(INFO) << "dynstr size (bytes) =" << dynstr_.size()
+ << std::hex << " " << dynstr_.size();
LOG(INFO) << "dynsym size (elements)=" << dynsym_builder_.GetSize()
<< std::hex << " " << dynsym_builder_.GetSize();
}
- // get the strtab
- std::string strtab;
- if (IncludingDebugSymbols()) {
- strtab = symtab_builder_.GenerateStrtab();
- if (debug_logging_) {
- LOG(INFO) << "strtab size (bytes) =" << strtab.size()
- << std::hex << " " << strtab.size();
- LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
- << std::hex << " " << symtab_builder_.GetSize();
- }
- }
-
// Get the section header string table.
- std::vector<Elf32_Shdr*> section_ptrs;
- std::string shstrtab;
- shstrtab += '\0';
+ shstrtab_ += '\0';
// Setup sym_undef
- Elf32_Shdr null_hdr;
- memset(&null_hdr, 0, sizeof(null_hdr));
- null_hdr.sh_type = SHT_NULL;
- null_hdr.sh_link = SHN_UNDEF;
- section_ptrs.push_back(&null_hdr);
+ memset(&null_hdr_, 0, sizeof(null_hdr_));
+ null_hdr_.sh_type = SHT_NULL;
+ null_hdr_.sh_link = SHN_UNDEF;
+ section_ptrs_.push_back(&null_hdr_);
- uint32_t section_index = 1;
+ section_index_ = 1;
// setup .dynsym
- section_ptrs.push_back(&dynsym_builder_.section_);
- AssignSectionStr(&dynsym_builder_, &shstrtab);
- dynsym_builder_.section_index_ = section_index++;
+ section_ptrs_.push_back(&dynsym_builder_.section_);
+ AssignSectionStr(&dynsym_builder_, &shstrtab_);
+ dynsym_builder_.section_index_ = section_index_++;
// Setup .dynstr
- section_ptrs.push_back(&dynsym_builder_.strtab_.section_);
- AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab);
- dynsym_builder_.strtab_.section_index_ = section_index++;
+ section_ptrs_.push_back(&dynsym_builder_.strtab_.section_);
+ AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab_);
+ dynsym_builder_.strtab_.section_index_ = section_index_++;
// Setup .hash
- section_ptrs.push_back(&hash_builder_.section_);
- AssignSectionStr(&hash_builder_, &shstrtab);
- hash_builder_.section_index_ = section_index++;
+ section_ptrs_.push_back(&hash_builder_.section_);
+ AssignSectionStr(&hash_builder_, &shstrtab_);
+ hash_builder_.section_index_ = section_index_++;
// Setup .rodata
- section_ptrs.push_back(&rodata_builder_.section_);
- AssignSectionStr(&rodata_builder_, &shstrtab);
- rodata_builder_.section_index_ = section_index++;
+ section_ptrs_.push_back(&rodata_builder_.section_);
+ AssignSectionStr(&rodata_builder_, &shstrtab_);
+ rodata_builder_.section_index_ = section_index_++;
// Setup .text
- section_ptrs.push_back(&text_builder_.section_);
- AssignSectionStr(&text_builder_, &shstrtab);
- text_builder_.section_index_ = section_index++;
+ section_ptrs_.push_back(&text_builder_.section_);
+ AssignSectionStr(&text_builder_, &shstrtab_);
+ text_builder_.section_index_ = section_index_++;
// Setup .dynamic
- section_ptrs.push_back(&dynamic_builder_.section_);
- AssignSectionStr(&dynamic_builder_, &shstrtab);
- dynamic_builder_.section_index_ = section_index++;
-
- if (IncludingDebugSymbols()) {
- // Setup .symtab
- section_ptrs.push_back(&symtab_builder_.section_);
- AssignSectionStr(&symtab_builder_, &shstrtab);
- symtab_builder_.section_index_ = section_index++;
-
- // Setup .strtab
- section_ptrs.push_back(&symtab_builder_.strtab_.section_);
- AssignSectionStr(&symtab_builder_.strtab_, &shstrtab);
- symtab_builder_.strtab_.section_index_ = section_index++;
- }
- ElfRawSectionBuilder* it = other_builders_.data();
- for (uint32_t cnt = 0; cnt < other_builders_.size(); ++it, ++cnt) {
- // Setup all the other sections.
- section_ptrs.push_back(&it->section_);
- AssignSectionStr(it, &shstrtab);
- it->section_index_ = section_index++;
- }
-
- // Setup shstrtab
- section_ptrs.push_back(&shstrtab_builder_.section_);
- AssignSectionStr(&shstrtab_builder_, &shstrtab);
- shstrtab_builder_.section_index_ = section_index++;
-
- if (debug_logging_) {
- LOG(INFO) << ".shstrtab size (bytes) =" << shstrtab.size()
- << std::hex << " " << shstrtab.size();
- LOG(INFO) << "section list size (elements)=" << section_ptrs.size()
- << std::hex << " " << section_ptrs.size();
- }
+ section_ptrs_.push_back(&dynamic_builder_.section_);
+ AssignSectionStr(&dynamic_builder_, &shstrtab_);
+ dynamic_builder_.section_index_ = section_index_++;
// Fill in the hash section.
- std::vector<Elf32_Word> hash = dynsym_builder_.GenerateHashContents();
+ hash_ = dynsym_builder_.GenerateHashContents();
if (debug_logging_) {
- LOG(INFO) << ".hash size (bytes)=" << hash.size() * sizeof(Elf32_Word)
- << std::hex << " " << hash.size() * sizeof(Elf32_Word);
+ LOG(INFO) << ".hash size (bytes)=" << hash_.size() * sizeof(Elf32_Word)
+ << std::hex << " " << hash_.size() * sizeof(Elf32_Word);
}
- Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers);
- std::vector<ElfFilePiece> pieces;
+ Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers_);
// Get the layout in the sections.
//
@@ -318,14 +292,14 @@ bool ElfWriterQuick::ElfBuilder::Write() {
dynsym_builder_.strtab_.section_.sh_offset = NextOffset(dynsym_builder_.strtab_.section_,
dynsym_builder_.section_);
dynsym_builder_.strtab_.section_.sh_addr = dynsym_builder_.strtab_.section_.sh_offset;
- dynsym_builder_.strtab_.section_.sh_size = dynstr.size();
+ dynsym_builder_.strtab_.section_.sh_size = dynstr_.size();
dynsym_builder_.strtab_.section_.sh_link = dynsym_builder_.strtab_.GetLink();
// Get the layout of the hash section
hash_builder_.section_.sh_offset = NextOffset(hash_builder_.section_,
dynsym_builder_.strtab_.section_);
hash_builder_.section_.sh_addr = hash_builder_.section_.sh_offset;
- hash_builder_.section_.sh_size = hash.size() * sizeof(Elf32_Word);
+ hash_builder_.section_.sh_size = hash_.size() * sizeof(Elf32_Word);
hash_builder_.section_.sh_link = hash_builder_.GetLink();
// Get the layout of the rodata section.
@@ -349,7 +323,70 @@ bool ElfWriterQuick::ElfBuilder::Write() {
dynamic_builder_.section_.sh_size = dynamic_builder_.GetSize() * sizeof(Elf32_Dyn);
dynamic_builder_.section_.sh_link = dynamic_builder_.GetLink();
+ if (debug_logging_) {
+ LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset
+ << " dynsym size=" << dynsym_builder_.section_.sh_size;
+ LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset
+ << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size;
+ LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset
+ << " hash size=" << hash_builder_.section_.sh_size;
+ LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset
+ << " rodata size=" << rodata_builder_.section_.sh_size;
+ LOG(INFO) << "text off=" << text_builder_.section_.sh_offset
+ << " text size=" << text_builder_.section_.sh_size;
+ LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset
+ << " dynamic size=" << dynamic_builder_.section_.sh_size;
+ }
+
+ return true;
+}
+
+bool ElfWriterQuick::ElfBuilder::Write() {
+ std::vector<ElfFilePiece> pieces;
Elf32_Shdr prev = dynamic_builder_.section_;
+ std::string strtab;
+
+ if (IncludingDebugSymbols()) {
+ // Setup .symtab
+ section_ptrs_.push_back(&symtab_builder_.section_);
+ AssignSectionStr(&symtab_builder_, &shstrtab_);
+ symtab_builder_.section_index_ = section_index_++;
+
+ // Setup .strtab
+ section_ptrs_.push_back(&symtab_builder_.strtab_.section_);
+ AssignSectionStr(&symtab_builder_.strtab_, &shstrtab_);
+ symtab_builder_.strtab_.section_index_ = section_index_++;
+
+ strtab = symtab_builder_.GenerateStrtab();
+ if (debug_logging_) {
+ LOG(INFO) << "strtab size (bytes) =" << strtab.size()
+ << std::hex << " " << strtab.size();
+ LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
+ << std::hex << " " << symtab_builder_.GetSize();
+ }
+ }
+
+ // Setup all the other sections.
+ for (ElfRawSectionBuilder *builder = other_builders_.data(),
+ *end = builder + other_builders_.size();
+ builder != end; ++builder) {
+ section_ptrs_.push_back(&builder->section_);
+ AssignSectionStr(builder, &shstrtab_);
+ builder->section_index_ = section_index_++;
+ }
+
+ // Setup shstrtab
+ section_ptrs_.push_back(&shstrtab_builder_.section_);
+ AssignSectionStr(&shstrtab_builder_, &shstrtab_);
+ shstrtab_builder_.section_index_ = section_index_++;
+
+ if (debug_logging_) {
+ LOG(INFO) << ".shstrtab size (bytes) =" << shstrtab_.size()
+ << std::hex << " " << shstrtab_.size();
+ LOG(INFO) << "section list size (elements)=" << section_ptrs_.size()
+ << std::hex << " " << section_ptrs_.size();
+ }
+
if (IncludingDebugSymbols()) {
// Get the layout of the symtab section.
symtab_builder_.section_.sh_offset = NextOffset(symtab_builder_.section_,
@@ -367,27 +404,14 @@ bool ElfWriterQuick::ElfBuilder::Write() {
symtab_builder_.strtab_.section_.sh_link = symtab_builder_.strtab_.GetLink();
prev = symtab_builder_.strtab_.section_;
- }
- if (debug_logging_) {
- LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset
- << " dynsym size=" << dynsym_builder_.section_.sh_size;
- LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset
- << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size;
- LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset
- << " hash size=" << hash_builder_.section_.sh_size;
- LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset
- << " rodata size=" << rodata_builder_.section_.sh_size;
- LOG(INFO) << "text off=" << text_builder_.section_.sh_offset
- << " text size=" << text_builder_.section_.sh_size;
- LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset
- << " dynamic size=" << dynamic_builder_.section_.sh_size;
- if (IncludingDebugSymbols()) {
+ if (debug_logging_) {
LOG(INFO) << "symtab off=" << symtab_builder_.section_.sh_offset
<< " symtab size=" << symtab_builder_.section_.sh_size;
LOG(INFO) << "strtab off=" << symtab_builder_.strtab_.section_.sh_offset
<< " strtab size=" << symtab_builder_.strtab_.section_.sh_size;
}
}
+
// Get the layout of the extra sections. (This will deal with the debug
// sections if they are there)
for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) {
@@ -403,10 +427,11 @@ bool ElfWriterQuick::ElfBuilder::Write() {
<< " " << it->name_ << " size=" << it->section_.sh_size;
}
}
+
// Get the layout of the shstrtab section
shstrtab_builder_.section_.sh_offset = NextOffset(shstrtab_builder_.section_, prev);
shstrtab_builder_.section_.sh_addr = 0;
- shstrtab_builder_.section_.sh_size = shstrtab.size();
+ shstrtab_builder_.section_.sh_size = shstrtab_.size();
shstrtab_builder_.section_.sh_link = shstrtab_builder_.GetLink();
if (debug_logging_) {
LOG(INFO) << "shstrtab off=" << shstrtab_builder_.section_.sh_offset
@@ -430,58 +455,58 @@ bool ElfWriterQuick::ElfBuilder::Write() {
// Setup the dynamic section.
// This will add the 2 values we cannot know until now time, namely the size
// and the soname_offset.
- std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr.size(),
- dynstr_soname_offset);
+ std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr_.size(),
+ dynstr_soname_offset_);
CHECK_EQ(dynamic.size() * sizeof(Elf32_Dyn), dynamic_builder_.section_.sh_size);
// Finish setup of the program headers now that we know the layout of the
// whole file.
Elf32_Word load_r_size = rodata_builder_.section_.sh_offset + rodata_builder_.section_.sh_size;
- program_headers[PH_LOAD_R__].p_filesz = load_r_size;
- program_headers[PH_LOAD_R__].p_memsz = load_r_size;
- program_headers[PH_LOAD_R__].p_align = rodata_builder_.section_.sh_addralign;
+ program_headers_[PH_LOAD_R__].p_filesz = load_r_size;
+ program_headers_[PH_LOAD_R__].p_memsz = load_r_size;
+ program_headers_[PH_LOAD_R__].p_align = rodata_builder_.section_.sh_addralign;
Elf32_Word load_rx_size = text_builder_.section_.sh_size;
- program_headers[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset;
- program_headers[PH_LOAD_R_X].p_vaddr = text_builder_.section_.sh_offset;
- program_headers[PH_LOAD_R_X].p_paddr = text_builder_.section_.sh_offset;
- program_headers[PH_LOAD_R_X].p_filesz = load_rx_size;
- program_headers[PH_LOAD_R_X].p_memsz = load_rx_size;
- program_headers[PH_LOAD_R_X].p_align = text_builder_.section_.sh_addralign;
-
- program_headers[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset;
- program_headers[PH_LOAD_RW_].p_vaddr = dynamic_builder_.section_.sh_offset;
- program_headers[PH_LOAD_RW_].p_paddr = dynamic_builder_.section_.sh_offset;
- program_headers[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size;
- program_headers[PH_LOAD_RW_].p_memsz = dynamic_builder_.section_.sh_size;
- program_headers[PH_LOAD_RW_].p_align = dynamic_builder_.section_.sh_addralign;
-
- program_headers[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset;
- program_headers[PH_DYNAMIC].p_vaddr = dynamic_builder_.section_.sh_offset;
- program_headers[PH_DYNAMIC].p_paddr = dynamic_builder_.section_.sh_offset;
- program_headers[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size;
- program_headers[PH_DYNAMIC].p_memsz = dynamic_builder_.section_.sh_size;
- program_headers[PH_DYNAMIC].p_align = dynamic_builder_.section_.sh_addralign;
+ program_headers_[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_R_X].p_vaddr = text_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_R_X].p_paddr = text_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_R_X].p_filesz = load_rx_size;
+ program_headers_[PH_LOAD_R_X].p_memsz = load_rx_size;
+ program_headers_[PH_LOAD_R_X].p_align = text_builder_.section_.sh_addralign;
+
+ program_headers_[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_RW_].p_vaddr = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_RW_].p_paddr = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size;
+ program_headers_[PH_LOAD_RW_].p_memsz = dynamic_builder_.section_.sh_size;
+ program_headers_[PH_LOAD_RW_].p_align = dynamic_builder_.section_.sh_addralign;
+
+ program_headers_[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_DYNAMIC].p_vaddr = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_DYNAMIC].p_paddr = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size;
+ program_headers_[PH_DYNAMIC].p_memsz = dynamic_builder_.section_.sh_size;
+ program_headers_[PH_DYNAMIC].p_align = dynamic_builder_.section_.sh_addralign;
// Finish setup of the Ehdr values.
- elf_header_.e_phoff = phdr_offset;
+ elf_header_.e_phoff = PHDR_OFFSET;
elf_header_.e_shoff = sections_offset;
elf_header_.e_phnum = PH_NUM;
- elf_header_.e_shnum = section_ptrs.size();
+ elf_header_.e_shnum = section_ptrs_.size();
elf_header_.e_shstrndx = shstrtab_builder_.section_index_;
// Add the rest of the pieces to the list.
pieces.push_back(ElfFilePiece("Elf Header", 0, &elf_header_, sizeof(elf_header_)));
- pieces.push_back(ElfFilePiece("Program headers", phdr_offset,
- &program_headers, sizeof(program_headers)));
+ pieces.push_back(ElfFilePiece("Program headers", PHDR_OFFSET,
+ &program_headers_, sizeof(program_headers_)));
pieces.push_back(ElfFilePiece(".dynamic", dynamic_builder_.section_.sh_offset,
dynamic.data(), dynamic_builder_.section_.sh_size));
pieces.push_back(ElfFilePiece(".dynsym", dynsym_builder_.section_.sh_offset,
dynsym.data(), dynsym.size() * sizeof(Elf32_Sym)));
pieces.push_back(ElfFilePiece(".dynstr", dynsym_builder_.strtab_.section_.sh_offset,
- dynstr.c_str(), dynstr.size()));
+ dynstr_.c_str(), dynstr_.size()));
pieces.push_back(ElfFilePiece(".hash", hash_builder_.section_.sh_offset,
- hash.data(), hash.size() * sizeof(Elf32_Word)));
+ hash_.data(), hash_.size() * sizeof(Elf32_Word)));
pieces.push_back(ElfFilePiece(".rodata", rodata_builder_.section_.sh_offset,
nullptr, rodata_builder_.section_.sh_size));
pieces.push_back(ElfFilePiece(".text", text_builder_.section_.sh_offset,
@@ -493,13 +518,13 @@ bool ElfWriterQuick::ElfBuilder::Write() {
strtab.c_str(), strtab.size()));
}
pieces.push_back(ElfFilePiece(".shstrtab", shstrtab_builder_.section_.sh_offset,
- &shstrtab[0], shstrtab.size()));
- for (uint32_t i = 0; i < section_ptrs.size(); ++i) {
+ &shstrtab_[0], shstrtab_.size()));
+ for (uint32_t i = 0; i < section_ptrs_.size(); ++i) {
// Just add all the sections in induvidually since they are all over the
// place on the heap/stack.
Elf32_Word cur_off = sections_offset + i * sizeof(Elf32_Shdr);
pieces.push_back(ElfFilePiece("section table piece", cur_off,
- section_ptrs[i], sizeof(Elf32_Shdr)));
+ section_ptrs_[i], sizeof(Elf32_Shdr)));
}
if (!WriteOutFile(pieces)) {
@@ -664,7 +689,7 @@ std::vector<Elf32_Word> ElfWriterQuick::ElfSymtabBuilder::GenerateHashContents()
// Lets say the state is something like this.
// +--------+ +--------+ +-----------+
// | symtab | | bucket | | chain |
- // | nullptr | | 1 | | STN_UNDEF |
+ // | null | | 1 | | STN_UNDEF |
// | <sym1> | | 4 | | 2 |
// | <sym2> | | | | 5 |
// | <sym3> | | | | STN_UNDEF |
@@ -836,13 +861,24 @@ void ElfWriterQuick::ReservePatchSpace(std::vector<uint8_t>* buffer, bool debug)
}
std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) {
- std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+ std::vector<uint8_t>* cfi_info = new std::vector<uint8_t>;
// Length (will be filled in later in this routine).
- PushWord(cfi_info, 0);
+ if (is_x86_64) {
+ PushWord(cfi_info, 0xffffffff); // Indicates 64bit
+ PushWord(cfi_info, 0);
+ PushWord(cfi_info, 0);
+ } else {
+ PushWord(cfi_info, 0);
+ }
// CIE id: always 0.
- PushWord(cfi_info, 0);
+ if (is_x86_64) {
+ PushWord(cfi_info, 0);
+ PushWord(cfi_info, 0);
+ } else {
+ PushWord(cfi_info, 0);
+ }
// Version: always 1.
cfi_info->push_back(0x01);
@@ -874,8 +910,14 @@ std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) {
// Augmentation length: 1.
cfi_info->push_back(1);
- // Augmentation data: 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
- cfi_info->push_back(0x03);
+ // Augmentation data.
+ if (is_x86_64) {
+ // 0x04 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8).
+ cfi_info->push_back(0x04);
+ } else {
+ // 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
+ cfi_info->push_back(0x03);
+ }
// Initial instructions.
if (is_x86_64) {
@@ -905,11 +947,13 @@ std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) {
}
// Set the length of the CIE inside the generated bytes.
- uint32_t length = cfi_info->size() - 4;
- (*cfi_info)[0] = length;
- (*cfi_info)[1] = length >> 8;
- (*cfi_info)[2] = length >> 16;
- (*cfi_info)[3] = length >> 24;
+ if (is_x86_64) {
+ uint32_t length = cfi_info->size() - 12;
+ UpdateWord(cfi_info, 4, length);
+ } else {
+ uint32_t length = cfi_info->size() - 4;
+ UpdateWord(cfi_info, 0, length);
+ }
return cfi_info;
}
@@ -940,8 +984,12 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer,
compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(),
debug);
+ if (!builder.Init()) {
+ return false;
+ }
+
if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
- WriteDebugSymbols(builder, oat_writer);
+ WriteDebugSymbols(&builder, oat_writer);
}
if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) {
@@ -954,15 +1002,17 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer,
return builder.Write();
}
-void ElfWriterQuick::WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_writer) {
+void ElfWriterQuick::WriteDebugSymbols(ElfBuilder* builder, OatWriter* oat_writer) {
std::unique_ptr<std::vector<uint8_t>> cfi_info(
ConstructCIEFrame(compiler_driver_->GetInstructionSet()));
+ Elf32_Addr text_section_address = builder->text_builder_.section_.sh_addr;
+
// Iterate over the compiled methods.
const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo();
- ElfSymtabBuilder* symtab = &builder.symtab_builder_;
+ ElfSymtabBuilder* symtab = &builder->symtab_builder_;
for (auto it = method_info.begin(); it != method_info.end(); ++it) {
- symtab->AddSymbol(it->method_name_, &builder.text_builder_, it->low_pc_, true,
+ symtab->AddSymbol(it->method_name_, &builder->text_builder_, it->low_pc_, true,
it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC);
// Include CFI for compiled method, if possible.
@@ -976,96 +1026,314 @@ void ElfWriterQuick::WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_write
int cur_offset = cfi_info->size();
cfi_info->insert(cfi_info->end(), fde->begin(), fde->end());
- // Set the 'CIE_pointer' field to cur_offset+4.
- uint32_t CIE_pointer = cur_offset + 4;
- uint32_t offset_to_update = cur_offset + sizeof(uint32_t);
- (*cfi_info)[offset_to_update+0] = CIE_pointer;
- (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
- (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
- (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
-
- // Set the 'initial_location' field to address the start of the method.
- offset_to_update = cur_offset + 2*sizeof(uint32_t);
- const uint32_t quick_code_start = it->low_pc_;
- (*cfi_info)[offset_to_update+0] = quick_code_start;
- (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
- (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
- (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+ bool is_64bit = *(reinterpret_cast<const uint32_t*>(fde->data())) == 0xffffffff;
+
+ // Set the 'CIE_pointer' field.
+ uint64_t CIE_pointer = cur_offset + (is_64bit ? 12 : 4);
+ uint64_t offset_to_update = CIE_pointer;
+ if (is_64bit) {
+ (*cfi_info)[offset_to_update+0] = CIE_pointer;
+ (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
+ (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
+ (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+ (*cfi_info)[offset_to_update+4] = CIE_pointer >> 32;
+ (*cfi_info)[offset_to_update+5] = CIE_pointer >> 40;
+ (*cfi_info)[offset_to_update+6] = CIE_pointer >> 48;
+ (*cfi_info)[offset_to_update+7] = CIE_pointer >> 56;
+ } else {
+ (*cfi_info)[offset_to_update+0] = CIE_pointer;
+ (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
+ (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
+ (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+ }
+
+ // Set the 'initial_location' field.
+ offset_to_update += is_64bit ? 8 : 4;
+ if (is_64bit) {
+ const uint64_t quick_code_start = it->low_pc_ + text_section_address;
+ (*cfi_info)[offset_to_update+0] = quick_code_start;
+ (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
+ (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
+ (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+ (*cfi_info)[offset_to_update+4] = quick_code_start >> 32;
+ (*cfi_info)[offset_to_update+5] = quick_code_start >> 40;
+ (*cfi_info)[offset_to_update+6] = quick_code_start >> 48;
+ (*cfi_info)[offset_to_update+7] = quick_code_start >> 56;
+ } else {
+ const uint32_t quick_code_start = it->low_pc_ + text_section_address;
+ (*cfi_info)[offset_to_update+0] = quick_code_start;
+ (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
+ (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
+ (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+ }
}
}
}
- if (cfi_info.get() != nullptr) {
- // Now lay down the Elf sections.
- ElfRawSectionBuilder debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ bool hasCFI = (cfi_info.get() != nullptr);
+ bool hasLineInfo = false;
+ for (auto& dbg_info : oat_writer->GetCFIMethodInfo()) {
+ if (dbg_info.dbgstream_ != nullptr &&
+ !dbg_info.compiled_method_->GetSrcMappingTable().empty()) {
+ hasLineInfo = true;
+ break;
+ }
+ }
+
+ if (hasLineInfo || hasCFI) {
+ ElfRawSectionBuilder debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- ElfRawSectionBuilder debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- ElfRawSectionBuilder eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
- eh_frame.SetBuffer(std::move(*cfi_info.get()));
-
- FillInCFIInformation(oat_writer, debug_info.GetBuffer(), debug_abbrev.GetBuffer(),
- debug_str.GetBuffer());
- builder.RegisterRawSection(debug_info);
- builder.RegisterRawSection(debug_abbrev);
- builder.RegisterRawSection(eh_frame);
- builder.RegisterRawSection(debug_str);
+ ElfRawSectionBuilder debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ ElfRawSectionBuilder debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+
+ FillInCFIInformation(oat_writer, debug_info.GetBuffer(),
+ debug_abbrev.GetBuffer(), debug_str.GetBuffer(),
+ hasLineInfo ? debug_line.GetBuffer() : nullptr,
+ text_section_address);
+
+ builder->RegisterRawSection(debug_info);
+ builder->RegisterRawSection(debug_abbrev);
+
+ if (hasCFI) {
+ ElfRawSectionBuilder eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
+ eh_frame.SetBuffer(std::move(*cfi_info.get()));
+ builder->RegisterRawSection(eh_frame);
+ }
+
+ if (hasLineInfo) {
+ builder->RegisterRawSection(debug_line);
+ }
+
+ builder->RegisterRawSection(debug_str);
+ }
+}
+
+class LineTableGenerator FINAL : public Leb128Encoder {
+ public:
+ LineTableGenerator(int line_base, int line_range, int opcode_base,
+ std::vector<uint8_t>* data, uintptr_t current_address,
+ size_t current_line)
+ : Leb128Encoder(data), line_base_(line_base), line_range_(line_range),
+ opcode_base_(opcode_base), current_address_(current_address),
+ current_line_(current_line) {}
+
+ void PutDelta(unsigned delta_addr, int delta_line) {
+ current_line_ += delta_line;
+ current_address_ += delta_addr;
+
+ if (delta_line >= line_base_ && delta_line < line_base_ + line_range_) {
+ unsigned special_opcode = (delta_line - line_base_) +
+ (line_range_ * delta_addr) + opcode_base_;
+ if (special_opcode <= 255) {
+ PushByte(data_, special_opcode);
+ return;
+ }
+ }
+
+ // generate standart opcode for address advance
+ if (delta_addr != 0) {
+ PushByte(data_, DW_LNS_advance_pc);
+ PushBackUnsigned(delta_addr);
+ }
+
+ // generate standart opcode for line delta
+ if (delta_line != 0) {
+ PushByte(data_, DW_LNS_advance_line);
+ PushBackSigned(delta_line);
+ }
+
+ // generate standart opcode for new LTN entry
+ PushByte(data_, DW_LNS_copy);
+ }
+
+ void SetAddr(uintptr_t addr) {
+ if (current_address_ == addr) {
+ return;
+ }
+
+ current_address_ = addr;
+
+ PushByte(data_, 0); // extended opcode:
+ PushByte(data_, 1 + 4); // length: opcode_size + address_size
+ PushByte(data_, DW_LNE_set_address);
+ PushWord(data_, addr);
+ }
+
+ void SetLine(unsigned line) {
+ int delta_line = line - current_line_;
+ if (delta_line) {
+ current_line_ = line;
+ PushByte(data_, DW_LNS_advance_line);
+ PushBackSigned(delta_line);
+ }
+ }
+
+ void SetFile(unsigned file_index) {
+ PushByte(data_, DW_LNS_set_file);
+ PushBackUnsigned(file_index);
+ }
+
+ void EndSequence() {
+ // End of Line Table Program
+ // 0(=ext), 1(len), DW_LNE_end_sequence
+ PushByte(data_, 0);
+ PushByte(data_, 1);
+ PushByte(data_, DW_LNE_end_sequence);
+ }
+
+ private:
+ const int line_base_;
+ const int line_range_;
+ const int opcode_base_;
+ uintptr_t current_address_;
+ size_t current_line_;
+
+ DISALLOW_COPY_AND_ASSIGN(LineTableGenerator);
+};
+
+// TODO: rewriting it using DexFile::DecodeDebugInfo needs unneeded stuff.
+static void GetLineInfoForJava(const uint8_t* dbgstream, const SrcMap& pc2dex,
+ SrcMap* result, uint32_t start_pc = 0) {
+ if (dbgstream == nullptr) {
+ return;
+ }
+
+ int adjopcode;
+ uint32_t dex_offset = 0;
+ uint32_t java_line = DecodeUnsignedLeb128(&dbgstream);
+
+ // skip parameters
+ for (uint32_t param_count = DecodeUnsignedLeb128(&dbgstream); param_count != 0; --param_count) {
+ DecodeUnsignedLeb128(&dbgstream);
+ }
+
+ for (bool is_end = false; is_end == false; ) {
+ uint8_t opcode = *dbgstream;
+ dbgstream++;
+ switch (opcode) {
+ case DexFile::DBG_END_SEQUENCE:
+ is_end = true;
+ break;
+
+ case DexFile::DBG_ADVANCE_PC:
+ dex_offset += DecodeUnsignedLeb128(&dbgstream);
+ break;
+
+ case DexFile::DBG_ADVANCE_LINE:
+ java_line += DecodeSignedLeb128(&dbgstream);
+ break;
+
+ case DexFile::DBG_START_LOCAL:
+ case DexFile::DBG_START_LOCAL_EXTENDED:
+ DecodeUnsignedLeb128(&dbgstream);
+ DecodeUnsignedLeb128(&dbgstream);
+ DecodeUnsignedLeb128(&dbgstream);
+
+ if (opcode == DexFile::DBG_START_LOCAL_EXTENDED) {
+ DecodeUnsignedLeb128(&dbgstream);
+ }
+ break;
+
+ case DexFile::DBG_END_LOCAL:
+ case DexFile::DBG_RESTART_LOCAL:
+ DecodeUnsignedLeb128(&dbgstream);
+ break;
+
+ case DexFile::DBG_SET_PROLOGUE_END:
+ case DexFile::DBG_SET_EPILOGUE_BEGIN:
+ case DexFile::DBG_SET_FILE:
+ break;
+
+ default:
+ adjopcode = opcode - DexFile::DBG_FIRST_SPECIAL;
+ dex_offset += adjopcode / DexFile::DBG_LINE_RANGE;
+ java_line += DexFile::DBG_LINE_BASE + (adjopcode % DexFile::DBG_LINE_RANGE);
+
+ for (SrcMap::const_iterator found = pc2dex.FindByTo(dex_offset);
+ found != pc2dex.end() && found->to_ == static_cast<int32_t>(dex_offset);
+ found++) {
+ result->push_back({found->from_ + start_pc, static_cast<int32_t>(java_line)});
+ }
+ break;
+ }
}
}
void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
std::vector<uint8_t>* dbg_info,
std::vector<uint8_t>* dbg_abbrev,
- std::vector<uint8_t>* dbg_str) {
+ std::vector<uint8_t>* dbg_str,
+ std::vector<uint8_t>* dbg_line,
+ uint32_t text_section_offset) {
+ const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo();
+
+ uint32_t producer_str_offset = PushStr(dbg_str, "Android dex2oat");
+
// Create the debug_abbrev section with boilerplate information.
// We only care about low_pc and high_pc right now for the compilation
// unit and methods.
// Tag 1: Compilation unit: DW_TAG_compile_unit.
- dbg_abbrev->push_back(1);
- dbg_abbrev->push_back(DW_TAG_compile_unit);
+ PushByte(dbg_abbrev, 1);
+ PushByte(dbg_abbrev, DW_TAG_compile_unit);
// There are children (the methods).
- dbg_abbrev->push_back(DW_CHILDREN_yes);
+ PushByte(dbg_abbrev, DW_CHILDREN_yes);
+
+ // DW_AT_producer DW_FORM_data1.
+ // REVIEW: we can get rid of dbg_str section if
+ // DW_FORM_string (immediate string) was used everywhere instead of
+ // DW_FORM_strp (ref to string from .debug_str section).
+ // DW_FORM_strp makes sense only if we reuse the strings.
+ PushByte(dbg_abbrev, DW_AT_producer);
+ PushByte(dbg_abbrev, DW_FORM_strp);
// DW_LANG_Java DW_FORM_data1.
- dbg_abbrev->push_back(DW_AT_language);
- dbg_abbrev->push_back(DW_FORM_data1);
+ PushByte(dbg_abbrev, DW_AT_language);
+ PushByte(dbg_abbrev, DW_FORM_data1);
// DW_AT_low_pc DW_FORM_addr.
- dbg_abbrev->push_back(DW_AT_low_pc);
- dbg_abbrev->push_back(DW_FORM_addr);
+ PushByte(dbg_abbrev, DW_AT_low_pc);
+ PushByte(dbg_abbrev, DW_FORM_addr);
// DW_AT_high_pc DW_FORM_addr.
- dbg_abbrev->push_back(DW_AT_high_pc);
- dbg_abbrev->push_back(DW_FORM_addr);
+ PushByte(dbg_abbrev, DW_AT_high_pc);
+ PushByte(dbg_abbrev, DW_FORM_addr);
+
+ if (dbg_line != nullptr) {
+ // DW_AT_stmt_list DW_FORM_sec_offset.
+ PushByte(dbg_abbrev, DW_AT_stmt_list);
+ PushByte(dbg_abbrev, DW_FORM_sec_offset);
+ }
// End of DW_TAG_compile_unit.
PushHalf(dbg_abbrev, 0);
// Tag 2: Compilation unit: DW_TAG_subprogram.
- dbg_abbrev->push_back(2);
- dbg_abbrev->push_back(DW_TAG_subprogram);
+ PushByte(dbg_abbrev, 2);
+ PushByte(dbg_abbrev, DW_TAG_subprogram);
// There are no children.
- dbg_abbrev->push_back(DW_CHILDREN_no);
+ PushByte(dbg_abbrev, DW_CHILDREN_no);
// Name of the method.
- dbg_abbrev->push_back(DW_AT_name);
- dbg_abbrev->push_back(DW_FORM_strp);
+ PushByte(dbg_abbrev, DW_AT_name);
+ PushByte(dbg_abbrev, DW_FORM_strp);
// DW_AT_low_pc DW_FORM_addr.
- dbg_abbrev->push_back(DW_AT_low_pc);
- dbg_abbrev->push_back(DW_FORM_addr);
+ PushByte(dbg_abbrev, DW_AT_low_pc);
+ PushByte(dbg_abbrev, DW_FORM_addr);
// DW_AT_high_pc DW_FORM_addr.
- dbg_abbrev->push_back(DW_AT_high_pc);
- dbg_abbrev->push_back(DW_FORM_addr);
+ PushByte(dbg_abbrev, DW_AT_high_pc);
+ PushByte(dbg_abbrev, DW_FORM_addr);
// End of DW_TAG_subprogram.
PushHalf(dbg_abbrev, 0);
// Start the debug_info section with the header information
// 'unit_length' will be filled in later.
+ int cunit_length = dbg_info->size();
PushWord(dbg_info, 0);
// 'version' - 3.
@@ -1075,55 +1343,153 @@ void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
PushWord(dbg_info, 0);
// Address size: 4.
- dbg_info->push_back(4);
+ PushByte(dbg_info, 4);
// Start the description for the compilation unit.
// This uses tag 1.
- dbg_info->push_back(1);
+ PushByte(dbg_info, 1);
+
+ // The producer is Android dex2oat.
+ PushWord(dbg_info, producer_str_offset);
// The language is Java.
- dbg_info->push_back(DW_LANG_Java);
+ PushByte(dbg_info, DW_LANG_Java);
- // Leave space for low_pc and high_pc.
- int low_pc_offset = dbg_info->size();
+ // low_pc and high_pc.
+ uint32_t cunit_low_pc = 0 - 1;
+ uint32_t cunit_high_pc = 0;
+ int cunit_low_pc_pos = dbg_info->size();
PushWord(dbg_info, 0);
PushWord(dbg_info, 0);
- // Walk through the information in the method table, and enter into dbg_info.
- const std::vector<OatWriter::DebugInfo>& dbg = oat_writer->GetCFIMethodInfo();
- uint32_t low_pc = 0xFFFFFFFFU;
- uint32_t high_pc = 0;
+ if (dbg_line == nullptr) {
+ for (size_t i = 0; i < method_info.size(); ++i) {
+ const OatWriter::DebugInfo &dbg = method_info[i];
+
+ cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_);
+ cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_);
+
+ // Start a new TAG: subroutine (2).
+ PushByte(dbg_info, 2);
- for (uint32_t i = 0; i < dbg.size(); i++) {
- const OatWriter::DebugInfo& info = dbg[i];
- if (info.low_pc_ < low_pc) {
- low_pc = info.low_pc_;
+ // Enter name, low_pc, high_pc.
+ PushWord(dbg_info, PushStr(dbg_str, dbg.method_name_));
+ PushWord(dbg_info, dbg.low_pc_ + text_section_offset);
+ PushWord(dbg_info, dbg.high_pc_ + text_section_offset);
}
- if (info.high_pc_ > high_pc) {
- high_pc = info.high_pc_;
+ } else {
+ // TODO: in gdb info functions <regexp> - reports Java functions, but
+ // source file is <unknown> because .debug_line is formed as one
+ // compilation unit. To fix this it is possible to generate
+ // a separate compilation unit for every distinct Java source.
+ // Each of the these compilation units can have several non-adjacent
+ // method ranges.
+
+ // Line number table offset
+ PushWord(dbg_info, dbg_line->size());
+
+ size_t lnt_length = dbg_line->size();
+ PushWord(dbg_line, 0);
+
+ PushHalf(dbg_line, 4); // LNT Version DWARF v4 => 4
+
+ size_t lnt_hdr_length = dbg_line->size();
+ PushWord(dbg_line, 0); // TODO: 64-bit uses 8-byte here
+
+ PushByte(dbg_line, 1); // minimum_instruction_length (ubyte)
+ PushByte(dbg_line, 1); // maximum_operations_per_instruction (ubyte) = always 1
+ PushByte(dbg_line, 1); // default_is_stmt (ubyte)
+
+ const int8_t LINE_BASE = -5;
+ PushByte(dbg_line, LINE_BASE); // line_base (sbyte)
+
+ const uint8_t LINE_RANGE = 14;
+ PushByte(dbg_line, LINE_RANGE); // line_range (ubyte)
+
+ const uint8_t OPCODE_BASE = 13;
+ PushByte(dbg_line, OPCODE_BASE); // opcode_base (ubyte)
+
+ // Standard_opcode_lengths (array of ubyte).
+ PushByte(dbg_line, 0); PushByte(dbg_line, 1); PushByte(dbg_line, 1);
+ PushByte(dbg_line, 1); PushByte(dbg_line, 1); PushByte(dbg_line, 0);
+ PushByte(dbg_line, 0); PushByte(dbg_line, 0); PushByte(dbg_line, 1);
+ PushByte(dbg_line, 0); PushByte(dbg_line, 0); PushByte(dbg_line, 1);
+
+ PushByte(dbg_line, 0); // include_directories (sequence of path names) = EMPTY
+
+ // File_names (sequence of file entries).
+ std::unordered_map<const char*, size_t> files;
+ for (size_t i = 0; i < method_info.size(); ++i) {
+ const OatWriter::DebugInfo &dbg = method_info[i];
+ // TODO: add package directory to the file name
+ const char* file_name = dbg.src_file_name_ == nullptr ? "null" : dbg.src_file_name_;
+ auto found = files.find(file_name);
+ if (found == files.end()) {
+ size_t file_index = 1 + files.size();
+ files[file_name] = file_index;
+ PushStr(dbg_line, file_name);
+ PushByte(dbg_line, 0); // include directory index = LEB128(0) - no directory
+ PushByte(dbg_line, 0); // modification time = LEB128(0) - NA
+ PushByte(dbg_line, 0); // file length = LEB128(0) - NA
+ }
+ }
+ PushByte(dbg_line, 0); // End of file_names.
+
+ // Set lnt header length.
+ UpdateWord(dbg_line, lnt_hdr_length, dbg_line->size() - lnt_hdr_length - 4);
+
+ // Generate Line Number Program code, one long program for all methods.
+ LineTableGenerator line_table_generator(LINE_BASE, LINE_RANGE, OPCODE_BASE,
+ dbg_line, 0, 1);
+
+ SrcMap pc2java_map;
+ for (size_t i = 0; i < method_info.size(); ++i) {
+ const OatWriter::DebugInfo &dbg = method_info[i];
+ const char* file_name = (dbg.src_file_name_ == nullptr) ? "null" : dbg.src_file_name_;
+ size_t file_index = files[file_name];
+ DCHECK_NE(file_index, 0U) << file_name;
+
+ cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_);
+ cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_);
+
+ // Start a new TAG: subroutine (2).
+ PushByte(dbg_info, 2);
+
+ // Enter name, low_pc, high_pc.
+ PushWord(dbg_info, PushStr(dbg_str, dbg.method_name_));
+ PushWord(dbg_info, dbg.low_pc_ + text_section_offset);
+ PushWord(dbg_info, dbg.high_pc_ + text_section_offset);
+
+ pc2java_map.clear();
+ GetLineInfoForJava(dbg.dbgstream_, dbg.compiled_method_->GetSrcMappingTable(),
+ &pc2java_map, dbg.low_pc_);
+ pc2java_map.DeltaFormat({dbg.low_pc_, 1}, dbg.high_pc_);
+
+ line_table_generator.SetFile(file_index);
+ line_table_generator.SetAddr(dbg.low_pc_ + text_section_offset);
+ line_table_generator.SetLine(1);
+ for (auto& src_map_elem : pc2java_map) {
+ line_table_generator.PutDelta(src_map_elem.from_, src_map_elem.to_);
+ }
}
- // Start a new TAG: subroutine (2).
- dbg_info->push_back(2);
-
- // Enter the name into the string table (and NUL terminate).
- uint32_t str_offset = dbg_str->size();
- dbg_str->insert(dbg_str->end(), info.method_name_.begin(), info.method_name_.end());
- dbg_str->push_back('\0');
+ // End Sequence should have the highest address set.
+ line_table_generator.SetAddr(cunit_high_pc + text_section_offset);
+ line_table_generator.EndSequence();
- // Enter name, low_pc, high_pc.
- PushWord(dbg_info, str_offset);
- PushWord(dbg_info, info.low_pc_);
- PushWord(dbg_info, info.high_pc_);
+ // set lnt length
+ UpdateWord(dbg_line, lnt_length, dbg_line->size() - lnt_length - 4);
}
// One byte terminator
- dbg_info->push_back(0);
+ PushByte(dbg_info, 0);
+
+ // Fill in cunit's low_pc and high_pc.
+ UpdateWord(dbg_info, cunit_low_pc_pos, cunit_low_pc + text_section_offset);
+ UpdateWord(dbg_info, cunit_low_pc_pos + 4, cunit_high_pc + text_section_offset);
- // We have now walked all the methods. Fill in lengths and low/high PCs.
- UpdateWord(dbg_info, 0, dbg_info->size() - 4);
- UpdateWord(dbg_info, low_pc_offset, low_pc);
- UpdateWord(dbg_info, low_pc_offset + 4, high_pc);
+ // We have now walked all the methods. Fill in lengths.
+ UpdateWord(dbg_info, cunit_length, dbg_info->size() - cunit_length - 4);
}
} // namespace art