aleksandr.urakov updated this revision to Diff 220144.
aleksandr.urakov edited the summary of this revision.
aleksandr.urakov added a comment.

Update due to the requests.


Repository:
  rLLDB LLDB

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67347/new/

https://reviews.llvm.org/D67347

Files:
  lldb/include/lldb/Symbol/CallFrameInfo.h
  lldb/include/lldb/Symbol/FuncUnwinders.h
  lldb/include/lldb/Symbol/ObjectFile.h
  lldb/include/lldb/Symbol/UnwindTable.h
  lldb/include/lldb/lldb-forward.h
  lldb/source/Commands/CommandObjectTarget.cpp
  lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt
  lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
  lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
  lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp
  lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.h
  lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
  lldb/source/Symbol/FuncUnwinders.cpp
  lldb/source/Symbol/ObjectFile.cpp
  lldb/source/Symbol/UnwindTable.cpp
  lldb/unittests/ObjectFile/CMakeLists.txt
  lldb/unittests/ObjectFile/PECOFF/CMakeLists.txt
  lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp
  llvm/include/llvm/Support/Win64EH.h

Index: llvm/include/llvm/Support/Win64EH.h
===================================================================
--- llvm/include/llvm/Support/Win64EH.h
+++ llvm/include/llvm/Support/Win64EH.h
@@ -30,7 +30,9 @@
   UOP_SetFPReg,
   UOP_SaveNonVol,
   UOP_SaveNonVolBig,
-  UOP_SaveXMM128 = 8,
+  UOP_Epilog,
+  UOP_SpareCode,
+  UOP_SaveXMM128,
   UOP_SaveXMM128Big,
   UOP_PushMachFrame,
   // The following set of unwind opcodes is for ARM64.  They are documented at
