1 //===-- XCOFFDump.cpp - XCOFF-specific dumper -----------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file implements the XCOFF-specific dumper for llvm-objdump.
12 //===----------------------------------------------------------------------===//
14 #include "XCOFFDump.h"
16 #include "llvm-objdump.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/Demangle/Demangle.h"
19 #include "llvm/MC/MCInstPrinter.h"
20 #include "llvm/MC/MCSubtargetInfo.h"
21 #include "llvm/Support/Casting.h"
22 #include "llvm/Support/Endian.h"
23 #include "llvm/Support/FormattedStream.h"
27 using namespace llvm::object
;
28 using namespace llvm::XCOFF
;
29 using namespace llvm::support
;
32 class XCOFFDumper
: public objdump::Dumper
{
34 XCOFFDumper(const object::XCOFFObjectFile
&O
) : Dumper(O
) {}
35 void printPrivateHeaders() override
{}
39 std::unique_ptr
<objdump::Dumper
>
40 objdump::createXCOFFDumper(const object::XCOFFObjectFile
&Obj
) {
41 return std::make_unique
<XCOFFDumper
>(Obj
);
44 Error
objdump::getXCOFFRelocationValueString(const XCOFFObjectFile
&Obj
,
45 const RelocationRef
&Rel
,
46 SmallVectorImpl
<char> &Result
) {
47 symbol_iterator SymI
= Rel
.getSymbol();
48 if (SymI
== Obj
.symbol_end())
49 return make_error
<GenericBinaryError
>(
50 "invalid symbol reference in relocation entry",
51 object_error::parse_failed
);
53 Expected
<StringRef
> SymNameOrErr
= SymI
->getName();
55 return SymNameOrErr
.takeError();
58 Demangle
? demangle(*SymNameOrErr
) : SymNameOrErr
->str();
59 if (SymbolDescription
)
60 SymName
= getXCOFFSymbolDescription(createSymbolInfo(Obj
, *SymI
), SymName
);
62 Result
.append(SymName
.begin(), SymName
.end());
63 return Error::success();
66 std::optional
<XCOFF::StorageMappingClass
>
67 objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile
&Obj
,
68 const SymbolRef
&Sym
) {
69 const XCOFFSymbolRef SymRef
= Obj
.toSymbolRef(Sym
.getRawDataRefImpl());
71 if (!SymRef
.isCsectSymbol())
74 auto CsectAuxEntOrErr
= SymRef
.getXCOFFCsectAuxRef();
75 if (!CsectAuxEntOrErr
)
78 return CsectAuxEntOrErr
.get().getStorageMappingClass();
81 std::optional
<object::SymbolRef
>
82 objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile
&Obj
,
83 const SymbolRef
&Sym
) {
84 const XCOFFSymbolRef SymRef
= Obj
.toSymbolRef(Sym
.getRawDataRefImpl());
85 if (!SymRef
.isCsectSymbol())
88 Expected
<XCOFFCsectAuxRef
> CsectAuxEntOrErr
= SymRef
.getXCOFFCsectAuxRef();
89 if (!CsectAuxEntOrErr
|| !CsectAuxEntOrErr
.get().isLabel())
92 static_cast<uint32_t>(CsectAuxEntOrErr
.get().getSectionOrLength());
94 DRI
.p
= Obj
.getSymbolByIndex(Idx
);
95 return SymbolRef(DRI
, &Obj
);
98 bool objdump::isLabel(const XCOFFObjectFile
&Obj
, const SymbolRef
&Sym
) {
99 const XCOFFSymbolRef SymRef
= Obj
.toSymbolRef(Sym
.getRawDataRefImpl());
100 if (!SymRef
.isCsectSymbol())
103 auto CsectAuxEntOrErr
= SymRef
.getXCOFFCsectAuxRef();
104 if (!CsectAuxEntOrErr
)
107 return CsectAuxEntOrErr
.get().isLabel();
110 std::string
objdump::getXCOFFSymbolDescription(const SymbolInfoTy
&SymbolInfo
,
111 StringRef SymbolName
) {
112 assert(SymbolInfo
.isXCOFF() && "Must be a XCOFFSymInfo.");
115 // Dummy symbols have no symbol index.
116 if (SymbolInfo
.XCOFFSymInfo
.Index
)
118 ("(idx: " + Twine(*SymbolInfo
.XCOFFSymInfo
.Index
) + ") " + SymbolName
)
121 Result
.append(SymbolName
.begin(), SymbolName
.end());
123 if (SymbolInfo
.XCOFFSymInfo
.StorageMappingClass
&&
124 !SymbolInfo
.XCOFFSymInfo
.IsLabel
) {
125 const XCOFF::StorageMappingClass Smc
=
126 *SymbolInfo
.XCOFFSymInfo
.StorageMappingClass
;
127 Result
.append(("[" + XCOFF::getMappingClassString(Smc
) + "]").str());
133 #define PRINTBOOL(Prefix, Obj, Field) \
134 OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field
136 #define PRINTGET(Prefix, Obj, Field) \
137 OS << Prefix << " " << #Field << " = " \
138 << static_cast<unsigned>(Obj.get##Field())
140 #define PRINTOPTIONAL(Field) \
141 if (TbTable.get##Field()) { \
143 printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \
145 OS << "\t# " << #Field << " = " << *TbTable.get##Field(); \
148 void objdump::dumpTracebackTable(ArrayRef
<uint8_t> Bytes
, uint64_t Address
,
149 formatted_raw_ostream
&OS
, uint64_t End
,
150 const MCSubtargetInfo
&STI
,
151 const XCOFFObjectFile
*Obj
) {
153 unsigned TabStop
= getInstStartColumn(STI
) - 1;
154 // Print traceback table boundary.
155 printRawData(Bytes
.slice(Index
, 4), Address
, OS
, STI
);
156 OS
<< "\t# Traceback table start\n";
159 uint64_t Size
= End
- Address
;
160 bool Is64Bit
= Obj
->is64Bit();
162 // XCOFFTracebackTable::create modifies the size parameter, so ensure Size
164 uint64_t SizeCopy
= End
- Address
;
165 Expected
<XCOFFTracebackTable
> TTOrErr
=
166 XCOFFTracebackTable::create(Bytes
.data() + Index
, SizeCopy
, Is64Bit
);
169 std::string WarningMsgStr
;
170 raw_string_ostream
WarningStream(WarningMsgStr
);
171 WarningStream
<< "failure parsing traceback table with address: 0x"
172 << utohexstr(Address
) + "\n>>> "
173 << toString(TTOrErr
.takeError())
174 << "\n>>> Raw traceback table data is:\n";
176 uint64_t LastNonZero
= Index
;
177 for (uint64_t I
= Index
; I
< Size
; I
+= 4)
178 if (support::endian::read32be(Bytes
.slice(I
, 4).data()) != 0)
179 LastNonZero
= I
+ 4 > Size
? Size
: I
+ 4;
181 if (Size
- LastNonZero
<= 4)
184 formatted_raw_ostream
FOS(WarningStream
);
185 while (Index
< LastNonZero
) {
186 printRawData(Bytes
.slice(Index
, 4), Address
+ Index
, FOS
, STI
);
188 WarningStream
<< '\n';
191 // Print all remaining zeroes as ...
192 if (Size
- LastNonZero
>= 8)
193 WarningStream
<< "\t\t...\n";
195 reportWarning(WarningMsgStr
, Obj
->getFileName());
199 auto PrintBytes
= [&](uint64_t N
) {
200 printRawData(Bytes
.slice(Index
, N
), Address
+ Index
, OS
, STI
);
204 XCOFFTracebackTable TbTable
= *TTOrErr
;
205 // Print the first of the 8 bytes of mandatory fields.
207 OS
<< format("\t# Version = %i", TbTable
.getVersion()) << '\n';
209 // Print the second of the 8 bytes of mandatory fields.
211 TracebackTable::LanguageID LangId
=
212 static_cast<TracebackTable::LanguageID
>(TbTable
.getLanguageID());
213 OS
<< "\t# Language = " << getNameForTracebackTableLanguageId(LangId
) << '\n';
220 // Print the third of the 8 bytes of mandatory fields.
222 PRINTBOOL("\t#", TbTable
, isGlobalLinkage
);
223 PRINTBOOL(",", TbTable
, isOutOfLineEpilogOrPrologue
);
225 PRINTBOOL("\t ", TbTable
, hasTraceBackTableOffset
);
226 PRINTBOOL(",", TbTable
, isInternalProcedure
);
228 PRINTBOOL("\t ", TbTable
, hasControlledStorage
);
229 PRINTBOOL(",", TbTable
, isTOCless
);
231 PRINTBOOL("\t ", TbTable
, isFloatingPointPresent
);
233 PRINTBOOL("\t ", TbTable
, isFloatingPointOperationLogOrAbortEnabled
);
236 // Print the 4th of the 8 bytes of mandatory fields.
238 PRINTBOOL("\t#", TbTable
, isInterruptHandler
);
239 PRINTBOOL(",", TbTable
, isFuncNamePresent
);
240 PRINTBOOL(",", TbTable
, isAllocaUsed
);
242 PRINTGET("\t ", TbTable
, OnConditionDirective
);
243 PRINTBOOL(",", TbTable
, isCRSaved
);
244 PRINTBOOL(",", TbTable
, isLRSaved
);
247 // Print the 5th of the 8 bytes of mandatory fields.
249 PRINTBOOL("\t#", TbTable
, isBackChainStored
);
250 PRINTBOOL(",", TbTable
, isFixup
);
251 PRINTGET(",", TbTable
, NumOfFPRsSaved
);
254 // Print the 6th of the 8 bytes of mandatory fields.
256 PRINTBOOL("\t#", TbTable
, hasExtensionTable
);
257 PRINTBOOL(",", TbTable
, hasVectorInfo
);
258 PRINTGET(",", TbTable
, NumOfGPRsSaved
);
261 // Print the 7th of the 8 bytes of mandatory fields.
263 PRINTGET("\t#", TbTable
, NumberOfFixedParms
);
266 // Print the 8th of the 8 bytes of mandatory fields.
268 PRINTGET("\t#", TbTable
, NumberOfFPParms
);
269 PRINTBOOL(",", TbTable
, hasParmsOnStack
);
271 PRINTOPTIONAL(ParmsType
);
272 PRINTOPTIONAL(TraceBackTableOffset
);
273 PRINTOPTIONAL(HandlerMask
);
274 PRINTOPTIONAL(NumOfCtlAnchors
);
276 if (TbTable
.getControlledStorageInfoDisp()) {
277 SmallVector
<uint32_t, 8> Disp
= *TbTable
.getControlledStorageInfoDisp();
278 for (unsigned I
= 0; I
< Disp
.size(); ++I
) {
281 OS
<< "\t" << (I
? " " : "#") << " ControlledStorageInfoDisp[" << I
282 << "] = " << Disp
[I
];
286 // If there is a name, print the function name and function name length.
287 if (TbTable
.isFuncNamePresent()) {
288 uint16_t FunctionNameLen
= TbTable
.getFunctionName()->size();
289 if (FunctionNameLen
== 0) {
292 "the length of the function name must be greater than zero if the "
293 "isFuncNamePresent bit is set in the traceback table",
300 OS
<< "\t# FunctionNameLen = " << FunctionNameLen
;
302 uint16_t RemainingBytes
= FunctionNameLen
;
303 bool HasPrinted
= false;
304 while (RemainingBytes
> 0) {
306 uint16_t PrintLen
= RemainingBytes
>= 4 ? 4 : RemainingBytes
;
307 printRawData(Bytes
.slice(Index
, PrintLen
), Address
+ Index
, OS
, STI
);
309 RemainingBytes
-= PrintLen
;
312 OS
<< "\t# FunctionName = " << *TbTable
.getFunctionName();
318 if (TbTable
.isAllocaUsed()) {
321 OS
<< format("\t# AllocaRegister = %u", *TbTable
.getAllocaRegister());
324 if (TbTable
.getVectorExt()) {
326 TBVectorExt VecExt
= *TbTable
.getVectorExt();
327 // Print first byte of VectorExt.
329 PRINTGET("\t#", VecExt
, NumberOfVRSaved
);
330 PRINTBOOL(",", VecExt
, isVRSavedOnStack
);
331 PRINTBOOL(",", VecExt
, hasVarArgs
);
334 // Print the second byte of VectorExt.
336 PRINTGET("\t#", VecExt
, NumberOfVectorParms
);
337 PRINTBOOL(",", VecExt
, hasVMXInstruction
);
341 OS
<< "\t# VectorParmsInfoString = " << VecExt
.getVectorParmsInfo();
343 // There are two bytes of padding after vector info.
349 if (TbTable
.getExtensionTable()) {
352 ExtendedTBTableFlag Flag
=
353 static_cast<ExtendedTBTableFlag
>(*TbTable
.getExtensionTable());
354 OS
<< "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag
);
357 if (TbTable
.getEhInfoDisp()) {
358 // There are 4 bytes alignment before eh info displacement.
361 PrintBytes(4 - Index
% 4);
362 OS
<< "\t# Alignment padding for eh info displacement";
365 // The size of the displacement (address) is 4 bytes in 32-bit object files,
366 // and 8 bytes in 64-bit object files.
368 OS
<< "\t# EH info displacement";
376 if (End
== Address
+ Index
)
379 Size
= End
- Address
;
381 const char *LineSuffix
= "\t# Padding\n";
382 auto IsWordZero
= [&](uint64_t WordPos
) {
385 uint64_t LineLength
= std::min(4 - WordPos
% 4, Size
- WordPos
);
386 return std::all_of(Bytes
.begin() + WordPos
,
387 Bytes
.begin() + WordPos
+ LineLength
,
388 [](uint8_t Byte
) { return Byte
== 0; });
391 bool AreWordsZero
[] = {IsWordZero(Index
), IsWordZero(alignTo(Index
, 4) + 4),
392 IsWordZero(alignTo(Index
, 4) + 8)};
393 bool ShouldPrintLine
= true;
395 // Determine the length of the line (4, except for the first line, which
396 // will be just enough to align to the word boundary, and the last line,
397 // which will be the remainder of the data).
398 uint64_t LineLength
= std::min(4 - Index
% 4, Size
- Index
);
399 if (ShouldPrintLine
) {
401 printRawData(Bytes
.slice(Index
, LineLength
), Address
+ Index
, OS
, STI
);
410 // For 3 or more consecutive lines of zeros, skip all but the first one, and
411 // replace them with "...".
412 if (AreWordsZero
[0] && AreWordsZero
[1] && AreWordsZero
[2]) {
414 OS
<< std::string(8, ' ') << "...\n";
415 ShouldPrintLine
= false;
416 } else if (!AreWordsZero
[1]) {
417 // We have reached the end of a skipped block of zeros.
418 ShouldPrintLine
= true;
420 AreWordsZero
[0] = AreWordsZero
[1];
421 AreWordsZero
[1] = AreWordsZero
[2];
422 AreWordsZero
[2] = IsWordZero(Index
+ 8);