1//===-- ObjectFileCOFF.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 "ObjectFileCOFF.h"
10
11#include "lldb/Core/Module.h"
12#include "lldb/Core/ModuleSpec.h"
13#include "lldb/Core/PluginManager.h"
14#include "lldb/Utility/LLDBLog.h"
15
16#include "llvm/Support/Error.h"
17#include "llvm/Support/FormatAdapters.h"
18
19using namespace lldb;
20using namespace lldb_private;
21
22using namespace llvm;
23using namespace llvm::object;
24
25static bool IsCOFFObjectFile(const DataBufferSP &data) {
26 return identify_magic(magic: toStringRef(Input: data->GetData())) ==
27 file_magic::coff_object;
28}
29
30LLDB_PLUGIN_DEFINE(ObjectFileCOFF)
31
32char ObjectFileCOFF::ID;
33
34ObjectFileCOFF::~ObjectFileCOFF() = default;
35
36void ObjectFileCOFF::Initialize() {
37 PluginManager::RegisterPlugin(name: GetPluginNameStatic(),
38 description: GetPluginDescriptionStatic(), create_callback: CreateInstance,
39 create_memory_callback: CreateMemoryInstance, get_module_specifications: GetModuleSpecifications);
40}
41
42void ObjectFileCOFF::Terminate() {
43 PluginManager::UnregisterPlugin(create_callback: CreateInstance);
44}
45
46lldb_private::ObjectFile *
47ObjectFileCOFF::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,
48 offset_t data_offset, const FileSpec *file,
49 offset_t file_offset, offset_t length) {
50 Log *log = GetLog(mask: LLDBLog::Object);
51
52 if (!data_sp) {
53 data_sp = MapFileData(file: *file, Size: length, Offset: file_offset);
54 if (!data_sp) {
55 LLDB_LOG(log,
56 "Failed to create ObjectFileCOFF instance: cannot read file {0}",
57 file->GetPath());
58 return nullptr;
59 }
60 data_offset = 0;
61 }
62
63 assert(data_sp && "must have mapped file at this point");
64
65 if (!IsCOFFObjectFile(data: data_sp))
66 return nullptr;
67
68 if (data_sp->GetByteSize() < length) {
69 data_sp = MapFileData(file: *file, Size: length, Offset: file_offset);
70 if (!data_sp) {
71 LLDB_LOG(log,
72 "Failed to create ObjectFileCOFF instance: cannot read file {0}",
73 file->GetPath());
74 return nullptr;
75 }
76 data_offset = 0;
77 }
78
79
80 MemoryBufferRef buffer{toStringRef(Input: data_sp->GetData()),
81 file->GetFilename().GetStringRef()};
82
83 Expected<std::unique_ptr<Binary>> binary = createBinary(Source: buffer);
84 if (!binary) {
85 LLDB_LOG_ERROR(log, binary.takeError(),
86 "Failed to create binary for file ({1}): {0}",
87 file->GetPath());
88 return nullptr;
89 }
90
91 LLDB_LOG(log, "ObjectFileCOFF::ObjectFileCOFF module = {1} ({2}), file = {3}",
92 module_sp.get(), module_sp->GetSpecificationDescription(),
93 file->GetPath());
94
95 return new ObjectFileCOFF(unique_dyn_cast<COFFObjectFile>(Val: std::move(*binary)),
96 module_sp, data_sp, data_offset, file, file_offset,
97 length);
98}
99
100lldb_private::ObjectFile *ObjectFileCOFF::CreateMemoryInstance(
101 const ModuleSP &module_sp, WritableDataBufferSP data_sp,
102 const ProcessSP &process_sp, addr_t header) {
103 // FIXME: do we need to worry about construction from a memory region?
104 return nullptr;
105}
106
107size_t ObjectFileCOFF::GetModuleSpecifications(
108 const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
109 offset_t file_offset, offset_t length, ModuleSpecList &specs) {
110 if (!IsCOFFObjectFile(data: data_sp))
111 return 0;
112
113 MemoryBufferRef buffer{toStringRef(Input: data_sp->GetData()),
114 file.GetFilename().GetStringRef()};
115 Expected<std::unique_ptr<Binary>> binary = createBinary(Source: buffer);
116 if (!binary) {
117 Log *log = GetLog(mask: LLDBLog::Object);
118 LLDB_LOG_ERROR(log, binary.takeError(),
119 "Failed to create binary for file ({1}): {0}",
120 file.GetFilename());
121 return 0;
122 }
123
124 std::unique_ptr<COFFObjectFile> object =
125 unique_dyn_cast<COFFObjectFile>(Val: std::move(*binary));
126 switch (static_cast<COFF::MachineTypes>(object->getMachine())) {
127 case COFF::IMAGE_FILE_MACHINE_I386:
128 specs.Append(spec: ModuleSpec(file, ArchSpec("i686-unknown-windows-msvc")));
129 return 1;
130 case COFF::IMAGE_FILE_MACHINE_AMD64:
131 specs.Append(spec: ModuleSpec(file, ArchSpec("x86_64-unknown-windows-msvc")));
132 return 1;
133 case COFF::IMAGE_FILE_MACHINE_ARMNT:
134 specs.Append(spec: ModuleSpec(file, ArchSpec("armv7-unknown-windows-msvc")));
135 return 1;
136 case COFF::IMAGE_FILE_MACHINE_ARM64:
137 specs.Append(spec: ModuleSpec(file, ArchSpec("aarch64-unknown-windows-msvc")));
138 return 1;
139 default:
140 return 0;
141 }
142}
143
144void ObjectFileCOFF::Dump(Stream *stream) {
145 ModuleSP module(GetModule());
146 if (!module)
147 return;
148
149 std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
150
151 stream->Printf(format: "%p: ", static_cast<void *>(this));
152 stream->Indent();
153 stream->PutCString(cstr: "ObjectFileCOFF");
154 *stream << ", file = '" << m_file
155 << "', arch = " << GetArchitecture().GetArchitectureName() << '\n';
156
157 if (SectionList *sections = GetSectionList())
158 sections->Dump(s&: stream->AsRawOstream(), indent: stream->GetIndentLevel(), target: nullptr,
159 show_header: true, depth: std::numeric_limits<uint32_t>::max());
160}
161
162uint32_t ObjectFileCOFF::GetAddressByteSize() const {
163 return const_cast<ObjectFileCOFF *>(this)->GetArchitecture().GetAddressByteSize();
164}
165
166ArchSpec ObjectFileCOFF::GetArchitecture() {
167 switch (static_cast<COFF::MachineTypes>(m_object->getMachine())) {
168 case COFF::IMAGE_FILE_MACHINE_I386:
169 return ArchSpec("i686-unknown-windows-msvc");
170 case COFF::IMAGE_FILE_MACHINE_AMD64:
171 return ArchSpec("x86_64-unknown-windows-msvc");
172 case COFF::IMAGE_FILE_MACHINE_ARMNT:
173 return ArchSpec("armv7-unknown-windows-msvc");
174 case COFF::IMAGE_FILE_MACHINE_ARM64:
175 return ArchSpec("aarch64-unknown-windows-msvc");
176 default:
177 return ArchSpec();
178 }
179}
180
181void ObjectFileCOFF::CreateSections(lldb_private::SectionList &sections) {
182 if (m_sections_up)
183 return;
184
185 m_sections_up = std::make_unique<SectionList>();
186 ModuleSP module(GetModule());
187 if (!module)
188 return;
189
190 std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
191
192 auto SectionType = [](StringRef Name,
193 const coff_section *Section) -> lldb::SectionType {
194 lldb::SectionType type =
195 StringSwitch<lldb::SectionType>(Name)
196 // DWARF Debug Sections
197 .Case(S: ".debug_abbrev", Value: eSectionTypeDWARFDebugAbbrev)
198 .Case(S: ".debug_info", Value: eSectionTypeDWARFDebugInfo)
199 .Case(S: ".debug_line", Value: eSectionTypeDWARFDebugLine)
200 .Case(S: ".debug_pubnames", Value: eSectionTypeDWARFDebugPubNames)
201 .Case(S: ".debug_pubtypes", Value: eSectionTypeDWARFDebugPubTypes)
202 .Case(S: ".debug_str", Value: eSectionTypeDWARFDebugStr)
203 // CodeView Debug Sections: .debug$S, .debug$T
204 .StartsWith(S: ".debug$", Value: eSectionTypeDebug)
205 .Case(S: "clangast", Value: eSectionTypeOther)
206 .Default(Value: eSectionTypeInvalid);
207 if (type != eSectionTypeInvalid)
208 return type;
209
210 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_CODE)
211 return eSectionTypeCode;
212 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
213 return eSectionTypeData;
214 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
215 return Section->SizeOfRawData ? eSectionTypeData : eSectionTypeZeroFill;
216 return eSectionTypeOther;
217 };
218 auto Permissions = [](const object::coff_section *Section) -> uint32_t {
219 uint32_t permissions = 0;
220 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
221 permissions |= lldb::ePermissionsExecutable;
222 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_READ)
223 permissions |= lldb::ePermissionsReadable;
224 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)
225 permissions |= lldb::ePermissionsWritable;
226 return permissions;
227 };
228
229 for (const auto &SecRef : m_object->sections()) {
230 const auto COFFSection = m_object->getCOFFSection(Section: SecRef);
231
232 llvm::Expected<StringRef> Name = SecRef.getName();
233 StringRef SectionName = Name ? *Name : COFFSection->Name;
234 if (!Name)
235 consumeError(Err: Name.takeError());
236
237 SectionSP section =
238 std::make_unique<Section>(args&: module, args: this,
239 args: static_cast<user_id_t>(SecRef.getIndex()),
240 args: ConstString(SectionName),
241 args: SectionType(SectionName, COFFSection),
242 args: COFFSection->VirtualAddress,
243 args: COFFSection->VirtualSize,
244 args: COFFSection->PointerToRawData,
245 args: COFFSection->SizeOfRawData,
246 args: COFFSection->getAlignment(),
247 args: 0);
248 section->SetPermissions(Permissions(COFFSection));
249
250 m_sections_up->AddSection(section_sp: section);
251 sections.AddSection(section_sp: section);
252 }
253}
254
255void ObjectFileCOFF::ParseSymtab(lldb_private::Symtab &symtab) {
256 Log *log = GetLog(mask: LLDBLog::Object);
257
258 SectionList *sections = GetSectionList();
259 symtab.Reserve(count: symtab.GetNumSymbols() + m_object->getNumberOfSymbols());
260
261 auto SymbolType = [](const COFFSymbolRef &Symbol) -> lldb::SymbolType {
262 if (Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
263 return eSymbolTypeCode;
264 if (Symbol.getBaseType() == COFF::IMAGE_SYM_TYPE_NULL &&
265 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_NULL)
266 return eSymbolTypeData;
267 return eSymbolTypeInvalid;
268 };
269
270 for (const auto &SymRef : m_object->symbols()) {
271 const auto COFFSymRef = m_object->getCOFFSymbol(Symbol: SymRef);
272
273 Expected<StringRef> NameOrErr = SymRef.getName();
274 if (!NameOrErr) {
275 LLDB_LOG_ERROR(log, NameOrErr.takeError(),
276 "ObjectFileCOFF: failed to get symbol name: {0}");
277 continue;
278 }
279
280 Symbol symbol;
281 symbol.GetMangled().SetValue(ConstString(*NameOrErr));
282
283 int16_t SecIdx = static_cast<int16_t>(COFFSymRef.getSectionNumber());
284 if (SecIdx == COFF::IMAGE_SYM_ABSOLUTE) {
285 symbol.GetAddressRef() = Address{COFFSymRef.getValue()};
286 symbol.SetType(eSymbolTypeAbsolute);
287 } else if (SecIdx >= 1) {
288 symbol.GetAddressRef() = Address(sections->GetSectionAtIndex(idx: SecIdx - 1),
289 COFFSymRef.getValue());
290 symbol.SetType(SymbolType(COFFSymRef));
291 }
292
293 symtab.AddSymbol(symbol);
294 }
295
296 LLDB_LOG(log, "ObjectFileCOFF::ParseSymtab processed {0} symbols",
297 m_object->getNumberOfSymbols());
298}
299
300bool ObjectFileCOFF::ParseHeader() {
301 ModuleSP module(GetModule());
302 if (!module)
303 return false;
304
305 std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
306
307 m_data.SetByteOrder(eByteOrderLittle);
308 m_data.SetAddressByteSize(GetAddressByteSize());
309
310 return true;
311}
312

source code of lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp