alvinhochun updated this revision to Diff 434568.
alvinhochun edited the summary of this revision.
alvinhochun added a comment.

Addressed comments, added CRC checking for debuglink (only applies if the 
object does not contain a PDB build id) and added tests for this.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D126367

Files:
  lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
  lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
  lldb/source/Plugins/SymbolVendor/CMakeLists.txt
  lldb/source/Plugins/SymbolVendor/PECOFF/CMakeLists.txt
  lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
  lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.h
  lldb/source/Symbol/LocateSymbolFile.cpp
  lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-i686.yaml
  lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-mismatched-crc.yaml
  lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-pdb-buildid.yaml
  lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink.yaml

Index: lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink.yaml
@@ -0,0 +1,50 @@
+# This test produces a stripped version of the object file and adds a
+# gnu-debuglink section to it linking to the unstripped version of the object
+# file. The debug info shall be loaded from the gnu-debuglink reference.
+
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t %t %t.stripped
+# RUN: lldb-test object-file %t.stripped | FileCheck %s
+
+# CHECK: Name: .debug_info
+# CHECK-NEXT: Type: dwarf-info
+
+--- !COFF
+OptionalHeader:
+  AddressOfEntryPoint: 5152
+  ImageBase:       5368709120
+  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, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ]
+  SizeOfStackReserve: 1048576
+  SizeOfStackCommit: 4096
+  SizeOfHeapReserve: 1048576
+  SizeOfHeapCommit: 4096
+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:     64
+    SectionData:     DEADBEEFBAADF00D
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  8192
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+  - Name:            .debug_info
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  16384
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+symbols:         []
+...
Index: lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-pdb-buildid.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-pdb-buildid.yaml
@@ -0,0 +1,63 @@
+# This test produces a stripped version of the object file and adds a
+# gnu-debuglink section to it linking to the unstripped version of the object
+# file. Then the unstripped version is stripped to keep only debug info to
+# cause its crc to change. In this case the object files still have the
+# synthetic PDB build id that LLD adds even for the mingw target. Because this
+# build id still matches, the debug info shall still be loaded from the
+# gnu-debuglink reference.
+
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t %t %t.stripped
+# RUN: llvm-strip --only-keep-debug %t
+# RUN: lldb-test object-file %t.stripped | FileCheck %s
+
+# CHECK: Name: .debug_info
+# CHECK-NEXT: Type: dwarf-info
+
+--- !COFF
+OptionalHeader:
+  AddressOfEntryPoint: 5152
+  ImageBase:       5368709120
+  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, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ]
+  SizeOfStackReserve: 1048576
+  SizeOfStackCommit: 4096
+  SizeOfHeapReserve: 1048576
+  SizeOfHeapCommit: 4096
+  Debug:
+    RelativeVirtualAddress: 16384
+    Size:            28
+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:     64
+    SectionData:     DEADBEEFBAADF00D
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  8192
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+  - Name:            .buildid
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  16384
+    VirtualSize:     53
+    SectionData:     00000000E5038E620000000002000000190000001C4000001C300000525344534674A52A37FB4C784C4C44205044422E0100000000
+  - Name:            .debug_info
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  20480
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+symbols:         []
+...
Index: lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-mismatched-crc.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-mismatched-crc.yaml
@@ -0,0 +1,52 @@
+# This test produces a stripped version of the object file and adds a
+# gnu-debuglink section to it linking to the unstripped version of the object
+# file. Then the unstripped version is stripped to keep only debug info to
+# cause its crc to change. In this case the debug info shall not be loaded.
+
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t %t %t.stripped
+# RUN: llvm-strip --only-keep-debug %t
+# RUN: lldb-test object-file %t.stripped | FileCheck %s
+
+# CHECK-NOT: Name: .debug_info
+# CHECK-NOT: Type: dwarf-info
+
+--- !COFF
+OptionalHeader:
+  AddressOfEntryPoint: 5152
+  ImageBase:       5368709120
+  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, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ]
+  SizeOfStackReserve: 1048576
+  SizeOfStackCommit: 4096
+  SizeOfHeapReserve: 1048576
+  SizeOfHeapCommit: 4096
+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:     64
+    SectionData:     DEADBEEFBAADF00D
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  8192
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+  - Name:            .debug_info
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  16384
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+symbols:         []
+...
Index: lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-i686.yaml
===================================================================
--- /dev/null
+++ lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-i686.yaml
@@ -0,0 +1,55 @@
+# This test produces a stripped version of the object file and adds a
+# gnu-debuglink section to it linking to the unstripped version of the object
+# file. The debug info shall be loaded from the gnu-debuglink reference.
+#
+# This test is added to check that Symbols::LocateExecutableSymbolFile (in
+# LocateSymbolFile.cpp) can handle ObjectFilePECOFF::GetModuleSpecifications
+# returning two different module specs for MachineX86 -- "i386-pc-windows" and
+# "i686-pc-windows".
+
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t %t %t.stripped
+# RUN: lldb-test object-file %t.stripped | FileCheck %s
+
+# CHECK: Name: .debug_info
+# CHECK-NEXT: Type: dwarf-info
+
+--- !COFF
+OptionalHeader:
+  AddressOfEntryPoint: 4480
+  ImageBase:       268435456
+  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_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE ]
+  SizeOfStackReserve: 1048576
+  SizeOfStackCommit: 4096
+  SizeOfHeapReserve: 1048576
+  SizeOfHeapCommit: 4096
+header:
+  Machine:         IMAGE_FILE_MACHINE_I386
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_32BIT_MACHINE ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  4096
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  8192
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+  - Name:            .debug_info
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  16384
+    VirtualSize:     64
+    SectionData:     DEADBEEFBAADF00D
+symbols:         []
+...
Index: lldb/source/Symbol/LocateSymbolFile.cpp
===================================================================
--- lldb/source/Symbol/LocateSymbolFile.cpp
+++ lldb/source/Symbol/LocateSymbolFile.cpp
@@ -362,18 +362,34 @@
         lldb_private::ModuleSpecList specs;
         const size_t num_specs =
             ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs);
