17fa27ce4SDimitry Andric //===-- ObjectFileCOFF.cpp ------------------------------------------------===//
27fa27ce4SDimitry Andric //
37fa27ce4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47fa27ce4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
57fa27ce4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67fa27ce4SDimitry Andric //
77fa27ce4SDimitry Andric //===----------------------------------------------------------------------===//
87fa27ce4SDimitry Andric
97fa27ce4SDimitry Andric #include "ObjectFileCOFF.h"
107fa27ce4SDimitry Andric
117fa27ce4SDimitry Andric #include "lldb/Core/Module.h"
127fa27ce4SDimitry Andric #include "lldb/Core/ModuleSpec.h"
137fa27ce4SDimitry Andric #include "lldb/Core/PluginManager.h"
147fa27ce4SDimitry Andric #include "lldb/Utility/LLDBLog.h"
157fa27ce4SDimitry Andric
167fa27ce4SDimitry Andric #include "llvm/Support/Error.h"
177fa27ce4SDimitry Andric #include "llvm/Support/FormatAdapters.h"
187fa27ce4SDimitry Andric
197fa27ce4SDimitry Andric using namespace lldb;
207fa27ce4SDimitry Andric using namespace lldb_private;
217fa27ce4SDimitry Andric
227fa27ce4SDimitry Andric using namespace llvm;
237fa27ce4SDimitry Andric using namespace llvm::object;
247fa27ce4SDimitry Andric
IsCOFFObjectFile(const DataBufferSP & data)257fa27ce4SDimitry Andric static bool IsCOFFObjectFile(const DataBufferSP &data) {
267fa27ce4SDimitry Andric return identify_magic(toStringRef(data->GetData())) ==
277fa27ce4SDimitry Andric file_magic::coff_object;
287fa27ce4SDimitry Andric }
297fa27ce4SDimitry Andric
307fa27ce4SDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileCOFF)
317fa27ce4SDimitry Andric
327fa27ce4SDimitry Andric char ObjectFileCOFF::ID;
337fa27ce4SDimitry Andric
347fa27ce4SDimitry Andric ObjectFileCOFF::~ObjectFileCOFF() = default;
357fa27ce4SDimitry Andric
Initialize()367fa27ce4SDimitry Andric void ObjectFileCOFF::Initialize() {
377fa27ce4SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
387fa27ce4SDimitry Andric GetPluginDescriptionStatic(), CreateInstance,
397fa27ce4SDimitry Andric CreateMemoryInstance, GetModuleSpecifications);
407fa27ce4SDimitry Andric }
417fa27ce4SDimitry Andric
Terminate()427fa27ce4SDimitry Andric void ObjectFileCOFF::Terminate() {
437fa27ce4SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
447fa27ce4SDimitry Andric }
457fa27ce4SDimitry Andric
467fa27ce4SDimitry 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)477fa27ce4SDimitry Andric ObjectFileCOFF::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,
487fa27ce4SDimitry Andric offset_t data_offset, const FileSpec *file,
497fa27ce4SDimitry Andric offset_t file_offset, offset_t length) {
507fa27ce4SDimitry Andric Log *log = GetLog(LLDBLog::Object);
517fa27ce4SDimitry Andric
527fa27ce4SDimitry Andric if (!data_sp) {
537fa27ce4SDimitry Andric data_sp = MapFileData(*file, length, file_offset);
547fa27ce4SDimitry Andric if (!data_sp) {
557fa27ce4SDimitry Andric LLDB_LOG(log,
567fa27ce4SDimitry Andric "Failed to create ObjectFileCOFF instance: cannot read file {0}",
577fa27ce4SDimitry Andric file->GetPath());
587fa27ce4SDimitry Andric return nullptr;
597fa27ce4SDimitry Andric }
607fa27ce4SDimitry Andric data_offset = 0;
617fa27ce4SDimitry Andric }
627fa27ce4SDimitry Andric
637fa27ce4SDimitry Andric assert(data_sp && "must have mapped file at this point");
647fa27ce4SDimitry Andric
657fa27ce4SDimitry Andric if (!IsCOFFObjectFile(data_sp))
667fa27ce4SDimitry Andric return nullptr;
677fa27ce4SDimitry Andric
687fa27ce4SDimitry Andric if (data_sp->GetByteSize() < length) {
697fa27ce4SDimitry Andric data_sp = MapFileData(*file, length, file_offset);
707fa27ce4SDimitry Andric if (!data_sp) {
717fa27ce4SDimitry Andric LLDB_LOG(log,
727fa27ce4SDimitry Andric "Failed to create ObjectFileCOFF instance: cannot read file {0}",
737fa27ce4SDimitry Andric file->GetPath());
747fa27ce4SDimitry Andric return nullptr;
757fa27ce4SDimitry Andric }
767fa27ce4SDimitry Andric data_offset = 0;
777fa27ce4SDimitry Andric }
787fa27ce4SDimitry Andric
797fa27ce4SDimitry Andric
807fa27ce4SDimitry Andric MemoryBufferRef buffer{toStringRef(data_sp->GetData()),
817fa27ce4SDimitry Andric file->GetFilename().GetStringRef()};
827fa27ce4SDimitry Andric
837fa27ce4SDimitry Andric Expected<std::unique_ptr<Binary>> binary = createBinary(buffer);
847fa27ce4SDimitry Andric if (!binary) {
857fa27ce4SDimitry Andric LLDB_LOG_ERROR(log, binary.takeError(),
867fa27ce4SDimitry Andric "Failed to create binary for file ({1}): {0}",
877fa27ce4SDimitry Andric file->GetPath());
887fa27ce4SDimitry Andric return nullptr;
897fa27ce4SDimitry Andric }
907fa27ce4SDimitry Andric
917fa27ce4SDimitry Andric LLDB_LOG(log, "ObjectFileCOFF::ObjectFileCOFF module = {1} ({2}), file = {3}",
927fa27ce4SDimitry Andric module_sp.get(), module_sp->GetSpecificationDescription(),
937fa27ce4SDimitry Andric file->GetPath());
947fa27ce4SDimitry Andric
957fa27ce4SDimitry Andric return new ObjectFileCOFF(unique_dyn_cast<COFFObjectFile>(std::move(*binary)),
967fa27ce4SDimitry Andric module_sp, data_sp, data_offset, file, file_offset,
977fa27ce4SDimitry Andric length);
987fa27ce4SDimitry Andric }
997fa27ce4SDimitry Andric
CreateMemoryInstance(const ModuleSP & module_sp,WritableDataBufferSP data_sp,const ProcessSP & process_sp,addr_t header)1007fa27ce4SDimitry Andric lldb_private::ObjectFile *ObjectFileCOFF::CreateMemoryInstance(
1017fa27ce4SDimitry Andric const ModuleSP &module_sp, WritableDataBufferSP data_sp,
1027fa27ce4SDimitry Andric const ProcessSP &process_sp, addr_t header) {
1037fa27ce4SDimitry Andric // FIXME: do we need to worry about construction from a memory region?
1047fa27ce4SDimitry Andric return nullptr;
1057fa27ce4SDimitry Andric }
1067fa27ce4SDimitry Andric
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)1077fa27ce4SDimitry Andric size_t ObjectFileCOFF::GetModuleSpecifications(
1087fa27ce4SDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
1097fa27ce4SDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) {
1107fa27ce4SDimitry Andric if (!IsCOFFObjectFile(data_sp))
1117fa27ce4SDimitry Andric return 0;
1127fa27ce4SDimitry Andric
1137fa27ce4SDimitry Andric MemoryBufferRef buffer{toStringRef(data_sp->GetData()),
1147fa27ce4SDimitry Andric file.GetFilename().GetStringRef()};
1157fa27ce4SDimitry Andric Expected<std::unique_ptr<Binary>> binary = createBinary(buffer);
1167fa27ce4SDimitry Andric if (!binary) {
1177fa27ce4SDimitry Andric Log *log = GetLog(LLDBLog::Object);
1187fa27ce4SDimitry Andric LLDB_LOG_ERROR(log, binary.takeError(),
1197fa27ce4SDimitry Andric "Failed to create binary for file ({1}): {0}",
1207fa27ce4SDimitry Andric file.GetFilename());
1217fa27ce4SDimitry Andric return 0;
1227fa27ce4SDimitry Andric }
1237fa27ce4SDimitry Andric
1247fa27ce4SDimitry Andric std::unique_ptr<COFFObjectFile> object =
1257fa27ce4SDimitry Andric unique_dyn_cast<COFFObjectFile>(std::move(*binary));
1267fa27ce4SDimitry Andric switch (static_cast<COFF::MachineTypes>(object->getMachine())) {
1277fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
1287fa27ce4SDimitry Andric specs.Append(ModuleSpec(file, ArchSpec("i686-unknown-windows-msvc")));
1297fa27ce4SDimitry Andric return 1;
1307fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
1317fa27ce4SDimitry Andric specs.Append(ModuleSpec(file, ArchSpec("x86_64-unknown-windows-msvc")));
1327fa27ce4SDimitry Andric return 1;
1337fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
1347fa27ce4SDimitry Andric specs.Append(ModuleSpec(file, ArchSpec("armv7-unknown-windows-msvc")));
1357fa27ce4SDimitry Andric return 1;
1367fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
1377fa27ce4SDimitry Andric specs.Append(ModuleSpec(file, ArchSpec("aarch64-unknown-windows-msvc")));
1387fa27ce4SDimitry Andric return 1;
1397fa27ce4SDimitry Andric default:
1407fa27ce4SDimitry Andric return 0;
1417fa27ce4SDimitry Andric }
1427fa27ce4SDimitry Andric }
1437fa27ce4SDimitry Andric
Dump(Stream * stream)1447fa27ce4SDimitry Andric void ObjectFileCOFF::Dump(Stream *stream) {
1457fa27ce4SDimitry Andric ModuleSP module(GetModule());
1467fa27ce4SDimitry Andric if (!module)
1477fa27ce4SDimitry Andric return;
1487fa27ce4SDimitry Andric
1497fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
1507fa27ce4SDimitry Andric
1517fa27ce4SDimitry Andric stream->Printf("%p: ", static_cast<void *>(this));
1527fa27ce4SDimitry Andric stream->Indent();
1537fa27ce4SDimitry Andric stream->PutCString("ObjectFileCOFF");
1547fa27ce4SDimitry Andric *stream << ", file = '" << m_file
1557fa27ce4SDimitry Andric << "', arch = " << GetArchitecture().GetArchitectureName() << '\n';
1567fa27ce4SDimitry Andric
1577fa27ce4SDimitry Andric if (SectionList *sections = GetSectionList())
1587fa27ce4SDimitry Andric sections->Dump(stream->AsRawOstream(), stream->GetIndentLevel(), nullptr,
1597fa27ce4SDimitry Andric true, std::numeric_limits<uint32_t>::max());
1607fa27ce4SDimitry Andric }
1617fa27ce4SDimitry Andric
GetAddressByteSize() const1627fa27ce4SDimitry Andric uint32_t ObjectFileCOFF::GetAddressByteSize() const {
1637fa27ce4SDimitry Andric return const_cast<ObjectFileCOFF *>(this)->GetArchitecture().GetAddressByteSize();
1647fa27ce4SDimitry Andric }
1657fa27ce4SDimitry Andric
GetArchitecture()1667fa27ce4SDimitry Andric ArchSpec ObjectFileCOFF::GetArchitecture() {
1677fa27ce4SDimitry Andric switch (static_cast<COFF::MachineTypes>(m_object->getMachine())) {
1687fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
1697fa27ce4SDimitry Andric return ArchSpec("i686-unknown-windows-msvc");
1707fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
1717fa27ce4SDimitry Andric return ArchSpec("x86_64-unknown-windows-msvc");
1727fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
1737fa27ce4SDimitry Andric return ArchSpec("armv7-unknown-windows-msvc");
1747fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
1757fa27ce4SDimitry Andric return ArchSpec("aarch64-unknown-windows-msvc");
1767fa27ce4SDimitry Andric default:
1777fa27ce4SDimitry Andric return ArchSpec();
1787fa27ce4SDimitry Andric }
1797fa27ce4SDimitry Andric }
1807fa27ce4SDimitry Andric
CreateSections(lldb_private::SectionList & sections)1817fa27ce4SDimitry Andric void ObjectFileCOFF::CreateSections(lldb_private::SectionList §ions) {
1827fa27ce4SDimitry Andric if (m_sections_up)
1837fa27ce4SDimitry Andric return;
1847fa27ce4SDimitry Andric
1857fa27ce4SDimitry Andric m_sections_up = std::make_unique<SectionList>();
1867fa27ce4SDimitry Andric ModuleSP module(GetModule());
1877fa27ce4SDimitry Andric if (!module)
1887fa27ce4SDimitry Andric return;
1897fa27ce4SDimitry Andric
1907fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
1917fa27ce4SDimitry Andric
1927fa27ce4SDimitry Andric auto SectionType = [](StringRef Name,
1937fa27ce4SDimitry Andric const coff_section *Section) -> lldb::SectionType {
1947fa27ce4SDimitry Andric lldb::SectionType type =
1957fa27ce4SDimitry Andric StringSwitch<lldb::SectionType>(Name)
1967fa27ce4SDimitry Andric // DWARF Debug Sections
1977fa27ce4SDimitry Andric .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev)
1987fa27ce4SDimitry Andric .Case(".debug_info", eSectionTypeDWARFDebugInfo)
1997fa27ce4SDimitry Andric .Case(".debug_line", eSectionTypeDWARFDebugLine)
2007fa27ce4SDimitry Andric .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames)
2017fa27ce4SDimitry Andric .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes)
2027fa27ce4SDimitry Andric .Case(".debug_str", eSectionTypeDWARFDebugStr)
2037fa27ce4SDimitry Andric // CodeView Debug Sections: .debug$S, .debug$T
2047fa27ce4SDimitry Andric .StartsWith(".debug$", eSectionTypeDebug)
2057fa27ce4SDimitry Andric .Case("clangast", eSectionTypeOther)
2067fa27ce4SDimitry Andric .Default(eSectionTypeInvalid);
2077fa27ce4SDimitry Andric if (type != eSectionTypeInvalid)
2087fa27ce4SDimitry Andric return type;
2097fa27ce4SDimitry Andric
2107fa27ce4SDimitry Andric if (Section->Characteristics & COFF::IMAGE_SCN_CNT_CODE)
2117fa27ce4SDimitry Andric return eSectionTypeCode;
2127fa27ce4SDimitry Andric if (Section->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
2137fa27ce4SDimitry Andric return eSectionTypeData;
2147fa27ce4SDimitry Andric if (Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
2157fa27ce4SDimitry Andric return Section->SizeOfRawData ? eSectionTypeData : eSectionTypeZeroFill;
2167fa27ce4SDimitry Andric return eSectionTypeOther;
2177fa27ce4SDimitry Andric };
2187fa27ce4SDimitry Andric auto Permissions = [](const object::coff_section *Section) -> uint32_t {
2197fa27ce4SDimitry Andric uint32_t permissions = 0;
2207fa27ce4SDimitry Andric if (Section->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)
2217fa27ce4SDimitry Andric permissions |= lldb::ePermissionsExecutable;
2227fa27ce4SDimitry Andric if (Section->Characteristics & COFF::IMAGE_SCN_MEM_READ)
2237fa27ce4SDimitry Andric permissions |= lldb::ePermissionsReadable;
2247fa27ce4SDimitry Andric if (Section->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)
2257fa27ce4SDimitry Andric permissions |= lldb::ePermissionsWritable;
2267fa27ce4SDimitry Andric return permissions;
2277fa27ce4SDimitry Andric };
2287fa27ce4SDimitry Andric
2297fa27ce4SDimitry Andric for (const auto &SecRef : m_object->sections()) {
2307fa27ce4SDimitry Andric const auto COFFSection = m_object->getCOFFSection(SecRef);
2317fa27ce4SDimitry Andric
2327fa27ce4SDimitry Andric llvm::Expected<StringRef> Name = SecRef.getName();
2337fa27ce4SDimitry Andric StringRef SectionName = Name ? *Name : COFFSection->Name;
2347fa27ce4SDimitry Andric if (!Name)
2357fa27ce4SDimitry Andric consumeError(Name.takeError());
2367fa27ce4SDimitry Andric
2377fa27ce4SDimitry Andric SectionSP section =
2387fa27ce4SDimitry Andric std::make_unique<Section>(module, this,
2397fa27ce4SDimitry Andric static_cast<user_id_t>(SecRef.getIndex()),
2407fa27ce4SDimitry Andric ConstString(SectionName),
2417fa27ce4SDimitry Andric SectionType(SectionName, COFFSection),
2427fa27ce4SDimitry Andric COFFSection->VirtualAddress,
2437fa27ce4SDimitry Andric COFFSection->VirtualSize,
2447fa27ce4SDimitry Andric COFFSection->PointerToRawData,
2457fa27ce4SDimitry Andric COFFSection->SizeOfRawData,
2467fa27ce4SDimitry Andric COFFSection->getAlignment(),
2477fa27ce4SDimitry Andric 0);
2487fa27ce4SDimitry Andric section->SetPermissions(Permissions(COFFSection));
2497fa27ce4SDimitry Andric
2507fa27ce4SDimitry Andric m_sections_up->AddSection(section);
2517fa27ce4SDimitry Andric sections.AddSection(section);
2527fa27ce4SDimitry Andric }
2537fa27ce4SDimitry Andric }
2547fa27ce4SDimitry Andric
ParseSymtab(lldb_private::Symtab & symtab)2557fa27ce4SDimitry Andric void ObjectFileCOFF::ParseSymtab(lldb_private::Symtab &symtab) {
2567fa27ce4SDimitry Andric Log *log = GetLog(LLDBLog::Object);
2577fa27ce4SDimitry Andric
2587fa27ce4SDimitry Andric SectionList *sections = GetSectionList();
2597fa27ce4SDimitry Andric symtab.Reserve(symtab.GetNumSymbols() + m_object->getNumberOfSymbols());
2607fa27ce4SDimitry Andric
2617fa27ce4SDimitry Andric auto SymbolType = [](const COFFSymbolRef &Symbol) -> lldb::SymbolType {
2627fa27ce4SDimitry Andric if (Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
2637fa27ce4SDimitry Andric return eSymbolTypeCode;
2647fa27ce4SDimitry Andric if (Symbol.getBaseType() == COFF::IMAGE_SYM_TYPE_NULL &&
2657fa27ce4SDimitry Andric Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_NULL)
2667fa27ce4SDimitry Andric return eSymbolTypeData;
2677fa27ce4SDimitry Andric return eSymbolTypeInvalid;
2687fa27ce4SDimitry Andric };
2697fa27ce4SDimitry Andric
2707fa27ce4SDimitry Andric for (const auto &SymRef : m_object->symbols()) {
2717fa27ce4SDimitry Andric const auto COFFSymRef = m_object->getCOFFSymbol(SymRef);
2727fa27ce4SDimitry Andric
2737fa27ce4SDimitry Andric Expected<StringRef> NameOrErr = SymRef.getName();
274b1c73532SDimitry Andric if (!NameOrErr) {
275b1c73532SDimitry Andric LLDB_LOG_ERROR(log, NameOrErr.takeError(),
276b1c73532SDimitry Andric "ObjectFileCOFF: failed to get symbol name: {0}");
2777fa27ce4SDimitry Andric continue;
2787fa27ce4SDimitry Andric }
2797fa27ce4SDimitry Andric
2807fa27ce4SDimitry Andric Symbol symbol;
2817fa27ce4SDimitry Andric symbol.GetMangled().SetValue(ConstString(*NameOrErr));
2827fa27ce4SDimitry Andric
2837fa27ce4SDimitry Andric int16_t SecIdx = static_cast<int16_t>(COFFSymRef.getSectionNumber());
2847fa27ce4SDimitry Andric if (SecIdx == COFF::IMAGE_SYM_ABSOLUTE) {
2857fa27ce4SDimitry Andric symbol.GetAddressRef() = Address{COFFSymRef.getValue()};
2867fa27ce4SDimitry Andric symbol.SetType(eSymbolTypeAbsolute);
2877fa27ce4SDimitry Andric } else if (SecIdx >= 1) {
2887fa27ce4SDimitry Andric symbol.GetAddressRef() = Address(sections->GetSectionAtIndex(SecIdx - 1),
2897fa27ce4SDimitry Andric COFFSymRef.getValue());
2907fa27ce4SDimitry Andric symbol.SetType(SymbolType(COFFSymRef));
2917fa27ce4SDimitry Andric }
2927fa27ce4SDimitry Andric
2937fa27ce4SDimitry Andric symtab.AddSymbol(symbol);
2947fa27ce4SDimitry Andric }
2957fa27ce4SDimitry Andric
2967fa27ce4SDimitry Andric LLDB_LOG(log, "ObjectFileCOFF::ParseSymtab processed {0} symbols",
2977fa27ce4SDimitry Andric m_object->getNumberOfSymbols());
2987fa27ce4SDimitry Andric }
2997fa27ce4SDimitry Andric
ParseHeader()3007fa27ce4SDimitry Andric bool ObjectFileCOFF::ParseHeader() {
3017fa27ce4SDimitry Andric ModuleSP module(GetModule());
3027fa27ce4SDimitry Andric if (!module)
3037fa27ce4SDimitry Andric return false;
3047fa27ce4SDimitry Andric
3057fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
3067fa27ce4SDimitry Andric
3077fa27ce4SDimitry Andric m_data.SetByteOrder(eByteOrderLittle);
3087fa27ce4SDimitry Andric m_data.SetAddressByteSize(GetAddressByteSize());
3097fa27ce4SDimitry Andric
3107fa27ce4SDimitry Andric return true;
3117fa27ce4SDimitry Andric }
312