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>
184std::unique_ptr<UnwindPlan>
192 if (module_sp.get() ==
nullptr || module_sp->GetObjectFile() ==
nullptr ||
193 module_sp->GetObjectFile() != &
m_objfile)
196 std::vector<AddressRange> valid_ranges;
199 result->SetSourceName(
m_type ==
EH ?
"eh_frame CFI" :
"DWARF CFI");
205 result->SetUnwindPlanValidAtAllInstructions(
eLazyBoolNo);
212 std::optional<FDE> fde =
ParseFDE(entry->data, addr);
216 fde->range.GetBaseAddress().GetFileAddress() - addr.
GetFileAddress();
217 valid_ranges.push_back(std::move(fde->range));
218 if (fde->for_signal_trap)
220 result->SetReturnAddressRegister(fde->return_addr_reg_num);
223 result->AppendRow(std::move(row));
226 result->SetPlanValidAddressRanges(std::move(valid_ranges));
227 if (result->GetRowCount() == 0)
237 if (module_sp.get() ==
nullptr || module_sp->GetObjectFile() ==
nullptr ||
238 module_sp->GetObjectFile() != &
m_objfile)
254std::optional<DWARFCallFrameInfo::FDEEntryMap::Entry>
263 m_fde_index.FindEntryThatContainsOrFollows(start_file_addr);
275 function_info.
Clear();
278 for (
size_t i = 0; i < count; ++i) {
281 if (func_offset_data_entry) {
283 func_offset_data_entry->
base, func_offset_data_entry->
size);
284 function_info.
Append(function_offset_entry);
291 cie_map_t::iterator pos =
m_cie_map.find(cie_offset);
295 if (pos->second ==
nullptr)
298 return pos->second.get();
311 bool is_64bit = (length == llvm::dwarf::DW_LENGTH_DWARF64);
315 end_offset = cie_offset + length + 12;
318 end_offset = cie_offset + length + 4;
327 cie_sp->ptr_encoding = DW_EH_PE_absptr;
331 llvm::formatv(
"CIE parse error: CFI version {0} is not supported",
337 cie_sp->augmentation[i] =
m_cfi_data.GetU8(&offset);
338 if (cie_sp->augmentation[i] ==
'\0') {
341 cie_sp->augmentation[j] =
'\0';
350 "CIE parse error: CIE augmentation string was too large "
351 "for the fixed sized buffer of {0} bytes.",
359 cie_sp->address_size =
m_cfi_data.GetU8(&offset);
360 cie_sp->segment_size =
m_cfi_data.GetU8(&offset);
363 cie_sp->code_align = (uint32_t)
m_cfi_data.GetULEB128(&offset);
364 cie_sp->data_align = (int32_t)
m_cfi_data.GetSLEB128(&offset);
366 cie_sp->return_addr_reg_num =
368 ?
static_cast<uint32_t
>(
m_cfi_data.GetULEB128(&offset))
371 if (cie_sp->augmentation[0]) {
374 const size_t aug_data_len = (size_t)
m_cfi_data.GetULEB128(&offset);
375 const size_t aug_data_end = offset + aug_data_len;
376 const size_t aug_str_len = strlen(cie_sp->augmentation);
381 if (cie_sp->augmentation[0] ==
'z') {
383 size_t aug_str_idx = 0;
384 for (aug_str_idx = 1; aug_str_idx < aug_str_len; aug_str_idx++) {
385 char aug = cie_sp->augmentation[aug_str_idx];
395 cie_sp->lsda_addr_encoding =
m_cfi_data.GetU8(&offset);
411 uint8_t arg_ptr_encoding =
m_cfi_data.GetU8(&offset);
414 m_cfi_data, &offset, arg_ptr_encoding, pc_rel_addr,
425 cie_sp->ptr_encoding =
m_cfi_data.GetU8(&offset);
429 }
else if (strcmp(cie_sp->augmentation,
"eh") == 0) {
436 offset = (uint32_t)aug_data_end;
439 if (end_offset > offset) {
440 cie_sp->inst_offset = offset;
441 cie_sp->inst_length = end_offset - offset;
443 while (offset < end_offset) {
445 uint8_t primary_opcode = inst & 0xC0;
446 uint8_t extended_opcode = inst & 0x3F;
449 cie_sp->data_align, offset,
450 cie_sp->initial_row))
462 m_objfile.GetModule()->LogMessage(log,
"Reading EH frame info");
485 bool clear_address_zeroth_bit =
false;
487 if (arch.GetTriple().getArch() == llvm::Triple::arm ||
488 arch.GetTriple().getArch() == llvm::Triple::thumb)
489 clear_address_zeroth_bit =
true;
495 while (
m_cfi_data.ValidOffsetForDataOfSize(offset, 8)) {
499 bool is_64bit = (len == llvm::dwarf::DW_LENGTH_DWARF64);
503 next_entry = current_entry + len + 12;
504 cie_offset = current_entry + 12 - cie_id;
507 next_entry = current_entry + len + 4;
508 cie_offset = current_entry + 4 - cie_id;
511 if (next_entry >
m_cfi_data.GetByteSize() + 1) {
513 "of {0:x} found in cie/fde at {1:x}",
514 next_entry, current_entry));
524 auto cie_sp =
ParseCIE(current_entry);
532 m_cie_map[current_entry] = std::move(cie_sp);
542 "found in cie/fde at {1:x}",
543 cie_offset, current_entry));
559 text_addr, data_addr);
560 if (clear_address_zeroth_bit)
565 pc_rel_addr, text_addr, data_addr);
570 "unable to find CIE at {0:x} for cie_id = {1:x} for entry at {2:x}.",
571 cie_offset, cie_id, current_entry));
579std::optional<DWARFCallFrameInfo::FDE>
594 bool is_64bit = (length == llvm::dwarf::DW_LENGTH_DWARF64);
603 assert(!(
m_type ==
EH && 0 == cie_offset) &&
605 (is_64bit ? llvm::dwarf::DW64_CIE_ID : llvm::dwarf::DW_CIE_ID));
610 cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;
613 assert(cie !=
nullptr);
615 const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4);
622 text_addr, data_addr);
625 pc_rel_addr, text_addr, data_addr);
631 if (cie->augmentation[0] ==
'z')
632 offset += (uint32_t)
m_cfi_data.GetULEB128(&offset);
639 uint32_t code_align = cie->code_align;
640 int32_t data_align = cie->data_align;
643 std::vector<UnwindPlan::Row> stack;
646 while (
m_cfi_data.ValidOffset(offset) && offset < end_offset) {
648 uint8_t primary_opcode = inst & 0xC0;
649 uint8_t extended_opcode = inst & 0x3F;
653 if (primary_opcode) {
654 switch (primary_opcode) {
655 case DW_CFA_advance_loc:
662 fde.
rows.push_back(row);
667 case DW_CFA_restore: {
672 uint32_t reg_num = extended_opcode;
678 if (fde.
rows[0].GetRegisterInfo(reg_num, reg_location))
689 switch (extended_opcode) {
697 fde.
rows.push_back(row);
703 case DW_CFA_advance_loc1:
708 fde.
rows.push_back(row);
713 case DW_CFA_advance_loc2:
718 fde.
rows.push_back(row);
723 case DW_CFA_advance_loc4:
728 fde.
rows.push_back(row);
733 case DW_CFA_restore_extended:
738 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
739 if (fde.
rows[0].GetRegisterInfo(reg_num, reg_location))
744 case DW_CFA_remember_state:
753 stack.push_back(row);
757 case DW_CFA_restore_state:
768 "DWARFCallFrameInfo::{0}(dwarf_offset: "
769 "{1:x16}, startaddr: [{2:x16}] encountered "
770 "DW_CFA_restore_state but state stack "
771 "is empty. Corrupt unwind info?",
776 row = std::move(stack.back());
782 case DW_CFA_GNU_args_size:
794 case DW_CFA_val_offset: {
800 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
802 (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
807 case DW_CFA_val_offset_sf: {
813 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
815 (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
826 fde.
rows.push_back(row);
831 uint8_t extended_opcode,
837 if (primary_opcode) {
838 switch (primary_opcode) {
839 case DW_CFA_offset: {
846 uint8_t reg_num = extended_opcode;
847 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
854 switch (extended_opcode) {
858 case DW_CFA_offset_extended:
863 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
864 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset) * data_align;
871 case DW_CFA_undefined:
876 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
883 case DW_CFA_same_value:
888 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
895 case DW_CFA_register:
900 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
901 uint32_t other_reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
913 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
914 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset);
919 case DW_CFA_def_cfa_register:
924 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
930 case DW_CFA_def_cfa_offset:
935 int32_t op_offset = (int32_t)
m_cfi_data.GetULEB128(&offset);
941 case DW_CFA_def_cfa_expression:
943 size_t block_len = (size_t)
m_cfi_data.GetULEB128(&offset);
944 const uint8_t *block_data =
945 static_cast<const uint8_t *
>(
m_cfi_data.GetData(&offset, block_len));
950 case DW_CFA_expression:
959 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
960 uint32_t block_len = (uint32_t)
m_cfi_data.GetULEB128(&offset);
961 const uint8_t *block_data =
962 static_cast<const uint8_t *
>(
m_cfi_data.GetData(&offset, block_len));
969 case DW_CFA_offset_extended_sf:
975 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
976 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
983 case DW_CFA_def_cfa_sf:
989 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
990 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
995 case DW_CFA_def_cfa_offset_sf:
1000 int32_t op_offset = (int32_t)
m_cfi_data.GetSLEB128(&offset) * data_align;
1006 case DW_CFA_val_expression:
1015 uint32_t reg_num = (uint32_t)
m_cfi_data.GetULEB128(&offset);
1016 uint32_t block_len = (uint32_t)
m_cfi_data.GetULEB128(&offset);
1017 const uint8_t *block_data =
1018 (
const uint8_t *)
m_cfi_data.GetData(&offset, block_len);
1032 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