-        assert(num_specs <= 1 &&
-               "Symbol Vendor supports only a single architecture");
-        if (num_specs == 1) {
-          ModuleSpec mspec;
-          if (specs.GetModuleSpecAtIndex(0, mspec)) {
-            // Skip the uuids check if module_uuid is invalid. For example,
-            // this happens for *.dwp files since at the moment llvm-dwp
-            // doesn't output build ids, nor does binutils dwp.
-            if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID())
-              return file_spec;
+        ModuleSpec mspec;
+        bool valid_mspec = false;
+        if (num_specs == 2) {
+          // Special case to handle both i386 and i686 from ObjectFilePECOFF
+          ModuleSpec mspec2;
+          if (specs.GetModuleSpecAtIndex(0, mspec) &&
+              specs.GetModuleSpecAtIndex(1, mspec2) &&
+              mspec.GetArchitecture().GetTriple().isCompatibleWith(
+                  mspec2.GetArchitecture().GetTriple())) {
+            valid_mspec = true;
           }
         }
+        if (!valid_mspec) {
+          assert(num_specs <= 1 &&
+                 "Symbol Vendor supports only a single architecture");
+          if (num_specs == 1) {
+            if (specs.GetModuleSpecAtIndex(0, mspec)) {
+              valid_mspec = true;
+            }
+          }
+        }
+        if (valid_mspec) {
+          // Skip the uuids check if module_uuid is invalid. For example,
+          // this happens for *.dwp files since at the moment llvm-dwp
+          // doesn't output build ids, nor does binutils dwp.
+          if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID())
+            return file_spec;
+        }
       }
     }
   }
