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 &sections) {
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