xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
106c3fb27SDimitry Andric //===-- ObjectFileCOFF.cpp ------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "ObjectFileCOFF.h"
1006c3fb27SDimitry Andric 
1106c3fb27SDimitry Andric #include "lldb/Core/Module.h"
1206c3fb27SDimitry Andric #include "lldb/Core/ModuleSpec.h"
1306c3fb27SDimitry Andric #include "lldb/Core/PluginManager.h"
1406c3fb27SDimitry Andric #include "lldb/Utility/LLDBLog.h"
1506c3fb27SDimitry Andric 
1606c3fb27SDimitry Andric #include "llvm/Support/Error.h"
1706c3fb27SDimitry Andric #include "llvm/Support/FormatAdapters.h"
1806c3fb27SDimitry Andric 
1906c3fb27SDimitry Andric using namespace lldb;
2006c3fb27SDimitry Andric using namespace lldb_private;
2106c3fb27SDimitry Andric 
2206c3fb27SDimitry Andric using namespace llvm;
2306c3fb27SDimitry Andric using namespace llvm::object;
2406c3fb27SDimitry Andric 
IsCOFFObjectFile(const DataBufferSP & data)2506c3fb27SDimitry Andric static bool IsCOFFObjectFile(const DataBufferSP &data) {
2606c3fb27SDimitry Andric   return identify_magic(toStringRef(data->GetData())) ==
2706c3fb27SDimitry Andric          file_magic::coff_object;
2806c3fb27SDimitry Andric }
2906c3fb27SDimitry Andric 
3006c3fb27SDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileCOFF)
3106c3fb27SDimitry Andric 
3206c3fb27SDimitry Andric char ObjectFileCOFF::ID;
3306c3fb27SDimitry Andric 
3406c3fb27SDimitry Andric ObjectFileCOFF::~ObjectFileCOFF() = default;
3506c3fb27SDimitry Andric 
Initialize()3606c3fb27SDimitry Andric void ObjectFileCOFF::Initialize() {
3706c3fb27SDimitry Andric   PluginManager::RegisterPlugin(GetPluginNameStatic(),
3806c3fb27SDimitry Andric                                 GetPluginDescriptionStatic(), CreateInstance,
3906c3fb27SDimitry Andric                                 CreateMemoryInstance, GetModuleSpecifications);
4006c3fb27SDimitry Andric }
4106c3fb27SDimitry Andric 
Terminate()4206c3fb27SDimitry Andric void ObjectFileCOFF::Terminate() {
4306c3fb27SDimitry Andric   PluginManager::UnregisterPlugin(CreateInstance);
4406c3fb27SDimitry Andric }
4506c3fb27SDimitry Andric 
4606c3fb27SDimitry 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)4706c3fb27SDimitry Andric ObjectFileCOFF::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,
4806c3fb27SDimitry Andric                                offset_t data_offset, const FileSpec *file,
4906c3fb27SDimitry Andric                                offset_t file_offset, offset_t length) {
5006c3fb27SDimitry Andric   Log *log = GetLog(LLDBLog::Object);
5106c3fb27SDimitry Andric 
5206c3fb27SDimitry Andric   if (!data_sp) {
5306c3fb27SDimitry Andric     data_sp = MapFileData(*file, length, file_offset);
5406c3fb27SDimitry Andric     if (!data_sp) {
5506c3fb27SDimitry Andric       LLDB_LOG(log,
5606c3fb27SDimitry Andric                "Failed to create ObjectFileCOFF instance: cannot read file {0}",
5706c3fb27SDimitry Andric                file->GetPath());
5806c3fb27SDimitry Andric       return nullptr;
5906c3fb27SDimitry Andric     }
6006c3fb27SDimitry Andric     data_offset = 0;
6106c3fb27SDimitry Andric   }
6206c3fb27SDimitry Andric 
6306c3fb27SDimitry Andric   assert(data_sp && "must have mapped file at this point");
6406c3fb27SDimitry Andric 
6506c3fb27SDimitry Andric   if (!IsCOFFObjectFile(data_sp))
6606c3fb27SDimitry Andric     return nullptr;
6706c3fb27SDimitry Andric 
6806c3fb27SDimitry Andric   if (data_sp->GetByteSize() < length) {
6906c3fb27SDimitry Andric     data_sp = MapFileData(*file, length, file_offset);
7006c3fb27SDimitry Andric     if (!data_sp) {
7106c3fb27SDimitry Andric       LLDB_LOG(log,
7206c3fb27SDimitry Andric                "Failed to create ObjectFileCOFF instance: cannot read file {0}",
7306c3fb27SDimitry Andric                file->GetPath());
7406c3fb27SDimitry Andric       return nullptr;
7506c3fb27SDimitry Andric     }
7606c3fb27SDimitry Andric     data_offset = 0;
7706c3fb27SDimitry Andric   }
7806c3fb27SDimitry Andric 
7906c3fb27SDimitry Andric 
8006c3fb27SDimitry Andric   MemoryBufferRef buffer{toStringRef(data_sp->GetData()),
8106c3fb27SDimitry Andric                          file->GetFilename().GetStringRef()};
8206c3fb27SDimitry Andric 
8306c3fb27SDimitry Andric   Expected<std::unique_ptr<Binary>> binary = createBinary(buffer);
8406c3fb27SDimitry Andric   if (!binary) {
8506c3fb27SDimitry Andric     LLDB_LOG_ERROR(log, binary.takeError(),
8606c3fb27SDimitry Andric                    "Failed to create binary for file ({1}): {0}",
8706c3fb27SDimitry Andric                    file->GetPath());
8806c3fb27SDimitry Andric     return nullptr;
8906c3fb27SDimitry Andric   }
9006c3fb27SDimitry Andric 
9106c3fb27SDimitry Andric   LLDB_LOG(log, "ObjectFileCOFF::ObjectFileCOFF module = {1} ({2}), file = {3}",
9206c3fb27SDimitry Andric            module_sp.get(), module_sp->GetSpecificationDescription(),
9306c3fb27SDimitry Andric            file->GetPath());
9406c3fb27SDimitry Andric 
9506c3fb27SDimitry Andric   return new ObjectFileCOFF(unique_dyn_cast<COFFObjectFile>(std::move(*binary)),
9606c3fb27SDimitry Andric                             module_sp, data_sp, data_offset, file, file_offset,
9706c3fb27SDimitry Andric                             length);
9806c3fb27SDimitry Andric }
9906c3fb27SDimitry Andric 
CreateMemoryInstance(const ModuleSP & module_sp,WritableDataBufferSP data_sp,const ProcessSP & process_sp,addr_t header)10006c3fb27SDimitry Andric lldb_private::ObjectFile *ObjectFileCOFF::CreateMemoryInstance(
10106c3fb27SDimitry Andric     const ModuleSP &module_sp, WritableDataBufferSP data_sp,
10206c3fb27SDimitry Andric     const ProcessSP &process_sp, addr_t header) {
10306c3fb27SDimitry Andric   // FIXME: do we need to worry about construction from a memory region?
10406c3fb27SDimitry Andric   return nullptr;
10506c3fb27SDimitry Andric }
10606c3fb27SDimitry Andric 
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)10706c3fb27SDimitry Andric size_t ObjectFileCOFF::GetModuleSpecifications(
10806c3fb27SDimitry Andric     const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
10906c3fb27SDimitry Andric     offset_t file_offset, offset_t length, ModuleSpecList &specs) {
11006c3fb27SDimitry Andric   if (!IsCOFFObjectFile(data_sp))
11106c3fb27SDimitry Andric     return 0;
11206c3fb27SDimitry Andric 
11306c3fb27SDimitry Andric   MemoryBufferRef buffer{toStringRef(data_sp->GetData()),
11406c3fb27SDimitry Andric                          file.GetFilename().GetStringRef()};
11506c3fb27SDimitry Andric   Expected<std::unique_ptr<Binary>> binary = createBinary(buffer);
11606c3fb27SDimitry Andric   if (!binary) {
11706c3fb27SDimitry Andric     Log *log = GetLog(LLDBLog::Object);
11806c3fb27SDimitry Andric     LLDB_LOG_ERROR(log, binary.takeError(),
11906c3fb27SDimitry Andric                    "Failed to create binary for file ({1}): {0}",
12006c3fb27SDimitry Andric                    file.GetFilename());
12106c3fb27SDimitry Andric     return 0;
12206c3fb27SDimitry Andric   }
12306c3fb27SDimitry Andric 
12406c3fb27SDimitry Andric   std::unique_ptr<COFFObjectFile> object =
12506c3fb27SDimitry Andric       unique_dyn_cast<COFFObjectFile>(std::move(*binary));
12606c3fb27SDimitry Andric   switch (static_cast<COFF::MachineTypes>(object->getMachine())) {
12706c3fb27SDimitry Andric   case COFF::IMAGE_FILE_MACHINE_I386:
12806c3fb27SDimitry Andric     specs.Append(ModuleSpec(file, ArchSpec("i686-unknown-windows-msvc")));
12906c3fb27SDimitry Andric     return 1;
13006c3fb27SDimitry Andric   case COFF::IMAGE_FILE_MACHINE_AMD64:
13106c3fb27SDimitry Andric     specs.Append(ModuleSpec(file, ArchSpec("x86_64-unknown-windows-msvc")));
13206c3fb27SDimitry Andric     return 1;
13306c3fb27SDimitry Andric   case COFF::IMAGE_FILE_MACHINE_ARMNT:
13406c3fb27SDimitry Andric     specs.Append(ModuleSpec(file, ArchSpec("armv7-unknown-windows-msvc")));
13506c3fb27SDimitry Andric     return 1;
13606c3fb27SDimitry Andric   case COFF::IMAGE_FILE_MACHINE_ARM64:
13706c3fb27SDimitry Andric     specs.Append(ModuleSpec(file, ArchSpec("aarch64-unknown-windows-msvc")));
13806c3fb27SDimitry Andric     return 1;
13906c3fb27SDimitry Andric   default:
14006c3fb27SDimitry Andric     return 0;
14106c3fb27SDimitry Andric   }
14206c3fb27SDimitry Andric }
14306c3fb27SDimitry Andric 
Dump(Stream * stream)14406c3fb27SDimitry Andric void ObjectFileCOFF::Dump(Stream *stream) {
14506c3fb27SDimitry Andric   ModuleSP module(GetModule());
14606c3fb27SDimitry Andric   if (!module)
14706c3fb27SDimitry Andric     return;
14806c3fb27SDimitry Andric 
14906c3fb27SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
15006c3fb27SDimitry Andric 
15106c3fb27SDimitry Andric   stream->Printf("%p: ", static_cast<void *>(this));
15206c3fb27SDimitry Andric   stream->Indent();
15306c3fb27SDimitry Andric   stream->PutCString("ObjectFileCOFF");
15406c3fb27SDimitry Andric   *stream << ", file = '" << m_file
15506c3fb27SDimitry Andric           << "', arch = " << GetArchitecture().GetArchitectureName() << '\n';
15606c3fb27SDimitry Andric 
15706c3fb27SDimitry Andric   if (SectionList *sections = GetSectionList())
15806c3fb27SDimitry Andric     sections->Dump(stream->AsRawOstream(), stream->GetIndentLevel(), nullptr,
15906c3fb27SDimitry Andric                    true, std::numeric_limits<uint32_t>::max());
16006c3fb27SDimitry Andric }
16106c3fb27SDimitry Andric 
GetAddressByteSize() const16206c3fb27SDimitry Andric uint32_t ObjectFileCOFF::GetAddressByteSize() const {
16306c3fb27SDimitry Andric   return const_cast<ObjectFileCOFF *>(this)->GetArchitecture().GetAddressByteSize();
16406c3fb27SDimitry Andric }
16506c3fb27SDimitry Andric 
GetArchitecture()16606c3fb27SDimitry Andric ArchSpec ObjectFileCOFF::GetArchitecture() {
16706c3fb27SDimitry Andric   switch (static_cast<COFF::MachineTypes>(m_object->getMachine())) {
16806c3fb27SDimitry Andric   case COFF::IMAGE_FILE_MACHINE_I386:
16906c3fb27SDimitry Andric     return ArchSpec("i686-unknown-windows-msvc");
17006c3fb27SDimitry Andric   case COFF::IMAGE_FILE_MACHINE_AMD64:
17106c3fb27SDimitry Andric     return ArchSpec("x86_64-unknown-windows-msvc");
17206c3fb27SDimitry Andric   case COFF::IMAGE_FILE_MACHINE_ARMNT:
17306c3fb27SDimitry Andric     return ArchSpec("armv7-unknown-windows-msvc");
17406c3fb27SDimitry Andric   case COFF::IMAGE_FILE_MACHINE_ARM64:
17506c3fb27SDimitry Andric     return ArchSpec("aarch64-unknown-windows-msvc");
17606c3fb27SDimitry Andric   default:
17706c3fb27SDimitry Andric     return ArchSpec();
17806c3fb27SDimitry Andric   }
17906c3fb27SDimitry Andric }
18006c3fb27SDimitry Andric 
CreateSections(lldb_private::SectionList & sections)18106c3fb27SDimitry Andric void ObjectFileCOFF::CreateSections(lldb_private::SectionList &sections) {
18206c3fb27SDimitry Andric   if (m_sections_up)
18306c3fb27SDimitry Andric     return;
18406c3fb27SDimitry Andric 
18506c3fb27SDimitry Andric   m_sections_up = std::make_unique<SectionList>();
18606c3fb27SDimitry Andric   ModuleSP module(GetModule());
18706c3fb27SDimitry Andric   if (!module)
18806c3fb27SDimitry Andric     return;
18906c3fb27SDimitry Andric 
19006c3fb27SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
19106c3fb27SDimitry Andric 
19206c3fb27SDimitry Andric   auto SectionType = [](StringRef Name,
19306c3fb27SDimitry Andric                         const coff_section *Section) -> lldb::SectionType {
19406c3fb27SDimitry Andric     lldb::SectionType type =
19506c3fb27SDimitry Andric         StringSwitch<lldb::SectionType>(Name)
19606c3fb27SDimitry Andric             // DWARF Debug Sections
19706c3fb27SDimitry Andric             .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev)
19806c3fb27SDimitry Andric             .Case(".debug_info", eSectionTypeDWARFDebugInfo)
19906c3fb27SDimitry Andric             .Case(".debug_line", eSectionTypeDWARFDebugLine)
20006c3fb27SDimitry Andric             .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames)
20106c3fb27SDimitry Andric             .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes)
20206c3fb27SDimitry Andric             .Case(".debug_str", eSectionTypeDWARFDebugStr)
20306c3fb27SDimitry Andric             // CodeView Debug Sections: .debug$S, .debug$T
20406c3fb27SDimitry Andric             .StartsWith(".debug$", eSectionTypeDebug)
20506c3fb27SDimitry Andric             .Case("clangast", eSectionTypeOther)
20606c3fb27SDimitry Andric             .Default(eSectionTypeInvalid);
20706c3fb27SDimitry Andric     if (type != eSectionTypeInvalid)
20806c3fb27SDimitry Andric       return type;
20906c3fb27SDimitry Andric 
21006c3fb27SDimitry Andric     if (Section->Characteristics & COFF::IMAGE_SCN_CNT_CODE)
21106c3fb27SDimitry Andric       return eSectionTypeCode;
21206c3fb27SDimitry Andric     if (Section->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
21306c3fb27SDimitry Andric       return eSectionTypeData;
21406c3fb27SDimitry Andric     if (Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
21506c3fb27SDimitry Andric       return Section->SizeOfRawData ? eSectionTypeData : eSectionTypeZeroFill;
21606c3fb27SDimitry Andric     return eSectionTypeOther;
21706c3fb27SDimitry Andric   };
21806c3fb27SDimitry Andric   auto Permissions = [](const object::coff_section *Section) -> uint32_t {
21906c3fb27SDimitry Andric     uint32_t permissions = 0;
22006c3fb27SDimitry Andric     if (Section->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
22106c3fb27SDimitry Andric       permissions |= lldb::ePermissionsExecutable;
22206c3fb27SDimitry Andric     if (Section->Characteristics & COFF::IMAGE_SCN_MEM_READ)
22306c3fb27SDimitry Andric       permissions |= lldb::ePermissionsReadable;
22406c3fb27SDimitry Andric     if (Section->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)
22506c3fb27SDimitry Andric       permissions |= lldb::ePermissionsWritable;
22606c3fb27SDimitry Andric     return permissions;
22706c3fb27SDimitry Andric   };
22806c3fb27SDimitry Andric 
22906c3fb27SDimitry Andric   for (const auto &SecRef : m_object->sections()) {
23006c3fb27SDimitry Andric     const auto COFFSection = m_object->getCOFFSection(SecRef);
23106c3fb27SDimitry Andric 
23206c3fb27SDimitry Andric     llvm::Expected<StringRef> Name = SecRef.getName();
23306c3fb27SDimitry Andric     StringRef SectionName = Name ? *Name : COFFSection->Name;
23406c3fb27SDimitry Andric     if (!Name)
23506c3fb27SDimitry Andric       consumeError(Name.takeError());
23606c3fb27SDimitry Andric 
23706c3fb27SDimitry Andric     SectionSP section =
23806c3fb27SDimitry Andric         std::make_unique<Section>(module, this,
23906c3fb27SDimitry Andric                                   static_cast<user_id_t>(SecRef.getIndex()),
24006c3fb27SDimitry Andric                                   ConstString(SectionName),
24106c3fb27SDimitry Andric                                   SectionType(SectionName, COFFSection),
24206c3fb27SDimitry Andric                                   COFFSection->VirtualAddress,
24306c3fb27SDimitry Andric                                   COFFSection->VirtualSize,
24406c3fb27SDimitry Andric                                   COFFSection->PointerToRawData,
24506c3fb27SDimitry Andric                                   COFFSection->SizeOfRawData,
24606c3fb27SDimitry Andric                                   COFFSection->getAlignment(),
24706c3fb27SDimitry Andric                                   0);
24806c3fb27SDimitry Andric     section->SetPermissions(Permissions(COFFSection));
24906c3fb27SDimitry Andric 
25006c3fb27SDimitry Andric     m_sections_up->AddSection(section);
25106c3fb27SDimitry Andric     sections.AddSection(section);
25206c3fb27SDimitry Andric   }
25306c3fb27SDimitry Andric }
25406c3fb27SDimitry Andric 
ParseSymtab(lldb_private::Symtab & symtab)25506c3fb27SDimitry Andric void ObjectFileCOFF::ParseSymtab(lldb_private::Symtab &symtab) {
25606c3fb27SDimitry Andric   Log *log = GetLog(LLDBLog::Object);
25706c3fb27SDimitry Andric 
25806c3fb27SDimitry Andric   SectionList *sections = GetSectionList();
25906c3fb27SDimitry Andric   symtab.Reserve(symtab.GetNumSymbols() + m_object->getNumberOfSymbols());
26006c3fb27SDimitry Andric 
26106c3fb27SDimitry Andric   auto SymbolType = [](const COFFSymbolRef &Symbol) -> lldb::SymbolType {
26206c3fb27SDimitry Andric     if (Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
26306c3fb27SDimitry Andric       return eSymbolTypeCode;
26406c3fb27SDimitry Andric     if (Symbol.getBaseType() == COFF::IMAGE_SYM_TYPE_NULL &&
26506c3fb27SDimitry Andric         Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_NULL)
26606c3fb27SDimitry Andric       return eSymbolTypeData;
26706c3fb27SDimitry Andric     return eSymbolTypeInvalid;
26806c3fb27SDimitry Andric   };
26906c3fb27SDimitry Andric 
27006c3fb27SDimitry Andric   for (const auto &SymRef : m_object->symbols()) {
27106c3fb27SDimitry Andric     const auto COFFSymRef = m_object->getCOFFSymbol(SymRef);
27206c3fb27SDimitry Andric 
27306c3fb27SDimitry Andric     Expected<StringRef> NameOrErr = SymRef.getName();
274*5f757f3fSDimitry Andric     if (!NameOrErr) {
275*5f757f3fSDimitry Andric       LLDB_LOG_ERROR(log, NameOrErr.takeError(),
276*5f757f3fSDimitry Andric                      "ObjectFileCOFF: failed to get symbol name: {0}");
27706c3fb27SDimitry Andric       continue;
27806c3fb27SDimitry Andric     }
27906c3fb27SDimitry Andric 
28006c3fb27SDimitry Andric     Symbol symbol;
28106c3fb27SDimitry Andric     symbol.GetMangled().SetValue(ConstString(*NameOrErr));
28206c3fb27SDimitry Andric 
28306c3fb27SDimitry Andric     int16_t SecIdx = static_cast<int16_t>(COFFSymRef.getSectionNumber());
28406c3fb27SDimitry Andric     if (SecIdx == COFF::IMAGE_SYM_ABSOLUTE) {
28506c3fb27SDimitry Andric       symbol.GetAddressRef() = Address{COFFSymRef.getValue()};
28606c3fb27SDimitry Andric       symbol.SetType(eSymbolTypeAbsolute);
28706c3fb27SDimitry Andric     } else if (SecIdx >= 1) {
28806c3fb27SDimitry Andric       symbol.GetAddressRef() = Address(sections->GetSectionAtIndex(SecIdx - 1),
28906c3fb27SDimitry Andric                                        COFFSymRef.getValue());
29006c3fb27SDimitry Andric       symbol.SetType(SymbolType(COFFSymRef));
29106c3fb27SDimitry Andric     }
29206c3fb27SDimitry Andric 
29306c3fb27SDimitry Andric     symtab.AddSymbol(symbol);
29406c3fb27SDimitry Andric   }
29506c3fb27SDimitry Andric 
29606c3fb27SDimitry Andric   LLDB_LOG(log, "ObjectFileCOFF::ParseSymtab processed {0} symbols",
29706c3fb27SDimitry Andric            m_object->getNumberOfSymbols());
29806c3fb27SDimitry Andric }
29906c3fb27SDimitry Andric 
ParseHeader()30006c3fb27SDimitry Andric bool ObjectFileCOFF::ParseHeader() {
30106c3fb27SDimitry Andric   ModuleSP module(GetModule());
30206c3fb27SDimitry Andric   if (!module)
30306c3fb27SDimitry Andric     return false;
30406c3fb27SDimitry Andric 
30506c3fb27SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
30606c3fb27SDimitry Andric 
30706c3fb27SDimitry Andric   m_data.SetByteOrder(eByteOrderLittle);
30806c3fb27SDimitry Andric   m_data.SetAddressByteSize(GetAddressByteSize());
30906c3fb27SDimitry Andric 
31006c3fb27SDimitry Andric   return true;
31106c3fb27SDimitry Andric }
312