Index: lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.h
@@ -0,0 +1,37 @@
+//===-- SymbolVendorPECOFF.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 LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_PECOFF_SYMBOLVENDORPECOFF_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_PECOFF_SYMBOLVENDORPECOFF_H
+
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/lldb-private.h"
+
+class SymbolVendorPECOFF : public lldb_private::SymbolVendor {
+public:
+  // Constructors and Destructors
+  SymbolVendorPECOFF(const lldb::ModuleSP &module_sp);
+
+  // Static Functions
+  static void Initialize();
+
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() { return "PE-COFF"; }
+
+  static llvm::StringRef GetPluginDescriptionStatic();
+
+  static lldb_private::SymbolVendor *
+  CreateInstance(const lldb::ModuleSP &module_sp,
+                 lldb_private::Stream *feedback_strm);
+
+  // PluginInterface protocol
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+};
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_PECOFF_SYMBOLVENDORPECOFF_H
Index: lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
@@ -0,0 +1,135 @@
+//===-- SymbolVendorPECOFF.cpp --------------------------------------------===//
+//
+// 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 "SymbolVendorPECOFF.h"
+
+#include <cstring>
+
+#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/LocateSymbolFile.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/Timer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(SymbolVendorPECOFF)
+
+// SymbolVendorPECOFF constructor
+SymbolVendorPECOFF::SymbolVendorPECOFF(const lldb::ModuleSP &module_sp)
+    : SymbolVendor(module_sp) {}
+
+void SymbolVendorPECOFF::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void SymbolVendorPECOFF::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef SymbolVendorPECOFF::GetPluginDescriptionStatic() {
+  return "Symbol vendor for PE/COFF that looks for dSYM files that match "
+         "executables.";
+}
+
+// CreateInstance
+//
+// Platforms can register a callback to use when creating symbol vendors to
+// allow for complex debug information file setups, and to also allow for
+// finding separate debug information files.
+SymbolVendor *
+SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP &module_sp,
+                                   lldb_private::Stream *feedback_strm) {
+  if (!module_sp)
+    return nullptr;
+
+  ObjectFilePECOFF *obj_file =
+      llvm::dyn_cast_or_null<ObjectFilePECOFF>(module_sp->GetObjectFile());
+  if (!obj_file)
+    return nullptr;
+
+  lldb_private::UUID uuid = obj_file->GetUUID();
+  if (!uuid)
+    return nullptr;
+
+  // If the main object file already contains debug info, then we are done.
+  if (obj_file->GetSectionList()->FindSectionByType(
+          lldb::eSectionTypeDWARFDebugInfo, true))
+    return nullptr;
+
+  // If the module specified a filespec, use that.
+  FileSpec fspec = module_sp->GetSymbolFileFileSpec();
+  // Otherwise, try gnu_debuglink, if one exists.
+  if (!fspec)
+    fspec = obj_file->GetDebugLink().getValueOr(FileSpec());
+
+  LLDB_SCOPED_TIMERF("SymbolVendorPECOFF::CreateInstance (module = %s)",
+                     module_sp->GetFileSpec().GetPath().c_str());
+
+  ModuleSpec module_spec;
+
+  module_spec.GetFileSpec() = obj_file->GetFileSpec();
+  FileSystem::Instance().Resolve(module_spec.GetFileSpec());
+  module_spec.GetSymbolFileSpec() = fspec;
+  module_spec.GetUUID() = uuid;
+  FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
+  FileSpec dsym_fspec =
+      Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+  if (!dsym_fspec)
+    return nullptr;
+
+  DataBufferSP dsym_file_data_sp;
+  lldb::offset_t dsym_file_data_offset = 0;
+  ObjectFileSP dsym_objfile_sp = ObjectFile::FindPlugin(
+      module_sp, &dsym_fspec, 0, FileSystem::Instance().GetByteSize(dsym_fspec),
+      dsym_file_data_sp, dsym_file_data_offset);
+  if (!dsym_objfile_sp)
+    return nullptr;
+
+  // This objfile is for debugging purposes.
+  dsym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo);
+
+  SymbolVendorPECOFF *symbol_vendor = new SymbolVendorPECOFF(module_sp);
+
+  // Get the module unified section list and add our debug sections to
+  // that.
+  SectionList *module_section_list = module_sp->GetSectionList();
+  SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList();
+
+  static const SectionType g_sections[] = {
+      eSectionTypeDWARFDebugAbbrev,   eSectionTypeDWARFDebugAranges,
+      eSectionTypeDWARFDebugFrame,    eSectionTypeDWARFDebugInfo,
+      eSectionTypeDWARFDebugLine,     eSectionTypeDWARFDebugLoc,
+      eSectionTypeDWARFDebugLocLists, eSectionTypeDWARFDebugMacInfo,
+      eSectionTypeDWARFDebugNames,    eSectionTypeDWARFDebugPubNames,
+      eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges,
+      eSectionTypeDWARFDebugStr,      eSectionTypeDWARFDebugTypes,
+  };
+  for (SectionType section_type : g_sections) {
+    if (SectionSP section_sp =
+            objfile_section_list->FindSectionByType(section_type, true)) {
+      if (SectionSP module_section_sp =
+              module_section_list->FindSectionByType(section_type, true))
+        module_section_list->ReplaceSection(module_section_sp->GetID(),
+                                            section_sp);
+      else
+        module_section_list->AddSection(section_sp);
+    }
+  }
+
+  symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
+  return symbol_vendor;
+}
Index: lldb/source/Plugins/SymbolVendor/PECOFF/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/SymbolVendor/PECOFF/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lldb_library(lldbPluginSymbolVendorPECOFF PLUGIN
+  SymbolVendorPECOFF.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbHost
+    lldbSymbol
+    lldbPluginObjectFilePECOFF
+  )
Index: lldb/source/Plugins/SymbolVendor/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/SymbolVendor/CMakeLists.txt
+++ lldb/source/Plugins/SymbolVendor/CMakeLists.txt
@@ -4,4 +4,5 @@
   add_subdirectory(MacOSX)
 endif()
 
+add_subdirectory(PECOFF)
 add_subdirectory(wasm)
