Path: blob/main/contrib/llvm-project/lldb/source/Symbol/DWARFCallFrameInfo.cpp
39587 views
//===-- DWARFCallFrameInfo.cpp --------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Symbol/DWARFCallFrameInfo.h"9#include "lldb/Core/Debugger.h"10#include "lldb/Core/Module.h"11#include "lldb/Core/Section.h"12#include "lldb/Core/dwarf.h"13#include "lldb/Host/Host.h"14#include "lldb/Symbol/ObjectFile.h"15#include "lldb/Symbol/UnwindPlan.h"16#include "lldb/Target/RegisterContext.h"17#include "lldb/Target/Thread.h"18#include "lldb/Utility/ArchSpec.h"19#include "lldb/Utility/LLDBLog.h"20#include "lldb/Utility/Log.h"21#include "lldb/Utility/Timer.h"22#include <cstring>23#include <list>24#include <optional>2526using namespace lldb;27using namespace lldb_private;28using namespace lldb_private::dwarf;2930// GetDwarfEHPtr31//32// Used for calls when the value type is specified by a DWARF EH Frame pointer33// encoding.34static uint64_t35GetGNUEHPointer(const DataExtractor &DE, offset_t *offset_ptr,36uint32_t eh_ptr_enc, addr_t pc_rel_addr, addr_t text_addr,37addr_t data_addr) //, BSDRelocs *data_relocs) const38{39if (eh_ptr_enc == DW_EH_PE_omit)40return ULLONG_MAX; // Value isn't in the buffer...4142uint64_t baseAddress = 0;43uint64_t addressValue = 0;44const uint32_t addr_size = DE.GetAddressByteSize();45assert(addr_size == 4 || addr_size == 8);4647bool signExtendValue = false;48// Decode the base part or adjust our offset49switch (eh_ptr_enc & 0x70) {50case DW_EH_PE_pcrel:51signExtendValue = true;52baseAddress = *offset_ptr;53if (pc_rel_addr != LLDB_INVALID_ADDRESS)54baseAddress += pc_rel_addr;55// else56// Log::GlobalWarning ("PC relative pointer encoding found with57// invalid pc relative address.");58break;5960case DW_EH_PE_textrel:61signExtendValue = true;62if (text_addr != LLDB_INVALID_ADDRESS)63baseAddress = text_addr;64// else65// Log::GlobalWarning ("text relative pointer encoding being66// decoded with invalid text section address, setting base address67// to zero.");68break;6970case DW_EH_PE_datarel:71signExtendValue = true;72if (data_addr != LLDB_INVALID_ADDRESS)73baseAddress = data_addr;74// else75// Log::GlobalWarning ("data relative pointer encoding being76// decoded with invalid data section address, setting base address77// to zero.");78break;7980case DW_EH_PE_funcrel:81signExtendValue = true;82break;8384case DW_EH_PE_aligned: {85// SetPointerSize should be called prior to extracting these so the pointer86// size is cached87assert(addr_size != 0);88if (addr_size) {89// Align to a address size boundary first90uint32_t alignOffset = *offset_ptr % addr_size;91if (alignOffset)92offset_ptr += addr_size - alignOffset;93}94} break;9596default:97break;98}99100// Decode the value part101switch (eh_ptr_enc & DW_EH_PE_MASK_ENCODING) {102case DW_EH_PE_absptr: {103addressValue = DE.GetAddress(offset_ptr);104// if (data_relocs)105// addressValue = data_relocs->Relocate(*offset_ptr -106// addr_size, *this, addressValue);107} break;108case DW_EH_PE_uleb128:109addressValue = DE.GetULEB128(offset_ptr);110break;111case DW_EH_PE_udata2:112addressValue = DE.GetU16(offset_ptr);113break;114case DW_EH_PE_udata4:115addressValue = DE.GetU32(offset_ptr);116break;117case DW_EH_PE_udata8:118addressValue = DE.GetU64(offset_ptr);119break;120case DW_EH_PE_sleb128:121addressValue = DE.GetSLEB128(offset_ptr);122break;123case DW_EH_PE_sdata2:124addressValue = (int16_t)DE.GetU16(offset_ptr);125break;126case DW_EH_PE_sdata4:127addressValue = (int32_t)DE.GetU32(offset_ptr);128break;129case DW_EH_PE_sdata8:130addressValue = (int64_t)DE.GetU64(offset_ptr);131break;132default:133// Unhandled encoding type134assert(eh_ptr_enc);135break;136}137138// Since we promote everything to 64 bit, we may need to sign extend139if (signExtendValue && addr_size < sizeof(baseAddress)) {140uint64_t sign_bit = 1ull << ((addr_size * 8ull) - 1ull);141if (sign_bit & addressValue) {142uint64_t mask = ~sign_bit + 1;143addressValue |= mask;144}145}146return baseAddress + addressValue;147}148149DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile &objfile,150SectionSP §ion_sp, Type type)151: m_objfile(objfile), m_section_sp(section_sp), m_type(type) {}152153bool DWARFCallFrameInfo::GetUnwindPlan(const Address &addr,154UnwindPlan &unwind_plan) {155return GetUnwindPlan(AddressRange(addr, 1), unwind_plan);156}157158bool DWARFCallFrameInfo::GetUnwindPlan(const AddressRange &range,159UnwindPlan &unwind_plan) {160FDEEntryMap::Entry fde_entry;161Address addr = range.GetBaseAddress();162163// Make sure that the Address we're searching for is the same object file as164// this DWARFCallFrameInfo, we only store File offsets in m_fde_index.165ModuleSP module_sp = addr.GetModule();166if (module_sp.get() == nullptr || module_sp->GetObjectFile() == nullptr ||167module_sp->GetObjectFile() != &m_objfile)168return false;169170if (std::optional<FDEEntryMap::Entry> entry = GetFirstFDEEntryInRange(range))171return FDEToUnwindPlan(entry->data, addr, unwind_plan);172return false;173}174175bool DWARFCallFrameInfo::GetAddressRange(Address addr, AddressRange &range) {176177// Make sure that the Address we're searching for is the same object file as178// this DWARFCallFrameInfo, we only store File offsets in m_fde_index.179ModuleSP module_sp = addr.GetModule();180if (module_sp.get() == nullptr || module_sp->GetObjectFile() == nullptr ||181module_sp->GetObjectFile() != &m_objfile)182return false;183184if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())185return false;186GetFDEIndex();187FDEEntryMap::Entry *fde_entry =188m_fde_index.FindEntryThatContains(addr.GetFileAddress());189if (!fde_entry)190return false;191192range = AddressRange(fde_entry->base, fde_entry->size,193m_objfile.GetSectionList());194return true;195}196197std::optional<DWARFCallFrameInfo::FDEEntryMap::Entry>198DWARFCallFrameInfo::GetFirstFDEEntryInRange(const AddressRange &range) {199if (!m_section_sp || m_section_sp->IsEncrypted())200return std::nullopt;201202GetFDEIndex();203204addr_t start_file_addr = range.GetBaseAddress().GetFileAddress();205const FDEEntryMap::Entry *fde =206m_fde_index.FindEntryThatContainsOrFollows(start_file_addr);207if (fde && fde->DoesIntersect(208FDEEntryMap::Range(start_file_addr, range.GetByteSize())))209return *fde;210211return std::nullopt;212}213214void DWARFCallFrameInfo::GetFunctionAddressAndSizeVector(215FunctionAddressAndSizeVector &function_info) {216GetFDEIndex();217const size_t count = m_fde_index.GetSize();218function_info.Clear();219if (count > 0)220function_info.Reserve(count);221for (size_t i = 0; i < count; ++i) {222const FDEEntryMap::Entry *func_offset_data_entry =223m_fde_index.GetEntryAtIndex(i);224if (func_offset_data_entry) {225FunctionAddressAndSizeVector::Entry function_offset_entry(226func_offset_data_entry->base, func_offset_data_entry->size);227function_info.Append(function_offset_entry);228}229}230}231232const DWARFCallFrameInfo::CIE *233DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset) {234cie_map_t::iterator pos = m_cie_map.find(cie_offset);235236if (pos != m_cie_map.end()) {237// Parse and cache the CIE238if (pos->second == nullptr)239pos->second = ParseCIE(cie_offset);240241return pos->second.get();242}243return nullptr;244}245246DWARFCallFrameInfo::CIESP247DWARFCallFrameInfo::ParseCIE(const dw_offset_t cie_offset) {248CIESP cie_sp(new CIE(cie_offset));249lldb::offset_t offset = cie_offset;250if (!m_cfi_data_initialized)251GetCFIData();252uint32_t length = m_cfi_data.GetU32(&offset);253dw_offset_t cie_id, end_offset;254bool is_64bit = (length == UINT32_MAX);255if (is_64bit) {256length = m_cfi_data.GetU64(&offset);257cie_id = m_cfi_data.GetU64(&offset);258end_offset = cie_offset + length + 12;259} else {260cie_id = m_cfi_data.GetU32(&offset);261end_offset = cie_offset + length + 4;262}263if (length > 0 && ((m_type == DWARF && cie_id == UINT32_MAX) ||264(m_type == EH && cie_id == 0ul))) {265size_t i;266// cie.offset = cie_offset;267// cie.length = length;268// cie.cieID = cieID;269cie_sp->ptr_encoding = DW_EH_PE_absptr; // default270cie_sp->version = m_cfi_data.GetU8(&offset);271if (cie_sp->version > CFI_VERSION4) {272Debugger::ReportError(273llvm::formatv("CIE parse error: CFI version {0} is not supported",274cie_sp->version));275return nullptr;276}277278for (i = 0; i < CFI_AUG_MAX_SIZE; ++i) {279cie_sp->augmentation[i] = m_cfi_data.GetU8(&offset);280if (cie_sp->augmentation[i] == '\0') {281// Zero out remaining bytes in augmentation string282for (size_t j = i + 1; j < CFI_AUG_MAX_SIZE; ++j)283cie_sp->augmentation[j] = '\0';284285break;286}287}288289if (i == CFI_AUG_MAX_SIZE &&290cie_sp->augmentation[CFI_AUG_MAX_SIZE - 1] != '\0') {291Debugger::ReportError(llvm::formatv(292"CIE parse error: CIE augmentation string was too large "293"for the fixed sized buffer of {0} bytes.",294CFI_AUG_MAX_SIZE));295return nullptr;296}297298// m_cfi_data uses address size from target architecture of the process may299// ignore these fields?300if (m_type == DWARF && cie_sp->version >= CFI_VERSION4) {301cie_sp->address_size = m_cfi_data.GetU8(&offset);302cie_sp->segment_size = m_cfi_data.GetU8(&offset);303}304305cie_sp->code_align = (uint32_t)m_cfi_data.GetULEB128(&offset);306cie_sp->data_align = (int32_t)m_cfi_data.GetSLEB128(&offset);307308cie_sp->return_addr_reg_num =309m_type == DWARF && cie_sp->version >= CFI_VERSION3310? static_cast<uint32_t>(m_cfi_data.GetULEB128(&offset))311: m_cfi_data.GetU8(&offset);312313if (cie_sp->augmentation[0]) {314// Get the length of the eh_frame augmentation data which starts with a315// ULEB128 length in bytes316const size_t aug_data_len = (size_t)m_cfi_data.GetULEB128(&offset);317const size_t aug_data_end = offset + aug_data_len;318const size_t aug_str_len = strlen(cie_sp->augmentation);319// A 'z' may be present as the first character of the string.320// If present, the Augmentation Data field shall be present. The contents321// of the Augmentation Data shall be interpreted according to other322// characters in the Augmentation String.323if (cie_sp->augmentation[0] == 'z') {324// Extract the Augmentation Data325size_t aug_str_idx = 0;326for (aug_str_idx = 1; aug_str_idx < aug_str_len; aug_str_idx++) {327char aug = cie_sp->augmentation[aug_str_idx];328switch (aug) {329case 'L':330// Indicates the presence of one argument in the Augmentation Data331// of the CIE, and a corresponding argument in the Augmentation332// Data of the FDE. The argument in the Augmentation Data of the333// CIE is 1-byte and represents the pointer encoding used for the334// argument in the Augmentation Data of the FDE, which is the335// address of a language-specific data area (LSDA). The size of the336// LSDA pointer is specified by the pointer encoding used.337cie_sp->lsda_addr_encoding = m_cfi_data.GetU8(&offset);338break;339340case 'P':341// Indicates the presence of two arguments in the Augmentation Data342// of the CIE. The first argument is 1-byte and represents the343// pointer encoding used for the second argument, which is the344// address of a personality routine handler. The size of the345// personality routine pointer is specified by the pointer encoding346// used.347//348// The address of the personality function will be stored at this349// location. Pre-execution, it will be all zero's so don't read it350// until we're trying to do an unwind & the reloc has been351// resolved.352{353uint8_t arg_ptr_encoding = m_cfi_data.GetU8(&offset);354const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();355cie_sp->personality_loc = GetGNUEHPointer(356m_cfi_data, &offset, arg_ptr_encoding, pc_rel_addr,357LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS);358}359break;360361case 'R':362// A 'R' may be present at any position after the363// first character of the string. The Augmentation Data shall364// include a 1 byte argument that represents the pointer encoding365// for the address pointers used in the FDE. Example: 0x1B ==366// DW_EH_PE_pcrel | DW_EH_PE_sdata4367cie_sp->ptr_encoding = m_cfi_data.GetU8(&offset);368break;369}370}371} else if (strcmp(cie_sp->augmentation, "eh") == 0) {372// If the Augmentation string has the value "eh", then the EH Data373// field shall be present374}375376// Set the offset to be the end of the augmentation data just in case we377// didn't understand any of the data.378offset = (uint32_t)aug_data_end;379}380381if (end_offset > offset) {382cie_sp->inst_offset = offset;383cie_sp->inst_length = end_offset - offset;384}385while (offset < end_offset) {386uint8_t inst = m_cfi_data.GetU8(&offset);387uint8_t primary_opcode = inst & 0xC0;388uint8_t extended_opcode = inst & 0x3F;389390if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode,391cie_sp->data_align, offset,392cie_sp->initial_row))393break; // Stop if we hit an unrecognized opcode394}395}396397return cie_sp;398}399400void DWARFCallFrameInfo::GetCFIData() {401if (!m_cfi_data_initialized) {402Log *log = GetLog(LLDBLog::Unwind);403if (log)404m_objfile.GetModule()->LogMessage(log, "Reading EH frame info");405m_objfile.ReadSectionData(m_section_sp.get(), m_cfi_data);406m_cfi_data_initialized = true;407}408}409// Scan through the eh_frame or debug_frame section looking for FDEs and noting410// the start/end addresses of the functions and a pointer back to the411// function's FDE for later expansion. Internalize CIEs as we come across them.412413void DWARFCallFrameInfo::GetFDEIndex() {414if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())415return;416417if (m_fde_index_initialized)418return;419420std::lock_guard<std::mutex> guard(m_fde_index_mutex);421422if (m_fde_index_initialized) // if two threads hit the locker423return;424425LLDB_SCOPED_TIMERF("%s", m_objfile.GetFileSpec().GetFilename().AsCString(""));426427bool clear_address_zeroth_bit = false;428if (ArchSpec arch = m_objfile.GetArchitecture()) {429if (arch.GetTriple().getArch() == llvm::Triple::arm ||430arch.GetTriple().getArch() == llvm::Triple::thumb)431clear_address_zeroth_bit = true;432}433434lldb::offset_t offset = 0;435if (!m_cfi_data_initialized)436GetCFIData();437while (m_cfi_data.ValidOffsetForDataOfSize(offset, 8)) {438const dw_offset_t current_entry = offset;439dw_offset_t cie_id, next_entry, cie_offset;440uint32_t len = m_cfi_data.GetU32(&offset);441bool is_64bit = (len == UINT32_MAX);442if (is_64bit) {443len = m_cfi_data.GetU64(&offset);444cie_id = m_cfi_data.GetU64(&offset);445next_entry = current_entry + len + 12;446cie_offset = current_entry + 12 - cie_id;447} else {448cie_id = m_cfi_data.GetU32(&offset);449next_entry = current_entry + len + 4;450cie_offset = current_entry + 4 - cie_id;451}452453if (next_entry > m_cfi_data.GetByteSize() + 1) {454Debugger::ReportError(llvm::formatv("Invalid fde/cie next entry offset "455"of {0:x} found in cie/fde at {1:x}",456next_entry, current_entry));457// Don't trust anything in this eh_frame section if we find blatantly458// invalid data.459m_fde_index.Clear();460m_fde_index_initialized = true;461return;462}463464// An FDE entry contains CIE_pointer in debug_frame in same place as cie_id465// in eh_frame. CIE_pointer is an offset into the .debug_frame section. So,466// variable cie_offset should be equal to cie_id for debug_frame.467// FDE entries with cie_id == 0 shouldn't be ignored for it.468if ((cie_id == 0 && m_type == EH) || cie_id == UINT32_MAX || len == 0) {469auto cie_sp = ParseCIE(current_entry);470if (!cie_sp) {471// Cannot parse, the reason is already logged472m_fde_index.Clear();473m_fde_index_initialized = true;474return;475}476477m_cie_map[current_entry] = std::move(cie_sp);478offset = next_entry;479continue;480}481482if (m_type == DWARF)483cie_offset = cie_id;484485if (cie_offset > m_cfi_data.GetByteSize()) {486Debugger::ReportError(llvm::formatv("Invalid cie offset of {0:x} "487"found in cie/fde at {1:x}",488cie_offset, current_entry));489// Don't trust anything in this eh_frame section if we find blatantly490// invalid data.491m_fde_index.Clear();492m_fde_index_initialized = true;493return;494}495496const CIE *cie = GetCIE(cie_offset);497if (cie) {498const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();499const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;500const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;501502lldb::addr_t addr =503GetGNUEHPointer(m_cfi_data, &offset, cie->ptr_encoding, pc_rel_addr,504text_addr, data_addr);505if (clear_address_zeroth_bit)506addr &= ~1ull;507508lldb::addr_t length = GetGNUEHPointer(509m_cfi_data, &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING,510pc_rel_addr, text_addr, data_addr);511FDEEntryMap::Entry fde(addr, length, current_entry);512m_fde_index.Append(fde);513} else {514Debugger::ReportError(llvm::formatv(515"unable to find CIE at {0:x} for cie_id = {1:x} for entry at {2:x}.",516cie_offset, cie_id, current_entry));517}518offset = next_entry;519}520m_fde_index.Sort();521m_fde_index_initialized = true;522}523524bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,525Address startaddr,526UnwindPlan &unwind_plan) {527Log *log = GetLog(LLDBLog::Unwind);528lldb::offset_t offset = dwarf_offset;529lldb::offset_t current_entry = offset;530531if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())532return false;533534if (!m_cfi_data_initialized)535GetCFIData();536537uint32_t length = m_cfi_data.GetU32(&offset);538dw_offset_t cie_offset;539bool is_64bit = (length == UINT32_MAX);540if (is_64bit) {541length = m_cfi_data.GetU64(&offset);542cie_offset = m_cfi_data.GetU64(&offset);543} else {544cie_offset = m_cfi_data.GetU32(&offset);545}546547// FDE entries with zeroth cie_offset may occur for debug_frame.548assert(!(m_type == EH && 0 == cie_offset) && cie_offset != UINT32_MAX);549550// Translate the CIE_id from the eh_frame format, which is relative to the551// FDE offset, into a __eh_frame section offset552if (m_type == EH) {553unwind_plan.SetSourceName("eh_frame CFI");554cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;555unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);556} else {557unwind_plan.SetSourceName("DWARF CFI");558// In theory the debug_frame info should be valid at all call sites559// ("asynchronous unwind info" as it is sometimes called) but in practice560// gcc et al all emit call frame info for the prologue and call sites, but561// not for the epilogue or all the other locations during the function562// reliably.563unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);564}565unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);566567const CIE *cie = GetCIE(cie_offset);568assert(cie != nullptr);569570const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4);571572const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();573const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;574const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;575lldb::addr_t range_base =576GetGNUEHPointer(m_cfi_data, &offset, cie->ptr_encoding, pc_rel_addr,577text_addr, data_addr);578lldb::addr_t range_len = GetGNUEHPointer(579m_cfi_data, &offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING,580pc_rel_addr, text_addr, data_addr);581AddressRange range(range_base, m_objfile.GetAddressByteSize(),582m_objfile.GetSectionList());583range.SetByteSize(range_len);584585addr_t lsda_data_file_address = LLDB_INVALID_ADDRESS;586587if (cie->augmentation[0] == 'z') {588uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);589if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) {590offset_t saved_offset = offset;591lsda_data_file_address =592GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding,593pc_rel_addr, text_addr, data_addr);594if (offset - saved_offset != aug_data_len) {595// There is more in the augmentation region than we know how to process;596// don't read anything.597lsda_data_file_address = LLDB_INVALID_ADDRESS;598}599offset = saved_offset;600}601offset += aug_data_len;602}603unwind_plan.SetUnwindPlanForSignalTrap(604strchr(cie->augmentation, 'S') ? eLazyBoolYes : eLazyBoolNo);605606Address lsda_data;607Address personality_function_ptr;608609if (lsda_data_file_address != LLDB_INVALID_ADDRESS &&610cie->personality_loc != LLDB_INVALID_ADDRESS) {611m_objfile.GetModule()->ResolveFileAddress(lsda_data_file_address,612lsda_data);613m_objfile.GetModule()->ResolveFileAddress(cie->personality_loc,614personality_function_ptr);615}616617if (lsda_data.IsValid() && personality_function_ptr.IsValid()) {618unwind_plan.SetLSDAAddress(lsda_data);619unwind_plan.SetPersonalityFunctionPtr(personality_function_ptr);620}621622uint32_t code_align = cie->code_align;623int32_t data_align = cie->data_align;624625unwind_plan.SetPlanValidAddressRange(range);626UnwindPlan::Row *cie_initial_row = new UnwindPlan::Row;627*cie_initial_row = cie->initial_row;628UnwindPlan::RowSP row(cie_initial_row);629630unwind_plan.SetRegisterKind(GetRegisterKind());631unwind_plan.SetReturnAddressRegister(cie->return_addr_reg_num);632633std::vector<UnwindPlan::RowSP> stack;634635UnwindPlan::Row::RegisterLocation reg_location;636while (m_cfi_data.ValidOffset(offset) && offset < end_offset) {637uint8_t inst = m_cfi_data.GetU8(&offset);638uint8_t primary_opcode = inst & 0xC0;639uint8_t extended_opcode = inst & 0x3F;640641if (!HandleCommonDwarfOpcode(primary_opcode, extended_opcode, data_align,642offset, *row)) {643if (primary_opcode) {644switch (primary_opcode) {645case DW_CFA_advance_loc: // (Row Creation Instruction)646{ // 0x40 - high 2 bits are 0x1, lower 6 bits are delta647// takes a single argument that represents a constant delta. The648// required action is to create a new table row with a location value649// that is computed by taking the current entry's location value and650// adding (delta * code_align). All other values in the new row are651// initially identical to the current row.652unwind_plan.AppendRow(row);653UnwindPlan::Row *newrow = new UnwindPlan::Row;654*newrow = *row.get();655row.reset(newrow);656row->SlideOffset(extended_opcode * code_align);657break;658}659660case DW_CFA_restore: { // 0xC0 - high 2 bits are 0x3, lower 6 bits are661// register662// takes a single argument that represents a register number. The663// required action is to change the rule for the indicated register664// to the rule assigned it by the initial_instructions in the CIE.665uint32_t reg_num = extended_opcode;666// We only keep enough register locations around to unwind what is in667// our thread, and these are organized by the register index in that668// state, so we need to convert our eh_frame register number from the669// EH frame info, to a register index670671if (unwind_plan.IsValidRowIndex(0) &&672unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,673reg_location))674row->SetRegisterInfo(reg_num, reg_location);675else {676// If the register was not set in the first row, remove the677// register info to keep the unmodified value from the caller.678row->RemoveRegisterInfo(reg_num);679}680break;681}682}683} else {684switch (extended_opcode) {685case DW_CFA_set_loc: // 0x1 (Row Creation Instruction)686{687// DW_CFA_set_loc takes a single argument that represents an address.688// The required action is to create a new table row using the689// specified address as the location. All other values in the new row690// are initially identical to the current row. The new location value691// should always be greater than the current one.692unwind_plan.AppendRow(row);693UnwindPlan::Row *newrow = new UnwindPlan::Row;694*newrow = *row.get();695row.reset(newrow);696row->SetOffset(m_cfi_data.GetAddress(&offset) -697startaddr.GetFileAddress());698break;699}700701case DW_CFA_advance_loc1: // 0x2 (Row Creation Instruction)702{703// takes a single uword argument that represents a constant delta.704// This instruction is identical to DW_CFA_advance_loc except for the705// encoding and size of the delta argument.706unwind_plan.AppendRow(row);707UnwindPlan::Row *newrow = new UnwindPlan::Row;708*newrow = *row.get();709row.reset(newrow);710row->SlideOffset(m_cfi_data.GetU8(&offset) * code_align);711break;712}713714case DW_CFA_advance_loc2: // 0x3 (Row Creation Instruction)715{716// takes a single uword argument that represents a constant delta.717// This instruction is identical to DW_CFA_advance_loc except for the718// encoding and size of the delta argument.719unwind_plan.AppendRow(row);720UnwindPlan::Row *newrow = new UnwindPlan::Row;721*newrow = *row.get();722row.reset(newrow);723row->SlideOffset(m_cfi_data.GetU16(&offset) * code_align);724break;725}726727case DW_CFA_advance_loc4: // 0x4 (Row Creation Instruction)728{729// takes a single uword argument that represents a constant delta.730// This instruction is identical to DW_CFA_advance_loc except for the731// encoding and size of the delta argument.732unwind_plan.AppendRow(row);733UnwindPlan::Row *newrow = new UnwindPlan::Row;734*newrow = *row.get();735row.reset(newrow);736row->SlideOffset(m_cfi_data.GetU32(&offset) * code_align);737break;738}739740case DW_CFA_restore_extended: // 0x6741{742// takes a single unsigned LEB128 argument that represents a register743// number. This instruction is identical to DW_CFA_restore except for744// the encoding and size of the register argument.745uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);746if (unwind_plan.IsValidRowIndex(0) &&747unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,748reg_location))749row->SetRegisterInfo(reg_num, reg_location);750break;751}752753case DW_CFA_remember_state: // 0xA754{755// These instructions define a stack of information. Encountering the756// DW_CFA_remember_state instruction means to save the rules for757// every register on the current row on the stack. Encountering the758// DW_CFA_restore_state instruction means to pop the set of rules off759// the stack and place them in the current row. (This operation is760// useful for compilers that move epilogue code into the body of a761// function.)762stack.push_back(row);763UnwindPlan::Row *newrow = new UnwindPlan::Row;764*newrow = *row.get();765row.reset(newrow);766break;767}768769case DW_CFA_restore_state: // 0xB770{771// These instructions define a stack of information. Encountering the772// DW_CFA_remember_state instruction means to save the rules for773// every register on the current row on the stack. Encountering the774// DW_CFA_restore_state instruction means to pop the set of rules off775// the stack and place them in the current row. (This operation is776// useful for compilers that move epilogue code into the body of a777// function.)778if (stack.empty()) {779LLDB_LOG(log,780"DWARFCallFrameInfo::{0}(dwarf_offset: "781"{1:x16}, startaddr: [{2:x16}] encountered "782"DW_CFA_restore_state but state stack "783"is empty. Corrupt unwind info?",784__FUNCTION__, dwarf_offset, startaddr.GetFileAddress());785break;786}787lldb::addr_t offset = row->GetOffset();788row = stack.back();789stack.pop_back();790row->SetOffset(offset);791break;792}793794case DW_CFA_GNU_args_size: // 0x2e795{796// The DW_CFA_GNU_args_size instruction takes an unsigned LEB128797// operand representing an argument size. This instruction specifies798// the total of the size of the arguments which have been pushed onto799// the stack.800801// TODO: Figure out how we should handle this.802m_cfi_data.GetULEB128(&offset);803break;804}805806case DW_CFA_val_offset: // 0x14807case DW_CFA_val_offset_sf: // 0x15808default:809break;810}811}812}813}814unwind_plan.AppendRow(row);815816return true;817}818819bool DWARFCallFrameInfo::HandleCommonDwarfOpcode(uint8_t primary_opcode,820uint8_t extended_opcode,821int32_t data_align,822lldb::offset_t &offset,823UnwindPlan::Row &row) {824UnwindPlan::Row::RegisterLocation reg_location;825826if (primary_opcode) {827switch (primary_opcode) {828case DW_CFA_offset: { // 0x80 - high 2 bits are 0x2, lower 6 bits are829// register830// takes two arguments: an unsigned LEB128 constant representing a831// factored offset and a register number. The required action is to832// change the rule for the register indicated by the register number to833// be an offset(N) rule with a value of (N = factored offset *834// data_align).835uint8_t reg_num = extended_opcode;836int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;837reg_location.SetAtCFAPlusOffset(op_offset);838row.SetRegisterInfo(reg_num, reg_location);839return true;840}841}842} else {843switch (extended_opcode) {844case DW_CFA_nop: // 0x0845return true;846847case DW_CFA_offset_extended: // 0x5848{849// takes two unsigned LEB128 arguments representing a register number and850// a factored offset. This instruction is identical to DW_CFA_offset851// except for the encoding and size of the register argument.852uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);853int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;854UnwindPlan::Row::RegisterLocation reg_location;855reg_location.SetAtCFAPlusOffset(op_offset);856row.SetRegisterInfo(reg_num, reg_location);857return true;858}859860case DW_CFA_undefined: // 0x7861{862// takes a single unsigned LEB128 argument that represents a register863// number. The required action is to set the rule for the specified864// register to undefined.865uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);866UnwindPlan::Row::RegisterLocation reg_location;867reg_location.SetUndefined();868row.SetRegisterInfo(reg_num, reg_location);869return true;870}871872case DW_CFA_same_value: // 0x8873{874// takes a single unsigned LEB128 argument that represents a register875// number. The required action is to set the rule for the specified876// register to same value.877uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);878UnwindPlan::Row::RegisterLocation reg_location;879reg_location.SetSame();880row.SetRegisterInfo(reg_num, reg_location);881return true;882}883884case DW_CFA_register: // 0x9885{886// takes two unsigned LEB128 arguments representing register numbers. The887// required action is to set the rule for the first register to be the888// second register.889uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);890uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);891UnwindPlan::Row::RegisterLocation reg_location;892reg_location.SetInRegister(other_reg_num);893row.SetRegisterInfo(reg_num, reg_location);894return true;895}896897case DW_CFA_def_cfa: // 0xC (CFA Definition Instruction)898{899// Takes two unsigned LEB128 operands representing a register number and900// a (non-factored) offset. The required action is to define the current901// CFA rule to use the provided register and offset.902uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);903int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);904row.GetCFAValue().SetIsRegisterPlusOffset(reg_num, op_offset);905return true;906}907908case DW_CFA_def_cfa_register: // 0xD (CFA Definition Instruction)909{910// takes a single unsigned LEB128 argument representing a register911// number. The required action is to define the current CFA rule to use912// the provided register (but to keep the old offset).913uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);914row.GetCFAValue().SetIsRegisterPlusOffset(reg_num,915row.GetCFAValue().GetOffset());916return true;917}918919case DW_CFA_def_cfa_offset: // 0xE (CFA Definition Instruction)920{921// Takes a single unsigned LEB128 operand representing a (non-factored)922// offset. The required action is to define the current CFA rule to use923// the provided offset (but to keep the old register).924int32_t op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);925row.GetCFAValue().SetIsRegisterPlusOffset(926row.GetCFAValue().GetRegisterNumber(), op_offset);927return true;928}929930case DW_CFA_def_cfa_expression: // 0xF (CFA Definition Instruction)931{932size_t block_len = (size_t)m_cfi_data.GetULEB128(&offset);933const uint8_t *block_data =934static_cast<const uint8_t *>(m_cfi_data.GetData(&offset, block_len));935row.GetCFAValue().SetIsDWARFExpression(block_data, block_len);936return true;937}938939case DW_CFA_expression: // 0x10940{941// Takes two operands: an unsigned LEB128 value representing a register942// number, and a DW_FORM_block value representing a DWARF expression. The943// required action is to change the rule for the register indicated by944// the register number to be an expression(E) rule where E is the DWARF945// expression. That is, the DWARF expression computes the address. The946// value of the CFA is pushed on the DWARF evaluation stack prior to947// execution of the DWARF expression.948uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);949uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);950const uint8_t *block_data =951static_cast<const uint8_t *>(m_cfi_data.GetData(&offset, block_len));952UnwindPlan::Row::RegisterLocation reg_location;953reg_location.SetAtDWARFExpression(block_data, block_len);954row.SetRegisterInfo(reg_num, reg_location);955return true;956}957958case DW_CFA_offset_extended_sf: // 0x11959{960// takes two operands: an unsigned LEB128 value representing a register961// number and a signed LEB128 factored offset. This instruction is962// identical to DW_CFA_offset_extended except that the second operand is963// signed and factored.964uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);965int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;966UnwindPlan::Row::RegisterLocation reg_location;967reg_location.SetAtCFAPlusOffset(op_offset);968row.SetRegisterInfo(reg_num, reg_location);969return true;970}971972case DW_CFA_def_cfa_sf: // 0x12 (CFA Definition Instruction)973{974// Takes two operands: an unsigned LEB128 value representing a register975// number and a signed LEB128 factored offset. This instruction is976// identical to DW_CFA_def_cfa except that the second operand is signed977// and factored.978uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);979int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;980row.GetCFAValue().SetIsRegisterPlusOffset(reg_num, op_offset);981return true;982}983984case DW_CFA_def_cfa_offset_sf: // 0x13 (CFA Definition Instruction)985{986// takes a signed LEB128 operand representing a factored offset. This987// instruction is identical to DW_CFA_def_cfa_offset except that the988// operand is signed and factored.989int32_t op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;990uint32_t cfa_regnum = row.GetCFAValue().GetRegisterNumber();991row.GetCFAValue().SetIsRegisterPlusOffset(cfa_regnum, op_offset);992return true;993}994995case DW_CFA_val_expression: // 0x16996{997// takes two operands: an unsigned LEB128 value representing a register998// number, and a DW_FORM_block value representing a DWARF expression. The999// required action is to change the rule for the register indicated by1000// the register number to be a val_expression(E) rule where E is the1001// DWARF expression. That is, the DWARF expression computes the value of1002// the given register. The value of the CFA is pushed on the DWARF1003// evaluation stack prior to execution of the DWARF expression.1004uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);1005uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);1006const uint8_t *block_data =1007(const uint8_t *)m_cfi_data.GetData(&offset, block_len);1008reg_location.SetIsDWARFExpression(block_data, block_len);1009row.SetRegisterInfo(reg_num, reg_location);1010return true;1011}1012}1013}1014return false;1015}10161017void DWARFCallFrameInfo::ForEachFDEEntries(1018const std::function<bool(lldb::addr_t, uint32_t, dw_offset_t)> &callback) {1019GetFDEIndex();10201021for (size_t i = 0, c = m_fde_index.GetSize(); i < c; ++i) {1022const FDEEntryMap::Entry &entry = m_fde_index.GetEntryRef(i);1023if (!callback(entry.base, entry.size, entry.data))1024break;1025}1026}102710281029