Index: lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp
@@ -0,0 +1,336 @@
+//===-- TestPECallFrameInfo.cpp ------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+#include "TestingSupport/TestUtilities.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/CallFrameInfo.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "llvm/Testing/Support/Error.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+class PECallFrameInfoTest : public testing::Test {
+public:
+  void SetUp() override {
+    FileSystem::Initialize();
+    ObjectFilePECOFF::Initialize();
+  }
+
+  void TearDown() override {
+    ObjectFilePECOFF::Terminate();
+    FileSystem::Terminate();
+  }
+
+protected:
+  void GetUnwindPlan(addr_t file_addr, UnwindPlan &plan) const;
+};
+
+void PECallFrameInfoTest::GetUnwindPlan(addr_t file_addr, UnwindPlan &plan) const {
+  llvm::Expected<TestFile> ExpectedFile = TestFile::fromYaml(
+      R"(
+--- !COFF
+OptionalHeader:  
+  AddressOfEntryPoint: 0
+  ImageBase:       16777216
+  SectionAlignment: 4096
+  FileAlignment:   512
+  MajorOperatingSystemVersion: 6
+  MinorOperatingSystemVersion: 0
+  MajorImageVersion: 0
+  MinorImageVersion: 0
+  MajorSubsystemVersion: 6
+  MinorSubsystemVersion: 0
+  Subsystem:       IMAGE_SUBSYSTEM_WINDOWS_CUI
+  DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ]
+  SizeOfStackReserve: 1048576
+  SizeOfStackCommit: 4096
+  SizeOfHeapReserve: 1048576
+  SizeOfHeapCommit: 4096
+  ExportTable:     
+    RelativeVirtualAddress: 0
+    Size:            0
+  ImportTable:     
+    RelativeVirtualAddress: 0
+    Size:            0
+  ResourceTable:   
+    RelativeVirtualAddress: 0
+    Size:            0
+  ExceptionTable:  
+    RelativeVirtualAddress: 12288
+    Size:            60
+  CertificateTable: 
+    RelativeVirtualAddress: 0
+    Size:            0
+  BaseRelocationTable: 
+    RelativeVirtualAddress: 0
+    Size:            0
+  Debug:           
+    RelativeVirtualAddress: 0
+    Size:            0
+  Architecture:    
+    RelativeVirtualAddress: 0
+    Size:            0
+  GlobalPtr:       
+    RelativeVirtualAddress: 0
+    Size:            0
+  TlsTable:        
+    RelativeVirtualAddress: 0
+    Size:            0
+  LoadConfigTable: 
+    RelativeVirtualAddress: 0
+    Size:            0
+  BoundImport:     
+    RelativeVirtualAddress: 0
+    Size:            0
+  IAT:             
+    RelativeVirtualAddress: 0
+    Size:            0
+  DelayImportDescriptor: 
+    RelativeVirtualAddress: 0
+    Size:            0
+  ClrRuntimeHeader: 
+    RelativeVirtualAddress: 0
+    Size:            0
+header:          
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ]
+sections:        
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  4096
+    VirtualSize:     4096
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  8192
+    VirtualSize:     68
+    SectionData:     010C06000C3208F006E00470036002302105020005540D0000100000001100000020000019400E352F74670028646600213465001A3315015E000EF00CE00AD008C00650
+
+
+# Unwind info at 0x2000:
+# 01 0C 06 00    No chained info, prolog size = 0xC, unwind codes size is 6 words, no frame register
+# 0C 32          UOP_AllocSmall(2) 3 * 8 + 8 bytes, offset in prolog is 0xC
+# 08 F0          UOP_PushNonVol(0) R15(0xF), offset in prolog is 8
+# 06 E0          UOP_PushNonVol(0) R14(0xE), offset in prolog is 6
+# 04 70          UOP_PushNonVol(0) RDI(7), offset in prolog is 4
+# 03 60          UOP_PushNonVol(0) RSI(6), offset in prolog is 3
+# 02 30          UOP_PushNonVol(0) RBX(3), offset in prolog is 2
+# Corresponding prolog:
+# 00    push    rbx
+# 02    push    rsi
+# 03    push    rdi
+# 04    push    r14
+# 06    push    r15
+# 08    sub     rsp, 20h
+
+# Unwind info at 0x2010:
+# 21 05 02 00    Has chained info, prolog size = 5, unwind codes size is 2 words, no frame register
+# 05 54 0D 00    UOP_SaveNonVol(4) RBP(5) to RSP + 0xD * 8, offset in prolog is 5
+# Chained runtime function:
+# 00 10 00 00    Start address is 0x1000
+# 00 11 00 00    End address is 0x1100
+# 00 20 00 00    Unwind info RVA is 0x2000
+# Corresponding prolog:
+# 00    mov     [rsp+68h], rbp
+
+# Unwind info at 0x2024:
+# 19 40 0E 35    No chained info, prolog size = 0x40, unwind codes size is 0xE words, frame register is RBP, frame register offset is RSP + 3 * 16
+# 2F 74 67 00    UOP_SaveNonVol(4) RDI(7) to RSP + 0x67 * 8, offset in prolog is 0x2F
+# 28 64 66 00    UOP_SaveNonVol(4) RSI(6) to RSP + 0x66 * 8, offset in prolog is 0x28
+# 21 34 65 00    UOP_SaveNonVol(4) RBX(3) to RSP + 0x65 * 8, offset in prolog is 0x21
+# 1A 33          UOP_SetFPReg(3), offset in prolog is 0x1A
+# 15 01 5E 00    UOP_AllocLarge(1) 0x5E * 8 bytes, offset in prolog is 0x15
+# 0E F0          UOP_PushNonVol(0) R15(0xF), offset in prolog is 0xE
+# 0C E0          UOP_PushNonVol(0) R14(0xE), offset in prolog is 0xC
+# 0A D0          UOP_PushNonVol(0) R13(0xD), offset in prolog is 0xA
+# 08 C0          UOP_PushNonVol(0) R12(0xC), offset in prolog is 8
+# 06 50          UOP_PushNonVol(0) RBP(5), offset in prolog is 6
+# Corresponding prolog:
+# 00    mov     [rsp+8], rcx
+# 05    push    rbp
+# 06    push    r12
+# 08    push    r13
+# 0A    push    r14
+# 0C    push    r15
+# 0E    sub     rsp, 2F0h
+# 15    lea     rbp, [rsp+30h]
+# 1A    mov     [rbp+2F8h], rbx
+# 21    mov     [rbp+300h], rsi
+# 28    mov     [rbp+308h], rdi
+
+  - Name:            .pdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  12288
+    VirtualSize:     60
+    SectionData:     000000000000000000000000000000000000000000000000001000000011000000200000001100000012000010200000001200000013000024200000
+
+# 00 00 00 00
+# 00 00 00 00    Test correct processing of empty runtime functions at begin
+# 00 00 00 00
+
+# 00 00 00 00
+# 00 00 00 00    Test correct processing of empty runtime functions at begin
+# 00 00 00 00
+
+# 00 10 00 00    Start address is 0x1000
+# 00 11 00 00    End address is 0x1100
+# 00 20 00 00    Unwind info RVA is 0x2000
+
+# 00 11 00 00    Start address is 0x1100
+# 00 12 00 00    End address is 0x1200
+# 10 20 00 00    Unwind info RVA is 0x2010
+
+# 00 12 00 00    Start address is 0x1200
+# 00 13 00 00    End address is 0x1300
+# 24 20 00 00    Unwind info RVA is 0x2024
+
+symbols:         []
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  ModuleSP module_sp = std::make_shared<Module>(ModuleSpec(FileSpec(ExpectedFile->name())));
+  ObjectFile *object_file = module_sp->GetObjectFile();
+  ASSERT_NE(object_file, nullptr);
+
+  std::unique_ptr<CallFrameInfo> cfi = object_file->CreateCallFrameInfo();
+  ASSERT_NE(cfi.get(), nullptr);
+
+  SectionList *sect_list = object_file->GetSectionList();
+  ASSERT_NE(sect_list, nullptr);
+
+  EXPECT_TRUE(cfi->GetUnwindPlan(Address(file_addr, sect_list), plan));
+}
+
+TEST_F(PECallFrameInfoTest, Basic_eh) {
+  UnwindPlan plan(eRegisterKindLLDB);
+  GetUnwindPlan(0x1001080, plan);
+  EXPECT_EQ(plan.GetRowCount(), 7);
+
+  UnwindPlan::Row row;
+  row.SetOffset(0);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 8);
+  row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(0), row);
+
+  row.SetOffset(2);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x10);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, -0x10, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(1), row);
+
+  row.SetOffset(3);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x18);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, -0x18, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(2), row);
+
+  row.SetOffset(4);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x20);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, -0x20, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(3), row);
+
+  row.SetOffset(6);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x28);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(4), row);
+
+  row.SetOffset(8);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x30);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(5), row);
+
+  row.SetOffset(0xC);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x50);
+  EXPECT_EQ(*plan.GetRowAtIndex(6), row);
+}
+
+TEST_F(PECallFrameInfoTest, Chained_eh) {
+  UnwindPlan plan(eRegisterKindLLDB);
+  GetUnwindPlan(0x1001180, plan);
+  EXPECT_EQ(plan.GetRowCount(), 2);
+
+  UnwindPlan::Row row;
+  row.SetOffset(0);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x50);
+  row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, -0x10, true);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, -0x18, true);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, -0x20, true);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(0), row);
+
+  row.SetOffset(5);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbp_x86_64, 0x18, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(1), row);
+}
+
+TEST_F(PECallFrameInfoTest, Frame_reg_eh) {
+  UnwindPlan plan(eRegisterKindLLDB);
+  GetUnwindPlan(0x1001280, plan);
+  EXPECT_EQ(plan.GetRowCount(), 11);
+
+  UnwindPlan::Row row;
+  row.SetOffset(0);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 8);
+  row.SetRegisterLocationToIsCFAPlusOffset(lldb_rsp_x86_64, 0, true);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rip_x86_64, -8, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(0), row);
+
+  row.SetOffset(6);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x10);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbp_x86_64, -0x10, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(1), row);
+
+  row.SetOffset(8);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x18);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_r12_x86_64, -0x18, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(2), row);
+
+  row.SetOffset(0xA);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x20);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_r13_x86_64, -0x20, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(3), row);
+
+  row.SetOffset(0xC);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x28);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_r14_x86_64, -0x28, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(4), row);
+
+  row.SetOffset(0xE);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x30);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_r15_x86_64, -0x30, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(5), row);
+
+  row.SetOffset(0x15);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rsp_x86_64, 0x320);
+  EXPECT_EQ(*plan.GetRowAtIndex(6), row);
+
+  row.SetOffset(0x1A);
+  row.GetCFAValue().SetIsRegisterPlusOffset(lldb_rbp_x86_64, 0x2F0);
+  EXPECT_EQ(*plan.GetRowAtIndex(7), row);
+
+  row.SetOffset(0x21);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rbx_x86_64, 8, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(8), row);
+
+  row.SetOffset(0x28);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rsi_x86_64, 0x10, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(9), row);
+
+  row.SetOffset(0x2F);
+  row.SetRegisterLocationToAtCFAPlusOffset(lldb_rdi_x86_64, 0x18, true);
+  EXPECT_EQ(*plan.GetRowAtIndex(10), row);
+}
Index: lldb/unittests/ObjectFile/PECOFF/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/unittests/ObjectFile/PECOFF/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_lldb_unittest(ObjectFilePECOFFTests
+  TestPECallFrameInfo.cpp
+
+  LINK_LIBS
+    lldbUtilityHelpers
+    lldbPluginObjectFilePECOFF
+    LLVMTestingSupport
+  )
Index: lldb/unittests/ObjectFile/CMakeLists.txt
===================================================================
--- lldb/unittests/ObjectFile/CMakeLists.txt
+++ lldb/unittests/ObjectFile/CMakeLists.txt
@@ -1,2 +1,3 @@
 add_subdirectory(Breakpad)
 add_subdirectory(ELF)
