summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/ObjectFile
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ObjectFile')
-rw-r--r--lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp52
-rw-r--r--lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h8
-rw-r--r--lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp535
-rw-r--r--lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.h47
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_
OpenPOWER on IntegriCloud