Chromium Code Reviews| 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 |