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