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-exception 6 // 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 19 using namespace lldb; 20 using namespace lldb_private; 21 22 using namespace llvm; 23 using namespace llvm::object; 24 25 static bool IsCOFFObjectFile(const DataBufferSP &data) { 26 return identify_magic(toStringRef(data->GetData())) == 27 file_magic::coff_object; 28 } 29 30 LLDB_PLUGIN_DEFINE(ObjectFileCOFF) 31 32 char ObjectFileCOFF::ID; 33 34 ObjectFileCOFF::~ObjectFileCOFF() = default; 35 36 void ObjectFileCOFF::Initialize() { 37 PluginManager::RegisterPlugin(GetPluginNameStatic(), 38 GetPluginDescriptionStatic(), CreateInstance, 39 CreateMemoryInstance, GetModuleSpecifications); 40 } 41 42 void ObjectFileCOFF::Terminate() { 43 PluginManager::UnregisterPlugin(CreateInstance); 44 } 45 46 lldb_private::ObjectFile * 47 ObjectFileCOFF::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 100 lldb_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 107 size_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 144 void 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_file 155 << "', 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 162 uint32_t ObjectFileCOFF::GetAddressByteSize() const { 163 return const_cast<ObjectFileCOFF *>(this)->GetArchitecture().GetAddressByteSize(); 164 } 165 166 ArchSpec 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 181 void 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 lldb::SectionType type = 195 StringSwitch<lldb::SectionType>(Name) 196 // DWARF Debug Sections 197 .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) 198 .Case(".debug_info", eSectionTypeDWARFDebugInfo) 199 .Case(".debug_line", eSectionTypeDWARFDebugLine) 200 .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames) 201 .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes) 202 .Case(".debug_str", eSectionTypeDWARFDebugStr) 203 // CodeView Debug Sections: .debug$S, .debug$T 204 .StartsWith(".debug$", eSectionTypeDebug) 205 .Case("clangast", eSectionTypeOther) 206 .Default(eSectionTypeInvalid); 207 if (type != eSectionTypeInvalid) 208 return type; 209 210 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_CODE) 211 return eSectionTypeCode; 212 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) 213 return eSectionTypeData; 214 if (Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) 215 return Section->SizeOfRawData ? eSectionTypeData : eSectionTypeZeroFill; 216 return eSectionTypeOther; 217 }; 218 auto Permissions = [](const object::coff_section *Section) -> uint32_t { 219 uint32_t permissions = 0; 220 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE) 221 permissions |= lldb::ePermissionsExecutable; 222 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_READ) 223 permissions |= lldb::ePermissionsReadable; 224 if (Section->Characteristics & COFF::IMAGE_SCN_MEM_WRITE) 225 permissions |= lldb::ePermissionsWritable; 226 return permissions; 227 }; 228 229 for (const auto &SecRef : m_object->sections()) { 230 const auto COFFSection = m_object->getCOFFSection(SecRef); 231 232 llvm::Expected<StringRef> Name = SecRef.getName(); 233 StringRef SectionName = Name ? *Name : COFFSection->Name; 234 if (!Name) 235 consumeError(Name.takeError()); 236 237 SectionSP section = 238 std::make_unique<Section>(module, this, 239 static_cast<user_id_t>(SecRef.getIndex()), 240 ConstString(SectionName), 241 SectionType(SectionName, COFFSection), 242 COFFSection->VirtualAddress, 243 COFFSection->VirtualSize, 244 COFFSection->PointerToRawData, 245 COFFSection->SizeOfRawData, 246 COFFSection->getAlignment(), 247 0); 248 section->SetPermissions(Permissions(COFFSection)); 249 250 m_sections_up->AddSection(section); 251 sections.AddSection(section); 252 } 253 } 254 255 void ObjectFileCOFF::ParseSymtab(lldb_private::Symtab &symtab) { 256 Log *log = GetLog(LLDBLog::Object); 257 258 SectionList *sections = GetSectionList(); 259 symtab.Reserve(symtab.GetNumSymbols() + m_object->getNumberOfSymbols()); 260 261 auto SymbolType = [](const COFFSymbolRef &Symbol) -> lldb::SymbolType { 262 if (Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) 263 return eSymbolTypeCode; 264 if (Symbol.getBaseType() == COFF::IMAGE_SYM_TYPE_NULL && 265 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_NULL) 266 return eSymbolTypeData; 267 return eSymbolTypeInvalid; 268 }; 269 270 for (const auto &SymRef : m_object->symbols()) { 271 const auto COFFSymRef = m_object->getCOFFSymbol(SymRef); 272 273 Expected<StringRef> NameOrErr = SymRef.getName(); 274 if (auto error = NameOrErr.takeError()) { 275 LLDB_LOG(log, "ObjectFileCOFF: failed to get symbol name: {0}", 276 llvm::fmt_consume(std::move(error))); 277 continue; 278 } 279 280 Symbol symbol; 281 symbol.GetMangled().SetValue(ConstString(*NameOrErr)); 282 283 int16_t SecIdx = static_cast<int16_t>(COFFSymRef.getSectionNumber()); 284 if (SecIdx == COFF::IMAGE_SYM_ABSOLUTE) { 285 symbol.GetAddressRef() = Address{COFFSymRef.getValue()}; 286 symbol.SetType(eSymbolTypeAbsolute); 287 } else if (SecIdx >= 1) { 288 symbol.GetAddressRef() = Address(sections->GetSectionAtIndex(SecIdx - 1), 289 COFFSymRef.getValue()); 290 symbol.SetType(SymbolType(COFFSymRef)); 291 } 292 293 symtab.AddSymbol(symbol); 294 } 295 296 LLDB_LOG(log, "ObjectFileCOFF::ParseSymtab processed {0} symbols", 297 m_object->getNumberOfSymbols()); 298 } 299 300 bool ObjectFileCOFF::ParseHeader() { 301 ModuleSP module(GetModule()); 302 if (!module) 303 return false; 304 305 std::lock_guard<std::recursive_mutex> guard(module->GetMutex()); 306 307 m_data.SetByteOrder(eByteOrderLittle); 308 m_data.SetAddressByteSize(GetAddressByteSize()); 309 310 return true; 311 } 312