+add_subdirectory(PECOFF)
Index: lldb/source/Symbol/UnwindTable.cpp
===================================================================
--- lldb/source/Symbol/UnwindTable.cpp
+++ lldb/source/Symbol/UnwindTable.cpp
@@ -13,6 +13,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Symbol/ArmUnwindInfo.h"
+#include "lldb/Symbol/CallFrameInfo.h"
 #include "lldb/Symbol/CompactUnwindInfo.h"
 #include "lldb/Symbol/DWARFCallFrameInfo.h"
 #include "lldb/Symbol/FuncUnwinders.h"
@@ -29,7 +30,8 @@
 
 UnwindTable::UnwindTable(Module &module)
     : m_module(module), m_unwinds(), m_initialized(false), m_mutex(),
-      m_eh_frame_up(), m_compact_unwind_up(), m_arm_unwind_up() {}
+      m_object_file_unwind_up(), m_eh_frame_up(), m_compact_unwind_up(),
+      m_arm_unwind_up() {}
 
 // We can't do some of this initialization when the ObjectFile is running its
 // ctor; delay doing it until needed for something.
@@ -47,6 +49,8 @@
   if (!object_file)
     return;
 
+  m_object_file_unwind_up = object_file->CreateCallFrameInfo();
+
   SectionList *sl = m_module.GetSectionList();
   if (!sl)
     return;
