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