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 //===----------------------------------------------------------------------===// 13 14 #include "XCOFFDump.h" 15 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> 25 26 using namespace llvm; 27 using namespace llvm::object; 28 using namespace llvm::XCOFF; 29 using namespace llvm::support; 30 31 namespace { 32 class XCOFFDumper : public objdump::Dumper { 33 public: 34 XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {} 35 void printPrivateHeaders(bool MachOOnlyFirst) override; 36 }; 37 } // namespace 38 39 std::unique_ptr<objdump::Dumper> 40 objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) { 41 return std::make_unique<XCOFFDumper>(Obj); 42 } 43 44 void XCOFFDumper::printPrivateHeaders(bool) {} 45 46 Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj, 47 const RelocationRef &Rel, 48 SmallVectorImpl<char> &Result) { 49 symbol_iterator SymI = Rel.getSymbol(); 50 if (SymI == Obj.symbol_end()) 51 return make_error<GenericBinaryError>( 52 "invalid symbol reference in relocation entry", 53 object_error::parse_failed); 54 55 Expected<StringRef> SymNameOrErr = SymI->getName(); 56 if (!SymNameOrErr) 57 return SymNameOrErr.takeError(); 58 59 std::string SymName = 60 Demangle ? demangle(*SymNameOrErr) : SymNameOrErr->str(); 61 if (SymbolDescription) 62 SymName = getXCOFFSymbolDescription(createSymbolInfo(Obj, *SymI), SymName); 63 64 Result.append(SymName.begin(), SymName.end()); 65 return Error::success(); 66 } 67 68 std::optional<XCOFF::StorageMappingClass> 69 objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj, 70 const SymbolRef &Sym) { 71 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl()); 72 73 if (!SymRef.isCsectSymbol()) 74 return std::nullopt; 75 76 auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef(); 77 if (!CsectAuxEntOrErr) 78 return std::nullopt; 79 80 return CsectAuxEntOrErr.get().getStorageMappingClass(); 81 } 82 83 std::optional<object::SymbolRef> 84 objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj, 85 const SymbolRef &Sym) { 86 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl()); 87 if (!SymRef.isCsectSymbol()) 88 return std::nullopt; 89 90 Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef(); 91 if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel()) 92 return std::nullopt; 93 uint32_t Idx = 94 static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength()); 95 DataRefImpl DRI; 96 DRI.p = Obj.getSymbolByIndex(Idx); 97 return SymbolRef(DRI, &Obj); 98 } 99 100 bool objdump::isLabel(const XCOFFObjectFile &Obj, const SymbolRef &Sym) { 101 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl()); 102 if (!SymRef.isCsectSymbol()) 103 return false; 104 105 auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef(); 106 if (!CsectAuxEntOrErr) 107 return false; 108 109 return CsectAuxEntOrErr.get().isLabel(); 110 } 111 112 std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, 113 StringRef SymbolName) { 114 assert(SymbolInfo.isXCOFF() && "Must be a XCOFFSymInfo."); 115 116 std::string Result; 117 // Dummy symbols have no symbol index. 118 if (SymbolInfo.XCOFFSymInfo.Index) 119 Result = 120 ("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName) 121 .str(); 122 else 123 Result.append(SymbolName.begin(), SymbolName.end()); 124 125 if (SymbolInfo.XCOFFSymInfo.StorageMappingClass && 126 !SymbolInfo.XCOFFSymInfo.IsLabel) { 127 const XCOFF::StorageMappingClass Smc = 128 *SymbolInfo.XCOFFSymInfo.StorageMappingClass; 129 Result.append(("[" + XCOFF::getMappingClassString(Smc) + "]").str()); 130 } 131 132 return Result; 133 } 134 135 #define PRINTBOOL(Prefix, Obj, Field) \ 136 OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field 137 138 #define PRINTGET(Prefix, Obj, Field) \ 139 OS << Prefix << " " << #Field << " = " \ 140 << static_cast<unsigned>(Obj.get##Field()) 141 142 #define PRINTOPTIONAL(Field) \ 143 if (TbTable.get##Field()) { \ 144 OS << '\n'; \ 145 printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \ 146 Index += 4; \ 147 OS << "\t# " << #Field << " = " << *TbTable.get##Field(); \ 148 } 149 150 void objdump::dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address, 151 formatted_raw_ostream &OS, uint64_t End, 152 const MCSubtargetInfo &STI, 153 const XCOFFObjectFile *Obj) { 154 uint64_t Index = 0; 155 unsigned TabStop = getInstStartColumn(STI) - 1; 156 // Print traceback table boundary. 157 printRawData(Bytes.slice(Index, 4), Address, OS, STI); 158 OS << "\t# Traceback table start\n"; 159 Index += 4; 160 161 uint64_t Size = End - Address; 162 bool Is64Bit = Obj->is64Bit(); 163 164 // XCOFFTracebackTable::create modifies the size parameter, so ensure Size 165 // isn't changed. 166 uint64_t SizeCopy = End - Address; 167 Expected<XCOFFTracebackTable> TTOrErr = 168 XCOFFTracebackTable::create(Bytes.data() + Index, SizeCopy, Is64Bit); 169 170 if (!TTOrErr) { 171 std::string WarningMsgStr; 172 raw_string_ostream WarningStream(WarningMsgStr); 173 WarningStream << "failure parsing traceback table with address: 0x" 174 << utohexstr(Address) + "\n>>> " 175 << toString(TTOrErr.takeError()) 176 << "\n>>> Raw traceback table data is:\n"; 177 178 uint64_t LastNonZero = Index; 179 for (uint64_t I = Index; I < Size; I += 4) 180 if (support::endian::read32be(Bytes.slice(I, 4).data()) != 0) 181 LastNonZero = I + 4 > Size ? Size : I + 4; 182 183 if (Size - LastNonZero <= 4) 184 LastNonZero = Size; 185 186 formatted_raw_ostream FOS(WarningStream); 187 while (Index < LastNonZero) { 188 printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI); 189 Index += 4; 190 WarningStream << '\n'; 191 } 192 193 // Print all remaining zeroes as ... 194 if (Size - LastNonZero >= 8) 195 WarningStream << "\t\t...\n"; 196 197 reportWarning(WarningMsgStr, Obj->getFileName()); 198 return; 199 } 200 201 auto PrintBytes = [&](uint64_t N) { 202 printRawData(Bytes.slice(Index, N), Address + Index, OS, STI); 203 Index += N; 204 }; 205 206 XCOFFTracebackTable TbTable = *TTOrErr; 207 // Print the first of the 8 bytes of mandatory fields. 208 PrintBytes(1); 209 OS << format("\t# Version = %i", TbTable.getVersion()) << '\n'; 210 211 // Print the second of the 8 bytes of mandatory fields. 212 PrintBytes(1); 213 TracebackTable::LanguageID LangId = 214 static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID()); 215 OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n'; 216 217 auto Split = [&]() { 218 OS << '\n'; 219 OS.indent(TabStop); 220 }; 221 222 // Print the third of the 8 bytes of mandatory fields. 223 PrintBytes(1); 224 PRINTBOOL("\t#", TbTable, isGlobalLinkage); 225 PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue); 226 Split(); 227 PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset); 228 PRINTBOOL(",", TbTable, isInternalProcedure); 229 Split(); 230 PRINTBOOL("\t ", TbTable, hasControlledStorage); 231 PRINTBOOL(",", TbTable, isTOCless); 232 Split(); 233 PRINTBOOL("\t ", TbTable, isFloatingPointPresent); 234 Split(); 235 PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled); 236 OS << '\n'; 237 238 // Print the 4th of the 8 bytes of mandatory fields. 239 PrintBytes(1); 240 PRINTBOOL("\t#", TbTable, isInterruptHandler); 241 PRINTBOOL(",", TbTable, isFuncNamePresent); 242 PRINTBOOL(",", TbTable, isAllocaUsed); 243 Split(); 244 PRINTGET("\t ", TbTable, OnConditionDirective); 245 PRINTBOOL(",", TbTable, isCRSaved); 246 PRINTBOOL(",", TbTable, isLRSaved); 247 OS << '\n'; 248 249 // Print the 5th of the 8 bytes of mandatory fields. 250 PrintBytes(1); 251 PRINTBOOL("\t#", TbTable, isBackChainStored); 252 PRINTBOOL(",", TbTable, isFixup); 253 PRINTGET(",", TbTable, NumOfFPRsSaved); 254 OS << '\n'; 255 256 // Print the 6th of the 8 bytes of mandatory fields. 257 PrintBytes(1); 258 PRINTBOOL("\t#", TbTable, hasExtensionTable); 259 PRINTBOOL(",", TbTable, hasVectorInfo); 260 PRINTGET(",", TbTable, NumOfGPRsSaved); 261 OS << '\n'; 262 263 // Print the 7th of the 8 bytes of mandatory fields. 264 PrintBytes(1); 265 PRINTGET("\t#", TbTable, NumberOfFixedParms); 266 OS << '\n'; 267 268 // Print the 8th of the 8 bytes of mandatory fields. 269 PrintBytes(1); 270 PRINTGET("\t#", TbTable, NumberOfFPParms); 271 PRINTBOOL(",", TbTable, hasParmsOnStack); 272 273 PRINTOPTIONAL(ParmsType); 274 PRINTOPTIONAL(TraceBackTableOffset); 275 PRINTOPTIONAL(HandlerMask); 276 PRINTOPTIONAL(NumOfCtlAnchors); 277 278 if (TbTable.getControlledStorageInfoDisp()) { 279 SmallVector<uint32_t, 8> Disp = *TbTable.getControlledStorageInfoDisp(); 280 for (unsigned I = 0; I < Disp.size(); ++I) { 281 OS << '\n'; 282 PrintBytes(4); 283 OS << "\t" << (I ? " " : "#") << " ControlledStorageInfoDisp[" << I 284 << "] = " << Disp[I]; 285 } 286 } 287 288 // If there is a name, print the function name and function name length. 289 if (TbTable.isFuncNamePresent()) { 290 uint16_t FunctionNameLen = TbTable.getFunctionName()->size(); 291 if (FunctionNameLen == 0) { 292 OS << '\n'; 293 reportWarning( 294 "the length of the function name must be greater than zero if the " 295 "isFuncNamePresent bit is set in the traceback table", 296 Obj->getFileName()); 297 return; 298 } 299 300 OS << '\n'; 301 PrintBytes(2); 302 OS << "\t# FunctionNameLen = " << FunctionNameLen; 303 304 uint16_t RemainingBytes = FunctionNameLen; 305 bool HasPrinted = false; 306 while (RemainingBytes > 0) { 307 OS << '\n'; 308 uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes; 309 printRawData(Bytes.slice(Index, PrintLen), Address + Index, OS, STI); 310 Index += PrintLen; 311 RemainingBytes -= PrintLen; 312 313 if (!HasPrinted) { 314 OS << "\t# FunctionName = " << *TbTable.getFunctionName(); 315 HasPrinted = true; 316 } 317 } 318 } 319 320 if (TbTable.isAllocaUsed()) { 321 OS << '\n'; 322 PrintBytes(1); 323 OS << format("\t# AllocaRegister = %u", *TbTable.getAllocaRegister()); 324 } 325 326 if (TbTable.getVectorExt()) { 327 OS << '\n'; 328 TBVectorExt VecExt = *TbTable.getVectorExt(); 329 // Print first byte of VectorExt. 330 PrintBytes(1); 331 PRINTGET("\t#", VecExt, NumberOfVRSaved); 332 PRINTBOOL(",", VecExt, isVRSavedOnStack); 333 PRINTBOOL(",", VecExt, hasVarArgs); 334 OS << '\n'; 335 336 // Print the second byte of VectorExt. 337 PrintBytes(1); 338 PRINTGET("\t#", VecExt, NumberOfVectorParms); 339 PRINTBOOL(",", VecExt, hasVMXInstruction); 340 OS << '\n'; 341 342 PrintBytes(4); 343 OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo(); 344 345 // There are two bytes of padding after vector info. 346 OS << '\n'; 347 PrintBytes(2); 348 OS << "\t# Padding"; 349 } 350 351 if (TbTable.getExtensionTable()) { 352 OS << '\n'; 353 PrintBytes(1); 354 ExtendedTBTableFlag Flag = 355 static_cast<ExtendedTBTableFlag>(*TbTable.getExtensionTable()); 356 OS << "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag); 357 } 358 359 if (TbTable.getEhInfoDisp()) { 360 // There are 4 bytes alignment before eh info displacement. 361 if (Index % 4) { 362 OS << '\n'; 363 PrintBytes(4 - Index % 4); 364 OS << "\t# Alignment padding for eh info displacement"; 365 } 366 OS << '\n'; 367 // The size of the displacement (address) is 4 bytes in 32-bit object files, 368 // and 8 bytes in 64-bit object files. 369 PrintBytes(4); 370 OS << "\t# EH info displacement"; 371 if (Is64Bit) { 372 OS << '\n'; 373 PrintBytes(4); 374 } 375 } 376 377 OS << '\n'; 378 if (End == Address + Index) 379 return; 380 381 Size = End - Address; 382 383 const char *LineSuffix = "\t# Padding\n"; 384 auto IsWordZero = [&](uint64_t WordPos) { 385 if (WordPos >= Size) 386 return false; 387 uint64_t LineLength = std::min(4 - WordPos % 4, Size - WordPos); 388 return std::all_of(Bytes.begin() + WordPos, 389 Bytes.begin() + WordPos + LineLength, 390 [](uint8_t Byte) { return Byte == 0; }); 391 }; 392 393 bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Index, 4) + 4), 394 IsWordZero(alignTo(Index, 4) + 8)}; 395 bool ShouldPrintLine = true; 396 while (true) { 397 // Determine the length of the line (4, except for the first line, which 398 // will be just enough to align to the word boundary, and the last line, 399 // which will be the remainder of the data). 400 uint64_t LineLength = std::min(4 - Index % 4, Size - Index); 401 if (ShouldPrintLine) { 402 // Print the line. 403 printRawData(Bytes.slice(Index, LineLength), Address + Index, OS, STI); 404 OS << LineSuffix; 405 LineSuffix = "\n"; 406 } 407 408 Index += LineLength; 409 if (Index == Size) 410 return; 411 412 // For 3 or more consecutive lines of zeros, skip all but the first one, and 413 // replace them with "...". 414 if (AreWordsZero[0] && AreWordsZero[1] && AreWordsZero[2]) { 415 if (ShouldPrintLine) 416 OS << std::string(8, ' ') << "...\n"; 417 ShouldPrintLine = false; 418 } else if (!AreWordsZero[1]) { 419 // We have reached the end of a skipped block of zeros. 420 ShouldPrintLine = true; 421 } 422 AreWordsZero[0] = AreWordsZero[1]; 423 AreWordsZero[1] = AreWordsZero[2]; 424 AreWordsZero[2] = IsWordZero(Index + 8); 425 } 426 } 427 #undef PRINTBOOL 428 #undef PRINTGET 429 #undef PRINTOPTIONAL 430