412 lines · cpp
1//===-- ObjectFileXCOFF.cpp2//-------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10#include "ObjectFileXCOFF.h"11#include "lldb/Core/Module.h"12#include "lldb/Core/ModuleSpec.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Core/Progress.h"15#include "lldb/Core/Section.h"16#include "lldb/Host/FileSystem.h"17#include "lldb/Symbol/SymbolContext.h"18#include "lldb/Target/Process.h"19#include "lldb/Target/Target.h"20#include "lldb/Utility/ArchSpec.h"21#include "lldb/Utility/DataBufferHeap.h"22#include "lldb/Utility/FileSpecList.h"23#include "lldb/Utility/LLDBLog.h"24#include "lldb/Utility/Log.h"25#include "lldb/Utility/RangeMap.h"26#include "lldb/Utility/Status.h"27#include "lldb/Utility/Stream.h"28#include "llvm/ADT/StringRef.h"29#include "llvm/BinaryFormat/XCOFF.h"30#include "llvm/Object/XCOFFObjectFile.h"31#include "llvm/Support/MemoryBuffer.h"32#include <algorithm>33#include <cassert>34#include <cstring>35#include <unordered_map>36 37using namespace llvm;38using namespace lldb;39using namespace lldb_private;40 41LLDB_PLUGIN_DEFINE(ObjectFileXCOFF)42// FIXME: target 64bit at this moment.43 44// Static methods.45void ObjectFileXCOFF::Initialize() {46 PluginManager::RegisterPlugin(GetPluginNameStatic(),47 GetPluginDescriptionStatic(), CreateInstance,48 CreateMemoryInstance, GetModuleSpecifications);49}50 51void ObjectFileXCOFF::Terminate() {52 PluginManager::UnregisterPlugin(CreateInstance);53}54 55ObjectFile *ObjectFileXCOFF::CreateInstance(const lldb::ModuleSP &module_sp,56 DataBufferSP data_sp,57 lldb::offset_t data_offset,58 const lldb_private::FileSpec *file,59 lldb::offset_t file_offset,60 lldb::offset_t length) {61 if (!data_sp) {62 data_sp = MapFileData(*file, length, file_offset);63 if (!data_sp)64 return nullptr;65 data_offset = 0;66 }67 if (!ObjectFileXCOFF::MagicBytesMatch(data_sp, data_offset, length))68 return nullptr;69 // Update the data to contain the entire file if it doesn't already70 if (data_sp->GetByteSize() < length) {71 data_sp = MapFileData(*file, length, file_offset);72 if (!data_sp)73 return nullptr;74 data_offset = 0;75 }76 auto objfile_up = std::make_unique<ObjectFileXCOFF>(77 module_sp, data_sp, data_offset, file, file_offset, length);78 if (!objfile_up)79 return nullptr;80 81 // Cache xcoff binary.82 if (!objfile_up->CreateBinary())83 return nullptr;84 85 if (!objfile_up->ParseHeader())86 return nullptr;87 88 return objfile_up.release();89}90 91bool ObjectFileXCOFF::CreateBinary() {92 if (m_binary)93 return true;94 95 Log *log = GetLog(LLDBLog::Object);96 97 auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data.GetData()),98 m_file.GetFilename().GetStringRef());99 llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer());100 101 auto binary = llvm::object::ObjectFile::createObjectFile(memory_ref, magic);102 if (!binary) {103 LLDB_LOG_ERROR(log, binary.takeError(),104 "Failed to create binary for file ({1}): {0}", m_file);105 return false;106 }107 // Make sure we only handle XCOFF format.108 m_binary =109 llvm::unique_dyn_cast<llvm::object::XCOFFObjectFile>(std::move(*binary));110 if (!m_binary)111 return false;112 113 LLDB_LOG(log, "this = {0}, module = {1} ({2}), file = {3}, binary = {4}",114 this, GetModule().get(), GetModule()->GetSpecificationDescription(),115 m_file.GetPath(), m_binary.get());116 117 return true;118}119 120ObjectFile *ObjectFileXCOFF::CreateMemoryInstance(121 const lldb::ModuleSP &module_sp, WritableDataBufferSP data_sp,122 const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {123 return nullptr;124}125 126size_t ObjectFileXCOFF::GetModuleSpecifications(127 const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,128 lldb::offset_t data_offset, lldb::offset_t file_offset,129 lldb::offset_t length, lldb_private::ModuleSpecList &specs) {130 const size_t initial_count = specs.GetSize();131 132 if (ObjectFileXCOFF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {133 ArchSpec arch_spec =134 ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);135 ModuleSpec spec(file, arch_spec);136 spec.GetArchitecture().SetArchitecture(eArchTypeXCOFF, XCOFF::TCPU_PPC64,137 LLDB_INVALID_CPUTYPE,138 llvm::Triple::AIX);139 specs.Append(spec);140 }141 return specs.GetSize() - initial_count;142}143 144static uint32_t XCOFFHeaderSizeFromMagic(uint32_t magic) {145 switch (magic) {146 case XCOFF::XCOFF32:147 return sizeof(struct llvm::object::XCOFFFileHeader32);148 break;149 case XCOFF::XCOFF64:150 return sizeof(struct llvm::object::XCOFFFileHeader64);151 break;152 153 default:154 break;155 }156 return 0;157}158 159bool ObjectFileXCOFF::MagicBytesMatch(DataBufferSP &data_sp,160 lldb::addr_t data_offset,161 lldb::addr_t data_length) {162 lldb_private::DataExtractor data;163 data.SetData(data_sp, data_offset, data_length);164 // Need to set this as XCOFF is only compatible with Big Endian165 data.SetByteOrder(eByteOrderBig);166 lldb::offset_t offset = 0;167 uint16_t magic = data.GetU16(&offset);168 return XCOFFHeaderSizeFromMagic(magic) != 0;169}170 171bool ObjectFileXCOFF::ParseHeader() {172 if (m_binary->is64Bit())173 return m_binary->fileHeader64()->Magic == XCOFF::XCOFF64;174 return m_binary->fileHeader32()->Magic == XCOFF::XCOFF32;175}176 177ByteOrder ObjectFileXCOFF::GetByteOrder() const { return eByteOrderBig; }178 179bool ObjectFileXCOFF::IsExecutable() const { return true; }180 181uint32_t ObjectFileXCOFF::GetAddressByteSize() const {182 if (m_binary->is64Bit())183 return 8;184 return 4;185}186 187AddressClass ObjectFileXCOFF::GetAddressClass(addr_t file_addr) {188 return AddressClass::eUnknown;189}190 191static lldb::SymbolType MapSymbolType(llvm::object::SymbolRef::Type sym_type) {192 switch (sym_type) {193 case llvm::object::SymbolRef::ST_Function:194 return lldb::eSymbolTypeCode;195 case llvm::object::SymbolRef::ST_Data:196 return lldb::eSymbolTypeData;197 case llvm::object::SymbolRef::ST_File:198 return lldb::eSymbolTypeSourceFile;199 default:200 return lldb::eSymbolTypeInvalid;201 }202}203 204void ObjectFileXCOFF::ParseSymtab(Symtab &lldb_symtab) {205 Log *log = GetLog(LLDBLog::Object);206 SectionList *sectionList = GetSectionList();207 208 for (const auto &symbol_ref : m_binary->symbols()) {209 llvm::object::XCOFFSymbolRef xcoff_sym_ref(symbol_ref);210 211 llvm::Expected<llvm::StringRef> name_or_err = xcoff_sym_ref.getName();212 if (!name_or_err) {213 LLDB_LOG_ERROR(log, name_or_err.takeError(),214 "Unable to extract name from the xcoff symbol ref object");215 continue;216 }217 218 llvm::StringRef symbolName = name_or_err.get();219 // Remove the . prefix added during compilation. This prefix is usually220 // added to differentiate between reference to the code and function221 // descriptor. For instance, Adding .func will only allow user to put bp on222 // .func, which is not known to the user, instead of func.223 llvm::StringRef name_no_dot =224 symbolName.starts_with(".") ? symbolName.drop_front() : symbolName;225 auto storageClass = xcoff_sym_ref.getStorageClass();226 // C_HIDEXT symbols are not needed to be exposed, with the exception of TOC227 // which is responsible for storing references to global data228 if (storageClass == XCOFF::C_HIDEXT && symbolName != "TOC") {229 230 // Zero or muliple aux entries may suggest ambiguous data231 if (xcoff_sym_ref.getNumberOfAuxEntries() != 1)232 continue;233 234 auto aux_csect_or_err = xcoff_sym_ref.getXCOFFCsectAuxRef();235 if (!aux_csect_or_err) {236 LLDB_LOG_ERROR(log, aux_csect_or_err.takeError(),237 "Unable to access xcoff csect aux ref object");238 continue;239 }240 241 const llvm::object::XCOFFCsectAuxRef csect_aux = aux_csect_or_err.get();242 243 // Only add hidden ext entries which come under Program Code, skip others244 // as they are not useful as debugging data.245 if (csect_aux.getStorageMappingClass() != XCOFF::XMC_PR)246 continue;247 248 // This does not apply to 32-bit,249 // Only add csect symbols identified by the aux entry, as they are250 // needed to reference section information. Skip others251 if (m_binary->is64Bit())252 if (csect_aux.getAuxType64() != XCOFF::AUX_CSECT)253 continue;254 }255 256 Symbol symbol;257 symbol.GetMangled().SetValue(ConstString(name_no_dot));258 259 int16_t sectionNumber = xcoff_sym_ref.getSectionNumber();260 // Note that XCOFF section headers are numbered from 1 and not 0.261 size_t sectionIndex = static_cast<size_t>(sectionNumber - 1);262 if (sectionNumber > 0) {263 if (sectionIndex < sectionList->GetSize()) {264 265 lldb::SectionSP section_sp =266 sectionList->GetSectionAtIndex(sectionIndex);267 if (!section_sp || section_sp->GetFileAddress() == LLDB_INVALID_ADDRESS)268 continue;269 270 lldb::addr_t file_addr = section_sp->GetFileAddress();271 lldb::addr_t symbolValue = xcoff_sym_ref.getValue();272 if (symbolValue < file_addr)273 continue;274 275 symbol.GetAddressRef() = Address(section_sp, symbolValue - file_addr);276 }277 }278 279 Expected<llvm::object::SymbolRef::Type> sym_type_or_err =280 symbol_ref.getType();281 if (!sym_type_or_err) {282 LLDB_LOG_ERROR(log, sym_type_or_err.takeError(),283 "Unable to access xcoff symbol type");284 continue;285 }286 287 symbol.SetType(MapSymbolType(sym_type_or_err.get()));288 289 lldb_symtab.AddSymbol(symbol);290 }291}292 293bool ObjectFileXCOFF::IsStripped() { return false; }294 295void ObjectFileXCOFF::CreateSections(SectionList &unified_section_list) {296 297 if (m_sections_up)298 return;299 300 m_sections_up = std::make_unique<SectionList>();301 if (m_binary->is64Bit())302 CreateSectionsWithBitness<XCOFF64>(unified_section_list);303 else304 CreateSectionsWithBitness<XCOFF32>(unified_section_list);305}306 307template <typename T>308static auto GetSections(llvm::object::XCOFFObjectFile *binary) {309 if constexpr (T::Is64Bit)310 return binary->sections64();311 else312 return binary->sections32();313}314 315template <typename T>316void ObjectFileXCOFF::CreateSectionsWithBitness(317 SectionList &unified_section_list) {318 ModuleSP module_sp(GetModule());319 if (!module_sp)320 return;321 322 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());323 324 int idx = 0;325 for (const typename T::SectionHeader §ion :326 GetSections<T>(m_binary.get())) {327 328 ConstString const_sect_name(section.Name);329 330 SectionType section_type = lldb::eSectionTypeOther;331 if (section.Flags & XCOFF::STYP_TEXT)332 section_type = eSectionTypeCode;333 else if (section.Flags & XCOFF::STYP_DATA)334 section_type = eSectionTypeData;335 else if (section.Flags & XCOFF::STYP_BSS)336 section_type = eSectionTypeZeroFill;337 else if (section.Flags & XCOFF::STYP_DWARF) {338 section_type = llvm::StringSwitch<SectionType>(section.Name)339 .Case(".dwinfo", eSectionTypeDWARFDebugInfo)340 .Case(".dwline", eSectionTypeDWARFDebugLine)341 .Case(".dwabrev", eSectionTypeDWARFDebugAbbrev)342 .Case(".dwrnges", eSectionTypeDWARFDebugRanges)343 .Default(eSectionTypeInvalid);344 }345 346 SectionSP section_sp(new Section(347 module_sp, this, ++idx, const_sect_name, section_type,348 section.VirtualAddress, section.SectionSize,349 section.FileOffsetToRawData, section.SectionSize, 0, section.Flags));350 351 uint32_t permissions = ePermissionsReadable;352 if (section.Flags & (XCOFF::STYP_DATA | XCOFF::STYP_BSS))353 permissions |= ePermissionsWritable;354 if (section.Flags & XCOFF::STYP_TEXT)355 permissions |= ePermissionsExecutable;356 357 section_sp->SetPermissions(permissions);358 m_sections_up->AddSection(section_sp);359 unified_section_list.AddSection(section_sp);360 }361}362 363void ObjectFileXCOFF::Dump(Stream *s) {}364 365ArchSpec ObjectFileXCOFF::GetArchitecture() {366 ArchSpec arch_spec =367 ArchSpec(eArchTypeXCOFF, XCOFF::TCPU_PPC64, LLDB_INVALID_CPUTYPE);368 return arch_spec;369}370 371UUID ObjectFileXCOFF::GetUUID() { return UUID(); }372 373uint32_t ObjectFileXCOFF::GetDependentModules(FileSpecList &files) { return 0; }374 375ObjectFile::Type ObjectFileXCOFF::CalculateType() {376 377 const auto flags = m_binary->is64Bit() ? m_binary->fileHeader64()->Flags378 : m_binary->fileHeader32()->Flags;379 380 if (flags & XCOFF::F_EXEC)381 return eTypeExecutable;382 else if (flags & XCOFF::F_SHROBJ)383 return eTypeSharedLibrary;384 return eTypeUnknown;385}386 387ObjectFile::Strata ObjectFileXCOFF::CalculateStrata() { return eStrataUnknown; }388 389lldb::WritableDataBufferSP390ObjectFileXCOFF::MapFileDataWritable(const FileSpec &file, uint64_t Size,391 uint64_t Offset) {392 return FileSystem::Instance().CreateWritableDataBuffer(file.GetPath(), Size,393 Offset);394}395 396ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,397 DataBufferSP data_sp,398 lldb::offset_t data_offset,399 const FileSpec *file,400 lldb::offset_t file_offset,401 lldb::offset_t length)402 : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset) {403 if (file)404 m_file = *file;405}406 407ObjectFileXCOFF::ObjectFileXCOFF(const lldb::ModuleSP &module_sp,408 DataBufferSP header_data_sp,409 const lldb::ProcessSP &process_sp,410 addr_t header_addr)411 : ObjectFile(module_sp, process_sp, header_addr, header_data_sp) {}412