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: |
+ |
+#ifdef V8_TARGET_ARCH_X64 |
+ enum OffsetType { |
+ 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 tag) |
+ : name_(name), |
+ code_(code), |
+ script_(script), |
+ lineinfo_(lineinfo), |
+ tag_(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,18 @@ |
lineinfo_ != NULL; |
} |
+#ifdef V8_TARGET_ARCH_X64 |
+ uintptr_t get_location(OffsetType ofs) const { |
+ ASSERT(ofs < OFFSET_TYPE_MAX); |
+ return offsets_[ofs]; |
+ } |
+ |
+ void set_location(OffsetType ofs, uintptr_t value) { |
+ ASSERT(ofs < OFFSET_TYPE_MAX); |
+ offsets_[ofs] = value; |
+ } |
+#endif |
+ |
GDBJITLineInfo* lineinfo() const { return lineinfo_; } |
SmartPointer<char> filename() { |
@@ -676,11 +708,19 @@ |
return GetScriptLineNumberSafe(script_, pos) + 1; |
} |
+ GDBJITInterface::CodeTag get_tag() const { |
Vyacheslav Egorov (Chromium)
2011/02/01 21:00:25
Getters don't have get_ prefix in Google C++ Code
|
+ return tag_; |
+ } |
+ |
private: |
const char* name_; |
Code* code_; |
Handle<Script> script_; |
GDBJITLineInfo* lineinfo_; |
+ GDBJITInterface::CodeTag tag_; |
+#ifdef V8_TARGET_ARCH_X64 |
+ uintptr_t offsets_[OFFSET_TYPE_MAX]; |
+#endif |
}; |
@@ -900,12 +940,232 @@ |
}; |
+#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); |
Vyacheslav Egorov (Chromium)
2011/02/01 21:00:25
This names are not informative.
|
+ 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)); |
} |
+#ifdef V8_TARGET_ARCH_X64 |
+ elf->AddSection(new UnwindInfoSection(desc)); |
+#endif |
} |
@@ -1065,15 +1325,47 @@ |
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); |
} |
} |
+static const int kFramePointerPushOffset = 1; |
+static const int kFramePointerSetOffset = 4; |
+static const int kFramePointerPopOffset = -3; |
+static void AddUnwindInfo(CodeDescription *cd) { |
+#ifdef V8_TARGET_ARCH_X64 |
+ if (cd->get_tag() == GDBJITInterface::FUNCTION) { |
+ |
Vyacheslav Egorov (Chromium)
2011/02/01 21:00:25
This does not lint (did you run tools/presubmit.py
|
+ { |
+ // Sanity check |
+ byte *code = reinterpret_cast<byte*>(cd->code_start()); |
Vyacheslav Egorov (Chromium)
2011/02/01 21:00:25
This will fail to compile in release mode (due to
|
+ ASSERT(code[kFramePointerSetOffset] == 0x56); |
+ ASSERT(code[kFramePointerSetOffset + 1] == 0x57); |
+ ASSERT(code[kFramePointerPushOffset] == 0x48); |
+ ASSERT(code[kFramePointerPopOffset] == 0xBE); |
+ } |
+ |
+ cd->set_location(CodeDescription::POST_RBP_PUSH, |
+ cd->code_start() + kFramePointerPushOffset); |
+ cd->set_location(CodeDescription::POST_RBP_SET, |
+ cd->code_start() + kFramePointerSetOffset); |
+ cd->set_location(CodeDescription::POST_RBP_POP, |
+ cd->code_end() + kFramePointerPopOffset); |
+ } 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()); |
+ } |
+#endif // V8_TARGET_ARCH_X64 |
+} |
+ |
+ |
void GDBJITInterface::AddCode(const char* name, |
Code* code, |
+ GDBJITInterface::CodeTag tag, |
Script* script) { |
if (!FLAG_gdbjit) return; |
AssertNoAllocation no_gc; |
@@ -1086,7 +1378,8 @@ |
code, |
script != NULL ? Handle<Script>(script) |
: Handle<Script>(), |
- lineinfo); |
+ lineinfo, |
+ tag); |
if (!FLAG_gdbjit_full && !code_desc.is_line_info_available()) { |
delete lineinfo; |
@@ -1094,6 +1387,7 @@ |
return; |
} |
+ AddUnwindInfo(&code_desc); |
JITCodeEntry* entry = CreateELFObject(&code_desc); |
ASSERT(!IsLineInfoTagged(entry)); |
@@ -1120,7 +1414,7 @@ |
builder.AddFormatted(": code object %p", static_cast<void*>(code)); |
} |
- AddCode(builder.Finalize(), code); |
+ AddCode(builder.Finalize(), code, tag); |
} |