Index: src/gdb-jit.cc |
=================================================================== |
--- src/gdb-jit.cc (revision 6445) |
+++ 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 |
@@ -1166,5 +1167,264 @@ |
} |
+#ifdef V8_TARGET_ARCH_X64 |
+ |
+ |
+class UnwindInfoSection : public ELFSection { |
+ public: |
+ explicit UnwindInfoSection(UnwindInfoInterface::UnwindInformation *); |
+ explicit UnwindInfoSection(uintptr_t begin, uintptr_t end); |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
2 argument constructors don't need explicit.
|
+ virtual bool WriteBody(Writer *w); |
+ |
+ private: |
+ UnwindInfoInterface::UnwindInformation *info_; |
+ uintptr_t begin_, length_; |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
uintptr_t begin_;
uintptr_t length_;
|
+ bool is_code_stub_; |
+ |
+ // DWARF3 Specification, Table 7.23 |
+ enum CFIInstructions { |
+ DW_CFA_ADVANCE_LOC = 0X40, |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
style nit: 0X -> 0x
|
+ 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 |
+ }; |
+}; |
+ |
+ |
+UnwindInfoSection::UnwindInfoSection(UnwindInfoInterface::UnwindInformation |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
I think the right way to format this will be
Unw
|
+ *info) |
+ : ELFSection(".eh_frame", TYPE_X86_64_UNWIND, 1), info_(info), |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
either all on a single line or each initializer on
|
+ is_code_stub_(false) { } |
+ |
+ |
+UnwindInfoSection::UnwindInfoSection(uintptr_t begin, uintptr_t length) |
+ : ELFSection(".eh_frame", TYPE_X86_64_UNWIND, 1), begin_(begin), |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
ditto
|
+ length_(length), is_code_stub_(true) { } |
+ |
+ |
+bool UnwindInfoSection::WriteBody(Writer *w) { |
+ Writer::Slot<uint32_t> cie_length_slot = w->CreateSlotHere<uint32_t>(); |
+ uint32_t cie_position = w->position(), align; |
+ |
+ // 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); // Augmentation string. |
+ w->WriteSLEB128(CODE_ALIGN_FACTOR); |
+ w->WriteSLEB128(DATA_ALIGN_FACTOR); |
+ w->Write<uint8_t>(RETURN_ADDRESS_REGISTER); |
+ |
+ align = (w->position() - cie_position) % kPointerSize; |
+ if (align) { |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
We don't rely on implicit int->bool convertions, s
|
+ for (uint32_t i = 0; i < (kPointerSize - align); i++) { |
+ w->Write<uint8_t>(DW_CFA_NOP); |
+ } |
+ } |
+ ASSERT((w->position() - cie_position) % kPointerSize == 0); |
+ cie_length_slot.set(w->position() - cie_position); |
+ |
+ 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); // Pointer to CIE |
+ |
+ // The (only) FDE for this function |
+ |
+ if (!is_code_stub_) { |
+ w->Write<uintptr_t>(info_->begin_); |
+ w->Write<uintptr_t> |
+ (info_->state_offsets_[UnwindInfoInterface::UNWIND_STATE_AFTER_RETURN]); |
+ |
+ // The CFA is the frame-pointer of the current function. This seemed the |
+ // most straightforward since (it seems) both the full-codegen and the |
+ // classic codegen maintain the frame-pointer. |
+ |
+ // -- The first state, just after the control has been transferred to the |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
Can you split this into four different functions f
|
+ // -- 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> |
+ (info_->begin_ + info_->state_offsets_ |
+ [UnwindInfoInterface::UNWIND_STATE_AFTER_RBP_PUSH]); |
+ |
+ // -- 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> |
+ (info_->begin_ + info_->state_offsets_ |
+ [UnwindInfoInterface::UNWIND_STATE_AFTER_RBP_SET]); |
+ |
+ // -- 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> |
+ (info_->begin_ + info_->state_offsets_ |
+ [UnwindInfoInterface::UNWIND_STATE_AFTER_RBP_POP]); |
+ |
+ // -- 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> |
+ (info_->begin_ + |
+ info_->state_offsets_[UnwindInfoInterface::UNWIND_STATE_AFTER_RETURN]); |
+ } else { |
+ // This is a code-stub. Unwind information for code-stubs is not divided |
+ // into stages, we just tell GDB to unwind using the frame pointer. |
+ w->Write<uintptr_t>(begin_); |
+ w->Write<uintptr_t>(length_); |
+ |
+ // The CFA is the current function's RBP |
+ w->Write<uint8_t>(DW_CFA_DEF_CFA); |
+ w->WriteULEB128(AMD64_RBP); |
+ w->WriteULEB128(0); |
+ |
+ // These assumptions are not true at the code-stub entry and exit. However, |
+ // we are assuming that the debugger will halt code-stubs only at their |
+ // call sites. |
+ w->Write<uint8_t>(DW_CFA_OFFSET_EXTENDED); |
+ w->WriteULEB128(AMD64_RA); |
+ w->WriteSLEB128(StandardFrameConstants::kCallerPCOffset); |
+ |
+ w->Write<uint8_t>(DW_CFA_OFFSET_EXTENDED); |
+ w->WriteULEB128(AMD64_RBP); |
+ w->WriteSLEB128(StandardFrameConstants::kCallerFPOffset); |
+ |
+ // The last location described by this entry. |
+ w->Write<uint8_t>(DW_CFA_SET_LOC); |
+ w->Write<uint64_t>(begin_ + length_); |
+ } |
+ |
+ if ((align = (w->position() - fde_position) % kPointerSize)) { |
Vyacheslav Egorov (Chromium)
2011/01/25 12:50:11
I think we usually avoid assignments in expression
|
+ for (uint32_t i = 0; i < (kPointerSize - align); i++) |
+ w->Write<uint8_t>(DW_CFA_NOP); |
+ } |
+ |
+ ASSERT((w->position() - fde_position) % kPointerSize == 0); |
+ fde_length_slot.set(w->position() - fde_position); |
+ |
+ return true; |
+} |
+ |
+ |
+UnwindInfoInterface::UnwindInformationList *UnwindInfoInterface::info_ = NULL; |
+ |
+ |
+static void SaveUnwindInfo(UnwindInfoSection *section) { |
+ ELF elf; |
+ elf.AddSection(section); |
+ Writer w(&elf); |
+ elf.Write(&w); |
+ JITCodeEntry *entry = CreateCodeEntry(w.buffer(), w.position()); |
+ RegisterCodeEntry(entry); |
+} |
+ |
+ |
+UnwindInfoInterface::~UnwindInfoInterface() { |
+ ASSERT(info_ != NULL); |
+ |
+ UnwindInfoSection unwind_section(&info_->data_); |
+ SaveUnwindInfo(&unwind_section); |
+ UnwindInformationList *tmp = info_->next_; |
+ delete info_; |
+ info_ = tmp; |
+} |
+ |
+ |
+void UnwindInfoInterface::SetCodeStub(uintptr_t b, uintptr_t l) { |
+ UnwindInfoSection unwind_section(b, l); |
+ SaveUnwindInfo(&unwind_section); |
+} |
+ |
+ |
+#endif // V8_TARGET_ARCH_X64 |
+ |
+ |
} } // namespace v8::internal |
#endif |