| Index: src/gdb-jit.cc
|
| ===================================================================
|
| --- src/gdb-jit.cc (revision 8618)
|
| +++ src/gdb-jit.cc (working copy)
|
| @@ -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 @@
|
| }
|
| }
|
|
|
| - ELF* elf() { return elf_; }
|
| + DebugObject* debug_object() { return debug_object_; }
|
|
|
| byte* buffer() { return buffer_; }
|
|
|
| @@ -165,7 +178,7 @@
|
| return reinterpret_cast<T*>(&buffer_[offset]);
|
| }
|
|
|
| - ELF* elf_;
|
| + DebugObject* debug_object_;
|
| uintptr_t position_;
|
| uintptr_t capacity_;
|
| byte* buffer_;
|
| @@ -173,21 +186,120 @@
|
|
|
| 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, sizeof(header->sectname));
|
| + memset(header->segname, 0, sizeof(header->segname));
|
| + ASSERT(strlen(name_) < sizeof(header->sectname));
|
| + ASSERT(strlen(segment_) < sizeof(header->segname));
|
| + strncpy(header->sectname, name_, sizeof(header->sectname));
|
| + strncpy(header->segname, segment_, sizeof(header->segname));
|
| + }
|
| +
|
| + 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 @@
|
| 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 @@
|
| 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 @@
|
|
|
| // 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,11 +913,11 @@
|
| ZoneList<ELFSymbol> locals_;
|
| ZoneList<ELFSymbol> globals_;
|
| };
|
| +#endif // defined(__ELF)
|
|
|
|
|
| class CodeDescription BASE_EMBEDDED {
|
| public:
|
| -
|
| #ifdef V8_TARGET_ARCH_X64
|
| enum StackState {
|
| POST_RBP_PUSH,
|
| @@ -658,12 +931,14 @@
|
| 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 {
|
| @@ -678,6 +953,14 @@
|
| 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());
|
| }
|
| @@ -725,12 +1008,13 @@
|
| 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) {
|
| @@ -755,14 +1039,42 @@
|
| 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.
|
| @@ -774,6 +1086,123 @@
|
| 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;
|
| }
|
| @@ -783,13 +1212,28 @@
|
| };
|
|
|
|
|
| -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.
|
| @@ -800,23 +1244,55 @@
|
|
|
| // 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);
|
| @@ -827,16 +1303,101 @@
|
| 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);
|
| + 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.
|
| @@ -993,8 +1554,7 @@
|
|
|
| #ifdef V8_TARGET_ARCH_X64
|
|
|
| -
|
| -class UnwindInfoSection : public ELFSection {
|
| +class UnwindInfoSection : public DebugSection {
|
| public:
|
| explicit UnwindInfoSection(CodeDescription *desc);
|
| virtual bool WriteBody(Writer *w);
|
| @@ -1080,8 +1640,13 @@
|
|
|
|
|
| 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>();
|
| @@ -1213,15 +1778,14 @@
|
|
|
| #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
|
| }
|
|
|
| @@ -1261,6 +1825,13 @@
|
| // 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
|
| }
|
|
|
|
|
| @@ -1284,17 +1855,23 @@
|
| }
|
|
|
|
|
| -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,8 +1904,19 @@
|
|
|
|
|
| static JITCodeEntry* CreateELFObject(CodeDescription* desc) {
|
| - ZoneScope zone_scope(DELETE_ON_EXIT);
|
| + 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);
|
|
|
| @@ -1346,6 +1934,7 @@
|
| CreateDWARFSections(desc, &elf);
|
|
|
| elf.Write(&w);
|
| +#endif
|
|
|
| return CreateCodeEntry(w.buffer(), w.position());
|
| }
|
| @@ -1394,7 +1983,8 @@
|
|
|
| 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.
|
| @@ -1402,9 +1992,9 @@
|
|
|
| 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);
|
| }
|
| }
|
|
|
| @@ -1451,7 +2041,8 @@
|
| void GDBJITInterface::AddCode(const char* name,
|
| Code* code,
|
| GDBJITInterface::CodeTag tag,
|
| - Script* script) {
|
| + Script* script,
|
| + CompilationInfo* info) {
|
| if (!FLAG_gdbjit) return;
|
|
|
| ScopedLock lock(mutex_);
|
| @@ -1466,7 +2057,8 @@
|
| script != NULL ? Handle<Script>(script)
|
| : Handle<Script>(),
|
| lineinfo,
|
| - tag);
|
| + tag,
|
| + info);
|
|
|
| if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) {
|
| delete lineinfo;
|
| @@ -1481,7 +2073,18 @@
|
| 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);
|
| }
|
|
|
|
|
| @@ -1501,7 +2104,7 @@
|
| builder.AddFormatted(": code object %p", static_cast<void*>(code));
|
| }
|
|
|
| - AddCode(builder.Finalize(), code, tag);
|
| + AddCode(builder.Finalize(), code, tag, NULL, NULL);
|
| }
|
|
|
|
|
|
|