10b57cec5SDimitry Andric //===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This program is a utility that works like binutils "objdump", that is, it 100b57cec5SDimitry Andric // dumps out a plethora of information about an object file depending on the 110b57cec5SDimitry Andric // flags. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric // The flags and output of this program should be near identical to those of 140b57cec5SDimitry Andric // binutils objdump. 150b57cec5SDimitry Andric // 160b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "llvm-objdump.h" 195ffd83dbSDimitry Andric #include "COFFDump.h" 205ffd83dbSDimitry Andric #include "ELFDump.h" 215ffd83dbSDimitry Andric #include "MachODump.h" 22fe6060f1SDimitry Andric #include "ObjdumpOptID.h" 2381ad6265SDimitry Andric #include "OffloadDump.h" 24fe6060f1SDimitry Andric #include "SourcePrinter.h" 255ffd83dbSDimitry Andric #include "WasmDump.h" 265ffd83dbSDimitry Andric #include "XCOFFDump.h" 270b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 280b57cec5SDimitry Andric #include "llvm/ADT/SetOperations.h" 290b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 300b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h" 31e8d8bef9SDimitry Andric #include "llvm/ADT/Twine.h" 32*0fca6ea1SDimitry Andric #include "llvm/BinaryFormat/Wasm.h" 335f757f3fSDimitry Andric #include "llvm/DebugInfo/BTF/BTFParser.h" 340b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 3581ad6265SDimitry Andric #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" 360b57cec5SDimitry Andric #include "llvm/DebugInfo/Symbolize/Symbolize.h" 37bdd1243dSDimitry Andric #include "llvm/Debuginfod/BuildIDFetcher.h" 38bdd1243dSDimitry Andric #include "llvm/Debuginfod/Debuginfod.h" 39bdd1243dSDimitry Andric #include "llvm/Debuginfod/HTTPClient.h" 400b57cec5SDimitry Andric #include "llvm/Demangle/Demangle.h" 410b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 420b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 430b57cec5SDimitry Andric #include "llvm/MC/MCDisassembler/MCDisassembler.h" 440b57cec5SDimitry Andric #include "llvm/MC/MCDisassembler/MCRelocationInfo.h" 450b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 460b57cec5SDimitry Andric #include "llvm/MC/MCInstPrinter.h" 470b57cec5SDimitry Andric #include "llvm/MC/MCInstrAnalysis.h" 480b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h" 490b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 500b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 51480093f4SDimitry Andric #include "llvm/MC/MCTargetOptions.h" 52349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 530b57cec5SDimitry Andric #include "llvm/Object/Archive.h" 54bdd1243dSDimitry Andric #include "llvm/Object/BuildID.h" 550b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 560b57cec5SDimitry Andric #include "llvm/Object/COFFImportFile.h" 570b57cec5SDimitry Andric #include "llvm/Object/ELFObjectFile.h" 5881ad6265SDimitry Andric #include "llvm/Object/ELFTypes.h" 59fe6060f1SDimitry Andric #include "llvm/Object/FaultMapParser.h" 600b57cec5SDimitry Andric #include "llvm/Object/MachO.h" 610b57cec5SDimitry Andric #include "llvm/Object/MachOUniversal.h" 620b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h" 6381ad6265SDimitry Andric #include "llvm/Object/OffloadBinary.h" 640b57cec5SDimitry Andric #include "llvm/Object/Wasm.h" 65fe6060f1SDimitry Andric #include "llvm/Option/Arg.h" 66fe6060f1SDimitry Andric #include "llvm/Option/ArgList.h" 67fe6060f1SDimitry Andric #include "llvm/Option/Option.h" 680b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 690b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 700b57cec5SDimitry Andric #include "llvm/Support/Errc.h" 710b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 720b57cec5SDimitry Andric #include "llvm/Support/Format.h" 738bcb0991SDimitry Andric #include "llvm/Support/FormatVariadic.h" 740b57cec5SDimitry Andric #include "llvm/Support/GraphWriter.h" 755f757f3fSDimitry Andric #include "llvm/Support/LLVMDriver.h" 760b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 770b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h" 780b57cec5SDimitry Andric #include "llvm/Support/StringSaver.h" 790b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h" 800b57cec5SDimitry Andric #include "llvm/Support/WithColor.h" 810b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 8206c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h" 8306c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h" 840b57cec5SDimitry Andric #include <algorithm> 850b57cec5SDimitry Andric #include <cctype> 860b57cec5SDimitry Andric #include <cstring> 87bdd1243dSDimitry Andric #include <optional> 885f757f3fSDimitry Andric #include <set> 890b57cec5SDimitry Andric #include <system_error> 900b57cec5SDimitry Andric #include <unordered_map> 910b57cec5SDimitry Andric #include <utility> 920b57cec5SDimitry Andric 935ffd83dbSDimitry Andric using namespace llvm; 940b57cec5SDimitry Andric using namespace llvm::object; 955ffd83dbSDimitry Andric using namespace llvm::objdump; 96fe6060f1SDimitry Andric using namespace llvm::opt; 97fe6060f1SDimitry Andric 98fe6060f1SDimitry Andric namespace { 99fe6060f1SDimitry Andric 100bdd1243dSDimitry Andric class CommonOptTable : public opt::GenericOptTable { 101fe6060f1SDimitry Andric public: 102fe6060f1SDimitry Andric CommonOptTable(ArrayRef<Info> OptionInfos, const char *Usage, 103fe6060f1SDimitry Andric const char *Description) 104bdd1243dSDimitry Andric : opt::GenericOptTable(OptionInfos), Usage(Usage), 105bdd1243dSDimitry Andric Description(Description) { 106fe6060f1SDimitry Andric setGroupedShortOptions(true); 107fe6060f1SDimitry Andric } 108fe6060f1SDimitry Andric 109fe6060f1SDimitry Andric void printHelp(StringRef Argv0, bool ShowHidden = false) const { 110fe6060f1SDimitry Andric Argv0 = sys::path::filename(Argv0); 111bdd1243dSDimitry Andric opt::GenericOptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(), 112bdd1243dSDimitry Andric Description, ShowHidden, ShowHidden); 113fe6060f1SDimitry Andric // TODO Replace this with OptTable API once it adds extrahelp support. 114fe6060f1SDimitry Andric outs() << "\nPass @FILE as argument to read options from FILE.\n"; 115fe6060f1SDimitry Andric } 116fe6060f1SDimitry Andric 117fe6060f1SDimitry Andric private: 118fe6060f1SDimitry Andric const char *Usage; 119fe6060f1SDimitry Andric const char *Description; 120fe6060f1SDimitry Andric }; 121fe6060f1SDimitry Andric 122fe6060f1SDimitry Andric // ObjdumpOptID is in ObjdumpOptID.h 123bdd1243dSDimitry Andric namespace objdump_opt { 124bdd1243dSDimitry Andric #define PREFIX(NAME, VALUE) \ 125bdd1243dSDimitry Andric static constexpr StringLiteral NAME##_init[] = VALUE; \ 126bdd1243dSDimitry Andric static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ 127bdd1243dSDimitry Andric std::size(NAME##_init) - 1); 128fe6060f1SDimitry Andric #include "ObjdumpOpts.inc" 129fe6060f1SDimitry Andric #undef PREFIX 130fe6060f1SDimitry Andric 131fe6060f1SDimitry Andric static constexpr opt::OptTable::Info ObjdumpInfoTable[] = { 1325f757f3fSDimitry Andric #define OPTION(...) \ 1335f757f3fSDimitry Andric LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJDUMP_, __VA_ARGS__), 134fe6060f1SDimitry Andric #include "ObjdumpOpts.inc" 135fe6060f1SDimitry Andric #undef OPTION 136fe6060f1SDimitry Andric }; 137bdd1243dSDimitry Andric } // namespace objdump_opt 138fe6060f1SDimitry Andric 139fe6060f1SDimitry Andric class ObjdumpOptTable : public CommonOptTable { 140fe6060f1SDimitry Andric public: 141fe6060f1SDimitry Andric ObjdumpOptTable() 142bdd1243dSDimitry Andric : CommonOptTable(objdump_opt::ObjdumpInfoTable, 143bdd1243dSDimitry Andric " [options] <input object files>", 144fe6060f1SDimitry Andric "llvm object file dumper") {} 145fe6060f1SDimitry Andric }; 146fe6060f1SDimitry Andric 147fe6060f1SDimitry Andric enum OtoolOptID { 148fe6060f1SDimitry Andric OTOOL_INVALID = 0, // This is not an option ID. 1495f757f3fSDimitry Andric #define OPTION(...) LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OTOOL_, __VA_ARGS__), 150fe6060f1SDimitry Andric #include "OtoolOpts.inc" 151fe6060f1SDimitry Andric #undef OPTION 152fe6060f1SDimitry Andric }; 153fe6060f1SDimitry Andric 154bdd1243dSDimitry Andric namespace otool { 155bdd1243dSDimitry Andric #define PREFIX(NAME, VALUE) \ 156bdd1243dSDimitry Andric static constexpr StringLiteral NAME##_init[] = VALUE; \ 157bdd1243dSDimitry Andric static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ 158bdd1243dSDimitry Andric std::size(NAME##_init) - 1); 159fe6060f1SDimitry Andric #include "OtoolOpts.inc" 160fe6060f1SDimitry Andric #undef PREFIX 161fe6060f1SDimitry Andric 162fe6060f1SDimitry Andric static constexpr opt::OptTable::Info OtoolInfoTable[] = { 1635f757f3fSDimitry Andric #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OTOOL_, __VA_ARGS__), 164fe6060f1SDimitry Andric #include "OtoolOpts.inc" 165fe6060f1SDimitry Andric #undef OPTION 166fe6060f1SDimitry Andric }; 167bdd1243dSDimitry Andric } // namespace otool 168fe6060f1SDimitry Andric 169fe6060f1SDimitry Andric class OtoolOptTable : public CommonOptTable { 170fe6060f1SDimitry Andric public: 171fe6060f1SDimitry Andric OtoolOptTable() 172bdd1243dSDimitry Andric : CommonOptTable(otool::OtoolInfoTable, " [option...] [file...]", 173fe6060f1SDimitry Andric "Mach-O object file displaying tool") {} 174fe6060f1SDimitry Andric }; 175fe6060f1SDimitry Andric 176*0fca6ea1SDimitry Andric struct BBAddrMapLabel { 177*0fca6ea1SDimitry Andric std::string BlockLabel; 178*0fca6ea1SDimitry Andric std::string PGOAnalysis; 179*0fca6ea1SDimitry Andric }; 180*0fca6ea1SDimitry Andric 181*0fca6ea1SDimitry Andric // This class represents the BBAddrMap and PGOMap associated with a single 182*0fca6ea1SDimitry Andric // function. 183*0fca6ea1SDimitry Andric class BBAddrMapFunctionEntry { 184*0fca6ea1SDimitry Andric public: 185*0fca6ea1SDimitry Andric BBAddrMapFunctionEntry(BBAddrMap AddrMap, PGOAnalysisMap PGOMap) 186*0fca6ea1SDimitry Andric : AddrMap(std::move(AddrMap)), PGOMap(std::move(PGOMap)) {} 187*0fca6ea1SDimitry Andric 188*0fca6ea1SDimitry Andric const BBAddrMap &getAddrMap() const { return AddrMap; } 189*0fca6ea1SDimitry Andric 190*0fca6ea1SDimitry Andric // Returns the PGO string associated with the entry of index `PGOBBEntryIndex` 191*0fca6ea1SDimitry Andric // in `PGOMap`. If PrettyPGOAnalysis is true, prints BFI as relative frequency 192*0fca6ea1SDimitry Andric // and BPI as percentage. Otherwise raw values are displayed. 193*0fca6ea1SDimitry Andric std::string constructPGOLabelString(size_t PGOBBEntryIndex, 194*0fca6ea1SDimitry Andric bool PrettyPGOAnalysis) const { 195*0fca6ea1SDimitry Andric if (!PGOMap.FeatEnable.hasPGOAnalysis()) 196*0fca6ea1SDimitry Andric return ""; 197*0fca6ea1SDimitry Andric std::string PGOString; 198*0fca6ea1SDimitry Andric raw_string_ostream PGOSS(PGOString); 199*0fca6ea1SDimitry Andric 200*0fca6ea1SDimitry Andric PGOSS << " ("; 201*0fca6ea1SDimitry Andric if (PGOMap.FeatEnable.FuncEntryCount && PGOBBEntryIndex == 0) { 202*0fca6ea1SDimitry Andric PGOSS << "Entry count: " << Twine(PGOMap.FuncEntryCount); 203*0fca6ea1SDimitry Andric if (PGOMap.FeatEnable.hasPGOAnalysisBBData()) { 204*0fca6ea1SDimitry Andric PGOSS << ", "; 205*0fca6ea1SDimitry Andric } 206*0fca6ea1SDimitry Andric } 207*0fca6ea1SDimitry Andric 208*0fca6ea1SDimitry Andric if (PGOMap.FeatEnable.hasPGOAnalysisBBData()) { 209*0fca6ea1SDimitry Andric 210*0fca6ea1SDimitry Andric assert(PGOBBEntryIndex < PGOMap.BBEntries.size() && 211*0fca6ea1SDimitry Andric "Expected PGOAnalysisMap and BBAddrMap to have the same entries"); 212*0fca6ea1SDimitry Andric const PGOAnalysisMap::PGOBBEntry &PGOBBEntry = 213*0fca6ea1SDimitry Andric PGOMap.BBEntries[PGOBBEntryIndex]; 214*0fca6ea1SDimitry Andric 215*0fca6ea1SDimitry Andric if (PGOMap.FeatEnable.BBFreq) { 216*0fca6ea1SDimitry Andric PGOSS << "Frequency: "; 217*0fca6ea1SDimitry Andric if (PrettyPGOAnalysis) 218*0fca6ea1SDimitry Andric printRelativeBlockFreq(PGOSS, PGOMap.BBEntries.front().BlockFreq, 219*0fca6ea1SDimitry Andric PGOBBEntry.BlockFreq); 220*0fca6ea1SDimitry Andric else 221*0fca6ea1SDimitry Andric PGOSS << Twine(PGOBBEntry.BlockFreq.getFrequency()); 222*0fca6ea1SDimitry Andric if (PGOMap.FeatEnable.BrProb && PGOBBEntry.Successors.size() > 0) { 223*0fca6ea1SDimitry Andric PGOSS << ", "; 224*0fca6ea1SDimitry Andric } 225*0fca6ea1SDimitry Andric } 226*0fca6ea1SDimitry Andric if (PGOMap.FeatEnable.BrProb && PGOBBEntry.Successors.size() > 0) { 227*0fca6ea1SDimitry Andric PGOSS << "Successors: "; 228*0fca6ea1SDimitry Andric interleaveComma( 229*0fca6ea1SDimitry Andric PGOBBEntry.Successors, PGOSS, 230*0fca6ea1SDimitry Andric [&](const PGOAnalysisMap::PGOBBEntry::SuccessorEntry &SE) { 231*0fca6ea1SDimitry Andric PGOSS << "BB" << SE.ID << ":"; 232*0fca6ea1SDimitry Andric if (PrettyPGOAnalysis) 233*0fca6ea1SDimitry Andric PGOSS << "[" << SE.Prob << "]"; 234*0fca6ea1SDimitry Andric else 235*0fca6ea1SDimitry Andric PGOSS.write_hex(SE.Prob.getNumerator()); 236*0fca6ea1SDimitry Andric }); 237*0fca6ea1SDimitry Andric } 238*0fca6ea1SDimitry Andric } 239*0fca6ea1SDimitry Andric PGOSS << ")"; 240*0fca6ea1SDimitry Andric 241*0fca6ea1SDimitry Andric return PGOString; 242*0fca6ea1SDimitry Andric } 243*0fca6ea1SDimitry Andric 244*0fca6ea1SDimitry Andric private: 245*0fca6ea1SDimitry Andric const BBAddrMap AddrMap; 246*0fca6ea1SDimitry Andric const PGOAnalysisMap PGOMap; 247*0fca6ea1SDimitry Andric }; 248*0fca6ea1SDimitry Andric 249*0fca6ea1SDimitry Andric // This class represents the BBAddrMap and PGOMap of potentially multiple 250*0fca6ea1SDimitry Andric // functions in a section. 251*0fca6ea1SDimitry Andric class BBAddrMapInfo { 252*0fca6ea1SDimitry Andric public: 253*0fca6ea1SDimitry Andric void clear() { 254*0fca6ea1SDimitry Andric FunctionAddrToMap.clear(); 255*0fca6ea1SDimitry Andric RangeBaseAddrToFunctionAddr.clear(); 256*0fca6ea1SDimitry Andric } 257*0fca6ea1SDimitry Andric 258*0fca6ea1SDimitry Andric bool empty() const { return FunctionAddrToMap.empty(); } 259*0fca6ea1SDimitry Andric 260*0fca6ea1SDimitry Andric void AddFunctionEntry(BBAddrMap AddrMap, PGOAnalysisMap PGOMap) { 261*0fca6ea1SDimitry Andric uint64_t FunctionAddr = AddrMap.getFunctionAddress(); 262*0fca6ea1SDimitry Andric for (size_t I = 1; I < AddrMap.BBRanges.size(); ++I) 263*0fca6ea1SDimitry Andric RangeBaseAddrToFunctionAddr.emplace(AddrMap.BBRanges[I].BaseAddress, 264*0fca6ea1SDimitry Andric FunctionAddr); 265*0fca6ea1SDimitry Andric [[maybe_unused]] auto R = FunctionAddrToMap.try_emplace( 266*0fca6ea1SDimitry Andric FunctionAddr, std::move(AddrMap), std::move(PGOMap)); 267*0fca6ea1SDimitry Andric assert(R.second && "duplicate function address"); 268*0fca6ea1SDimitry Andric } 269*0fca6ea1SDimitry Andric 270*0fca6ea1SDimitry Andric // Returns the BBAddrMap entry for the function associated with `BaseAddress`. 271*0fca6ea1SDimitry Andric // `BaseAddress` could be the function address or the address of a range 272*0fca6ea1SDimitry Andric // associated with that function. Returns `nullptr` if `BaseAddress` is not 273*0fca6ea1SDimitry Andric // mapped to any entry. 274*0fca6ea1SDimitry Andric const BBAddrMapFunctionEntry *getEntryForAddress(uint64_t BaseAddress) const { 275*0fca6ea1SDimitry Andric uint64_t FunctionAddr = BaseAddress; 276*0fca6ea1SDimitry Andric auto S = RangeBaseAddrToFunctionAddr.find(BaseAddress); 277*0fca6ea1SDimitry Andric if (S != RangeBaseAddrToFunctionAddr.end()) 278*0fca6ea1SDimitry Andric FunctionAddr = S->second; 279*0fca6ea1SDimitry Andric auto R = FunctionAddrToMap.find(FunctionAddr); 280*0fca6ea1SDimitry Andric if (R == FunctionAddrToMap.end()) 281*0fca6ea1SDimitry Andric return nullptr; 282*0fca6ea1SDimitry Andric return &R->second; 283*0fca6ea1SDimitry Andric } 284*0fca6ea1SDimitry Andric 285*0fca6ea1SDimitry Andric private: 286*0fca6ea1SDimitry Andric std::unordered_map<uint64_t, BBAddrMapFunctionEntry> FunctionAddrToMap; 287*0fca6ea1SDimitry Andric std::unordered_map<uint64_t, uint64_t> RangeBaseAddrToFunctionAddr; 288*0fca6ea1SDimitry Andric }; 289*0fca6ea1SDimitry Andric 290fe6060f1SDimitry Andric } // namespace 2910b57cec5SDimitry Andric 2925ffd83dbSDimitry Andric #define DEBUG_TYPE "objdump" 2930b57cec5SDimitry Andric 2945f757f3fSDimitry Andric enum class ColorOutput { 2955f757f3fSDimitry Andric Auto, 2965f757f3fSDimitry Andric Enable, 2975f757f3fSDimitry Andric Disable, 2985f757f3fSDimitry Andric Invalid, 2995f757f3fSDimitry Andric }; 3005f757f3fSDimitry Andric 301fe6060f1SDimitry Andric static uint64_t AdjustVMA; 302fe6060f1SDimitry Andric static bool AllHeaders; 303fe6060f1SDimitry Andric static std::string ArchName; 304fe6060f1SDimitry Andric bool objdump::ArchiveHeaders; 305fe6060f1SDimitry Andric bool objdump::Demangle; 306fe6060f1SDimitry Andric bool objdump::Disassemble; 307fe6060f1SDimitry Andric bool objdump::DisassembleAll; 308fe6060f1SDimitry Andric bool objdump::SymbolDescription; 30906c3fb27SDimitry Andric bool objdump::TracebackTable; 310fe6060f1SDimitry Andric static std::vector<std::string> DisassembleSymbols; 311fe6060f1SDimitry Andric static bool DisassembleZeroes; 312fe6060f1SDimitry Andric static std::vector<std::string> DisassemblerOptions; 3135f757f3fSDimitry Andric static ColorOutput DisassemblyColor; 314fe6060f1SDimitry Andric DIDumpType objdump::DwarfDumpType; 315fe6060f1SDimitry Andric static bool DynamicRelocations; 316fe6060f1SDimitry Andric static bool FaultMapSection; 317fe6060f1SDimitry Andric static bool FileHeaders; 318fe6060f1SDimitry Andric bool objdump::SectionContents; 319fe6060f1SDimitry Andric static std::vector<std::string> InputFilenames; 320fe6060f1SDimitry Andric bool objdump::PrintLines; 321fe6060f1SDimitry Andric static bool MachOOpt; 322fe6060f1SDimitry Andric std::string objdump::MCPU; 323fe6060f1SDimitry Andric std::vector<std::string> objdump::MAttrs; 324fe6060f1SDimitry Andric bool objdump::ShowRawInsn; 325fe6060f1SDimitry Andric bool objdump::LeadingAddr; 32681ad6265SDimitry Andric static bool Offloading; 327fe6060f1SDimitry Andric static bool RawClangAST; 328fe6060f1SDimitry Andric bool objdump::Relocations; 329fe6060f1SDimitry Andric bool objdump::PrintImmHex; 330fe6060f1SDimitry Andric bool objdump::PrivateHeaders; 331fe6060f1SDimitry Andric std::vector<std::string> objdump::FilterSections; 332fe6060f1SDimitry Andric bool objdump::SectionHeaders; 333bdd1243dSDimitry Andric static bool ShowAllSymbols; 334fe6060f1SDimitry Andric static bool ShowLMA; 335fe6060f1SDimitry Andric bool objdump::PrintSource; 3360b57cec5SDimitry Andric 337fe6060f1SDimitry Andric static uint64_t StartAddress; 338fe6060f1SDimitry Andric static bool HasStartAddressFlag; 339fe6060f1SDimitry Andric static uint64_t StopAddress = UINT64_MAX; 340fe6060f1SDimitry Andric static bool HasStopAddressFlag; 3410b57cec5SDimitry Andric 342fe6060f1SDimitry Andric bool objdump::SymbolTable; 343fe6060f1SDimitry Andric static bool SymbolizeOperands; 344*0fca6ea1SDimitry Andric static bool PrettyPGOAnalysisMap; 345fe6060f1SDimitry Andric static bool DynamicSymbolTable; 346fe6060f1SDimitry Andric std::string objdump::TripleName; 347fe6060f1SDimitry Andric bool objdump::UnwindInfo; 348fe6060f1SDimitry Andric static bool Wide; 349fe6060f1SDimitry Andric std::string objdump::Prefix; 350fe6060f1SDimitry Andric uint32_t objdump::PrefixStrip; 3510b57cec5SDimitry Andric 352fe6060f1SDimitry Andric DebugVarsFormat objdump::DbgVariables = DVDisabled; 3530b57cec5SDimitry Andric 354fe6060f1SDimitry Andric int objdump::DbgIndent = 52; 3550b57cec5SDimitry Andric 3565ffd83dbSDimitry Andric static StringSet<> DisasmSymbolSet; 3575ffd83dbSDimitry Andric StringSet<> objdump::FoundSectionSet; 3580b57cec5SDimitry Andric static StringRef ToolName; 3590b57cec5SDimitry Andric 360bdd1243dSDimitry Andric std::unique_ptr<BuildIDFetcher> BIDFetcher; 3615f757f3fSDimitry Andric 3625f757f3fSDimitry Andric Dumper::Dumper(const object::ObjectFile &O) : O(O) { 3635f757f3fSDimitry Andric WarningHandler = [this](const Twine &Msg) { 3645f757f3fSDimitry Andric if (Warnings.insert(Msg.str()).second) 3655f757f3fSDimitry Andric reportWarning(Msg, this->O.getFileName()); 3665f757f3fSDimitry Andric return Error::success(); 3675f757f3fSDimitry Andric }; 3685f757f3fSDimitry Andric } 369bdd1243dSDimitry Andric 37006c3fb27SDimitry Andric void Dumper::reportUniqueWarning(Error Err) { 37106c3fb27SDimitry Andric reportUniqueWarning(toString(std::move(Err))); 37206c3fb27SDimitry Andric } 37306c3fb27SDimitry Andric 37406c3fb27SDimitry Andric void Dumper::reportUniqueWarning(const Twine &Msg) { 3755f757f3fSDimitry Andric cantFail(WarningHandler(Msg)); 37606c3fb27SDimitry Andric } 37706c3fb27SDimitry Andric 37806c3fb27SDimitry Andric static Expected<std::unique_ptr<Dumper>> createDumper(const ObjectFile &Obj) { 37906c3fb27SDimitry Andric if (const auto *O = dyn_cast<COFFObjectFile>(&Obj)) 38006c3fb27SDimitry Andric return createCOFFDumper(*O); 38106c3fb27SDimitry Andric if (const auto *O = dyn_cast<ELFObjectFileBase>(&Obj)) 38206c3fb27SDimitry Andric return createELFDumper(*O); 38306c3fb27SDimitry Andric if (const auto *O = dyn_cast<MachOObjectFile>(&Obj)) 38406c3fb27SDimitry Andric return createMachODumper(*O); 38506c3fb27SDimitry Andric if (const auto *O = dyn_cast<WasmObjectFile>(&Obj)) 38606c3fb27SDimitry Andric return createWasmDumper(*O); 38706c3fb27SDimitry Andric if (const auto *O = dyn_cast<XCOFFObjectFile>(&Obj)) 38806c3fb27SDimitry Andric return createXCOFFDumper(*O); 38906c3fb27SDimitry Andric 39006c3fb27SDimitry Andric return createStringError(errc::invalid_argument, 39106c3fb27SDimitry Andric "unsupported object file format"); 39206c3fb27SDimitry Andric } 39306c3fb27SDimitry Andric 3948bcb0991SDimitry Andric namespace { 3958bcb0991SDimitry Andric struct FilterResult { 3968bcb0991SDimitry Andric // True if the section should not be skipped. 3978bcb0991SDimitry Andric bool Keep; 3988bcb0991SDimitry Andric 3998bcb0991SDimitry Andric // True if the index counter should be incremented, even if the section should 4008bcb0991SDimitry Andric // be skipped. For example, sections may be skipped if they are not included 4018bcb0991SDimitry Andric // in the --section flag, but we still want those to count toward the section 4028bcb0991SDimitry Andric // count. 4038bcb0991SDimitry Andric bool IncrementIndex; 4048bcb0991SDimitry Andric }; 4058bcb0991SDimitry Andric } // namespace 4068bcb0991SDimitry Andric 4078bcb0991SDimitry Andric static FilterResult checkSectionFilter(object::SectionRef S) { 4080b57cec5SDimitry Andric if (FilterSections.empty()) 4098bcb0991SDimitry Andric return {/*Keep=*/true, /*IncrementIndex=*/true}; 4108bcb0991SDimitry Andric 4118bcb0991SDimitry Andric Expected<StringRef> SecNameOrErr = S.getName(); 4128bcb0991SDimitry Andric if (!SecNameOrErr) { 4138bcb0991SDimitry Andric consumeError(SecNameOrErr.takeError()); 4148bcb0991SDimitry Andric return {/*Keep=*/false, /*IncrementIndex=*/false}; 4158bcb0991SDimitry Andric } 4168bcb0991SDimitry Andric StringRef SecName = *SecNameOrErr; 4178bcb0991SDimitry Andric 4180b57cec5SDimitry Andric // StringSet does not allow empty key so avoid adding sections with 4190b57cec5SDimitry Andric // no name (such as the section with index 0) here. 4200b57cec5SDimitry Andric if (!SecName.empty()) 4210b57cec5SDimitry Andric FoundSectionSet.insert(SecName); 4228bcb0991SDimitry Andric 4238bcb0991SDimitry Andric // Only show the section if it's in the FilterSections list, but always 4248bcb0991SDimitry Andric // increment so the indexing is stable. 4258bcb0991SDimitry Andric return {/*Keep=*/is_contained(FilterSections, SecName), 4268bcb0991SDimitry Andric /*IncrementIndex=*/true}; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric 4295ffd83dbSDimitry Andric SectionFilter objdump::ToolSectionFilter(object::ObjectFile const &O, 4305ffd83dbSDimitry Andric uint64_t *Idx) { 4318bcb0991SDimitry Andric // Start at UINT64_MAX so that the first index returned after an increment is 4328bcb0991SDimitry Andric // zero (after the unsigned wrap). 4338bcb0991SDimitry Andric if (Idx) 4348bcb0991SDimitry Andric *Idx = UINT64_MAX; 4358bcb0991SDimitry Andric return SectionFilter( 4368bcb0991SDimitry Andric [Idx](object::SectionRef S) { 4378bcb0991SDimitry Andric FilterResult Result = checkSectionFilter(S); 4388bcb0991SDimitry Andric if (Idx != nullptr && Result.IncrementIndex) 4398bcb0991SDimitry Andric *Idx += 1; 4408bcb0991SDimitry Andric return Result.Keep; 4418bcb0991SDimitry Andric }, 4428bcb0991SDimitry Andric O); 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric 4455ffd83dbSDimitry Andric std::string objdump::getFileNameForError(const object::Archive::Child &C, 4468bcb0991SDimitry Andric unsigned Index) { 4478bcb0991SDimitry Andric Expected<StringRef> NameOrErr = C.getName(); 4488bcb0991SDimitry Andric if (NameOrErr) 4495ffd83dbSDimitry Andric return std::string(NameOrErr.get()); 4508bcb0991SDimitry Andric // If we have an error getting the name then we print the index of the archive 4518bcb0991SDimitry Andric // member. Since we are already in an error state, we just ignore this error. 4528bcb0991SDimitry Andric consumeError(NameOrErr.takeError()); 4538bcb0991SDimitry Andric return "<file index: " + std::to_string(Index) + ">"; 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric 456e8d8bef9SDimitry Andric void objdump::reportWarning(const Twine &Message, StringRef File) { 4570b57cec5SDimitry Andric // Output order between errs() and outs() matters especially for archive 4580b57cec5SDimitry Andric // files where the output is per member object. 4590b57cec5SDimitry Andric outs().flush(); 4608bcb0991SDimitry Andric WithColor::warning(errs(), ToolName) 4618bcb0991SDimitry Andric << "'" << File << "': " << Message << "\n"; 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric 464349cc55cSDimitry Andric [[noreturn]] void objdump::reportError(StringRef File, const Twine &Message) { 4655ffd83dbSDimitry Andric outs().flush(); 4668bcb0991SDimitry Andric WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n"; 4670b57cec5SDimitry Andric exit(1); 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric 470349cc55cSDimitry Andric [[noreturn]] void objdump::reportError(Error E, StringRef FileName, 4718bcb0991SDimitry Andric StringRef ArchiveName, 4720b57cec5SDimitry Andric StringRef ArchitectureName) { 4730b57cec5SDimitry Andric assert(E); 4745ffd83dbSDimitry Andric outs().flush(); 4750b57cec5SDimitry Andric WithColor::error(errs(), ToolName); 4760b57cec5SDimitry Andric if (ArchiveName != "") 4770b57cec5SDimitry Andric errs() << ArchiveName << "(" << FileName << ")"; 4780b57cec5SDimitry Andric else 4790b57cec5SDimitry Andric errs() << "'" << FileName << "'"; 4800b57cec5SDimitry Andric if (!ArchitectureName.empty()) 4810b57cec5SDimitry Andric errs() << " (for architecture " << ArchitectureName << ")"; 4825ffd83dbSDimitry Andric errs() << ": "; 4835ffd83dbSDimitry Andric logAllUnhandledErrors(std::move(E), errs()); 4840b57cec5SDimitry Andric exit(1); 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric 487e8d8bef9SDimitry Andric static void reportCmdLineWarning(const Twine &Message) { 4888bcb0991SDimitry Andric WithColor::warning(errs(), ToolName) << Message << "\n"; 4898bcb0991SDimitry Andric } 4908bcb0991SDimitry Andric 491349cc55cSDimitry Andric [[noreturn]] static void reportCmdLineError(const Twine &Message) { 4928bcb0991SDimitry Andric WithColor::error(errs(), ToolName) << Message << "\n"; 4938bcb0991SDimitry Andric exit(1); 4940b57cec5SDimitry Andric } 4950b57cec5SDimitry Andric 4960b57cec5SDimitry Andric static void warnOnNoMatchForSections() { 4970b57cec5SDimitry Andric SetVector<StringRef> MissingSections; 4980b57cec5SDimitry Andric for (StringRef S : FilterSections) { 4990b57cec5SDimitry Andric if (FoundSectionSet.count(S)) 5000b57cec5SDimitry Andric return; 5010b57cec5SDimitry Andric // User may specify a unnamed section. Don't warn for it. 5020b57cec5SDimitry Andric if (!S.empty()) 5030b57cec5SDimitry Andric MissingSections.insert(S); 5040b57cec5SDimitry Andric } 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric // Warn only if no section in FilterSections is matched. 5070b57cec5SDimitry Andric for (StringRef S : MissingSections) 5088bcb0991SDimitry Andric reportCmdLineWarning("section '" + S + 5098bcb0991SDimitry Andric "' mentioned in a -j/--section option, but not " 5100b57cec5SDimitry Andric "found in any input file"); 5110b57cec5SDimitry Andric } 5120b57cec5SDimitry Andric 5138bcb0991SDimitry Andric static const Target *getTarget(const ObjectFile *Obj) { 5140b57cec5SDimitry Andric // Figure out the target triple. 5150b57cec5SDimitry Andric Triple TheTriple("unknown-unknown-unknown"); 5160b57cec5SDimitry Andric if (TripleName.empty()) { 5170b57cec5SDimitry Andric TheTriple = Obj->makeTriple(); 5180b57cec5SDimitry Andric } else { 5190b57cec5SDimitry Andric TheTriple.setTriple(Triple::normalize(TripleName)); 5200b57cec5SDimitry Andric auto Arch = Obj->getArch(); 5210b57cec5SDimitry Andric if (Arch == Triple::arm || Arch == Triple::armeb) 5220b57cec5SDimitry Andric Obj->setARMSubArch(TheTriple); 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric // Get the target specific parser. 5260b57cec5SDimitry Andric std::string Error; 5270b57cec5SDimitry Andric const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple, 5280b57cec5SDimitry Andric Error); 5298bcb0991SDimitry Andric if (!TheTarget) 5308bcb0991SDimitry Andric reportError(Obj->getFileName(), "can't find target: " + Error); 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric // Update the triple name and return the found target. 5330b57cec5SDimitry Andric TripleName = TheTriple.getTriple(); 5340b57cec5SDimitry Andric return TheTarget; 5350b57cec5SDimitry Andric } 5360b57cec5SDimitry Andric 5375ffd83dbSDimitry Andric bool objdump::isRelocAddressLess(RelocationRef A, RelocationRef B) { 5380b57cec5SDimitry Andric return A.getOffset() < B.getOffset(); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric static Error getRelocationValueString(const RelocationRef &Rel, 542cb14a3feSDimitry Andric bool SymbolDescription, 5430b57cec5SDimitry Andric SmallVectorImpl<char> &Result) { 5440b57cec5SDimitry Andric const ObjectFile *Obj = Rel.getObject(); 5450b57cec5SDimitry Andric if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj)) 5460b57cec5SDimitry Andric return getELFRelocationValueString(ELF, Rel, Result); 5470b57cec5SDimitry Andric if (auto *COFF = dyn_cast<COFFObjectFile>(Obj)) 5480b57cec5SDimitry Andric return getCOFFRelocationValueString(COFF, Rel, Result); 5490b57cec5SDimitry Andric if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj)) 5500b57cec5SDimitry Andric return getWasmRelocationValueString(Wasm, Rel, Result); 5510b57cec5SDimitry Andric if (auto *MachO = dyn_cast<MachOObjectFile>(Obj)) 5520b57cec5SDimitry Andric return getMachORelocationValueString(MachO, Rel, Result); 5535ffd83dbSDimitry Andric if (auto *XCOFF = dyn_cast<XCOFFObjectFile>(Obj)) 554cb14a3feSDimitry Andric return getXCOFFRelocationValueString(*XCOFF, Rel, SymbolDescription, 555cb14a3feSDimitry Andric Result); 5560b57cec5SDimitry Andric llvm_unreachable("unknown object file format"); 5570b57cec5SDimitry Andric } 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric /// Indicates whether this relocation should hidden when listing 5600b57cec5SDimitry Andric /// relocations, usually because it is the trailing part of a multipart 5610b57cec5SDimitry Andric /// relocation that will be printed as part of the leading relocation. 5620b57cec5SDimitry Andric static bool getHidden(RelocationRef RelRef) { 5630b57cec5SDimitry Andric auto *MachO = dyn_cast<MachOObjectFile>(RelRef.getObject()); 5640b57cec5SDimitry Andric if (!MachO) 5650b57cec5SDimitry Andric return false; 5660b57cec5SDimitry Andric 5670b57cec5SDimitry Andric unsigned Arch = MachO->getArch(); 5680b57cec5SDimitry Andric DataRefImpl Rel = RelRef.getRawDataRefImpl(); 5690b57cec5SDimitry Andric uint64_t Type = MachO->getRelocationType(Rel); 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric // On arches that use the generic relocations, GENERIC_RELOC_PAIR 5720b57cec5SDimitry Andric // is always hidden. 5730b57cec5SDimitry Andric if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc) 5740b57cec5SDimitry Andric return Type == MachO::GENERIC_RELOC_PAIR; 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric if (Arch == Triple::x86_64) { 5770b57cec5SDimitry Andric // On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows 5780b57cec5SDimitry Andric // an X86_64_RELOC_SUBTRACTOR. 5790b57cec5SDimitry Andric if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) { 5800b57cec5SDimitry Andric DataRefImpl RelPrev = Rel; 5810b57cec5SDimitry Andric RelPrev.d.a--; 5820b57cec5SDimitry Andric uint64_t PrevType = MachO->getRelocationType(RelPrev); 5830b57cec5SDimitry Andric if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR) 5840b57cec5SDimitry Andric return true; 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric return false; 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric 5915ffd83dbSDimitry Andric /// Get the column at which we want to start printing the instruction 5925ffd83dbSDimitry Andric /// disassembly, taking into account anything which appears to the left of it. 59306c3fb27SDimitry Andric unsigned objdump::getInstStartColumn(const MCSubtargetInfo &STI) { 594fe6060f1SDimitry Andric return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24; 5950b57cec5SDimitry Andric } 5960b57cec5SDimitry Andric 59706c3fb27SDimitry Andric static void AlignToInstStartColumn(size_t Start, const MCSubtargetInfo &STI, 59806c3fb27SDimitry Andric raw_ostream &OS) { 59906c3fb27SDimitry Andric // The output of printInst starts with a tab. Print some spaces so that 60006c3fb27SDimitry Andric // the tab has 1 column and advances to the target tab stop. 60106c3fb27SDimitry Andric unsigned TabStop = getInstStartColumn(STI); 60206c3fb27SDimitry Andric unsigned Column = OS.tell() - Start; 60306c3fb27SDimitry Andric OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); 60406c3fb27SDimitry Andric } 60506c3fb27SDimitry Andric 60606c3fb27SDimitry Andric void objdump::printRawData(ArrayRef<uint8_t> Bytes, uint64_t Address, 60706c3fb27SDimitry Andric formatted_raw_ostream &OS, 60806c3fb27SDimitry Andric MCSubtargetInfo const &STI) { 60906c3fb27SDimitry Andric size_t Start = OS.tell(); 61006c3fb27SDimitry Andric if (LeadingAddr) 61106c3fb27SDimitry Andric OS << format("%8" PRIx64 ":", Address); 61206c3fb27SDimitry Andric if (ShowRawInsn) { 61306c3fb27SDimitry Andric OS << ' '; 61406c3fb27SDimitry Andric dumpBytes(Bytes, OS); 61506c3fb27SDimitry Andric } 61606c3fb27SDimitry Andric AlignToInstStartColumn(Start, STI, OS); 61706c3fb27SDimitry Andric } 61806c3fb27SDimitry Andric 61906c3fb27SDimitry Andric namespace { 62006c3fb27SDimitry Andric 621753f127fSDimitry Andric static bool isAArch64Elf(const ObjectFile &Obj) { 622753f127fSDimitry Andric const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj); 6230b57cec5SDimitry Andric return Elf && Elf->getEMachine() == ELF::EM_AARCH64; 6240b57cec5SDimitry Andric } 6250b57cec5SDimitry Andric 626753f127fSDimitry Andric static bool isArmElf(const ObjectFile &Obj) { 627753f127fSDimitry Andric const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj); 6280b57cec5SDimitry Andric return Elf && Elf->getEMachine() == ELF::EM_ARM; 6290b57cec5SDimitry Andric } 6300b57cec5SDimitry Andric 631753f127fSDimitry Andric static bool isCSKYElf(const ObjectFile &Obj) { 632753f127fSDimitry Andric const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj); 63381ad6265SDimitry Andric return Elf && Elf->getEMachine() == ELF::EM_CSKY; 63481ad6265SDimitry Andric } 63581ad6265SDimitry Andric 636753f127fSDimitry Andric static bool hasMappingSymbols(const ObjectFile &Obj) { 63781ad6265SDimitry Andric return isArmElf(Obj) || isAArch64Elf(Obj) || isCSKYElf(Obj) ; 6380b57cec5SDimitry Andric } 6390b57cec5SDimitry Andric 6405ffd83dbSDimitry Andric static void printRelocation(formatted_raw_ostream &OS, StringRef FileName, 6415ffd83dbSDimitry Andric const RelocationRef &Rel, uint64_t Address, 6425ffd83dbSDimitry Andric bool Is64Bits) { 643bdd1243dSDimitry Andric StringRef Fmt = Is64Bits ? "%016" PRIx64 ": " : "%08" PRIx64 ": "; 6440b57cec5SDimitry Andric SmallString<16> Name; 6450b57cec5SDimitry Andric SmallString<32> Val; 6460b57cec5SDimitry Andric Rel.getTypeName(Name); 647cb14a3feSDimitry Andric if (Error E = getRelocationValueString(Rel, SymbolDescription, Val)) 6488bcb0991SDimitry Andric reportError(std::move(E), FileName); 649bdd1243dSDimitry Andric OS << (Is64Bits || !LeadingAddr ? "\t\t" : "\t\t\t"); 650bdd1243dSDimitry Andric if (LeadingAddr) 651bdd1243dSDimitry Andric OS << format(Fmt.data(), Address); 652bdd1243dSDimitry Andric OS << Name << "\t" << Val; 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric 6555f757f3fSDimitry Andric static void printBTFRelocation(formatted_raw_ostream &FOS, llvm::BTFParser &BTF, 6565f757f3fSDimitry Andric object::SectionedAddress Address, 6575f757f3fSDimitry Andric LiveVariablePrinter &LVP) { 6585f757f3fSDimitry Andric const llvm::BTF::BPFFieldReloc *Reloc = BTF.findFieldReloc(Address); 6595f757f3fSDimitry Andric if (!Reloc) 6605f757f3fSDimitry Andric return; 6615f757f3fSDimitry Andric 6625f757f3fSDimitry Andric SmallString<64> Val; 6635f757f3fSDimitry Andric BTF.symbolize(Reloc, Val); 6645f757f3fSDimitry Andric FOS << "\t\t"; 6655f757f3fSDimitry Andric if (LeadingAddr) 6665f757f3fSDimitry Andric FOS << format("%016" PRIx64 ": ", Address.Address + AdjustVMA); 6675f757f3fSDimitry Andric FOS << "CO-RE " << Val; 6685f757f3fSDimitry Andric LVP.printAfterOtherLine(FOS, true); 6695f757f3fSDimitry Andric } 6705f757f3fSDimitry Andric 6710b57cec5SDimitry Andric class PrettyPrinter { 6720b57cec5SDimitry Andric public: 6730b57cec5SDimitry Andric virtual ~PrettyPrinter() = default; 6745ffd83dbSDimitry Andric virtual void 6755ffd83dbSDimitry Andric printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 6765ffd83dbSDimitry Andric object::SectionedAddress Address, formatted_raw_ostream &OS, 6775ffd83dbSDimitry Andric StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 6785ffd83dbSDimitry Andric StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 6795ffd83dbSDimitry Andric LiveVariablePrinter &LVP) { 6800b57cec5SDimitry Andric if (SP && (PrintSource || PrintLines)) 6815ffd83dbSDimitry Andric SP->printSourceLine(OS, Address, ObjectFilename, LVP); 6825ffd83dbSDimitry Andric LVP.printBetweenInsts(OS, false); 6830b57cec5SDimitry Andric 68406c3fb27SDimitry Andric printRawData(Bytes, Address.Address, OS, STI); 6850b57cec5SDimitry Andric 6865ffd83dbSDimitry Andric if (MI) { 6875ffd83dbSDimitry Andric // See MCInstPrinter::printInst. On targets where a PC relative immediate 6885ffd83dbSDimitry Andric // is relative to the next instruction and the length of a MCInst is 6895ffd83dbSDimitry Andric // difficult to measure (x86), this is the address of the next 6905ffd83dbSDimitry Andric // instruction. 6915ffd83dbSDimitry Andric uint64_t Addr = 6925ffd83dbSDimitry Andric Address.Address + (STI.getTargetTriple().isX86() ? Bytes.size() : 0); 6935ffd83dbSDimitry Andric IP.printInst(MI, Addr, "", STI, OS); 6945ffd83dbSDimitry Andric } else 6950b57cec5SDimitry Andric OS << "\t<unknown>"; 6960b57cec5SDimitry Andric } 6970b57cec5SDimitry Andric }; 6980b57cec5SDimitry Andric PrettyPrinter PrettyPrinterInst; 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric class HexagonPrettyPrinter : public PrettyPrinter { 7010b57cec5SDimitry Andric public: 7020b57cec5SDimitry Andric void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address, 7035ffd83dbSDimitry Andric formatted_raw_ostream &OS) { 7040b57cec5SDimitry Andric uint32_t opcode = 7050b57cec5SDimitry Andric (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0]; 706fe6060f1SDimitry Andric if (LeadingAddr) 7070b57cec5SDimitry Andric OS << format("%8" PRIx64 ":", Address); 708fe6060f1SDimitry Andric if (ShowRawInsn) { 7090b57cec5SDimitry Andric OS << "\t"; 7100b57cec5SDimitry Andric dumpBytes(Bytes.slice(0, 4), OS); 7110b57cec5SDimitry Andric OS << format("\t%08" PRIx32, opcode); 7120b57cec5SDimitry Andric } 7130b57cec5SDimitry Andric } 7140b57cec5SDimitry Andric void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 7155ffd83dbSDimitry Andric object::SectionedAddress Address, formatted_raw_ostream &OS, 7160b57cec5SDimitry Andric StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 7175ffd83dbSDimitry Andric StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 7185ffd83dbSDimitry Andric LiveVariablePrinter &LVP) override { 7190b57cec5SDimitry Andric if (SP && (PrintSource || PrintLines)) 7205ffd83dbSDimitry Andric SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); 7210b57cec5SDimitry Andric if (!MI) { 7220b57cec5SDimitry Andric printLead(Bytes, Address.Address, OS); 7230b57cec5SDimitry Andric OS << " <unknown>"; 7240b57cec5SDimitry Andric return; 7250b57cec5SDimitry Andric } 7260b57cec5SDimitry Andric std::string Buffer; 7270b57cec5SDimitry Andric { 7280b57cec5SDimitry Andric raw_string_ostream TempStream(Buffer); 729480093f4SDimitry Andric IP.printInst(MI, Address.Address, "", STI, TempStream); 7300b57cec5SDimitry Andric } 7310b57cec5SDimitry Andric StringRef Contents(Buffer); 7320b57cec5SDimitry Andric // Split off bundle attributes 7330b57cec5SDimitry Andric auto PacketBundle = Contents.rsplit('\n'); 7340b57cec5SDimitry Andric // Split off first instruction from the rest 7350b57cec5SDimitry Andric auto HeadTail = PacketBundle.first.split('\n'); 7360b57cec5SDimitry Andric auto Preamble = " { "; 7370b57cec5SDimitry Andric auto Separator = ""; 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric // Hexagon's packets require relocations to be inline rather than 7400b57cec5SDimitry Andric // clustered at the end of the packet. 7410b57cec5SDimitry Andric std::vector<RelocationRef>::const_iterator RelCur = Rels->begin(); 7420b57cec5SDimitry Andric std::vector<RelocationRef>::const_iterator RelEnd = Rels->end(); 7430b57cec5SDimitry Andric auto PrintReloc = [&]() -> void { 7440b57cec5SDimitry Andric while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) { 7450b57cec5SDimitry Andric if (RelCur->getOffset() == Address.Address) { 7465ffd83dbSDimitry Andric printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false); 7470b57cec5SDimitry Andric return; 7480b57cec5SDimitry Andric } 7490b57cec5SDimitry Andric ++RelCur; 7500b57cec5SDimitry Andric } 7510b57cec5SDimitry Andric }; 7520b57cec5SDimitry Andric 7530b57cec5SDimitry Andric while (!HeadTail.first.empty()) { 7540b57cec5SDimitry Andric OS << Separator; 7550b57cec5SDimitry Andric Separator = "\n"; 7560b57cec5SDimitry Andric if (SP && (PrintSource || PrintLines)) 7575ffd83dbSDimitry Andric SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); 7580b57cec5SDimitry Andric printLead(Bytes, Address.Address, OS); 7590b57cec5SDimitry Andric OS << Preamble; 7600b57cec5SDimitry Andric Preamble = " "; 7610b57cec5SDimitry Andric StringRef Inst; 7620b57cec5SDimitry Andric auto Duplex = HeadTail.first.split('\v'); 7630b57cec5SDimitry Andric if (!Duplex.second.empty()) { 7640b57cec5SDimitry Andric OS << Duplex.first; 7650b57cec5SDimitry Andric OS << "; "; 7660b57cec5SDimitry Andric Inst = Duplex.second; 7670b57cec5SDimitry Andric } 7680b57cec5SDimitry Andric else 7690b57cec5SDimitry Andric Inst = HeadTail.first; 7700b57cec5SDimitry Andric OS << Inst; 7710b57cec5SDimitry Andric HeadTail = HeadTail.second.split('\n'); 7720b57cec5SDimitry Andric if (HeadTail.first.empty()) 7730b57cec5SDimitry Andric OS << " } " << PacketBundle.second; 7740b57cec5SDimitry Andric PrintReloc(); 7750b57cec5SDimitry Andric Bytes = Bytes.slice(4); 7760b57cec5SDimitry Andric Address.Address += 4; 7770b57cec5SDimitry Andric } 7780b57cec5SDimitry Andric } 7790b57cec5SDimitry Andric }; 7800b57cec5SDimitry Andric HexagonPrettyPrinter HexagonPrettyPrinterInst; 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric class AMDGCNPrettyPrinter : public PrettyPrinter { 7830b57cec5SDimitry Andric public: 7840b57cec5SDimitry Andric void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 7855ffd83dbSDimitry Andric object::SectionedAddress Address, formatted_raw_ostream &OS, 7860b57cec5SDimitry Andric StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 7875ffd83dbSDimitry Andric StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 7885ffd83dbSDimitry Andric LiveVariablePrinter &LVP) override { 7890b57cec5SDimitry Andric if (SP && (PrintSource || PrintLines)) 7905ffd83dbSDimitry Andric SP->printSourceLine(OS, Address, ObjectFilename, LVP); 7910b57cec5SDimitry Andric 7920b57cec5SDimitry Andric if (MI) { 7930b57cec5SDimitry Andric SmallString<40> InstStr; 7940b57cec5SDimitry Andric raw_svector_ostream IS(InstStr); 7950b57cec5SDimitry Andric 796480093f4SDimitry Andric IP.printInst(MI, Address.Address, "", STI, IS); 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric OS << left_justify(IS.str(), 60); 7990b57cec5SDimitry Andric } else { 8000b57cec5SDimitry Andric // an unrecognized encoding - this is probably data so represent it 8010b57cec5SDimitry Andric // using the .long directive, or .byte directive if fewer than 4 bytes 8020b57cec5SDimitry Andric // remaining 8030b57cec5SDimitry Andric if (Bytes.size() >= 4) { 8045f757f3fSDimitry Andric OS << format( 8055f757f3fSDimitry Andric "\t.long 0x%08" PRIx32 " ", 8065f757f3fSDimitry Andric support::endian::read32<llvm::endianness::little>(Bytes.data())); 8070b57cec5SDimitry Andric OS.indent(42); 8080b57cec5SDimitry Andric } else { 8090b57cec5SDimitry Andric OS << format("\t.byte 0x%02" PRIx8, Bytes[0]); 8100b57cec5SDimitry Andric for (unsigned int i = 1; i < Bytes.size(); i++) 8110b57cec5SDimitry Andric OS << format(", 0x%02" PRIx8, Bytes[i]); 8120b57cec5SDimitry Andric OS.indent(55 - (6 * Bytes.size())); 8130b57cec5SDimitry Andric } 8140b57cec5SDimitry Andric } 8150b57cec5SDimitry Andric 8160b57cec5SDimitry Andric OS << format("// %012" PRIX64 ":", Address.Address); 8170b57cec5SDimitry Andric if (Bytes.size() >= 4) { 8180b57cec5SDimitry Andric // D should be casted to uint32_t here as it is passed by format to 8190b57cec5SDimitry Andric // snprintf as vararg. 820bdd1243dSDimitry Andric for (uint32_t D : 821bdd1243dSDimitry Andric ArrayRef(reinterpret_cast<const support::little32_t *>(Bytes.data()), 8220b57cec5SDimitry Andric Bytes.size() / 4)) 8230b57cec5SDimitry Andric OS << format(" %08" PRIX32, D); 8240b57cec5SDimitry Andric } else { 8250b57cec5SDimitry Andric for (unsigned char B : Bytes) 8260b57cec5SDimitry Andric OS << format(" %02" PRIX8, B); 8270b57cec5SDimitry Andric } 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric if (!Annot.empty()) 8300b57cec5SDimitry Andric OS << " // " << Annot; 8310b57cec5SDimitry Andric } 8320b57cec5SDimitry Andric }; 8330b57cec5SDimitry Andric AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst; 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric class BPFPrettyPrinter : public PrettyPrinter { 8360b57cec5SDimitry Andric public: 8370b57cec5SDimitry Andric void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 8385ffd83dbSDimitry Andric object::SectionedAddress Address, formatted_raw_ostream &OS, 8390b57cec5SDimitry Andric StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 8405ffd83dbSDimitry Andric StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 8415ffd83dbSDimitry Andric LiveVariablePrinter &LVP) override { 8420b57cec5SDimitry Andric if (SP && (PrintSource || PrintLines)) 8435ffd83dbSDimitry Andric SP->printSourceLine(OS, Address, ObjectFilename, LVP); 844fe6060f1SDimitry Andric if (LeadingAddr) 8450b57cec5SDimitry Andric OS << format("%8" PRId64 ":", Address.Address / 8); 846fe6060f1SDimitry Andric if (ShowRawInsn) { 8470b57cec5SDimitry Andric OS << "\t"; 8480b57cec5SDimitry Andric dumpBytes(Bytes, OS); 8490b57cec5SDimitry Andric } 8500b57cec5SDimitry Andric if (MI) 851480093f4SDimitry Andric IP.printInst(MI, Address.Address, "", STI, OS); 8520b57cec5SDimitry Andric else 8530b57cec5SDimitry Andric OS << "\t<unknown>"; 8540b57cec5SDimitry Andric } 8550b57cec5SDimitry Andric }; 8560b57cec5SDimitry Andric BPFPrettyPrinter BPFPrettyPrinterInst; 8570b57cec5SDimitry Andric 858972a253aSDimitry Andric class ARMPrettyPrinter : public PrettyPrinter { 859972a253aSDimitry Andric public: 860972a253aSDimitry Andric void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 861972a253aSDimitry Andric object::SectionedAddress Address, formatted_raw_ostream &OS, 862972a253aSDimitry Andric StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 863972a253aSDimitry Andric StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 864972a253aSDimitry Andric LiveVariablePrinter &LVP) override { 865972a253aSDimitry Andric if (SP && (PrintSource || PrintLines)) 866972a253aSDimitry Andric SP->printSourceLine(OS, Address, ObjectFilename, LVP); 867972a253aSDimitry Andric LVP.printBetweenInsts(OS, false); 868972a253aSDimitry Andric 869972a253aSDimitry Andric size_t Start = OS.tell(); 870972a253aSDimitry Andric if (LeadingAddr) 871972a253aSDimitry Andric OS << format("%8" PRIx64 ":", Address.Address); 872972a253aSDimitry Andric if (ShowRawInsn) { 873972a253aSDimitry Andric size_t Pos = 0, End = Bytes.size(); 874972a253aSDimitry Andric if (STI.checkFeatures("+thumb-mode")) { 875972a253aSDimitry Andric for (; Pos + 2 <= End; Pos += 2) 876972a253aSDimitry Andric OS << ' ' 877972a253aSDimitry Andric << format_hex_no_prefix( 878972a253aSDimitry Andric llvm::support::endian::read<uint16_t>( 879bdd1243dSDimitry Andric Bytes.data() + Pos, InstructionEndianness), 880972a253aSDimitry Andric 4); 881972a253aSDimitry Andric } else { 882972a253aSDimitry Andric for (; Pos + 4 <= End; Pos += 4) 883972a253aSDimitry Andric OS << ' ' 884972a253aSDimitry Andric << format_hex_no_prefix( 885972a253aSDimitry Andric llvm::support::endian::read<uint32_t>( 886bdd1243dSDimitry Andric Bytes.data() + Pos, InstructionEndianness), 887972a253aSDimitry Andric 8); 888972a253aSDimitry Andric } 889972a253aSDimitry Andric if (Pos < End) { 890972a253aSDimitry Andric OS << ' '; 891972a253aSDimitry Andric dumpBytes(Bytes.slice(Pos), OS); 892972a253aSDimitry Andric } 893972a253aSDimitry Andric } 894972a253aSDimitry Andric 895972a253aSDimitry Andric AlignToInstStartColumn(Start, STI, OS); 896972a253aSDimitry Andric 897972a253aSDimitry Andric if (MI) { 898972a253aSDimitry Andric IP.printInst(MI, Address.Address, "", STI, OS); 899972a253aSDimitry Andric } else 900972a253aSDimitry Andric OS << "\t<unknown>"; 901972a253aSDimitry Andric } 902bdd1243dSDimitry Andric 9035f757f3fSDimitry Andric void setInstructionEndianness(llvm::endianness Endianness) { 904bdd1243dSDimitry Andric InstructionEndianness = Endianness; 905bdd1243dSDimitry Andric } 906bdd1243dSDimitry Andric 907bdd1243dSDimitry Andric private: 9085f757f3fSDimitry Andric llvm::endianness InstructionEndianness = llvm::endianness::little; 909972a253aSDimitry Andric }; 910972a253aSDimitry Andric ARMPrettyPrinter ARMPrettyPrinterInst; 911972a253aSDimitry Andric 912972a253aSDimitry Andric class AArch64PrettyPrinter : public PrettyPrinter { 913972a253aSDimitry Andric public: 914972a253aSDimitry Andric void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 915972a253aSDimitry Andric object::SectionedAddress Address, formatted_raw_ostream &OS, 916972a253aSDimitry Andric StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 917972a253aSDimitry Andric StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 918972a253aSDimitry Andric LiveVariablePrinter &LVP) override { 919972a253aSDimitry Andric if (SP && (PrintSource || PrintLines)) 920972a253aSDimitry Andric SP->printSourceLine(OS, Address, ObjectFilename, LVP); 921972a253aSDimitry Andric LVP.printBetweenInsts(OS, false); 922972a253aSDimitry Andric 923972a253aSDimitry Andric size_t Start = OS.tell(); 924972a253aSDimitry Andric if (LeadingAddr) 925972a253aSDimitry Andric OS << format("%8" PRIx64 ":", Address.Address); 926972a253aSDimitry Andric if (ShowRawInsn) { 927972a253aSDimitry Andric size_t Pos = 0, End = Bytes.size(); 928972a253aSDimitry Andric for (; Pos + 4 <= End; Pos += 4) 929972a253aSDimitry Andric OS << ' ' 930972a253aSDimitry Andric << format_hex_no_prefix( 9315f757f3fSDimitry Andric llvm::support::endian::read<uint32_t>( 9325f757f3fSDimitry Andric Bytes.data() + Pos, llvm::endianness::little), 933972a253aSDimitry Andric 8); 934972a253aSDimitry Andric if (Pos < End) { 935972a253aSDimitry Andric OS << ' '; 936972a253aSDimitry Andric dumpBytes(Bytes.slice(Pos), OS); 937972a253aSDimitry Andric } 938972a253aSDimitry Andric } 939972a253aSDimitry Andric 940972a253aSDimitry Andric AlignToInstStartColumn(Start, STI, OS); 941972a253aSDimitry Andric 942972a253aSDimitry Andric if (MI) { 943972a253aSDimitry Andric IP.printInst(MI, Address.Address, "", STI, OS); 944972a253aSDimitry Andric } else 945972a253aSDimitry Andric OS << "\t<unknown>"; 946972a253aSDimitry Andric } 947972a253aSDimitry Andric }; 948972a253aSDimitry Andric AArch64PrettyPrinter AArch64PrettyPrinterInst; 949972a253aSDimitry Andric 950*0fca6ea1SDimitry Andric class RISCVPrettyPrinter : public PrettyPrinter { 951*0fca6ea1SDimitry Andric public: 952*0fca6ea1SDimitry Andric void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, 953*0fca6ea1SDimitry Andric object::SectionedAddress Address, formatted_raw_ostream &OS, 954*0fca6ea1SDimitry Andric StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, 955*0fca6ea1SDimitry Andric StringRef ObjectFilename, std::vector<RelocationRef> *Rels, 956*0fca6ea1SDimitry Andric LiveVariablePrinter &LVP) override { 957*0fca6ea1SDimitry Andric if (SP && (PrintSource || PrintLines)) 958*0fca6ea1SDimitry Andric SP->printSourceLine(OS, Address, ObjectFilename, LVP); 959*0fca6ea1SDimitry Andric LVP.printBetweenInsts(OS, false); 960*0fca6ea1SDimitry Andric 961*0fca6ea1SDimitry Andric size_t Start = OS.tell(); 962*0fca6ea1SDimitry Andric if (LeadingAddr) 963*0fca6ea1SDimitry Andric OS << format("%8" PRIx64 ":", Address.Address); 964*0fca6ea1SDimitry Andric if (ShowRawInsn) { 965*0fca6ea1SDimitry Andric size_t Pos = 0, End = Bytes.size(); 966*0fca6ea1SDimitry Andric if (End % 4 == 0) { 967*0fca6ea1SDimitry Andric // 32-bit and 64-bit instructions. 968*0fca6ea1SDimitry Andric for (; Pos + 4 <= End; Pos += 4) 969*0fca6ea1SDimitry Andric OS << ' ' 970*0fca6ea1SDimitry Andric << format_hex_no_prefix( 971*0fca6ea1SDimitry Andric llvm::support::endian::read<uint32_t>( 972*0fca6ea1SDimitry Andric Bytes.data() + Pos, llvm::endianness::little), 973*0fca6ea1SDimitry Andric 8); 974*0fca6ea1SDimitry Andric } else if (End % 2 == 0) { 975*0fca6ea1SDimitry Andric // 16-bit and 48-bits instructions. 976*0fca6ea1SDimitry Andric for (; Pos + 2 <= End; Pos += 2) 977*0fca6ea1SDimitry Andric OS << ' ' 978*0fca6ea1SDimitry Andric << format_hex_no_prefix( 979*0fca6ea1SDimitry Andric llvm::support::endian::read<uint16_t>( 980*0fca6ea1SDimitry Andric Bytes.data() + Pos, llvm::endianness::little), 981*0fca6ea1SDimitry Andric 4); 982*0fca6ea1SDimitry Andric } 983*0fca6ea1SDimitry Andric if (Pos < End) { 984*0fca6ea1SDimitry Andric OS << ' '; 985*0fca6ea1SDimitry Andric dumpBytes(Bytes.slice(Pos), OS); 986*0fca6ea1SDimitry Andric } 987*0fca6ea1SDimitry Andric } 988*0fca6ea1SDimitry Andric 989*0fca6ea1SDimitry Andric AlignToInstStartColumn(Start, STI, OS); 990*0fca6ea1SDimitry Andric 991*0fca6ea1SDimitry Andric if (MI) { 992*0fca6ea1SDimitry Andric IP.printInst(MI, Address.Address, "", STI, OS); 993*0fca6ea1SDimitry Andric } else 994*0fca6ea1SDimitry Andric OS << "\t<unknown>"; 995*0fca6ea1SDimitry Andric } 996*0fca6ea1SDimitry Andric }; 997*0fca6ea1SDimitry Andric RISCVPrettyPrinter RISCVPrettyPrinterInst; 998*0fca6ea1SDimitry Andric 9990b57cec5SDimitry Andric PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { 10000b57cec5SDimitry Andric switch(Triple.getArch()) { 10010b57cec5SDimitry Andric default: 10020b57cec5SDimitry Andric return PrettyPrinterInst; 10030b57cec5SDimitry Andric case Triple::hexagon: 10040b57cec5SDimitry Andric return HexagonPrettyPrinterInst; 10050b57cec5SDimitry Andric case Triple::amdgcn: 10060b57cec5SDimitry Andric return AMDGCNPrettyPrinterInst; 10070b57cec5SDimitry Andric case Triple::bpfel: 10080b57cec5SDimitry Andric case Triple::bpfeb: 10090b57cec5SDimitry Andric return BPFPrettyPrinterInst; 1010972a253aSDimitry Andric case Triple::arm: 1011972a253aSDimitry Andric case Triple::armeb: 1012972a253aSDimitry Andric case Triple::thumb: 1013972a253aSDimitry Andric case Triple::thumbeb: 1014972a253aSDimitry Andric return ARMPrettyPrinterInst; 1015972a253aSDimitry Andric case Triple::aarch64: 1016972a253aSDimitry Andric case Triple::aarch64_be: 1017972a253aSDimitry Andric case Triple::aarch64_32: 1018972a253aSDimitry Andric return AArch64PrettyPrinterInst; 1019*0fca6ea1SDimitry Andric case Triple::riscv32: 1020*0fca6ea1SDimitry Andric case Triple::riscv64: 1021*0fca6ea1SDimitry Andric return RISCVPrettyPrinterInst; 10220b57cec5SDimitry Andric } 10230b57cec5SDimitry Andric } 10245f757f3fSDimitry Andric 10255f757f3fSDimitry Andric class DisassemblerTarget { 10265f757f3fSDimitry Andric public: 10275f757f3fSDimitry Andric const Target *TheTarget; 10285f757f3fSDimitry Andric std::unique_ptr<const MCSubtargetInfo> SubtargetInfo; 10295f757f3fSDimitry Andric std::shared_ptr<MCContext> Context; 10305f757f3fSDimitry Andric std::unique_ptr<MCDisassembler> DisAsm; 10315f757f3fSDimitry Andric std::shared_ptr<MCInstrAnalysis> InstrAnalysis; 10325f757f3fSDimitry Andric std::shared_ptr<MCInstPrinter> InstPrinter; 10335f757f3fSDimitry Andric PrettyPrinter *Printer; 10345f757f3fSDimitry Andric 10355f757f3fSDimitry Andric DisassemblerTarget(const Target *TheTarget, ObjectFile &Obj, 10365f757f3fSDimitry Andric StringRef TripleName, StringRef MCPU, 10375f757f3fSDimitry Andric SubtargetFeatures &Features); 10385f757f3fSDimitry Andric DisassemblerTarget(DisassemblerTarget &Other, SubtargetFeatures &Features); 10395f757f3fSDimitry Andric 10405f757f3fSDimitry Andric private: 10415f757f3fSDimitry Andric MCTargetOptions Options; 10425f757f3fSDimitry Andric std::shared_ptr<const MCRegisterInfo> RegisterInfo; 10435f757f3fSDimitry Andric std::shared_ptr<const MCAsmInfo> AsmInfo; 10445f757f3fSDimitry Andric std::shared_ptr<const MCInstrInfo> InstrInfo; 10455f757f3fSDimitry Andric std::shared_ptr<MCObjectFileInfo> ObjectFileInfo; 10465f757f3fSDimitry Andric }; 10475f757f3fSDimitry Andric 10485f757f3fSDimitry Andric DisassemblerTarget::DisassemblerTarget(const Target *TheTarget, ObjectFile &Obj, 10495f757f3fSDimitry Andric StringRef TripleName, StringRef MCPU, 10505f757f3fSDimitry Andric SubtargetFeatures &Features) 10515f757f3fSDimitry Andric : TheTarget(TheTarget), 10525f757f3fSDimitry Andric Printer(&selectPrettyPrinter(Triple(TripleName))), 10535f757f3fSDimitry Andric RegisterInfo(TheTarget->createMCRegInfo(TripleName)) { 10545f757f3fSDimitry Andric if (!RegisterInfo) 10555f757f3fSDimitry Andric reportError(Obj.getFileName(), "no register info for target " + TripleName); 10565f757f3fSDimitry Andric 10575f757f3fSDimitry Andric // Set up disassembler. 10585f757f3fSDimitry Andric AsmInfo.reset(TheTarget->createMCAsmInfo(*RegisterInfo, TripleName, Options)); 10595f757f3fSDimitry Andric if (!AsmInfo) 10605f757f3fSDimitry Andric reportError(Obj.getFileName(), "no assembly info for target " + TripleName); 10615f757f3fSDimitry Andric 10625f757f3fSDimitry Andric SubtargetInfo.reset( 10635f757f3fSDimitry Andric TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); 10645f757f3fSDimitry Andric if (!SubtargetInfo) 10655f757f3fSDimitry Andric reportError(Obj.getFileName(), 10665f757f3fSDimitry Andric "no subtarget info for target " + TripleName); 10675f757f3fSDimitry Andric InstrInfo.reset(TheTarget->createMCInstrInfo()); 10685f757f3fSDimitry Andric if (!InstrInfo) 10695f757f3fSDimitry Andric reportError(Obj.getFileName(), 10705f757f3fSDimitry Andric "no instruction info for target " + TripleName); 10715f757f3fSDimitry Andric Context = 10725f757f3fSDimitry Andric std::make_shared<MCContext>(Triple(TripleName), AsmInfo.get(), 10735f757f3fSDimitry Andric RegisterInfo.get(), SubtargetInfo.get()); 10745f757f3fSDimitry Andric 10755f757f3fSDimitry Andric // FIXME: for now initialize MCObjectFileInfo with default values 10765f757f3fSDimitry Andric ObjectFileInfo.reset( 10775f757f3fSDimitry Andric TheTarget->createMCObjectFileInfo(*Context, /*PIC=*/false)); 10785f757f3fSDimitry Andric Context->setObjectFileInfo(ObjectFileInfo.get()); 10795f757f3fSDimitry Andric 10805f757f3fSDimitry Andric DisAsm.reset(TheTarget->createMCDisassembler(*SubtargetInfo, *Context)); 10815f757f3fSDimitry Andric if (!DisAsm) 10825f757f3fSDimitry Andric reportError(Obj.getFileName(), "no disassembler for target " + TripleName); 10835f757f3fSDimitry Andric 1084*0fca6ea1SDimitry Andric if (auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) 1085*0fca6ea1SDimitry Andric DisAsm->setABIVersion(ELFObj->getEIdentABIVersion()); 1086*0fca6ea1SDimitry Andric 10875f757f3fSDimitry Andric InstrAnalysis.reset(TheTarget->createMCInstrAnalysis(InstrInfo.get())); 10885f757f3fSDimitry Andric 10895f757f3fSDimitry Andric int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 10905f757f3fSDimitry Andric InstPrinter.reset(TheTarget->createMCInstPrinter(Triple(TripleName), 10915f757f3fSDimitry Andric AsmPrinterVariant, *AsmInfo, 10925f757f3fSDimitry Andric *InstrInfo, *RegisterInfo)); 10935f757f3fSDimitry Andric if (!InstPrinter) 10945f757f3fSDimitry Andric reportError(Obj.getFileName(), 10955f757f3fSDimitry Andric "no instruction printer for target " + TripleName); 10965f757f3fSDimitry Andric InstPrinter->setPrintImmHex(PrintImmHex); 10975f757f3fSDimitry Andric InstPrinter->setPrintBranchImmAsAddress(true); 10985f757f3fSDimitry Andric InstPrinter->setSymbolizeOperands(SymbolizeOperands); 10995f757f3fSDimitry Andric InstPrinter->setMCInstrAnalysis(InstrAnalysis.get()); 11005f757f3fSDimitry Andric 11015f757f3fSDimitry Andric switch (DisassemblyColor) { 11025f757f3fSDimitry Andric case ColorOutput::Enable: 11035f757f3fSDimitry Andric InstPrinter->setUseColor(true); 11045f757f3fSDimitry Andric break; 11055f757f3fSDimitry Andric case ColorOutput::Auto: 11065f757f3fSDimitry Andric InstPrinter->setUseColor(outs().has_colors()); 11075f757f3fSDimitry Andric break; 11085f757f3fSDimitry Andric case ColorOutput::Disable: 11095f757f3fSDimitry Andric case ColorOutput::Invalid: 11105f757f3fSDimitry Andric InstPrinter->setUseColor(false); 11115f757f3fSDimitry Andric break; 11125f757f3fSDimitry Andric }; 11135f757f3fSDimitry Andric } 11145f757f3fSDimitry Andric 11155f757f3fSDimitry Andric DisassemblerTarget::DisassemblerTarget(DisassemblerTarget &Other, 11165f757f3fSDimitry Andric SubtargetFeatures &Features) 11175f757f3fSDimitry Andric : TheTarget(Other.TheTarget), 11185f757f3fSDimitry Andric SubtargetInfo(TheTarget->createMCSubtargetInfo(TripleName, MCPU, 11195f757f3fSDimitry Andric Features.getString())), 11205f757f3fSDimitry Andric Context(Other.Context), 11215f757f3fSDimitry Andric DisAsm(TheTarget->createMCDisassembler(*SubtargetInfo, *Context)), 11225f757f3fSDimitry Andric InstrAnalysis(Other.InstrAnalysis), InstPrinter(Other.InstPrinter), 11235f757f3fSDimitry Andric Printer(Other.Printer), RegisterInfo(Other.RegisterInfo), 11245f757f3fSDimitry Andric AsmInfo(Other.AsmInfo), InstrInfo(Other.InstrInfo), 11255f757f3fSDimitry Andric ObjectFileInfo(Other.ObjectFileInfo) {} 112606c3fb27SDimitry Andric } // namespace 11270b57cec5SDimitry Andric 1128753f127fSDimitry Andric static uint8_t getElfSymbolType(const ObjectFile &Obj, const SymbolRef &Sym) { 1129753f127fSDimitry Andric assert(Obj.isELF()); 1130753f127fSDimitry Andric if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj)) 1131e8d8bef9SDimitry Andric return unwrapOrError(Elf32LEObj->getSymbol(Sym.getRawDataRefImpl()), 1132753f127fSDimitry Andric Obj.getFileName()) 1133e8d8bef9SDimitry Andric ->getType(); 1134753f127fSDimitry Andric if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj)) 1135e8d8bef9SDimitry Andric return unwrapOrError(Elf64LEObj->getSymbol(Sym.getRawDataRefImpl()), 1136753f127fSDimitry Andric Obj.getFileName()) 1137e8d8bef9SDimitry Andric ->getType(); 1138753f127fSDimitry Andric if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj)) 1139e8d8bef9SDimitry Andric return unwrapOrError(Elf32BEObj->getSymbol(Sym.getRawDataRefImpl()), 1140753f127fSDimitry Andric Obj.getFileName()) 1141e8d8bef9SDimitry Andric ->getType(); 1142753f127fSDimitry Andric if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj)) 1143e8d8bef9SDimitry Andric return unwrapOrError(Elf64BEObj->getSymbol(Sym.getRawDataRefImpl()), 1144753f127fSDimitry Andric Obj.getFileName()) 1145e8d8bef9SDimitry Andric ->getType(); 11460b57cec5SDimitry Andric llvm_unreachable("Unsupported binary format"); 11470b57cec5SDimitry Andric } 11480b57cec5SDimitry Andric 1149753f127fSDimitry Andric template <class ELFT> 1150753f127fSDimitry Andric static void 1151753f127fSDimitry Andric addDynamicElfSymbols(const ELFObjectFile<ELFT> &Obj, 11520b57cec5SDimitry Andric std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { 1153753f127fSDimitry Andric for (auto Symbol : Obj.getDynamicSymbolIterators()) { 11540b57cec5SDimitry Andric uint8_t SymbolType = Symbol.getELFType(); 11550b57cec5SDimitry Andric if (SymbolType == ELF::STT_SECTION) 11560b57cec5SDimitry Andric continue; 11570b57cec5SDimitry Andric 1158753f127fSDimitry Andric uint64_t Address = unwrapOrError(Symbol.getAddress(), Obj.getFileName()); 11590b57cec5SDimitry Andric // ELFSymbolRef::getAddress() returns size instead of value for common 11600b57cec5SDimitry Andric // symbols which is not desirable for disassembly output. Overriding. 11610b57cec5SDimitry Andric if (SymbolType == ELF::STT_COMMON) 1162753f127fSDimitry Andric Address = unwrapOrError(Obj.getSymbol(Symbol.getRawDataRefImpl()), 1163753f127fSDimitry Andric Obj.getFileName()) 1164e8d8bef9SDimitry Andric ->st_value; 11650b57cec5SDimitry Andric 1166753f127fSDimitry Andric StringRef Name = unwrapOrError(Symbol.getName(), Obj.getFileName()); 11670b57cec5SDimitry Andric if (Name.empty()) 11680b57cec5SDimitry Andric continue; 11690b57cec5SDimitry Andric 11700b57cec5SDimitry Andric section_iterator SecI = 1171753f127fSDimitry Andric unwrapOrError(Symbol.getSection(), Obj.getFileName()); 1172753f127fSDimitry Andric if (SecI == Obj.section_end()) 11730b57cec5SDimitry Andric continue; 11740b57cec5SDimitry Andric 11750b57cec5SDimitry Andric AllSymbols[*SecI].emplace_back(Address, Name, SymbolType); 11760b57cec5SDimitry Andric } 11770b57cec5SDimitry Andric } 11780b57cec5SDimitry Andric 11790b57cec5SDimitry Andric static void 1180753f127fSDimitry Andric addDynamicElfSymbols(const ELFObjectFileBase &Obj, 11810b57cec5SDimitry Andric std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { 1182753f127fSDimitry Andric if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj)) 1183753f127fSDimitry Andric addDynamicElfSymbols(*Elf32LEObj, AllSymbols); 1184753f127fSDimitry Andric else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj)) 1185753f127fSDimitry Andric addDynamicElfSymbols(*Elf64LEObj, AllSymbols); 1186753f127fSDimitry Andric else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj)) 1187753f127fSDimitry Andric addDynamicElfSymbols(*Elf32BEObj, AllSymbols); 1188753f127fSDimitry Andric else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj)) 1189753f127fSDimitry Andric addDynamicElfSymbols(*Elf64BEObj, AllSymbols); 11900b57cec5SDimitry Andric else 11910b57cec5SDimitry Andric llvm_unreachable("Unsupported binary format"); 11920b57cec5SDimitry Andric } 11930b57cec5SDimitry Andric 1194bdd1243dSDimitry Andric static std::optional<SectionRef> getWasmCodeSection(const WasmObjectFile &Obj) { 1195753f127fSDimitry Andric for (auto SecI : Obj.sections()) { 1196753f127fSDimitry Andric const WasmSection &Section = Obj.getWasmSection(SecI); 1197fe6060f1SDimitry Andric if (Section.Type == wasm::WASM_SEC_CODE) 1198fe6060f1SDimitry Andric return SecI; 1199fe6060f1SDimitry Andric } 1200bdd1243dSDimitry Andric return std::nullopt; 1201fe6060f1SDimitry Andric } 1202fe6060f1SDimitry Andric 1203fe6060f1SDimitry Andric static void 1204753f127fSDimitry Andric addMissingWasmCodeSymbols(const WasmObjectFile &Obj, 1205fe6060f1SDimitry Andric std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { 1206bdd1243dSDimitry Andric std::optional<SectionRef> Section = getWasmCodeSection(Obj); 1207fe6060f1SDimitry Andric if (!Section) 1208fe6060f1SDimitry Andric return; 1209fe6060f1SDimitry Andric SectionSymbolsTy &Symbols = AllSymbols[*Section]; 1210fe6060f1SDimitry Andric 1211fe6060f1SDimitry Andric std::set<uint64_t> SymbolAddresses; 1212fe6060f1SDimitry Andric for (const auto &Sym : Symbols) 1213fe6060f1SDimitry Andric SymbolAddresses.insert(Sym.Addr); 1214fe6060f1SDimitry Andric 1215753f127fSDimitry Andric for (const wasm::WasmFunction &Function : Obj.functions()) { 1216*0fca6ea1SDimitry Andric // This adjustment mirrors the one in WasmObjectFile::getSymbolAddress. 1217*0fca6ea1SDimitry Andric uint32_t Adjustment = Obj.isRelocatableObject() || Obj.isSharedObject() 1218*0fca6ea1SDimitry Andric ? 0 1219*0fca6ea1SDimitry Andric : Section->getAddress(); 1220*0fca6ea1SDimitry Andric uint64_t Address = Function.CodeSectionOffset + Adjustment; 1221fe6060f1SDimitry Andric // Only add fallback symbols for functions not already present in the symbol 1222fe6060f1SDimitry Andric // table. 1223fe6060f1SDimitry Andric if (SymbolAddresses.count(Address)) 1224fe6060f1SDimitry Andric continue; 1225fe6060f1SDimitry Andric // This function has no symbol, so it should have no SymbolName. 1226fe6060f1SDimitry Andric assert(Function.SymbolName.empty()); 1227fe6060f1SDimitry Andric // We use DebugName for the name, though it may be empty if there is no 1228fe6060f1SDimitry Andric // "name" custom section, or that section is missing a name for this 1229fe6060f1SDimitry Andric // function. 1230fe6060f1SDimitry Andric StringRef Name = Function.DebugName; 1231fe6060f1SDimitry Andric Symbols.emplace_back(Address, Name, ELF::STT_NOTYPE); 1232fe6060f1SDimitry Andric } 1233fe6060f1SDimitry Andric } 1234fe6060f1SDimitry Andric 1235753f127fSDimitry Andric static void addPltEntries(const ObjectFile &Obj, 12360b57cec5SDimitry Andric std::map<SectionRef, SectionSymbolsTy> &AllSymbols, 12370b57cec5SDimitry Andric StringSaver &Saver) { 123806c3fb27SDimitry Andric auto *ElfObj = dyn_cast<ELFObjectFileBase>(&Obj); 123906c3fb27SDimitry Andric if (!ElfObj) 124006c3fb27SDimitry Andric return; 124106c3fb27SDimitry Andric DenseMap<StringRef, SectionRef> Sections; 124206c3fb27SDimitry Andric for (SectionRef Section : Obj.sections()) { 12438bcb0991SDimitry Andric Expected<StringRef> SecNameOrErr = Section.getName(); 12448bcb0991SDimitry Andric if (!SecNameOrErr) { 12458bcb0991SDimitry Andric consumeError(SecNameOrErr.takeError()); 12460b57cec5SDimitry Andric continue; 12478bcb0991SDimitry Andric } 124806c3fb27SDimitry Andric Sections[*SecNameOrErr] = Section; 12490b57cec5SDimitry Andric } 125006c3fb27SDimitry Andric for (auto Plt : ElfObj->getPltEntries()) { 125106c3fb27SDimitry Andric if (Plt.Symbol) { 125206c3fb27SDimitry Andric SymbolRef Symbol(*Plt.Symbol, ElfObj); 12530b57cec5SDimitry Andric uint8_t SymbolType = getElfSymbolType(Obj, Symbol); 1254e8d8bef9SDimitry Andric if (Expected<StringRef> NameOrErr = Symbol.getName()) { 1255e8d8bef9SDimitry Andric if (!NameOrErr->empty()) 125606c3fb27SDimitry Andric AllSymbols[Sections[Plt.Section]].emplace_back( 125706c3fb27SDimitry Andric Plt.Address, Saver.save((*NameOrErr + "@plt").str()), SymbolType); 1258e8d8bef9SDimitry Andric continue; 1259e8d8bef9SDimitry Andric } else { 1260e8d8bef9SDimitry Andric // The warning has been reported in disassembleObject(). 1261e8d8bef9SDimitry Andric consumeError(NameOrErr.takeError()); 1262e8d8bef9SDimitry Andric } 1263e8d8bef9SDimitry Andric } 126406c3fb27SDimitry Andric reportWarning("PLT entry at 0x" + Twine::utohexstr(Plt.Address) + 1265e8d8bef9SDimitry Andric " references an invalid symbol", 1266753f127fSDimitry Andric Obj.getFileName()); 12670b57cec5SDimitry Andric } 12680b57cec5SDimitry Andric } 12690b57cec5SDimitry Andric 12700b57cec5SDimitry Andric // Normally the disassembly output will skip blocks of zeroes. This function 12710b57cec5SDimitry Andric // returns the number of zero bytes that can be skipped when dumping the 12720b57cec5SDimitry Andric // disassembly of the instructions in Buf. 12730b57cec5SDimitry Andric static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) { 12740b57cec5SDimitry Andric // Find the number of leading zeroes. 12750b57cec5SDimitry Andric size_t N = 0; 12760b57cec5SDimitry Andric while (N < Buf.size() && !Buf[N]) 12770b57cec5SDimitry Andric ++N; 12780b57cec5SDimitry Andric 12790b57cec5SDimitry Andric // We may want to skip blocks of zero bytes, but unless we see 12800b57cec5SDimitry Andric // at least 8 of them in a row. 12810b57cec5SDimitry Andric if (N < 8) 12820b57cec5SDimitry Andric return 0; 12830b57cec5SDimitry Andric 12840b57cec5SDimitry Andric // We skip zeroes in multiples of 4 because do not want to truncate an 12850b57cec5SDimitry Andric // instruction if it starts with a zero byte. 12860b57cec5SDimitry Andric return N & ~0x3; 12870b57cec5SDimitry Andric } 12880b57cec5SDimitry Andric 12890b57cec5SDimitry Andric // Returns a map from sections to their relocations. 12900b57cec5SDimitry Andric static std::map<SectionRef, std::vector<RelocationRef>> 12910b57cec5SDimitry Andric getRelocsMap(object::ObjectFile const &Obj) { 12920b57cec5SDimitry Andric std::map<SectionRef, std::vector<RelocationRef>> Ret; 12938bcb0991SDimitry Andric uint64_t I = (uint64_t)-1; 12940b57cec5SDimitry Andric for (SectionRef Sec : Obj.sections()) { 12958bcb0991SDimitry Andric ++I; 12968bcb0991SDimitry Andric Expected<section_iterator> RelocatedOrErr = Sec.getRelocatedSection(); 12978bcb0991SDimitry Andric if (!RelocatedOrErr) 12988bcb0991SDimitry Andric reportError(Obj.getFileName(), 12998bcb0991SDimitry Andric "section (" + Twine(I) + 13008bcb0991SDimitry Andric "): failed to get a relocated section: " + 13018bcb0991SDimitry Andric toString(RelocatedOrErr.takeError())); 13028bcb0991SDimitry Andric 13038bcb0991SDimitry Andric section_iterator Relocated = *RelocatedOrErr; 13048bcb0991SDimitry Andric if (Relocated == Obj.section_end() || !checkSectionFilter(*Relocated).Keep) 13050b57cec5SDimitry Andric continue; 13060b57cec5SDimitry Andric std::vector<RelocationRef> &V = Ret[*Relocated]; 1307fe6060f1SDimitry Andric append_range(V, Sec.relocations()); 13080b57cec5SDimitry Andric // Sort relocations by address. 13090b57cec5SDimitry Andric llvm::stable_sort(V, isRelocAddressLess); 13100b57cec5SDimitry Andric } 13110b57cec5SDimitry Andric return Ret; 13120b57cec5SDimitry Andric } 13130b57cec5SDimitry Andric 13140b57cec5SDimitry Andric // Used for --adjust-vma to check if address should be adjusted by the 13150b57cec5SDimitry Andric // specified value for a given section. 13160b57cec5SDimitry Andric // For ELF we do not adjust non-allocatable sections like debug ones, 13170b57cec5SDimitry Andric // because they are not loadable. 13180b57cec5SDimitry Andric // TODO: implement for other file formats. 13190b57cec5SDimitry Andric static bool shouldAdjustVA(const SectionRef &Section) { 13200b57cec5SDimitry Andric const ObjectFile *Obj = Section.getObject(); 13215ffd83dbSDimitry Andric if (Obj->isELF()) 13220b57cec5SDimitry Andric return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC; 13230b57cec5SDimitry Andric return false; 13240b57cec5SDimitry Andric } 13250b57cec5SDimitry Andric 13260b57cec5SDimitry Andric 13270b57cec5SDimitry Andric typedef std::pair<uint64_t, char> MappingSymbolPair; 13280b57cec5SDimitry Andric static char getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols, 13290b57cec5SDimitry Andric uint64_t Address) { 13300b57cec5SDimitry Andric auto It = 13310b57cec5SDimitry Andric partition_point(MappingSymbols, [Address](const MappingSymbolPair &Val) { 13320b57cec5SDimitry Andric return Val.first <= Address; 13330b57cec5SDimitry Andric }); 13340b57cec5SDimitry Andric // Return zero for any address before the first mapping symbol; this means 13350b57cec5SDimitry Andric // we should use the default disassembly mode, depending on the target. 13360b57cec5SDimitry Andric if (It == MappingSymbols.begin()) 13370b57cec5SDimitry Andric return '\x00'; 13380b57cec5SDimitry Andric return (It - 1)->second; 13390b57cec5SDimitry Andric } 13400b57cec5SDimitry Andric 13415ffd83dbSDimitry Andric static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index, 1342753f127fSDimitry Andric uint64_t End, const ObjectFile &Obj, 13435ffd83dbSDimitry Andric ArrayRef<uint8_t> Bytes, 13445ffd83dbSDimitry Andric ArrayRef<MappingSymbolPair> MappingSymbols, 1345972a253aSDimitry Andric const MCSubtargetInfo &STI, raw_ostream &OS) { 13465f757f3fSDimitry Andric llvm::endianness Endian = 13475f757f3fSDimitry Andric Obj.isLittleEndian() ? llvm::endianness::little : llvm::endianness::big; 1348972a253aSDimitry Andric size_t Start = OS.tell(); 1349972a253aSDimitry Andric OS << format("%8" PRIx64 ": ", SectionAddr + Index); 13500b57cec5SDimitry Andric if (Index + 4 <= End) { 13515ffd83dbSDimitry Andric dumpBytes(Bytes.slice(Index, 4), OS); 1352972a253aSDimitry Andric AlignToInstStartColumn(Start, STI, OS); 13535ffd83dbSDimitry Andric OS << "\t.word\t" 13545ffd83dbSDimitry Andric << format_hex(support::endian::read32(Bytes.data() + Index, Endian), 13555ffd83dbSDimitry Andric 10); 13565ffd83dbSDimitry Andric return 4; 13570b57cec5SDimitry Andric } 13585ffd83dbSDimitry Andric if (Index + 2 <= End) { 13595ffd83dbSDimitry Andric dumpBytes(Bytes.slice(Index, 2), OS); 1360972a253aSDimitry Andric AlignToInstStartColumn(Start, STI, OS); 1361972a253aSDimitry Andric OS << "\t.short\t" 1362972a253aSDimitry Andric << format_hex(support::endian::read16(Bytes.data() + Index, Endian), 6); 13635ffd83dbSDimitry Andric return 2; 13640b57cec5SDimitry Andric } 13655ffd83dbSDimitry Andric dumpBytes(Bytes.slice(Index, 1), OS); 1366972a253aSDimitry Andric AlignToInstStartColumn(Start, STI, OS); 1367972a253aSDimitry Andric OS << "\t.byte\t" << format_hex(Bytes[Index], 4); 13685ffd83dbSDimitry Andric return 1; 13690b57cec5SDimitry Andric } 13700b57cec5SDimitry Andric 13710b57cec5SDimitry Andric static void dumpELFData(uint64_t SectionAddr, uint64_t Index, uint64_t End, 13720b57cec5SDimitry Andric ArrayRef<uint8_t> Bytes) { 13730b57cec5SDimitry Andric // print out data up to 8 bytes at a time in hex and ascii 13740b57cec5SDimitry Andric uint8_t AsciiData[9] = {'\0'}; 13750b57cec5SDimitry Andric uint8_t Byte; 13760b57cec5SDimitry Andric int NumBytes = 0; 13770b57cec5SDimitry Andric 13780b57cec5SDimitry Andric for (; Index < End; ++Index) { 13790b57cec5SDimitry Andric if (NumBytes == 0) 13800b57cec5SDimitry Andric outs() << format("%8" PRIx64 ":", SectionAddr + Index); 13810b57cec5SDimitry Andric Byte = Bytes.slice(Index)[0]; 13820b57cec5SDimitry Andric outs() << format(" %02x", Byte); 13830b57cec5SDimitry Andric AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.'; 13840b57cec5SDimitry Andric 13850b57cec5SDimitry Andric uint8_t IndentOffset = 0; 13860b57cec5SDimitry Andric NumBytes++; 13870b57cec5SDimitry Andric if (Index == End - 1 || NumBytes > 8) { 13880b57cec5SDimitry Andric // Indent the space for less than 8 bytes data. 13890b57cec5SDimitry Andric // 2 spaces for byte and one for space between bytes 13900b57cec5SDimitry Andric IndentOffset = 3 * (8 - NumBytes); 13910b57cec5SDimitry Andric for (int Excess = NumBytes; Excess < 8; Excess++) 13920b57cec5SDimitry Andric AsciiData[Excess] = '\0'; 13930b57cec5SDimitry Andric NumBytes = 8; 13940b57cec5SDimitry Andric } 13950b57cec5SDimitry Andric if (NumBytes == 8) { 13960b57cec5SDimitry Andric AsciiData[8] = '\0'; 13970b57cec5SDimitry Andric outs() << std::string(IndentOffset, ' ') << " "; 13980b57cec5SDimitry Andric outs() << reinterpret_cast<char *>(AsciiData); 13990b57cec5SDimitry Andric outs() << '\n'; 14000b57cec5SDimitry Andric NumBytes = 0; 14010b57cec5SDimitry Andric } 14020b57cec5SDimitry Andric } 14030b57cec5SDimitry Andric } 14040b57cec5SDimitry Andric 1405753f127fSDimitry Andric SymbolInfoTy objdump::createSymbolInfo(const ObjectFile &Obj, 14065f757f3fSDimitry Andric const SymbolRef &Symbol, 14075f757f3fSDimitry Andric bool IsMappingSymbol) { 1408753f127fSDimitry Andric const StringRef FileName = Obj.getFileName(); 14095ffd83dbSDimitry Andric const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 14105ffd83dbSDimitry Andric const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 14115ffd83dbSDimitry Andric 141206c3fb27SDimitry Andric if (Obj.isXCOFF() && (SymbolDescription || TracebackTable)) { 1413753f127fSDimitry Andric const auto &XCOFFObj = cast<XCOFFObjectFile>(Obj); 14145ffd83dbSDimitry Andric DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl(); 14155ffd83dbSDimitry Andric 1416753f127fSDimitry Andric const uint32_t SymbolIndex = XCOFFObj.getSymbolIndex(SymbolDRI.p); 1417bdd1243dSDimitry Andric std::optional<XCOFF::StorageMappingClass> Smc = 14185ffd83dbSDimitry Andric getXCOFFSymbolCsectSMC(XCOFFObj, Symbol); 14195f757f3fSDimitry Andric return SymbolInfoTy(Smc, Addr, Name, SymbolIndex, 14205ffd83dbSDimitry Andric isLabel(XCOFFObj, Symbol)); 1421753f127fSDimitry Andric } else if (Obj.isXCOFF()) { 142281ad6265SDimitry Andric const SymbolRef::Type SymType = unwrapOrError(Symbol.getType(), FileName); 14235f757f3fSDimitry Andric return SymbolInfoTy(Addr, Name, SymType, /*IsMappingSymbol=*/false, 14245f757f3fSDimitry Andric /*IsXCOFF=*/true); 1425*0fca6ea1SDimitry Andric } else if (Obj.isWasm()) { 1426*0fca6ea1SDimitry Andric uint8_t SymType = 1427*0fca6ea1SDimitry Andric cast<WasmObjectFile>(&Obj)->getWasmSymbol(Symbol).Info.Kind; 1428*0fca6ea1SDimitry Andric return SymbolInfoTy(Addr, Name, SymType, false); 14295f757f3fSDimitry Andric } else { 14305f757f3fSDimitry Andric uint8_t Type = 14315f757f3fSDimitry Andric Obj.isELF() ? getElfSymbolType(Obj, Symbol) : (uint8_t)ELF::STT_NOTYPE; 14325f757f3fSDimitry Andric return SymbolInfoTy(Addr, Name, Type, IsMappingSymbol); 14335f757f3fSDimitry Andric } 14345ffd83dbSDimitry Andric } 14355ffd83dbSDimitry Andric 1436753f127fSDimitry Andric static SymbolInfoTy createDummySymbolInfo(const ObjectFile &Obj, 14375ffd83dbSDimitry Andric const uint64_t Addr, StringRef &Name, 14385ffd83dbSDimitry Andric uint8_t Type) { 143906c3fb27SDimitry Andric if (Obj.isXCOFF() && (SymbolDescription || TracebackTable)) 14405f757f3fSDimitry Andric return SymbolInfoTy(std::nullopt, Addr, Name, std::nullopt, false); 1441*0fca6ea1SDimitry Andric if (Obj.isWasm()) 1442*0fca6ea1SDimitry Andric return SymbolInfoTy(Addr, Name, wasm::WASM_SYMBOL_TYPE_SECTION); 14435ffd83dbSDimitry Andric return SymbolInfoTy(Addr, Name, Type); 14445ffd83dbSDimitry Andric } 14455ffd83dbSDimitry Andric 14467a6dacacSDimitry Andric static void collectBBAddrMapLabels( 1447*0fca6ea1SDimitry Andric const BBAddrMapInfo &FullAddrMap, uint64_t SectionAddr, uint64_t Start, 1448*0fca6ea1SDimitry Andric uint64_t End, 1449*0fca6ea1SDimitry Andric std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> &Labels) { 1450*0fca6ea1SDimitry Andric if (FullAddrMap.empty()) 145181ad6265SDimitry Andric return; 145281ad6265SDimitry Andric Labels.clear(); 145381ad6265SDimitry Andric uint64_t StartAddress = SectionAddr + Start; 145481ad6265SDimitry Andric uint64_t EndAddress = SectionAddr + End; 1455*0fca6ea1SDimitry Andric const BBAddrMapFunctionEntry *FunctionMap = 1456*0fca6ea1SDimitry Andric FullAddrMap.getEntryForAddress(StartAddress); 1457*0fca6ea1SDimitry Andric if (!FunctionMap) 145881ad6265SDimitry Andric return; 1459*0fca6ea1SDimitry Andric std::optional<size_t> BBRangeIndex = 1460*0fca6ea1SDimitry Andric FunctionMap->getAddrMap().getBBRangeIndexForBaseAddress(StartAddress); 1461*0fca6ea1SDimitry Andric if (!BBRangeIndex) 1462*0fca6ea1SDimitry Andric return; 1463*0fca6ea1SDimitry Andric size_t NumBBEntriesBeforeRange = 0; 1464*0fca6ea1SDimitry Andric for (size_t I = 0; I < *BBRangeIndex; ++I) 1465*0fca6ea1SDimitry Andric NumBBEntriesBeforeRange += 1466*0fca6ea1SDimitry Andric FunctionMap->getAddrMap().BBRanges[I].BBEntries.size(); 1467*0fca6ea1SDimitry Andric const auto &BBRange = FunctionMap->getAddrMap().BBRanges[*BBRangeIndex]; 1468*0fca6ea1SDimitry Andric for (size_t I = 0; I < BBRange.BBEntries.size(); ++I) { 1469*0fca6ea1SDimitry Andric const BBAddrMap::BBEntry &BBEntry = BBRange.BBEntries[I]; 1470*0fca6ea1SDimitry Andric uint64_t BBAddress = BBEntry.Offset + BBRange.BaseAddress; 147181ad6265SDimitry Andric if (BBAddress >= EndAddress) 147281ad6265SDimitry Andric continue; 14737a6dacacSDimitry Andric 14747a6dacacSDimitry Andric std::string LabelString = ("BB" + Twine(BBEntry.ID)).str(); 1475*0fca6ea1SDimitry Andric Labels[BBAddress].push_back( 1476*0fca6ea1SDimitry Andric {LabelString, FunctionMap->constructPGOLabelString( 1477*0fca6ea1SDimitry Andric NumBBEntriesBeforeRange + I, PrettyPGOAnalysisMap)}); 147881ad6265SDimitry Andric } 147981ad6265SDimitry Andric } 148081ad6265SDimitry Andric 14815f757f3fSDimitry Andric static void 14825f757f3fSDimitry Andric collectLocalBranchTargets(ArrayRef<uint8_t> Bytes, MCInstrAnalysis *MIA, 14835f757f3fSDimitry Andric MCDisassembler *DisAsm, MCInstPrinter *IP, 14845f757f3fSDimitry Andric const MCSubtargetInfo *STI, uint64_t SectionAddr, 14855f757f3fSDimitry Andric uint64_t Start, uint64_t End, 14865f757f3fSDimitry Andric std::unordered_map<uint64_t, std::string> &Labels) { 14870eae32dcSDimitry Andric // So far only supports PowerPC and X86. 1488cb14a3feSDimitry Andric const bool isPPC = STI->getTargetTriple().isPPC(); 1489cb14a3feSDimitry Andric if (!isPPC && !STI->getTargetTriple().isX86()) 1490e8d8bef9SDimitry Andric return; 1491e8d8bef9SDimitry Andric 14925f757f3fSDimitry Andric if (MIA) 14935f757f3fSDimitry Andric MIA->resetState(); 14945f757f3fSDimitry Andric 1495e8d8bef9SDimitry Andric Labels.clear(); 1496e8d8bef9SDimitry Andric unsigned LabelCount = 0; 1497e8d8bef9SDimitry Andric Start += SectionAddr; 1498e8d8bef9SDimitry Andric End += SectionAddr; 1499cb14a3feSDimitry Andric const bool isXCOFF = STI->getTargetTriple().isOSBinFormatXCOFF(); 1500cb14a3feSDimitry Andric for (uint64_t Index = Start; Index < End;) { 1501e8d8bef9SDimitry Andric // Disassemble a real instruction and record function-local branch labels. 1502e8d8bef9SDimitry Andric MCInst Inst; 1503e8d8bef9SDimitry Andric uint64_t Size; 1504972a253aSDimitry Andric ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index - SectionAddr); 1505972a253aSDimitry Andric bool Disassembled = 1506972a253aSDimitry Andric DisAsm->getInstruction(Inst, Size, ThisBytes, Index, nulls()); 1507e8d8bef9SDimitry Andric if (Size == 0) 1508972a253aSDimitry Andric Size = std::min<uint64_t>(ThisBytes.size(), 1509972a253aSDimitry Andric DisAsm->suggestBytesToSkip(ThisBytes, Index)); 1510e8d8bef9SDimitry Andric 1511cb14a3feSDimitry Andric if (MIA) { 1512cb14a3feSDimitry Andric if (Disassembled) { 1513e8d8bef9SDimitry Andric uint64_t Target; 1514e8d8bef9SDimitry Andric bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target); 1515e8d8bef9SDimitry Andric if (TargetKnown && (Target >= Start && Target < End) && 1516cb14a3feSDimitry Andric !Labels.count(Target)) { 1517cb14a3feSDimitry Andric // On PowerPC and AIX, a function call is encoded as a branch to 0. 1518cb14a3feSDimitry Andric // On other PowerPC platforms (ELF), a function call is encoded as 1519cb14a3feSDimitry Andric // a branch to self. Do not add a label for these cases. 1520cb14a3feSDimitry Andric if (!(isPPC && 1521cb14a3feSDimitry Andric ((Target == 0 && isXCOFF) || (Target == Index && !isXCOFF)))) 1522e8d8bef9SDimitry Andric Labels[Target] = ("L" + Twine(LabelCount++)).str(); 1523cb14a3feSDimitry Andric } 15245f757f3fSDimitry Andric MIA->updateState(Inst, Index); 1525cb14a3feSDimitry Andric } else 15265f757f3fSDimitry Andric MIA->resetState(); 1527e8d8bef9SDimitry Andric } 1528e8d8bef9SDimitry Andric Index += Size; 1529e8d8bef9SDimitry Andric } 1530e8d8bef9SDimitry Andric } 1531e8d8bef9SDimitry Andric 1532fe6060f1SDimitry Andric // Create an MCSymbolizer for the target and add it to the MCDisassembler. 1533fe6060f1SDimitry Andric // This is currently only used on AMDGPU, and assumes the format of the 1534fe6060f1SDimitry Andric // void * argument passed to AMDGPU's createMCSymbolizer. 1535fe6060f1SDimitry Andric static void addSymbolizer( 1536fe6060f1SDimitry Andric MCContext &Ctx, const Target *Target, StringRef TripleName, 1537fe6060f1SDimitry Andric MCDisassembler *DisAsm, uint64_t SectionAddr, ArrayRef<uint8_t> Bytes, 1538fe6060f1SDimitry Andric SectionSymbolsTy &Symbols, 1539fe6060f1SDimitry Andric std::vector<std::unique_ptr<std::string>> &SynthesizedLabelNames) { 1540fe6060f1SDimitry Andric 1541fe6060f1SDimitry Andric std::unique_ptr<MCRelocationInfo> RelInfo( 1542fe6060f1SDimitry Andric Target->createMCRelocationInfo(TripleName, Ctx)); 1543fe6060f1SDimitry Andric if (!RelInfo) 1544fe6060f1SDimitry Andric return; 1545fe6060f1SDimitry Andric std::unique_ptr<MCSymbolizer> Symbolizer(Target->createMCSymbolizer( 1546fe6060f1SDimitry Andric TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo))); 1547fe6060f1SDimitry Andric MCSymbolizer *SymbolizerPtr = &*Symbolizer; 1548fe6060f1SDimitry Andric DisAsm->setSymbolizer(std::move(Symbolizer)); 1549fe6060f1SDimitry Andric 1550fe6060f1SDimitry Andric if (!SymbolizeOperands) 1551fe6060f1SDimitry Andric return; 1552fe6060f1SDimitry Andric 1553fe6060f1SDimitry Andric // Synthesize labels referenced by branch instructions by 1554fe6060f1SDimitry Andric // disassembling, discarding the output, and collecting the referenced 1555fe6060f1SDimitry Andric // addresses from the symbolizer. 1556fe6060f1SDimitry Andric for (size_t Index = 0; Index != Bytes.size();) { 1557fe6060f1SDimitry Andric MCInst Inst; 1558fe6060f1SDimitry Andric uint64_t Size; 1559bdd1243dSDimitry Andric ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index); 1560bdd1243dSDimitry Andric const uint64_t ThisAddr = SectionAddr + Index; 1561bdd1243dSDimitry Andric DisAsm->getInstruction(Inst, Size, ThisBytes, ThisAddr, nulls()); 1562fe6060f1SDimitry Andric if (Size == 0) 1563972a253aSDimitry Andric Size = std::min<uint64_t>(ThisBytes.size(), 1564972a253aSDimitry Andric DisAsm->suggestBytesToSkip(ThisBytes, Index)); 1565fe6060f1SDimitry Andric Index += Size; 1566fe6060f1SDimitry Andric } 1567fe6060f1SDimitry Andric ArrayRef<uint64_t> LabelAddrsRef = SymbolizerPtr->getReferencedAddresses(); 1568fe6060f1SDimitry Andric // Copy and sort to remove duplicates. 1569fe6060f1SDimitry Andric std::vector<uint64_t> LabelAddrs; 1570fe6060f1SDimitry Andric LabelAddrs.insert(LabelAddrs.end(), LabelAddrsRef.begin(), 1571fe6060f1SDimitry Andric LabelAddrsRef.end()); 1572fe6060f1SDimitry Andric llvm::sort(LabelAddrs); 1573*0fca6ea1SDimitry Andric LabelAddrs.resize(llvm::unique(LabelAddrs) - LabelAddrs.begin()); 1574fe6060f1SDimitry Andric // Add the labels. 1575fe6060f1SDimitry Andric for (unsigned LabelNum = 0; LabelNum != LabelAddrs.size(); ++LabelNum) { 1576fe6060f1SDimitry Andric auto Name = std::make_unique<std::string>(); 1577fe6060f1SDimitry Andric *Name = (Twine("L") + Twine(LabelNum)).str(); 1578fe6060f1SDimitry Andric SynthesizedLabelNames.push_back(std::move(Name)); 1579fe6060f1SDimitry Andric Symbols.push_back(SymbolInfoTy( 1580fe6060f1SDimitry Andric LabelAddrs[LabelNum], *SynthesizedLabelNames.back(), ELF::STT_NOTYPE)); 1581fe6060f1SDimitry Andric } 1582fe6060f1SDimitry Andric llvm::stable_sort(Symbols); 1583fe6060f1SDimitry Andric // Recreate the symbolizer with the new symbols list. 1584fe6060f1SDimitry Andric RelInfo.reset(Target->createMCRelocationInfo(TripleName, Ctx)); 1585fe6060f1SDimitry Andric Symbolizer.reset(Target->createMCSymbolizer( 1586fe6060f1SDimitry Andric TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo))); 1587fe6060f1SDimitry Andric DisAsm->setSymbolizer(std::move(Symbolizer)); 1588fe6060f1SDimitry Andric } 1589fe6060f1SDimitry Andric 1590e8d8bef9SDimitry Andric static StringRef getSegmentName(const MachOObjectFile *MachO, 1591e8d8bef9SDimitry Andric const SectionRef &Section) { 1592e8d8bef9SDimitry Andric if (MachO) { 1593e8d8bef9SDimitry Andric DataRefImpl DR = Section.getRawDataRefImpl(); 1594e8d8bef9SDimitry Andric StringRef SegmentName = MachO->getSectionFinalSegmentName(DR); 1595e8d8bef9SDimitry Andric return SegmentName; 1596e8d8bef9SDimitry Andric } 1597e8d8bef9SDimitry Andric return ""; 1598e8d8bef9SDimitry Andric } 1599e8d8bef9SDimitry Andric 1600fe6060f1SDimitry Andric static void emitPostInstructionInfo(formatted_raw_ostream &FOS, 1601fe6060f1SDimitry Andric const MCAsmInfo &MAI, 1602fe6060f1SDimitry Andric const MCSubtargetInfo &STI, 1603fe6060f1SDimitry Andric StringRef Comments, 1604fe6060f1SDimitry Andric LiveVariablePrinter &LVP) { 1605fe6060f1SDimitry Andric do { 1606fe6060f1SDimitry Andric if (!Comments.empty()) { 1607fe6060f1SDimitry Andric // Emit a line of comments. 1608fe6060f1SDimitry Andric StringRef Comment; 1609fe6060f1SDimitry Andric std::tie(Comment, Comments) = Comments.split('\n'); 1610fe6060f1SDimitry Andric // MAI.getCommentColumn() assumes that instructions are printed at the 1611fe6060f1SDimitry Andric // position of 8, while getInstStartColumn() returns the actual position. 1612fe6060f1SDimitry Andric unsigned CommentColumn = 1613fe6060f1SDimitry Andric MAI.getCommentColumn() - 8 + getInstStartColumn(STI); 1614fe6060f1SDimitry Andric FOS.PadToColumn(CommentColumn); 1615fe6060f1SDimitry Andric FOS << MAI.getCommentString() << ' ' << Comment; 1616fe6060f1SDimitry Andric } 1617fe6060f1SDimitry Andric LVP.printAfterInst(FOS); 1618fe6060f1SDimitry Andric FOS << '\n'; 1619fe6060f1SDimitry Andric } while (!Comments.empty()); 1620fe6060f1SDimitry Andric FOS.flush(); 1621fe6060f1SDimitry Andric } 1622fe6060f1SDimitry Andric 1623fcaf7f86SDimitry Andric static void createFakeELFSections(ObjectFile &Obj) { 1624fcaf7f86SDimitry Andric assert(Obj.isELF()); 1625fcaf7f86SDimitry Andric if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(&Obj)) 1626fcaf7f86SDimitry Andric Elf32LEObj->createFakeSections(); 1627fcaf7f86SDimitry Andric else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(&Obj)) 1628fcaf7f86SDimitry Andric Elf64LEObj->createFakeSections(); 1629fcaf7f86SDimitry Andric else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(&Obj)) 1630fcaf7f86SDimitry Andric Elf32BEObj->createFakeSections(); 1631fcaf7f86SDimitry Andric else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(&Obj)) 1632fcaf7f86SDimitry Andric Elf64BEObj->createFakeSections(); 1633fcaf7f86SDimitry Andric else 1634fcaf7f86SDimitry Andric llvm_unreachable("Unsupported binary format"); 1635fcaf7f86SDimitry Andric } 1636fcaf7f86SDimitry Andric 1637bdd1243dSDimitry Andric // Tries to fetch a more complete version of the given object file using its 1638bdd1243dSDimitry Andric // Build ID. Returns std::nullopt if nothing was found. 1639bdd1243dSDimitry Andric static std::optional<OwningBinary<Binary>> 1640bdd1243dSDimitry Andric fetchBinaryByBuildID(const ObjectFile &Obj) { 164106c3fb27SDimitry Andric object::BuildIDRef BuildID = getBuildID(&Obj); 164206c3fb27SDimitry Andric if (BuildID.empty()) 1643bdd1243dSDimitry Andric return std::nullopt; 164406c3fb27SDimitry Andric std::optional<std::string> Path = BIDFetcher->fetch(BuildID); 1645bdd1243dSDimitry Andric if (!Path) 1646bdd1243dSDimitry Andric return std::nullopt; 1647bdd1243dSDimitry Andric Expected<OwningBinary<Binary>> DebugBinary = createBinary(*Path); 1648bdd1243dSDimitry Andric if (!DebugBinary) { 1649bdd1243dSDimitry Andric reportWarning(toString(DebugBinary.takeError()), *Path); 1650bdd1243dSDimitry Andric return std::nullopt; 1651bdd1243dSDimitry Andric } 1652bdd1243dSDimitry Andric return std::move(*DebugBinary); 1653bdd1243dSDimitry Andric } 1654bdd1243dSDimitry Andric 16555f757f3fSDimitry Andric static void 16565f757f3fSDimitry Andric disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj, 16575f757f3fSDimitry Andric DisassemblerTarget &PrimaryTarget, 16585f757f3fSDimitry Andric std::optional<DisassemblerTarget> &SecondaryTarget, 16595f757f3fSDimitry Andric SourcePrinter &SP, bool InlineRelocs) { 16605f757f3fSDimitry Andric DisassemblerTarget *DT = &PrimaryTarget; 16610b57cec5SDimitry Andric bool PrimaryIsThumb = false; 16625f757f3fSDimitry Andric SmallVector<std::pair<uint64_t, uint64_t>, 0> CHPECodeMap; 16635f757f3fSDimitry Andric 16645f757f3fSDimitry Andric if (SecondaryTarget) { 16655f757f3fSDimitry Andric if (isArmElf(Obj)) { 16665f757f3fSDimitry Andric PrimaryIsThumb = 16675f757f3fSDimitry Andric PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode"); 16685f757f3fSDimitry Andric } else if (const auto *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) { 16695f757f3fSDimitry Andric const chpe_metadata *CHPEMetadata = COFFObj->getCHPEMetadata(); 16705f757f3fSDimitry Andric if (CHPEMetadata && CHPEMetadata->CodeMapCount) { 16715f757f3fSDimitry Andric uintptr_t CodeMapInt; 16725f757f3fSDimitry Andric cantFail(COFFObj->getRvaPtr(CHPEMetadata->CodeMap, CodeMapInt)); 16735f757f3fSDimitry Andric auto CodeMap = reinterpret_cast<const chpe_range_entry *>(CodeMapInt); 16745f757f3fSDimitry Andric 16755f757f3fSDimitry Andric for (uint32_t i = 0; i < CHPEMetadata->CodeMapCount; ++i) { 16765f757f3fSDimitry Andric if (CodeMap[i].getType() == chpe_range_type::Amd64 && 16775f757f3fSDimitry Andric CodeMap[i].Length) { 16785f757f3fSDimitry Andric // Store x86_64 CHPE code ranges. 16795f757f3fSDimitry Andric uint64_t Start = CodeMap[i].getStart() + COFFObj->getImageBase(); 16805f757f3fSDimitry Andric CHPECodeMap.emplace_back(Start, Start + CodeMap[i].Length); 16815f757f3fSDimitry Andric } 16825f757f3fSDimitry Andric } 16835f757f3fSDimitry Andric llvm::sort(CHPECodeMap); 16845f757f3fSDimitry Andric } 16855f757f3fSDimitry Andric } 16865f757f3fSDimitry Andric } 16870b57cec5SDimitry Andric 16880b57cec5SDimitry Andric std::map<SectionRef, std::vector<RelocationRef>> RelocMap; 1689cb14a3feSDimitry Andric if (InlineRelocs || Obj.isXCOFF()) 1690753f127fSDimitry Andric RelocMap = getRelocsMap(Obj); 1691753f127fSDimitry Andric bool Is64Bits = Obj.getBytesInAddress() > 4; 16920b57cec5SDimitry Andric 16930b57cec5SDimitry Andric // Create a mapping from virtual address to symbol name. This is used to 16940b57cec5SDimitry Andric // pretty print the symbols while disassembling. 16950b57cec5SDimitry Andric std::map<SectionRef, SectionSymbolsTy> AllSymbols; 16965f757f3fSDimitry Andric std::map<SectionRef, SmallVector<MappingSymbolPair, 0>> AllMappingSymbols; 16970b57cec5SDimitry Andric SectionSymbolsTy AbsoluteSymbols; 1698753f127fSDimitry Andric const StringRef FileName = Obj.getFileName(); 1699753f127fSDimitry Andric const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&Obj); 1700753f127fSDimitry Andric for (const SymbolRef &Symbol : Obj.symbols()) { 1701e8d8bef9SDimitry Andric Expected<StringRef> NameOrErr = Symbol.getName(); 1702e8d8bef9SDimitry Andric if (!NameOrErr) { 1703e8d8bef9SDimitry Andric reportWarning(toString(NameOrErr.takeError()), FileName); 1704e8d8bef9SDimitry Andric continue; 1705e8d8bef9SDimitry Andric } 1706753f127fSDimitry Andric if (NameOrErr->empty() && !(Obj.isXCOFF() && SymbolDescription)) 17070b57cec5SDimitry Andric continue; 17080b57cec5SDimitry Andric 17095f757f3fSDimitry Andric if (Obj.isELF() && 17105f757f3fSDimitry Andric (cantFail(Symbol.getFlags()) & SymbolRef::SF_FormatSpecific)) { 17115f757f3fSDimitry Andric // Symbol is intended not to be displayed by default (STT_FILE, 17125f757f3fSDimitry Andric // STT_SECTION, or a mapping symbol). Ignore STT_SECTION symbols. We will 17135f757f3fSDimitry Andric // synthesize a section symbol if no symbol is defined at offset 0. 17145f757f3fSDimitry Andric // 17155f757f3fSDimitry Andric // For a mapping symbol, store it within both AllSymbols and 17165f757f3fSDimitry Andric // AllMappingSymbols. If --show-all-symbols is unspecified, its label will 17175f757f3fSDimitry Andric // not be printed in disassembly listing. 17185f757f3fSDimitry Andric if (getElfSymbolType(Obj, Symbol) != ELF::STT_SECTION && 17195f757f3fSDimitry Andric hasMappingSymbols(Obj)) { 17205f757f3fSDimitry Andric section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 17215f757f3fSDimitry Andric if (SecI != Obj.section_end()) { 17225f757f3fSDimitry Andric uint64_t SectionAddr = SecI->getAddress(); 17235f757f3fSDimitry Andric uint64_t Address = cantFail(Symbol.getAddress()); 17245f757f3fSDimitry Andric StringRef Name = *NameOrErr; 17255f757f3fSDimitry Andric if (Name.consume_front("$") && Name.size() && 17265f757f3fSDimitry Andric strchr("adtx", Name[0])) { 17275f757f3fSDimitry Andric AllMappingSymbols[*SecI].emplace_back(Address - SectionAddr, 17285f757f3fSDimitry Andric Name[0]); 17295f757f3fSDimitry Andric AllSymbols[*SecI].push_back( 17305f757f3fSDimitry Andric createSymbolInfo(Obj, Symbol, /*MappingSymbol=*/true)); 17315f757f3fSDimitry Andric } 17325f757f3fSDimitry Andric } 17335f757f3fSDimitry Andric } 17340b57cec5SDimitry Andric continue; 17355f757f3fSDimitry Andric } 17360b57cec5SDimitry Andric 1737fe6060f1SDimitry Andric if (MachO) { 1738fe6060f1SDimitry Andric // __mh_(execute|dylib|dylinker|bundle|preload|object)_header are special 1739fe6060f1SDimitry Andric // symbols that support MachO header introspection. They do not bind to 1740fe6060f1SDimitry Andric // code locations and are irrelevant for disassembly. 17415f757f3fSDimitry Andric if (NameOrErr->starts_with("__mh_") && NameOrErr->ends_with("_header")) 1742fe6060f1SDimitry Andric continue; 1743480093f4SDimitry Andric // Don't ask a Mach-O STAB symbol for its section unless you know that 1744480093f4SDimitry Andric // STAB symbol's section field refers to a valid section index. Otherwise 1745480093f4SDimitry Andric // the symbol may error trying to load a section that does not exist. 1746480093f4SDimitry Andric DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); 1747480093f4SDimitry Andric uint8_t NType = (MachO->is64Bit() ? 1748480093f4SDimitry Andric MachO->getSymbol64TableEntry(SymDRI).n_type: 1749480093f4SDimitry Andric MachO->getSymbolTableEntry(SymDRI).n_type); 1750480093f4SDimitry Andric if (NType & MachO::N_STAB) 1751480093f4SDimitry Andric continue; 1752480093f4SDimitry Andric } 1753480093f4SDimitry Andric 17540b57cec5SDimitry Andric section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 1755753f127fSDimitry Andric if (SecI != Obj.section_end()) 17565ffd83dbSDimitry Andric AllSymbols[*SecI].push_back(createSymbolInfo(Obj, Symbol)); 17570b57cec5SDimitry Andric else 17585ffd83dbSDimitry Andric AbsoluteSymbols.push_back(createSymbolInfo(Obj, Symbol)); 17590b57cec5SDimitry Andric } 17605ffd83dbSDimitry Andric 1761753f127fSDimitry Andric if (AllSymbols.empty() && Obj.isELF()) 1762753f127fSDimitry Andric addDynamicElfSymbols(cast<ELFObjectFileBase>(Obj), AllSymbols); 17630b57cec5SDimitry Andric 1764753f127fSDimitry Andric if (Obj.isWasm()) 1765fe6060f1SDimitry Andric addMissingWasmCodeSymbols(cast<WasmObjectFile>(Obj), AllSymbols); 1766fe6060f1SDimitry Andric 1767fcaf7f86SDimitry Andric if (Obj.isELF() && Obj.sections().empty()) 1768fcaf7f86SDimitry Andric createFakeELFSections(Obj); 1769fcaf7f86SDimitry Andric 17700b57cec5SDimitry Andric BumpPtrAllocator A; 17710b57cec5SDimitry Andric StringSaver Saver(A); 17720b57cec5SDimitry Andric addPltEntries(Obj, AllSymbols, Saver); 17730b57cec5SDimitry Andric 17745ffd83dbSDimitry Andric // Create a mapping from virtual address to section. An empty section can 17755ffd83dbSDimitry Andric // cause more than one section at the same address. Sort such sections to be 17765ffd83dbSDimitry Andric // before same-addressed non-empty sections so that symbol lookups prefer the 17775ffd83dbSDimitry Andric // non-empty section. 17780b57cec5SDimitry Andric std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses; 1779753f127fSDimitry Andric for (SectionRef Sec : Obj.sections()) 17800b57cec5SDimitry Andric SectionAddresses.emplace_back(Sec.getAddress(), Sec); 17815ffd83dbSDimitry Andric llvm::stable_sort(SectionAddresses, [](const auto &LHS, const auto &RHS) { 17825ffd83dbSDimitry Andric if (LHS.first != RHS.first) 17835ffd83dbSDimitry Andric return LHS.first < RHS.first; 17845ffd83dbSDimitry Andric return LHS.second.getSize() < RHS.second.getSize(); 17855ffd83dbSDimitry Andric }); 17860b57cec5SDimitry Andric 17870b57cec5SDimitry Andric // Linked executables (.exe and .dll files) typically don't include a real 17880b57cec5SDimitry Andric // symbol table but they might contain an export table. 1789753f127fSDimitry Andric if (const auto *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) { 17900b57cec5SDimitry Andric for (const auto &ExportEntry : COFFObj->export_directories()) { 17910b57cec5SDimitry Andric StringRef Name; 17925ffd83dbSDimitry Andric if (Error E = ExportEntry.getSymbolName(Name)) 1793753f127fSDimitry Andric reportError(std::move(E), Obj.getFileName()); 17940b57cec5SDimitry Andric if (Name.empty()) 17950b57cec5SDimitry Andric continue; 17968bcb0991SDimitry Andric 17970b57cec5SDimitry Andric uint32_t RVA; 17985ffd83dbSDimitry Andric if (Error E = ExportEntry.getExportRVA(RVA)) 1799753f127fSDimitry Andric reportError(std::move(E), Obj.getFileName()); 18000b57cec5SDimitry Andric 18010b57cec5SDimitry Andric uint64_t VA = COFFObj->getImageBase() + RVA; 18020b57cec5SDimitry Andric auto Sec = partition_point( 18030b57cec5SDimitry Andric SectionAddresses, [VA](const std::pair<uint64_t, SectionRef> &O) { 18040b57cec5SDimitry Andric return O.first <= VA; 18050b57cec5SDimitry Andric }); 18060b57cec5SDimitry Andric if (Sec != SectionAddresses.begin()) { 18070b57cec5SDimitry Andric --Sec; 18080b57cec5SDimitry Andric AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE); 18090b57cec5SDimitry Andric } else 18100b57cec5SDimitry Andric AbsoluteSymbols.emplace_back(VA, Name, ELF::STT_NOTYPE); 18110b57cec5SDimitry Andric } 18120b57cec5SDimitry Andric } 18130b57cec5SDimitry Andric 18140b57cec5SDimitry Andric // Sort all the symbols, this allows us to use a simple binary search to find 18155ffd83dbSDimitry Andric // Multiple symbols can have the same address. Use a stable sort to stabilize 18165ffd83dbSDimitry Andric // the output. 18175ffd83dbSDimitry Andric StringSet<> FoundDisasmSymbolSet; 18180b57cec5SDimitry Andric for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 1819e8d8bef9SDimitry Andric llvm::stable_sort(SecSyms.second); 1820e8d8bef9SDimitry Andric llvm::stable_sort(AbsoluteSymbols); 18215ffd83dbSDimitry Andric 18225ffd83dbSDimitry Andric std::unique_ptr<DWARFContext> DICtx; 18235f757f3fSDimitry Andric LiveVariablePrinter LVP(*DT->Context->getRegisterInfo(), *DT->SubtargetInfo); 18245ffd83dbSDimitry Andric 18255ffd83dbSDimitry Andric if (DbgVariables != DVDisabled) { 1826bdd1243dSDimitry Andric DICtx = DWARFContext::create(DbgObj); 18275ffd83dbSDimitry Andric for (const std::unique_ptr<DWARFUnit> &CU : DICtx->compile_units()) 18285ffd83dbSDimitry Andric LVP.addCompileUnit(CU->getUnitDIE(false)); 18295ffd83dbSDimitry Andric } 18305ffd83dbSDimitry Andric 18315ffd83dbSDimitry Andric LLVM_DEBUG(LVP.dump()); 18320b57cec5SDimitry Andric 1833*0fca6ea1SDimitry Andric BBAddrMapInfo FullAddrMap; 1834bdd1243dSDimitry Andric auto ReadBBAddrMap = [&](std::optional<unsigned> SectionIndex = 1835bdd1243dSDimitry Andric std::nullopt) { 1836*0fca6ea1SDimitry Andric FullAddrMap.clear(); 1837fcaf7f86SDimitry Andric if (const auto *Elf = dyn_cast<ELFObjectFileBase>(&Obj)) { 18387a6dacacSDimitry Andric std::vector<PGOAnalysisMap> PGOAnalyses; 18397a6dacacSDimitry Andric auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex, &PGOAnalyses); 184006c3fb27SDimitry Andric if (!BBAddrMapsOrErr) { 1841bdd1243dSDimitry Andric reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName()); 184206c3fb27SDimitry Andric return; 184306c3fb27SDimitry Andric } 1844*0fca6ea1SDimitry Andric for (auto &&[FunctionBBAddrMap, FunctionPGOAnalysis] : 18457a6dacacSDimitry Andric zip_equal(*std::move(BBAddrMapsOrErr), std::move(PGOAnalyses))) { 1846*0fca6ea1SDimitry Andric FullAddrMap.AddFunctionEntry(std::move(FunctionBBAddrMap), 1847*0fca6ea1SDimitry Andric std::move(FunctionPGOAnalysis)); 18487a6dacacSDimitry Andric } 1849fcaf7f86SDimitry Andric } 1850fcaf7f86SDimitry Andric }; 1851fcaf7f86SDimitry Andric 1852fcaf7f86SDimitry Andric // For non-relocatable objects, Read all LLVM_BB_ADDR_MAP sections into a 1853fcaf7f86SDimitry Andric // single mapping, since they don't have any conflicts. 1854fcaf7f86SDimitry Andric if (SymbolizeOperands && !Obj.isRelocatableObject()) 1855fcaf7f86SDimitry Andric ReadBBAddrMap(); 1856fcaf7f86SDimitry Andric 18575f757f3fSDimitry Andric std::optional<llvm::BTFParser> BTF; 18585f757f3fSDimitry Andric if (InlineRelocs && BTFParser::hasBTFSections(Obj)) { 18595f757f3fSDimitry Andric BTF.emplace(); 18605f757f3fSDimitry Andric BTFParser::ParseOptions Opts = {}; 18615f757f3fSDimitry Andric Opts.LoadTypes = true; 18625f757f3fSDimitry Andric Opts.LoadRelocs = true; 18635f757f3fSDimitry Andric if (Error E = BTF->parse(Obj, Opts)) 18645f757f3fSDimitry Andric WithColor::defaultErrorHandler(std::move(E)); 18655f757f3fSDimitry Andric } 18665f757f3fSDimitry Andric 1867753f127fSDimitry Andric for (const SectionRef &Section : ToolSectionFilter(Obj)) { 18680b57cec5SDimitry Andric if (FilterSections.empty() && !DisassembleAll && 18690b57cec5SDimitry Andric (!Section.isText() || Section.isVirtual())) 18700b57cec5SDimitry Andric continue; 18710b57cec5SDimitry Andric 18720b57cec5SDimitry Andric uint64_t SectionAddr = Section.getAddress(); 18730b57cec5SDimitry Andric uint64_t SectSize = Section.getSize(); 18740b57cec5SDimitry Andric if (!SectSize) 18750b57cec5SDimitry Andric continue; 18760b57cec5SDimitry Andric 1877fcaf7f86SDimitry Andric // For relocatable object files, read the LLVM_BB_ADDR_MAP section 1878fcaf7f86SDimitry Andric // corresponding to this section, if present. 1879fcaf7f86SDimitry Andric if (SymbolizeOperands && Obj.isRelocatableObject()) 1880fcaf7f86SDimitry Andric ReadBBAddrMap(Section.getIndex()); 188181ad6265SDimitry Andric 18820b57cec5SDimitry Andric // Get the list of all the symbols in this section. 18830b57cec5SDimitry Andric SectionSymbolsTy &Symbols = AllSymbols[Section]; 18845f757f3fSDimitry Andric auto &MappingSymbols = AllMappingSymbols[Section]; 18850b57cec5SDimitry Andric llvm::sort(MappingSymbols); 18860b57cec5SDimitry Andric 1887fe6060f1SDimitry Andric ArrayRef<uint8_t> Bytes = arrayRefFromStringRef( 1888753f127fSDimitry Andric unwrapOrError(Section.getContents(), Obj.getFileName())); 1889fe6060f1SDimitry Andric 1890fe6060f1SDimitry Andric std::vector<std::unique_ptr<std::string>> SynthesizedLabelNames; 1891753f127fSDimitry Andric if (Obj.isELF() && Obj.getArch() == Triple::amdgcn) { 18920b57cec5SDimitry Andric // AMDGPU disassembler uses symbolizer for printing labels 18935f757f3fSDimitry Andric addSymbolizer(*DT->Context, DT->TheTarget, TripleName, DT->DisAsm.get(), 18945f757f3fSDimitry Andric SectionAddr, Bytes, Symbols, SynthesizedLabelNames); 18950b57cec5SDimitry Andric } 18960b57cec5SDimitry Andric 1897e8d8bef9SDimitry Andric StringRef SegmentName = getSegmentName(MachO, Section); 1898753f127fSDimitry Andric StringRef SectionName = unwrapOrError(Section.getName(), Obj.getFileName()); 18990b57cec5SDimitry Andric // If the section has no symbol at the start, just insert a dummy one. 19005f757f3fSDimitry Andric // Without --show-all-symbols, also insert one if all symbols at the start 19015f757f3fSDimitry Andric // are mapping symbols. 19025f757f3fSDimitry Andric bool CreateDummy = Symbols.empty(); 19035f757f3fSDimitry Andric if (!CreateDummy) { 19045f757f3fSDimitry Andric CreateDummy = true; 19055f757f3fSDimitry Andric for (auto &Sym : Symbols) { 19065f757f3fSDimitry Andric if (Sym.Addr != SectionAddr) 19075f757f3fSDimitry Andric break; 19085f757f3fSDimitry Andric if (!Sym.IsMappingSymbol || ShowAllSymbols) 19095f757f3fSDimitry Andric CreateDummy = false; 19105f757f3fSDimitry Andric } 19115f757f3fSDimitry Andric } 19125f757f3fSDimitry Andric if (CreateDummy) { 19135f757f3fSDimitry Andric SymbolInfoTy Sym = createDummySymbolInfo( 19145f757f3fSDimitry Andric Obj, SectionAddr, SectionName, 19155f757f3fSDimitry Andric Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT); 19165f757f3fSDimitry Andric if (Obj.isXCOFF()) 19175f757f3fSDimitry Andric Symbols.insert(Symbols.begin(), Sym); 19185f757f3fSDimitry Andric else 19195f757f3fSDimitry Andric Symbols.insert(llvm::lower_bound(Symbols, Sym), Sym); 19200b57cec5SDimitry Andric } 19210b57cec5SDimitry Andric 19220b57cec5SDimitry Andric SmallString<40> Comments; 19230b57cec5SDimitry Andric raw_svector_ostream CommentStream(Comments); 19240b57cec5SDimitry Andric 19250b57cec5SDimitry Andric uint64_t VMAAdjustment = 0; 19260b57cec5SDimitry Andric if (shouldAdjustVA(Section)) 19270b57cec5SDimitry Andric VMAAdjustment = AdjustVMA; 19280b57cec5SDimitry Andric 192969ade1e0SDimitry Andric // In executable and shared objects, r_offset holds a virtual address. 193069ade1e0SDimitry Andric // Subtract SectionAddr from the r_offset field of a relocation to get 193169ade1e0SDimitry Andric // the section offset. 1932753f127fSDimitry Andric uint64_t RelAdjustment = Obj.isRelocatableObject() ? 0 : SectionAddr; 19330b57cec5SDimitry Andric uint64_t Size; 19340b57cec5SDimitry Andric uint64_t Index; 19350b57cec5SDimitry Andric bool PrintedSection = false; 19360b57cec5SDimitry Andric std::vector<RelocationRef> Rels = RelocMap[Section]; 19370b57cec5SDimitry Andric std::vector<RelocationRef>::const_iterator RelCur = Rels.begin(); 19380b57cec5SDimitry Andric std::vector<RelocationRef>::const_iterator RelEnd = Rels.end(); 19390b57cec5SDimitry Andric 1940bdd1243dSDimitry Andric // Loop over each chunk of code between two points where at least 1941bdd1243dSDimitry Andric // one symbol is defined. 1942bdd1243dSDimitry Andric for (size_t SI = 0, SE = Symbols.size(); SI != SE;) { 1943bdd1243dSDimitry Andric // Advance SI past all the symbols starting at the same address, 1944bdd1243dSDimitry Andric // and make an ArrayRef of them. 1945bdd1243dSDimitry Andric unsigned FirstSI = SI; 19465ffd83dbSDimitry Andric uint64_t Start = Symbols[SI].Addr; 1947bdd1243dSDimitry Andric ArrayRef<SymbolInfoTy> SymbolsHere; 1948bdd1243dSDimitry Andric while (SI != SE && Symbols[SI].Addr == Start) 1949bdd1243dSDimitry Andric ++SI; 1950bdd1243dSDimitry Andric SymbolsHere = ArrayRef<SymbolInfoTy>(&Symbols[FirstSI], SI - FirstSI); 1951bdd1243dSDimitry Andric 1952bdd1243dSDimitry Andric // Get the demangled names of all those symbols. We end up with a vector 1953bdd1243dSDimitry Andric // of StringRef that holds the names we're going to use, and a vector of 1954bdd1243dSDimitry Andric // std::string that stores the new strings returned by demangle(), if 1955bdd1243dSDimitry Andric // any. If we don't call demangle() then that vector can stay empty. 1956bdd1243dSDimitry Andric std::vector<StringRef> SymNamesHere; 1957bdd1243dSDimitry Andric std::vector<std::string> DemangledSymNamesHere; 1958bdd1243dSDimitry Andric if (Demangle) { 1959bdd1243dSDimitry Andric // Fetch the demangled names and store them locally. 1960bdd1243dSDimitry Andric for (const SymbolInfoTy &Symbol : SymbolsHere) 196106c3fb27SDimitry Andric DemangledSymNamesHere.push_back(demangle(Symbol.Name)); 1962bdd1243dSDimitry Andric // Now we've finished modifying that vector, it's safe to make 1963bdd1243dSDimitry Andric // a vector of StringRefs pointing into it. 1964bdd1243dSDimitry Andric SymNamesHere.insert(SymNamesHere.begin(), DemangledSymNamesHere.begin(), 1965bdd1243dSDimitry Andric DemangledSymNamesHere.end()); 1966bdd1243dSDimitry Andric } else { 1967bdd1243dSDimitry Andric for (const SymbolInfoTy &Symbol : SymbolsHere) 1968bdd1243dSDimitry Andric SymNamesHere.push_back(Symbol.Name); 1969bdd1243dSDimitry Andric } 1970bdd1243dSDimitry Andric 1971bdd1243dSDimitry Andric // Distinguish ELF data from code symbols, which will be used later on to 1972bdd1243dSDimitry Andric // decide whether to 'disassemble' this chunk as a data declaration via 1973bdd1243dSDimitry Andric // dumpELFData(), or whether to treat it as code. 1974bdd1243dSDimitry Andric // 1975bdd1243dSDimitry Andric // If data _and_ code symbols are defined at the same address, the code 1976bdd1243dSDimitry Andric // takes priority, on the grounds that disassembling code is our main 1977bdd1243dSDimitry Andric // purpose here, and it would be a worse failure to _not_ interpret 1978bdd1243dSDimitry Andric // something that _was_ meaningful as code than vice versa. 1979bdd1243dSDimitry Andric // 1980bdd1243dSDimitry Andric // Any ELF symbol type that is not clearly data will be regarded as code. 1981bdd1243dSDimitry Andric // In particular, one of the uses of STT_NOTYPE is for branch targets 1982bdd1243dSDimitry Andric // inside functions, for which STT_FUNC would be inaccurate. 1983bdd1243dSDimitry Andric // 1984bdd1243dSDimitry Andric // So here, we spot whether there's any non-data symbol present at all, 19855f757f3fSDimitry Andric // and only set the DisassembleAsELFData flag if there isn't. Also, we use 1986bdd1243dSDimitry Andric // this distinction to inform the decision of which symbol to print at 1987bdd1243dSDimitry Andric // the head of the section, so that if we're printing code, we print a 1988bdd1243dSDimitry Andric // code-related symbol name to go with it. 19895f757f3fSDimitry Andric bool DisassembleAsELFData = false; 1990bdd1243dSDimitry Andric size_t DisplaySymIndex = SymbolsHere.size() - 1; 1991bdd1243dSDimitry Andric if (Obj.isELF() && !DisassembleAll && Section.isText()) { 19925f757f3fSDimitry Andric DisassembleAsELFData = true; // unless we find a code symbol below 1993bdd1243dSDimitry Andric 1994bdd1243dSDimitry Andric for (size_t i = 0; i < SymbolsHere.size(); ++i) { 1995bdd1243dSDimitry Andric uint8_t SymTy = SymbolsHere[i].Type; 1996bdd1243dSDimitry Andric if (SymTy != ELF::STT_OBJECT && SymTy != ELF::STT_COMMON) { 19975f757f3fSDimitry Andric DisassembleAsELFData = false; 1998bdd1243dSDimitry Andric DisplaySymIndex = i; 1999bdd1243dSDimitry Andric } 2000bdd1243dSDimitry Andric } 2001bdd1243dSDimitry Andric } 2002bdd1243dSDimitry Andric 2003bdd1243dSDimitry Andric // Decide which symbol(s) from this collection we're going to print. 2004bdd1243dSDimitry Andric std::vector<bool> SymsToPrint(SymbolsHere.size(), false); 2005bdd1243dSDimitry Andric // If the user has given the --disassemble-symbols option, then we must 2006bdd1243dSDimitry Andric // display every symbol in that set, and no others. 2007bdd1243dSDimitry Andric if (!DisasmSymbolSet.empty()) { 2008bdd1243dSDimitry Andric bool FoundAny = false; 2009bdd1243dSDimitry Andric for (size_t i = 0; i < SymbolsHere.size(); ++i) { 2010bdd1243dSDimitry Andric if (DisasmSymbolSet.count(SymNamesHere[i])) { 2011bdd1243dSDimitry Andric SymsToPrint[i] = true; 2012bdd1243dSDimitry Andric FoundAny = true; 2013bdd1243dSDimitry Andric } 2014bdd1243dSDimitry Andric } 2015bdd1243dSDimitry Andric 2016bdd1243dSDimitry Andric // And if none of the symbols here is one that the user asked for, skip 2017bdd1243dSDimitry Andric // disassembling this entire chunk of code. 2018bdd1243dSDimitry Andric if (!FoundAny) 2019bdd1243dSDimitry Andric continue; 20205f757f3fSDimitry Andric } else if (!SymbolsHere[DisplaySymIndex].IsMappingSymbol) { 2021bdd1243dSDimitry Andric // Otherwise, print whichever symbol at this location is last in the 2022bdd1243dSDimitry Andric // Symbols array, because that array is pre-sorted in a way intended to 2023bdd1243dSDimitry Andric // correlate with priority of which symbol to display. 2024bdd1243dSDimitry Andric SymsToPrint[DisplaySymIndex] = true; 2025bdd1243dSDimitry Andric } 2026bdd1243dSDimitry Andric 2027bdd1243dSDimitry Andric // Now that we know we're disassembling this section, override the choice 2028bdd1243dSDimitry Andric // of which symbols to display by printing _all_ of them at this address 2029bdd1243dSDimitry Andric // if the user asked for all symbols. 2030bdd1243dSDimitry Andric // 2031bdd1243dSDimitry Andric // That way, '--show-all-symbols --disassemble-symbol=foo' will print 2032bdd1243dSDimitry Andric // only the chunk of code headed by 'foo', but also show any other 2033bdd1243dSDimitry Andric // symbols defined at that address, such as aliases for 'foo', or the ARM 2034bdd1243dSDimitry Andric // mapping symbol preceding its code. 2035bdd1243dSDimitry Andric if (ShowAllSymbols) { 2036bdd1243dSDimitry Andric for (size_t i = 0; i < SymbolsHere.size(); ++i) 2037bdd1243dSDimitry Andric SymsToPrint[i] = true; 2038bdd1243dSDimitry Andric } 2039bdd1243dSDimitry Andric 20400b57cec5SDimitry Andric if (Start < SectionAddr || StopAddress <= Start) 20410b57cec5SDimitry Andric continue; 2042bdd1243dSDimitry Andric 2043bdd1243dSDimitry Andric for (size_t i = 0; i < SymbolsHere.size(); ++i) 2044bdd1243dSDimitry Andric FoundDisasmSymbolSet.insert(SymNamesHere[i]); 20450b57cec5SDimitry Andric 20460b57cec5SDimitry Andric // The end is the section end, the beginning of the next symbol, or 20470b57cec5SDimitry Andric // --stop-address. 20480b57cec5SDimitry Andric uint64_t End = std::min<uint64_t>(SectionAddr + SectSize, StopAddress); 2049bdd1243dSDimitry Andric if (SI < SE) 2050bdd1243dSDimitry Andric End = std::min(End, Symbols[SI].Addr); 20510b57cec5SDimitry Andric if (Start >= End || End <= StartAddress) 20520b57cec5SDimitry Andric continue; 20530b57cec5SDimitry Andric Start -= SectionAddr; 20540b57cec5SDimitry Andric End -= SectionAddr; 20550b57cec5SDimitry Andric 20560b57cec5SDimitry Andric if (!PrintedSection) { 20570b57cec5SDimitry Andric PrintedSection = true; 20580b57cec5SDimitry Andric outs() << "\nDisassembly of section "; 20590b57cec5SDimitry Andric if (!SegmentName.empty()) 20600b57cec5SDimitry Andric outs() << SegmentName << ","; 20610b57cec5SDimitry Andric outs() << SectionName << ":\n"; 20620b57cec5SDimitry Andric } 20630b57cec5SDimitry Andric 20645f757f3fSDimitry Andric bool PrintedLabel = false; 2065bdd1243dSDimitry Andric for (size_t i = 0; i < SymbolsHere.size(); ++i) { 2066bdd1243dSDimitry Andric if (!SymsToPrint[i]) 2067bdd1243dSDimitry Andric continue; 2068bdd1243dSDimitry Andric 2069bdd1243dSDimitry Andric const SymbolInfoTy &Symbol = SymbolsHere[i]; 2070bdd1243dSDimitry Andric const StringRef SymbolName = SymNamesHere[i]; 2071bdd1243dSDimitry Andric 20725f757f3fSDimitry Andric if (!PrintedLabel) { 20735f757f3fSDimitry Andric outs() << '\n'; 20745f757f3fSDimitry Andric PrintedLabel = true; 20755f757f3fSDimitry Andric } 2076fe6060f1SDimitry Andric if (LeadingAddr) 20770b57cec5SDimitry Andric outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ", 20780b57cec5SDimitry Andric SectionAddr + Start + VMAAdjustment); 2079753f127fSDimitry Andric if (Obj.isXCOFF() && SymbolDescription) { 2080bdd1243dSDimitry Andric outs() << getXCOFFSymbolDescription(Symbol, SymbolName) << ":\n"; 20815ffd83dbSDimitry Andric } else 20825ffd83dbSDimitry Andric outs() << '<' << SymbolName << ">:\n"; 2083bdd1243dSDimitry Andric } 20840b57cec5SDimitry Andric 20850b57cec5SDimitry Andric // Don't print raw contents of a virtual section. A virtual section 20860b57cec5SDimitry Andric // doesn't have any contents in the file. 20870b57cec5SDimitry Andric if (Section.isVirtual()) { 20880b57cec5SDimitry Andric outs() << "...\n"; 20890b57cec5SDimitry Andric continue; 20900b57cec5SDimitry Andric } 20910b57cec5SDimitry Andric 2092bdd1243dSDimitry Andric // See if any of the symbols defined at this location triggers target- 2093bdd1243dSDimitry Andric // specific disassembly behavior, e.g. of special descriptors or function 2094bdd1243dSDimitry Andric // prelude information. 2095bdd1243dSDimitry Andric // 2096bdd1243dSDimitry Andric // We stop this loop at the first symbol that triggers some kind of 2097bdd1243dSDimitry Andric // interesting behavior (if any), on the assumption that if two symbols 2098bdd1243dSDimitry Andric // defined at the same address trigger two conflicting symbol handlers, 2099bdd1243dSDimitry Andric // the object file is probably confused anyway, and it would make even 2100bdd1243dSDimitry Andric // less sense to present the output of _both_ handlers, because that 2101bdd1243dSDimitry Andric // would describe the same data twice. 2102bdd1243dSDimitry Andric for (size_t SHI = 0; SHI < SymbolsHere.size(); ++SHI) { 2103bdd1243dSDimitry Andric SymbolInfoTy Symbol = SymbolsHere[SHI]; 2104bdd1243dSDimitry Andric 2105*0fca6ea1SDimitry Andric Expected<bool> RespondedOrErr = DT->DisAsm->onSymbolStart( 2106*0fca6ea1SDimitry Andric Symbol, Size, Bytes.slice(Start, End - Start), SectionAddr + Start); 2107bdd1243dSDimitry Andric 2108*0fca6ea1SDimitry Andric if (RespondedOrErr && !*RespondedOrErr) { 2109*0fca6ea1SDimitry Andric // This symbol didn't trigger any interesting handling. Try the other 2110*0fca6ea1SDimitry Andric // symbols defined at this address. 2111bdd1243dSDimitry Andric continue; 2112bdd1243dSDimitry Andric } 2113bdd1243dSDimitry Andric 2114*0fca6ea1SDimitry Andric // If onSymbolStart returned an Error, that means it identified some 2115*0fca6ea1SDimitry Andric // kind of special data at this address, but wasn't able to disassemble 2116*0fca6ea1SDimitry Andric // it meaningfully. So we fall back to printing the error out and 2117*0fca6ea1SDimitry Andric // disassembling the failed region as bytes, assuming that the target 2118*0fca6ea1SDimitry Andric // detected the failure before printing anything. 2119*0fca6ea1SDimitry Andric if (!RespondedOrErr) { 2120*0fca6ea1SDimitry Andric std::string ErrMsgStr = toString(RespondedOrErr.takeError()); 2121*0fca6ea1SDimitry Andric StringRef ErrMsg = ErrMsgStr; 2122*0fca6ea1SDimitry Andric do { 2123*0fca6ea1SDimitry Andric StringRef Line; 2124*0fca6ea1SDimitry Andric std::tie(Line, ErrMsg) = ErrMsg.split('\n'); 21255f757f3fSDimitry Andric outs() << DT->Context->getAsmInfo()->getCommentString() 2126*0fca6ea1SDimitry Andric << " error decoding " << SymNamesHere[SHI] << ": " << Line 2127*0fca6ea1SDimitry Andric << '\n'; 2128*0fca6ea1SDimitry Andric } while (!ErrMsg.empty()); 2129*0fca6ea1SDimitry Andric 2130*0fca6ea1SDimitry Andric if (Size) { 2131*0fca6ea1SDimitry Andric outs() << DT->Context->getAsmInfo()->getCommentString() 2132*0fca6ea1SDimitry Andric << " decoding failed region as bytes\n"; 2133*0fca6ea1SDimitry Andric for (uint64_t I = 0; I < Size; ++I) 21345ffd83dbSDimitry Andric outs() << "\t.byte\t " << format_hex(Bytes[I], 1, /*Upper=*/true) 2135*0fca6ea1SDimitry Andric << '\n'; 21365ffd83dbSDimitry Andric } 21375ffd83dbSDimitry Andric } 2138*0fca6ea1SDimitry Andric 2139*0fca6ea1SDimitry Andric // Regardless of whether onSymbolStart returned an Error or true, 'Size' 2140*0fca6ea1SDimitry Andric // will have been set to the amount of data covered by whatever prologue 2141*0fca6ea1SDimitry Andric // the target identified. So we advance our own position to beyond that. 2142*0fca6ea1SDimitry Andric // Sometimes that will be the entire distance to the next symbol, and 2143*0fca6ea1SDimitry Andric // sometimes it will be just a prologue and we should start 2144*0fca6ea1SDimitry Andric // disassembling instructions from where it left off. 21450b57cec5SDimitry Andric Start += Size; 2146bdd1243dSDimitry Andric break; 2147bdd1243dSDimitry Andric } 21480b57cec5SDimitry Andric 21490b57cec5SDimitry Andric Index = Start; 21500b57cec5SDimitry Andric if (SectionAddr < StartAddress) 21510b57cec5SDimitry Andric Index = std::max<uint64_t>(Index, StartAddress - SectionAddr); 21520b57cec5SDimitry Andric 21535f757f3fSDimitry Andric if (DisassembleAsELFData) { 21540b57cec5SDimitry Andric dumpELFData(SectionAddr, Index, End, Bytes); 21550b57cec5SDimitry Andric Index = End; 2156bdd1243dSDimitry Andric continue; 21570b57cec5SDimitry Andric } 21580b57cec5SDimitry Andric 2159cb14a3feSDimitry Andric // Skip relocations from symbols that are not dumped. 2160cb14a3feSDimitry Andric for (; RelCur != RelEnd; ++RelCur) { 2161cb14a3feSDimitry Andric uint64_t Offset = RelCur->getOffset() - RelAdjustment; 2162cb14a3feSDimitry Andric if (Index <= Offset) 2163cb14a3feSDimitry Andric break; 2164cb14a3feSDimitry Andric } 2165cb14a3feSDimitry Andric 21665ffd83dbSDimitry Andric bool DumpARMELFData = false; 216706c3fb27SDimitry Andric bool DumpTracebackTableForXCOFFFunction = 216806c3fb27SDimitry Andric Obj.isXCOFF() && Section.isText() && TracebackTable && 216906c3fb27SDimitry Andric Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass && 217006c3fb27SDimitry Andric (*Symbols[SI - 1].XCOFFSymInfo.StorageMappingClass == XCOFF::XMC_PR); 217106c3fb27SDimitry Andric 21725ffd83dbSDimitry Andric formatted_raw_ostream FOS(outs()); 2173e8d8bef9SDimitry Andric 2174e8d8bef9SDimitry Andric std::unordered_map<uint64_t, std::string> AllLabels; 21757a6dacacSDimitry Andric std::unordered_map<uint64_t, std::vector<BBAddrMapLabel>> BBAddrMapLabels; 217681ad6265SDimitry Andric if (SymbolizeOperands) { 21775f757f3fSDimitry Andric collectLocalBranchTargets(Bytes, DT->InstrAnalysis.get(), 21785f757f3fSDimitry Andric DT->DisAsm.get(), DT->InstPrinter.get(), 21795f757f3fSDimitry Andric PrimaryTarget.SubtargetInfo.get(), 2180e8d8bef9SDimitry Andric SectionAddr, Index, End, AllLabels); 2181*0fca6ea1SDimitry Andric collectBBAddrMapLabels(FullAddrMap, SectionAddr, Index, End, 2182*0fca6ea1SDimitry Andric BBAddrMapLabels); 218381ad6265SDimitry Andric } 2184e8d8bef9SDimitry Andric 21855f757f3fSDimitry Andric if (DT->InstrAnalysis) 21865f757f3fSDimitry Andric DT->InstrAnalysis->resetState(); 21875f757f3fSDimitry Andric 21880b57cec5SDimitry Andric while (Index < End) { 2189cb14a3feSDimitry Andric uint64_t RelOffset; 2190cb14a3feSDimitry Andric 21910b57cec5SDimitry Andric // ARM and AArch64 ELF binaries can interleave data and text in the 21920b57cec5SDimitry Andric // same section. We rely on the markers introduced to understand what 21930b57cec5SDimitry Andric // we need to dump. If the data marker is within a function, it is 21940b57cec5SDimitry Andric // denoted as a word/short etc. 2195bdd1243dSDimitry Andric if (!MappingSymbols.empty()) { 21965ffd83dbSDimitry Andric char Kind = getMappingSymbolKind(MappingSymbols, Index); 21975ffd83dbSDimitry Andric DumpARMELFData = Kind == 'd'; 21985f757f3fSDimitry Andric if (SecondaryTarget) { 21995ffd83dbSDimitry Andric if (Kind == 'a') { 22005f757f3fSDimitry Andric DT = PrimaryIsThumb ? &*SecondaryTarget : &PrimaryTarget; 22015ffd83dbSDimitry Andric } else if (Kind == 't') { 22025f757f3fSDimitry Andric DT = PrimaryIsThumb ? &PrimaryTarget : &*SecondaryTarget; 22035ffd83dbSDimitry Andric } 22045ffd83dbSDimitry Andric } 22055f757f3fSDimitry Andric } else if (!CHPECodeMap.empty()) { 22065f757f3fSDimitry Andric uint64_t Address = SectionAddr + Index; 22075f757f3fSDimitry Andric auto It = partition_point( 22085f757f3fSDimitry Andric CHPECodeMap, 22095f757f3fSDimitry Andric [Address](const std::pair<uint64_t, uint64_t> &Entry) { 22105f757f3fSDimitry Andric return Entry.first <= Address; 22115f757f3fSDimitry Andric }); 22125f757f3fSDimitry Andric if (It != CHPECodeMap.begin() && Address < (It - 1)->second) { 22135f757f3fSDimitry Andric DT = &*SecondaryTarget; 22145f757f3fSDimitry Andric } else { 22155f757f3fSDimitry Andric DT = &PrimaryTarget; 22165f757f3fSDimitry Andric // X64 disassembler range may have left Index unaligned, so 22175f757f3fSDimitry Andric // make sure that it's aligned when we switch back to ARM64 22185f757f3fSDimitry Andric // code. 22195f757f3fSDimitry Andric Index = llvm::alignTo(Index, 4); 22205f757f3fSDimitry Andric if (Index >= End) 22215f757f3fSDimitry Andric break; 22225f757f3fSDimitry Andric } 22230b57cec5SDimitry Andric } 22240b57cec5SDimitry Andric 2225cb14a3feSDimitry Andric auto findRel = [&]() { 2226cb14a3feSDimitry Andric while (RelCur != RelEnd) { 2227cb14a3feSDimitry Andric RelOffset = RelCur->getOffset() - RelAdjustment; 2228cb14a3feSDimitry Andric // If this relocation is hidden, skip it. 2229cb14a3feSDimitry Andric if (getHidden(*RelCur) || SectionAddr + RelOffset < StartAddress) { 2230cb14a3feSDimitry Andric ++RelCur; 2231cb14a3feSDimitry Andric continue; 2232cb14a3feSDimitry Andric } 2233cb14a3feSDimitry Andric 2234cb14a3feSDimitry Andric // Stop when RelCur's offset is past the disassembled 2235cb14a3feSDimitry Andric // instruction/data. 2236cb14a3feSDimitry Andric if (RelOffset >= Index + Size) 2237cb14a3feSDimitry Andric return false; 2238cb14a3feSDimitry Andric if (RelOffset >= Index) 2239cb14a3feSDimitry Andric return true; 2240cb14a3feSDimitry Andric ++RelCur; 2241cb14a3feSDimitry Andric } 2242cb14a3feSDimitry Andric return false; 2243cb14a3feSDimitry Andric }; 2244cb14a3feSDimitry Andric 22455ffd83dbSDimitry Andric if (DumpARMELFData) { 22465ffd83dbSDimitry Andric Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes, 22475f757f3fSDimitry Andric MappingSymbols, *DT->SubtargetInfo, FOS); 22485ffd83dbSDimitry Andric } else { 22490b57cec5SDimitry Andric // When -z or --disassemble-zeroes are given we always dissasemble 22500b57cec5SDimitry Andric // them. Otherwise we might want to skip zero bytes we see. 22510b57cec5SDimitry Andric if (!DisassembleZeroes) { 22520b57cec5SDimitry Andric uint64_t MaxOffset = End - Index; 22535ffd83dbSDimitry Andric // For --reloc: print zero blocks patched by relocations, so that 22540b57cec5SDimitry Andric // relocations can be shown in the dump. 2255cb14a3feSDimitry Andric if (InlineRelocs && RelCur != RelEnd) 225669ade1e0SDimitry Andric MaxOffset = std::min(RelCur->getOffset() - RelAdjustment - Index, 225769ade1e0SDimitry Andric MaxOffset); 22580b57cec5SDimitry Andric 22590b57cec5SDimitry Andric if (size_t N = 22600b57cec5SDimitry Andric countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) { 22615ffd83dbSDimitry Andric FOS << "\t\t..." << '\n'; 22620b57cec5SDimitry Andric Index += N; 22630b57cec5SDimitry Andric continue; 22640b57cec5SDimitry Andric } 22650b57cec5SDimitry Andric } 22660b57cec5SDimitry Andric 226706c3fb27SDimitry Andric if (DumpTracebackTableForXCOFFFunction && 226806c3fb27SDimitry Andric doesXCOFFTracebackTableBegin(Bytes.slice(Index, 4))) { 226906c3fb27SDimitry Andric dumpTracebackTable(Bytes.slice(Index), 227006c3fb27SDimitry Andric SectionAddr + Index + VMAAdjustment, FOS, 22715f757f3fSDimitry Andric SectionAddr + End + VMAAdjustment, 22725f757f3fSDimitry Andric *DT->SubtargetInfo, cast<XCOFFObjectFile>(&Obj)); 227306c3fb27SDimitry Andric Index = End; 227406c3fb27SDimitry Andric continue; 227506c3fb27SDimitry Andric } 227606c3fb27SDimitry Andric 2277e8d8bef9SDimitry Andric // Print local label if there's any. 227881ad6265SDimitry Andric auto Iter1 = BBAddrMapLabels.find(SectionAddr + Index); 227981ad6265SDimitry Andric if (Iter1 != BBAddrMapLabels.end()) { 22807a6dacacSDimitry Andric for (const auto &BBLabel : Iter1->second) 22817a6dacacSDimitry Andric FOS << "<" << BBLabel.BlockLabel << ">" << BBLabel.PGOAnalysis 22827a6dacacSDimitry Andric << ":\n"; 228381ad6265SDimitry Andric } else { 228481ad6265SDimitry Andric auto Iter2 = AllLabels.find(SectionAddr + Index); 228581ad6265SDimitry Andric if (Iter2 != AllLabels.end()) 228681ad6265SDimitry Andric FOS << "<" << Iter2->second << ">:\n"; 228781ad6265SDimitry Andric } 2288e8d8bef9SDimitry Andric 22890b57cec5SDimitry Andric // Disassemble a real instruction or a data when disassemble all is 22900b57cec5SDimitry Andric // provided 22910b57cec5SDimitry Andric MCInst Inst; 2292972a253aSDimitry Andric ArrayRef<uint8_t> ThisBytes = Bytes.slice(Index); 2293972a253aSDimitry Andric uint64_t ThisAddr = SectionAddr + Index; 22945f757f3fSDimitry Andric bool Disassembled = DT->DisAsm->getInstruction( 22955f757f3fSDimitry Andric Inst, Size, ThisBytes, ThisAddr, CommentStream); 22960b57cec5SDimitry Andric if (Size == 0) 2297972a253aSDimitry Andric Size = std::min<uint64_t>( 2298972a253aSDimitry Andric ThisBytes.size(), 22995f757f3fSDimitry Andric DT->DisAsm->suggestBytesToSkip(ThisBytes, ThisAddr)); 23000b57cec5SDimitry Andric 23015ffd83dbSDimitry Andric LVP.update({Index, Section.getIndex()}, 23025ffd83dbSDimitry Andric {Index + Size, Section.getIndex()}, Index + Size != End); 23035ffd83dbSDimitry Andric 23045f757f3fSDimitry Andric DT->InstPrinter->setCommentStream(CommentStream); 2305fe6060f1SDimitry Andric 23065f757f3fSDimitry Andric DT->Printer->printInst( 23075f757f3fSDimitry Andric *DT->InstPrinter, Disassembled ? &Inst : nullptr, 23085f757f3fSDimitry Andric Bytes.slice(Index, Size), 23095ffd83dbSDimitry Andric {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS, 23105f757f3fSDimitry Andric "", *DT->SubtargetInfo, &SP, Obj.getFileName(), &Rels, LVP); 2311fe6060f1SDimitry Andric 23125f757f3fSDimitry Andric DT->InstPrinter->setCommentStream(llvm::nulls()); 23130b57cec5SDimitry Andric 2314cb14a3feSDimitry Andric // If disassembly succeeds, we try to resolve the target address 2315cb14a3feSDimitry Andric // (jump target or memory operand address) and print it to the 23165ffd83dbSDimitry Andric // right of the instruction. 2317cb14a3feSDimitry Andric // 2318cb14a3feSDimitry Andric // Otherwise, we don't print anything else so that we avoid 2319cb14a3feSDimitry Andric // analyzing invalid or incomplete instruction information. 23205f757f3fSDimitry Andric if (Disassembled && DT->InstrAnalysis) { 2321fe6060f1SDimitry Andric llvm::raw_ostream *TargetOS = &FOS; 23220b57cec5SDimitry Andric uint64_t Target; 23235f757f3fSDimitry Andric bool PrintTarget = DT->InstrAnalysis->evaluateBranch( 23245f757f3fSDimitry Andric Inst, SectionAddr + Index, Size, Target); 2325cb14a3feSDimitry Andric 2326cb14a3feSDimitry Andric if (!PrintTarget) { 2327bdd1243dSDimitry Andric if (std::optional<uint64_t> MaybeTarget = 23285f757f3fSDimitry Andric DT->InstrAnalysis->evaluateMemoryOperandAddress( 23295f757f3fSDimitry Andric Inst, DT->SubtargetInfo.get(), SectionAddr + Index, 23305f757f3fSDimitry Andric Size)) { 23315ffd83dbSDimitry Andric Target = *MaybeTarget; 23325ffd83dbSDimitry Andric PrintTarget = true; 2333e8d8bef9SDimitry Andric // Do not print real address when symbolizing. 2334fe6060f1SDimitry Andric if (!SymbolizeOperands) { 2335fe6060f1SDimitry Andric // Memory operand addresses are printed as comments. 2336fe6060f1SDimitry Andric TargetOS = &CommentStream; 2337fe6060f1SDimitry Andric *TargetOS << "0x" << Twine::utohexstr(Target); 2338fe6060f1SDimitry Andric } 23395ffd83dbSDimitry Andric } 2340cb14a3feSDimitry Andric } 2341cb14a3feSDimitry Andric 23425ffd83dbSDimitry Andric if (PrintTarget) { 23430b57cec5SDimitry Andric // In a relocatable object, the target's section must reside in 23440b57cec5SDimitry Andric // the same section as the call instruction or it is accessed 23450b57cec5SDimitry Andric // through a relocation. 23460b57cec5SDimitry Andric // 23470b57cec5SDimitry Andric // In a non-relocatable object, the target may be in any section. 23485ffd83dbSDimitry Andric // In that case, locate the section(s) containing the target 23495ffd83dbSDimitry Andric // address and find the symbol in one of those, if possible. 23500b57cec5SDimitry Andric // 2351cb14a3feSDimitry Andric // N.B. Except for XCOFF, we don't walk the relocations in the 2352cb14a3feSDimitry Andric // relocatable case yet. 23535ffd83dbSDimitry Andric std::vector<const SectionSymbolsTy *> TargetSectionSymbols; 2354753f127fSDimitry Andric if (!Obj.isRelocatableObject()) { 23555ffd83dbSDimitry Andric auto It = llvm::partition_point( 23560b57cec5SDimitry Andric SectionAddresses, 23570b57cec5SDimitry Andric [=](const std::pair<uint64_t, SectionRef> &O) { 23580b57cec5SDimitry Andric return O.first <= Target; 23590b57cec5SDimitry Andric }); 23605ffd83dbSDimitry Andric uint64_t TargetSecAddr = 0; 23615ffd83dbSDimitry Andric while (It != SectionAddresses.begin()) { 23620b57cec5SDimitry Andric --It; 23635ffd83dbSDimitry Andric if (TargetSecAddr == 0) 23645ffd83dbSDimitry Andric TargetSecAddr = It->first; 23655ffd83dbSDimitry Andric if (It->first != TargetSecAddr) 23665ffd83dbSDimitry Andric break; 23675ffd83dbSDimitry Andric TargetSectionSymbols.push_back(&AllSymbols[It->second]); 23685ffd83dbSDimitry Andric } 23690b57cec5SDimitry Andric } else { 23705ffd83dbSDimitry Andric TargetSectionSymbols.push_back(&Symbols); 23715ffd83dbSDimitry Andric } 23725ffd83dbSDimitry Andric TargetSectionSymbols.push_back(&AbsoluteSymbols); 23735ffd83dbSDimitry Andric 23745ffd83dbSDimitry Andric // Find the last symbol in the first candidate section whose 23755ffd83dbSDimitry Andric // offset is less than or equal to the target. If there are no 23765ffd83dbSDimitry Andric // such symbols, try in the next section and so on, before finally 23775ffd83dbSDimitry Andric // using the nearest preceding absolute symbol (if any), if there 23785ffd83dbSDimitry Andric // are no other valid symbols. 23795ffd83dbSDimitry Andric const SymbolInfoTy *TargetSym = nullptr; 23805ffd83dbSDimitry Andric for (const SectionSymbolsTy *TargetSymbols : 23815ffd83dbSDimitry Andric TargetSectionSymbols) { 23825ffd83dbSDimitry Andric auto It = llvm::partition_point( 23835ffd83dbSDimitry Andric *TargetSymbols, 23845ffd83dbSDimitry Andric [=](const SymbolInfoTy &O) { return O.Addr <= Target; }); 2385bdd1243dSDimitry Andric while (It != TargetSymbols->begin()) { 2386bdd1243dSDimitry Andric --It; 2387bdd1243dSDimitry Andric // Skip mapping symbols to avoid possible ambiguity as they 2388bdd1243dSDimitry Andric // do not allow uniquely identifying the target address. 23895f757f3fSDimitry Andric if (!It->IsMappingSymbol) { 2390bdd1243dSDimitry Andric TargetSym = &*It; 23915ffd83dbSDimitry Andric break; 23920b57cec5SDimitry Andric } 23930b57cec5SDimitry Andric } 2394bdd1243dSDimitry Andric if (TargetSym) 2395bdd1243dSDimitry Andric break; 2396bdd1243dSDimitry Andric } 23970b57cec5SDimitry Andric 2398cb14a3feSDimitry Andric // Branch targets are printed just after the instructions. 2399e8d8bef9SDimitry Andric // Print the labels corresponding to the target if there's any. 240081ad6265SDimitry Andric bool BBAddrMapLabelAvailable = BBAddrMapLabels.count(Target); 2401e8d8bef9SDimitry Andric bool LabelAvailable = AllLabels.count(Target); 2402cb14a3feSDimitry Andric 24035ffd83dbSDimitry Andric if (TargetSym != nullptr) { 24045ffd83dbSDimitry Andric uint64_t TargetAddress = TargetSym->Addr; 2405e8d8bef9SDimitry Andric uint64_t Disp = Target - TargetAddress; 240606c3fb27SDimitry Andric std::string TargetName = Demangle ? demangle(TargetSym->Name) 240706c3fb27SDimitry Andric : TargetSym->Name.str(); 2408cb14a3feSDimitry Andric bool RelFixedUp = false; 2409cb14a3feSDimitry Andric SmallString<32> Val; 24105ffd83dbSDimitry Andric 2411fe6060f1SDimitry Andric *TargetOS << " <"; 2412cb14a3feSDimitry Andric // On XCOFF, we use relocations, even without -r, so we 2413cb14a3feSDimitry Andric // can print the correct name for an extern function call. 2414cb14a3feSDimitry Andric if (Obj.isXCOFF() && findRel()) { 2415cb14a3feSDimitry Andric // Check for possible branch relocations and 2416cb14a3feSDimitry Andric // branches to fixup code. 2417cb14a3feSDimitry Andric bool BranchRelocationType = true; 2418cb14a3feSDimitry Andric XCOFF::RelocationType RelocType; 2419cb14a3feSDimitry Andric if (Obj.is64Bit()) { 2420cb14a3feSDimitry Andric const XCOFFRelocation64 *Reloc = 2421cb14a3feSDimitry Andric reinterpret_cast<XCOFFRelocation64 *>( 2422cb14a3feSDimitry Andric RelCur->getRawDataRefImpl().p); 2423cb14a3feSDimitry Andric RelFixedUp = Reloc->isFixupIndicated(); 2424cb14a3feSDimitry Andric RelocType = Reloc->Type; 2425cb14a3feSDimitry Andric } else { 2426cb14a3feSDimitry Andric const XCOFFRelocation32 *Reloc = 2427cb14a3feSDimitry Andric reinterpret_cast<XCOFFRelocation32 *>( 2428cb14a3feSDimitry Andric RelCur->getRawDataRefImpl().p); 2429cb14a3feSDimitry Andric RelFixedUp = Reloc->isFixupIndicated(); 2430cb14a3feSDimitry Andric RelocType = Reloc->Type; 2431cb14a3feSDimitry Andric } 2432cb14a3feSDimitry Andric BranchRelocationType = 2433cb14a3feSDimitry Andric RelocType == XCOFF::R_BA || RelocType == XCOFF::R_BR || 2434cb14a3feSDimitry Andric RelocType == XCOFF::R_RBA || RelocType == XCOFF::R_RBR; 2435cb14a3feSDimitry Andric 2436cb14a3feSDimitry Andric // If we have a valid relocation, try to print its 2437cb14a3feSDimitry Andric // corresponding symbol name. Multiple relocations on the 2438cb14a3feSDimitry Andric // same instruction are not handled. 2439cb14a3feSDimitry Andric // Branches to fixup code will have the RelFixedUp flag set in 2440cb14a3feSDimitry Andric // the RLD. For these instructions, we print the correct 2441cb14a3feSDimitry Andric // branch target, but print the referenced symbol as a 2442cb14a3feSDimitry Andric // comment. 2443cb14a3feSDimitry Andric if (Error E = getRelocationValueString(*RelCur, false, Val)) { 2444cb14a3feSDimitry Andric // If -r was used, this error will be printed later. 2445cb14a3feSDimitry Andric // Otherwise, we ignore the error and print what 2446cb14a3feSDimitry Andric // would have been printed without using relocations. 2447cb14a3feSDimitry Andric consumeError(std::move(E)); 2448cb14a3feSDimitry Andric *TargetOS << TargetName; 2449cb14a3feSDimitry Andric RelFixedUp = false; // Suppress comment for RLD sym name 2450cb14a3feSDimitry Andric } else if (BranchRelocationType && !RelFixedUp) 2451cb14a3feSDimitry Andric *TargetOS << Val; 2452cb14a3feSDimitry Andric else 2453cb14a3feSDimitry Andric *TargetOS << TargetName; 2454cb14a3feSDimitry Andric if (Disp) 2455cb14a3feSDimitry Andric *TargetOS << "+0x" << Twine::utohexstr(Disp); 2456cb14a3feSDimitry Andric } else if (!Disp) { 2457fe6060f1SDimitry Andric *TargetOS << TargetName; 245881ad6265SDimitry Andric } else if (BBAddrMapLabelAvailable) { 24597a6dacacSDimitry Andric *TargetOS << BBAddrMapLabels[Target].front().BlockLabel; 246081ad6265SDimitry Andric } else if (LabelAvailable) { 246181ad6265SDimitry Andric *TargetOS << AllLabels[Target]; 246281ad6265SDimitry Andric } else { 2463e8d8bef9SDimitry Andric // Always Print the binary symbol plus an offset if there's no 2464e8d8bef9SDimitry Andric // local label corresponding to the target address. 2465fe6060f1SDimitry Andric *TargetOS << TargetName << "+0x" << Twine::utohexstr(Disp); 2466e8d8bef9SDimitry Andric } 2467fe6060f1SDimitry Andric *TargetOS << ">"; 2468cb14a3feSDimitry Andric if (RelFixedUp && !InlineRelocs) { 2469cb14a3feSDimitry Andric // We have fixup code for a relocation. We print the 2470cb14a3feSDimitry Andric // referenced symbol as a comment. 2471cb14a3feSDimitry Andric *TargetOS << "\t# " << Val; 2472cb14a3feSDimitry Andric } 2473cb14a3feSDimitry Andric 247481ad6265SDimitry Andric } else if (BBAddrMapLabelAvailable) { 24757a6dacacSDimitry Andric *TargetOS << " <" << BBAddrMapLabels[Target].front().BlockLabel 24767a6dacacSDimitry Andric << ">"; 2477e8d8bef9SDimitry Andric } else if (LabelAvailable) { 2478fe6060f1SDimitry Andric *TargetOS << " <" << AllLabels[Target] << ">"; 24790b57cec5SDimitry Andric } 2480fe6060f1SDimitry Andric // By convention, each record in the comment stream should be 2481fe6060f1SDimitry Andric // terminated. 2482fe6060f1SDimitry Andric if (TargetOS == &CommentStream) 2483fe6060f1SDimitry Andric *TargetOS << "\n"; 24840b57cec5SDimitry Andric } 24855f757f3fSDimitry Andric 24865f757f3fSDimitry Andric DT->InstrAnalysis->updateState(Inst, SectionAddr + Index); 24875f757f3fSDimitry Andric } else if (!Disassembled && DT->InstrAnalysis) { 24885f757f3fSDimitry Andric DT->InstrAnalysis->resetState(); 24890b57cec5SDimitry Andric } 24905ffd83dbSDimitry Andric } 24915ffd83dbSDimitry Andric 24925f757f3fSDimitry Andric assert(DT->Context->getAsmInfo()); 24935f757f3fSDimitry Andric emitPostInstructionInfo(FOS, *DT->Context->getAsmInfo(), 24945f757f3fSDimitry Andric *DT->SubtargetInfo, CommentStream.str(), LVP); 2495fe6060f1SDimitry Andric Comments.clear(); 24960b57cec5SDimitry Andric 24975f757f3fSDimitry Andric if (BTF) 24985f757f3fSDimitry Andric printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP); 24995f757f3fSDimitry Andric 2500cb14a3feSDimitry Andric // Hexagon handles relocs in pretty printer 2501cb14a3feSDimitry Andric if (InlineRelocs && Obj.getArch() != Triple::hexagon) { 2502cb14a3feSDimitry Andric while (findRel()) { 25030b57cec5SDimitry Andric // When --adjust-vma is used, update the address printed. 2504753f127fSDimitry Andric if (RelCur->getSymbol() != Obj.symbol_end()) { 25050b57cec5SDimitry Andric Expected<section_iterator> SymSI = 25060b57cec5SDimitry Andric RelCur->getSymbol()->getSection(); 2507753f127fSDimitry Andric if (SymSI && *SymSI != Obj.section_end() && 25080b57cec5SDimitry Andric shouldAdjustVA(**SymSI)) 2509cb14a3feSDimitry Andric RelOffset += AdjustVMA; 25100b57cec5SDimitry Andric } 25110b57cec5SDimitry Andric 2512753f127fSDimitry Andric printRelocation(FOS, Obj.getFileName(), *RelCur, 2513cb14a3feSDimitry Andric SectionAddr + RelOffset, Is64Bits); 25145ffd83dbSDimitry Andric LVP.printAfterOtherLine(FOS, true); 25150b57cec5SDimitry Andric ++RelCur; 25160b57cec5SDimitry Andric } 25170b57cec5SDimitry Andric } 25180b57cec5SDimitry Andric 25190b57cec5SDimitry Andric Index += Size; 25200b57cec5SDimitry Andric } 25210b57cec5SDimitry Andric } 25220b57cec5SDimitry Andric } 25235ffd83dbSDimitry Andric StringSet<> MissingDisasmSymbolSet = 25245ffd83dbSDimitry Andric set_difference(DisasmSymbolSet, FoundDisasmSymbolSet); 25255ffd83dbSDimitry Andric for (StringRef Sym : MissingDisasmSymbolSet.keys()) 25265ffd83dbSDimitry Andric reportWarning("failed to disassemble missing symbol " + Sym, FileName); 25270b57cec5SDimitry Andric } 25280b57cec5SDimitry Andric 2529fcaf7f86SDimitry Andric static void disassembleObject(ObjectFile *Obj, bool InlineRelocs) { 2530bdd1243dSDimitry Andric // If information useful for showing the disassembly is missing, try to find a 2531bdd1243dSDimitry Andric // more complete binary and disassemble that instead. 2532bdd1243dSDimitry Andric OwningBinary<Binary> FetchedBinary; 2533bdd1243dSDimitry Andric if (Obj->symbols().empty()) { 2534bdd1243dSDimitry Andric if (std::optional<OwningBinary<Binary>> FetchedBinaryOpt = 2535bdd1243dSDimitry Andric fetchBinaryByBuildID(*Obj)) { 2536bdd1243dSDimitry Andric if (auto *O = dyn_cast<ObjectFile>(FetchedBinaryOpt->getBinary())) { 2537bdd1243dSDimitry Andric if (!O->symbols().empty() || 2538bdd1243dSDimitry Andric (!O->sections().empty() && Obj->sections().empty())) { 2539bdd1243dSDimitry Andric FetchedBinary = std::move(*FetchedBinaryOpt); 2540bdd1243dSDimitry Andric Obj = O; 2541bdd1243dSDimitry Andric } 2542bdd1243dSDimitry Andric } 2543bdd1243dSDimitry Andric } 2544bdd1243dSDimitry Andric } 2545bdd1243dSDimitry Andric 25460b57cec5SDimitry Andric const Target *TheTarget = getTarget(Obj); 25470b57cec5SDimitry Andric 25480b57cec5SDimitry Andric // Package up features to be passed to target/subtarget 2549bdd1243dSDimitry Andric Expected<SubtargetFeatures> FeaturesValue = Obj->getFeatures(); 2550bdd1243dSDimitry Andric if (!FeaturesValue) 2551bdd1243dSDimitry Andric reportError(FeaturesValue.takeError(), Obj->getFileName()); 2552bdd1243dSDimitry Andric SubtargetFeatures Features = *FeaturesValue; 255381ad6265SDimitry Andric if (!MAttrs.empty()) { 25540b57cec5SDimitry Andric for (unsigned I = 0; I != MAttrs.size(); ++I) 25550b57cec5SDimitry Andric Features.AddFeature(MAttrs[I]); 255681ad6265SDimitry Andric } else if (MCPU.empty() && Obj->getArch() == llvm::Triple::aarch64) { 255781ad6265SDimitry Andric Features.AddFeature("+all"); 255881ad6265SDimitry Andric } 25590b57cec5SDimitry Andric 2560e8d8bef9SDimitry Andric if (MCPU.empty()) 256181ad6265SDimitry Andric MCPU = Obj->tryGetCPUName().value_or("").str(); 2562e8d8bef9SDimitry Andric 2563bdd1243dSDimitry Andric if (isArmElf(*Obj)) { 2564bdd1243dSDimitry Andric // When disassembling big-endian Arm ELF, the instruction endianness is 2565bdd1243dSDimitry Andric // determined in a complex way. In relocatable objects, AAELF32 mandates 2566bdd1243dSDimitry Andric // that instruction endianness matches the ELF file endianness; in 2567bdd1243dSDimitry Andric // executable images, that's true unless the file header has the EF_ARM_BE8 2568bdd1243dSDimitry Andric // flag, in which case instructions are little-endian regardless of data 2569bdd1243dSDimitry Andric // endianness. 2570bdd1243dSDimitry Andric // 2571bdd1243dSDimitry Andric // We must set the big-endian-instructions SubtargetFeature to make the 2572bdd1243dSDimitry Andric // disassembler read the instructions the right way round, and also tell 2573bdd1243dSDimitry Andric // our own prettyprinter to retrieve the encodings the same way to print in 2574bdd1243dSDimitry Andric // hex. 2575bdd1243dSDimitry Andric const auto *Elf32BE = dyn_cast<ELF32BEObjectFile>(Obj); 2576bdd1243dSDimitry Andric 2577bdd1243dSDimitry Andric if (Elf32BE && (Elf32BE->isRelocatableObject() || 2578bdd1243dSDimitry Andric !(Elf32BE->getPlatformFlags() & ELF::EF_ARM_BE8))) { 2579bdd1243dSDimitry Andric Features.AddFeature("+big-endian-instructions"); 25805f757f3fSDimitry Andric ARMPrettyPrinterInst.setInstructionEndianness(llvm::endianness::big); 2581bdd1243dSDimitry Andric } else { 25825f757f3fSDimitry Andric ARMPrettyPrinterInst.setInstructionEndianness(llvm::endianness::little); 2583bdd1243dSDimitry Andric } 2584bdd1243dSDimitry Andric } 2585bdd1243dSDimitry Andric 25865f757f3fSDimitry Andric DisassemblerTarget PrimaryTarget(TheTarget, *Obj, TripleName, MCPU, Features); 25870b57cec5SDimitry Andric 25880b57cec5SDimitry Andric // If we have an ARM object file, we need a second disassembler, because 25890b57cec5SDimitry Andric // ARM CPUs have two different instruction sets: ARM mode, and Thumb mode. 25900b57cec5SDimitry Andric // We use mapping symbols to switch between the two assemblers, where 25910b57cec5SDimitry Andric // appropriate. 25925f757f3fSDimitry Andric std::optional<DisassemblerTarget> SecondaryTarget; 25935f757f3fSDimitry Andric 25945f757f3fSDimitry Andric if (isArmElf(*Obj)) { 25955f757f3fSDimitry Andric if (!PrimaryTarget.SubtargetInfo->checkFeatures("+mclass")) { 25965f757f3fSDimitry Andric if (PrimaryTarget.SubtargetInfo->checkFeatures("+thumb-mode")) 25970b57cec5SDimitry Andric Features.AddFeature("-thumb-mode"); 25980b57cec5SDimitry Andric else 25990b57cec5SDimitry Andric Features.AddFeature("+thumb-mode"); 26005f757f3fSDimitry Andric SecondaryTarget.emplace(PrimaryTarget, Features); 26010b57cec5SDimitry Andric } 26025f757f3fSDimitry Andric } else if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) { 26035f757f3fSDimitry Andric const chpe_metadata *CHPEMetadata = COFFObj->getCHPEMetadata(); 26045f757f3fSDimitry Andric if (CHPEMetadata && CHPEMetadata->CodeMapCount) { 26055f757f3fSDimitry Andric // Set up x86_64 disassembler for ARM64EC binaries. 26065f757f3fSDimitry Andric Triple X64Triple(TripleName); 26075f757f3fSDimitry Andric X64Triple.setArch(Triple::ArchType::x86_64); 26080b57cec5SDimitry Andric 26095f757f3fSDimitry Andric std::string Error; 26105f757f3fSDimitry Andric const Target *X64Target = 26115f757f3fSDimitry Andric TargetRegistry::lookupTarget("", X64Triple, Error); 26125f757f3fSDimitry Andric if (X64Target) { 26135f757f3fSDimitry Andric SubtargetFeatures X64Features; 26145f757f3fSDimitry Andric SecondaryTarget.emplace(X64Target, *Obj, X64Triple.getTriple(), "", 26155f757f3fSDimitry Andric X64Features); 26165f757f3fSDimitry Andric } else { 26175f757f3fSDimitry Andric reportWarning(Error, Obj->getFileName()); 26185f757f3fSDimitry Andric } 26195f757f3fSDimitry Andric } 26205f757f3fSDimitry Andric } 2621bdd1243dSDimitry Andric 2622bdd1243dSDimitry Andric const ObjectFile *DbgObj = Obj; 2623bdd1243dSDimitry Andric if (!FetchedBinary.getBinary() && !Obj->hasDebugInfo()) { 2624bdd1243dSDimitry Andric if (std::optional<OwningBinary<Binary>> DebugBinaryOpt = 2625bdd1243dSDimitry Andric fetchBinaryByBuildID(*Obj)) { 2626bdd1243dSDimitry Andric if (auto *FetchedObj = 2627bdd1243dSDimitry Andric dyn_cast<const ObjectFile>(DebugBinaryOpt->getBinary())) { 2628bdd1243dSDimitry Andric if (FetchedObj->hasDebugInfo()) { 2629bdd1243dSDimitry Andric FetchedBinary = std::move(*DebugBinaryOpt); 2630bdd1243dSDimitry Andric DbgObj = FetchedObj; 2631bdd1243dSDimitry Andric } 2632bdd1243dSDimitry Andric } 2633bdd1243dSDimitry Andric } 2634bdd1243dSDimitry Andric } 2635bdd1243dSDimitry Andric 2636bdd1243dSDimitry Andric std::unique_ptr<object::Binary> DSYMBinary; 2637bdd1243dSDimitry Andric std::unique_ptr<MemoryBuffer> DSYMBuf; 2638bdd1243dSDimitry Andric if (!DbgObj->hasDebugInfo()) { 2639bdd1243dSDimitry Andric if (const MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*Obj)) { 2640bdd1243dSDimitry Andric DbgObj = objdump::getMachODSymObject(MachOOF, Obj->getFileName(), 2641bdd1243dSDimitry Andric DSYMBinary, DSYMBuf); 2642bdd1243dSDimitry Andric if (!DbgObj) 2643bdd1243dSDimitry Andric return; 2644bdd1243dSDimitry Andric } 2645bdd1243dSDimitry Andric } 2646bdd1243dSDimitry Andric 2647bdd1243dSDimitry Andric SourcePrinter SP(DbgObj, TheTarget->getName()); 26480b57cec5SDimitry Andric 26490b57cec5SDimitry Andric for (StringRef Opt : DisassemblerOptions) 26505f757f3fSDimitry Andric if (!PrimaryTarget.InstPrinter->applyTargetSpecificCLOption(Opt)) 26518bcb0991SDimitry Andric reportError(Obj->getFileName(), 26528bcb0991SDimitry Andric "Unrecognized disassembler option: " + Opt); 26530b57cec5SDimitry Andric 26545f757f3fSDimitry Andric disassembleObject(*Obj, *DbgObj, PrimaryTarget, SecondaryTarget, SP, 26555f757f3fSDimitry Andric InlineRelocs); 26560b57cec5SDimitry Andric } 26570b57cec5SDimitry Andric 265806c3fb27SDimitry Andric void Dumper::printRelocations() { 265906c3fb27SDimitry Andric StringRef Fmt = O.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; 26600b57cec5SDimitry Andric 26610b57cec5SDimitry Andric // Build a mapping from relocation target to a vector of relocation 26620b57cec5SDimitry Andric // sections. Usually, there is an only one relocation section for 26630b57cec5SDimitry Andric // each relocated section. 26640b57cec5SDimitry Andric MapVector<SectionRef, std::vector<SectionRef>> SecToRelSec; 26658bcb0991SDimitry Andric uint64_t Ndx; 266606c3fb27SDimitry Andric for (const SectionRef &Section : ToolSectionFilter(O, &Ndx)) { 266706c3fb27SDimitry Andric if (O.isELF() && (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC)) 266881ad6265SDimitry Andric continue; 26690b57cec5SDimitry Andric if (Section.relocation_begin() == Section.relocation_end()) 26700b57cec5SDimitry Andric continue; 26718bcb0991SDimitry Andric Expected<section_iterator> SecOrErr = Section.getRelocatedSection(); 26728bcb0991SDimitry Andric if (!SecOrErr) 267306c3fb27SDimitry Andric reportError(O.getFileName(), 26748bcb0991SDimitry Andric "section (" + Twine(Ndx) + 26758bcb0991SDimitry Andric "): unable to get a relocation target: " + 26768bcb0991SDimitry Andric toString(SecOrErr.takeError())); 26778bcb0991SDimitry Andric SecToRelSec[**SecOrErr].push_back(Section); 26780b57cec5SDimitry Andric } 26790b57cec5SDimitry Andric 26800b57cec5SDimitry Andric for (std::pair<SectionRef, std::vector<SectionRef>> &P : SecToRelSec) { 268106c3fb27SDimitry Andric StringRef SecName = unwrapOrError(P.first.getName(), O.getFileName()); 2682fe6060f1SDimitry Andric outs() << "\nRELOCATION RECORDS FOR [" << SecName << "]:\n"; 268306c3fb27SDimitry Andric uint32_t OffsetPadding = (O.getBytesInAddress() > 4 ? 16 : 8); 26845ffd83dbSDimitry Andric uint32_t TypePadding = 24; 26855ffd83dbSDimitry Andric outs() << left_justify("OFFSET", OffsetPadding) << " " 26865ffd83dbSDimitry Andric << left_justify("TYPE", TypePadding) << " " 26875ffd83dbSDimitry Andric << "VALUE\n"; 26880b57cec5SDimitry Andric 26890b57cec5SDimitry Andric for (SectionRef Section : P.second) { 2690*0fca6ea1SDimitry Andric // CREL sections require decoding, each section may have its own specific 2691*0fca6ea1SDimitry Andric // decode problems. 2692*0fca6ea1SDimitry Andric if (O.isELF() && ELFSectionRef(Section).getType() == ELF::SHT_CREL) { 2693*0fca6ea1SDimitry Andric StringRef Err = 2694*0fca6ea1SDimitry Andric cast<const ELFObjectFileBase>(O).getCrelDecodeProblem(Section); 2695*0fca6ea1SDimitry Andric if (!Err.empty()) { 2696*0fca6ea1SDimitry Andric reportUniqueWarning(Err); 2697*0fca6ea1SDimitry Andric continue; 2698*0fca6ea1SDimitry Andric } 2699*0fca6ea1SDimitry Andric } 27000b57cec5SDimitry Andric for (const RelocationRef &Reloc : Section.relocations()) { 27010b57cec5SDimitry Andric uint64_t Address = Reloc.getOffset(); 27020b57cec5SDimitry Andric SmallString<32> RelocName; 27030b57cec5SDimitry Andric SmallString<32> ValueStr; 27040b57cec5SDimitry Andric if (Address < StartAddress || Address > StopAddress || getHidden(Reloc)) 27050b57cec5SDimitry Andric continue; 27060b57cec5SDimitry Andric Reloc.getTypeName(RelocName); 2707cb14a3feSDimitry Andric if (Error E = 2708cb14a3feSDimitry Andric getRelocationValueString(Reloc, SymbolDescription, ValueStr)) 270906c3fb27SDimitry Andric reportUniqueWarning(std::move(E)); 27108bcb0991SDimitry Andric 27115ffd83dbSDimitry Andric outs() << format(Fmt.data(), Address) << " " 27125ffd83dbSDimitry Andric << left_justify(RelocName, TypePadding) << " " << ValueStr 27135ffd83dbSDimitry Andric << "\n"; 27140b57cec5SDimitry Andric } 27150b57cec5SDimitry Andric } 27160b57cec5SDimitry Andric } 27170b57cec5SDimitry Andric } 27180b57cec5SDimitry Andric 27190b57cec5SDimitry Andric // Returns true if we need to show LMA column when dumping section headers. We 27200b57cec5SDimitry Andric // show it only when the platform is ELF and either we have at least one section 27210b57cec5SDimitry Andric // whose VMA and LMA are different and/or when --show-lma flag is used. 2722753f127fSDimitry Andric static bool shouldDisplayLMA(const ObjectFile &Obj) { 2723753f127fSDimitry Andric if (!Obj.isELF()) 27240b57cec5SDimitry Andric return false; 2725753f127fSDimitry Andric for (const SectionRef &S : ToolSectionFilter(Obj)) 27260b57cec5SDimitry Andric if (S.getAddress() != getELFSectionLMA(S)) 27270b57cec5SDimitry Andric return true; 27280b57cec5SDimitry Andric return ShowLMA; 27290b57cec5SDimitry Andric } 27300b57cec5SDimitry Andric 2731753f127fSDimitry Andric static size_t getMaxSectionNameWidth(const ObjectFile &Obj) { 27328bcb0991SDimitry Andric // Default column width for names is 13 even if no names are that long. 27338bcb0991SDimitry Andric size_t MaxWidth = 13; 2734753f127fSDimitry Andric for (const SectionRef &Section : ToolSectionFilter(Obj)) { 2735753f127fSDimitry Andric StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName()); 27368bcb0991SDimitry Andric MaxWidth = std::max(MaxWidth, Name.size()); 27378bcb0991SDimitry Andric } 27388bcb0991SDimitry Andric return MaxWidth; 27398bcb0991SDimitry Andric } 27408bcb0991SDimitry Andric 2741fcaf7f86SDimitry Andric void objdump::printSectionHeaders(ObjectFile &Obj) { 2742bdd1243dSDimitry Andric if (Obj.isELF() && Obj.sections().empty()) 2743bdd1243dSDimitry Andric createFakeELFSections(Obj); 2744bdd1243dSDimitry Andric 27458bcb0991SDimitry Andric size_t NameWidth = getMaxSectionNameWidth(Obj); 2746753f127fSDimitry Andric size_t AddressWidth = 2 * Obj.getBytesInAddress(); 27470b57cec5SDimitry Andric bool HasLMAColumn = shouldDisplayLMA(Obj); 2748fe6060f1SDimitry Andric outs() << "\nSections:\n"; 27490b57cec5SDimitry Andric if (HasLMAColumn) 2750fe6060f1SDimitry Andric outs() << "Idx " << left_justify("Name", NameWidth) << " Size " 27518bcb0991SDimitry Andric << left_justify("VMA", AddressWidth) << " " 27528bcb0991SDimitry Andric << left_justify("LMA", AddressWidth) << " Type\n"; 27530b57cec5SDimitry Andric else 2754fe6060f1SDimitry Andric outs() << "Idx " << left_justify("Name", NameWidth) << " Size " 27558bcb0991SDimitry Andric << left_justify("VMA", AddressWidth) << " Type\n"; 27560b57cec5SDimitry Andric 27578bcb0991SDimitry Andric uint64_t Idx; 2758753f127fSDimitry Andric for (const SectionRef &Section : ToolSectionFilter(Obj, &Idx)) { 2759753f127fSDimitry Andric StringRef Name = unwrapOrError(Section.getName(), Obj.getFileName()); 27600b57cec5SDimitry Andric uint64_t VMA = Section.getAddress(); 27610b57cec5SDimitry Andric if (shouldAdjustVA(Section)) 27620b57cec5SDimitry Andric VMA += AdjustVMA; 27630b57cec5SDimitry Andric 27640b57cec5SDimitry Andric uint64_t Size = Section.getSize(); 27658bcb0991SDimitry Andric 27668bcb0991SDimitry Andric std::string Type = Section.isText() ? "TEXT" : ""; 27678bcb0991SDimitry Andric if (Section.isData()) 2768fe6060f1SDimitry Andric Type += Type.empty() ? "DATA" : ", DATA"; 27698bcb0991SDimitry Andric if (Section.isBSS()) 2770fe6060f1SDimitry Andric Type += Type.empty() ? "BSS" : ", BSS"; 2771fe6060f1SDimitry Andric if (Section.isDebugSection()) 2772fe6060f1SDimitry Andric Type += Type.empty() ? "DEBUG" : ", DEBUG"; 27730b57cec5SDimitry Andric 27740b57cec5SDimitry Andric if (HasLMAColumn) 27758bcb0991SDimitry Andric outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth, 27768bcb0991SDimitry Andric Name.str().c_str(), Size) 27778bcb0991SDimitry Andric << format_hex_no_prefix(VMA, AddressWidth) << " " 27788bcb0991SDimitry Andric << format_hex_no_prefix(getELFSectionLMA(Section), AddressWidth) 27798bcb0991SDimitry Andric << " " << Type << "\n"; 27800b57cec5SDimitry Andric else 27818bcb0991SDimitry Andric outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth, 27828bcb0991SDimitry Andric Name.str().c_str(), Size) 27838bcb0991SDimitry Andric << format_hex_no_prefix(VMA, AddressWidth) << " " << Type << "\n"; 27840b57cec5SDimitry Andric } 27850b57cec5SDimitry Andric } 27860b57cec5SDimitry Andric 27875ffd83dbSDimitry Andric void objdump::printSectionContents(const ObjectFile *Obj) { 2788e8d8bef9SDimitry Andric const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj); 2789e8d8bef9SDimitry Andric 27900b57cec5SDimitry Andric for (const SectionRef &Section : ToolSectionFilter(*Obj)) { 27918bcb0991SDimitry Andric StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); 27920b57cec5SDimitry Andric uint64_t BaseAddr = Section.getAddress(); 27930b57cec5SDimitry Andric uint64_t Size = Section.getSize(); 27940b57cec5SDimitry Andric if (!Size) 27950b57cec5SDimitry Andric continue; 27960b57cec5SDimitry Andric 2797e8d8bef9SDimitry Andric outs() << "Contents of section "; 2798e8d8bef9SDimitry Andric StringRef SegmentName = getSegmentName(MachO, Section); 2799e8d8bef9SDimitry Andric if (!SegmentName.empty()) 2800e8d8bef9SDimitry Andric outs() << SegmentName << ","; 2801e8d8bef9SDimitry Andric outs() << Name << ":\n"; 28020b57cec5SDimitry Andric if (Section.isBSS()) { 28030b57cec5SDimitry Andric outs() << format("<skipping contents of bss section at [%04" PRIx64 28040b57cec5SDimitry Andric ", %04" PRIx64 ")>\n", 28050b57cec5SDimitry Andric BaseAddr, BaseAddr + Size); 28060b57cec5SDimitry Andric continue; 28070b57cec5SDimitry Andric } 28080b57cec5SDimitry Andric 28090b57cec5SDimitry Andric StringRef Contents = unwrapOrError(Section.getContents(), Obj->getFileName()); 28100b57cec5SDimitry Andric 28110b57cec5SDimitry Andric // Dump out the content as hex and printable ascii characters. 28120b57cec5SDimitry Andric for (std::size_t Addr = 0, End = Contents.size(); Addr < End; Addr += 16) { 28130b57cec5SDimitry Andric outs() << format(" %04" PRIx64 " ", BaseAddr + Addr); 28140b57cec5SDimitry Andric // Dump line of hex. 28150b57cec5SDimitry Andric for (std::size_t I = 0; I < 16; ++I) { 28160b57cec5SDimitry Andric if (I != 0 && I % 4 == 0) 28170b57cec5SDimitry Andric outs() << ' '; 28180b57cec5SDimitry Andric if (Addr + I < End) 28190b57cec5SDimitry Andric outs() << hexdigit((Contents[Addr + I] >> 4) & 0xF, true) 28200b57cec5SDimitry Andric << hexdigit(Contents[Addr + I] & 0xF, true); 28210b57cec5SDimitry Andric else 28220b57cec5SDimitry Andric outs() << " "; 28230b57cec5SDimitry Andric } 28240b57cec5SDimitry Andric // Print ascii. 28250b57cec5SDimitry Andric outs() << " "; 28260b57cec5SDimitry Andric for (std::size_t I = 0; I < 16 && Addr + I < End; ++I) { 28270b57cec5SDimitry Andric if (isPrint(static_cast<unsigned char>(Contents[Addr + I]) & 0xFF)) 28280b57cec5SDimitry Andric outs() << Contents[Addr + I]; 28290b57cec5SDimitry Andric else 28300b57cec5SDimitry Andric outs() << "."; 28310b57cec5SDimitry Andric } 28320b57cec5SDimitry Andric outs() << "\n"; 28330b57cec5SDimitry Andric } 28340b57cec5SDimitry Andric } 28350b57cec5SDimitry Andric } 28360b57cec5SDimitry Andric 283706c3fb27SDimitry Andric void Dumper::printSymbolTable(StringRef ArchiveName, StringRef ArchitectureName, 283806c3fb27SDimitry Andric bool DumpDynamic) { 2839753f127fSDimitry Andric if (O.isCOFF() && !DumpDynamic) { 2840fe6060f1SDimitry Andric outs() << "\nSYMBOL TABLE:\n"; 28415ffd83dbSDimitry Andric printCOFFSymbolTable(cast<const COFFObjectFile>(O)); 28420b57cec5SDimitry Andric return; 28430b57cec5SDimitry Andric } 28440b57cec5SDimitry Andric 2845753f127fSDimitry Andric const StringRef FileName = O.getFileName(); 28465ffd83dbSDimitry Andric 28475ffd83dbSDimitry Andric if (!DumpDynamic) { 2848fe6060f1SDimitry Andric outs() << "\nSYMBOL TABLE:\n"; 2849753f127fSDimitry Andric for (auto I = O.symbol_begin(); I != O.symbol_end(); ++I) 285006c3fb27SDimitry Andric printSymbol(*I, {}, FileName, ArchiveName, ArchitectureName, DumpDynamic); 28515ffd83dbSDimitry Andric return; 28525ffd83dbSDimitry Andric } 28535ffd83dbSDimitry Andric 2854fe6060f1SDimitry Andric outs() << "\nDYNAMIC SYMBOL TABLE:\n"; 2855753f127fSDimitry Andric if (!O.isELF()) { 28565ffd83dbSDimitry Andric reportWarning( 28575ffd83dbSDimitry Andric "this operation is not currently supported for this file format", 28585ffd83dbSDimitry Andric FileName); 28595ffd83dbSDimitry Andric return; 28605ffd83dbSDimitry Andric } 28615ffd83dbSDimitry Andric 2862753f127fSDimitry Andric const ELFObjectFileBase *ELF = cast<const ELFObjectFileBase>(&O); 2863349cc55cSDimitry Andric auto Symbols = ELF->getDynamicSymbolIterators(); 2864349cc55cSDimitry Andric Expected<std::vector<VersionEntry>> SymbolVersionsOrErr = 2865349cc55cSDimitry Andric ELF->readDynsymVersions(); 2866349cc55cSDimitry Andric if (!SymbolVersionsOrErr) { 2867349cc55cSDimitry Andric reportWarning(toString(SymbolVersionsOrErr.takeError()), FileName); 2868349cc55cSDimitry Andric SymbolVersionsOrErr = std::vector<VersionEntry>(); 2869349cc55cSDimitry Andric (void)!SymbolVersionsOrErr; 2870349cc55cSDimitry Andric } 2871349cc55cSDimitry Andric for (auto &Sym : Symbols) 287206c3fb27SDimitry Andric printSymbol(Sym, *SymbolVersionsOrErr, FileName, ArchiveName, 2873349cc55cSDimitry Andric ArchitectureName, DumpDynamic); 28745ffd83dbSDimitry Andric } 28755ffd83dbSDimitry Andric 287606c3fb27SDimitry Andric void Dumper::printSymbol(const SymbolRef &Symbol, 2877349cc55cSDimitry Andric ArrayRef<VersionEntry> SymbolVersions, 28785ffd83dbSDimitry Andric StringRef FileName, StringRef ArchiveName, 28795ffd83dbSDimitry Andric StringRef ArchitectureName, bool DumpDynamic) { 2880753f127fSDimitry Andric const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&O); 288106c3fb27SDimitry Andric Expected<uint64_t> AddrOrErr = Symbol.getAddress(); 288206c3fb27SDimitry Andric if (!AddrOrErr) { 288306c3fb27SDimitry Andric reportUniqueWarning(AddrOrErr.takeError()); 288406c3fb27SDimitry Andric return; 288506c3fb27SDimitry Andric } 288606c3fb27SDimitry Andric uint64_t Address = *AddrOrErr; 28875f757f3fSDimitry Andric section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 28885f757f3fSDimitry Andric if (SecI != O.section_end() && shouldAdjustVA(*SecI)) 28895f757f3fSDimitry Andric Address += AdjustVMA; 28900b57cec5SDimitry Andric if ((Address < StartAddress) || (Address > StopAddress)) 28915ffd83dbSDimitry Andric return; 28925ffd83dbSDimitry Andric SymbolRef::Type Type = 28935ffd83dbSDimitry Andric unwrapOrError(Symbol.getType(), FileName, ArchiveName, ArchitectureName); 28945ffd83dbSDimitry Andric uint32_t Flags = 28955ffd83dbSDimitry Andric unwrapOrError(Symbol.getFlags(), FileName, ArchiveName, ArchitectureName); 2896480093f4SDimitry Andric 2897480093f4SDimitry Andric // Don't ask a Mach-O STAB symbol for its section unless you know that 2898480093f4SDimitry Andric // STAB symbol's section field refers to a valid section index. Otherwise 2899480093f4SDimitry Andric // the symbol may error trying to load a section that does not exist. 29005ffd83dbSDimitry Andric bool IsSTAB = false; 2901480093f4SDimitry Andric if (MachO) { 2902480093f4SDimitry Andric DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); 29035ffd83dbSDimitry Andric uint8_t NType = 29045ffd83dbSDimitry Andric (MachO->is64Bit() ? MachO->getSymbol64TableEntry(SymDRI).n_type 29055ffd83dbSDimitry Andric : MachO->getSymbolTableEntry(SymDRI).n_type); 2906480093f4SDimitry Andric if (NType & MachO::N_STAB) 29075ffd83dbSDimitry Andric IsSTAB = true; 2908480093f4SDimitry Andric } 29095ffd83dbSDimitry Andric section_iterator Section = IsSTAB 2910753f127fSDimitry Andric ? O.section_end() 29115ffd83dbSDimitry Andric : unwrapOrError(Symbol.getSection(), FileName, 29128bcb0991SDimitry Andric ArchiveName, ArchitectureName); 2913480093f4SDimitry Andric 29140b57cec5SDimitry Andric StringRef Name; 2915753f127fSDimitry Andric if (Type == SymbolRef::ST_Debug && Section != O.section_end()) { 29168bcb0991SDimitry Andric if (Expected<StringRef> NameOrErr = Section->getName()) 29178bcb0991SDimitry Andric Name = *NameOrErr; 29180b57cec5SDimitry Andric else 29198bcb0991SDimitry Andric consumeError(NameOrErr.takeError()); 29208bcb0991SDimitry Andric 29218bcb0991SDimitry Andric } else { 29228bcb0991SDimitry Andric Name = unwrapOrError(Symbol.getName(), FileName, ArchiveName, 29230b57cec5SDimitry Andric ArchitectureName); 29248bcb0991SDimitry Andric } 29250b57cec5SDimitry Andric 29260b57cec5SDimitry Andric bool Global = Flags & SymbolRef::SF_Global; 29270b57cec5SDimitry Andric bool Weak = Flags & SymbolRef::SF_Weak; 29280b57cec5SDimitry Andric bool Absolute = Flags & SymbolRef::SF_Absolute; 29290b57cec5SDimitry Andric bool Common = Flags & SymbolRef::SF_Common; 29300b57cec5SDimitry Andric bool Hidden = Flags & SymbolRef::SF_Hidden; 29310b57cec5SDimitry Andric 29320b57cec5SDimitry Andric char GlobLoc = ' '; 2933753f127fSDimitry Andric if ((Section != O.section_end() || Absolute) && !Weak) 29340b57cec5SDimitry Andric GlobLoc = Global ? 'g' : 'l'; 29355ffd83dbSDimitry Andric char IFunc = ' '; 2936753f127fSDimitry Andric if (O.isELF()) { 29375ffd83dbSDimitry Andric if (ELFSymbolRef(Symbol).getELFType() == ELF::STT_GNU_IFUNC) 29385ffd83dbSDimitry Andric IFunc = 'i'; 29395ffd83dbSDimitry Andric if (ELFSymbolRef(Symbol).getBinding() == ELF::STB_GNU_UNIQUE) 29405ffd83dbSDimitry Andric GlobLoc = 'u'; 29415ffd83dbSDimitry Andric } 29425ffd83dbSDimitry Andric 29435ffd83dbSDimitry Andric char Debug = ' '; 29445ffd83dbSDimitry Andric if (DumpDynamic) 29455ffd83dbSDimitry Andric Debug = 'D'; 29465ffd83dbSDimitry Andric else if (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File) 29475ffd83dbSDimitry Andric Debug = 'd'; 29485ffd83dbSDimitry Andric 29490b57cec5SDimitry Andric char FileFunc = ' '; 29500b57cec5SDimitry Andric if (Type == SymbolRef::ST_File) 29510b57cec5SDimitry Andric FileFunc = 'f'; 29520b57cec5SDimitry Andric else if (Type == SymbolRef::ST_Function) 29530b57cec5SDimitry Andric FileFunc = 'F'; 29540b57cec5SDimitry Andric else if (Type == SymbolRef::ST_Data) 29550b57cec5SDimitry Andric FileFunc = 'O'; 29560b57cec5SDimitry Andric 2957753f127fSDimitry Andric const char *Fmt = O.getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; 29580b57cec5SDimitry Andric 29590b57cec5SDimitry Andric outs() << format(Fmt, Address) << " " 29600b57cec5SDimitry Andric << GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' ' 29610b57cec5SDimitry Andric << (Weak ? 'w' : ' ') // Weak? 29620b57cec5SDimitry Andric << ' ' // Constructor. Not supported yet. 29630b57cec5SDimitry Andric << ' ' // Warning. Not supported yet. 29645ffd83dbSDimitry Andric << IFunc // Indirect reference to another symbol. 29650b57cec5SDimitry Andric << Debug // Debugging (d) or dynamic (D) symbol. 29660b57cec5SDimitry Andric << FileFunc // Name of function (F), file (f) or object (O). 29670b57cec5SDimitry Andric << ' '; 29680b57cec5SDimitry Andric if (Absolute) { 29690b57cec5SDimitry Andric outs() << "*ABS*"; 29700b57cec5SDimitry Andric } else if (Common) { 29710b57cec5SDimitry Andric outs() << "*COM*"; 2972753f127fSDimitry Andric } else if (Section == O.section_end()) { 2973753f127fSDimitry Andric if (O.isXCOFF()) { 2974753f127fSDimitry Andric XCOFFSymbolRef XCOFFSym = cast<const XCOFFObjectFile>(O).toSymbolRef( 2975349cc55cSDimitry Andric Symbol.getRawDataRefImpl()); 2976349cc55cSDimitry Andric if (XCOFF::N_DEBUG == XCOFFSym.getSectionNumber()) 2977349cc55cSDimitry Andric outs() << "*DEBUG*"; 2978349cc55cSDimitry Andric else 2979349cc55cSDimitry Andric outs() << "*UND*"; 2980349cc55cSDimitry Andric } else 29810b57cec5SDimitry Andric outs() << "*UND*"; 29820b57cec5SDimitry Andric } else { 2983e8d8bef9SDimitry Andric StringRef SegmentName = getSegmentName(MachO, *Section); 2984e8d8bef9SDimitry Andric if (!SegmentName.empty()) 29850b57cec5SDimitry Andric outs() << SegmentName << ","; 29865ffd83dbSDimitry Andric StringRef SectionName = unwrapOrError(Section->getName(), FileName); 29870b57cec5SDimitry Andric outs() << SectionName; 2988753f127fSDimitry Andric if (O.isXCOFF()) { 2989bdd1243dSDimitry Andric std::optional<SymbolRef> SymRef = 2990753f127fSDimitry Andric getXCOFFSymbolContainingSymbolRef(cast<XCOFFObjectFile>(O), Symbol); 2991349cc55cSDimitry Andric if (SymRef) { 2992349cc55cSDimitry Andric 299381ad6265SDimitry Andric Expected<StringRef> NameOrErr = SymRef->getName(); 2994349cc55cSDimitry Andric 2995349cc55cSDimitry Andric if (NameOrErr) { 2996349cc55cSDimitry Andric outs() << " (csect:"; 299706c3fb27SDimitry Andric std::string SymName = 299806c3fb27SDimitry Andric Demangle ? demangle(*NameOrErr) : NameOrErr->str(); 2999349cc55cSDimitry Andric 3000349cc55cSDimitry Andric if (SymbolDescription) 3001bdd1243dSDimitry Andric SymName = getXCOFFSymbolDescription(createSymbolInfo(O, *SymRef), 3002bdd1243dSDimitry Andric SymName); 3003349cc55cSDimitry Andric 3004349cc55cSDimitry Andric outs() << ' ' << SymName; 3005349cc55cSDimitry Andric outs() << ") "; 3006349cc55cSDimitry Andric } else 3007349cc55cSDimitry Andric reportWarning(toString(NameOrErr.takeError()), FileName); 3008349cc55cSDimitry Andric } 3009349cc55cSDimitry Andric } 30100b57cec5SDimitry Andric } 30110b57cec5SDimitry Andric 3012349cc55cSDimitry Andric if (Common) 3013349cc55cSDimitry Andric outs() << '\t' << format(Fmt, static_cast<uint64_t>(Symbol.getAlignment())); 3014753f127fSDimitry Andric else if (O.isXCOFF()) 3015349cc55cSDimitry Andric outs() << '\t' 3016753f127fSDimitry Andric << format(Fmt, cast<XCOFFObjectFile>(O).getSymbolSize( 3017349cc55cSDimitry Andric Symbol.getRawDataRefImpl())); 3018753f127fSDimitry Andric else if (O.isELF()) 3019349cc55cSDimitry Andric outs() << '\t' << format(Fmt, ELFSymbolRef(Symbol).getSize()); 3020*0fca6ea1SDimitry Andric else if (O.isWasm()) 3021*0fca6ea1SDimitry Andric outs() << '\t' 3022*0fca6ea1SDimitry Andric << format(Fmt, static_cast<uint64_t>( 3023*0fca6ea1SDimitry Andric cast<WasmObjectFile>(O).getSymbolSize(Symbol))); 30240b57cec5SDimitry Andric 3025753f127fSDimitry Andric if (O.isELF()) { 3026349cc55cSDimitry Andric if (!SymbolVersions.empty()) { 3027349cc55cSDimitry Andric const VersionEntry &Ver = 3028349cc55cSDimitry Andric SymbolVersions[Symbol.getRawDataRefImpl().d.b - 1]; 3029349cc55cSDimitry Andric std::string Str; 3030349cc55cSDimitry Andric if (!Ver.Name.empty()) 3031349cc55cSDimitry Andric Str = Ver.IsVerDef ? ' ' + Ver.Name : '(' + Ver.Name + ')'; 3032349cc55cSDimitry Andric outs() << ' ' << left_justify(Str, 12); 3033349cc55cSDimitry Andric } 3034349cc55cSDimitry Andric 30350b57cec5SDimitry Andric uint8_t Other = ELFSymbolRef(Symbol).getOther(); 30360b57cec5SDimitry Andric switch (Other) { 30370b57cec5SDimitry Andric case ELF::STV_DEFAULT: 30380b57cec5SDimitry Andric break; 30390b57cec5SDimitry Andric case ELF::STV_INTERNAL: 30400b57cec5SDimitry Andric outs() << " .internal"; 30410b57cec5SDimitry Andric break; 30420b57cec5SDimitry Andric case ELF::STV_HIDDEN: 30430b57cec5SDimitry Andric outs() << " .hidden"; 30440b57cec5SDimitry Andric break; 30450b57cec5SDimitry Andric case ELF::STV_PROTECTED: 30460b57cec5SDimitry Andric outs() << " .protected"; 30470b57cec5SDimitry Andric break; 30480b57cec5SDimitry Andric default: 30490b57cec5SDimitry Andric outs() << format(" 0x%02x", Other); 30500b57cec5SDimitry Andric break; 30510b57cec5SDimitry Andric } 30520b57cec5SDimitry Andric } else if (Hidden) { 30530b57cec5SDimitry Andric outs() << " .hidden"; 30540b57cec5SDimitry Andric } 30550b57cec5SDimitry Andric 305606c3fb27SDimitry Andric std::string SymName = Demangle ? demangle(Name) : Name.str(); 3057753f127fSDimitry Andric if (O.isXCOFF() && SymbolDescription) 3058349cc55cSDimitry Andric SymName = getXCOFFSymbolDescription(createSymbolInfo(O, Symbol), SymName); 3059349cc55cSDimitry Andric 3060349cc55cSDimitry Andric outs() << ' ' << SymName << '\n'; 30610b57cec5SDimitry Andric } 30620b57cec5SDimitry Andric 30630b57cec5SDimitry Andric static void printUnwindInfo(const ObjectFile *O) { 30640b57cec5SDimitry Andric outs() << "Unwind info:\n\n"; 30650b57cec5SDimitry Andric 30660b57cec5SDimitry Andric if (const COFFObjectFile *Coff = dyn_cast<COFFObjectFile>(O)) 30670b57cec5SDimitry Andric printCOFFUnwindInfo(Coff); 30680b57cec5SDimitry Andric else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O)) 30690b57cec5SDimitry Andric printMachOUnwindInfo(MachO); 30700b57cec5SDimitry Andric else 30710b57cec5SDimitry Andric // TODO: Extract DWARF dump tool to objdump. 30720b57cec5SDimitry Andric WithColor::error(errs(), ToolName) 30730b57cec5SDimitry Andric << "This operation is only currently supported " 30740b57cec5SDimitry Andric "for COFF and MachO object files.\n"; 30750b57cec5SDimitry Andric } 30760b57cec5SDimitry Andric 30770b57cec5SDimitry Andric /// Dump the raw contents of the __clangast section so the output can be piped 30780b57cec5SDimitry Andric /// into llvm-bcanalyzer. 30795ffd83dbSDimitry Andric static void printRawClangAST(const ObjectFile *Obj) { 30800b57cec5SDimitry Andric if (outs().is_displayed()) { 30810b57cec5SDimitry Andric WithColor::error(errs(), ToolName) 30820b57cec5SDimitry Andric << "The -raw-clang-ast option will dump the raw binary contents of " 30830b57cec5SDimitry Andric "the clang ast section.\n" 30840b57cec5SDimitry Andric "Please redirect the output to a file or another program such as " 30850b57cec5SDimitry Andric "llvm-bcanalyzer.\n"; 30860b57cec5SDimitry Andric return; 30870b57cec5SDimitry Andric } 30880b57cec5SDimitry Andric 30890b57cec5SDimitry Andric StringRef ClangASTSectionName("__clangast"); 30905ffd83dbSDimitry Andric if (Obj->isCOFF()) { 30910b57cec5SDimitry Andric ClangASTSectionName = "clangast"; 30920b57cec5SDimitry Andric } 30930b57cec5SDimitry Andric 3094bdd1243dSDimitry Andric std::optional<object::SectionRef> ClangASTSection; 30950b57cec5SDimitry Andric for (auto Sec : ToolSectionFilter(*Obj)) { 30960b57cec5SDimitry Andric StringRef Name; 30978bcb0991SDimitry Andric if (Expected<StringRef> NameOrErr = Sec.getName()) 30988bcb0991SDimitry Andric Name = *NameOrErr; 30998bcb0991SDimitry Andric else 31008bcb0991SDimitry Andric consumeError(NameOrErr.takeError()); 31018bcb0991SDimitry Andric 31020b57cec5SDimitry Andric if (Name == ClangASTSectionName) { 31030b57cec5SDimitry Andric ClangASTSection = Sec; 31040b57cec5SDimitry Andric break; 31050b57cec5SDimitry Andric } 31060b57cec5SDimitry Andric } 31070b57cec5SDimitry Andric if (!ClangASTSection) 31080b57cec5SDimitry Andric return; 31090b57cec5SDimitry Andric 3110753f127fSDimitry Andric StringRef ClangASTContents = 3111bdd1243dSDimitry Andric unwrapOrError(ClangASTSection->getContents(), Obj->getFileName()); 31120b57cec5SDimitry Andric outs().write(ClangASTContents.data(), ClangASTContents.size()); 31130b57cec5SDimitry Andric } 31140b57cec5SDimitry Andric 31150b57cec5SDimitry Andric static void printFaultMaps(const ObjectFile *Obj) { 31160b57cec5SDimitry Andric StringRef FaultMapSectionName; 31170b57cec5SDimitry Andric 31185ffd83dbSDimitry Andric if (Obj->isELF()) { 31190b57cec5SDimitry Andric FaultMapSectionName = ".llvm_faultmaps"; 31205ffd83dbSDimitry Andric } else if (Obj->isMachO()) { 31210b57cec5SDimitry Andric FaultMapSectionName = "__llvm_faultmaps"; 31220b57cec5SDimitry Andric } else { 31230b57cec5SDimitry Andric WithColor::error(errs(), ToolName) 31240b57cec5SDimitry Andric << "This operation is only currently supported " 31250b57cec5SDimitry Andric "for ELF and Mach-O executable files.\n"; 31260b57cec5SDimitry Andric return; 31270b57cec5SDimitry Andric } 31280b57cec5SDimitry Andric 3129bdd1243dSDimitry Andric std::optional<object::SectionRef> FaultMapSection; 31300b57cec5SDimitry Andric 31310b57cec5SDimitry Andric for (auto Sec : ToolSectionFilter(*Obj)) { 31320b57cec5SDimitry Andric StringRef Name; 31338bcb0991SDimitry Andric if (Expected<StringRef> NameOrErr = Sec.getName()) 31348bcb0991SDimitry Andric Name = *NameOrErr; 31358bcb0991SDimitry Andric else 31368bcb0991SDimitry Andric consumeError(NameOrErr.takeError()); 31378bcb0991SDimitry Andric 31380b57cec5SDimitry Andric if (Name == FaultMapSectionName) { 31390b57cec5SDimitry Andric FaultMapSection = Sec; 31400b57cec5SDimitry Andric break; 31410b57cec5SDimitry Andric } 31420b57cec5SDimitry Andric } 31430b57cec5SDimitry Andric 31440b57cec5SDimitry Andric outs() << "FaultMap table:\n"; 31450b57cec5SDimitry Andric 314681ad6265SDimitry Andric if (!FaultMapSection) { 31470b57cec5SDimitry Andric outs() << "<not found>\n"; 31480b57cec5SDimitry Andric return; 31490b57cec5SDimitry Andric } 31500b57cec5SDimitry Andric 31510b57cec5SDimitry Andric StringRef FaultMapContents = 315281ad6265SDimitry Andric unwrapOrError(FaultMapSection->getContents(), Obj->getFileName()); 31530b57cec5SDimitry Andric FaultMapParser FMP(FaultMapContents.bytes_begin(), 31540b57cec5SDimitry Andric FaultMapContents.bytes_end()); 31550b57cec5SDimitry Andric 31560b57cec5SDimitry Andric outs() << FMP; 31570b57cec5SDimitry Andric } 31580b57cec5SDimitry Andric 31595f757f3fSDimitry Andric void Dumper::printPrivateHeaders() { 316006c3fb27SDimitry Andric reportError(O.getFileName(), "Invalid/Unsupported object file format"); 31610b57cec5SDimitry Andric } 31620b57cec5SDimitry Andric 31630b57cec5SDimitry Andric static void printFileHeaders(const ObjectFile *O) { 3164*0fca6ea1SDimitry Andric if (!O->isELF() && !O->isCOFF() && !O->isXCOFF()) 31658bcb0991SDimitry Andric reportError(O->getFileName(), "Invalid/Unsupported object file format"); 31660b57cec5SDimitry Andric 31670b57cec5SDimitry Andric Triple::ArchType AT = O->getArch(); 31680b57cec5SDimitry Andric outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n"; 31690b57cec5SDimitry Andric uint64_t Address = unwrapOrError(O->getStartAddress(), O->getFileName()); 31700b57cec5SDimitry Andric 31710b57cec5SDimitry Andric StringRef Fmt = O->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; 31720b57cec5SDimitry Andric outs() << "start address: " 3173fe6060f1SDimitry Andric << "0x" << format(Fmt.data(), Address) << "\n"; 31740b57cec5SDimitry Andric } 31750b57cec5SDimitry Andric 31760b57cec5SDimitry Andric static void printArchiveChild(StringRef Filename, const Archive::Child &C) { 31770b57cec5SDimitry Andric Expected<sys::fs::perms> ModeOrErr = C.getAccessMode(); 31780b57cec5SDimitry Andric if (!ModeOrErr) { 31790b57cec5SDimitry Andric WithColor::error(errs(), ToolName) << "ill-formed archive entry.\n"; 31800b57cec5SDimitry Andric consumeError(ModeOrErr.takeError()); 31810b57cec5SDimitry Andric return; 31820b57cec5SDimitry Andric } 31830b57cec5SDimitry Andric sys::fs::perms Mode = ModeOrErr.get(); 31840b57cec5SDimitry Andric outs() << ((Mode & sys::fs::owner_read) ? "r" : "-"); 31850b57cec5SDimitry Andric outs() << ((Mode & sys::fs::owner_write) ? "w" : "-"); 31860b57cec5SDimitry Andric outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-"); 31870b57cec5SDimitry Andric outs() << ((Mode & sys::fs::group_read) ? "r" : "-"); 31880b57cec5SDimitry Andric outs() << ((Mode & sys::fs::group_write) ? "w" : "-"); 31890b57cec5SDimitry Andric outs() << ((Mode & sys::fs::group_exe) ? "x" : "-"); 31900b57cec5SDimitry Andric outs() << ((Mode & sys::fs::others_read) ? "r" : "-"); 31910b57cec5SDimitry Andric outs() << ((Mode & sys::fs::others_write) ? "w" : "-"); 31920b57cec5SDimitry Andric outs() << ((Mode & sys::fs::others_exe) ? "x" : "-"); 31930b57cec5SDimitry Andric 31940b57cec5SDimitry Andric outs() << " "; 31950b57cec5SDimitry Andric 31960b57cec5SDimitry Andric outs() << format("%d/%d %6" PRId64 " ", unwrapOrError(C.getUID(), Filename), 31970b57cec5SDimitry Andric unwrapOrError(C.getGID(), Filename), 31980b57cec5SDimitry Andric unwrapOrError(C.getRawSize(), Filename)); 31990b57cec5SDimitry Andric 32000b57cec5SDimitry Andric StringRef RawLastModified = C.getRawLastModified(); 32010b57cec5SDimitry Andric unsigned Seconds; 32020b57cec5SDimitry Andric if (RawLastModified.getAsInteger(10, Seconds)) 32030b57cec5SDimitry Andric outs() << "(date: \"" << RawLastModified 32040b57cec5SDimitry Andric << "\" contains non-decimal chars) "; 32050b57cec5SDimitry Andric else { 32060b57cec5SDimitry Andric // Since ctime(3) returns a 26 character string of the form: 32070b57cec5SDimitry Andric // "Sun Sep 16 01:03:52 1973\n\0" 32080b57cec5SDimitry Andric // just print 24 characters. 32090b57cec5SDimitry Andric time_t t = Seconds; 32100b57cec5SDimitry Andric outs() << format("%.24s ", ctime(&t)); 32110b57cec5SDimitry Andric } 32120b57cec5SDimitry Andric 32130b57cec5SDimitry Andric StringRef Name = ""; 32140b57cec5SDimitry Andric Expected<StringRef> NameOrErr = C.getName(); 32150b57cec5SDimitry Andric if (!NameOrErr) { 32160b57cec5SDimitry Andric consumeError(NameOrErr.takeError()); 32170b57cec5SDimitry Andric Name = unwrapOrError(C.getRawName(), Filename); 32180b57cec5SDimitry Andric } else { 32190b57cec5SDimitry Andric Name = NameOrErr.get(); 32200b57cec5SDimitry Andric } 32210b57cec5SDimitry Andric outs() << Name << "\n"; 32220b57cec5SDimitry Andric } 32230b57cec5SDimitry Andric 32248bcb0991SDimitry Andric // For ELF only now. 32258bcb0991SDimitry Andric static bool shouldWarnForInvalidStartStopAddress(ObjectFile *Obj) { 32268bcb0991SDimitry Andric if (const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj)) { 32278bcb0991SDimitry Andric if (Elf->getEType() != ELF::ET_REL) 32288bcb0991SDimitry Andric return true; 32298bcb0991SDimitry Andric } 32308bcb0991SDimitry Andric return false; 32318bcb0991SDimitry Andric } 32328bcb0991SDimitry Andric 32338bcb0991SDimitry Andric static void checkForInvalidStartStopAddress(ObjectFile *Obj, 32348bcb0991SDimitry Andric uint64_t Start, uint64_t Stop) { 32358bcb0991SDimitry Andric if (!shouldWarnForInvalidStartStopAddress(Obj)) 32368bcb0991SDimitry Andric return; 32378bcb0991SDimitry Andric 32388bcb0991SDimitry Andric for (const SectionRef &Section : Obj->sections()) 32398bcb0991SDimitry Andric if (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC) { 32408bcb0991SDimitry Andric uint64_t BaseAddr = Section.getAddress(); 32418bcb0991SDimitry Andric uint64_t Size = Section.getSize(); 32428bcb0991SDimitry Andric if ((Start < BaseAddr + Size) && Stop > BaseAddr) 32438bcb0991SDimitry Andric return; 32448bcb0991SDimitry Andric } 32458bcb0991SDimitry Andric 3246fe6060f1SDimitry Andric if (!HasStartAddressFlag) 32478bcb0991SDimitry Andric reportWarning("no section has address less than 0x" + 32488bcb0991SDimitry Andric Twine::utohexstr(Stop) + " specified by --stop-address", 32498bcb0991SDimitry Andric Obj->getFileName()); 3250fe6060f1SDimitry Andric else if (!HasStopAddressFlag) 32518bcb0991SDimitry Andric reportWarning("no section has address greater than or equal to 0x" + 32528bcb0991SDimitry Andric Twine::utohexstr(Start) + " specified by --start-address", 32538bcb0991SDimitry Andric Obj->getFileName()); 32548bcb0991SDimitry Andric else 32558bcb0991SDimitry Andric reportWarning("no section overlaps the range [0x" + 32568bcb0991SDimitry Andric Twine::utohexstr(Start) + ",0x" + Twine::utohexstr(Stop) + 32578bcb0991SDimitry Andric ") specified by --start-address/--stop-address", 32588bcb0991SDimitry Andric Obj->getFileName()); 32598bcb0991SDimitry Andric } 32608bcb0991SDimitry Andric 32610b57cec5SDimitry Andric static void dumpObject(ObjectFile *O, const Archive *A = nullptr, 32620b57cec5SDimitry Andric const Archive::Child *C = nullptr) { 326306c3fb27SDimitry Andric Expected<std::unique_ptr<Dumper>> DumperOrErr = createDumper(*O); 326406c3fb27SDimitry Andric if (!DumperOrErr) { 326506c3fb27SDimitry Andric reportError(DumperOrErr.takeError(), O->getFileName(), 326606c3fb27SDimitry Andric A ? A->getFileName() : ""); 326706c3fb27SDimitry Andric return; 326806c3fb27SDimitry Andric } 326906c3fb27SDimitry Andric Dumper &D = **DumperOrErr; 327006c3fb27SDimitry Andric 32710b57cec5SDimitry Andric // Avoid other output when using a raw option. 32720b57cec5SDimitry Andric if (!RawClangAST) { 32730b57cec5SDimitry Andric outs() << '\n'; 32740b57cec5SDimitry Andric if (A) 32750b57cec5SDimitry Andric outs() << A->getFileName() << "(" << O->getFileName() << ")"; 32760b57cec5SDimitry Andric else 32770b57cec5SDimitry Andric outs() << O->getFileName(); 3278fe6060f1SDimitry Andric outs() << ":\tfile format " << O->getFileFormatName().lower() << "\n"; 32790b57cec5SDimitry Andric } 32800b57cec5SDimitry Andric 3281fe6060f1SDimitry Andric if (HasStartAddressFlag || HasStopAddressFlag) 32828bcb0991SDimitry Andric checkForInvalidStartStopAddress(O, StartAddress, StopAddress); 32838bcb0991SDimitry Andric 328406c3fb27SDimitry Andric // TODO: Change print* free functions to Dumper member functions to utilitize 328506c3fb27SDimitry Andric // stateful functions like reportUniqueWarning. 328606c3fb27SDimitry Andric 32878bcb0991SDimitry Andric // Note: the order here matches GNU objdump for compatability. 32880b57cec5SDimitry Andric StringRef ArchiveName = A ? A->getFileName() : ""; 32890b57cec5SDimitry Andric if (ArchiveHeaders && !MachOOpt && C) 32900b57cec5SDimitry Andric printArchiveChild(ArchiveName, *C); 32918bcb0991SDimitry Andric if (FileHeaders) 32928bcb0991SDimitry Andric printFileHeaders(O); 32938bcb0991SDimitry Andric if (PrivateHeaders || FirstPrivateHeader) 32945f757f3fSDimitry Andric D.printPrivateHeaders(); 32958bcb0991SDimitry Andric if (SectionHeaders) 3296753f127fSDimitry Andric printSectionHeaders(*O); 32978bcb0991SDimitry Andric if (SymbolTable) 329806c3fb27SDimitry Andric D.printSymbolTable(ArchiveName); 32995ffd83dbSDimitry Andric if (DynamicSymbolTable) 330006c3fb27SDimitry Andric D.printSymbolTable(ArchiveName, /*ArchitectureName=*/"", 33015ffd83dbSDimitry Andric /*DumpDynamic=*/true); 33028bcb0991SDimitry Andric if (DwarfDumpType != DIDT_Null) { 33038bcb0991SDimitry Andric std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O); 33048bcb0991SDimitry Andric // Dump the complete DWARF structure. 33058bcb0991SDimitry Andric DIDumpOptions DumpOpts; 33068bcb0991SDimitry Andric DumpOpts.DumpType = DwarfDumpType; 33078bcb0991SDimitry Andric DICtx->dump(outs(), DumpOpts); 33088bcb0991SDimitry Andric } 33090b57cec5SDimitry Andric if (Relocations && !Disassemble) 331006c3fb27SDimitry Andric D.printRelocations(); 33110b57cec5SDimitry Andric if (DynamicRelocations) 331206c3fb27SDimitry Andric D.printDynamicRelocations(); 33130b57cec5SDimitry Andric if (SectionContents) 33140b57cec5SDimitry Andric printSectionContents(O); 33158bcb0991SDimitry Andric if (Disassemble) 33168bcb0991SDimitry Andric disassembleObject(O, Relocations); 33170b57cec5SDimitry Andric if (UnwindInfo) 33180b57cec5SDimitry Andric printUnwindInfo(O); 33198bcb0991SDimitry Andric 33208bcb0991SDimitry Andric // Mach-O specific options: 33210b57cec5SDimitry Andric if (ExportsTrie) 33220b57cec5SDimitry Andric printExportsTrie(O); 33230b57cec5SDimitry Andric if (Rebase) 33240b57cec5SDimitry Andric printRebaseTable(O); 33250b57cec5SDimitry Andric if (Bind) 33260b57cec5SDimitry Andric printBindTable(O); 33270b57cec5SDimitry Andric if (LazyBind) 33280b57cec5SDimitry Andric printLazyBindTable(O); 33290b57cec5SDimitry Andric if (WeakBind) 33300b57cec5SDimitry Andric printWeakBindTable(O); 33318bcb0991SDimitry Andric 33328bcb0991SDimitry Andric // Other special sections: 33330b57cec5SDimitry Andric if (RawClangAST) 33340b57cec5SDimitry Andric printRawClangAST(O); 33350b57cec5SDimitry Andric if (FaultMapSection) 33360b57cec5SDimitry Andric printFaultMaps(O); 333781ad6265SDimitry Andric if (Offloading) 333881ad6265SDimitry Andric dumpOffloadBinary(*O); 33390b57cec5SDimitry Andric } 33400b57cec5SDimitry Andric 33410b57cec5SDimitry Andric static void dumpObject(const COFFImportFile *I, const Archive *A, 33420b57cec5SDimitry Andric const Archive::Child *C = nullptr) { 33430b57cec5SDimitry Andric StringRef ArchiveName = A ? A->getFileName() : ""; 33440b57cec5SDimitry Andric 33450b57cec5SDimitry Andric // Avoid other output when using a raw option. 33460b57cec5SDimitry Andric if (!RawClangAST) 33470b57cec5SDimitry Andric outs() << '\n' 33480b57cec5SDimitry Andric << ArchiveName << "(" << I->getFileName() << ")" 33490b57cec5SDimitry Andric << ":\tfile format COFF-import-file" 33500b57cec5SDimitry Andric << "\n\n"; 33510b57cec5SDimitry Andric 33520b57cec5SDimitry Andric if (ArchiveHeaders && !MachOOpt && C) 33530b57cec5SDimitry Andric printArchiveChild(ArchiveName, *C); 33540b57cec5SDimitry Andric if (SymbolTable) 3355753f127fSDimitry Andric printCOFFSymbolTable(*I); 33560b57cec5SDimitry Andric } 33570b57cec5SDimitry Andric 33580b57cec5SDimitry Andric /// Dump each object file in \a a; 33590b57cec5SDimitry Andric static void dumpArchive(const Archive *A) { 33600b57cec5SDimitry Andric Error Err = Error::success(); 33618bcb0991SDimitry Andric unsigned I = -1; 33620b57cec5SDimitry Andric for (auto &C : A->children(Err)) { 33638bcb0991SDimitry Andric ++I; 33640b57cec5SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(); 33650b57cec5SDimitry Andric if (!ChildOrErr) { 33660b57cec5SDimitry Andric if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) 33678bcb0991SDimitry Andric reportError(std::move(E), getFileNameForError(C, I), A->getFileName()); 33680b57cec5SDimitry Andric continue; 33690b57cec5SDimitry Andric } 33700b57cec5SDimitry Andric if (ObjectFile *O = dyn_cast<ObjectFile>(&*ChildOrErr.get())) 33710b57cec5SDimitry Andric dumpObject(O, A, &C); 33720b57cec5SDimitry Andric else if (COFFImportFile *I = dyn_cast<COFFImportFile>(&*ChildOrErr.get())) 33730b57cec5SDimitry Andric dumpObject(I, A, &C); 33740b57cec5SDimitry Andric else 33758bcb0991SDimitry Andric reportError(errorCodeToError(object_error::invalid_file_type), 33760b57cec5SDimitry Andric A->getFileName()); 33770b57cec5SDimitry Andric } 33780b57cec5SDimitry Andric if (Err) 33798bcb0991SDimitry Andric reportError(std::move(Err), A->getFileName()); 33800b57cec5SDimitry Andric } 33810b57cec5SDimitry Andric 33820b57cec5SDimitry Andric /// Open file and figure out how to dump it. 33830b57cec5SDimitry Andric static void dumpInput(StringRef file) { 33840b57cec5SDimitry Andric // If we are using the Mach-O specific object file parser, then let it parse 33850b57cec5SDimitry Andric // the file and process the command line options. So the -arch flags can 33860b57cec5SDimitry Andric // be used to select specific slices, etc. 33870b57cec5SDimitry Andric if (MachOOpt) { 33880b57cec5SDimitry Andric parseInputMachO(file); 33890b57cec5SDimitry Andric return; 33900b57cec5SDimitry Andric } 33910b57cec5SDimitry Andric 33920b57cec5SDimitry Andric // Attempt to open the binary. 33930b57cec5SDimitry Andric OwningBinary<Binary> OBinary = unwrapOrError(createBinary(file), file); 33940b57cec5SDimitry Andric Binary &Binary = *OBinary.getBinary(); 33950b57cec5SDimitry Andric 33960b57cec5SDimitry Andric if (Archive *A = dyn_cast<Archive>(&Binary)) 33970b57cec5SDimitry Andric dumpArchive(A); 33980b57cec5SDimitry Andric else if (ObjectFile *O = dyn_cast<ObjectFile>(&Binary)) 33990b57cec5SDimitry Andric dumpObject(O); 34000b57cec5SDimitry Andric else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary)) 34010b57cec5SDimitry Andric parseInputMachO(UB); 340281ad6265SDimitry Andric else if (OffloadBinary *OB = dyn_cast<OffloadBinary>(&Binary)) 340381ad6265SDimitry Andric dumpOffloadSections(*OB); 34040b57cec5SDimitry Andric else 34058bcb0991SDimitry Andric reportError(errorCodeToError(object_error::invalid_file_type), file); 34060b57cec5SDimitry Andric } 34070b57cec5SDimitry Andric 3408fe6060f1SDimitry Andric template <typename T> 3409fe6060f1SDimitry Andric static void parseIntArg(const llvm::opt::InputArgList &InputArgs, int ID, 3410fe6060f1SDimitry Andric T &Value) { 3411fe6060f1SDimitry Andric if (const opt::Arg *A = InputArgs.getLastArg(ID)) { 3412fe6060f1SDimitry Andric StringRef V(A->getValue()); 3413fe6060f1SDimitry Andric if (!llvm::to_integer(V, Value, 0)) { 3414fe6060f1SDimitry Andric reportCmdLineError(A->getSpelling() + 3415fe6060f1SDimitry Andric ": expected a non-negative integer, but got '" + V + 3416fe6060f1SDimitry Andric "'"); 3417fe6060f1SDimitry Andric } 3418fe6060f1SDimitry Andric } 3419fe6060f1SDimitry Andric } 3420fe6060f1SDimitry Andric 3421bdd1243dSDimitry Andric static object::BuildID parseBuildIDArg(const opt::Arg *A) { 3422bdd1243dSDimitry Andric StringRef V(A->getValue()); 342306c3fb27SDimitry Andric object::BuildID BID = parseBuildID(V); 342406c3fb27SDimitry Andric if (BID.empty()) 3425bdd1243dSDimitry Andric reportCmdLineError(A->getSpelling() + ": expected a build ID, but got '" + 3426bdd1243dSDimitry Andric V + "'"); 342706c3fb27SDimitry Andric return BID; 3428bdd1243dSDimitry Andric } 3429bdd1243dSDimitry Andric 3430bdd1243dSDimitry Andric void objdump::invalidArgValue(const opt::Arg *A) { 3431349cc55cSDimitry Andric reportCmdLineError("'" + StringRef(A->getValue()) + 3432349cc55cSDimitry Andric "' is not a valid value for '" + A->getSpelling() + "'"); 3433349cc55cSDimitry Andric } 3434349cc55cSDimitry Andric 3435fe6060f1SDimitry Andric static std::vector<std::string> 3436fe6060f1SDimitry Andric commaSeparatedValues(const llvm::opt::InputArgList &InputArgs, int ID) { 3437fe6060f1SDimitry Andric std::vector<std::string> Values; 3438fe6060f1SDimitry Andric for (StringRef Value : InputArgs.getAllArgValues(ID)) { 3439fe6060f1SDimitry Andric llvm::SmallVector<StringRef, 2> SplitValues; 3440fe6060f1SDimitry Andric llvm::SplitString(Value, SplitValues, ","); 3441fe6060f1SDimitry Andric for (StringRef SplitValue : SplitValues) 3442fe6060f1SDimitry Andric Values.push_back(SplitValue.str()); 3443fe6060f1SDimitry Andric } 3444fe6060f1SDimitry Andric return Values; 3445fe6060f1SDimitry Andric } 3446fe6060f1SDimitry Andric 3447fe6060f1SDimitry Andric static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) { 3448fe6060f1SDimitry Andric MachOOpt = true; 3449fe6060f1SDimitry Andric FullLeadingAddr = true; 3450fe6060f1SDimitry Andric PrintImmHex = true; 3451fe6060f1SDimitry Andric 3452fe6060f1SDimitry Andric ArchName = InputArgs.getLastArgValue(OTOOL_arch).str(); 3453fe6060f1SDimitry Andric LinkOptHints = InputArgs.hasArg(OTOOL_C); 3454fe6060f1SDimitry Andric if (InputArgs.hasArg(OTOOL_d)) 3455fe6060f1SDimitry Andric FilterSections.push_back("__DATA,__data"); 3456fe6060f1SDimitry Andric DylibId = InputArgs.hasArg(OTOOL_D); 3457fe6060f1SDimitry Andric UniversalHeaders = InputArgs.hasArg(OTOOL_f); 3458fe6060f1SDimitry Andric DataInCode = InputArgs.hasArg(OTOOL_G); 3459fe6060f1SDimitry Andric FirstPrivateHeader = InputArgs.hasArg(OTOOL_h); 3460fe6060f1SDimitry Andric IndirectSymbols = InputArgs.hasArg(OTOOL_I); 3461fe6060f1SDimitry Andric ShowRawInsn = InputArgs.hasArg(OTOOL_j); 3462fe6060f1SDimitry Andric PrivateHeaders = InputArgs.hasArg(OTOOL_l); 3463fe6060f1SDimitry Andric DylibsUsed = InputArgs.hasArg(OTOOL_L); 3464fe6060f1SDimitry Andric MCPU = InputArgs.getLastArgValue(OTOOL_mcpu_EQ).str(); 3465fe6060f1SDimitry Andric ObjcMetaData = InputArgs.hasArg(OTOOL_o); 3466fe6060f1SDimitry Andric DisSymName = InputArgs.getLastArgValue(OTOOL_p).str(); 3467fe6060f1SDimitry Andric InfoPlist = InputArgs.hasArg(OTOOL_P); 3468fe6060f1SDimitry Andric Relocations = InputArgs.hasArg(OTOOL_r); 3469fe6060f1SDimitry Andric if (const Arg *A = InputArgs.getLastArg(OTOOL_s)) { 3470fe6060f1SDimitry Andric auto Filter = (A->getValue(0) + StringRef(",") + A->getValue(1)).str(); 3471fe6060f1SDimitry Andric FilterSections.push_back(Filter); 3472fe6060f1SDimitry Andric } 3473fe6060f1SDimitry Andric if (InputArgs.hasArg(OTOOL_t)) 3474fe6060f1SDimitry Andric FilterSections.push_back("__TEXT,__text"); 3475fe6060f1SDimitry Andric Verbose = InputArgs.hasArg(OTOOL_v) || InputArgs.hasArg(OTOOL_V) || 3476fe6060f1SDimitry Andric InputArgs.hasArg(OTOOL_o); 3477fe6060f1SDimitry Andric SymbolicOperands = InputArgs.hasArg(OTOOL_V); 3478fe6060f1SDimitry Andric if (InputArgs.hasArg(OTOOL_x)) 3479fe6060f1SDimitry Andric FilterSections.push_back(",__text"); 3480fe6060f1SDimitry Andric LeadingAddr = LeadingHeaders = !InputArgs.hasArg(OTOOL_X); 3481fe6060f1SDimitry Andric 3482bdd1243dSDimitry Andric ChainedFixups = InputArgs.hasArg(OTOOL_chained_fixups); 3483bdd1243dSDimitry Andric DyldInfo = InputArgs.hasArg(OTOOL_dyld_info); 3484bdd1243dSDimitry Andric 3485fe6060f1SDimitry Andric InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT); 3486fe6060f1SDimitry Andric if (InputFilenames.empty()) 3487fe6060f1SDimitry Andric reportCmdLineError("no input file"); 3488fe6060f1SDimitry Andric 3489fe6060f1SDimitry Andric for (const Arg *A : InputArgs) { 3490fe6060f1SDimitry Andric const Option &O = A->getOption(); 3491fe6060f1SDimitry Andric if (O.getGroup().isValid() && O.getGroup().getID() == OTOOL_grp_obsolete) { 3492fe6060f1SDimitry Andric reportCmdLineWarning(O.getPrefixedName() + 3493fe6060f1SDimitry Andric " is obsolete and not implemented"); 3494fe6060f1SDimitry Andric } 3495fe6060f1SDimitry Andric } 3496fe6060f1SDimitry Andric } 3497fe6060f1SDimitry Andric 3498fe6060f1SDimitry Andric static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) { 3499fe6060f1SDimitry Andric parseIntArg(InputArgs, OBJDUMP_adjust_vma_EQ, AdjustVMA); 3500fe6060f1SDimitry Andric AllHeaders = InputArgs.hasArg(OBJDUMP_all_headers); 3501fe6060f1SDimitry Andric ArchName = InputArgs.getLastArgValue(OBJDUMP_arch_name_EQ).str(); 3502fe6060f1SDimitry Andric ArchiveHeaders = InputArgs.hasArg(OBJDUMP_archive_headers); 3503fe6060f1SDimitry Andric Demangle = InputArgs.hasArg(OBJDUMP_demangle); 3504fe6060f1SDimitry Andric Disassemble = InputArgs.hasArg(OBJDUMP_disassemble); 3505fe6060f1SDimitry Andric DisassembleAll = InputArgs.hasArg(OBJDUMP_disassemble_all); 3506fe6060f1SDimitry Andric SymbolDescription = InputArgs.hasArg(OBJDUMP_symbol_description); 350706c3fb27SDimitry Andric TracebackTable = InputArgs.hasArg(OBJDUMP_traceback_table); 3508fe6060f1SDimitry Andric DisassembleSymbols = 3509fe6060f1SDimitry Andric commaSeparatedValues(InputArgs, OBJDUMP_disassemble_symbols_EQ); 3510fe6060f1SDimitry Andric DisassembleZeroes = InputArgs.hasArg(OBJDUMP_disassemble_zeroes); 3511fe6060f1SDimitry Andric if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_dwarf_EQ)) { 3512349cc55cSDimitry Andric DwarfDumpType = StringSwitch<DIDumpType>(A->getValue()) 3513349cc55cSDimitry Andric .Case("frames", DIDT_DebugFrame) 3514349cc55cSDimitry Andric .Default(DIDT_Null); 3515349cc55cSDimitry Andric if (DwarfDumpType == DIDT_Null) 3516349cc55cSDimitry Andric invalidArgValue(A); 3517fe6060f1SDimitry Andric } 3518fe6060f1SDimitry Andric DynamicRelocations = InputArgs.hasArg(OBJDUMP_dynamic_reloc); 3519fe6060f1SDimitry Andric FaultMapSection = InputArgs.hasArg(OBJDUMP_fault_map_section); 352081ad6265SDimitry Andric Offloading = InputArgs.hasArg(OBJDUMP_offloading); 3521fe6060f1SDimitry Andric FileHeaders = InputArgs.hasArg(OBJDUMP_file_headers); 3522fe6060f1SDimitry Andric SectionContents = InputArgs.hasArg(OBJDUMP_full_contents); 3523fe6060f1SDimitry Andric PrintLines = InputArgs.hasArg(OBJDUMP_line_numbers); 3524fe6060f1SDimitry Andric InputFilenames = InputArgs.getAllArgValues(OBJDUMP_INPUT); 3525fe6060f1SDimitry Andric MachOOpt = InputArgs.hasArg(OBJDUMP_macho); 3526fe6060f1SDimitry Andric MCPU = InputArgs.getLastArgValue(OBJDUMP_mcpu_EQ).str(); 3527fe6060f1SDimitry Andric MAttrs = commaSeparatedValues(InputArgs, OBJDUMP_mattr_EQ); 3528fe6060f1SDimitry Andric ShowRawInsn = !InputArgs.hasArg(OBJDUMP_no_show_raw_insn); 3529fe6060f1SDimitry Andric LeadingAddr = !InputArgs.hasArg(OBJDUMP_no_leading_addr); 3530fe6060f1SDimitry Andric RawClangAST = InputArgs.hasArg(OBJDUMP_raw_clang_ast); 3531fe6060f1SDimitry Andric Relocations = InputArgs.hasArg(OBJDUMP_reloc); 3532fe6060f1SDimitry Andric PrintImmHex = 3533bdd1243dSDimitry Andric InputArgs.hasFlag(OBJDUMP_print_imm_hex, OBJDUMP_no_print_imm_hex, true); 3534fe6060f1SDimitry Andric PrivateHeaders = InputArgs.hasArg(OBJDUMP_private_headers); 3535fe6060f1SDimitry Andric FilterSections = InputArgs.getAllArgValues(OBJDUMP_section_EQ); 3536fe6060f1SDimitry Andric SectionHeaders = InputArgs.hasArg(OBJDUMP_section_headers); 3537bdd1243dSDimitry Andric ShowAllSymbols = InputArgs.hasArg(OBJDUMP_show_all_symbols); 3538fe6060f1SDimitry Andric ShowLMA = InputArgs.hasArg(OBJDUMP_show_lma); 3539fe6060f1SDimitry Andric PrintSource = InputArgs.hasArg(OBJDUMP_source); 3540fe6060f1SDimitry Andric parseIntArg(InputArgs, OBJDUMP_start_address_EQ, StartAddress); 3541fe6060f1SDimitry Andric HasStartAddressFlag = InputArgs.hasArg(OBJDUMP_start_address_EQ); 3542fe6060f1SDimitry Andric parseIntArg(InputArgs, OBJDUMP_stop_address_EQ, StopAddress); 3543fe6060f1SDimitry Andric HasStopAddressFlag = InputArgs.hasArg(OBJDUMP_stop_address_EQ); 3544fe6060f1SDimitry Andric SymbolTable = InputArgs.hasArg(OBJDUMP_syms); 3545fe6060f1SDimitry Andric SymbolizeOperands = InputArgs.hasArg(OBJDUMP_symbolize_operands); 3546*0fca6ea1SDimitry Andric PrettyPGOAnalysisMap = InputArgs.hasArg(OBJDUMP_pretty_pgo_analysis_map); 3547*0fca6ea1SDimitry Andric if (PrettyPGOAnalysisMap && !SymbolizeOperands) 3548*0fca6ea1SDimitry Andric reportCmdLineWarning("--symbolize-operands must be enabled for " 3549*0fca6ea1SDimitry Andric "--pretty-pgo-analysis-map to have an effect"); 3550fe6060f1SDimitry Andric DynamicSymbolTable = InputArgs.hasArg(OBJDUMP_dynamic_syms); 3551fe6060f1SDimitry Andric TripleName = InputArgs.getLastArgValue(OBJDUMP_triple_EQ).str(); 3552fe6060f1SDimitry Andric UnwindInfo = InputArgs.hasArg(OBJDUMP_unwind_info); 3553fe6060f1SDimitry Andric Wide = InputArgs.hasArg(OBJDUMP_wide); 3554fe6060f1SDimitry Andric Prefix = InputArgs.getLastArgValue(OBJDUMP_prefix).str(); 3555fe6060f1SDimitry Andric parseIntArg(InputArgs, OBJDUMP_prefix_strip, PrefixStrip); 3556fe6060f1SDimitry Andric if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_debug_vars_EQ)) { 3557fe6060f1SDimitry Andric DbgVariables = StringSwitch<DebugVarsFormat>(A->getValue()) 3558fe6060f1SDimitry Andric .Case("ascii", DVASCII) 3559349cc55cSDimitry Andric .Case("unicode", DVUnicode) 3560349cc55cSDimitry Andric .Default(DVInvalid); 3561349cc55cSDimitry Andric if (DbgVariables == DVInvalid) 3562349cc55cSDimitry Andric invalidArgValue(A); 3563fe6060f1SDimitry Andric } 35645f757f3fSDimitry Andric if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_disassembler_color_EQ)) { 35655f757f3fSDimitry Andric DisassemblyColor = StringSwitch<ColorOutput>(A->getValue()) 35665f757f3fSDimitry Andric .Case("on", ColorOutput::Enable) 35675f757f3fSDimitry Andric .Case("off", ColorOutput::Disable) 35685f757f3fSDimitry Andric .Case("terminal", ColorOutput::Auto) 35695f757f3fSDimitry Andric .Default(ColorOutput::Invalid); 35705f757f3fSDimitry Andric if (DisassemblyColor == ColorOutput::Invalid) 35715f757f3fSDimitry Andric invalidArgValue(A); 35725f757f3fSDimitry Andric } 35735f757f3fSDimitry Andric 3574fe6060f1SDimitry Andric parseIntArg(InputArgs, OBJDUMP_debug_vars_indent_EQ, DbgIndent); 3575fe6060f1SDimitry Andric 3576fe6060f1SDimitry Andric parseMachOOptions(InputArgs); 3577fe6060f1SDimitry Andric 3578fe6060f1SDimitry Andric // Parse -M (--disassembler-options) and deprecated 3579fe6060f1SDimitry Andric // --x86-asm-syntax={att,intel}. 3580fe6060f1SDimitry Andric // 3581fe6060f1SDimitry Andric // Note, for x86, the asm dialect (AssemblerDialect) is initialized when the 3582fe6060f1SDimitry Andric // MCAsmInfo is constructed. MCInstPrinter::applyTargetSpecificCLOption is 3583fe6060f1SDimitry Andric // called too late. For now we have to use the internal cl::opt option. 3584fe6060f1SDimitry Andric const char *AsmSyntax = nullptr; 3585fe6060f1SDimitry Andric for (const auto *A : InputArgs.filtered(OBJDUMP_disassembler_options_EQ, 3586fe6060f1SDimitry Andric OBJDUMP_x86_asm_syntax_att, 3587fe6060f1SDimitry Andric OBJDUMP_x86_asm_syntax_intel)) { 3588fe6060f1SDimitry Andric switch (A->getOption().getID()) { 3589fe6060f1SDimitry Andric case OBJDUMP_x86_asm_syntax_att: 3590fe6060f1SDimitry Andric AsmSyntax = "--x86-asm-syntax=att"; 3591fe6060f1SDimitry Andric continue; 3592fe6060f1SDimitry Andric case OBJDUMP_x86_asm_syntax_intel: 3593fe6060f1SDimitry Andric AsmSyntax = "--x86-asm-syntax=intel"; 3594fe6060f1SDimitry Andric continue; 3595fe6060f1SDimitry Andric } 3596fe6060f1SDimitry Andric 3597fe6060f1SDimitry Andric SmallVector<StringRef, 2> Values; 3598fe6060f1SDimitry Andric llvm::SplitString(A->getValue(), Values, ","); 3599fe6060f1SDimitry Andric for (StringRef V : Values) { 3600fe6060f1SDimitry Andric if (V == "att") 3601fe6060f1SDimitry Andric AsmSyntax = "--x86-asm-syntax=att"; 3602fe6060f1SDimitry Andric else if (V == "intel") 3603fe6060f1SDimitry Andric AsmSyntax = "--x86-asm-syntax=intel"; 3604fe6060f1SDimitry Andric else 3605fe6060f1SDimitry Andric DisassemblerOptions.push_back(V.str()); 3606fe6060f1SDimitry Andric } 3607fe6060f1SDimitry Andric } 3608cb14a3feSDimitry Andric SmallVector<const char *> Args = {"llvm-objdump"}; 3609cb14a3feSDimitry Andric for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_mllvm)) 3610cb14a3feSDimitry Andric Args.push_back(A->getValue()); 3611cb14a3feSDimitry Andric if (AsmSyntax) 3612cb14a3feSDimitry Andric Args.push_back(AsmSyntax); 3613cb14a3feSDimitry Andric if (Args.size() > 1) 3614cb14a3feSDimitry Andric llvm::cl::ParseCommandLineOptions(Args.size(), Args.data()); 3615fe6060f1SDimitry Andric 3616bdd1243dSDimitry Andric // Look up any provided build IDs, then append them to the input filenames. 3617bdd1243dSDimitry Andric for (const opt::Arg *A : InputArgs.filtered(OBJDUMP_build_id)) { 3618bdd1243dSDimitry Andric object::BuildID BuildID = parseBuildIDArg(A); 3619bdd1243dSDimitry Andric std::optional<std::string> Path = BIDFetcher->fetch(BuildID); 3620bdd1243dSDimitry Andric if (!Path) { 3621bdd1243dSDimitry Andric reportCmdLineError(A->getSpelling() + ": could not find build ID '" + 3622bdd1243dSDimitry Andric A->getValue() + "'"); 3623bdd1243dSDimitry Andric } 3624bdd1243dSDimitry Andric InputFilenames.push_back(std::move(*Path)); 3625bdd1243dSDimitry Andric } 3626bdd1243dSDimitry Andric 3627fe6060f1SDimitry Andric // objdump defaults to a.out if no filenames specified. 3628fe6060f1SDimitry Andric if (InputFilenames.empty()) 3629fe6060f1SDimitry Andric InputFilenames.push_back("a.out"); 3630fe6060f1SDimitry Andric } 3631fe6060f1SDimitry Andric 36325f757f3fSDimitry Andric int llvm_objdump_main(int argc, char **argv, const llvm::ToolContext &) { 36330b57cec5SDimitry Andric using namespace llvm; 3634fe6060f1SDimitry Andric 3635fe6060f1SDimitry Andric ToolName = argv[0]; 3636fe6060f1SDimitry Andric std::unique_ptr<CommonOptTable> T; 3637fe6060f1SDimitry Andric OptSpecifier Unknown, HelpFlag, HelpHiddenFlag, VersionFlag; 3638fe6060f1SDimitry Andric 3639fe6060f1SDimitry Andric StringRef Stem = sys::path::stem(ToolName); 3640fe6060f1SDimitry Andric auto Is = [=](StringRef Tool) { 3641fe6060f1SDimitry Andric // We need to recognize the following filenames: 3642fe6060f1SDimitry Andric // 3643fe6060f1SDimitry Andric // llvm-objdump -> objdump 3644fe6060f1SDimitry Andric // llvm-otool-10.exe -> otool 3645fe6060f1SDimitry Andric // powerpc64-unknown-freebsd13-objdump -> objdump 3646fe6060f1SDimitry Andric auto I = Stem.rfind_insensitive(Tool); 3647fe6060f1SDimitry Andric return I != StringRef::npos && 3648fe6060f1SDimitry Andric (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); 3649fe6060f1SDimitry Andric }; 3650fe6060f1SDimitry Andric if (Is("otool")) { 3651fe6060f1SDimitry Andric T = std::make_unique<OtoolOptTable>(); 3652fe6060f1SDimitry Andric Unknown = OTOOL_UNKNOWN; 3653fe6060f1SDimitry Andric HelpFlag = OTOOL_help; 3654fe6060f1SDimitry Andric HelpHiddenFlag = OTOOL_help_hidden; 3655fe6060f1SDimitry Andric VersionFlag = OTOOL_version; 3656fe6060f1SDimitry Andric } else { 3657fe6060f1SDimitry Andric T = std::make_unique<ObjdumpOptTable>(); 3658fe6060f1SDimitry Andric Unknown = OBJDUMP_UNKNOWN; 3659fe6060f1SDimitry Andric HelpFlag = OBJDUMP_help; 3660fe6060f1SDimitry Andric HelpHiddenFlag = OBJDUMP_help_hidden; 3661fe6060f1SDimitry Andric VersionFlag = OBJDUMP_version; 3662fe6060f1SDimitry Andric } 3663fe6060f1SDimitry Andric 3664fe6060f1SDimitry Andric BumpPtrAllocator A; 3665fe6060f1SDimitry Andric StringSaver Saver(A); 3666fe6060f1SDimitry Andric opt::InputArgList InputArgs = 3667fe6060f1SDimitry Andric T->parseArgs(argc, argv, Unknown, Saver, 3668fe6060f1SDimitry Andric [&](StringRef Msg) { reportCmdLineError(Msg); }); 3669fe6060f1SDimitry Andric 3670fe6060f1SDimitry Andric if (InputArgs.size() == 0 || InputArgs.hasArg(HelpFlag)) { 3671fe6060f1SDimitry Andric T->printHelp(ToolName); 3672fe6060f1SDimitry Andric return 0; 3673fe6060f1SDimitry Andric } 3674fe6060f1SDimitry Andric if (InputArgs.hasArg(HelpHiddenFlag)) { 367504eeddc0SDimitry Andric T->printHelp(ToolName, /*ShowHidden=*/true); 3676fe6060f1SDimitry Andric return 0; 3677fe6060f1SDimitry Andric } 36780b57cec5SDimitry Andric 36790b57cec5SDimitry Andric // Initialize targets and assembly printers/parsers. 36800b57cec5SDimitry Andric InitializeAllTargetInfos(); 36810b57cec5SDimitry Andric InitializeAllTargetMCs(); 36820b57cec5SDimitry Andric InitializeAllDisassemblers(); 36830b57cec5SDimitry Andric 3684fe6060f1SDimitry Andric if (InputArgs.hasArg(VersionFlag)) { 3685fe6060f1SDimitry Andric cl::PrintVersionMessage(); 3686fe6060f1SDimitry Andric if (!Is("otool")) { 3687fe6060f1SDimitry Andric outs() << '\n'; 3688fe6060f1SDimitry Andric TargetRegistry::printRegisteredTargetsForVersion(outs()); 3689fe6060f1SDimitry Andric } 3690fe6060f1SDimitry Andric return 0; 3691fe6060f1SDimitry Andric } 36920b57cec5SDimitry Andric 3693bdd1243dSDimitry Andric // Initialize debuginfod. 3694bdd1243dSDimitry Andric const bool ShouldUseDebuginfodByDefault = 36951ac55f4cSDimitry Andric InputArgs.hasArg(OBJDUMP_build_id) || canUseDebuginfod(); 3696bdd1243dSDimitry Andric std::vector<std::string> DebugFileDirectories = 3697bdd1243dSDimitry Andric InputArgs.getAllArgValues(OBJDUMP_debug_file_directory); 3698bdd1243dSDimitry Andric if (InputArgs.hasFlag(OBJDUMP_debuginfod, OBJDUMP_no_debuginfod, 3699bdd1243dSDimitry Andric ShouldUseDebuginfodByDefault)) { 3700bdd1243dSDimitry Andric HTTPClient::initialize(); 3701bdd1243dSDimitry Andric BIDFetcher = 3702bdd1243dSDimitry Andric std::make_unique<DebuginfodFetcher>(std::move(DebugFileDirectories)); 3703bdd1243dSDimitry Andric } else { 3704bdd1243dSDimitry Andric BIDFetcher = 3705bdd1243dSDimitry Andric std::make_unique<BuildIDFetcher>(std::move(DebugFileDirectories)); 3706bdd1243dSDimitry Andric } 3707bdd1243dSDimitry Andric 3708fe6060f1SDimitry Andric if (Is("otool")) 3709fe6060f1SDimitry Andric parseOtoolOptions(InputArgs); 3710fe6060f1SDimitry Andric else 3711fe6060f1SDimitry Andric parseObjdumpOptions(InputArgs); 37120b57cec5SDimitry Andric 37130b57cec5SDimitry Andric if (StartAddress >= StopAddress) 37148bcb0991SDimitry Andric reportCmdLineError("start address should be less than stop address"); 37150b57cec5SDimitry Andric 3716e8d8bef9SDimitry Andric // Removes trailing separators from prefix. 3717e8d8bef9SDimitry Andric while (!Prefix.empty() && sys::path::is_separator(Prefix.back())) 3718e8d8bef9SDimitry Andric Prefix.pop_back(); 3719e8d8bef9SDimitry Andric 37200b57cec5SDimitry Andric if (AllHeaders) 37210b57cec5SDimitry Andric ArchiveHeaders = FileHeaders = PrivateHeaders = Relocations = 37220b57cec5SDimitry Andric SectionHeaders = SymbolTable = true; 37230b57cec5SDimitry Andric 372406c3fb27SDimitry Andric if (DisassembleAll || PrintSource || PrintLines || TracebackTable || 37255ffd83dbSDimitry Andric !DisassembleSymbols.empty()) 37260b57cec5SDimitry Andric Disassemble = true; 37270b57cec5SDimitry Andric 37280b57cec5SDimitry Andric if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null && 37290b57cec5SDimitry Andric !DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST && 37300b57cec5SDimitry Andric !Relocations && !SectionHeaders && !SectionContents && !SymbolTable && 373181ad6265SDimitry Andric !DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading && 3732bdd1243dSDimitry Andric !(MachOOpt && 3733bdd1243dSDimitry Andric (Bind || DataInCode || ChainedFixups || DyldInfo || DylibId || 3734bdd1243dSDimitry Andric DylibsUsed || ExportsTrie || FirstPrivateHeader || 3735bdd1243dSDimitry Andric FunctionStartsType != FunctionStartsMode::None || IndirectSymbols || 3736bdd1243dSDimitry Andric InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase || 3737bdd1243dSDimitry Andric Rpaths || UniversalHeaders || WeakBind || !FilterSections.empty()))) { 3738fe6060f1SDimitry Andric T->printHelp(ToolName); 37390b57cec5SDimitry Andric return 2; 37400b57cec5SDimitry Andric } 37410b57cec5SDimitry Andric 37425ffd83dbSDimitry Andric DisasmSymbolSet.insert(DisassembleSymbols.begin(), DisassembleSymbols.end()); 37430b57cec5SDimitry Andric 37440b57cec5SDimitry Andric llvm::for_each(InputFilenames, dumpInput); 37450b57cec5SDimitry Andric 37460b57cec5SDimitry Andric warnOnNoMatchForSections(); 37470b57cec5SDimitry Andric 37480b57cec5SDimitry Andric return EXIT_SUCCESS; 37490b57cec5SDimitry Andric } 3750