@@ -83,7 +87,12 @@
                                                           SymbolContext &sc) {
   AddressRange range;
 
-  // First check the symbol context
+  // First check the unwind info from the object file plugin
+  if (m_object_file_unwind_up &&
+      m_object_file_unwind_up->GetAddressRange(addr, range))
+    return range;
+
+  // Check the symbol context
   if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
                          false, range) &&
       range.GetBaseAddress().IsValid())
@@ -162,6 +171,11 @@
   s.EOL();
 }
 
+lldb_private::CallFrameInfo *UnwindTable::GetObjectFileUnwindInfo() {
+  Initialize();
+  return m_object_file_unwind_up.get();
+}
+
 DWARFCallFrameInfo *UnwindTable::GetEHFrameInfo() {
   Initialize();
   return m_eh_frame_up.get();
Index: lldb/source/Symbol/ObjectFile.cpp
===================================================================
--- lldb/source/Symbol/ObjectFile.cpp
+++ lldb/source/Symbol/ObjectFile.cpp
@@ -11,6 +11,7 @@
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Section.h"
+#include "lldb/Symbol/CallFrameInfo.h"
 #include "lldb/Symbol/ObjectContainer.h"
 #include "lldb/Symbol/SymbolFile.h"
 #include "lldb/Target/Process.h"
@@ -671,6 +672,10 @@
   return loadables;
 }
 
