Chromium Code Reviews| Index: src/gdb-jit.cc |
| diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc |
| index b4992a7f52680e0d766e6b8befa5ca31b6ec607b..4ab33c43775ee6c6360e883ef56e17df732b4a66 100644 |
| --- a/src/gdb-jit.cc |
| +++ b/src/gdb-jit.cc |
| @@ -34,16 +34,29 @@ |
| #include "global-handles.h" |
| #include "messages.h" |
| #include "natives.h" |
| +#include "scopeinfo.h" |
| namespace v8 { |
| namespace internal { |
| +#ifdef __APPLE__ |
| +#define __MACH_O |
| +class MachO; |
| +class MachOSection; |
| +typedef MachO DebugObject; |
| +typedef MachOSection DebugSection; |
| +#else |
| +#define __ELF |
| class ELF; |
| +class ELFSection; |
| +typedef ELF DebugObject; |
| +typedef ELFSection DebugSection; |
| +#endif |
| class Writer BASE_EMBEDDED { |
| public: |
| - explicit Writer(ELF* elf) |
| - : elf_(elf), |
| + explicit Writer(DebugObject* debug_object) |
| + : debug_object_(debug_object), |
| position_(0), |
| capacity_(1024), |
| buffer_(reinterpret_cast<byte*>(malloc(capacity_))) { |
| @@ -112,7 +125,7 @@ class Writer BASE_EMBEDDED { |
| } |
| } |
| - ELF* elf() { return elf_; } |
| + DebugObject* debug_object() { return debug_object_; } |
| byte* buffer() { return buffer_; } |
| @@ -165,7 +178,7 @@ class Writer BASE_EMBEDDED { |
| return reinterpret_cast<T*>(&buffer_[offset]); |
| } |
| - ELF* elf_; |
| + DebugObject* debug_object_; |
| uintptr_t position_; |
| uintptr_t capacity_; |
| byte* buffer_; |
| @@ -173,21 +186,120 @@ class Writer BASE_EMBEDDED { |
| class StringTable; |
| -class ELFSection : public ZoneObject { |
| +template<typename THeader> |
| +class DebugSectionBase : public ZoneObject { |
| public: |
| - struct Header { |
| - uint32_t name; |
| - uint32_t type; |
| - uintptr_t flags; |
| - uintptr_t address; |
| - uintptr_t offset; |
| - uintptr_t size; |
| - uint32_t link; |
| - uint32_t info; |
| - uintptr_t alignment; |
| - uintptr_t entry_size; |
| + virtual ~DebugSectionBase() { } |
| + |
| + virtual void WriteBody(Writer::Slot<THeader> header, Writer* writer) { |
| + uintptr_t start = writer->position(); |
| + if (WriteBody(writer)) { |
| + uintptr_t end = writer->position(); |
| + header->offset = start; |
| +#if defined(__MACH_O) |
| + header->addr = 0; |
| +#endif |
| + header->size = end - start; |
| + } |
| + } |
| + |
| + virtual bool WriteBody(Writer* writer) { |
| + return false; |
| + } |
| + |
| + typedef THeader Header; |
| +}; |
| + |
| + |
| +struct MachOSectionHeader { |
| + char sectname[16]; |
| + char segname[16]; |
| +#if defined(V8_TARGET_ARCH_IA32) |
| + uint32_t addr; |
| + uint32_t size; |
| +#else |
| + uint64_t addr; |
| + uint64_t size; |
| +#endif |
| + uint32_t offset; |
| + uint32_t align; |
| + uint32_t reloff; |
| + uint32_t nreloc; |
| + uint32_t flags; |
| + uint32_t reserved1; |
| + uint32_t reserved2; |
| +}; |
| + |
| + |
| +class MachOSection : public DebugSectionBase<MachOSectionHeader> { |
| + public: |
| + enum Type { |
| + S_REGULAR = 0x0u, |
| + S_ATTR_COALESCED = 0xbu, |
| + S_ATTR_SOME_INSTRUCTIONS = 0x400u, |
| + S_ATTR_DEBUG = 0x02000000u, |
| + S_ATTR_PURE_INSTRUCTIONS = 0x80000000u |
| }; |
| + MachOSection(const char* name, |
| + const char* segment, |
| + uintptr_t align, |
| + uint32_t flags) |
| + : name_(name), |
| + segment_(segment), |
| + align_(align), |
| + flags_(flags) { |
| + ASSERT(IsPowerOf2(align)); |
| + if (align_ != 0) { |
| + align_ = WhichPowerOf2(align_); |
| + } |
| + } |
| + |
| + virtual ~MachOSection() { } |
| + |
| + virtual void PopulateHeader(Writer::Slot<Header> header) { |
| + header->addr = 0; |
| + header->size = 0; |
| + header->offset = 0; |
| + header->align = align_; |
| + header->reloff = 0; |
| + header->nreloc = 0; |
| + header->flags = flags_; |
| + header->reserved1 = 0; |
| + header->reserved2 = 0; |
| + memset(header->sectname, 0, 16); |
| + memset(header->segname, 0, 16); |
| + ASSERT(strlen(name_) < 16); |
| + ASSERT(strlen(segment_) < 16); |
| + strcpy(header->sectname, name_); |
| + strcpy(header->segname, segment_); |
| + } |
| + |
| + private: |
| + const char* name_; |
| + const char* segment_; |
| + uintptr_t align_; |
| + uint32_t flags_; |
| +}; |
| + |
| + |
| +struct ELFSectionHeader { |
| + uint32_t name; |
| + uint32_t type; |
| + uintptr_t flags; |
| + uintptr_t address; |
| + uintptr_t offset; |
| + uintptr_t size; |
| + uint32_t link; |
| + uint32_t info; |
| + uintptr_t alignment; |
| + uintptr_t entry_size; |
| +}; |
| + |
| + |
| +#if defined(__ELF) |
| +class ELFSection : public DebugSectionBase<ELFSectionHeader> { |
| + public: |
| enum Type { |
| TYPE_NULL = 0, |
| TYPE_PROGBITS = 1, |
| @@ -252,15 +364,45 @@ class ELFSection : public ZoneObject { |
| header->entry_size = 0; |
| } |
| - |
| private: |
| const char* name_; |
| Type type_; |
| uintptr_t align_; |
| uint16_t index_; |
| }; |
| +#endif // defined(__ELF) |
| +#if defined(__MACH_O) |
| +class MachOTextSection : public MachOSection { |
| + public: |
| + MachOTextSection(uintptr_t align, |
| + uintptr_t addr, |
| + uintptr_t size) |
| + : MachOSection("__text", |
| + "__TEXT", |
| + align, |
| + MachOSection::S_REGULAR | |
| + MachOSection::S_ATTR_SOME_INSTRUCTIONS | |
| + MachOSection::S_ATTR_PURE_INSTRUCTIONS), |
| + addr_(addr), |
| + size_(size) { } |
| + |
| + protected: |
| + virtual void PopulateHeader(Writer::Slot<Header> header) { |
| + MachOSection::PopulateHeader(header); |
| + header->addr = addr_; |
| + header->size = size_; |
| + } |
| + |
| + private: |
| + uintptr_t addr_; |
| + uintptr_t size_; |
| +}; |
| +#endif // defined(__MACH_O) |
| + |
| + |
| +#if defined(__ELF) |
| class FullHeaderELFSection : public ELFSection { |
| public: |
| FullHeaderELFSection(const char* name, |
| @@ -349,8 +491,139 @@ void ELFSection::PopulateHeader(Writer::Slot<ELFSection::Header> header, |
| header->alignment = align_; |
| PopulateHeader(header); |
| } |
| +#endif // defined(__ELF) |
| + |
| + |
| +#if defined(__MACH_O) |
| +class MachO BASE_EMBEDDED { |
| + public: |
| + MachO() : sections_(6) { } |
| + |
| + uint32_t AddSection(MachOSection* section) { |
| + sections_.Add(section); |
| + return sections_.length() - 1; |
| + } |
| + |
| + void Write(Writer* w, uintptr_t code_start, uintptr_t code_size) { |
| + Writer::Slot<MachOHeader> header = WriteHeader(w); |
| + uintptr_t load_command_start = w->position(); |
| + Writer::Slot<MachOSegmentCommand> cmd = WriteSegmentCommand(w, |
| + code_start, |
| + code_size); |
| + WriteSections(w, cmd, header, load_command_start); |
| + } |
| + |
| + private: |
| + struct MachOHeader { |
| + uint32_t magic; |
| + uint32_t cputype; |
| + uint32_t cpusubtype; |
| + uint32_t filetype; |
| + uint32_t ncmds; |
| + uint32_t sizeofcmds; |
| + uint32_t flags; |
| +#if defined(V8_TARGET_ARCH_X64) |
| + uint32_t reserved; |
| +#endif |
| + }; |
| + |
| + struct MachOSegmentCommand { |
| + uint32_t cmd; |
| + uint32_t cmdsize; |
| + char segname[16]; |
| +#if defined(V8_TARGET_ARCH_IA32) |
| + uint32_t vmaddr; |
| + uint32_t vmsize; |
| + uint32_t fileoff; |
| + uint32_t filesize; |
| +#else |
| + uint64_t vmaddr; |
| + uint64_t vmsize; |
| + uint64_t fileoff; |
| + uint64_t filesize; |
| +#endif |
| + uint32_t maxprot; |
| + uint32_t initprot; |
| + uint32_t nsects; |
| + uint32_t flags; |
| + }; |
| + |
| + enum MachOLoadCommandCmd { |
| + LC_SEGMENT_32 = 0x00000001u, |
| + LC_SEGMENT_64 = 0x00000019u |
| + }; |
| + |
| + |
| + Writer::Slot<MachOHeader> WriteHeader(Writer* w) { |
| + ASSERT(w->position() == 0); |
| + Writer::Slot<MachOHeader> header = w->CreateSlotHere<MachOHeader>(); |
| +#if defined(V8_TARGET_ARCH_IA32) |
| + header->magic = 0xFEEDFACEu; |
| + header->cputype = 7; // i386 |
| + header->cpusubtype = 3; // CPU_SUBTYPE_I386_ALL |
| +#elif defined(V8_TARGET_ARCH_X64) |
| + header->magic = 0xFEEDFACFu; |
| + header->cputype = 7 | 0x01000000; // i386 | 64-bit ABI |
| + header->cpusubtype = 3; // CPU_SUBTYPE_I386_ALL |
| + header->reserved = 0; |
| +#else |
| +#error Unsupported target architecture. |
| +#endif |
| + header->filetype = 0x1; // MH_OBJECT |
| + header->ncmds = 1; |
| + header->sizeofcmds = 0; |
| + header->flags = 0; |
| + return header; |
| + } |
| + Writer::Slot<MachOSegmentCommand> WriteSegmentCommand(Writer* w, |
| + uintptr_t code_start, |
| + uintptr_t code_size) { |
| + Writer::Slot<MachOSegmentCommand> cmd = |
| + w->CreateSlotHere<MachOSegmentCommand>(); |
| +#if defined(V8_TARGET_ARCH_IA32) |
| + cmd->cmd = LC_SEGMENT_32; |
| +#else |
| + cmd->cmd = LC_SEGMENT_64; |
| +#endif |
| + cmd->vmaddr = code_start; |
| + cmd->vmsize = code_size; |
| + cmd->fileoff = 0; |
| + cmd->filesize = 0; |
| + cmd->maxprot = 7; |
| + cmd->initprot = 7; |
| + cmd->flags = 0; |
| + cmd->nsects = sections_.length(); |
| + memset(cmd->segname, 0, 16); |
| + cmd->cmdsize = sizeof(MachOSegmentCommand) + sizeof(MachOSection::Header) * |
| + cmd->nsects; |
| + return cmd; |
| + } |
| + |
| + |
| + void WriteSections(Writer* w, |
| + Writer::Slot<MachOSegmentCommand> cmd, |
| + Writer::Slot<MachOHeader> header, |
| + uintptr_t load_command_start) { |
| + Writer::Slot<MachOSection::Header> headers = |
| + w->CreateSlotsHere<MachOSection::Header>(sections_.length()); |
| + cmd->fileoff = w->position(); |
| + header->sizeofcmds = w->position() - load_command_start; |
| + for (int section = 0; section < sections_.length(); ++section) { |
| + sections_[section]->PopulateHeader(headers.at(section)); |
| + sections_[section]->WriteBody(headers.at(section), w); |
| + } |
| + cmd->filesize = w->position() - (uintptr_t)cmd->fileoff; |
| + } |
| + |
| + |
| + ZoneList<MachOSection*> sections_; |
| +}; |
| +#endif // defined(__MACH_O) |
| + |
| + |
| +#if defined(__ELF) |
| class ELF BASE_EMBEDDED { |
| public: |
| ELF() : sections_(6) { |
| @@ -596,7 +869,7 @@ class ELFSymbolTable : public ELFSection { |
| // String table for this symbol table should follow it in the section table. |
| StringTable* strtab = |
| - static_cast<StringTable*>(w->elf()->SectionAt(index() + 1)); |
| + static_cast<StringTable*>(w->debug_object()->SectionAt(index() + 1)); |
| strtab->AttachWriter(w); |
| symbols.at(0).set(ELFSymbol::SerializedLayout(0, |
| 0, |
| @@ -640,6 +913,7 @@ class ELFSymbolTable : public ELFSection { |
| ZoneList<ELFSymbol> locals_; |
| ZoneList<ELFSymbol> globals_; |
| }; |
| +#endif // defined(__ELF) |
| class CodeDescription BASE_EMBEDDED { |
| @@ -657,12 +931,14 @@ class CodeDescription BASE_EMBEDDED { |
| Code* code, |
| Handle<Script> script, |
| GDBJITLineInfo* lineinfo, |
| - GDBJITInterface::CodeTag tag) |
| + GDBJITInterface::CodeTag tag, |
| + CompilationInfo* info) |
| : name_(name), |
| code_(code), |
| script_(script), |
| lineinfo_(lineinfo), |
| - tag_(tag) { |
| + tag_(tag), |
| + info_(info) { |
| } |
| const char* name() const { |
| @@ -677,6 +953,14 @@ class CodeDescription BASE_EMBEDDED { |
| return tag_; |
| } |
| + CompilationInfo* info() const { |
| + return info_; |
| + } |
| + |
| + bool IsInfoAvailable() const { |
| + return info_ != NULL; |
| + } |
| + |
| uintptr_t CodeStart() const { |
| return reinterpret_cast<uintptr_t>(code_->instruction_start()); |
| } |
| @@ -724,12 +1008,13 @@ class CodeDescription BASE_EMBEDDED { |
| Handle<Script> script_; |
| GDBJITLineInfo* lineinfo_; |
| GDBJITInterface::CodeTag tag_; |
| + CompilationInfo* info_; |
| #ifdef V8_TARGET_ARCH_X64 |
| uintptr_t stack_state_start_addresses_[STACK_STATE_MAX]; |
| #endif |
| }; |
| - |
| +#if defined(__ELF) |
| static void CreateSymbolsTable(CodeDescription* desc, |
| ELF* elf, |
| int text_section_index) { |
| @@ -754,14 +1039,42 @@ static void CreateSymbolsTable(CodeDescription* desc, |
| ELFSymbol::TYPE_FUNC, |
| text_section_index)); |
| } |
| +#endif // defined(__ELF) |
| -class DebugInfoSection : public ELFSection { |
| +class DebugInfoSection : public DebugSection { |
| public: |
| explicit DebugInfoSection(CodeDescription* desc) |
| - : ELFSection(".debug_info", TYPE_PROGBITS, 1), desc_(desc) { } |
| +#if defined(__ELF) |
| + : ELFSection(".debug_info", TYPE_PROGBITS, 1), |
| +#else |
| + : MachOSection("__debug_info", |
| + "__DWARF", |
| + 1, |
| + MachOSection::S_REGULAR | MachOSection::S_ATTR_DEBUG), |
| +#endif |
| + desc_(desc) { } |
| + |
| + // DWARF2 standard |
| + enum DWARF2LocationOp { |
| + DW_OP_reg0 = 0x50, |
| + DW_OP_reg1 = 0x51, |
| + DW_OP_reg2 = 0x52, |
| + DW_OP_reg3 = 0x53, |
| + DW_OP_reg4 = 0x54, |
| + DW_OP_reg5 = 0x55, |
| + DW_OP_reg6 = 0x56, |
| + DW_OP_reg7 = 0x57, |
| + DW_OP_fbreg = 0x91 // 1 param: SLEB128 offset |
| + }; |
| + |
| + enum DWARF2Encoding { |
| + DW_ATE_ADDRESS = 0x1, |
| + DW_ATE_SIGNED = 0x5 |
| + }; |
| bool WriteBody(Writer* w) { |
| + uintptr_t cu_start = w->position(); |
| Writer::Slot<uint32_t> size = w->CreateSlotHere<uint32_t>(); |
| uintptr_t start = w->position(); |
| w->Write<uint16_t>(2); // DWARF version. |
| @@ -773,6 +1086,123 @@ class DebugInfoSection : public ELFSection { |
| w->Write<intptr_t>(desc_->CodeStart()); |
| w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize()); |
| w->Write<uint32_t>(0); |
| + |
| + uint32_t ty_offset = static_cast<uint32_t>(w->position() - cu_start); |
| + w->WriteULEB128(3); |
| + w->Write<uint8_t>(kPointerSize); |
| + w->WriteString("v8value"); |
| + |
| + if (desc_->IsInfoAvailable()) { |
| + CompilationInfo* info = desc_->info(); |
| + ScopeInfo<FreeStoreAllocationPolicy> scope_info(info->scope()); |
| + w->WriteULEB128(2); |
| + w->WriteString(desc_->name()); |
| + w->Write<intptr_t>(desc_->CodeStart()); |
| + w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize()); |
| + Writer::Slot<uint32_t> fb_block_size = w->CreateSlotHere<uint32_t>(); |
| + uintptr_t fb_block_start = w->position(); |
| +#if defined(V8_TARGET_ARCH_IA32) |
| + w->Write<uint8_t>(DW_OP_reg5); // The frame pointer's here on ia32 |
| +#elif defined(V8_TARGET_ARCH_X64) |
| + w->Write<uint8_t>(DW_OP_reg6); // and here on x64. |
| +#else |
| +#error Unsupported target architecture. |
| +#endif |
| + fb_block_size.set(static_cast<uint32_t>(w->position() - fb_block_start)); |
| + |
| + int params = scope_info.number_of_parameters(); |
| + int slots = scope_info.number_of_stack_slots(); |
| + int context_slots = scope_info.number_of_context_slots(); |
| + // The real slot ID is internal_slots + context_slot_id. |
| + int internal_slots = Context::MIN_CONTEXT_SLOTS; |
| + int locals = scope_info.NumberOfLocals(); |
| + int current_abbreviation = 4; |
| + |
| + for (int param = 0; param < params; ++param) { |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteString( |
| + *scope_info.parameter_name(param)->ToCString(DISALLOW_NULLS)); |
| + w->Write<uint32_t>(ty_offset); |
| + Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); |
| + uintptr_t block_start = w->position(); |
| + w->Write<uint8_t>(DW_OP_fbreg); |
| + w->WriteSLEB128( |
| + JavaScriptFrameConstants::kLastParameterOffset + |
| + kPointerSize * (params - param - 1)); |
| + block_size.set(static_cast<uint32_t>(w->position() - block_start)); |
| + } |
| + |
| + EmbeddedVector<char, 256> buffer; |
| + StringBuilder builder(buffer.start(), buffer.length()); |
| + |
| + for (int slot = 0; slot < slots; ++slot) { |
| + w->WriteULEB128(current_abbreviation++); |
| + builder.Reset(); |
| + builder.AddFormatted("slot%d", slot); |
| + w->WriteString(builder.Finalize()); |
| + } |
| + |
| + // See contexts.h for more information. |
| + ASSERT(Context::MIN_CONTEXT_SLOTS == 4); |
| + ASSERT(Context::CLOSURE_INDEX == 0); |
| + ASSERT(Context::PREVIOUS_INDEX == 1); |
| + ASSERT(Context::EXTENSION_INDEX == 2); |
| + ASSERT(Context::GLOBAL_INDEX == 3); |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteString(".closure"); |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteString(".previous"); |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteString(".extension"); |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteString(".global"); |
| + |
| + for (int context_slot = 0; |
| + context_slot < context_slots; |
| + ++context_slot) { |
| + w->WriteULEB128(current_abbreviation++); |
| + builder.Reset(); |
| + builder.AddFormatted("context_slot%d", context_slot + internal_slots); |
| + w->WriteString(builder.Finalize()); |
| + } |
| + |
| + for (int local = 0; local < locals; ++local) { |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteString( |
| + *scope_info.LocalName(local)->ToCString(DISALLOW_NULLS)); |
| + w->Write<uint32_t>(ty_offset); |
| + Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); |
| + uintptr_t block_start = w->position(); |
| + w->Write<uint8_t>(DW_OP_fbreg); |
| + w->WriteSLEB128( |
| + JavaScriptFrameConstants::kLocal0Offset - |
| + kPointerSize * local); |
| + block_size.set(static_cast<uint32_t>(w->position() - block_start)); |
| + } |
| + |
| + { |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteString("__function"); |
| + w->Write<uint32_t>(ty_offset); |
| + Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); |
| + uintptr_t block_start = w->position(); |
| + w->Write<uint8_t>(DW_OP_fbreg); |
| + w->WriteSLEB128(JavaScriptFrameConstants::kFunctionOffset); |
| + block_size.set(static_cast<uint32_t>(w->position() - block_start)); |
| + } |
| + |
| + { |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteString("__context"); |
| + w->Write<uint32_t>(ty_offset); |
| + Writer::Slot<uint32_t> block_size = w->CreateSlotHere<uint32_t>(); |
| + uintptr_t block_start = w->position(); |
| + w->Write<uint8_t>(DW_OP_fbreg); |
| + w->WriteSLEB128(StandardFrameConstants::kContextOffset); |
| + block_size.set(static_cast<uint32_t>(w->position() - block_start)); |
| + } |
| + } |
| + |
| size.set(static_cast<uint32_t>(w->position() - start)); |
| return true; |
| } |
| @@ -782,13 +1212,28 @@ class DebugInfoSection : public ELFSection { |
| }; |
| -class DebugAbbrevSection : public ELFSection { |
| +class DebugAbbrevSection : public DebugSection { |
| public: |
| - DebugAbbrevSection() : ELFSection(".debug_abbrev", TYPE_PROGBITS, 1) { } |
| + explicit DebugAbbrevSection(CodeDescription* desc) |
| +#ifdef __ELF |
| + : ELFSection(".debug_abbrev", TYPE_PROGBITS, 1), |
| +#else |
| + : MachOSection("__debug_abbrev", |
| + "__DWARF", |
| + 1, |
| + MachOSection::S_REGULAR | MachOSection::S_ATTR_DEBUG), |
| +#endif |
| + desc_(desc) { } |
| // DWARF2 standard, figure 14. |
| enum DWARF2Tags { |
| - DW_TAG_COMPILE_UNIT = 0x11 |
| + DW_TAG_FORMAL_PARAMETER = 0x05, |
| + DW_TAG_POINTER_TYPE = 0xf, |
| + DW_TAG_COMPILE_UNIT = 0x11, |
| + DW_TAG_STRUCTURE_TYPE = 0x13, |
| + DW_TAG_BASE_TYPE = 0x24, |
| + DW_TAG_SUBPROGRAM = 0x2e, |
| + DW_TAG_VARIABLE = 0x34 |
| }; |
| // DWARF2 standard, figure 16. |
| @@ -799,23 +1244,55 @@ class DebugAbbrevSection : public ELFSection { |
| // DWARF standard, figure 17. |
| enum DWARF2Attribute { |
| + DW_AT_LOCATION = 0x2, |
| DW_AT_NAME = 0x3, |
| + DW_AT_BYTE_SIZE = 0xb, |
| DW_AT_STMT_LIST = 0x10, |
| DW_AT_LOW_PC = 0x11, |
| - DW_AT_HIGH_PC = 0x12 |
| + DW_AT_HIGH_PC = 0x12, |
| + DW_AT_ENCODING = 0x3e, |
| + DW_AT_FRAME_BASE = 0x40, |
| + DW_AT_TYPE = 0x49 |
| }; |
| // DWARF2 standard, figure 19. |
| enum DWARF2AttributeForm { |
| DW_FORM_ADDR = 0x1, |
| + DW_FORM_BLOCK4 = 0x4, |
| DW_FORM_STRING = 0x8, |
| - DW_FORM_DATA4 = 0x6 |
| + DW_FORM_DATA4 = 0x6, |
| + DW_FORM_BLOCK = 0x9, |
| + DW_FORM_DATA1 = 0xb, |
| + DW_FORM_FLAG = 0xc, |
| + DW_FORM_REF4 = 0x13 |
| }; |
| + void WriteVariableAbbreviation(Writer* w, |
| + int abbreviation_code, |
| + bool has_value, |
| + bool is_parameter) { |
| + w->WriteULEB128(abbreviation_code); |
| + w->WriteULEB128(is_parameter ? DW_TAG_FORMAL_PARAMETER : DW_TAG_VARIABLE); |
| + w->Write<uint8_t>(DW_CHILDREN_NO); |
| + w->WriteULEB128(DW_AT_NAME); |
| + w->WriteULEB128(DW_FORM_STRING); |
| + if (has_value) { |
| + w->WriteULEB128(DW_AT_TYPE); |
| + w->WriteULEB128(DW_FORM_REF4); |
| + w->WriteULEB128(DW_AT_LOCATION); |
| + w->WriteULEB128(DW_FORM_BLOCK4); |
| + } |
| + w->WriteULEB128(0); |
| + w->WriteULEB128(0); |
| + } |
| + |
| bool WriteBody(Writer* w) { |
| - w->WriteULEB128(1); |
| + int current_abbreviation = 1; |
| + bool extra_info = desc_->IsInfoAvailable(); |
| + ASSERT(desc_->IsLineInfoAvailable()); |
| + w->WriteULEB128(current_abbreviation++); |
| w->WriteULEB128(DW_TAG_COMPILE_UNIT); |
| - w->Write<uint8_t>(DW_CHILDREN_NO); |
| + w->Write<uint8_t>(extra_info ? DW_CHILDREN_YES : DW_CHILDREN_NO); |
| w->WriteULEB128(DW_AT_NAME); |
| w->WriteULEB128(DW_FORM_STRING); |
| w->WriteULEB128(DW_AT_LOW_PC); |
| @@ -826,16 +1303,101 @@ class DebugAbbrevSection : public ELFSection { |
| w->WriteULEB128(DW_FORM_DATA4); |
| w->WriteULEB128(0); |
| w->WriteULEB128(0); |
| - w->WriteULEB128(0); |
| + |
| + if (extra_info) { |
| + CompilationInfo* info = desc_->info(); |
| + ScopeInfo<FreeStoreAllocationPolicy> scope_info(info->scope()); |
| + int params = scope_info.number_of_parameters(); |
| + int slots = scope_info.number_of_stack_slots(); |
| + int context_slots = scope_info.number_of_context_slots(); |
| + // The real slot ID is internal_slots + context_slot_id. |
| + int internal_slots = Context::MIN_CONTEXT_SLOTS; |
| + int locals = scope_info.NumberOfLocals(); |
| + int total_children = |
| + params + slots + context_slots + internal_slots + locals + 2; |
| + |
| + // The extra duplication below seems to be necessary to keep |
| + // gdb from getting upset on OSX. |
| + w->WriteULEB128(current_abbreviation++); // Abbreviation code. |
| + w->WriteULEB128(DW_TAG_SUBPROGRAM); |
| + w->Write<uint8_t>( |
| + total_children != 0 ? DW_CHILDREN_YES : DW_CHILDREN_NO); |
| + w->WriteULEB128(DW_AT_NAME); |
| + w->WriteULEB128(DW_FORM_STRING); |
| + w->WriteULEB128(DW_AT_LOW_PC); |
| + w->WriteULEB128(DW_FORM_ADDR); |
| + w->WriteULEB128(DW_AT_HIGH_PC); |
| + w->WriteULEB128(DW_FORM_ADDR); |
| + w->WriteULEB128(DW_AT_FRAME_BASE); |
| + w->WriteULEB128(DW_FORM_BLOCK4); |
| + w->WriteULEB128(0); |
| + w->WriteULEB128(0); |
| + |
| + w->WriteULEB128(current_abbreviation++); |
| + w->WriteULEB128(DW_TAG_STRUCTURE_TYPE); |
|
Vyacheslav Egorov (Chromium)
2011/06/29 12:12:02
What about using DW_TAG_base_type with DW_ATE_addr
|
| + w->Write<uint8_t>(DW_CHILDREN_NO); |
| + w->WriteULEB128(DW_AT_BYTE_SIZE); |
| + w->WriteULEB128(DW_FORM_DATA1); |
| + w->WriteULEB128(DW_AT_NAME); |
| + w->WriteULEB128(DW_FORM_STRING); |
| + w->WriteULEB128(0); |
| + w->WriteULEB128(0); |
| + |
| + for (int param = 0; param < params; ++param) { |
| + WriteVariableAbbreviation(w, current_abbreviation++, true, true); |
| + } |
| + |
| + for (int slot = 0; slot < slots; ++slot) { |
| + WriteVariableAbbreviation(w, current_abbreviation++, false, false); |
| + } |
| + |
| + for (int internal_slot = 0; |
| + internal_slot < internal_slots; |
| + ++internal_slot) { |
| + WriteVariableAbbreviation(w, current_abbreviation++, false, false); |
| + } |
| + |
| + for (int context_slot = 0; |
| + context_slot < context_slots; |
| + ++context_slot) { |
| + WriteVariableAbbreviation(w, current_abbreviation++, false, false); |
| + } |
| + |
| + for (int local = 0; local < locals; ++local) { |
| + WriteVariableAbbreviation(w, current_abbreviation++, true, false); |
| + } |
| + |
| + // The function. |
| + WriteVariableAbbreviation(w, current_abbreviation++, true, false); |
| + |
| + // The context. |
| + WriteVariableAbbreviation(w, current_abbreviation++, true, false); |
| + |
| + if (total_children != 0) { |
| + w->WriteULEB128(0); // Terminate the sibling list. |
| + } |
| + } |
| + |
| + w->WriteULEB128(0); // Terminate the table. |
| return true; |
| } |
| + |
| + private: |
| + CodeDescription* desc_; |
| }; |
| -class DebugLineSection : public ELFSection { |
| +class DebugLineSection : public DebugSection { |
| public: |
| explicit DebugLineSection(CodeDescription* desc) |
| +#ifdef __ELF |
| : ELFSection(".debug_line", TYPE_PROGBITS, 1), |
| +#else |
| + : MachOSection("__debug_line", |
| + "__DWARF", |
| + 1, |
| + MachOSection::S_REGULAR | MachOSection::S_ATTR_DEBUG), |
| +#endif |
| desc_(desc) { } |
| // DWARF2 standard, figure 34. |
| @@ -992,8 +1554,7 @@ class DebugLineSection : public ELFSection { |
| #ifdef V8_TARGET_ARCH_X64 |
| - |
| -class UnwindInfoSection : public ELFSection { |
| +class UnwindInfoSection : public DebugSection { |
| public: |
| explicit UnwindInfoSection(CodeDescription *desc); |
| virtual bool WriteBody(Writer *w); |
| @@ -1079,8 +1640,13 @@ void UnwindInfoSection::WriteLength(Writer *w, |
| UnwindInfoSection::UnwindInfoSection(CodeDescription *desc) |
| - : ELFSection(".eh_frame", TYPE_X86_64_UNWIND, 1), desc_(desc) |
| -{ } |
| +#ifdef __ELF |
| + : ELFSection(".eh_frame", TYPE_X86_64_UNWIND, 1), |
| +#else |
| + : MachOSection("__eh_frame", "__TEXT", sizeof(uintptr_t), |
| + MachOSection::S_REGULAR), |
| +#endif |
| + desc_(desc) { } |
| int UnwindInfoSection::WriteCIE(Writer *w) { |
| Writer::Slot<uint32_t> cie_length_slot = w->CreateSlotHere<uint32_t>(); |
| @@ -1212,15 +1778,14 @@ bool UnwindInfoSection::WriteBody(Writer *w) { |
| #endif // V8_TARGET_ARCH_X64 |
| - |
| -static void CreateDWARFSections(CodeDescription* desc, ELF* elf) { |
| +static void CreateDWARFSections(CodeDescription* desc, DebugObject* obj) { |
| if (desc->IsLineInfoAvailable()) { |
| - elf->AddSection(new DebugInfoSection(desc)); |
| - elf->AddSection(new DebugAbbrevSection); |
| - elf->AddSection(new DebugLineSection(desc)); |
| + obj->AddSection(new DebugInfoSection(desc)); |
| + obj->AddSection(new DebugAbbrevSection(desc)); |
| + obj->AddSection(new DebugLineSection(desc)); |
| } |
| #ifdef V8_TARGET_ARCH_X64 |
| - elf->AddSection(new UnwindInfoSection(desc)); |
| + obj->AddSection(new UnwindInfoSection(desc)); |
| #endif |
| } |
| @@ -1260,6 +1825,13 @@ extern "C" { |
| // Static initialization is necessary to prevent GDB from seeing |
| // uninitialized descriptor. |
| JITDescriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; |
| + |
| +#ifdef OBJECT_PRINT |
| + void __gdb_print_v8_object(MaybeObject* object) { |
| + object->Print(); |
| + fprintf(stdout, "\n"); |
| + } |
| +#endif |
| } |
| @@ -1283,17 +1855,23 @@ static void DestroyCodeEntry(JITCodeEntry* entry) { |
| } |
| -static void RegisterCodeEntry(JITCodeEntry* entry) { |
| +static void RegisterCodeEntry(JITCodeEntry* entry, |
| + bool dump_if_enabled, |
| + const char* name_hint) { |
| #if defined(DEBUG) && !defined(WIN32) |
| static int file_num = 0; |
| - if (FLAG_gdbjit_dump) { |
| + if (FLAG_gdbjit_dump && dump_if_enabled) { |
| static const int kMaxFileNameSize = 64; |
| static const char* kElfFilePrefix = "/tmp/elfdump"; |
| static const char* kObjFileExt = ".o"; |
| char file_name[64]; |
| - OS::SNPrintF(Vector<char>(file_name, kMaxFileNameSize), "%s%d%s", |
| - kElfFilePrefix, file_num++, kObjFileExt); |
| + OS::SNPrintF(Vector<char>(file_name, kMaxFileNameSize), |
| + "%s%s%d%s", |
| + kElfFilePrefix, |
| + (name_hint != NULL) ? name_hint : "", |
| + file_num++, |
| + kObjFileExt); |
| WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_); |
| } |
| #endif |
| @@ -1327,7 +1905,18 @@ static void UnregisterCodeEntry(JITCodeEntry* entry) { |
| static JITCodeEntry* CreateELFObject(CodeDescription* desc) { |
| ZoneScope zone_scope(Isolate::Current(), DELETE_ON_EXIT); |
| +#ifdef __MACH_O |
| + MachO mach_o; |
| + Writer w(&mach_o); |
| + |
| + mach_o.AddSection(new MachOTextSection(kCodeAlignment, |
| + desc->CodeStart(), |
| + desc->CodeSize())); |
| + |
| + CreateDWARFSections(desc, &mach_o); |
| + mach_o.Write(&w, desc->CodeStart(), desc->CodeSize()); |
| +#else |
| ELF elf; |
| Writer w(&elf); |
| @@ -1345,6 +1934,7 @@ static JITCodeEntry* CreateELFObject(CodeDescription* desc) { |
| CreateDWARFSections(desc, &elf); |
| elf.Write(&w); |
| +#endif |
| return CreateCodeEntry(w.buffer(), w.position()); |
| } |
| @@ -1393,7 +1983,8 @@ static GDBJITLineInfo* UntagLineInfo(void* ptr) { |
| void GDBJITInterface::AddCode(Handle<String> name, |
| Handle<Script> script, |
| - Handle<Code> code) { |
| + Handle<Code> code, |
| + CompilationInfo* info) { |
| if (!FLAG_gdbjit) return; |
| // Force initialization of line_ends array. |
| @@ -1401,9 +1992,9 @@ void GDBJITInterface::AddCode(Handle<String> name, |
| if (!name.is_null()) { |
| SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS); |
| - AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script); |
| + AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script, info); |
| } else { |
| - AddCode("", *code, GDBJITInterface::FUNCTION, *script); |
| + AddCode("", *code, GDBJITInterface::FUNCTION, *script, info); |
| } |
| } |
| @@ -1450,7 +2041,8 @@ Mutex* GDBJITInterface::mutex_ = OS::CreateMutex(); |
| void GDBJITInterface::AddCode(const char* name, |
| Code* code, |
| GDBJITInterface::CodeTag tag, |
| - Script* script) { |
| + Script* script, |
| + CompilationInfo* info) { |
| if (!FLAG_gdbjit) return; |
| ScopedLock lock(mutex_); |
| @@ -1465,7 +2057,8 @@ void GDBJITInterface::AddCode(const char* name, |
| script != NULL ? Handle<Script>(script) |
| : Handle<Script>(), |
| lineinfo, |
| - tag); |
| + tag, |
| + info); |
| if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) { |
| delete lineinfo; |
| @@ -1480,7 +2073,18 @@ void GDBJITInterface::AddCode(const char* name, |
| delete lineinfo; |
| e->value = entry; |
| - RegisterCodeEntry(entry); |
| + const char* name_hint = NULL; |
| + bool should_dump = false; |
| + if (FLAG_gdbjit_dump) { |
| + if (strlen(FLAG_gdbjit_dump_filter) == 0) { |
| + name_hint = name; |
| + should_dump = true; |
| + } else if (name != NULL) { |
| + name_hint = strstr(name, FLAG_gdbjit_dump_filter); |
| + should_dump = (name_hint != NULL); |
| + } |
| + } |
| + RegisterCodeEntry(entry, should_dump, name_hint); |
| } |
| @@ -1500,7 +2104,7 @@ void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, |
| builder.AddFormatted(": code object %p", static_cast<void*>(code)); |
| } |
| - AddCode(builder.Finalize(), code, tag); |
| + AddCode(builder.Finalize(), code, tag, NULL, NULL); |
| } |