llvm-project/llvm/lib/Object/ObjectFile.cpp
Chris B 2fe96439fb
[DirectX] Add ObjectFile boilerplate for objdump (#151434)
This change adds boilerplate code to implement the object::ObjectFile
interface for the DXContainer object file and an empty implementation of
the objdump Dumper object.

Adding an ObjectFile implementation for DXContainer is a bit odd because
the DXContainer format doesn't have a symbol table, so there isn't a
reasonable implementation for the SymbolicFile interfaces. That said, it
does have sections, and it will be useful for objdump to be able to
inspect some of the structured data stored in some of the special named
sections.

At this point in the implementation it can't do much other than dump the
part names, offsets, and sizes. Dumping detailed structured section
contents to be extended in subsequent PRs.

Fixes #151433
2025-08-04 10:57:25 -05:00

235 lines
7.7 KiB
C++

//===- ObjectFile.cpp - File format independent object file ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a file format independent ObjectFile class.
//
//===----------------------------------------------------------------------===//
#include "llvm/Object/ObjectFile.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/DXContainer.h"
#include "llvm/Object/Error.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdint>
#include <memory>
#include <system_error>
using namespace llvm;
using namespace object;
raw_ostream &object::operator<<(raw_ostream &OS, const SectionedAddress &Addr) {
OS << "SectionedAddress{" << format_hex(Addr.Address, 10);
if (Addr.SectionIndex != SectionedAddress::UndefSection)
OS << ", " << Addr.SectionIndex;
return OS << "}";
}
void ObjectFile::anchor() {}
ObjectFile::ObjectFile(unsigned int Type, MemoryBufferRef Source)
: SymbolicFile(Type, Source) {}
bool SectionRef::containsSymbol(SymbolRef S) const {
Expected<section_iterator> SymSec = S.getSection();
if (!SymSec) {
// TODO: Actually report errors helpfully.
consumeError(SymSec.takeError());
return false;
}
return *this == **SymSec;
}
Expected<uint64_t> ObjectFile::getSymbolValue(DataRefImpl Ref) const {
uint32_t Flags;
if (Error E = getSymbolFlags(Ref).moveInto(Flags))
// TODO: Test this error.
return std::move(E);
if (Flags & SymbolRef::SF_Undefined)
return 0;
if (Flags & SymbolRef::SF_Common)
return getCommonSymbolSize(Ref);
return getSymbolValueImpl(Ref);
}
Error ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {
Expected<StringRef> Name = getSymbolName(Symb);
if (!Name)
return Name.takeError();
OS << *Name;
return Error::success();
}
uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; }
bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const {
Expected<StringRef> NameOrErr = getSectionName(Sec);
if (NameOrErr)
return *NameOrErr == ".llvm.lto";
consumeError(NameOrErr.takeError());
return false;
}
bool ObjectFile::isSectionStripped(DataRefImpl Sec) const { return false; }
bool ObjectFile::isBerkeleyText(DataRefImpl Sec) const {
return isSectionText(Sec);
}
bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const {
return isSectionData(Sec);
}
bool ObjectFile::isDebugSection(DataRefImpl Sec) const { return false; }
bool ObjectFile::hasDebugInfo() const {
return any_of(sections(),
[](SectionRef Sec) { return Sec.isDebugSection(); });
}
Expected<section_iterator>
ObjectFile::getRelocatedSection(DataRefImpl Sec) const {
return section_iterator(SectionRef(Sec, this));
}
Triple ObjectFile::makeTriple() const {
Triple TheTriple;
auto Arch = getArch();
TheTriple.setArch(Triple::ArchType(Arch));
auto OS = getOS();
if (OS != Triple::UnknownOS)
TheTriple.setOS(OS);
// For ARM targets, try to use the build attributes to build determine
// the build target. Target features are also added, but later during
// disassembly.
if (Arch == Triple::arm || Arch == Triple::armeb)
setARMSubArch(TheTriple);
// TheTriple defaults to ELF, and COFF doesn't have an environment:
// something we can do here is indicate that it is mach-o.
if (isMachO()) {
TheTriple.setObjectFormat(Triple::MachO);
} else if (isCOFF()) {
const auto COFFObj = cast<COFFObjectFile>(this);
if (COFFObj->getArch() == Triple::thumb)
TheTriple.setTriple("thumbv7-windows");
} else if (isXCOFF()) {
// XCOFF implies AIX.
TheTriple.setOS(Triple::AIX);
TheTriple.setObjectFormat(Triple::XCOFF);
} else if (isGOFF()) {
TheTriple.setOS(Triple::ZOS);
TheTriple.setObjectFormat(Triple::GOFF);
} else if (TheTriple.isAMDGPU()) {
TheTriple.setVendor(Triple::AMD);
} else if (TheTriple.isNVPTX()) {
TheTriple.setVendor(Triple::NVIDIA);
}
return TheTriple;
}
Expected<std::unique_ptr<ObjectFile>>
ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type,
bool InitContent) {
StringRef Data = Object.getBuffer();
if (Type == file_magic::unknown)
Type = identify_magic(Data);
switch (Type) {
case file_magic::unknown:
case file_magic::bitcode:
case file_magic::clang_ast:
case file_magic::coff_cl_gl_object:
case file_magic::archive:
case file_magic::macho_universal_binary:
case file_magic::windows_resource:
case file_magic::pdb:
case file_magic::minidump:
case file_magic::goff_object:
case file_magic::cuda_fatbinary:
case file_magic::offload_binary:
case file_magic::offload_bundle:
case file_magic::offload_bundle_compressed:
case file_magic::spirv_object:
return errorCodeToError(object_error::invalid_file_type);
case file_magic::tapi_file:
return errorCodeToError(object_error::invalid_file_type);
case file_magic::elf:
case file_magic::elf_relocatable:
case file_magic::elf_executable:
case file_magic::elf_shared_object:
case file_magic::elf_core:
return createELFObjectFile(Object, InitContent);
case file_magic::macho_object:
case file_magic::macho_executable:
case file_magic::macho_fixed_virtual_memory_shared_lib:
case file_magic::macho_core:
case file_magic::macho_preload_executable:
case file_magic::macho_dynamically_linked_shared_lib:
case file_magic::macho_dynamic_linker:
case file_magic::macho_bundle:
case file_magic::macho_dynamically_linked_shared_lib_stub:
case file_magic::macho_dsym_companion:
case file_magic::macho_kext_bundle:
case file_magic::macho_file_set:
return createMachOObjectFile(Object);
case file_magic::coff_object:
case file_magic::coff_import_library:
case file_magic::pecoff_executable:
return createCOFFObjectFile(Object);
case file_magic::xcoff_object_32:
return createXCOFFObjectFile(Object, Binary::ID_XCOFF32);
case file_magic::xcoff_object_64:
return createXCOFFObjectFile(Object, Binary::ID_XCOFF64);
case file_magic::wasm_object:
return createWasmObjectFile(Object);
case file_magic::dxcontainer_object:
return createDXContainerObjectFile(Object);
}
llvm_unreachable("Unexpected Object File Type");
}
Expected<OwningBinary<ObjectFile>>
ObjectFile::createObjectFile(StringRef ObjectPath) {
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
MemoryBuffer::getFile(ObjectPath);
if (std::error_code EC = FileOrErr.getError())
return errorCodeToError(EC);
std::unique_ptr<MemoryBuffer> Buffer = std::move(FileOrErr.get());
Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
createObjectFile(Buffer->getMemBufferRef());
if (Error Err = ObjOrErr.takeError())
return std::move(Err);
std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
return OwningBinary<ObjectFile>(std::move(Obj), std::move(Buffer));
}
bool ObjectFile::isReflectionSectionStrippable(
llvm::binaryformat::Swift5ReflectionSectionKind ReflectionSectionKind)
const {
using llvm::binaryformat::Swift5ReflectionSectionKind;
return ReflectionSectionKind == Swift5ReflectionSectionKind::fieldmd ||
ReflectionSectionKind == Swift5ReflectionSectionKind::reflstr ||
ReflectionSectionKind == Swift5ReflectionSectionKind::assocty;
}