+std::unique_ptr<CallFrameInfo> ObjectFile::CreateCallFrameInfo() {
+  return {};
+}
+
 void ObjectFile::RelocateSection(lldb_private::Section *section)
 {
 }
Index: lldb/source/Symbol/FuncUnwinders.cpp
===================================================================
--- lldb/source/Symbol/FuncUnwinders.cpp
+++ lldb/source/Symbol/FuncUnwinders.cpp
@@ -10,6 +10,7 @@
 #include "lldb/Core/Address.h"
 #include "lldb/Core/AddressRange.h"
 #include "lldb/Symbol/ArmUnwindInfo.h"
+#include "lldb/Symbol/CallFrameInfo.h"
 #include "lldb/Symbol/CompactUnwindInfo.h"
 #include "lldb/Symbol/DWARFCallFrameInfo.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -58,6 +59,8 @@
                                                     Thread &thread) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
 
+  if (UnwindPlanSP plan_sp = GetObjectFileUnwindPlan(target))
+    return plan_sp;
   if (UnwindPlanSP plan_sp = GetSymbolFileUnwindPlan(thread))
     return plan_sp;
   if (UnwindPlanSP plan_sp = GetDebugFrameUnwindPlan(target))
@@ -97,6 +100,26 @@
   return UnwindPlanSP();
 }
 
+lldb::UnwindPlanSP FuncUnwinders::GetObjectFileUnwindPlan(Target &target) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  if (m_unwind_plan_object_file_sp.get() ||
+      m_tried_unwind_plan_object_file)
+    return m_unwind_plan_object_file_sp;
+
+  m_tried_unwind_plan_object_file = true;
+  if (m_range.GetBaseAddress().IsValid()) {
+    CallFrameInfo *object_file_frame = m_unwind_table.GetObjectFileUnwindInfo();
+    if (object_file_frame) {
+      m_unwind_plan_object_file_sp =
+          std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+      if (!object_file_frame->GetUnwindPlan(m_range,
+                                            *m_unwind_plan_object_file_sp))
+        m_unwind_plan_object_file_sp.reset();
+    }
+  }
+  return m_unwind_plan_object_file_sp;
+}
+
 UnwindPlanSP FuncUnwinders::GetEHFrameUnwindPlan(Target &target) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame)
@@ -185,6 +208,38 @@
   return m_unwind_plan_symbol_file_sp;
 }
 
