Chromium Code Reviews| Index: src/gdb-jit.cc |
| =================================================================== |
| --- src/gdb-jit.cc (revision 6529) |
| +++ src/gdb-jit.cc (working copy) |
| @@ -201,6 +201,7 @@ |
| TYPE_SHLIB = 10, |
| TYPE_DYNSYM = 11, |
| TYPE_LOPROC = 0x70000000, |
| + TYPE_X86_64_UNWIND = 0x70000001, |
| TYPE_HIPROC = 0x7fffffff, |
| TYPE_LOUSER = 0x80000000, |
| TYPE_HIUSER = 0xffffffff |
| @@ -639,11 +640,26 @@ |
| class CodeDescription BASE_EMBEDDED { |
| public: |
| + |
| + enum OffsetType { |
| +#ifdef V8_TARGET_ARCH_X64 |
| + POST_RBP_PUSH, |
| + POST_RBP_SET, |
| + POST_RBP_POP, |
| + OFFSET_TYPE_MAX |
| +#endif |
| + }; |
| + |
| CodeDescription(const char* name, |
| Code* code, |
| Handle<Script> script, |
| - GDBJITLineInfo* lineinfo) |
| - : name_(name), code_(code), script_(script), lineinfo_(lineinfo) |
| + GDBJITLineInfo* lineinfo, |
| + GDBJITInterface::CodeTag type) |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
nitpick: type -> tag
|
| + : name_(name), |
| + code_(code), |
| + script_(script), |
| + lineinfo_(lineinfo), |
| + type_(type) |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
nitpick: type -> tag
|
| { } |
| const char* code_name() const { |
| @@ -654,6 +670,10 @@ |
| return code_->instruction_end() - code_->instruction_start(); |
| } |
| + uintptr_t code_end() const { |
| + return (uintptr_t)code_->instruction_end(); |
| + } |
| + |
| uintptr_t code_start() const { |
| return (uintptr_t)code_->instruction_start(); |
| } |
| @@ -666,6 +686,16 @@ |
| lineinfo_ != NULL; |
| } |
| + uintptr_t get_location(OffsetType ofs) const { |
| + ASSERT(ofs < OFFSET_TYPE_MAX); |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
will not compile on ia32
|
| + return offsets_[ofs]; |
| + } |
| + |
| + void set_location(OffsetType ofs, uintptr_t value) { |
| + ASSERT(ofs < OFFSET_TYPE_MAX); |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
will not compile on ia32
|
| + offsets_[ofs] = value; |
| + } |
| + |
| GDBJITLineInfo* lineinfo() const { return lineinfo_; } |
| SmartPointer<char> filename() { |
| @@ -676,11 +706,19 @@ |
| return GetScriptLineNumberSafe(script_, pos) + 1; |
| } |
| + GDBJITInterface::CodeTag get_type() const { |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
nitpick: type -> tag
|
| + return type_; |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
nitpick: type -> tag
|
| + } |
| + |
| private: |
| const char* name_; |
| Code* code_; |
| Handle<Script> script_; |
| GDBJITLineInfo* lineinfo_; |
| + GDBJITInterface::CodeTag type_; |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
nitpick: type -> tag
|
| +#ifdef V8_TARGET_ARCH_X64 |
| + uintptr_t offsets_[OFFSET_TYPE_MAX]; |
| +#endif |
| }; |
| @@ -900,12 +938,230 @@ |
| }; |
| +#ifdef V8_TARGET_ARCH_X64 |
| + |
| + |
| +class UnwindInfoSection : public ELFSection { |
| + public: |
| + explicit UnwindInfoSection(CodeDescription *desc); |
| + virtual bool WriteBody(Writer *w); |
| + |
| + int WriteCIE(Writer *w); |
| + void WriteFDE(Writer *w, int); |
| + |
| + void WriteFDEStateOne(Writer *w); |
| + void WriteFDEStateTwo(Writer *w); |
| + void WriteFDEStateThree(Writer *w); |
| + void WriteFDEStateFour(Writer *w); |
| + |
| + void WriteLength(Writer *w, Writer::Slot<uint32_t> &, int); |
| + |
| + private: |
| + CodeDescription *desc_; |
| + |
| + // DWARF3 Specification, Table 7.23 |
| + enum CFIInstructions { |
| + DW_CFA_ADVANCE_LOC = 0X40, |
| + DW_CFA_OFFSET = 0X80, |
| + DW_CFA_RESTORE = 0XC0, |
| + DW_CFA_NOP = 0X00, |
| + DW_CFA_SET_LOC = 0X01, |
| + DW_CFA_ADVANCE_LOC1 = 0X02, |
| + DW_CFA_ADVANCE_LOC2 = 0X03, |
| + DW_CFA_ADVANCE_LOC4 = 0X04, |
| + DW_CFA_OFFSET_EXTENDED = 0X05, |
| + DW_CFA_RESTORE_EXTENDED = 0X06, |
| + DW_CFA_UNDEFINED = 0X07, |
| + DW_CFA_SAME_VALUE = 0X08, |
| + DW_CFA_REGISTER = 0X09, |
| + DW_CFA_REMEMBER_STATE = 0X0A, |
| + DW_CFA_RESTORE_STATE = 0X0B, |
| + DW_CFA_DEF_CFA = 0X0C, |
| + DW_CFA_DEF_CFA_REGISTER = 0X0D, |
| + DW_CFA_DEF_CFA_OFFSET = 0X0E, |
| + |
| + DW_CFA_DEF_CFA_EXPRESSION = 0X0F, |
| + DW_CFA_EXPRESSION = 0X10, |
| + DW_CFA_OFFSET_EXTENDED_SF = 0X11, |
| + DW_CFA_DEF_CFA_SF = 0X12, |
| + DW_CFA_DEF_CFA_OFFSET_SF = 0X13, |
| + DW_CFA_VAL_OFFSET = 0X14, |
| + DW_CFA_VAL_OFFSET_SF = 0X15, |
| + DW_CFA_VAL_EXPRESSION = 0X16 |
| + }; |
| + |
| + // System V ABI, AMD64 Supplement, Version 0.99.5, Figure 3.36 |
| + enum RegisterMapping { |
| + // Only the relevant ones have been added to reduce clutter. |
| + AMD64_RBP = 6, |
| + AMD64_RSP = 7, |
| + AMD64_RA = 16 |
| + }; |
| + |
| + enum CFIConstants { |
| + CIE_ID = 0, |
| + CIE_VERSION = 1, |
| + CODE_ALIGN_FACTOR = 1, |
| + DATA_ALIGN_FACTOR = 1, |
| + RETURN_ADDRESS_REGISTER = AMD64_RA |
| + }; |
| +}; |
| + |
| + |
| +void UnwindInfoSection::WriteLength(Writer *w, |
| + Writer::Slot<uint32_t> &length_slot, |
| + int initial_position) { |
| + uint32_t align = (w->position() - initial_position) % kPointerSize; |
| + |
| + if (align != 0) { |
| + for (uint32_t i = 0; i < (kPointerSize - align); i++) |
| + w->Write<uint8_t>(DW_CFA_NOP); |
| + } |
| + |
| + ASSERT((w->position() - initial_position) % kPointerSize == 0); |
| + length_slot.set(w->position() - initial_position); |
| +} |
| + |
| + |
| +UnwindInfoSection::UnwindInfoSection(CodeDescription *desc) |
| + : ELFSection(".eh_frame", TYPE_X86_64_UNWIND, 1), desc_(desc) |
| +{ } |
| + |
| +int UnwindInfoSection::WriteCIE(Writer *w) { |
| + Writer::Slot<uint32_t> cie_length_slot = w->CreateSlotHere<uint32_t>(); |
| + uint32_t cie_position = w->position(); |
| + |
| + // Write out the CIE header. Currently no 'common instructions' are |
| + // emitted onto the CIE; every FDE has its own set of instructions. |
| + |
| + w->Write<uint32_t>(CIE_ID); |
| + w->Write<uint8_t>(CIE_VERSION); |
| + w->Write<uint8_t>(0); // Null augmentation string. |
| + w->WriteSLEB128(CODE_ALIGN_FACTOR); |
| + w->WriteSLEB128(DATA_ALIGN_FACTOR); |
| + w->Write<uint8_t>(RETURN_ADDRESS_REGISTER); |
| + |
| + WriteLength(w, cie_length_slot, cie_position); |
| + |
| + return cie_position; |
| +} |
| + |
| + |
| +void UnwindInfoSection::WriteFDE(Writer *w, int cie_position) { |
| + // The only FDE for this function. The CFA is the current RBP. |
| + Writer::Slot<uint32_t> fde_length_slot = w->CreateSlotHere<uint32_t>(); |
| + int fde_position = w->position(); |
| + w->Write<int32_t>(fde_position - cie_position + 4); |
| + |
| + w->Write<uintptr_t>(desc_->code_start()); |
| + w->Write<uintptr_t>(desc_->code_size()); |
| + |
| + WriteFDEStateOne(w); |
| + WriteFDEStateTwo(w); |
| + WriteFDEStateThree(w); |
| + WriteFDEStateFour(w); |
| + |
| + WriteLength(w, fde_length_slot, fde_position); |
| +} |
| + |
| + |
| +void UnwindInfoSection::WriteFDEStateOne(Writer *w) { |
| + // The first state, just after the control has been transferred to the the |
| + // function. |
| + |
| + // RBP for this function will be the value of RSP after pushing the RBP |
| + // for the previous function. The previous RBP has not been pushed yet. |
| + w->Write<uint8_t>(DW_CFA_DEF_CFA_SF); |
| + w->WriteULEB128(AMD64_RSP); |
| + w->WriteSLEB128(-kPointerSize); |
| + |
| + // The RA is stored at location CFA + kCallerPCOffset. This is an invariant, |
| + // and hence omitted from the next states. |
| + w->Write<uint8_t>(DW_CFA_OFFSET_EXTENDED); |
| + w->WriteULEB128(AMD64_RA); |
| + w->WriteSLEB128(StandardFrameConstants::kCallerPCOffset); |
| + |
| + // The RBP of the previous function is still in RBP. |
| + w->Write<uint8_t>(DW_CFA_SAME_VALUE); |
| + w->WriteULEB128(AMD64_RBP); |
| + |
| + // Last location described by this entry. |
| + w->Write<uint8_t>(DW_CFA_SET_LOC); |
| + w->Write<uint64_t>(desc_->get_location(CodeDescription::POST_RBP_PUSH)); |
| +} |
| + |
| + |
| +void UnwindInfoSection::WriteFDEStateTwo(Writer *w) { |
| + // The second state, just after RBP has been pushed. |
| + |
| + // RBP / CFA for this function is now the current RSP, so just set the |
| + // offset from the previous rule (from -8) to 0. |
| + w->Write<uint8_t>(DW_CFA_DEF_CFA_OFFSET); |
| + w->WriteULEB128(0); |
| + |
| + // The previous RBP is stored at CFA + kCallerFPOffset. This is an invariant |
| + // in this and the next state, and hence omitted in the next state. |
| + w->Write<uint8_t>(DW_CFA_OFFSET_EXTENDED); |
| + w->WriteULEB128(AMD64_RBP); |
| + w->WriteSLEB128(StandardFrameConstants::kCallerFPOffset); |
| + |
| + // Last location described by this entry. |
| + w->Write<uint8_t>(DW_CFA_SET_LOC); |
| + w->Write<uint64_t>(desc_->get_location(CodeDescription::POST_RBP_SET)); |
| +} |
| + |
| + |
| +void UnwindInfoSection::WriteFDEStateThree(Writer *w) { |
| + // The third state, after the RBP has been set. |
| + |
| + // The CFA can now directly be set to RBP. |
| + w->Write<uint8_t>(DW_CFA_DEF_CFA); |
| + w->WriteULEB128(AMD64_RBP); |
| + w->WriteULEB128(0); |
| + |
| + // Last location described by this entry. |
| + w->Write<uint8_t>(DW_CFA_SET_LOC); |
| + w->Write<uint64_t>(desc_->get_location(CodeDescription::POST_RBP_POP)); |
| +} |
| + |
| + |
| +void UnwindInfoSection::WriteFDEStateFour(Writer *w) { |
| + // The fourth (final) state. The RBP has been popped (just before issuing a |
| + // return). |
| + |
| + // The CFA can is now calculated in the same way as in the first state. |
| + w->Write<uint8_t>(DW_CFA_DEF_CFA_SF); |
| + w->WriteULEB128(AMD64_RSP); |
| + w->WriteSLEB128(-kPointerSize); |
| + |
| + // The RBP |
| + w->Write<uint8_t>(DW_CFA_OFFSET_EXTENDED); |
| + w->WriteULEB128(AMD64_RBP); |
| + w->WriteSLEB128(StandardFrameConstants::kCallerFPOffset); |
| + |
| + // Last location described by this entry. |
| + w->Write<uint8_t>(DW_CFA_SET_LOC); |
| + w->Write<uint64_t>(desc_->code_end()); |
| +} |
| + |
| + |
| +bool UnwindInfoSection::WriteBody(Writer *w) { |
| + uint32_t cie_position = WriteCIE(w); |
| + WriteFDE(w, cie_position); |
| + return true; |
| +} |
| + |
| + |
| +#endif // V8_TARGET_ARCH_X64 |
| + |
| + |
| static void CreateDWARFSections(CodeDescription* desc, ELF* elf) { |
| if (desc->is_line_info_available()) { |
| elf->AddSection(new DebugInfoSection(desc)); |
| elf->AddSection(new DebugAbbrevSection); |
| elf->AddSection(new DebugLineSection(desc)); |
| } |
| + elf->AddSection(new UnwindInfoSection(desc)); |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
I don't think it will compile on ia32
|
| } |
| @@ -1065,41 +1321,65 @@ |
| if (!name.is_null()) { |
| SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS); |
| - AddCode(*name_cstring, *code, *script); |
| + AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script); |
| } else { |
| - AddCode("", *code, *script); |
| + AddCode("", *code, GDBJITInterface::FUNCTION, *script); |
| } |
| } |
| +#ifdef V8_TARGET_ARCH_X64 |
| +#define RBP_PUSH_OFFSET 1 |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
We prefer constants to macroses:
static const int
|
| +#define RBP_SET_OFFSET 4 |
| +#define RBP_POP_OFFSET -3 |
| + |
| +static void AddUnwindInfo(CodeDescription *cd) { |
| + if (cd->get_type() == GDBJITInterface::FUNCTION) { |
| + cd->set_location(CodeDescription::POST_RBP_PUSH, |
| + cd->code_start() + RBP_PUSH_OFFSET); |
| + cd->set_location(CodeDescription::POST_RBP_SET, |
| + cd->code_start() + RBP_SET_OFFSET); |
| + cd->set_location(CodeDescription::POST_RBP_POP, |
| + cd->code_end() + RBP_POP_OFFSET); |
| + } else { |
| + cd->set_location(CodeDescription::POST_RBP_PUSH, cd->code_start()); |
| + cd->set_location(CodeDescription::POST_RBP_SET, cd->code_start()); |
| + cd->set_location(CodeDescription::POST_RBP_POP, cd->code_end()); |
| + } |
| +} |
| +#else |
| +#define AddUnwindInfo(x) ((void) x) |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
Move #ifdef into function body to avoid defining m
|
| +#endif // V8_TARGET_ARCH_X64 |
| + |
| + |
| void GDBJITInterface::AddCode(const char* name, |
| Code* code, |
| + GDBJITInterface::CodeTag type, |
| Script* script) { |
| if (!FLAG_gdbjit) return; |
| AssertNoAllocation no_gc; |
| HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true); |
| - if (e->value != NULL && !IsLineInfoTagged(e->value)) return; |
| + GDBJITLineInfo* lineinfo; |
| - GDBJITLineInfo* lineinfo = UntagLineInfo(e->value); |
| + if (e->value != NULL && !IsLineInfoTagged(e->value)) |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
Is there a reason for this change?
If we are regi
|
| + lineinfo = NULL; |
| + else |
| + lineinfo = UntagLineInfo(e->value); |
| + |
| CodeDescription code_desc(name, |
| code, |
| script != NULL ? Handle<Script>(script) |
| : Handle<Script>(), |
| - lineinfo); |
| + lineinfo, |
| + type); |
| - if (!FLAG_gdbjit_full && !code_desc.is_line_info_available()) { |
|
Vyacheslav Egorov (Chromium)
2011/02/01 13:17:25
Why did you kill FLAG_gdbjit_full support?
It is
|
| - delete lineinfo; |
| - entries.Remove(code, HashForCodeObject(code)); |
| - return; |
| - } |
| + AddUnwindInfo(&code_desc); |
| JITCodeEntry* entry = CreateELFObject(&code_desc); |
| ASSERT(!IsLineInfoTagged(entry)); |
| - |
| delete lineinfo; |
| e->value = entry; |
| - |
| RegisterCodeEntry(entry); |
| } |
| @@ -1120,7 +1400,7 @@ |
| builder.AddFormatted(": code object %p", static_cast<void*>(code)); |
| } |
| - AddCode(builder.Finalize(), code); |
| + AddCode(builder.Finalize(), code, tag); |
| } |