LLDB mainline
ObjectFileCOFF.cpp
Go to the documentation of this file.
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"
16
17#include "llvm/Support/Error.h"
18#include "llvm/Support/FormatAdapters.h"
19
20using namespace lldb;
21using namespace lldb_private;
22
23using namespace llvm;
24using namespace llvm::object;
25
26static bool IsCOFFObjectFile(const llvm::ArrayRef<uint8_t> data) {
27 return identify_magic(toStringRef(data)) == file_magic::coff_object;
28}
29
31
33
35
41
45
48 DataExtractorSP extractor_sp,
49 offset_t data_offset, const FileSpec *file,
50 offset_t file_offset, offset_t length) {
52
53 if (!extractor_sp || !extractor_sp->HasData()) {
54 DataBufferSP data_sp = MapFileData(*file, length, file_offset);
55 if (!data_sp) {
56 LLDB_LOG(log,
57 "Failed to create ObjectFileCOFF instance: cannot read file {0}",
58 file->GetPath());
59 return nullptr;
60 }
61 extractor_sp = std::make_shared<lldb_private::DataExtractor>(data_sp);
62 data_offset = 0;
63 }
64
65 assert(extractor_sp && extractor_sp->HasData() &&
66 "must have mapped file at this point");
67
68 // If this is operating on a VirtualDataExtractor, it can have
69 // gaps between valid bytes in the DataBuffer. We extract an
70 // ArrayRef of the raw bytes, and can segfault.
71 DataExtractorSP contiguous_extractor_sp =
72 extractor_sp->GetContiguousDataExtractorSP();
73 if (!IsCOFFObjectFile(contiguous_extractor_sp->GetData()))
74 return nullptr;
75
76 if (contiguous_extractor_sp->GetByteSize() < length) {
77 DataBufferSP data_sp = MapFileData(*file, length, file_offset);
78 if (!data_sp) {
79 LLDB_LOG(log,
80 "Failed to create ObjectFileCOFF instance: cannot read file {0}",
81 file->GetPath());
82 return nullptr;
83 }
84 contiguous_extractor_sp =
85 std::make_shared<lldb_private::DataExtractor>(data_sp);
86 data_offset = 0;
87 }
88
89 MemoryBufferRef buffer{toStringRef(contiguous_extractor_sp->GetData()),
90 file->GetFilename()};
91
92 Expected<std::unique_ptr<Binary>> binary = createBinary(buffer);
93 if (!binary) {
94 LLDB_LOG_ERROR(log, binary.takeError(),
95 "Failed to create binary for file ({1}): {0}",
96 file->GetPath());
97 return nullptr;
98 }
99
100 LLDB_LOG(log, "ObjectFileCOFF::ObjectFileCOFF module = {0} ({1}), file = {2}",
101 module_sp.get(), module_sp->GetSpecificationDescription(),
102 file->GetPath());
103
104 return new ObjectFileCOFF(unique_dyn_cast<COFFObjectFile>(std::move(*binary)),
105 module_sp, contiguous_extractor_sp, data_offset,
106 file, file_offset, length);
107}
108
110 const ModuleSP &module_sp, WritableDataBufferSP data_sp,
111 const ProcessSP &process_sp, addr_t header) {
112 // FIXME: do we need to worry about construction from a memory region?
113 return nullptr;
114}
115
118 DataExtractorSP &extractor_sp,
119 offset_t file_offset, offset_t length) {
120 if (!extractor_sp || !extractor_sp->HasData())
121 return {};
122
123 // If this is opearting on a VirtualDataExtractor, it can have
124 // gaps between valid bytes in the DataBuffer. We extract an
125 // ArrayRef of the raw bytes, and can segfault.
126 DataExtractorSP contiguous_extractor_sp =
127 extractor_sp->GetContiguousDataExtractorSP();
128 if (!contiguous_extractor_sp)
129 return {};
130 if (!IsCOFFObjectFile(contiguous_extractor_sp->GetData()))
131 return {};
132
133 MemoryBufferRef buffer{toStringRef(contiguous_extractor_sp->GetData()),
134 file.GetFilename()};
135 Expected<std::unique_ptr<Binary>> binary = createBinary(buffer);
136 if (!binary) {
137 Log *log = GetLog(LLDBLog::Object);
138 LLDB_LOG_ERROR(log, binary.takeError(),
139 "Failed to create binary for file ({1}): {0}",
140 file.GetFilename());
141 return {};
142 }
143
144 std::unique_ptr<COFFObjectFile> object =
145 unique_dyn_cast<COFFObjectFile>(std::move(*binary));
146 ModuleSpecList specs;
147 switch (static_cast<COFF::MachineTypes>(object->getMachine())) {
148 case COFF::IMAGE_FILE_MACHINE_I386:
149 specs.Append(ModuleSpec(file, ArchSpec("i686-unknown-windows-msvc")));
150 return specs;
151 case COFF::IMAGE_FILE_MACHINE_AMD64:
152 specs.Append(ModuleSpec(file, ArchSpec("x86_64-unknown-windows-msvc")));
153 return specs;
154 case COFF::IMAGE_FILE_MACHINE_ARMNT:
155 specs.Append(ModuleSpec(file, ArchSpec("armv7-unknown-windows-msvc")));
156 return specs;
157 case COFF::IMAGE_FILE_MACHINE_ARM64:
158 specs.Append(ModuleSpec(file, ArchSpec("aarch64-unknown-windows-msvc")));
159 return specs;
160 default:
161 break;
162 }
163 return {};
164}
165
167 ModuleSP module(GetModule());
168 if (!module)
169 return;
170
171 std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
172
173 stream->Printf("%p: ", static_cast<void *>(this));
174 stream->Indent();
175 stream->PutCString("ObjectFileCOFF");
176 *stream << ", file = '" << m_file
177 << "', arch = " << GetArchitecture().GetArchitectureName() << '\n';
178
179 if (SectionList *sections = GetSectionList())
180 sections->Dump(stream->AsRawOstream(), stream->GetIndentLevel(), nullptr,
181 true, std::numeric_limits<uint32_t>::max());
182}
183
185 return const_cast<ObjectFileCOFF *>(this)->GetArchitecture().GetAddressByteSize();
186}
187
189 switch (static_cast<COFF::MachineTypes>(m_object->getMachine())) {
190 case COFF::IMAGE_FILE_MACHINE_I386:
191 return ArchSpec("i686-unknown-windows-msvc");
192 case COFF::IMAGE_FILE_MACHINE_AMD64:
193 return ArchSpec("x86_64-unknown-windows-msvc");
194 case COFF::IMAGE_FILE_MACHINE_ARMNT:
195 return ArchSpec("armv7-unknown-windows-msvc");
196 case COFF::IMAGE_FILE_MACHINE_ARM64:
197 return ArchSpec("aarch64-unknown-windows-msvc");
198 default:
199 return ArchSpec();
200 }
201}
202
204 if (m_sections_up)
205 return;
206
207 m_sections_up = std::make_unique<SectionList>();
208 ModuleSP module(GetModule());
209 if (!module)
210 return;
211
212 std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
213
214 auto SectionType = [](StringRef Name,
215 const coff_section *Section) -> lldb::SectionType {
216 // DWARF Debug Sections
217 if (Name.consume_front(".debug_"))
218 return GetDWARFSectionTypeFromName(Name);
219
220 lldb::SectionType type = StringSwitch<lldb::SectionType>(Name)
221 // CodeView Debug Sections: .debug$S, .debug$T
222 .StartsWith(".debug$", eSectionTypeDebug)
223 .Case("clangast", eSectionTypeOther)
224 .Default(eSectionTypeInvalid);
225 if (type != eSectionTypeInvalid)
226 return type;
227
228 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_CODE)
229 return eSectionTypeCode;
230 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
231 return eSectionTypeData;
232 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
233 return Section->SizeOfRawData ? eSectionTypeData : eSectionTypeZeroFill;
234 return eSectionTypeOther;
235 };
236 auto Permissions = [](const object::coff_section *Section) -> uint32_t {
237 uint32_t permissions = 0;
238 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
239 permissions |= lldb::ePermissionsExecutable;
240 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_READ)
241 permissions |= lldb::ePermissionsReadable;
242 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)
243 permissions |= lldb::ePermissionsWritable;
244 return permissions;
245 };
246
247 for (const auto &SecRef : m_object->sections()) {
248 const auto COFFSection = m_object->getCOFFSection(SecRef);
249
250 llvm::Expected<StringRef> Name = SecRef.getName();
251 StringRef SectionName = Name ? *Name : COFFSection->Name;
252 if (!Name)
253 consumeError(Name.takeError());
254
255 SectionSP section =
256 std::make_unique<Section>(module, this,
257 static_cast<user_id_t>(SecRef.getIndex()),
258 ConstString(SectionName),
259 SectionType(SectionName, COFFSection),
260 COFFSection->VirtualAddress,
261 COFFSection->VirtualSize,
262 COFFSection->PointerToRawData,
263 COFFSection->SizeOfRawData,
264 COFFSection->getAlignment(),
265 0);
266 section->SetPermissions(Permissions(COFFSection));
267
268 m_sections_up->AddSection(section);
269 sections.AddSection(section);
270 }
271}
272
274 Log *log = GetLog(LLDBLog::Object);
275
276 SectionList *sections = GetSectionList();
277 symtab.Reserve(symtab.GetNumSymbols() + m_object->getNumberOfSymbols());
278
279 auto SymbolType = [](const COFFSymbolRef &Symbol) -> lldb::SymbolType {
280 if (Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
281 return eSymbolTypeCode;
282 if (Symbol.getBaseType() == COFF::IMAGE_SYM_TYPE_NULL &&
283 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_NULL)
284 return eSymbolTypeData;
285 return eSymbolTypeInvalid;
286 };
287
288 for (const auto &SymRef : m_object->symbols()) {
289 const auto COFFSymRef = m_object->getCOFFSymbol(SymRef);
290
291 Expected<StringRef> NameOrErr = SymRef.getName();
292 if (!NameOrErr) {
293 LLDB_LOG_ERROR(log, NameOrErr.takeError(),
294 "ObjectFileCOFF: failed to get symbol name: {0}");
295 continue;
296 }
297
298 Symbol symbol;
299 symbol.GetMangled().SetValue(ConstString(*NameOrErr));
300
301 int16_t SecIdx = static_cast<int16_t>(COFFSymRef.getSectionNumber());
302 if (SecIdx == COFF::IMAGE_SYM_ABSOLUTE) {
303 symbol.GetAddressRef() = Address{COFFSymRef.getValue()};
305 } else if (SecIdx >= 1) {
306 symbol.GetAddressRef() = Address(sections->GetSectionAtIndex(SecIdx - 1),
307 COFFSymRef.getValue());
308 symbol.SetType(SymbolType(COFFSymRef));
309 }
310
311 symtab.AddSymbol(symbol);
312 }
313
314 LLDB_LOG(log, "ObjectFileCOFF::ParseSymtab processed {0} symbols",
315 m_object->getNumberOfSymbols());
316}
317
319 ModuleSP module(GetModule());
320 if (!module)
321 return false;
322
323 std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
324
325 m_data_nsp->SetByteOrder(eByteOrderLittle);
326 m_data_nsp->SetAddressByteSize(GetAddressByteSize());
327
328 return true;
329}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:405
static bool IsCOFFObjectFile(const llvm::ArrayRef< uint8_t > data)
#define LLDB_PLUGIN_DEFINE(PluginName)
uint32_t GetAddressByteSize() const override
Gets the address size in bytes for the current object file.
void ParseSymtab(lldb_private::Symtab &) override
Parse the symbol table into the provides symbol table object.
static lldb_private::ObjectFile * CreateMemoryInstance(const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header)
static void Initialize()
void Dump(lldb_private::Stream *stream) override
Dump a description of this object to a Stream.
void CreateSections(lldb_private::SectionList &) override
static char ID
static llvm::StringRef GetPluginDescriptionStatic()
lldb_private::ArchSpec GetArchitecture() override
Get the ArchSpec for this object file.
~ObjectFileCOFF() override
bool ParseHeader() override
Attempts to parse the object header.
static void Terminate()
std::unique_ptr< llvm::object::COFFObjectFile > m_object
static lldb_private::ModuleSpecList GetModuleSpecifications(const lldb_private::FileSpec &file, lldb::DataExtractorSP &extractor_sp, lldb::offset_t file_offset, lldb::offset_t length)
ObjectFileCOFF(std::unique_ptr< llvm::object::COFFObjectFile > object, const lldb::ModuleSP &module_sp, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length)
static lldb_private::ObjectFile * CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset, const lldb_private::FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length)
static llvm::StringRef GetPluginNameStatic()
A section + offset based address class.
Definition Address.h:62
An architecture specification class.
Definition ArchSpec.h:32
uint32_t GetAddressByteSize() const
Returns the size in bytes of an address of the current architecture.
Definition ArchSpec.cpp:891
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition ArchSpec.cpp:742
A uniqued constant string class.
Definition ConstString.h:40
A file utility class.
Definition FileSpec.h:56
llvm::StringRef GetFilename() const
Filename string const get accessor.
Definition FileSpec.h:248
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:380
void SetValue(ConstString name)
Set the string value in this object.
Definition Mangled.cpp:124
lldb::ModuleSP GetModule() const
Get const accessor for the module pointer.
void Append(const ModuleSpec &spec)
Definition ModuleSpec.h:371
A plug-in interface definition class for object file parsers.
Definition ObjectFile.h:46
std::unique_ptr< lldb_private::SectionList > m_sections_up
Definition ObjectFile.h:785
static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset)
static lldb::SectionType GetDWARFSectionTypeFromName(llvm::StringRef name)
Parses the section type from a section name for DWARF sections.
DataExtractorNSP m_data_nsp
The data for this object file so things can be parsed lazily.
Definition ObjectFile.h:777
virtual SectionList * GetSectionList(bool update_module_section_list=true)
Gets the section list for the currently selected architecture (and object for archives).
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
size_t AddSection(const lldb::SectionSP &section_sp)
Definition Section.cpp:483
lldb::SectionSP GetSectionAtIndex(size_t idx) const
Definition Section.cpp:555
A stream class that can stream formatted output to a file.
Definition Stream.h:28
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition Stream.h:405
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
Definition Stream.cpp:157
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
unsigned GetIndentLevel() const
Get the current indentation level.
Definition Stream.cpp:193
void SetType(lldb::SymbolType type)
Definition Symbol.h:199
Mangled & GetMangled()
Definition Symbol.h:162
Address & GetAddressRef()
Definition Symbol.h:78
uint32_t AddSymbol(const Symbol &symbol)
Definition Symtab.cpp:61
size_t GetNumSymbols() const
Definition Symtab.cpp:74
void Reserve(size_t count)
Definition Symtab.cpp:48
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
uint64_t offset_t
Definition lldb-types.h:86
std::shared_ptr< lldb_private::Process > ProcessSP
SymbolType
Symbol types.
@ eSymbolTypeAbsolute
uint64_t user_id_t
Definition lldb-types.h:83
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::Section > SectionSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
@ eSectionTypeInvalid
@ eSectionTypeZeroFill
std::shared_ptr< lldb_private::DataExtractor > DataExtractorSP
std::shared_ptr< lldb_private::Module > ModuleSP