Path: blob/main/contrib/llvm-project/llvm/tools/llvm-objdump/XCOFFDump.cpp
35231 views
//===-- XCOFFDump.cpp - XCOFF-specific dumper -----------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file implements the XCOFF-specific dumper for llvm-objdump.10///11//===----------------------------------------------------------------------===//1213#include "XCOFFDump.h"1415#include "llvm-objdump.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/Demangle/Demangle.h"18#include "llvm/MC/MCInstPrinter.h"19#include "llvm/MC/MCSubtargetInfo.h"20#include "llvm/Support/Casting.h"21#include "llvm/Support/Endian.h"22#include "llvm/Support/FormattedStream.h"23#include <algorithm>2425using namespace llvm;26using namespace llvm::object;27using namespace llvm::XCOFF;28using namespace llvm::support;2930namespace {31class XCOFFDumper : public objdump::Dumper {32public:33XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {}34void printPrivateHeaders() override {}35};36} // namespace3738std::unique_ptr<objdump::Dumper>39objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) {40return std::make_unique<XCOFFDumper>(Obj);41}4243Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj,44const RelocationRef &Rel,45bool SymbolDescription,46SmallVectorImpl<char> &Result) {47symbol_iterator SymI = Rel.getSymbol();48if (SymI == Obj.symbol_end())49return make_error<GenericBinaryError>(50"invalid symbol reference in relocation entry",51object_error::parse_failed);5253Expected<StringRef> SymNameOrErr = SymI->getName();54if (!SymNameOrErr)55return SymNameOrErr.takeError();5657std::string SymName =58Demangle ? demangle(*SymNameOrErr) : SymNameOrErr->str();59if (SymbolDescription)60SymName = getXCOFFSymbolDescription(createSymbolInfo(Obj, *SymI), SymName);6162Result.append(SymName.begin(), SymName.end());63return Error::success();64}6566std::optional<XCOFF::StorageMappingClass>67objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj,68const SymbolRef &Sym) {69const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());7071if (!SymRef.isCsectSymbol())72return std::nullopt;7374auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();75if (!CsectAuxEntOrErr)76return std::nullopt;7778return CsectAuxEntOrErr.get().getStorageMappingClass();79}8081std::optional<object::SymbolRef>82objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj,83const SymbolRef &Sym) {84const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());85if (!SymRef.isCsectSymbol())86return std::nullopt;8788Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();89if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())90return std::nullopt;91uint32_t Idx =92static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());93DataRefImpl DRI;94DRI.p = Obj.getSymbolByIndex(Idx);95return SymbolRef(DRI, &Obj);96}9798bool objdump::isLabel(const XCOFFObjectFile &Obj, const SymbolRef &Sym) {99const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl());100if (!SymRef.isCsectSymbol())101return false;102103auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();104if (!CsectAuxEntOrErr)105return false;106107return CsectAuxEntOrErr.get().isLabel();108}109110std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo,111StringRef SymbolName) {112assert(SymbolInfo.isXCOFF() && "Must be a XCOFFSymInfo.");113114std::string Result;115// Dummy symbols have no symbol index.116if (SymbolInfo.XCOFFSymInfo.Index)117Result =118("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName)119.str();120else121Result.append(SymbolName.begin(), SymbolName.end());122123if (SymbolInfo.XCOFFSymInfo.StorageMappingClass &&124!SymbolInfo.XCOFFSymInfo.IsLabel) {125const XCOFF::StorageMappingClass Smc =126*SymbolInfo.XCOFFSymInfo.StorageMappingClass;127Result.append(("[" + XCOFF::getMappingClassString(Smc) + "]").str());128}129130return Result;131}132133#define PRINTBOOL(Prefix, Obj, Field) \134OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field135136#define PRINTGET(Prefix, Obj, Field) \137OS << Prefix << " " << #Field << " = " \138<< static_cast<unsigned>(Obj.get##Field())139140#define PRINTOPTIONAL(Field) \141if (TbTable.get##Field()) { \142OS << '\n'; \143printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \144Index += 4; \145OS << "\t# " << #Field << " = " << *TbTable.get##Field(); \146}147148void objdump::dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address,149formatted_raw_ostream &OS, uint64_t End,150const MCSubtargetInfo &STI,151const XCOFFObjectFile *Obj) {152uint64_t Index = 0;153unsigned TabStop = getInstStartColumn(STI) - 1;154// Print traceback table boundary.155printRawData(Bytes.slice(Index, 4), Address, OS, STI);156OS << "\t# Traceback table start\n";157Index += 4;158159uint64_t Size = End - Address;160bool Is64Bit = Obj->is64Bit();161162// XCOFFTracebackTable::create modifies the size parameter, so ensure Size163// isn't changed.164uint64_t SizeCopy = End - Address;165Expected<XCOFFTracebackTable> TTOrErr =166XCOFFTracebackTable::create(Bytes.data() + Index, SizeCopy, Is64Bit);167168if (!TTOrErr) {169std::string WarningMsgStr;170raw_string_ostream WarningStream(WarningMsgStr);171WarningStream << "failure parsing traceback table with address: 0x"172<< utohexstr(Address) + "\n>>> "173<< toString(TTOrErr.takeError())174<< "\n>>> Raw traceback table data is:\n";175176uint64_t LastNonZero = Index;177for (uint64_t I = Index; I < Size; I += 4)178if (support::endian::read32be(Bytes.slice(I, 4).data()) != 0)179LastNonZero = I + 4 > Size ? Size : I + 4;180181if (Size - LastNonZero <= 4)182LastNonZero = Size;183184formatted_raw_ostream FOS(WarningStream);185while (Index < LastNonZero) {186printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI);187Index += 4;188WarningStream << '\n';189}190191// Print all remaining zeroes as ...192if (Size - LastNonZero >= 8)193WarningStream << "\t\t...\n";194195reportWarning(WarningMsgStr, Obj->getFileName());196return;197}198199auto PrintBytes = [&](uint64_t N) {200printRawData(Bytes.slice(Index, N), Address + Index, OS, STI);201Index += N;202};203204XCOFFTracebackTable TbTable = *TTOrErr;205// Print the first of the 8 bytes of mandatory fields.206PrintBytes(1);207OS << format("\t# Version = %i", TbTable.getVersion()) << '\n';208209// Print the second of the 8 bytes of mandatory fields.210PrintBytes(1);211TracebackTable::LanguageID LangId =212static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID());213OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n';214215auto Split = [&]() {216OS << '\n';217OS.indent(TabStop);218};219220// Print the third of the 8 bytes of mandatory fields.221PrintBytes(1);222PRINTBOOL("\t#", TbTable, isGlobalLinkage);223PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue);224Split();225PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset);226PRINTBOOL(",", TbTable, isInternalProcedure);227Split();228PRINTBOOL("\t ", TbTable, hasControlledStorage);229PRINTBOOL(",", TbTable, isTOCless);230Split();231PRINTBOOL("\t ", TbTable, isFloatingPointPresent);232Split();233PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled);234OS << '\n';235236// Print the 4th of the 8 bytes of mandatory fields.237PrintBytes(1);238PRINTBOOL("\t#", TbTable, isInterruptHandler);239PRINTBOOL(",", TbTable, isFuncNamePresent);240PRINTBOOL(",", TbTable, isAllocaUsed);241Split();242PRINTGET("\t ", TbTable, OnConditionDirective);243PRINTBOOL(",", TbTable, isCRSaved);244PRINTBOOL(",", TbTable, isLRSaved);245OS << '\n';246247// Print the 5th of the 8 bytes of mandatory fields.248PrintBytes(1);249PRINTBOOL("\t#", TbTable, isBackChainStored);250PRINTBOOL(",", TbTable, isFixup);251PRINTGET(",", TbTable, NumOfFPRsSaved);252OS << '\n';253254// Print the 6th of the 8 bytes of mandatory fields.255PrintBytes(1);256PRINTBOOL("\t#", TbTable, hasExtensionTable);257PRINTBOOL(",", TbTable, hasVectorInfo);258PRINTGET(",", TbTable, NumOfGPRsSaved);259OS << '\n';260261// Print the 7th of the 8 bytes of mandatory fields.262PrintBytes(1);263PRINTGET("\t#", TbTable, NumberOfFixedParms);264OS << '\n';265266// Print the 8th of the 8 bytes of mandatory fields.267PrintBytes(1);268PRINTGET("\t#", TbTable, NumberOfFPParms);269PRINTBOOL(",", TbTable, hasParmsOnStack);270271PRINTOPTIONAL(ParmsType);272PRINTOPTIONAL(TraceBackTableOffset);273PRINTOPTIONAL(HandlerMask);274PRINTOPTIONAL(NumOfCtlAnchors);275276if (TbTable.getControlledStorageInfoDisp()) {277SmallVector<uint32_t, 8> Disp = *TbTable.getControlledStorageInfoDisp();278for (unsigned I = 0; I < Disp.size(); ++I) {279OS << '\n';280PrintBytes(4);281OS << "\t" << (I ? " " : "#") << " ControlledStorageInfoDisp[" << I282<< "] = " << Disp[I];283}284}285286// If there is a name, print the function name and function name length.287if (TbTable.isFuncNamePresent()) {288uint16_t FunctionNameLen = TbTable.getFunctionName()->size();289if (FunctionNameLen == 0) {290OS << '\n';291reportWarning(292"the length of the function name must be greater than zero if the "293"isFuncNamePresent bit is set in the traceback table",294Obj->getFileName());295return;296}297298OS << '\n';299PrintBytes(2);300OS << "\t# FunctionNameLen = " << FunctionNameLen;301302uint16_t RemainingBytes = FunctionNameLen;303bool HasPrinted = false;304while (RemainingBytes > 0) {305OS << '\n';306uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes;307printRawData(Bytes.slice(Index, PrintLen), Address + Index, OS, STI);308Index += PrintLen;309RemainingBytes -= PrintLen;310311if (!HasPrinted) {312OS << "\t# FunctionName = " << *TbTable.getFunctionName();313HasPrinted = true;314}315}316}317318if (TbTable.isAllocaUsed()) {319OS << '\n';320PrintBytes(1);321OS << format("\t# AllocaRegister = %u", *TbTable.getAllocaRegister());322}323324if (TbTable.getVectorExt()) {325OS << '\n';326TBVectorExt VecExt = *TbTable.getVectorExt();327// Print first byte of VectorExt.328PrintBytes(1);329PRINTGET("\t#", VecExt, NumberOfVRSaved);330PRINTBOOL(",", VecExt, isVRSavedOnStack);331PRINTBOOL(",", VecExt, hasVarArgs);332OS << '\n';333334// Print the second byte of VectorExt.335PrintBytes(1);336PRINTGET("\t#", VecExt, NumberOfVectorParms);337PRINTBOOL(",", VecExt, hasVMXInstruction);338OS << '\n';339340PrintBytes(4);341OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo();342343// There are two bytes of padding after vector info.344OS << '\n';345PrintBytes(2);346OS << "\t# Padding";347}348349if (TbTable.getExtensionTable()) {350OS << '\n';351PrintBytes(1);352ExtendedTBTableFlag Flag =353static_cast<ExtendedTBTableFlag>(*TbTable.getExtensionTable());354OS << "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag);355}356357if (TbTable.getEhInfoDisp()) {358// There are 4 bytes alignment before eh info displacement.359if (Index % 4) {360OS << '\n';361PrintBytes(4 - Index % 4);362OS << "\t# Alignment padding for eh info displacement";363}364OS << '\n';365// The size of the displacement (address) is 4 bytes in 32-bit object files,366// and 8 bytes in 64-bit object files.367PrintBytes(4);368OS << "\t# EH info displacement";369if (Is64Bit) {370OS << '\n';371PrintBytes(4);372}373}374375OS << '\n';376if (End == Address + Index)377return;378379Size = End - Address;380381const char *LineSuffix = "\t# Padding\n";382auto IsWordZero = [&](uint64_t WordPos) {383if (WordPos >= Size)384return false;385uint64_t LineLength = std::min(4 - WordPos % 4, Size - WordPos);386return std::all_of(Bytes.begin() + WordPos,387Bytes.begin() + WordPos + LineLength,388[](uint8_t Byte) { return Byte == 0; });389};390391bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Index, 4) + 4),392IsWordZero(alignTo(Index, 4) + 8)};393bool ShouldPrintLine = true;394while (true) {395// Determine the length of the line (4, except for the first line, which396// will be just enough to align to the word boundary, and the last line,397// which will be the remainder of the data).398uint64_t LineLength = std::min(4 - Index % 4, Size - Index);399if (ShouldPrintLine) {400// Print the line.401printRawData(Bytes.slice(Index, LineLength), Address + Index, OS, STI);402OS << LineSuffix;403LineSuffix = "\n";404}405406Index += LineLength;407if (Index == Size)408return;409410// For 3 or more consecutive lines of zeros, skip all but the first one, and411// replace them with "...".412if (AreWordsZero[0] && AreWordsZero[1] && AreWordsZero[2]) {413if (ShouldPrintLine)414OS << std::string(8, ' ') << "...\n";415ShouldPrintLine = false;416} else if (!AreWordsZero[1]) {417// We have reached the end of a skipped block of zeros.418ShouldPrintLine = true;419}420AreWordsZero[0] = AreWordsZero[1];421AreWordsZero[1] = AreWordsZero[2];422AreWordsZero[2] = IsWordZero(Index + 8);423}424}425#undef PRINTBOOL426#undef PRINTGET427#undef PRINTOPTIONAL428429430