Index: lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
===================================================================
--- lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
+++ lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
@@ -119,6 +119,10 @@
 
   lldb_private::UUID GetUUID() override;
 
+  /// Return the contents of the .gnu_debuglink section, if the object file
+  /// contains it.
+  llvm::Optional<lldb_private::FileSpec> GetDebugLink();
+
   uint32_t GetDependentModules(lldb_private::FileSpecList &files) override;
 
   lldb_private::Address GetEntryPointAddress() override;
Index: lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
@@ -31,6 +31,7 @@
 #include "llvm/BinaryFormat/COFF.h"
 
 #include "llvm/Object/COFFImportFile.h"
+#include "llvm/Support/CRC.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MemoryBuffer.h"
 
@@ -44,10 +45,42 @@
 
 LLDB_PLUGIN_DEFINE(ObjectFilePECOFF)
 
+static bool GetDebugLinkContents(const llvm::object::COFFObjectFile &coff_obj,
+                                 std::string &gnu_debuglink_file,
+                                 uint32_t &gnu_debuglink_crc) {
+  static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink");
+  for (const auto &section : coff_obj.sections()) {
+    auto name = section.getName();
+    if (!name) {
+      llvm::consumeError(name.takeError());
+      continue;
+    }
+    if (*name == g_sect_name_gnu_debuglink.GetStringRef()) {
+      auto content = section.getContents();
+      if (!content) {
+        llvm::consumeError(content.takeError());
+        return false;
+      }
+      DataExtractor data(
+          content->data(), content->size(),
+          coff_obj.isLittleEndian() ? eByteOrderLittle : eByteOrderBig, 0);
+      lldb::offset_t gnu_debuglink_offset = 0;
+      gnu_debuglink_file = data.GetCStr(&gnu_debuglink_offset);
+      // Align to the next 4-byte offset
+      gnu_debuglink_offset = llvm::alignTo(gnu_debuglink_offset, 4);
+      data.GetU32(&gnu_debuglink_offset, &gnu_debuglink_crc, 1);
+      return true;
+    }
+  }
+  return false;
+}
+
 static UUID GetCoffUUID(llvm::object::COFFObjectFile &coff_obj) {
   const llvm::codeview::DebugInfo *pdb_info = nullptr;
   llvm::StringRef pdb_file;
 
+  // First, prefer to use the PDB build id. LLD generates this even for mingw
+  // targets without PDB output, and it does not get stripped either.
   if (!coff_obj.getDebugPDBInfo(pdb_info, pdb_file) && pdb_info) {
     if (pdb_info->PDB70.CVSignature == llvm::OMF::Signature::PDB70) {
       UUID::CvRecordPdb70 info;
@@ -57,7 +90,26 @@
     }
   }
 
-  return UUID();
+  std::string gnu_debuglink_file;
+  uint32_t gnu_debuglink_crc;
+
+  // The GNU linker does not write a PDB build id, so we should fall back to
+  // using the crc from .gnu_debuglink if it exists, just like how ObjectFileELF
+  // does it.
+  if (!GetDebugLinkContents(coff_obj, gnu_debuglink_file, gnu_debuglink_crc)) {
+    // If there is no .gnu_debuglink section, then this may be an object
+    // containing DWARF debug info for .gnu_debuglink, so calculate the crc of
+    // the object itself.
+    auto raw_data = coff_obj.getData();
+    LLDB_SCOPED_TIMERF(
+        "Calculating module crc32 %s with size %" PRIu64 " KiB",
+        FileSpec(coff_obj.getFileName()).GetLastPathComponent().AsCString(),
+        static_cast<lldb::offset_t>(raw_data.size()) / 1024);
+    gnu_debuglink_crc = llvm::crc32(0, llvm::arrayRefFromStringRef(raw_data));
+  }
+  // Use 4 bytes of crc from the .gnu_debuglink section.
+  llvm::support::ulittle32_t data(gnu_debuglink_crc);
+  return UUID::fromData(&data, sizeof(data));
 }
 
 char ObjectFilePECOFF::ID;
@@ -870,6 +922,15 @@
   return m_uuid;
 }
 
+llvm::Optional<FileSpec> ObjectFilePECOFF::GetDebugLink() {
+  std::string gnu_debuglink_file;
+  uint32_t gnu_debuglink_crc;
+  if (GetDebugLinkContents(*m_binary, gnu_debuglink_file, gnu_debuglink_crc)) {
+    return FileSpec(gnu_debuglink_file);
+  }
+  return llvm::None;
+}
+
 uint32_t ObjectFilePECOFF::ParseDependentModules() {
   ModuleSP module_sp(GetModule());
   if (!module_sp)
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to