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 §ions) {
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