1032 lines · cpp
1//===-- DWARFCallFrameInfo.cpp --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Symbol/DWARFCallFrameInfo.h"10#include "lldb/Core/Debugger.h"11#include "lldb/Core/Module.h"12#include "lldb/Core/Section.h"13#include "lldb/Core/dwarf.h"14#include "lldb/Host/Host.h"15#include "lldb/Symbol/ObjectFile.h"16#include "lldb/Symbol/UnwindPlan.h"17#include "lldb/Target/RegisterContext.h"18#include "lldb/Target/Thread.h"19#include "lldb/Utility/ArchSpec.h"20#include "lldb/Utility/LLDBLog.h"21#include "lldb/Utility/Log.h"22#include "lldb/Utility/Timer.h"23#include "llvm/BinaryFormat/Dwarf.h"24#include <cstdint>25#include <cstring>26#include <list>27#include <optional>28 29using namespace lldb;30using namespace lldb_private;31using namespace llvm::dwarf;32 33// GetDwarfEHPtr34//35// Used for calls when the value type is specified by a DWARF EH Frame pointer36// encoding.37static uint64_t38GetGNUEHPointer(const DataExtractor &DE, lldb::offset_t *offset_ptr,39 uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr,40 addr_t data_addr) //, BSDRelocs *data_relocs) const41{42 if (eh_ptr_enc == DW_EH_PE_omit)43 return ULLONG_MAX; // Value isn't in the buffer...44 45 uint64_t baseAddress = 0;46 uint64_t addressValue = 0;47 const uint32_t addr_size = DE.GetAddressByteSize();48 assert(addr_size == 4 || addr_size == 8);49 50 bool signExtendValue = false;51 // Decode the base part or adjust our offset52 switch (eh_ptr_enc & 0x70) {53 case DW_EH_PE_pcrel:54 signExtendValue = true;55 baseAddress = *offset_ptr;56 if (pc_rel_addr != LLDB_INVALID_ADDRESS)57 baseAddress += pc_rel_addr;58 // else59 // Log::GlobalWarning ("PC relative pointer encoding found with60 // invalid pc relative address.");61 break;62 63 case DW_EH_PE_textrel:64 signExtendValue = true;65 if (text_addr != LLDB_INVALID_ADDRESS)66 baseAddress = text_addr;67 // else68 // Log::GlobalWarning ("text relative pointer encoding being69 // decoded with invalid text section address, setting base address70 // to zero.");71 break;72 73 case DW_EH_PE_datarel:74 signExtendValue = true;75 if (data_addr != LLDB_INVALID_ADDRESS)76 baseAddress = data_addr;77 // else78 // Log::GlobalWarning ("data relative pointer encoding being79 // decoded with invalid data section address, setting base address80 // to zero.");81 break;82 83 case DW_EH_PE_funcrel:84 signExtendValue = true;85 break;86 87 case DW_EH_PE_aligned: {88 // SetPointerSize should be called prior to extracting these so the pointer89 // size is cached90 assert(addr_size != 0);91 if (addr_size) {92 // Align to a address size boundary first93 uint32_t alignOffset = *offset_ptr % addr_size;94 if (alignOffset)95 offset_ptr += addr_size - alignOffset;96 }97 } break;98 99 default:100 break;101 }102 103 // Decode the value part104 switch (eh_ptr_enc & DW_EH_PE_MASK_ENCODING) {105 case DW_EH_PE_absptr: {106 addressValue = DE.GetAddress(offset_ptr);107 // if (data_relocs)108 // addressValue = data_relocs->Relocate(*offset_ptr -109 // addr_size, *this, addressValue);110 } break;111 case DW_EH_PE_uleb128:112 addressValue = DE.GetULEB128(offset_ptr);113 break;114 case DW_EH_PE_udata2:115 addressValue = DE.GetU16(offset_ptr);116 break;117 case DW_EH_PE_udata4:118 addressValue = DE.GetU32(offset_ptr);119 break;120 case DW_EH_PE_udata8:121 addressValue = DE.GetU64(offset_ptr);122 break;123 case DW_EH_PE_sleb128:124 addressValue = DE.GetSLEB128(offset_ptr);125 break;126 case DW_EH_PE_sdata2:127 addressValue = (int16_t)DE.GetU16(offset_ptr);128 break;129 case DW_EH_PE_sdata4:130 addressValue = (int32_t)DE.GetU32(offset_ptr);131 break;132 case DW_EH_PE_sdata8:133 addressValue = (int64_t)DE.GetU64(offset_ptr);134 break;135 default:136 // Unhandled encoding type137 assert(eh_ptr_enc);138 break;139 }140 141 // Since we promote everything to 64 bit, we may need to sign extend142 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;147 }148 }149 return baseAddress + addressValue;150}151 152// Check if the given cie_id value indicates a CIE (Common Information Entry)153// as opposed to an FDE (Frame Description Entry).154static bool IsCIEMarker(uint64_t cie_id, bool is_64bit,155 DWARFCallFrameInfo::Type type) {156 // Check eh_frame CIE marker157 if (type == DWARFCallFrameInfo::EH)158 return cie_id == 0;159 160 // Check debug_frame CIE marker161 // DWARF64162 if (is_64bit)163 return cie_id == llvm::dwarf::DW64_CIE_ID;164 165 // DWARF32166 return cie_id == llvm::dwarf::DW_CIE_ID;167}168 169DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile &objfile,170 SectionSP §ion_sp, Type type)171 : m_objfile(objfile), m_section_sp(section_sp), m_type(type) {}172 173std::unique_ptr<UnwindPlan>174DWARFCallFrameInfo::GetUnwindPlan(const Address &addr) {175 return GetUnwindPlan({AddressRange(addr, 1)}, addr);176}177 178std::unique_ptr<UnwindPlan>179DWARFCallFrameInfo::GetUnwindPlan(llvm::ArrayRef<AddressRange> ranges,180 const Address &addr) {181 FDEEntryMap::Entry fde_entry;182 183 // Make sure that the Address we're searching for is the same object file as184 // this DWARFCallFrameInfo, we only store File offsets in m_fde_index.185 ModuleSP module_sp = addr.GetModule();186 if (module_sp.get() == nullptr || module_sp->GetObjectFile() == nullptr ||187 module_sp->GetObjectFile() != &m_objfile)188 return nullptr;189 190 std::vector<AddressRange> valid_ranges;191 192 auto result = std::make_unique<UnwindPlan>(GetRegisterKind());193 result->SetSourceName(m_type == EH ? "eh_frame CFI" : "DWARF CFI");194 // In theory the debug_frame info should be valid at all call sites195 // ("asynchronous unwind info" as it is sometimes called) but in practice196 // gcc et al all emit call frame info for the prologue and call sites, but197 // not for the epilogue or all the other locations during the function198 // reliably.199 result->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);200 result->SetSourcedFromCompiler(eLazyBoolYes);201 result->SetUnwindPlanForSignalTrap(eLazyBoolNo);202 for (const AddressRange &range : ranges) {203 std::optional<FDEEntryMap::Entry> entry = GetFirstFDEEntryInRange(range);204 if (!entry)205 continue;206 std::optional<FDE> fde = ParseFDE(entry->data, addr);207 if (!fde)208 continue;209 int64_t slide =210 fde->range.GetBaseAddress().GetFileAddress() - addr.GetFileAddress();211 valid_ranges.push_back(std::move(fde->range));212 if (fde->for_signal_trap)213 result->SetUnwindPlanForSignalTrap(eLazyBoolYes);214 result->SetReturnAddressRegister(fde->return_addr_reg_num);215 for (UnwindPlan::Row &row : fde->rows) {216 row.SlideOffset(slide);217 result->AppendRow(std::move(row));218 }219 }220 result->SetPlanValidAddressRanges(std::move(valid_ranges));221 if (result->GetRowCount() == 0)222 return nullptr;223 return result;224}225 226bool DWARFCallFrameInfo::GetAddressRange(Address addr, AddressRange &range) {227 228 // Make sure that the Address we're searching for is the same object file as229 // this DWARFCallFrameInfo, we only store File offsets in m_fde_index.230 ModuleSP module_sp = addr.GetModule();231 if (module_sp.get() == nullptr || module_sp->GetObjectFile() == nullptr ||232 module_sp->GetObjectFile() != &m_objfile)233 return false;234 235 if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())236 return false;237 GetFDEIndex();238 FDEEntryMap::Entry *fde_entry =239 m_fde_index.FindEntryThatContains(addr.GetFileAddress());240 if (!fde_entry)241 return false;242 243 range = AddressRange(fde_entry->base, fde_entry->size,244 m_objfile.GetSectionList());245 return true;246}247 248std::optional<DWARFCallFrameInfo::FDEEntryMap::Entry>249DWARFCallFrameInfo::GetFirstFDEEntryInRange(const AddressRange &range) {250 if (!m_section_sp || m_section_sp->IsEncrypted())251 return std::nullopt;252 253 GetFDEIndex();254 255 addr_t start_file_addr = range.GetBaseAddress().GetFileAddress();256 const FDEEntryMap::Entry *fde =257 m_fde_index.FindEntryThatContainsOrFollows(start_file_addr);258 if (fde && fde->DoesIntersect(259 FDEEntryMap::Range(start_file_addr, range.GetByteSize())))260 return *fde;261 262 return std::nullopt;263}264 265void DWARFCallFrameInfo::GetFunctionAddressAndSizeVector(266 FunctionAddressAndSizeVector &function_info) {267 GetFDEIndex();268 const size_t count = m_fde_index.GetSize();269 function_info.Clear();270 if (count > 0)271 function_info.Reserve(count);272 for (size_t i = 0; i < count; ++i) {273 const FDEEntryMap::Entry *func_offset_data_entry =274 m_fde_index.GetEntryAtIndex(i);275 if (func_offset_data_entry) {276 FunctionAddressAndSizeVector::Entry function_offset_entry(277 func_offset_data_entry->base, func_offset_data_entry->size);278 function_info.Append(function_offset_entry);279 }280 }281}282 283const DWARFCallFrameInfo::CIE *284DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset) {285 cie_map_t::iterator pos = m_cie_map.find(cie_offset);286 287 if (pos != m_cie_map.end()) {288 // Parse and cache the CIE289 if (pos->second == nullptr)290 pos->second = ParseCIE(cie_offset);291 292 return pos->second.get();293 }294 return nullptr;295}296 297DWARFCallFrameInfo::CIESP298DWARFCallFrameInfo::ParseCIE(const dw_offset_t cie_offset) {299 CIESP cie_sp(new CIE(cie_offset));300 lldb::offset_t offset = cie_offset;301 if (!m_cfi_data_initialized)302 GetCFIData();303 uint32_t length = m_cfi_data.GetU32(&offset);304 dw_offset_t cie_id, end_offset;305 bool is_64bit = (length == llvm::dwarf::DW_LENGTH_DWARF64);306 if (is_64bit) {307 length = m_cfi_data.GetU64(&offset);308 cie_id = m_cfi_data.GetU64(&offset);309 end_offset = cie_offset + length + 12;310 } else {311 cie_id = m_cfi_data.GetU32(&offset);312 end_offset = cie_offset + length + 4;313 }314 315 // Check if this is a CIE or FDE based on the CIE ID marker316 if (length > 0 && IsCIEMarker(cie_id, is_64bit, m_type)) {317 size_t i;318 // cie.offset = cie_offset;319 // cie.length = length;320 // cie.cieID = cieID;321 cie_sp->ptr_encoding = DW_EH_PE_absptr; // default322 cie_sp->version = m_cfi_data.GetU8(&offset);323 if (cie_sp->version > CFI_VERSION4) {324 Debugger::ReportError(325 llvm::formatv("CIE parse error: CFI version {0} is not supported",326 cie_sp->version));327 return nullptr;328 }329 330 for (i = 0; i < CFI_AUG_MAX_SIZE; ++i) {331 cie_sp->augmentation[i] = m_cfi_data.GetU8(&offset);332 if (cie_sp->augmentation[i] == '\0') {333 // Zero out remaining bytes in augmentation string334 for (size_t j = i + 1; j < CFI_AUG_MAX_SIZE; ++j)335 cie_sp->augmentation[j] = '\0';336 337 break;338 }339 }340 341 if (i == CFI_AUG_MAX_SIZE &&342 cie_sp->augmentation[CFI_AUG_MAX_SIZE - 1] != '\0') {343 Debugger::ReportError(llvm::formatv(344 "CIE parse error: CIE augmentation string was too large "345 "for the fixed sized buffer of {0} bytes.",346 CFI_AUG_MAX_SIZE));347 return nullptr;348 }349 350 // m_cfi_data uses address size from target architecture of the process may351 // ignore these fields?352 if (m_type == DWARF && cie_sp->version >= CFI_VERSION4) {353 cie_sp->address_size = m_cfi_data.GetU8(&offset);354 cie_sp->segment_size = m_cfi_data.GetU8(&offset);355 }356 357 cie_sp->code_align = (uint32_t)m_cfi_data.GetULEB128(&offset);358 cie_sp->data_align = (int32_t)m_cfi_data.GetSLEB128(&offset);359 360 cie_sp->return_addr_reg_num =361 m_type == DWARF && cie_sp->version >= CFI_VERSION3362 ? static_cast<uint32_t>(m_cfi_data.GetULEB128(&offset))363 : m_cfi_data.GetU8(&offset);364 365 if (cie_sp->augmentation[0]) {366 // Get the length of the eh_frame augmentation data which starts with a367 // ULEB128 length in bytes368 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);371 // A 'z' may be present as the first character of the string.372 // If present, the Augmentation Data field shall be present. The contents373 // of the Augmentation Data shall be interpreted according to other374 // characters in the Augmentation String.375 if (cie_sp->augmentation[0] == 'z') {376 // Extract the Augmentation Data377 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];380 switch (aug) {381 case 'L':382 // Indicates the presence of one argument in the Augmentation Data383 // of the CIE, and a corresponding argument in the Augmentation384 // Data of the FDE. The argument in the Augmentation Data of the385 // CIE is 1-byte and represents the pointer encoding used for the386 // argument in the Augmentation Data of the FDE, which is the387 // address of a language-specific data area (LSDA). The size of the388 // LSDA pointer is specified by the pointer encoding used.389 cie_sp->lsda_addr_encoding = m_cfi_data.GetU8(&offset);390 break;391 392 case 'P':393 // Indicates the presence of two arguments in the Augmentation Data394 // of the CIE. The first argument is 1-byte and represents the395 // pointer encoding used for the second argument, which is the396 // address of a personality routine handler. The size of the397 // personality routine pointer is specified by the pointer encoding398 // used.399 //400 // The address of the personality function will be stored at this401 // location. Pre-execution, it will be all zero's so don't read it402 // until we're trying to do an unwind & the reloc has been403 // resolved.404 {405 uint8_t arg_ptr_encoding = m_cfi_data.GetU8(&offset);406 const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();407 cie_sp->personality_loc = GetGNUEHPointer(408 m_cfi_data, &offset, arg_ptr_encoding, pc_rel_addr,409 LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS);410 }411 break;412 413 case 'R':414 // A 'R' may be present at any position after the415 // first character of the string. The Augmentation Data shall416 // include a 1 byte argument that represents the pointer encoding417 // for the address pointers used in the FDE. Example: 0x1B ==418 // DW_EH_PE_pcrel | DW_EH_PE_sdata4419 cie_sp->ptr_encoding = m_cfi_data.GetU8(&offset);420 break;421 }422 }423 } else if (strcmp(cie_sp->augmentation, "eh") == 0) {424 // If the Augmentation string has the value "eh", then the EH Data425 // field shall be present426 }427 428 // Set the offset to be the end of the augmentation data just in case we429 // didn't understand any of the data.430 offset = (uint32_t)aug_data_end;431 }432 433 if (end_offset > offset) {434 cie_sp->inst_offset = offset;435 cie_sp->inst_length = end_offset - offset;436 }437 while (offset < end_offset) {438 uint8_t inst = m_cfi_data.GetU8(&offset);439 uint8_t primary_opcode = inst & 0xC0;440 uint8_t extended_opcode = inst & 0x3F;441 442 if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode,443 cie_sp->data_align, offset,444 cie_sp->initial_row))445 break; // Stop if we hit an unrecognized opcode446 }447 }448 449 return cie_sp;450}451 452void DWARFCallFrameInfo::GetCFIData() {453 if (!m_cfi_data_initialized) {454 Log *log = GetLog(LLDBLog::Unwind);455 if (log)456 m_objfile.GetModule()->LogMessage(log, "Reading EH frame info");457 m_objfile.ReadSectionData(m_section_sp.get(), m_cfi_data);458 m_cfi_data_initialized = true;459 }460}461// Scan through the eh_frame or debug_frame section looking for FDEs and noting462// the start/end addresses of the functions and a pointer back to the463// function's FDE for later expansion. Internalize CIEs as we come across them.464 465void DWARFCallFrameInfo::GetFDEIndex() {466 if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())467 return;468 469 if (m_fde_index_initialized)470 return;471 472 std::lock_guard<std::mutex> guard(m_fde_index_mutex);473 474 if (m_fde_index_initialized) // if two threads hit the locker475 return;476 477 LLDB_SCOPED_TIMERF("%s", m_objfile.GetFileSpec().GetFilename().AsCString(""));478 479 bool clear_address_zeroth_bit = false;480 if (ArchSpec arch = m_objfile.GetArchitecture()) {481 if (arch.GetTriple().getArch() == llvm::Triple::arm ||482 arch.GetTriple().getArch() == llvm::Triple::thumb)483 clear_address_zeroth_bit = true;484 }485 486 lldb::offset_t offset = 0;487 if (!m_cfi_data_initialized)488 GetCFIData();489 while (m_cfi_data.ValidOffsetForDataOfSize(offset, 8)) {490 const dw_offset_t current_entry = offset;491 dw_offset_t cie_id, next_entry, cie_offset;492 uint32_t len = m_cfi_data.GetU32(&offset);493 bool is_64bit = (len == llvm::dwarf::DW_LENGTH_DWARF64);494 if (is_64bit) {495 len = m_cfi_data.GetU64(&offset);496 cie_id = m_cfi_data.GetU64(&offset);497 next_entry = current_entry + len + 12;498 cie_offset = current_entry + 12 - cie_id;499 } else {500 cie_id = m_cfi_data.GetU32(&offset);501 next_entry = current_entry + len + 4;502 cie_offset = current_entry + 4 - cie_id;503 }504 505 if (next_entry > m_cfi_data.GetByteSize() + 1) {506 Debugger::ReportError(llvm::formatv("Invalid fde/cie next entry offset "507 "of {0:x} found in cie/fde at {1:x}",508 next_entry, current_entry));509 // Don't trust anything in this eh_frame section if we find blatantly510 // invalid data.511 m_fde_index.Clear();512 m_fde_index_initialized = true;513 return;514 }515 516 // Check if this is a CIE or FDE based on the CIE ID marker517 if (IsCIEMarker(cie_id, is_64bit, m_type) || len == 0) {518 auto cie_sp = ParseCIE(current_entry);519 if (!cie_sp) {520 // Cannot parse, the reason is already logged521 m_fde_index.Clear();522 m_fde_index_initialized = true;523 return;524 }525 526 m_cie_map[current_entry] = std::move(cie_sp);527 offset = next_entry;528 continue;529 }530 531 if (m_type == DWARF)532 cie_offset = cie_id;533 534 if (cie_offset > m_cfi_data.GetByteSize()) {535 Debugger::ReportError(llvm::formatv("Invalid cie offset of {0:x} "536 "found in cie/fde at {1:x}",537 cie_offset, current_entry));538 // Don't trust anything in this eh_frame section if we find blatantly539 // invalid data.540 m_fde_index.Clear();541 m_fde_index_initialized = true;542 return;543 }544 545 const CIE *cie = GetCIE(cie_offset);546 if (cie) {547 const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();548 const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;549 const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;550 551 lldb::addr_t addr =552 GetGNUEHPointer(m_cfi_data, &offset, cie->ptr_encoding, pc_rel_addr,553 text_addr, data_addr);554 if (clear_address_zeroth_bit)555 addr &= ~1ull;556 557 lldb::addr_t length = GetGNUEHPointer(558 m_cfi_data, &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING,559 pc_rel_addr, text_addr, data_addr);560 FDEEntryMap::Entry fde(addr, length, current_entry);561 m_fde_index.Append(fde);562 } else {563 Debugger::ReportError(llvm::formatv(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));566 }567 offset = next_entry;568 }569 m_fde_index.Sort();570 m_fde_index_initialized = true;571}572 573std::optional<DWARFCallFrameInfo::FDE>574DWARFCallFrameInfo::ParseFDE(dw_offset_t dwarf_offset,575 const Address &startaddr) {576 Log *log = GetLog(LLDBLog::Unwind);577 lldb::offset_t offset = dwarf_offset;578 lldb::offset_t current_entry = offset;579 580 if (!m_section_sp || m_section_sp->IsEncrypted())581 return std::nullopt;582 583 if (!m_cfi_data_initialized)584 GetCFIData();585 586 uint32_t length = m_cfi_data.GetU32(&offset);587 dw_offset_t cie_offset;588 bool is_64bit = (length == llvm::dwarf::DW_LENGTH_DWARF64);589 if (is_64bit) {590 length = m_cfi_data.GetU64(&offset);591 cie_offset = m_cfi_data.GetU64(&offset);592 } else {593 cie_offset = m_cfi_data.GetU32(&offset);594 }595 596 // FDE entries with zeroth cie_offset may occur for debug_frame.597 assert(!(m_type == EH && 0 == cie_offset) &&598 cie_offset !=599 (is_64bit ? llvm::dwarf::DW64_CIE_ID : llvm::dwarf::DW_CIE_ID));600 601 // Translate the CIE_id from the eh_frame format, which is relative to the602 // FDE offset, into a __eh_frame section offset603 if (m_type == EH)604 cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;605 606 const CIE *cie = GetCIE(cie_offset);607 assert(cie != nullptr);608 609 const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4);610 611 const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();612 const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;613 const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;614 lldb::addr_t range_base =615 GetGNUEHPointer(m_cfi_data, &offset, cie->ptr_encoding, pc_rel_addr,616 text_addr, data_addr);617 lldb::addr_t range_len = GetGNUEHPointer(618 m_cfi_data, &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING,619 pc_rel_addr, text_addr, data_addr);620 AddressRange range(range_base, m_objfile.GetAddressByteSize(),621 m_objfile.GetSectionList());622 range.SetByteSize(range_len);623 624 // Skip the LSDA, if present.625 if (cie->augmentation[0] == 'z')626 offset += (uint32_t)m_cfi_data.GetULEB128(&offset);627 628 FDE fde;629 fde.for_signal_trap = strchr(cie->augmentation, 'S') != nullptr;630 fde.range = range;631 fde.return_addr_reg_num = cie->return_addr_reg_num;632 633 uint32_t code_align = cie->code_align;634 int32_t data_align = cie->data_align;635 636 UnwindPlan::Row row = cie->initial_row;637 std::vector<UnwindPlan::Row> stack;638 639 UnwindPlan::Row::AbstractRegisterLocation reg_location;640 while (m_cfi_data.ValidOffset(offset) && offset < end_offset) {641 uint8_t inst = m_cfi_data.GetU8(&offset);642 uint8_t primary_opcode = inst & 0xC0;643 uint8_t extended_opcode = inst & 0x3F;644 645 if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, data_align,646 offset, row)) {647 if (primary_opcode) {648 switch (primary_opcode) {649 case DW_CFA_advance_loc: // (Row Creation Instruction)650 { // 0x40 - high 2 bits are 0x1, lower 6 bits are delta651 // takes a single argument that represents a constant delta. The652 // required action is to create a new table row with a location value653 // that is computed by taking the current entry's location value and654 // adding (delta * code_align). All other values in the new row are655 // initially identical to the current row.656 fde.rows.push_back(row);657 row.SlideOffset(extended_opcode * code_align);658 break;659 }660 661 case DW_CFA_restore: { // 0xC0 - high 2 bits are 0x3, lower 6 bits are662 // register663 // takes a single argument that represents a register number. The664 // required action is to change the rule for the indicated register665 // to the rule assigned it by the initial_instructions in the CIE.666 uint32_t reg_num = extended_opcode;667 // We only keep enough register locations around to unwind what is in668 // our thread, and these are organized by the register index in that669 // state, so we need to convert our eh_frame register number from the670 // EH frame info, to a register index671 672 if (fde.rows[0].GetRegisterInfo(reg_num, reg_location))673 row.SetRegisterInfo(reg_num, reg_location);674 else {675 // If the register was not set in the first row, remove the676 // register info to keep the unmodified value from the caller.677 row.RemoveRegisterInfo(reg_num);678 }679 break;680 }681 }682 } else {683 switch (extended_opcode) {684 case DW_CFA_set_loc: // 0x1 (Row Creation Instruction)685 {686 // DW_CFA_set_loc takes a single argument that represents an address.687 // The required action is to create a new table row using the688 // specified address as the location. All other values in the new row689 // are initially identical to the current row. The new location value690 // should always be greater than the current one.691 fde.rows.push_back(row);692 row.SetOffset(m_cfi_data.GetAddress(&offset) -693 startaddr.GetFileAddress());694 break;695 }696 697 case DW_CFA_advance_loc1: // 0x2 (Row Creation Instruction)698 {699 // takes a single uword argument that represents a constant delta.700 // This instruction is identical to DW_CFA_advance_loc except for the701 // encoding and size of the delta argument.702 fde.rows.push_back(row);703 row.SlideOffset(m_cfi_data.GetU8(&offset) * code_align);704 break;705 }706 707 case DW_CFA_advance_loc2: // 0x3 (Row Creation Instruction)708 {709 // takes a single uword argument that represents a constant delta.710 // This instruction is identical to DW_CFA_advance_loc except for the711 // encoding and size of the delta argument.712 fde.rows.push_back(row);713 row.SlideOffset(m_cfi_data.GetU16(&offset) * code_align);714 break;715 }716 717 case DW_CFA_advance_loc4: // 0x4 (Row Creation Instruction)718 {719 // takes a single uword argument that represents a constant delta.720 // This instruction is identical to DW_CFA_advance_loc except for the721 // encoding and size of the delta argument.722 fde.rows.push_back(row);723 row.SlideOffset(m_cfi_data.GetU32(&offset) * code_align);724 break;725 }726 727 case DW_CFA_restore_extended: // 0x6728 {729 // takes a single unsigned LEB128 argument that represents a register730 // number. This instruction is identical to DW_CFA_restore except for731 // the encoding and size of the register argument.732 uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);733 if (fde.rows[0].GetRegisterInfo(reg_num, reg_location))734 row.SetRegisterInfo(reg_num, reg_location);735 break;736 }737 738 case DW_CFA_remember_state: // 0xA739 {740 // These instructions define a stack of information. Encountering the741 // DW_CFA_remember_state instruction means to save the rules for742 // every register on the current row on the stack. Encountering the743 // DW_CFA_restore_state instruction means to pop the set of rules off744 // the stack and place them in the current row. (This operation is745 // useful for compilers that move epilogue code into the body of a746 // function.)747 stack.push_back(row);748 break;749 }750 751 case DW_CFA_restore_state: // 0xB752 {753 // These instructions define a stack of information. Encountering the754 // DW_CFA_remember_state instruction means to save the rules for755 // every register on the current row on the stack. Encountering the756 // DW_CFA_restore_state instruction means to pop the set of rules off757 // the stack and place them in the current row. (This operation is758 // useful for compilers that move epilogue code into the body of a759 // function.)760 if (stack.empty()) {761 LLDB_LOG(log,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?",766 __FUNCTION__, dwarf_offset, startaddr.GetFileAddress());767 break;768 }769 int64_t offset = row.GetOffset();770 row = std::move(stack.back());771 stack.pop_back();772 row.SetOffset(offset);773 break;774 }775 776 case DW_CFA_GNU_args_size: // 0x2e777 {778 // The DW_CFA_GNU_args_size instruction takes an unsigned LEB128779 // operand representing an argument size. This instruction specifies780 // the total of the size of the arguments which have been pushed onto781 // the stack.782 783 // TODO: Figure out how we should handle this.784 m_cfi_data.GetULEB128(&offset);785 break;786 }787 788 case DW_CFA_val_offset: { // 0x14789 // takes two unsigned LEB128 operands representing a register number790 // and a factored offset. The required action is to change the rule791 // for the register indicated by the register number to be a792 // val_offset(N) rule where the value of N is factored_offset*793 // data_alignment_factor794 uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);795 int32_t op_offset =796 (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;797 reg_location.SetIsCFAPlusOffset(op_offset);798 row.SetRegisterInfo(reg_num, reg_location);799 break;800 }801 case DW_CFA_val_offset_sf: { // 0x15802 // takes two operands: an unsigned LEB128 value representing a803 // register number and a signed LEB128 factored offset. This804 // instruction is identical to DW_CFA_val_offset except that the805 // second operand is signed and factored. The resulting offset is806 // factored_offset* data_alignment_factor.807 uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);808 int32_t op_offset =809 (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;810 reg_location.SetIsCFAPlusOffset(op_offset);811 row.SetRegisterInfo(reg_num, reg_location);812 break;813 }814 default:815 break;816 }817 }818 }819 }820 fde.rows.push_back(row);821 return fde;822}823 824bool DWARFCallFrameInfo::HandleCommonDwarfOpcode(uint8_t primary_opcode,825 uint8_t extended_opcode,826 int32_t data_align,827 lldb::offset_t &offset,828 UnwindPlan::Row &row) {829 UnwindPlan::Row::AbstractRegisterLocation reg_location;830 831 if (primary_opcode) {832 switch (primary_opcode) {833 case DW_CFA_offset: { // 0x80 - high 2 bits are 0x2, lower 6 bits are834 // register835 // takes two arguments: an unsigned LEB128 constant representing a836 // factored offset and a register number. The required action is to837 // change the rule for the register indicated by the register number to838 // be an offset(N) rule with a value of (N = factored offset *839 // data_align).840 uint8_t reg_num = extended_opcode;841 int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;842 reg_location.SetAtCFAPlusOffset(op_offset);843 row.SetRegisterInfo(reg_num, reg_location);844 return true;845 }846 }847 } else {848 switch (extended_opcode) {849 case DW_CFA_nop: // 0x0850 return true;851 852 case DW_CFA_offset_extended: // 0x5853 {854 // takes two unsigned LEB128 arguments representing a register number and855 // a factored offset. This instruction is identical to DW_CFA_offset856 // except for the encoding and size of the register argument.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;859 UnwindPlan::Row::AbstractRegisterLocation reg_location;860 reg_location.SetAtCFAPlusOffset(op_offset);861 row.SetRegisterInfo(reg_num, reg_location);862 return true;863 }864 865 case DW_CFA_undefined: // 0x7866 {867 // takes a single unsigned LEB128 argument that represents a register868 // number. The required action is to set the rule for the specified869 // register to undefined.870 uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);871 UnwindPlan::Row::AbstractRegisterLocation reg_location;872 reg_location.SetUndefined();873 row.SetRegisterInfo(reg_num, reg_location);874 return true;875 }876 877 case DW_CFA_same_value: // 0x8878 {879 // takes a single unsigned LEB128 argument that represents a register880 // number. The required action is to set the rule for the specified881 // register to same value.882 uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);883 UnwindPlan::Row::AbstractRegisterLocation reg_location;884 reg_location.SetSame();885 row.SetRegisterInfo(reg_num, reg_location);886 return true;887 }888 889 case DW_CFA_register: // 0x9890 {891 // takes two unsigned LEB128 arguments representing register numbers. The892 // required action is to set the rule for the first register to be the893 // second 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);896 UnwindPlan::Row::AbstractRegisterLocation reg_location;897 reg_location.SetInRegister(other_reg_num);898 row.SetRegisterInfo(reg_num, reg_location);899 return true;900 }901 902 case DW_CFA_def_cfa: // 0xC (CFA Definition Instruction)903 {904 // Takes two unsigned LEB128 operands representing a register number and905 // a (non-factored) offset. The required action is to define the current906 // CFA rule to use the provided register and 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);909 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num, op_offset);910 return true;911 }912 913 case DW_CFA_def_cfa_register: // 0xD (CFA Definition Instruction)914 {915 // takes a single unsigned LEB128 argument representing a register916 // number. The required action is to define the current CFA rule to use917 // the provided register (but to keep the old offset).918 uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);919 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num,920 row.GetCFAValue().GetOffset());921 return true;922 }923 924 case DW_CFA_def_cfa_offset: // 0xE (CFA Definition Instruction)925 {926 // Takes a single unsigned LEB128 operand representing a (non-factored)927 // offset. The required action is to define the current CFA rule to use928 // the provided offset (but to keep the old register).929 int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);930 row.GetCFAValue().SetIsRegisterPlusOffset(931 row.GetCFAValue().GetRegisterNumber(), op_offset);932 return true;933 }934 935 case DW_CFA_def_cfa_expression: // 0xF (CFA Definition Instruction)936 {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));940 row.GetCFAValue().SetIsDWARFExpression(block_data, block_len);941 return true;942 }943 944 case DW_CFA_expression: // 0x10945 {946 // Takes two operands: an unsigned LEB128 value representing a register947 // number, and a DW_FORM_block value representing a DWARF expression. The948 // required action is to change the rule for the register indicated by949 // the register number to be an expression(E) rule where E is the DWARF950 // expression. That is, the DWARF expression computes the address. The951 // value of the CFA is pushed on the DWARF evaluation stack prior to952 // execution of the DWARF 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));957 UnwindPlan::Row::AbstractRegisterLocation reg_location;958 reg_location.SetAtDWARFExpression(block_data, block_len);959 row.SetRegisterInfo(reg_num, reg_location);960 return true;961 }962 963 case DW_CFA_offset_extended_sf: // 0x11964 {965 // takes two operands: an unsigned LEB128 value representing a register966 // number and a signed LEB128 factored offset. This instruction is967 // identical to DW_CFA_offset_extended except that the second operand is968 // signed and factored.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;971 UnwindPlan::Row::AbstractRegisterLocation reg_location;972 reg_location.SetAtCFAPlusOffset(op_offset);973 row.SetRegisterInfo(reg_num, reg_location);974 return true;975 }976 977 case DW_CFA_def_cfa_sf: // 0x12 (CFA Definition Instruction)978 {979 // Takes two operands: an unsigned LEB128 value representing a register980 // number and a signed LEB128 factored offset. This instruction is981 // identical to DW_CFA_def_cfa except that the second operand is signed982 // and factored.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;985 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num, op_offset);986 return true;987 }988 989 case DW_CFA_def_cfa_offset_sf: // 0x13 (CFA Definition Instruction)990 {991 // takes a signed LEB128 operand representing a factored offset. This992 // instruction is identical to DW_CFA_def_cfa_offset except that the993 // operand is signed and factored.994 int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;995 uint32_t cfa_regnum = row.GetCFAValue().GetRegisterNumber();996 row.GetCFAValue().SetIsRegisterPlusOffset(cfa_regnum, op_offset);997 return true;998 }999 1000 case DW_CFA_val_expression: // 0x161001 {1002 // takes two operands: an unsigned LEB128 value representing a register1003 // number, and a DW_FORM_block value representing a DWARF expression. The1004 // required action is to change the rule for the register indicated by1005 // the register number to be a val_expression(E) rule where E is the1006 // DWARF expression. That is, the DWARF expression computes the value of1007 // the given register. The value of the CFA is pushed on the DWARF1008 // evaluation stack prior to execution of the DWARF 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);1013 reg_location.SetIsDWARFExpression(block_data, block_len);1014 row.SetRegisterInfo(reg_num, reg_location);1015 return true;1016 }1017 }1018 }1019 return false;1020}1021 1022void DWARFCallFrameInfo::ForEachFDEEntries(1023 const std::function<bool(lldb::addr_t, uint32_t, dw_offset_t)> &callback) {1024 GetFDEIndex();1025 1026 for (size_t i = 0, c = m_fde_index.GetSize(); i < c; ++i) {1027 const FDEEntryMap::Entry &entry = m_fde_index.GetEntryRef(i);1028 if (!callback(entry.base, entry.size, entry.data))1029 break;1030 }1031}1032