+UnwindPlanSP
+FuncUnwinders::GetObjectFileAugmentedUnwindPlan(Target &target,
+                                                     Thread &thread) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  if (m_unwind_plan_object_file_augmented_sp.get() ||
+      m_tried_unwind_plan_object_file_augmented)
+    return m_unwind_plan_object_file_augmented_sp;
+
+  m_tried_unwind_plan_object_file_augmented = true;
+
+  UnwindPlanSP object_file_unwind_plan = GetObjectFileUnwindPlan(target);
+  if (!object_file_unwind_plan)
+    return m_unwind_plan_object_file_augmented_sp;
+
+  m_unwind_plan_object_file_augmented_sp =
+      std::make_shared<UnwindPlan>(*object_file_unwind_plan);
+
+  // Augment the instructions with epilogue descriptions if necessary
+  // so the UnwindPlan can be used at any instruction in the function.
+
+  UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
+  if (assembly_profiler_sp) {
+    if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
+            m_range, thread, *m_unwind_plan_object_file_augmented_sp)) {
+      m_unwind_plan_object_file_augmented_sp.reset();
+    }
+  } else {
+    m_unwind_plan_object_file_augmented_sp.reset();
+  }
+  return m_unwind_plan_object_file_augmented_sp;
+}
+
 UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target,
                                                           Thread &thread) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
@@ -328,6 +383,8 @@
   UnwindPlanSP eh_frame_sp = GetEHFrameUnwindPlan(target);
   if (!eh_frame_sp)
     eh_frame_sp = GetDebugFrameUnwindPlan(target);
+  if (!eh_frame_sp)
+    eh_frame_sp = GetObjectFileUnwindPlan(target);
   UnwindPlanSP arch_default_at_entry_sp =
       GetUnwindPlanArchitectureDefaultAtFunctionEntry(thread);
   UnwindPlanSP arch_default_sp = GetUnwindPlanArchitectureDefault(thread);
@@ -366,6 +423,8 @@
     return plan_sp;
   if (UnwindPlanSP plan_sp = GetEHFrameAugmentedUnwindPlan(target, thread))
     return plan_sp;
+  if (UnwindPlanSP plan_sp = GetObjectFileAugmentedUnwindPlan(target, thread))
+    return plan_sp;
 
   return assembly_sp;
 }
@@ -473,6 +532,9 @@
   if (unwind_plan_sp.get() == nullptr) {
     unwind_plan_sp = GetCompactUnwindUnwindPlan(target);
   }
+  if (unwind_plan_sp.get() == nullptr) {
+    unwind_plan_sp = GetObjectFileUnwindPlan(target);
+  }
   if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid()) {
     lsda_addr = unwind_plan_sp->GetLSDAAddress();
   }
@@ -486,6 +548,9 @@
   if (unwind_plan_sp.get() == nullptr) {
     unwind_plan_sp = GetCompactUnwindUnwindPlan(target);
   }
+  if (unwind_plan_sp.get() == nullptr) {
+    unwind_plan_sp = GetObjectFileUnwindPlan(target);
+  }
   if (unwind_plan_sp.get() &&
       unwind_plan_sp->GetPersonalityFunctionPtr().IsValid()) {
     personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr();
Index: lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -12,6 +12,7 @@
 #include "lldb/Core/Value.h"
 #include "lldb/Expression/DWARFExpression.h"
 #include "lldb/Symbol/ArmUnwindInfo.h"
+#include "lldb/Symbol/CallFrameInfo.h"
 #include "lldb/Symbol/DWARFCallFrameInfo.h"
 #include "lldb/Symbol/FuncUnwinders.h"
 #include "lldb/Symbol/Function.h"
@@ -783,6 +784,16 @@
         unwind_plan_sp.reset();
     }
 
+    CallFrameInfo *object_file_unwind =
+        pc_module_sp->GetUnwindTable().GetObjectFileUnwindInfo();
+    if (object_file_unwind) {
+      unwind_plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
+      if (object_file_unwind->GetUnwindPlan(m_current_pc, *unwind_plan_sp))
+        return unwind_plan_sp;
+      else
+        unwind_plan_sp.reset();
+    }
+
     return arch_default_unwind_plan_sp;
   }
 
@@ -795,6 +806,9 @@
     m_fast_unwind_plan_sp.reset();
     unwind_plan_sp =
         func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget());
