23#include "llvm/BinaryFormat/Dwarf.h"
31using namespace llvm::dwarf;
39 uint32_t eh_ptr_enc,
addr_t pc_rel_addr,
addr_t text_addr,
42 if (eh_ptr_enc == DW_EH_PE_omit)
45 uint64_t baseAddress = 0;
46 uint64_t addressValue = 0;
48 assert(addr_size == 4 || addr_size == 8);
50 bool signExtendValue =
false;
52 switch (eh_ptr_enc & 0x70) {
54 signExtendValue =
true;
55 baseAddress = *offset_ptr;
57 baseAddress += pc_rel_addr;
63 case DW_EH_PE_textrel:
64 signExtendValue =
true;
66 baseAddress = text_addr;
73 case DW_EH_PE_datarel:
74 signExtendValue =
true;
76 baseAddress = data_addr;
83 case DW_EH_PE_funcrel:
84 signExtendValue =
true;
87 case DW_EH_PE_aligned: {
90 assert(addr_size != 0);
93 uint32_t alignOffset = *offset_ptr % addr_size;
95 offset_ptr += addr_size - alignOffset;
105 case DW_EH_PE_absptr: {
111 case DW_EH_PE_uleb128:
114 case DW_EH_PE_udata2:
115 addressValue = DE.
GetU16(offset_ptr);
117 case DW_EH_PE_udata4:
118 addressValue = DE.
GetU32(offset_ptr);
120 case DW_EH_PE_udata8:
121 addressValue = DE.
GetU64(offset_ptr);
123 case DW_EH_PE_sleb128:
126 case DW_EH_PE_sdata2:
127 addressValue = (int16_t)DE.
GetU16(offset_ptr);
129 case DW_EH_PE_sdata4:
130 addressValue = (int32_t)DE.
GetU32(offset_ptr);
132 case DW_EH_PE_sdata8:
133 addressValue = (int64_t)DE.
GetU64(offset_ptr);
142 if (signExtendValue && addr_size <
sizeof(baseAddress)) {
143 uint64_t sign_bit = 1ull << ((addr_size * 8ull) - 1ull);
144 if (sign_bit & addressValue) {
145 uint64_t mask = ~sign_bit + 1;
146 addressValue |= mask;
149 return baseAddress + addressValue;
163 return cie_id == llvm::dwarf::DW64_CIE_ID;
166 return cie_id == llvm::dwarf::DW_CIE_ID;
173std::unique_ptr<UnwindPlan>
178std::unique_ptr<UnwindPlan>
186 if (module_sp.get() ==
nullptr || module_sp->GetObjectFile() ==
nullptr ||
187 module_sp->GetObjectFile() != &
m_objfile)
190 std::vector<AddressRange> valid_ranges;
193 result->SetSourceName(
m_type ==
EH ?
"eh_frame CFI" :
"DWARF CFI");
199 result->SetUnwindPlanValidAtAllInstructions(
eLazyBoolNo);
206 std::optional<FDE> fde =
ParseFDE(entry->data, addr);
210 fde->range.GetBaseAddress().GetFileAddress() - addr.
GetFileAddress();
211 valid_ranges.push_back(std::move(fde->range));
212 if (fde->for_signal_trap)
214 result->SetReturnAddressRegister(fde->return_addr_reg_num);
217 result->AppendRow(std::move(row));
220 result->SetPlanValidAddressRanges(std::move(valid_ranges));
221 if (result->GetRowCount() == 0)
231 if (module_sp.get() ==
nullptr || module_sp->GetObjectFile() ==
nullptr ||
232 module_sp->GetObjectFile() != &
m_objfile)
248std::optional<DWARFCallFrameInfo::FDEEntryMap::Entry>
257 m_fde_index.FindEntryThatContainsOrFollows(start_file_addr);
269 function_info.
Clear();
272 for (
size_t i = 0; i < count; ++i) {
275 if (func_offset_data_entry) {
277 func_offset_data_entry->
base, func_offset_data_entry->
size);
278 function_info.
Append(function_offset_entry);
285 cie_map_t::iterator pos =
m_cie_map.find(cie_offset);
289 if (pos->second ==
nullptr)
292 return pos->second.get();
305 bool is_64bit = (length == llvm::dwarf::DW_LENGTH_DWARF64);
309 end_offset = cie_offset + length + 12;
312 end_offset = cie_offset + length + 4;
321 cie_sp->ptr_encoding = DW_EH_PE_absptr;
325 llvm::formatv(
"CIE parse error: CFI version {0} is not supported",
331 cie_sp->augmentation[i] =
m_cfi_data.GetU8(&offset);
332 if (cie_sp->augmentation[i] ==
'\0') {
335 cie_sp->augmentation[j] =
'\0';
344 "CIE parse error: CIE augmentation string was too large "
345 "for the fixed sized buffer of {0} bytes.",
353 cie_sp->address_size =
m_cfi_data.GetU8(&offset);
354 cie_sp->segment_size =
m_cfi_data.GetU8(&offset);
357 cie_sp->code_align = (uint32_t)
m_cfi_data.GetULEB128(&offset);
358 cie_sp->data_align = (int32_t)
m_cfi_data.GetSLEB128(&offset);
360 cie_sp->return_addr_reg_num =
362 ?
static_cast<uint32_t
>(
m_cfi_data.GetULEB128(&offset))
365 if (cie_sp->augmentation[0]) {
368 const size_t aug_data_len = (size_t)
m_cfi_data.GetULEB128(&offset);
369 const size_t aug_data_end = offset + aug_data_len;
370 const size_t aug_str_len = strlen(cie_sp->augmentation);
375 if (cie_sp->augmentation[0] ==
'z') {
377 size_t aug_str_idx = 0;
378 for (aug_str_idx = 1; aug_str_idx < aug_str_len; aug_str_idx++) {
379 char aug = cie_sp->augmentation[aug_str_idx];
389 cie_sp->lsda_addr_encoding =
m_cfi_data.GetU8(&offset);
405 uint8_t arg_ptr_encoding =
m_cfi_data.GetU8(&offset);
408 m_cfi_data, &offset, arg_ptr_encoding, pc_rel_addr,
419 cie_sp->ptr_encoding =
m_cfi_data.GetU8(&offset);
423 }
else if (strcmp(cie_sp->augmentation,
"eh") == 0) {
430 offset = (uint32_t)aug_data_end;
433 if (end_offset > offset) {
434 cie_sp->inst_offset = offset;
435 cie_sp->inst_length = end_offset - offset;
437 while (offset < end_offset) {
439 uint8_t primary_opcode = inst & 0xC0;
440 uint8_t extended_opcode = inst & 0x3F;
443 cie_sp->data_align, offset,
444 cie_sp->initial_row))
456 m_objfile.GetModule()->LogMessage(log,
"Reading EH frame info");
479 bool clear_address_zeroth_bit =
false;
481 if (arch.GetTriple().getArch() == llvm::Triple::arm ||
482 arch.GetTriple().getArch() == llvm::Triple::thumb)
483 clear_address_zeroth_bit =
true;
489 while (
m_cfi_data.ValidOffsetForDataOfSize(offset, 8)) {
493 bool is_64bit = (len == llvm::dwarf::DW_LENGTH_DWARF64);
497 next_entry = current_entry + len + 12;
498 cie_offset = current_entry + 12 - cie_id;
501 next_entry = current_entry + len + 4;
502 cie_offset = current_entry + 4 - cie_id;
505 if (next_entry >
m_cfi_data.GetByteSize() + 1) {
507 "of {0:x} found in cie/fde at {1:x}",
508 next_entry, current_entry));
518 auto cie_sp =
ParseCIE(current_entry);
526 m_cie_map[current_entry] = std::move(cie_sp);
536 "found in cie/fde at {1:x}",
537 cie_offset, current_entry));
553 text_addr, data_addr);
554 if (clear_address_zeroth_bit)
559 pc_rel_addr, text_addr, data_addr);
564 "unable to find CIE at {0:x} for cie_id = {1:x} for entry at {2:x}.",
565 cie_offset, cie_id, current_entry));
573std::optional<DWARFCallFrameInfo::FDE>
588 bool is_64bit = (length == llvm::dwarf::DW_LENGTH_DWARF64);
597 assert(!(
m_type ==
EH && 0 == cie_offset) &&
599 (is_64bit ? llvm::dwarf::DW64_CIE_ID : llvm::dwarf::DW_CIE_ID));
604 cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;
607 assert(cie !=
nullptr);
609 const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4);
616 text_addr, data_addr);
619 pc_rel_addr, text_addr, data_addr);
625 if (cie->augmentation[0] ==
'z')
626 offset += (uint32_t)
m_cfi_data.GetULEB128(&offset);
633 uint32_t code_align = cie->code_align;
634 int32_t data_align = cie->data_align;
637 std::vector<UnwindPlan::Row> stack;
640 while (
m_cfi_data.ValidOffset(offset) && offset < end_offset) {
642 uint8_t primary_opcode = inst & 0xC0;
643 uint8_t extended_opcode = inst & 0x3F;
647 if (primary_opcode) {
648 switch (primary_opcode) {
649 case DW_CFA_advance_loc:
656 fde.
rows.push_back(row);
661 case DW_CFA_restore: {
666 uint32_t reg_num = extended_opcode;
672 if (fde.
rows[0].GetRegisterInfo(reg_num, reg_location))
683 switch (extended_opcode) {
691 fde.
rows.push_back(row);
697 case DW_CFA_advance_loc1:
702 fde.
rows.push_back(row);
707 case DW_CFA_advance_loc2:
712 fde.
rows.push_back(row);
717 case DW_CFA_advance_loc4:
722 fde.
rows.push_back(row);
727 case DW_CFA_restore_extended:
732 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
733 if (fde.
rows[0].GetRegisterInfo(reg_num, reg_location))
738 case DW_CFA_remember_state:
747 stack.push_back(row);
751 case DW_CFA_restore_state:
762 "DWARFCallFrameInfo::{0}(dwarf_offset: "
763 "{1:x16}, startaddr: [{2:x16}] encountered "
764 "DW_CFA_restore_state but state stack "
765 "is empty. Corrupt unwind info?",
770 row = std::move(stack.back());
776 case DW_CFA_GNU_args_size:
788 case DW_CFA_val_offset: {
794 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
796 (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
801 case DW_CFA_val_offset_sf: {
807 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
809 (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
820 fde.
rows.push_back(row);
825 uint8_t extended_opcode,
831 if (primary_opcode) {
832 switch (primary_opcode) {
833 case DW_CFA_offset: {
840 uint8_t reg_num = extended_opcode;
841 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
848 switch (extended_opcode) {
852 case DW_CFA_offset_extended:
857 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
858 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
865 case DW_CFA_undefined:
870 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
877 case DW_CFA_same_value:
882 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
889 case DW_CFA_register:
894 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
895 uint32_t other_reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
907 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
908 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset);
913 case DW_CFA_def_cfa_register:
918 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
924 case DW_CFA_def_cfa_offset:
929 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset);
935 case DW_CFA_def_cfa_expression:
937 size_t block_len = (size_t)
m_cfi_data.GetULEB128(&offset);
938 const uint8_t *block_data =
939 static_cast<const uint8_t *
>(
m_cfi_data.GetData(&offset, block_len));
944 case DW_CFA_expression:
953 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
954 uint32_t block_len = (uint32_t)
m_cfi_data.GetULEB128(&offset);
955 const uint8_t *block_data =
956 static_cast<const uint8_t *
>(
m_cfi_data.GetData(&offset, block_len));
963 case DW_CFA_offset_extended_sf:
969 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
970 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
977 case DW_CFA_def_cfa_sf:
983 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
984 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
989 case DW_CFA_def_cfa_offset_sf:
994 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
1000 case DW_CFA_val_expression:
1009 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
1010 uint32_t block_len = (uint32_t)
m_cfi_data.GetULEB128(&offset);
1011 const uint8_t *block_data =
1012 (
const uint8_t *)
m_cfi_data.GetData(&offset, block_len);
1026 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)
static bool IsCIEMarker(uint64_t cie_id, bool is_64bit, DWARFCallFrameInfo::Type type)
#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