29using namespace llvm::dwarf;
37 uint32_t eh_ptr_enc,
addr_t pc_rel_addr,
addr_t text_addr,
40 if (eh_ptr_enc == DW_EH_PE_omit)
43 uint64_t baseAddress = 0;
44 uint64_t addressValue = 0;
46 assert(addr_size == 4 || addr_size == 8);
48 bool signExtendValue =
false;
50 switch (eh_ptr_enc & 0x70) {
52 signExtendValue =
true;
53 baseAddress = *offset_ptr;
55 baseAddress += pc_rel_addr;
61 case DW_EH_PE_textrel:
62 signExtendValue =
true;
64 baseAddress = text_addr;
71 case DW_EH_PE_datarel:
72 signExtendValue =
true;
74 baseAddress = data_addr;
81 case DW_EH_PE_funcrel:
82 signExtendValue =
true;
85 case DW_EH_PE_aligned: {
88 assert(addr_size != 0);
91 uint32_t alignOffset = *offset_ptr % addr_size;
93 offset_ptr += addr_size - alignOffset;
103 case DW_EH_PE_absptr: {
109 case DW_EH_PE_uleb128:
112 case DW_EH_PE_udata2:
113 addressValue = DE.
GetU16(offset_ptr);
115 case DW_EH_PE_udata4:
116 addressValue = DE.
GetU32(offset_ptr);
118 case DW_EH_PE_udata8:
119 addressValue = DE.
GetU64(offset_ptr);
121 case DW_EH_PE_sleb128:
124 case DW_EH_PE_sdata2:
125 addressValue = (int16_t)DE.
GetU16(offset_ptr);
127 case DW_EH_PE_sdata4:
128 addressValue = (int32_t)DE.
GetU32(offset_ptr);
130 case DW_EH_PE_sdata8:
131 addressValue = (int64_t)DE.
GetU64(offset_ptr);
140 if (signExtendValue && addr_size <
sizeof(baseAddress)) {
141 uint64_t sign_bit = 1ull << ((addr_size * 8ull) - 1ull);
142 if (sign_bit & addressValue) {
143 uint64_t mask = ~sign_bit + 1;
144 addressValue |= mask;
147 return baseAddress + addressValue;
154std::unique_ptr<UnwindPlan>
159std::unique_ptr<UnwindPlan>
167 if (module_sp.get() ==
nullptr || module_sp->GetObjectFile() ==
nullptr ||
168 module_sp->GetObjectFile() != &
m_objfile)
171 std::vector<AddressRange> valid_ranges;
174 result->SetSourceName(
m_type ==
EH ?
"eh_frame CFI" :
"DWARF CFI");
180 result->SetUnwindPlanValidAtAllInstructions(
eLazyBoolNo);
187 std::optional<FDE> fde =
ParseFDE(entry->data, addr);
191 fde->range.GetBaseAddress().GetFileAddress() - addr.
GetFileAddress();
192 valid_ranges.push_back(std::move(fde->range));
193 if (fde->for_signal_trap)
195 result->SetReturnAddressRegister(fde->return_addr_reg_num);
198 result->AppendRow(std::move(row));
201 result->SetPlanValidAddressRanges(std::move(valid_ranges));
202 if (result->GetRowCount() == 0)
212 if (module_sp.get() ==
nullptr || module_sp->GetObjectFile() ==
nullptr ||
213 module_sp->GetObjectFile() != &
m_objfile)
229std::optional<DWARFCallFrameInfo::FDEEntryMap::Entry>
238 m_fde_index.FindEntryThatContainsOrFollows(start_file_addr);
250 function_info.
Clear();
253 for (
size_t i = 0; i < count; ++i) {
256 if (func_offset_data_entry) {
258 func_offset_data_entry->
base, func_offset_data_entry->
size);
259 function_info.
Append(function_offset_entry);
266 cie_map_t::iterator pos =
m_cie_map.find(cie_offset);
270 if (pos->second ==
nullptr)
273 return pos->second.get();
290 end_offset = cie_offset + length + 12;
293 end_offset = cie_offset + length + 4;
301 cie_sp->ptr_encoding = DW_EH_PE_absptr;
305 llvm::formatv(
"CIE parse error: CFI version {0} is not supported",
311 cie_sp->augmentation[i] =
m_cfi_data.GetU8(&offset);
312 if (cie_sp->augmentation[i] ==
'\0') {
315 cie_sp->augmentation[j] =
'\0';
324 "CIE parse error: CIE augmentation string was too large "
325 "for the fixed sized buffer of {0} bytes.",
333 cie_sp->address_size =
m_cfi_data.GetU8(&offset);
334 cie_sp->segment_size =
m_cfi_data.GetU8(&offset);
337 cie_sp->code_align = (uint32_t)
m_cfi_data.GetULEB128(&offset);
338 cie_sp->data_align = (int32_t)
m_cfi_data.GetSLEB128(&offset);
340 cie_sp->return_addr_reg_num =
342 ?
static_cast<uint32_t
>(
m_cfi_data.GetULEB128(&offset))
345 if (cie_sp->augmentation[0]) {
348 const size_t aug_data_len = (size_t)
m_cfi_data.GetULEB128(&offset);
349 const size_t aug_data_end = offset + aug_data_len;
350 const size_t aug_str_len = strlen(cie_sp->augmentation);
355 if (cie_sp->augmentation[0] ==
'z') {
357 size_t aug_str_idx = 0;
358 for (aug_str_idx = 1; aug_str_idx < aug_str_len; aug_str_idx++) {
359 char aug = cie_sp->augmentation[aug_str_idx];
369 cie_sp->lsda_addr_encoding =
m_cfi_data.GetU8(&offset);
385 uint8_t arg_ptr_encoding =
m_cfi_data.GetU8(&offset);
388 m_cfi_data, &offset, arg_ptr_encoding, pc_rel_addr,
399 cie_sp->ptr_encoding =
m_cfi_data.GetU8(&offset);
403 }
else if (strcmp(cie_sp->augmentation,
"eh") == 0) {
410 offset = (uint32_t)aug_data_end;
413 if (end_offset > offset) {
414 cie_sp->inst_offset = offset;
415 cie_sp->inst_length = end_offset - offset;
417 while (offset < end_offset) {
419 uint8_t primary_opcode = inst & 0xC0;
420 uint8_t extended_opcode = inst & 0x3F;
423 cie_sp->data_align, offset,
424 cie_sp->initial_row))
436 m_objfile.GetModule()->LogMessage(log,
"Reading EH frame info");
459 bool clear_address_zeroth_bit =
false;
461 if (arch.GetTriple().getArch() == llvm::Triple::arm ||
462 arch.GetTriple().getArch() == llvm::Triple::thumb)
463 clear_address_zeroth_bit =
true;
469 while (
m_cfi_data.ValidOffsetForDataOfSize(offset, 8)) {
477 next_entry = current_entry + len + 12;
478 cie_offset = current_entry + 12 - cie_id;
481 next_entry = current_entry + len + 4;
482 cie_offset = current_entry + 4 - cie_id;
485 if (next_entry >
m_cfi_data.GetByteSize() + 1) {
487 "of {0:x} found in cie/fde at {1:x}",
488 next_entry, current_entry));
501 auto cie_sp =
ParseCIE(current_entry);
509 m_cie_map[current_entry] = std::move(cie_sp);
519 "found in cie/fde at {1:x}",
520 cie_offset, current_entry));
536 text_addr, data_addr);
537 if (clear_address_zeroth_bit)
542 pc_rel_addr, text_addr, data_addr);
547 "unable to find CIE at {0:x} for cie_id = {1:x} for entry at {2:x}.",
548 cie_offset, cie_id, current_entry));
556std::optional<DWARFCallFrameInfo::FDE>
585 cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;
588 assert(cie !=
nullptr);
590 const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4);
597 text_addr, data_addr);
600 pc_rel_addr, text_addr, data_addr);
606 if (cie->augmentation[0] ==
'z')
607 offset += (uint32_t)
m_cfi_data.GetULEB128(&offset);
614 uint32_t code_align = cie->code_align;
615 int32_t data_align = cie->data_align;
618 std::vector<UnwindPlan::Row> stack;
621 while (
m_cfi_data.ValidOffset(offset) && offset < end_offset) {
623 uint8_t primary_opcode = inst & 0xC0;
624 uint8_t extended_opcode = inst & 0x3F;
628 if (primary_opcode) {
629 switch (primary_opcode) {
630 case DW_CFA_advance_loc:
637 fde.
rows.push_back(row);
642 case DW_CFA_restore: {
647 uint32_t reg_num = extended_opcode;
653 if (fde.
rows[0].GetRegisterInfo(reg_num, reg_location))
664 switch (extended_opcode) {
672 fde.
rows.push_back(row);
678 case DW_CFA_advance_loc1:
683 fde.
rows.push_back(row);
688 case DW_CFA_advance_loc2:
693 fde.
rows.push_back(row);
698 case DW_CFA_advance_loc4:
703 fde.
rows.push_back(row);
708 case DW_CFA_restore_extended:
713 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
714 if (fde.
rows[0].GetRegisterInfo(reg_num, reg_location))
719 case DW_CFA_remember_state:
728 stack.push_back(row);
732 case DW_CFA_restore_state:
743 "DWARFCallFrameInfo::{0}(dwarf_offset: "
744 "{1:x16}, startaddr: [{2:x16}] encountered "
745 "DW_CFA_restore_state but state stack "
746 "is empty. Corrupt unwind info?",
751 row = std::move(stack.back());
757 case DW_CFA_GNU_args_size:
769 case DW_CFA_val_offset: {
775 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
777 (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
782 case DW_CFA_val_offset_sf: {
788 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
790 (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
801 fde.
rows.push_back(row);
806 uint8_t extended_opcode,
812 if (primary_opcode) {
813 switch (primary_opcode) {
814 case DW_CFA_offset: {
821 uint8_t reg_num = extended_opcode;
822 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
829 switch (extended_opcode) {
833 case DW_CFA_offset_extended:
838 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
839 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
846 case DW_CFA_undefined:
851 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
858 case DW_CFA_same_value:
863 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
870 case DW_CFA_register:
875 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
876 uint32_t other_reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
888 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
889 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset);
894 case DW_CFA_def_cfa_register:
899 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
905 case DW_CFA_def_cfa_offset:
910 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset);
916 case DW_CFA_def_cfa_expression:
918 size_t block_len = (size_t)
m_cfi_data.GetULEB128(&offset);
919 const uint8_t *block_data =
920 static_cast<const uint8_t *
>(
m_cfi_data.GetData(&offset, block_len));
925 case DW_CFA_expression:
934 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
935 uint32_t block_len = (uint32_t)
m_cfi_data.GetULEB128(&offset);
936 const uint8_t *block_data =
937 static_cast<const uint8_t *
>(
m_cfi_data.GetData(&offset, block_len));
944 case DW_CFA_offset_extended_sf:
950 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
951 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
958 case DW_CFA_def_cfa_sf:
964 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
965 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
970 case DW_CFA_def_cfa_offset_sf:
975 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
981 case DW_CFA_val_expression:
990 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
991 uint32_t block_len = (uint32_t)
m_cfi_data.GetULEB128(&offset);
992 const uint8_t *block_data =
993 (
const uint8_t *)
m_cfi_data.GetData(&offset, block_len);
1007 for (
size_t i = 0, c =
m_fde_index.GetSize(); i < c; ++i) {
static uint64_t GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t *offset_ptr, uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr, addr_t data_addr)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_SCOPED_TIMERF(...)
A section + offset based address range class.
Address & GetBaseAddress()
Get accessor for the base address of the range.
void SetByteSize(lldb::addr_t byte_size)
Set accessor for the byte size of this range.
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
A section + offset based address class.
lldb::ModuleSP GetModule() const
Get accessor for the module for this address.
lldb::addr_t GetFileAddress() const
Get the file address.
An architecture specification class.
bool m_fde_index_initialized
lldb::RegisterKind GetRegisterKind() const
std::shared_ptr< CIE > CIESP
CIESP ParseCIE(const dw_offset_t cie_offset)
void GetFunctionAddressAndSizeVector(FunctionAddressAndSizeVector &function_info)
std::optional< FDEEntryMap::Entry > GetFirstFDEEntryInRange(const AddressRange &range)
lldb::SectionSP m_section_sp
void ForEachFDEEntries(const std::function< bool(lldb::addr_t, uint32_t, dw_offset_t)> &callback)
const CIE * GetCIE(dw_offset_t cie_offset)
std::mutex m_fde_index_mutex
bool GetAddressRange(Address addr, AddressRange &range)
DWARFCallFrameInfo(ObjectFile &objfile, lldb::SectionSP §ion, Type type)
RangeVector< lldb::addr_t, uint32_t > FunctionAddressAndSizeVector
std::unique_ptr< UnwindPlan > GetUnwindPlan(const Address &addr)
Return an UnwindPlan based on the call frame information encoded in the FDE of this DWARFCallFrameInf...
bool m_cfi_data_initialized
std::optional< FDE > ParseFDE(dw_offset_t offset, const Address &startaddr)
bool HandleCommonDwarfOpcode(uint8_t primary_opcode, uint8_t extended_opcode, int32_t data_align, lldb::offset_t &offset, UnwindPlan::Row &row)
static void ReportError(std::string message, std::optional< lldb::user_id_t > debugger_id=std::nullopt, std::once_flag *once=nullptr)
Report error events.
A plug-in interface definition class for object file parsers.
RangeData< lldb::addr_t, uint32_t, dw_offset_t > Entry
lldb_private::Range< lldb::addr_t, uint32_t > Range
void Append(const Entry &entry)
Range< lldb::addr_t, uint32_t > Entry
void Reserve(typename Collection::size_type size)
void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len)
void SetAtCFAPlusOffset(int32_t offset)
void SetInRegister(uint32_t reg_num)
void SetIsCFAPlusOffset(int32_t offset)
void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len)
void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len)
int32_t GetOffset() const
void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset)
uint32_t GetRegisterNumber() const
void SlideOffset(int64_t offset)
void SetOffset(int64_t offset)
int64_t GetOffset() const
const FAValue & GetCFAValue() const
void RemoveRegisterInfo(uint32_t reg_num)
void SetRegisterInfo(uint32_t reg_num, const AbstractRegisterLocation register_location)
#define DW_EH_PE_MASK_ENCODING
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::Section > SectionSP
std::shared_ptr< lldb_private::Module > ModuleSP
Parsed representation of a Frame Descriptor Entry.
uint32_t return_addr_reg_num
std::vector< UnwindPlan::Row > rows
bool DoesIntersect(const Range &rhs) const