+    if (!unwind_plan_sp)
+      unwind_plan_sp =
+          func_unwinders_sp->GetObjectFileUnwindPlan(process->GetTarget());
     if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc) &&
         unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) {
       return unwind_plan_sp;
@@ -817,6 +831,9 @@
     // intend) or compact unwind (this won't work)
     unwind_plan_sp =
         func_unwinders_sp->GetEHFrameUnwindPlan(process->GetTarget());
+    if (!unwind_plan_sp)
+      unwind_plan_sp =
+          func_unwinders_sp->GetObjectFileUnwindPlan(process->GetTarget());
     if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) {
       UnwindLogMsgVerbose("frame uses %s for full UnwindPlan because the "
                           "DynamicLoader suggested we prefer it",
Index: lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.h
===================================================================
--- /dev/null
+++ 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_
Index: lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp
===================================================================
--- /dev/null
+++ 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;
+}
Index: lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
===================================================================
--- lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
+++ lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
@@ -135,7 +135,14 @@
 
   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 @@
   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 {
Index: lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ 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"
@@ -514,7 +515,26 @@
   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.
@@ -537,6 +557,15 @@
   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) {
@@ -674,14 +703,8 @@
         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
@@ -736,6 +759,19 @@
   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;
Index: lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt
+++ lldb/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_lldb_library(lldbPluginObjectFilePECOFF PLUGIN
   ObjectFilePECOFF.cpp
+  PECallFrameInfo.cpp
   WindowsMiniDump.cpp
 
   LINK_LIBS
Index: lldb/source/Commands/CommandObjectTarget.cpp
===================================================================
--- lldb/source/Commands/CommandObjectTarget.cpp
+++ lldb/source/Commands/CommandObjectTarget.cpp
@@ -3447,6 +3447,25 @@
         result.GetOutputStream().Printf("\n");
       }
 
+      UnwindPlanSP of_unwind_sp =
+          func_unwinders_sp->GetObjectFileUnwindPlan(*target);
+      if (of_unwind_sp) {
+        result.GetOutputStream().Printf("object file UnwindPlan:\n");
+        of_unwind_sp->Dump(result.GetOutputStream(), thread.get(),
+                           LLDB_INVALID_ADDRESS);
+        result.GetOutputStream().Printf("\n");
+      }
+
+      UnwindPlanSP of_unwind_augmented_sp =
+          func_unwinders_sp->GetObjectFileAugmentedUnwindPlan(*target,
+                                                              *thread);
+      if (of_unwind_augmented_sp) {
+        result.GetOutputStream().Printf("object file augmented UnwindPlan:\n");
+        of_unwind_augmented_sp->Dump(result.GetOutputStream(), thread.get(),
+                                     LLDB_INVALID_ADDRESS);
+        result.GetOutputStream().Printf("\n");
+      }
+
       UnwindPlanSP ehframe_sp =
           func_unwinders_sp->GetEHFrameUnwindPlan(*target);
       if (ehframe_sp) {
Index: lldb/include/lldb/lldb-forward.h
===================================================================
--- lldb/include/lldb/lldb-forward.h
+++ lldb/include/lldb/lldb-forward.h
@@ -44,6 +44,7 @@
 class BroadcastEventSpec;
 class Broadcaster;
 class BroadcasterManager;
+class CallFrameInfo;
 class ClangASTContext;
 class ClangASTImporter;
 class ClangASTMetadata;
Index: lldb/include/lldb/Symbol/UnwindTable.h
===================================================================
--- lldb/include/lldb/Symbol/UnwindTable.h
+++ lldb/include/lldb/Symbol/UnwindTable.h
@@ -27,6 +27,8 @@
 
   ~UnwindTable();
 
+  lldb_private::CallFrameInfo *GetObjectFileUnwindInfo();
+
   lldb_private::DWARFCallFrameInfo *GetEHFrameInfo();
   lldb_private::DWARFCallFrameInfo *GetDebugFrameInfo();
 
@@ -71,6 +73,7 @@
   bool m_initialized; // delay some initialization until ObjectFile is set up
   std::mutex m_mutex;
 
+  std::unique_ptr<CallFrameInfo> m_object_file_unwind_up;
   std::unique_ptr<DWARFCallFrameInfo> m_eh_frame_up;
   std::unique_ptr<DWARFCallFrameInfo> m_debug_frame_up;
   std::unique_ptr<CompactUnwindInfo> m_compact_unwind_up;
Index: lldb/include/lldb/Symbol/ObjectFile.h
===================================================================
--- lldb/include/lldb/Symbol/ObjectFile.h
+++ lldb/include/lldb/Symbol/ObjectFile.h
@@ -650,6 +650,9 @@
   /// \return
   virtual std::vector<LoadableData> GetLoadableData(Target &target);
 
+  /// Creates a plugin-specific call frame info
+  virtual std::unique_ptr<CallFrameInfo> CreateCallFrameInfo();
+
 protected:
   // Member variables.
   FileSpec m_file;
Index: lldb/include/lldb/Symbol/FuncUnwinders.h
===================================================================
--- lldb/include/lldb/Symbol/FuncUnwinders.h
+++ lldb/include/lldb/Symbol/FuncUnwinders.h
@@ -76,6 +76,11 @@
 
   lldb::UnwindPlanSP GetAssemblyUnwindPlan(Target &target, Thread &thread);
 
+  lldb::UnwindPlanSP GetObjectFileUnwindPlan(Target &target);
+
+  lldb::UnwindPlanSP GetObjectFileAugmentedUnwindPlan(Target &target,
+                                                      Thread &thread);
+
   lldb::UnwindPlanSP GetEHFrameUnwindPlan(Target &target);
 
   lldb::UnwindPlanSP GetEHFrameAugmentedUnwindPlan(Target &target,
@@ -113,10 +118,12 @@
   std::recursive_mutex m_mutex;
 
   lldb::UnwindPlanSP m_unwind_plan_assembly_sp;
+  lldb::UnwindPlanSP m_unwind_plan_object_file_sp;
   lldb::UnwindPlanSP m_unwind_plan_eh_frame_sp;
   lldb::UnwindPlanSP m_unwind_plan_debug_frame_sp;
 
   // augmented by assembly inspection so it's valid everywhere
+  lldb::UnwindPlanSP m_unwind_plan_object_file_augmented_sp;
   lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp;
   lldb::UnwindPlanSP m_unwind_plan_debug_frame_augmented_sp;
 
@@ -130,7 +137,9 @@
   // Fetching the UnwindPlans can be expensive - if we've already attempted to
   // get one & failed, don't try again.
   bool m_tried_unwind_plan_assembly : 1, m_tried_unwind_plan_eh_frame : 1,
+      m_tried_unwind_plan_object_file : 1,
       m_tried_unwind_plan_debug_frame : 1,
+      m_tried_unwind_plan_object_file_augmented : 1,
       m_tried_unwind_plan_eh_frame_augmented : 1,
       m_tried_unwind_plan_debug_frame_augmented : 1,
       m_tried_unwind_plan_compact_unwind : 1,
Index: lldb/include/lldb/Symbol/CallFrameInfo.h
===================================================================
--- /dev/null
+++ lldb/include/lldb/Symbol/CallFrameInfo.h
@@ -0,0 +1,28 @@
+//===-- CallFrameInfo.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_CallFrameInfo_h_
+#define liblldb_CallFrameInfo_h_
+
+#include "lldb/Core/Address.h"
+
+namespace lldb_private {
+
+class CallFrameInfo {
+public:
+  virtual ~CallFrameInfo() = default;
+
+  virtual bool GetAddressRange(Address addr, AddressRange &range) = 0;
+
+  virtual bool GetUnwindPlan(const Address &addr, UnwindPlan &unwind_plan) = 0;
+  virtual bool GetUnwindPlan(const AddressRange &range, UnwindPlan &unwind_plan) = 0;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CallFrameInfo_h_
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to