1//===-- SymbolVendorPECOFF.cpp --------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SymbolVendorPECOFF.h"
10
11#include <cstring>
12
13#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
14#include "lldb/Core/Module.h"
15#include "lldb/Core/ModuleSpec.h"
16#include "lldb/Core/PluginManager.h"
17#include "lldb/Core/Section.h"
18#include "lldb/Host/Host.h"
19#include "lldb/Symbol/ObjectFile.h"
20#include "lldb/Target/Target.h"
21#include "lldb/Utility/StreamString.h"
22#include "lldb/Utility/Timer.h"
23
24using namespace lldb;
25using namespace lldb_private;
26
27LLDB_PLUGIN_DEFINE(SymbolVendorPECOFF)
28
29// SymbolVendorPECOFF constructor
30SymbolVendorPECOFF::SymbolVendorPECOFF(const lldb::ModuleSP &module_sp)
31    : SymbolVendor(module_sp) {}
32
33void SymbolVendorPECOFF::Initialize() {
34  PluginManager::RegisterPlugin(GetPluginNameStatic(),
35                                GetPluginDescriptionStatic(), CreateInstance);
36}
37
38void SymbolVendorPECOFF::Terminate() {
39  PluginManager::UnregisterPlugin(CreateInstance);
40}
41
42llvm::StringRef SymbolVendorPECOFF::GetPluginDescriptionStatic() {
43  return "Symbol vendor for PE/COFF that looks for dSYM files that match "
44         "executables.";
45}
46
47// CreateInstance
48//
49// Platforms can register a callback to use when creating symbol vendors to
50// allow for complex debug information file setups, and to also allow for
51// finding separate debug information files.
52SymbolVendor *
53SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP &module_sp,
54                                   lldb_private::Stream *feedback_strm) {
55  if (!module_sp)
56    return nullptr;
57
58  ObjectFilePECOFF *obj_file =
59      llvm::dyn_cast_or_null<ObjectFilePECOFF>(module_sp->GetObjectFile());
60  if (!obj_file)
61    return nullptr;
62
63  lldb_private::UUID uuid = obj_file->GetUUID();
64  if (!uuid)
65    return nullptr;
66
67  // If the main object file already contains debug info, then we are done.
68  if (obj_file->GetSectionList()->FindSectionByType(
69          lldb::eSectionTypeDWARFDebugInfo, true))
70    return nullptr;
71
72  // If the module specified a filespec, use that.
73  FileSpec fspec = module_sp->GetSymbolFileFileSpec();
74  // Otherwise, try gnu_debuglink, if one exists.
75  if (!fspec)
76    fspec = obj_file->GetDebugLink().value_or(FileSpec());
77
78  LLDB_SCOPED_TIMERF("SymbolVendorPECOFF::CreateInstance (module = %s)",
79                     module_sp->GetFileSpec().GetPath().c_str());
80
81  ModuleSpec module_spec;
82
83  module_spec.GetFileSpec() = obj_file->GetFileSpec();
84  FileSystem::Instance().Resolve(module_spec.GetFileSpec());
85  module_spec.GetSymbolFileSpec() = fspec;
86  module_spec.GetUUID() = uuid;
87  FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
88  FileSpec dsym_fspec =
89      PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
90  if (!dsym_fspec)
91    return nullptr;
92
93  DataBufferSP dsym_file_data_sp;
94  lldb::offset_t dsym_file_data_offset = 0;
95  ObjectFileSP dsym_objfile_sp = ObjectFile::FindPlugin(
96      module_sp, &dsym_fspec, 0, FileSystem::Instance().GetByteSize(dsym_fspec),
97      dsym_file_data_sp, dsym_file_data_offset);
98  if (!dsym_objfile_sp)
99    return nullptr;
100
101  // This objfile is for debugging purposes.
102  dsym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo);
103
104  // Get the module unified section list and add our debug sections to
105  // that.
106  SectionList *module_section_list = module_sp->GetSectionList();
107  SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList();
108  if (!objfile_section_list || !module_section_list)
109    return nullptr;
110
111  static const SectionType g_sections[] = {
112      eSectionTypeDWARFDebugAbbrev,   eSectionTypeDWARFDebugAranges,
113      eSectionTypeDWARFDebugFrame,    eSectionTypeDWARFDebugInfo,
114      eSectionTypeDWARFDebugLine,     eSectionTypeDWARFDebugLoc,
115      eSectionTypeDWARFDebugLocLists, eSectionTypeDWARFDebugMacInfo,
116      eSectionTypeDWARFDebugNames,    eSectionTypeDWARFDebugPubNames,
117      eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges,
118      eSectionTypeDWARFDebugStr,      eSectionTypeDWARFDebugTypes,
119  };
120  for (SectionType section_type : g_sections) {
121    if (SectionSP section_sp =
122            objfile_section_list->FindSectionByType(section_type, true)) {
123      if (SectionSP module_section_sp =
124              module_section_list->FindSectionByType(section_type, true))
125        module_section_list->ReplaceSection(module_section_sp->GetID(),
126                                            section_sp);
127      else
128        module_section_list->AddSection(section_sp);
129    }
130  }
131
132  SymbolVendorPECOFF *symbol_vendor = new SymbolVendorPECOFF(module_sp);
133  symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
134  return symbol_vendor;
135}
136