Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2644)

Unified Diff: runtime/vm/debuginfo_android.cc

Issue 10827327: Add GDB JIT support back into Android build. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/debuginfo_android.cc
diff --git a/runtime/vm/debuginfo_android.cc b/runtime/vm/debuginfo_android.cc
index 4e56b3c507df38c68fb1d171a3481cc23479781c..793c08fb8b963ba0ce0d6abb2573aecb9ea68f65 100644
--- a/runtime/vm/debuginfo_android.cc
+++ b/runtime/vm/debuginfo_android.cc
@@ -4,31 +4,525 @@
#include "vm/debuginfo.h"
+#include "platform/utils.h"
+#include "vm/gdbjit_android.h"
+#include "vm/os.h"
+#include "vm/thread.h"
namespace dart {
+// -----------------------------------------------------------------------------
cshapiro 2012/08/14 22:18:26 Can you move this into an elfgen.h which is includ
jackpal 2012/08/15 01:29:48 Done.
+// Implementation of ElfGen
+//
+// Specification documents:
+// http://refspecs.freestandards.org
+//
+// ELF generic ABI:
+// http://refspecs.freestandards.org/elf/gabi4+/contents.html
+// ELF processor-specific supplement for X86_64:
+// http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf
+// DWARF 2.0:
+// http://refspecs.freestandards.org/dwarf/dwarf-2.0.0.pdf
+
+// Forward declarations.
+class File;
+
+// ElfGen is used to generate minimal ELF information containing code, symbols,
+// and line numbers for generated code in the dart VM. This information is
+// used in two ways:
+// - it is used to generate in-memory ELF information which is then
+// registered with gdb using the JIT interface.
+// - it is also used to generate a file with the ELF information. This file
+// is not executed, but read by pprof to analyze Dart programs.
+
+class ElfGen {
+ public:
+ ElfGen();
+ ~ElfGen();
+
+ // Add the code starting at pc.
+ void AddCode(uword pc, intptr_t size);
+
+ // Add symbol information for a region (includes the start and end symbol),
+ // does not add the actual code.
+ void AddCodeRegion(const char* name, uword pc, intptr_t size);
+
+ // Add specified symbol information, does not add the actual code.
+ int AddFunction(const char* name, uword pc, intptr_t size);
+
+ // Write out all the Elf information using the specified handle.
+ bool WriteToFile(File* handle);
+ bool WriteToMemory(DebugInfo::ByteBuffer* region);
+
+ // Register this generated section with GDB using the JIT interface.
+ static void RegisterSectionWithGDB(const char* name,
+ uword entry_point,
+ intptr_t size);
+
+ // Unregister all generated section from GDB.
+ static void UnregisterAllSectionsWithGDB();
+
+ private:
+ // ELF helpers
+ typedef int (*OutputWriter)(void* handle,
+ const DebugInfo::ByteBuffer& section);
+ typedef void (*OutputPadder)(void* handle, int padding_size);
+
+ int AddString(DebugInfo::ByteBuffer* buf, const char* str);
+ int AddSectionName(const char* str);
+ int AddName(const char* str);
+ void AddELFHeader(int shoff);
+ void AddSectionHeader(int section, int offset);
+ int PadSection(DebugInfo::ByteBuffer* section, int offset, int alignment);
+ bool WriteOutput(void* handle, OutputWriter writer, OutputPadder padder);
+
+ uword text_vma_; // text section vma
+ intptr_t text_size_; // text section size
+ int text_padding_; // padding preceding text section
+
+ static const int kNumSections = 5; // we generate 5 sections
+ int section_name_[kNumSections]; // array of section name indices
+ DebugInfo::ByteBuffer section_buf_[kNumSections]; // array of section buffers
+ DebugInfo::ByteBuffer header_; // ELF header buffer
+ DebugInfo::ByteBuffer sheaders_; // section header table buffer
+ DebugInfo::ByteBuffer lineprog_; // line statement program, part of
+ // '.debug_line' section
+
+ // current state of the DWARF line info generator
+ uintptr_t cur_addr_; // current pc
+ int map_offset_;
+ uword map_begin_;
+ uword map_end_;
+
+ Mutex lock_;
+};
+
+
+enum {
+ // Various constant sizes for ELF files.
+ kAddrSize = sizeof(uword),
+ kPageSize = 4*1024, // Memory mapping page size.
+ kTextAlign = 16,
+ kELFHeaderSize = 40 + 3*kAddrSize,
+ kProgramHeaderEntrySize = 8 + 6*kAddrSize,
+ kSectionHeaderEntrySize = 16 + 6*kAddrSize,
+ kSymbolSize = 8 + 2*kAddrSize,
+
+ // Our own layout of sections.
+ kUndef = 0, // Undefined section.
+ kText, // Text section.
+ kShStrtab, // Section header string table.
+ kStrtab, // String table.
+ kSymtab, // Symbol table.
+ kNumSections, // Num of section header entries in section header table.
+
+ // Various ELF constants.
+ kELFCLASS32 = 1,
+ kELFCLASS64 = 2,
+ kELFDATA2LSB = 1,
+ kELFDATA2MSB = 2,
+ kEM_386 = 3,
+ kEM_ARM = 40,
+ kEM_X86_64 = 62,
+ kEV_CURRENT = 1,
+ kET_EXEC = 2, // not used
+ kET_DYN = 3,
+ kSHT_PROGBITS = 1,
+ kSHT_SYMTAB = 2,
+ kSHT_STRTAB = 3,
+ kSHF_WRITE = 1, // not used
+ kSHF_ALLOC = 2,
+ kSHF_EXECINSTR = 4,
+ kSTB_LOCAL = 0,
+ kSTB_EXPORTED = 1,
+ kSTT_FUNC = 2,
+};
+
+
+// ELF and DWARF constants.
+static const char* kEI_MAG0_MAG3 = "\177ELF";
+static const uint8_t kSpecialOpcodeLengths[] = { 0, 1, 1, 1, 1, 0, 0, 0, 1 };
+
+
+// Section attributes.
+// The field names correspond to the field names of Elf32_Shdr and Elf64_Shdr.
+static const struct {
+ // Section header index (only used to check correct section order).
+ int shndx;
+ const char* name; // sh_name will be the index of name inserted in shstrtab.
+ int sh_type;
+ int sh_flags;
+ int sh_link;
+ int sh_addralign;
+ int sh_entsize;
+} section_attr[kNumSections + 1] = {
+ { kUndef, "", 0, 0,
+ 0, 0, 0 },
+ { kText, ".text", kSHT_PROGBITS, kSHF_ALLOC|kSHF_EXECINSTR,
+ 0, kTextAlign, 0 },
+ { kShStrtab, ".shstrtab", kSHT_STRTAB, 0,
+ 0, 1, 0 },
+ { kStrtab, ".strtab", kSHT_STRTAB, 0,
+ 0, 1, 0 },
+ { kSymtab, ".symtab", kSHT_SYMTAB, 0,
+ kStrtab, kAddrSize, kSymbolSize },
+ // Sentinel to pad the last section
+ // for proper alignment of section header table.
+ { 0, "", 0, 0,
+ 0, kAddrSize, 0 }
+};
+
+
+// Convenience function aligning an integer.
+static inline uintptr_t Align(uintptr_t x, intptr_t size) {
+ // size is a power of 2
+ ASSERT((size & (size-1)) == 0);
+ return (x + (size-1)) & ~(size-1);
+}
+
+
+// Convenience function writing a single byte to a ByteBuffer.
+static inline void WriteByte(DebugInfo::ByteBuffer* buf, uint8_t byte) {
+ buf->Add(byte);
+}
+
+
+// Convenience function writing an unsigned native word to a ByteBuffer.
+// The word is 32-bit wide in 32-bit mode and 64-bit wide in 64-bit mode.
+static inline void WriteWord(DebugInfo::ByteBuffer* buf, uword word) {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&word);
+ for (size_t i = 0; i < sizeof(word); i++) {
+ buf->Add(p[i]);
+ }
+}
+
+static inline void WriteInt(DebugInfo::ByteBuffer* buf, int word) {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&word);
+ for (size_t i = 0; i < sizeof(word); i++) {
+ buf->Add(p[i]);
+ }
+}
+
+static inline void WriteShort(DebugInfo::ByteBuffer* buf, uint16_t word) {
+ uint8_t* p = reinterpret_cast<uint8_t*>(&word);
+ for (size_t i = 0; i < sizeof(word); i++) {
+ buf->Add(p[i]);
+ }
+}
+
+static inline void WriteString(DebugInfo::ByteBuffer* buf, const char* str) {
+ for (size_t i = 0; i < strlen(str); i++) {
+ buf->Add(static_cast<uint8_t>(str[i]));
+ }
+}
+
+static inline void Write(DebugInfo::ByteBuffer* buf,
+ const void* mem,
+ int length) {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(mem);
+ for (int i = 0; i < length; i++) {
+ buf->Add(p[i]);
+ }
+}
+
+
+// Write given section to file and return written size.
+static int WriteSectionToFile(void* handle,
+ const DebugInfo::ByteBuffer& section) {
+#if 0
+ File* fp = reinterpret_cast<File*>(handle);
+ int size = section.size();
+ fp->WriteFully(section.data(), size);
+ return size;
+#else
+ return 0;
+#endif
+}
+
+
+// Pad output file to specified padding size.
+static void PadFile(void* handle, int padding_size) {
+#if 0
+ File* fp = reinterpret_cast<File*>(handle);
+ for (int i = 0; i < padding_size; i++) {
+ fp->WriteFully("", 1);
+ }
+#endif
+}
+
+
+// Write given section to specified memory region and return written size.
+static int WriteSectionToMemory(void* handle,
+ const DebugInfo::ByteBuffer& section) {
+ DebugInfo::ByteBuffer* buffer =
+ reinterpret_cast<DebugInfo::ByteBuffer*>(handle);
+ int size = section.size();
+ for (int i = 0; i < size; i++) {
+ buffer->Add(static_cast<uint8_t>(section.data()[i]));
+ }
+ return size;
+}
+
+
+// Pad memory to specified padding size.
+static void PadMemory(void* handle, int padding_size) {
+ DebugInfo::ByteBuffer* buffer =
+ reinterpret_cast<DebugInfo::ByteBuffer*>(handle);
+ for (int i = 0; i < padding_size; i++) {
+ buffer->Add(static_cast<uint8_t>(0));
+ }
+}
+
+
+// Constructor
+ElfGen::ElfGen()
+ : text_vma_(0), text_size_(0), text_padding_(0), map_offset_(0), lock_() {
+ for (int i = 0; i < kNumSections; i++) {
+ ASSERT(section_attr[i].shndx == i); // Verify layout of sections.
+ section_name_[i] = AddSectionName(section_attr[i].name);
+ }
+ // Section header string table always starts with an empty string, which is
+ // the name of the kUndef section.
+ ASSERT((section_attr[0].name[0] == '\0') && (section_name_[0] == 0));
+
+ // String table always starts with an empty string.
+ AddName("");
+ ASSERT(section_buf_[kStrtab].size() == 1);
+
+ // Symbol at index 0 in symtab is always STN_UNDEF (all zero):
+ DebugInfo::ByteBuffer* symtab = &section_buf_[kSymtab];
+ while (symtab->size() < kSymbolSize) {
+ WriteInt(symtab, 0);
+ }
+ ASSERT(symtab->size() == kSymbolSize);
+}
+
+
+// Destructor
+ElfGen::~ElfGen() {
+}
+
+
+void ElfGen::AddCode(uword pc, intptr_t size) {
+ MutexLocker ml(&lock_);
+ text_vma_ = pc;
+ text_size_ = size;
+ // We pad the text section in the file to align absolute code addresses with
+ // corresponding file offsets as if the code had been loaded by memory
+ // mapping.
+ if (text_vma_ % kPageSize < kELFHeaderSize) {
+ text_padding_ = text_vma_ % kPageSize + kPageSize - kELFHeaderSize;
+ } else {
+ text_padding_ = text_vma_ % kPageSize - kELFHeaderSize;
+ }
+
+ Write(&section_buf_[kText], reinterpret_cast<void*>(pc), size);
+ // map_offset is the file offset of the first mapped page.
+ map_offset_ = (kELFHeaderSize + text_padding_)/kPageSize*kPageSize;
+ map_begin_ = Align(text_vma_ - kPageSize + 1, kPageSize);
+ map_end_ = Align(text_vma_ + size, kPageSize);
+}
+
+
+void ElfGen::AddCodeRegion(const char* name, uword pc, intptr_t size) {
+ MutexLocker ml(&lock_);
+ AddFunction(name, pc, size);
+ char end_name[256];
+ OS::SNPrint(end_name, sizeof(end_name), "%s_end", name);
+ AddFunction(end_name, pc + size, 0);
+}
+
+
+int ElfGen::AddFunction(const char* name, uword pc, intptr_t size) {
+ ASSERT(text_vma_ != 0); // code must have been added
+ DebugInfo::ByteBuffer* symtab = &section_buf_[kSymtab];
+ const int beg = symtab->size();
+ WriteInt(symtab, AddName(name)); // st_name
+#if defined(TARGET_ARCH_X64)
+ WriteShort(symtab, (kSTB_LOCAL << 4) + kSTT_FUNC); // st_info + (st_other<<8)
+ WriteShort(symtab, kText); // st_shndx
+#endif
+ WriteWord(symtab, pc); // st_value
+ WriteWord(symtab, size); // st_size
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
+ // st_info + (st_other<<8)
+ WriteShort(symtab, (kSTB_EXPORTED << 4) + kSTT_FUNC);
+ WriteShort(symtab, kText); // st_shndx
+#endif
+ ASSERT(symtab->size() - beg == kSymbolSize);
+ return beg / kSymbolSize; // symbol index in symtab
+}
+
+
+bool ElfGen::WriteToFile(File* handle) {
+ return WriteOutput(handle, WriteSectionToFile, PadFile);
+}
+
+
+bool ElfGen::WriteToMemory(DebugInfo::ByteBuffer* region) {
+ return WriteOutput(region, WriteSectionToMemory, PadMemory);
+}
+
+
+int ElfGen::AddString(DebugInfo::ByteBuffer* buf, const char* str) {
+ const int str_index = buf->size();
+ WriteString(buf, str);
+ WriteByte(buf, 0); // terminating '\0'
+ return str_index;
+}
+
+
+int ElfGen::AddSectionName(const char* str) {
+ return AddString(&section_buf_[kShStrtab], str);
+}
+
+
+int ElfGen::AddName(const char* str) {
+ return AddString(&section_buf_[kStrtab], str);
+}
+
+
+void ElfGen::AddELFHeader(int shoff) {
+ ASSERT(text_vma_ != 0); // Code must have been added.
+ Write(&header_, kEI_MAG0_MAG3, 4); // EI_MAG0..EI_MAG3
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
+ WriteByte(&header_, kELFCLASS32); // EI_CLASS
+#elif defined(TARGET_ARCH_X64)
+ WriteByte(&header_, kELFCLASS64); // EI_CLASS
+#endif
+ WriteByte(&header_, kELFDATA2LSB); // EI_DATA
+ WriteByte(&header_, kEV_CURRENT); // EI_VERSION
+ WriteByte(&header_, 0); // EI_PAD
+ WriteInt(&header_, 0); // EI_PAD
+ WriteInt(&header_, 0); // EI_PAD
+ WriteShort(&header_, kET_DYN); // e_type, fake a shared object.
+#if defined(TARGET_ARCH_IA32)
+ WriteShort(&header_, kEM_386); // e_machine
+#elif defined(TARGET_ARCH_X64)
+ WriteShort(&header_, kEM_X86_64); // e_machine
+#elif defined(TARGET_ARCH_ARM)
+ WriteShort(&header_, kEM_ARM); // e_machine
+#endif
+ WriteInt(&header_, kEV_CURRENT); // e_version
+ WriteWord(&header_, 0); // e_entry: none
+ WriteWord(&header_, 0); // e_phoff: no program header table.
+ WriteWord(&header_, shoff); // e_shoff: section header table offset.
+ WriteInt(&header_, 0); // e_flags: no flags.
+ WriteShort(&header_, kELFHeaderSize); // e_ehsize: header size.
+ WriteShort(&header_, kProgramHeaderEntrySize); // e_phentsize
+ WriteShort(&header_, 0); // e_phnum: no entries program header table.
+ WriteShort(&header_, kSectionHeaderEntrySize); // e_shentsize
+ // e_shnum: number of section header entries.
+ WriteShort(&header_, kNumSections);
+ WriteShort(&header_, kShStrtab); // e_shstrndx: index of shstrtab.
+ ASSERT(header_.size() == kELFHeaderSize);
+}
+
+
+void ElfGen::AddSectionHeader(int section, int offset) {
+ WriteInt(&sheaders_, section_name_[section]);
+ WriteInt(&sheaders_, section_attr[section].sh_type);
+ WriteWord(&sheaders_, section_attr[section].sh_flags);
+ // sh_addr: abs addr
+ WriteWord(&sheaders_, (section == kText) ? text_vma_ : 0);
+ WriteWord(&sheaders_, offset); // sh_offset: section file offset.
+ WriteWord(&sheaders_, section_buf_[section].size());
+ WriteInt(&sheaders_, section_attr[section].sh_link);
+ WriteInt(&sheaders_, 0);
+ WriteWord(&sheaders_, section_attr[section].sh_addralign);
+ WriteWord(&sheaders_, section_attr[section].sh_entsize);
+ ASSERT(sheaders_.size() == kSectionHeaderEntrySize * (section + 1));
+}
+
+
+// Pads the given section with zero bytes for the given aligment, assuming the
+// section starts at given file offset; returns file offset after padded
+// section.
+int ElfGen::PadSection(DebugInfo::ByteBuffer* section,
+ int offset,
+ int alignment) {
+ offset += section->size();
+ int aligned_offset = Align(offset, alignment);
+ while (offset++ < aligned_offset) {
+ WriteByte(section, 0); // one byte padding.
+ }
+ return aligned_offset;
+}
+
+
+bool ElfGen::WriteOutput(void* handle,
+ OutputWriter writer,
+ OutputPadder padder) {
+ if (handle == NULL || writer == NULL || padder == NULL) {
+ return false;
+ }
+
+ // Align all sections before writing the ELF header in order to calculate the
+ // file offset of the section header table, which is needed in the ELF header.
+ // Pad each section as required by the aligment constraint of the immediately
+ // following section, except the ELF header section, which requires special
+ // padding (text_padding_) to align the text_ section.
+ int offset = kELFHeaderSize + text_padding_;
+ for (int i = kText; i < kNumSections; i++) {
+ offset = PadSection(&section_buf_[i],
+ offset,
+ section_attr[i+1].sh_addralign);
+ }
+
+ const int shoff = offset; // Section header table offset.
+
+ // Write elf header.
+ AddELFHeader(shoff);
+ offset = (*writer)(handle, header_);
+
+ // Pad file before writing text section in order to align vma with file
+ // offset.
+ (*padder)(handle, text_padding_);
+
+ offset += text_padding_;
+ ASSERT((text_vma_ - offset) % kPageSize == 0);
+
+ // Section header at index 0 in section header table is always SHN_UNDEF:
+ for (int i = 0; i < kNumSections; i++) {
+ AddSectionHeader(i, offset);
+ offset += (*writer)(handle, section_buf_[i]);
+ }
+ // Write section header table.
+ ASSERT(offset == shoff);
+ offset += (*writer)(handle, sheaders_);
+ ASSERT(offset == shoff + kNumSections * kSectionHeaderEntrySize);
+
+ return true;
+}
+
+
DebugInfo::DebugInfo() {
- handle_ = NULL;
+ handle_ = reinterpret_cast<void*>(new ElfGen());
+ ASSERT(handle_ != NULL);
}
DebugInfo::~DebugInfo() {
+ ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
+ delete elf_gen;
}
void DebugInfo::AddCode(uword pc, intptr_t size) {
- // Nothing to do as there is no support for this on Android.
+ ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
+ elf_gen->AddCode(pc, size);
}
void DebugInfo::AddCodeRegion(const char* name, uword pc, intptr_t size) {
- // Nothing to do as there is no support for this on Android.
+ ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
+ elf_gen->AddCodeRegion(name, pc, size);
}
bool DebugInfo::WriteToMemory(ByteBuffer* region) {
- // Nothing to do as there is no support for this on Android.
- return false;
+ ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
+ return elf_gen->WriteToMemory(region);
}
@@ -40,12 +534,26 @@ DebugInfo* DebugInfo::NewGenerator() {
void DebugInfo::RegisterSection(const char* name,
uword entry_point,
intptr_t size) {
- // Nothing to do as there is no support for this on Android.
+ ElfGen* elf_section = new ElfGen();
+ ASSERT(elf_section != NULL);
+ elf_section->AddCode(entry_point, size);
+ elf_section->AddCodeRegion(name, entry_point, size);
+
+ ByteBuffer* dynamic_region = new ByteBuffer();
+ ASSERT(dynamic_region != NULL);
+
+ elf_section->WriteToMemory(dynamic_region);
+
+ ::addDynamicSection(reinterpret_cast<const char*>(dynamic_region->data()),
+ dynamic_region->size());
+ dynamic_region->set_data(NULL);
+ delete dynamic_region;
+ delete elf_section;
}
void DebugInfo::UnregisterAllSections() {
- // Nothing to do as there is no support for this on Android.
+ ::deleteDynamicSections();
}
} // namespace dart
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698