diff options
Diffstat (limited to 'lldb/source/Plugins/ObjectFile')
5 files changed, 635 insertions, 8 deletions
diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt b/lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt index 6981f7ecb71..ad768feca30 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt +++ b/lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt @@ -7,6 +7,7 @@ endif() add_lldb_library(lldbPluginObjectFilePECOFF PLUGIN ObjectFilePECOFF.cpp + PECallFrameInfo.cpp WindowsMiniDump.cpp LINK_LIBS diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 16c131fa469..eee98491a88 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "ObjectFilePECOFF.h" +#include "PECallFrameInfo.h" #include "WindowsMiniDump.h" #include "lldb/Core/FileSpecList.h" @@ -518,7 +519,26 @@ bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) { return success; } +uint32_t ObjectFilePECOFF::GetRVA(const Address &addr) const { + return addr.GetFileAddress() - m_image_base; +} + +Address ObjectFilePECOFF::GetAddress(uint32_t rva) { + SectionList *sect_list = GetSectionList(); + if (!sect_list) + return Address(GetFileAddress(rva)); + + return Address(GetFileAddress(rva), sect_list); +} + +lldb::addr_t ObjectFilePECOFF::GetFileAddress(uint32_t rva) const { + return m_image_base + rva; +} + DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) { + if (!size) + return {}; + if (m_file) { // A bit of a hack, but we intend to write to this buffer, so we can't // mmap it. @@ -541,6 +561,15 @@ DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) { return data; } +DataExtractor ObjectFilePECOFF::ReadImageDataByRVA(uint32_t rva, size_t size) { + if (m_file) { + Address addr = GetAddress(rva); + rva = addr.GetSection()->GetFileOffset() + addr.GetOffset(); + } + + return ReadImageData(rva, size); +} + // ParseSectionHeaders bool ObjectFilePECOFF::ParseSectionHeaders( uint32_t section_header_data_offset) { @@ -678,14 +707,8 @@ Symtab *ObjectFilePECOFF::GetSymtab() { uint32_t data_start = m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr; - uint32_t address_rva = data_start; - if (m_file) { - Address address(m_coff_header_opt.image_base + data_start, sect_list); - address_rva = - address.GetSection()->GetFileOffset() + address.GetOffset(); - } - DataExtractor symtab_data = - ReadImageData(address_rva, m_coff_header_opt.data_dirs[0].vmsize); + DataExtractor symtab_data = ReadImageDataByRVA( + data_start, m_coff_header_opt.data_dirs[0].vmsize); lldb::offset_t offset = 0; // Read export_table header @@ -740,6 +763,19 @@ Symtab *ObjectFilePECOFF::GetSymtab() { return m_symtab_up.get(); } +std::unique_ptr<CallFrameInfo> ObjectFilePECOFF::CreateCallFrameInfo() { + if (coff_data_dir_exception_table >= m_coff_header_opt.data_dirs.size()) + return {}; + + data_directory data_dir_exception = + m_coff_header_opt.data_dirs[coff_data_dir_exception_table]; + if (!data_dir_exception.vmaddr) + return {}; + + return std::make_unique<PECallFrameInfo>(*this, data_dir_exception.vmaddr, + data_dir_exception.vmsize); +} + bool ObjectFilePECOFF::IsStripped() { // TODO: determine this for COFF return false; diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h index 68ea7a7270c..78088ecc437 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -135,7 +135,14 @@ public: bool IsWindowsSubsystem(); + uint32_t GetRVA(const lldb_private::Address &addr) const; + lldb_private::Address GetAddress(uint32_t rva); + lldb::addr_t GetFileAddress(uint32_t rva) const; + lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size); + lldb_private::DataExtractor ReadImageDataByRVA(uint32_t rva, size_t size); + + std::unique_ptr<lldb_private::CallFrameInfo> CreateCallFrameInfo() override; protected: bool NeedsEndianSwap() const; @@ -216,6 +223,7 @@ protected: enum coff_data_dir_type { coff_data_dir_export_table = 0, coff_data_dir_import_table = 1, + coff_data_dir_exception_table = 3 }; typedef struct section_header { diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp new file mode 100644 index 00000000000..fe67e87f09f --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp @@ -0,0 +1,535 @@ +#include "PECallFrameInfo.h" + +#include "ObjectFilePECOFF.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "llvm/Support/Win64EH.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm::Win64EH; + +template <typename T> +static const T *TypedRead(const DataExtractor &data_extractor, offset_t &offset, + offset_t size = sizeof(T)) { + return static_cast<const T *>(data_extractor.GetData(&offset, size)); +} + +struct EHInstruction { + enum class Type { + PUSH_REGISTER, + ALLOCATE, + SET_FRAME_POINTER_REGISTER, + SAVE_REGISTER + }; + + uint8_t offset; + Type type; + uint32_t reg; + uint32_t frame_offset; +}; + +using EHProgram = std::vector<EHInstruction>; + +class UnwindCodesIterator { +public: + UnwindCodesIterator(ObjectFilePECOFF &object_file, uint32_t unwind_info_rva); + + bool GetNext(); + bool IsError() const { return m_error; } + + const UnwindInfo *GetUnwindInfo() const { return m_unwind_info; } + const UnwindCode *GetUnwindCode() const { return m_unwind_code; } + bool IsChained() const { return m_chained; } + +private: + ObjectFilePECOFF &m_object_file; + + bool m_error; + + uint32_t m_unwind_info_rva; + DataExtractor m_unwind_info_data; + const UnwindInfo *m_unwind_info; + + DataExtractor m_unwind_code_data; + offset_t m_unwind_code_offset; + const UnwindCode *m_unwind_code; + + bool m_chained; +}; + +UnwindCodesIterator::UnwindCodesIterator(ObjectFilePECOFF &object_file, + uint32_t unwind_info_rva) + : m_object_file(object_file), m_error(false), + m_unwind_info_rva(unwind_info_rva), + m_unwind_info(nullptr), m_unwind_code_offset{}, m_unwind_code(nullptr), + m_chained(false) {} + +bool UnwindCodesIterator::GetNext() { + static constexpr int UNWIND_INFO_SIZE = 4; + + m_error = false; + m_unwind_code = nullptr; + while (!m_unwind_code) { + if (!m_unwind_info) { + m_unwind_info_data = + m_object_file.ReadImageDataByRVA(m_unwind_info_rva, UNWIND_INFO_SIZE); + + offset_t offset = 0; + m_unwind_info = + TypedRead<UnwindInfo>(m_unwind_info_data, offset, UNWIND_INFO_SIZE); + if (!m_unwind_info) { + m_error = true; + break; + } + + m_unwind_code_data = m_object_file.ReadImageDataByRVA( + m_unwind_info_rva + UNWIND_INFO_SIZE, + m_unwind_info->NumCodes * sizeof(UnwindCode)); + m_unwind_code_offset = 0; + } + + if (m_unwind_code_offset < m_unwind_code_data.GetByteSize()) { + m_unwind_code = + TypedRead<UnwindCode>(m_unwind_code_data, m_unwind_code_offset); + m_error = !m_unwind_code; + break; + } + + if (!(m_unwind_info->getFlags() & UNW_ChainInfo)) + break; + + uint32_t runtime_function_rva = + m_unwind_info_rva + UNWIND_INFO_SIZE + + ((m_unwind_info->NumCodes + 1) & ~1) * sizeof(UnwindCode); + DataExtractor runtime_function_data = m_object_file.ReadImageDataByRVA( + runtime_function_rva, sizeof(RuntimeFunction)); + + offset_t offset = 0; + const auto *runtime_function = + TypedRead<RuntimeFunction>(runtime_function_data, offset); + if (!runtime_function) { + m_error = true; + break; + } + + m_unwind_info_rva = runtime_function->UnwindInfoOffset; + m_unwind_info = nullptr; + m_chained = true; + } + + return !!m_unwind_code; +} + +class EHProgramBuilder { +public: + EHProgramBuilder(ObjectFilePECOFF &object_file, uint32_t unwind_info_rva); + + bool Build(); + + const EHProgram &GetProgram() const { return m_program; } + +private: + static uint32_t ConvertMachineToLLDBRegister(uint8_t machine_reg); + static uint32_t ConvertXMMToLLDBRegister(uint8_t xmm_reg); + + bool ProcessUnwindCode(UnwindCode code); + void Finalize(); + + bool ParseBigOrScaledFrameOffset(uint32_t &result, bool big, uint32_t scale); + bool ParseBigFrameOffset(uint32_t &result); + bool ParseFrameOffset(uint32_t &result); + + UnwindCodesIterator m_iterator; + EHProgram m_program; +}; + +EHProgramBuilder::EHProgramBuilder(ObjectFilePECOFF &object_file, + uint32_t unwind_info_rva) + : m_iterator(object_file, unwind_info_rva) {} + +bool EHProgramBuilder::Build() { + while (m_iterator.GetNext()) + if (!ProcessUnwindCode(*m_iterator.GetUnwindCode())) + return false; + + if (m_iterator.IsError()) + return false; + + Finalize(); + + return true; +} + +uint32_t EHProgramBuilder::ConvertMachineToLLDBRegister(uint8_t machine_reg) { + static uint32_t machine_to_lldb_register[] = { + lldb_rax_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, lldb_rbx_x86_64, + lldb_rsp_x86_64, lldb_rbp_x86_64, lldb_rsi_x86_64, lldb_rdi_x86_64, + lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64, + lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64}; + + if (machine_reg >= llvm::array_lengthof(machine_to_lldb_register)) + return LLDB_INVALID_REGNUM; + + return machine_to_lldb_register[machine_reg]; +} + +uint32_t EHProgramBuilder::ConvertXMMToLLDBRegister(uint8_t xmm_reg) { + static uint32_t xmm_to_lldb_register[] = { + lldb_xmm0_x86_64, lldb_xmm1_x86_64, lldb_xmm2_x86_64, + lldb_xmm3_x86_64, lldb_xmm4_x86_64, lldb_xmm5_x86_64, + lldb_xmm6_x86_64, lldb_xmm7_x86_64, lldb_xmm8_x86_64, + lldb_xmm9_x86_64, lldb_xmm10_x86_64, lldb_xmm11_x86_64, + lldb_xmm12_x86_64, lldb_xmm13_x86_64, lldb_xmm14_x86_64, + lldb_xmm15_x86_64}; + + if (xmm_reg >= llvm::array_lengthof(xmm_to_lldb_register)) + return LLDB_INVALID_REGNUM; + + return xmm_to_lldb_register[xmm_reg]; +} + +bool EHProgramBuilder::ProcessUnwindCode(UnwindCode code) { + uint8_t o = m_iterator.IsChained() ? 0 : code.u.CodeOffset; + uint8_t unwind_operation = code.getUnwindOp(); + uint8_t operation_info = code.getOpInfo(); + + switch (unwind_operation) { + case UOP_PushNonVol: { + uint32_t r = ConvertMachineToLLDBRegister(operation_info); + if (r == LLDB_INVALID_REGNUM) + return false; + + m_program.emplace_back( + EHInstruction{o, EHInstruction::Type::PUSH_REGISTER, r, 8}); + + return true; + } + case UOP_AllocLarge: { + uint32_t fo; + if (!ParseBigOrScaledFrameOffset(fo, operation_info, 8)) + return false; + + m_program.emplace_back(EHInstruction{o, EHInstruction::Type::ALLOCATE, + LLDB_INVALID_REGNUM, fo}); + + return true; + } + case UOP_AllocSmall: { + m_program.emplace_back( + EHInstruction{o, EHInstruction::Type::ALLOCATE, LLDB_INVALID_REGNUM, + static_cast<uint32_t>(operation_info) * 8 + 8}); + return true; + } + case UOP_SetFPReg: { + uint32_t fpr = LLDB_INVALID_REGNUM; + if (m_iterator.GetUnwindInfo()->getFrameRegister()) + fpr = ConvertMachineToLLDBRegister( + m_iterator.GetUnwindInfo()->getFrameRegister()); + if (fpr == LLDB_INVALID_REGNUM) + return false; + + uint32_t fpro = + static_cast<uint32_t>(m_iterator.GetUnwindInfo()->getFrameOffset()) * + 16; + + m_program.emplace_back(EHInstruction{ + o, EHInstruction::Type::SET_FRAME_POINTER_REGISTER, fpr, fpro}); + + return true; + } + case UOP_SaveNonVol: + case UOP_SaveNonVolBig: { + uint32_t r = ConvertMachineToLLDBRegister(operation_info); + if (r == LLDB_INVALID_REGNUM) + return false; + + uint32_t fo; + if (!ParseBigOrScaledFrameOffset(fo, unwind_operation == UOP_SaveNonVolBig, + 8)) + return false; + + m_program.emplace_back( + EHInstruction{o, EHInstruction::Type::SAVE_REGISTER, r, fo}); + + return true; + } + case UOP_Epilog: { + return m_iterator.GetNext(); + } + case UOP_SpareCode: { + // ReSharper disable once CppIdenticalOperandsInBinaryExpression + return m_iterator.GetNext() && m_iterator.GetNext(); + } + case UOP_SaveXMM128: + case UOP_SaveXMM128Big: { + uint32_t r = ConvertXMMToLLDBRegister(operation_info); + if (r == LLDB_INVALID_REGNUM) + return false; + + uint32_t fo; + if (!ParseBigOrScaledFrameOffset(fo, unwind_operation == UOP_SaveXMM128Big, + 16)) + return false; + + m_program.emplace_back( + EHInstruction{o, EHInstruction::Type::SAVE_REGISTER, r, fo}); + + return true; + } + case UOP_PushMachFrame: { + if (operation_info) + m_program.emplace_back(EHInstruction{o, EHInstruction::Type::ALLOCATE, + LLDB_INVALID_REGNUM, 8}); + m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER, + lldb_rip_x86_64, 8}); + m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER, + lldb_cs_x86_64, 8}); + m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER, + lldb_rflags_x86_64, 8}); + m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER, + lldb_rsp_x86_64, 8}); + m_program.emplace_back(EHInstruction{o, EHInstruction::Type::PUSH_REGISTER, + lldb_ss_x86_64, 8}); + + return true; + } + default: + return false; + } +} + +void EHProgramBuilder::Finalize() { + for (const EHInstruction &i : m_program) + if (i.reg == lldb_rip_x86_64) + return; + + m_program.emplace_back( + EHInstruction{0, EHInstruction::Type::PUSH_REGISTER, lldb_rip_x86_64, 8}); +} + +bool EHProgramBuilder::ParseBigOrScaledFrameOffset(uint32_t &result, bool big, + uint32_t scale) { + if (big) { + if (!ParseBigFrameOffset(result)) + return false; + } else { + if (!ParseFrameOffset(result)) + return false; + + result *= scale; + } + + return true; +} + +bool EHProgramBuilder::ParseBigFrameOffset(uint32_t &result) { + if (!m_iterator.GetNext()) + return false; + + result = m_iterator.GetUnwindCode()->FrameOffset; + + if (!m_iterator.GetNext()) + return false; + + result += static_cast<uint32_t>(m_iterator.GetUnwindCode()->FrameOffset) + << 16; + + return true; +} + +bool EHProgramBuilder::ParseFrameOffset(uint32_t &result) { + if (!m_iterator.GetNext()) + return false; + + result = m_iterator.GetUnwindCode()->FrameOffset; + + return true; +} + +class EHProgramRange { +public: + EHProgramRange(EHProgram::const_iterator begin, + EHProgram::const_iterator end); + + std::unique_ptr<UnwindPlan::Row> BuildUnwindPlanRow() const; + +private: + int32_t GetCFAFrameOffset() const; + + EHProgram::const_iterator m_begin; + EHProgram::const_iterator m_end; +}; + +EHProgramRange::EHProgramRange(EHProgram::const_iterator begin, + EHProgram::const_iterator end) + : m_begin(begin), m_end(end) {} + +std::unique_ptr<UnwindPlan::Row> EHProgramRange::BuildUnwindPlanRow() const { + std::unique_ptr<UnwindPlan::Row> row = std::make_unique<UnwindPlan::Row>(); + + if (m_begin != m_end) + row->SetOffset(m_begin->offset); + + int32_t cfa_frame_offset = GetCFAFrameOffset(); + + bool frame_pointer_found = false; + for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) { + switch (it->type) { + case EHInstruction::Type::SET_FRAME_POINTER_REGISTER: + row->GetCFAValue().SetIsRegisterPlusOffset(it->reg, cfa_frame_offset - + it->frame_offset); + frame_pointer_found = true; + break; + default: + break; + } + if (frame_pointer_found) + break; + } + if (!frame_pointer_found) + row->GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, + cfa_frame_offset); + + int32_t rsp_frame_offset = 0; + for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) { + switch (it->type) { + case EHInstruction::Type::PUSH_REGISTER: + row->SetRegisterLocationToAtCFAPlusOffset( + it->reg, rsp_frame_offset - cfa_frame_offset, false); + rsp_frame_offset += it->frame_offset; + break; + case EHInstruction::Type::ALLOCATE: + rsp_frame_offset += it->frame_offset; + break; + case EHInstruction::Type::SAVE_REGISTER: + row->SetRegisterLocationToAtCFAPlusOffset( + it->reg, it->frame_offset - cfa_frame_offset, false); + break; + default: + break; + } + } + + row->SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, false); + + return row; +} + +int32_t EHProgramRange::GetCFAFrameOffset() const { + int32_t result = 0; + + for (EHProgram::const_iterator it = m_begin; it != m_end; ++it) { + switch (it->type) { + case EHInstruction::Type::PUSH_REGISTER: + case EHInstruction::Type::ALLOCATE: + result += it->frame_offset; + default: + break; + } + } + + return result; +} + +PECallFrameInfo::PECallFrameInfo(ObjectFilePECOFF &object_file, + uint32_t exception_dir_rva, + uint32_t exception_dir_size) + : m_object_file(object_file), + m_exception_dir(object_file.ReadImageDataByRVA(exception_dir_rva, + exception_dir_size)) {} + +bool PECallFrameInfo::GetAddressRange(Address addr, AddressRange &range) { + range.Clear(); + + const RuntimeFunction *runtime_function = + FindRuntimeFunctionIntersectsWithRange(AddressRange(addr, 1)); + if (!runtime_function) + return false; + + range.GetBaseAddress() = + m_object_file.GetAddress(runtime_function->StartAddress); + range.SetByteSize(runtime_function->EndAddress - + runtime_function->StartAddress); + + return true; +} + +bool PECallFrameInfo::GetUnwindPlan(const Address &addr, + UnwindPlan &unwind_plan) { + return GetUnwindPlan(AddressRange(addr, 1), unwind_plan); +} + +bool PECallFrameInfo::GetUnwindPlan(const AddressRange &range, + UnwindPlan &unwind_plan) { + unwind_plan.Clear(); + + unwind_plan.SetSourceName("PE EH info"); + unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); + unwind_plan.SetRegisterKind(eRegisterKindLLDB); + + const RuntimeFunction *runtime_function = + FindRuntimeFunctionIntersectsWithRange(range); + if (!runtime_function) + return false; + + EHProgramBuilder builder(m_object_file, runtime_function->UnwindInfoOffset); + if (!builder.Build()) + return false; + + std::vector<UnwindPlan::RowSP> rows; + + uint32_t last_offset = UINT32_MAX; + for (auto it = builder.GetProgram().begin(); it != builder.GetProgram().end(); + ++it) { + if (it->offset == last_offset) + continue; + + EHProgramRange program_range = + EHProgramRange(it, builder.GetProgram().end()); + rows.push_back(program_range.BuildUnwindPlanRow()); + + last_offset = it->offset; + } + + for (auto it = rows.rbegin(); it != rows.rend(); ++it) + unwind_plan.AppendRow(*it); + + unwind_plan.SetPlanValidAddressRange(AddressRange( + m_object_file.GetAddress(runtime_function->StartAddress), + runtime_function->EndAddress - runtime_function->StartAddress)); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); + + return true; +} + +const RuntimeFunction *PECallFrameInfo::FindRuntimeFunctionIntersectsWithRange( + const AddressRange &range) const { + uint32_t rva = m_object_file.GetRVA(range.GetBaseAddress()); + addr_t size = range.GetByteSize(); + + uint32_t begin = 0; + uint32_t end = m_exception_dir.GetByteSize() / sizeof(RuntimeFunction); + while (begin < end) { + uint32_t curr = (begin + end) / 2; + + offset_t offset = curr * sizeof(RuntimeFunction); + const auto *runtime_function = + TypedRead<RuntimeFunction>(m_exception_dir, offset); + if (!runtime_function) + break; + + if (runtime_function->StartAddress < rva + size && + runtime_function->EndAddress > rva) + return runtime_function; + + if (runtime_function->StartAddress >= rva + size) + end = curr; + + if (runtime_function->EndAddress <= rva) + begin = curr + 1; + } + + return nullptr; +} diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.h b/lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.h new file mode 100644 index 00000000000..b5932dc726a --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.h @@ -0,0 +1,47 @@ +//===-- PECallFrameInfo.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_PECallFrameInfo_h_ +#define liblldb_PECallFrameInfo_h_ + +#include "lldb/Symbol/CallFrameInfo.h" +#include "lldb/Utility/DataExtractor.h" + +class ObjectFilePECOFF; + +namespace llvm { +namespace Win64EH { + +struct RuntimeFunction; + +} +} // namespace llvm + +class PECallFrameInfo : public virtual lldb_private::CallFrameInfo { +public: + explicit PECallFrameInfo(ObjectFilePECOFF &object_file, + uint32_t exception_dir_rva, + uint32_t exception_dir_size); + + bool GetAddressRange(lldb_private::Address addr, + lldb_private::AddressRange &range) override; + + bool GetUnwindPlan(const lldb_private::Address &addr, + lldb_private::UnwindPlan &unwind_plan) override; + bool GetUnwindPlan(const lldb_private::AddressRange &range, + lldb_private::UnwindPlan &unwind_plan) override; + +private: + const llvm::Win64EH::RuntimeFunction *FindRuntimeFunctionIntersectsWithRange( + const lldb_private::AddressRange &range) const; + + ObjectFilePECOFF &m_object_file; + lldb_private::DataExtractor m_exception_dir; +}; + +#endif // liblldb_PECallFrameInfo_h_ |