Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / tools / llvm-objdump / XCOFFDump.cpp
blob0f6147924f8a1a310ee1242fe66fe6196afdeaf0
1 //===-- XCOFFDump.cpp - XCOFF-specific dumper -----------------------------===//
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 /// \file
10 /// This file implements the XCOFF-specific dumper for llvm-objdump.
11 ///
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"
24 #include <algorithm>
26 using namespace llvm;
27 using namespace llvm::object;
28 using namespace llvm::XCOFF;
29 using namespace llvm::support;
31 namespace {
32 class XCOFFDumper : public objdump::Dumper {
33 public:
34 XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {}
35 void printPrivateHeaders() override {}
37 } // namespace
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();
54 if (!SymNameOrErr)
55 return SymNameOrErr.takeError();
57 std::string SymName =
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())
72 return std::nullopt;
74 auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
75 if (!CsectAuxEntOrErr)
76 return std::nullopt;
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())
86 return std::nullopt;
88 Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
89 if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel())
90 return std::nullopt;
91 uint32_t Idx =
92 static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength());
93 DataRefImpl DRI;
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())
101 return false;
103 auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef();
104 if (!CsectAuxEntOrErr)
105 return false;
107 return CsectAuxEntOrErr.get().isLabel();
110 std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo,
111 StringRef SymbolName) {
112 assert(SymbolInfo.isXCOFF() && "Must be a XCOFFSymInfo.");
114 std::string Result;
115 // Dummy symbols have no symbol index.
116 if (SymbolInfo.XCOFFSymInfo.Index)
117 Result =
118 ("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName)
119 .str();
120 else
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());
130 return Result;
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()) { \
142 OS << '\n'; \
143 printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \
144 Index += 4; \
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) {
152 uint64_t Index = 0;
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";
157 Index += 4;
159 uint64_t Size = End - Address;
160 bool Is64Bit = Obj->is64Bit();
162 // XCOFFTracebackTable::create modifies the size parameter, so ensure Size
163 // isn't changed.
164 uint64_t SizeCopy = End - Address;
165 Expected<XCOFFTracebackTable> TTOrErr =
166 XCOFFTracebackTable::create(Bytes.data() + Index, SizeCopy, Is64Bit);
168 if (!TTOrErr) {
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)
182 LastNonZero = Size;
184 formatted_raw_ostream FOS(WarningStream);
185 while (Index < LastNonZero) {
186 printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI);
187 Index += 4;
188 WarningStream << '\n';
191 // Print all remaining zeroes as ...
192 if (Size - LastNonZero >= 8)
193 WarningStream << "\t\t...\n";
195 reportWarning(WarningMsgStr, Obj->getFileName());
196 return;
199 auto PrintBytes = [&](uint64_t N) {
200 printRawData(Bytes.slice(Index, N), Address + Index, OS, STI);
201 Index += N;
204 XCOFFTracebackTable TbTable = *TTOrErr;
205 // Print the first of the 8 bytes of mandatory fields.
206 PrintBytes(1);
207 OS << format("\t# Version = %i", TbTable.getVersion()) << '\n';
209 // Print the second of the 8 bytes of mandatory fields.
210 PrintBytes(1);
211 TracebackTable::LanguageID LangId =
212 static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID());
213 OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n';
215 auto Split = [&]() {
216 OS << '\n';
217 OS.indent(TabStop);
220 // Print the third of the 8 bytes of mandatory fields.
221 PrintBytes(1);
222 PRINTBOOL("\t#", TbTable, isGlobalLinkage);
223 PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue);
224 Split();
225 PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset);
226 PRINTBOOL(",", TbTable, isInternalProcedure);
227 Split();
228 PRINTBOOL("\t ", TbTable, hasControlledStorage);
229 PRINTBOOL(",", TbTable, isTOCless);
230 Split();
231 PRINTBOOL("\t ", TbTable, isFloatingPointPresent);
232 Split();
233 PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled);
234 OS << '\n';
236 // Print the 4th of the 8 bytes of mandatory fields.
237 PrintBytes(1);
238 PRINTBOOL("\t#", TbTable, isInterruptHandler);
239 PRINTBOOL(",", TbTable, isFuncNamePresent);
240 PRINTBOOL(",", TbTable, isAllocaUsed);
241 Split();
242 PRINTGET("\t ", TbTable, OnConditionDirective);
243 PRINTBOOL(",", TbTable, isCRSaved);
244 PRINTBOOL(",", TbTable, isLRSaved);
245 OS << '\n';
247 // Print the 5th of the 8 bytes of mandatory fields.
248 PrintBytes(1);
249 PRINTBOOL("\t#", TbTable, isBackChainStored);
250 PRINTBOOL(",", TbTable, isFixup);
251 PRINTGET(",", TbTable, NumOfFPRsSaved);
252 OS << '\n';
254 // Print the 6th of the 8 bytes of mandatory fields.
255 PrintBytes(1);
256 PRINTBOOL("\t#", TbTable, hasExtensionTable);
257 PRINTBOOL(",", TbTable, hasVectorInfo);
258 PRINTGET(",", TbTable, NumOfGPRsSaved);
259 OS << '\n';
261 // Print the 7th of the 8 bytes of mandatory fields.
262 PrintBytes(1);
263 PRINTGET("\t#", TbTable, NumberOfFixedParms);
264 OS << '\n';
266 // Print the 8th of the 8 bytes of mandatory fields.
267 PrintBytes(1);
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) {
279 OS << '\n';
280 PrintBytes(4);
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) {
290 OS << '\n';
291 reportWarning(
292 "the length of the function name must be greater than zero if the "
293 "isFuncNamePresent bit is set in the traceback table",
294 Obj->getFileName());
295 return;
298 OS << '\n';
299 PrintBytes(2);
300 OS << "\t# FunctionNameLen = " << FunctionNameLen;
302 uint16_t RemainingBytes = FunctionNameLen;
303 bool HasPrinted = false;
304 while (RemainingBytes > 0) {
305 OS << '\n';
306 uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes;
307 printRawData(Bytes.slice(Index, PrintLen), Address + Index, OS, STI);
308 Index += PrintLen;
309 RemainingBytes -= PrintLen;
311 if (!HasPrinted) {
312 OS << "\t# FunctionName = " << *TbTable.getFunctionName();
313 HasPrinted = true;
318 if (TbTable.isAllocaUsed()) {
319 OS << '\n';
320 PrintBytes(1);
321 OS << format("\t# AllocaRegister = %u", *TbTable.getAllocaRegister());
324 if (TbTable.getVectorExt()) {
325 OS << '\n';
326 TBVectorExt VecExt = *TbTable.getVectorExt();
327 // Print first byte of VectorExt.
328 PrintBytes(1);
329 PRINTGET("\t#", VecExt, NumberOfVRSaved);
330 PRINTBOOL(",", VecExt, isVRSavedOnStack);
331 PRINTBOOL(",", VecExt, hasVarArgs);
332 OS << '\n';
334 // Print the second byte of VectorExt.
335 PrintBytes(1);
336 PRINTGET("\t#", VecExt, NumberOfVectorParms);
337 PRINTBOOL(",", VecExt, hasVMXInstruction);
338 OS << '\n';
340 PrintBytes(4);
341 OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo();
343 // There are two bytes of padding after vector info.
344 OS << '\n';
345 PrintBytes(2);
346 OS << "\t# Padding";
349 if (TbTable.getExtensionTable()) {
350 OS << '\n';
351 PrintBytes(1);
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.
359 if (Index % 4) {
360 OS << '\n';
361 PrintBytes(4 - Index % 4);
362 OS << "\t# Alignment padding for eh info displacement";
364 OS << '\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.
367 PrintBytes(4);
368 OS << "\t# EH info displacement";
369 if (Is64Bit) {
370 OS << '\n';
371 PrintBytes(4);
375 OS << '\n';
376 if (End == Address + Index)
377 return;
379 Size = End - Address;
381 const char *LineSuffix = "\t# Padding\n";
382 auto IsWordZero = [&](uint64_t WordPos) {
383 if (WordPos >= Size)
384 return false;
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;
394 while (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) {
400 // Print the line.
401 printRawData(Bytes.slice(Index, LineLength), Address + Index, OS, STI);
402 OS << LineSuffix;
403 LineSuffix = "\n";
406 Index += LineLength;
407 if (Index == Size)
408 return;
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]) {
413 if (ShouldPrintLine)
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);
425 #undef PRINTBOOL
426 #undef PRINTGET
427 #undef PRINTOPTIONAL