17330f729Sjoerg //===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This program is a utility that works like binutils "objdump", that is, it
107330f729Sjoerg // dumps out a plethora of information about an object file depending on the
117330f729Sjoerg // flags.
127330f729Sjoerg //
137330f729Sjoerg // The flags and output of this program should be near identical to those of
147330f729Sjoerg // binutils objdump.
157330f729Sjoerg //
167330f729Sjoerg //===----------------------------------------------------------------------===//
177330f729Sjoerg
187330f729Sjoerg #include "llvm-objdump.h"
19*82d56013Sjoerg #include "COFFDump.h"
20*82d56013Sjoerg #include "ELFDump.h"
21*82d56013Sjoerg #include "MachODump.h"
22*82d56013Sjoerg #include "ObjdumpOptID.h"
23*82d56013Sjoerg #include "SourcePrinter.h"
24*82d56013Sjoerg #include "WasmDump.h"
25*82d56013Sjoerg #include "XCOFFDump.h"
26*82d56013Sjoerg #include "llvm/ADT/IndexedMap.h"
277330f729Sjoerg #include "llvm/ADT/Optional.h"
287330f729Sjoerg #include "llvm/ADT/STLExtras.h"
297330f729Sjoerg #include "llvm/ADT/SetOperations.h"
30*82d56013Sjoerg #include "llvm/ADT/SmallSet.h"
317330f729Sjoerg #include "llvm/ADT/StringExtras.h"
327330f729Sjoerg #include "llvm/ADT/StringSet.h"
337330f729Sjoerg #include "llvm/ADT/Triple.h"
34*82d56013Sjoerg #include "llvm/ADT/Twine.h"
357330f729Sjoerg #include "llvm/DebugInfo/DWARF/DWARFContext.h"
367330f729Sjoerg #include "llvm/DebugInfo/Symbolize/Symbolize.h"
377330f729Sjoerg #include "llvm/Demangle/Demangle.h"
387330f729Sjoerg #include "llvm/MC/MCAsmInfo.h"
397330f729Sjoerg #include "llvm/MC/MCContext.h"
407330f729Sjoerg #include "llvm/MC/MCDisassembler/MCDisassembler.h"
417330f729Sjoerg #include "llvm/MC/MCDisassembler/MCRelocationInfo.h"
427330f729Sjoerg #include "llvm/MC/MCInst.h"
437330f729Sjoerg #include "llvm/MC/MCInstPrinter.h"
447330f729Sjoerg #include "llvm/MC/MCInstrAnalysis.h"
457330f729Sjoerg #include "llvm/MC/MCInstrInfo.h"
467330f729Sjoerg #include "llvm/MC/MCObjectFileInfo.h"
477330f729Sjoerg #include "llvm/MC/MCRegisterInfo.h"
487330f729Sjoerg #include "llvm/MC/MCSubtargetInfo.h"
497330f729Sjoerg #include "llvm/MC/MCTargetOptions.h"
507330f729Sjoerg #include "llvm/Object/Archive.h"
517330f729Sjoerg #include "llvm/Object/COFF.h"
527330f729Sjoerg #include "llvm/Object/COFFImportFile.h"
537330f729Sjoerg #include "llvm/Object/ELFObjectFile.h"
54*82d56013Sjoerg #include "llvm/Object/FaultMapParser.h"
557330f729Sjoerg #include "llvm/Object/MachO.h"
567330f729Sjoerg #include "llvm/Object/MachOUniversal.h"
577330f729Sjoerg #include "llvm/Object/ObjectFile.h"
587330f729Sjoerg #include "llvm/Object/Wasm.h"
59*82d56013Sjoerg #include "llvm/Option/Arg.h"
60*82d56013Sjoerg #include "llvm/Option/ArgList.h"
61*82d56013Sjoerg #include "llvm/Option/Option.h"
627330f729Sjoerg #include "llvm/Support/Casting.h"
637330f729Sjoerg #include "llvm/Support/Debug.h"
647330f729Sjoerg #include "llvm/Support/Errc.h"
657330f729Sjoerg #include "llvm/Support/FileSystem.h"
667330f729Sjoerg #include "llvm/Support/Format.h"
677330f729Sjoerg #include "llvm/Support/FormatVariadic.h"
687330f729Sjoerg #include "llvm/Support/GraphWriter.h"
697330f729Sjoerg #include "llvm/Support/Host.h"
707330f729Sjoerg #include "llvm/Support/InitLLVM.h"
717330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
727330f729Sjoerg #include "llvm/Support/SourceMgr.h"
737330f729Sjoerg #include "llvm/Support/StringSaver.h"
747330f729Sjoerg #include "llvm/Support/TargetRegistry.h"
757330f729Sjoerg #include "llvm/Support/TargetSelect.h"
767330f729Sjoerg #include "llvm/Support/WithColor.h"
777330f729Sjoerg #include "llvm/Support/raw_ostream.h"
787330f729Sjoerg #include <algorithm>
797330f729Sjoerg #include <cctype>
807330f729Sjoerg #include <cstring>
817330f729Sjoerg #include <system_error>
827330f729Sjoerg #include <unordered_map>
837330f729Sjoerg #include <utility>
847330f729Sjoerg
85*82d56013Sjoerg using namespace llvm;
867330f729Sjoerg using namespace llvm::object;
87*82d56013Sjoerg using namespace llvm::objdump;
88*82d56013Sjoerg using namespace llvm::opt;
897330f729Sjoerg
90*82d56013Sjoerg namespace {
917330f729Sjoerg
92*82d56013Sjoerg class CommonOptTable : public opt::OptTable {
93*82d56013Sjoerg public:
CommonOptTable(ArrayRef<Info> OptionInfos,const char * Usage,const char * Description)94*82d56013Sjoerg CommonOptTable(ArrayRef<Info> OptionInfos, const char *Usage,
95*82d56013Sjoerg const char *Description)
96*82d56013Sjoerg : OptTable(OptionInfos), Usage(Usage), Description(Description) {
97*82d56013Sjoerg setGroupedShortOptions(true);
98*82d56013Sjoerg }
997330f729Sjoerg
printHelp(StringRef Argv0,bool ShowHidden=false) const100*82d56013Sjoerg void printHelp(StringRef Argv0, bool ShowHidden = false) const {
101*82d56013Sjoerg Argv0 = sys::path::filename(Argv0);
102*82d56013Sjoerg PrintHelp(outs(), (Argv0 + Usage).str().c_str(), Description, ShowHidden,
103*82d56013Sjoerg ShowHidden);
104*82d56013Sjoerg // TODO Replace this with OptTable API once it adds extrahelp support.
105*82d56013Sjoerg outs() << "\nPass @FILE as argument to read options from FILE.\n";
106*82d56013Sjoerg }
1077330f729Sjoerg
108*82d56013Sjoerg private:
109*82d56013Sjoerg const char *Usage;
110*82d56013Sjoerg const char *Description;
111*82d56013Sjoerg };
1127330f729Sjoerg
113*82d56013Sjoerg // ObjdumpOptID is in ObjdumpOptID.h
1147330f729Sjoerg
115*82d56013Sjoerg #define PREFIX(NAME, VALUE) const char *const OBJDUMP_##NAME[] = VALUE;
116*82d56013Sjoerg #include "ObjdumpOpts.inc"
117*82d56013Sjoerg #undef PREFIX
1187330f729Sjoerg
119*82d56013Sjoerg static constexpr opt::OptTable::Info ObjdumpInfoTable[] = {
120*82d56013Sjoerg #define OBJDUMP_nullptr nullptr
121*82d56013Sjoerg #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
122*82d56013Sjoerg HELPTEXT, METAVAR, VALUES) \
123*82d56013Sjoerg {OBJDUMP_##PREFIX, NAME, HELPTEXT, \
124*82d56013Sjoerg METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \
125*82d56013Sjoerg PARAM, FLAGS, OBJDUMP_##GROUP, \
126*82d56013Sjoerg OBJDUMP_##ALIAS, ALIASARGS, VALUES},
127*82d56013Sjoerg #include "ObjdumpOpts.inc"
128*82d56013Sjoerg #undef OPTION
129*82d56013Sjoerg #undef OBJDUMP_nullptr
130*82d56013Sjoerg };
1317330f729Sjoerg
132*82d56013Sjoerg class ObjdumpOptTable : public CommonOptTable {
133*82d56013Sjoerg public:
ObjdumpOptTable()134*82d56013Sjoerg ObjdumpOptTable()
135*82d56013Sjoerg : CommonOptTable(ObjdumpInfoTable, " [options] <input object files>",
136*82d56013Sjoerg "llvm object file dumper") {}
137*82d56013Sjoerg };
1387330f729Sjoerg
139*82d56013Sjoerg enum OtoolOptID {
140*82d56013Sjoerg OTOOL_INVALID = 0, // This is not an option ID.
141*82d56013Sjoerg #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
142*82d56013Sjoerg HELPTEXT, METAVAR, VALUES) \
143*82d56013Sjoerg OTOOL_##ID,
144*82d56013Sjoerg #include "OtoolOpts.inc"
145*82d56013Sjoerg #undef OPTION
146*82d56013Sjoerg };
1477330f729Sjoerg
148*82d56013Sjoerg #define PREFIX(NAME, VALUE) const char *const OTOOL_##NAME[] = VALUE;
149*82d56013Sjoerg #include "OtoolOpts.inc"
150*82d56013Sjoerg #undef PREFIX
1517330f729Sjoerg
152*82d56013Sjoerg static constexpr opt::OptTable::Info OtoolInfoTable[] = {
153*82d56013Sjoerg #define OTOOL_nullptr nullptr
154*82d56013Sjoerg #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
155*82d56013Sjoerg HELPTEXT, METAVAR, VALUES) \
156*82d56013Sjoerg {OTOOL_##PREFIX, NAME, HELPTEXT, \
157*82d56013Sjoerg METAVAR, OTOOL_##ID, opt::Option::KIND##Class, \
158*82d56013Sjoerg PARAM, FLAGS, OTOOL_##GROUP, \
159*82d56013Sjoerg OTOOL_##ALIAS, ALIASARGS, VALUES},
160*82d56013Sjoerg #include "OtoolOpts.inc"
161*82d56013Sjoerg #undef OPTION
162*82d56013Sjoerg #undef OTOOL_nullptr
163*82d56013Sjoerg };
1647330f729Sjoerg
165*82d56013Sjoerg class OtoolOptTable : public CommonOptTable {
166*82d56013Sjoerg public:
OtoolOptTable()167*82d56013Sjoerg OtoolOptTable()
168*82d56013Sjoerg : CommonOptTable(OtoolInfoTable, " [option...] [file...]",
169*82d56013Sjoerg "Mach-O object file displaying tool") {}
170*82d56013Sjoerg };
1717330f729Sjoerg
172*82d56013Sjoerg } // namespace
1737330f729Sjoerg
174*82d56013Sjoerg #define DEBUG_TYPE "objdump"
1757330f729Sjoerg
176*82d56013Sjoerg static uint64_t AdjustVMA;
177*82d56013Sjoerg static bool AllHeaders;
178*82d56013Sjoerg static std::string ArchName;
179*82d56013Sjoerg bool objdump::ArchiveHeaders;
180*82d56013Sjoerg bool objdump::Demangle;
181*82d56013Sjoerg bool objdump::Disassemble;
182*82d56013Sjoerg bool objdump::DisassembleAll;
183*82d56013Sjoerg bool objdump::SymbolDescription;
184*82d56013Sjoerg static std::vector<std::string> DisassembleSymbols;
185*82d56013Sjoerg static bool DisassembleZeroes;
186*82d56013Sjoerg static std::vector<std::string> DisassemblerOptions;
187*82d56013Sjoerg DIDumpType objdump::DwarfDumpType;
188*82d56013Sjoerg static bool DynamicRelocations;
189*82d56013Sjoerg static bool FaultMapSection;
190*82d56013Sjoerg static bool FileHeaders;
191*82d56013Sjoerg bool objdump::SectionContents;
192*82d56013Sjoerg static std::vector<std::string> InputFilenames;
193*82d56013Sjoerg bool objdump::PrintLines;
194*82d56013Sjoerg static bool MachOOpt;
195*82d56013Sjoerg std::string objdump::MCPU;
196*82d56013Sjoerg std::vector<std::string> objdump::MAttrs;
197*82d56013Sjoerg bool objdump::ShowRawInsn;
198*82d56013Sjoerg bool objdump::LeadingAddr;
199*82d56013Sjoerg static bool RawClangAST;
200*82d56013Sjoerg bool objdump::Relocations;
201*82d56013Sjoerg bool objdump::PrintImmHex;
202*82d56013Sjoerg bool objdump::PrivateHeaders;
203*82d56013Sjoerg std::vector<std::string> objdump::FilterSections;
204*82d56013Sjoerg bool objdump::SectionHeaders;
205*82d56013Sjoerg static bool ShowLMA;
206*82d56013Sjoerg bool objdump::PrintSource;
2077330f729Sjoerg
208*82d56013Sjoerg static uint64_t StartAddress;
209*82d56013Sjoerg static bool HasStartAddressFlag;
210*82d56013Sjoerg static uint64_t StopAddress = UINT64_MAX;
211*82d56013Sjoerg static bool HasStopAddressFlag;
2127330f729Sjoerg
213*82d56013Sjoerg bool objdump::SymbolTable;
214*82d56013Sjoerg static bool SymbolizeOperands;
215*82d56013Sjoerg static bool DynamicSymbolTable;
216*82d56013Sjoerg std::string objdump::TripleName;
217*82d56013Sjoerg bool objdump::UnwindInfo;
218*82d56013Sjoerg static bool Wide;
219*82d56013Sjoerg std::string objdump::Prefix;
220*82d56013Sjoerg uint32_t objdump::PrefixStrip;
2217330f729Sjoerg
222*82d56013Sjoerg DebugVarsFormat objdump::DbgVariables = DVDisabled;
2237330f729Sjoerg
224*82d56013Sjoerg int objdump::DbgIndent = 40;
2257330f729Sjoerg
226*82d56013Sjoerg static StringSet<> DisasmSymbolSet;
227*82d56013Sjoerg StringSet<> objdump::FoundSectionSet;
2287330f729Sjoerg static StringRef ToolName;
2297330f729Sjoerg
2307330f729Sjoerg namespace {
2317330f729Sjoerg struct FilterResult {
2327330f729Sjoerg // True if the section should not be skipped.
2337330f729Sjoerg bool Keep;
2347330f729Sjoerg
2357330f729Sjoerg // True if the index counter should be incremented, even if the section should
2367330f729Sjoerg // be skipped. For example, sections may be skipped if they are not included
2377330f729Sjoerg // in the --section flag, but we still want those to count toward the section
2387330f729Sjoerg // count.
2397330f729Sjoerg bool IncrementIndex;
2407330f729Sjoerg };
2417330f729Sjoerg } // namespace
2427330f729Sjoerg
checkSectionFilter(object::SectionRef S)2437330f729Sjoerg static FilterResult checkSectionFilter(object::SectionRef S) {
2447330f729Sjoerg if (FilterSections.empty())
2457330f729Sjoerg return {/*Keep=*/true, /*IncrementIndex=*/true};
2467330f729Sjoerg
2477330f729Sjoerg Expected<StringRef> SecNameOrErr = S.getName();
2487330f729Sjoerg if (!SecNameOrErr) {
2497330f729Sjoerg consumeError(SecNameOrErr.takeError());
2507330f729Sjoerg return {/*Keep=*/false, /*IncrementIndex=*/false};
2517330f729Sjoerg }
2527330f729Sjoerg StringRef SecName = *SecNameOrErr;
2537330f729Sjoerg
2547330f729Sjoerg // StringSet does not allow empty key so avoid adding sections with
2557330f729Sjoerg // no name (such as the section with index 0) here.
2567330f729Sjoerg if (!SecName.empty())
2577330f729Sjoerg FoundSectionSet.insert(SecName);
2587330f729Sjoerg
2597330f729Sjoerg // Only show the section if it's in the FilterSections list, but always
2607330f729Sjoerg // increment so the indexing is stable.
2617330f729Sjoerg return {/*Keep=*/is_contained(FilterSections, SecName),
2627330f729Sjoerg /*IncrementIndex=*/true};
2637330f729Sjoerg }
2647330f729Sjoerg
ToolSectionFilter(object::ObjectFile const & O,uint64_t * Idx)265*82d56013Sjoerg SectionFilter objdump::ToolSectionFilter(object::ObjectFile const &O,
266*82d56013Sjoerg uint64_t *Idx) {
2677330f729Sjoerg // Start at UINT64_MAX so that the first index returned after an increment is
2687330f729Sjoerg // zero (after the unsigned wrap).
2697330f729Sjoerg if (Idx)
2707330f729Sjoerg *Idx = UINT64_MAX;
2717330f729Sjoerg return SectionFilter(
2727330f729Sjoerg [Idx](object::SectionRef S) {
2737330f729Sjoerg FilterResult Result = checkSectionFilter(S);
2747330f729Sjoerg if (Idx != nullptr && Result.IncrementIndex)
2757330f729Sjoerg *Idx += 1;
2767330f729Sjoerg return Result.Keep;
2777330f729Sjoerg },
2787330f729Sjoerg O);
2797330f729Sjoerg }
2807330f729Sjoerg
getFileNameForError(const object::Archive::Child & C,unsigned Index)281*82d56013Sjoerg std::string objdump::getFileNameForError(const object::Archive::Child &C,
2827330f729Sjoerg unsigned Index) {
2837330f729Sjoerg Expected<StringRef> NameOrErr = C.getName();
2847330f729Sjoerg if (NameOrErr)
285*82d56013Sjoerg return std::string(NameOrErr.get());
2867330f729Sjoerg // If we have an error getting the name then we print the index of the archive
2877330f729Sjoerg // member. Since we are already in an error state, we just ignore this error.
2887330f729Sjoerg consumeError(NameOrErr.takeError());
2897330f729Sjoerg return "<file index: " + std::to_string(Index) + ">";
2907330f729Sjoerg }
2917330f729Sjoerg
reportWarning(const Twine & Message,StringRef File)292*82d56013Sjoerg void objdump::reportWarning(const Twine &Message, StringRef File) {
2937330f729Sjoerg // Output order between errs() and outs() matters especially for archive
2947330f729Sjoerg // files where the output is per member object.
2957330f729Sjoerg outs().flush();
2967330f729Sjoerg WithColor::warning(errs(), ToolName)
2977330f729Sjoerg << "'" << File << "': " << Message << "\n";
2987330f729Sjoerg }
2997330f729Sjoerg
reportError(StringRef File,const Twine & Message)300*82d56013Sjoerg LLVM_ATTRIBUTE_NORETURN void objdump::reportError(StringRef File,
301*82d56013Sjoerg const Twine &Message) {
302*82d56013Sjoerg outs().flush();
3037330f729Sjoerg WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n";
3047330f729Sjoerg exit(1);
3057330f729Sjoerg }
3067330f729Sjoerg
reportError(Error E,StringRef FileName,StringRef ArchiveName,StringRef ArchitectureName)307*82d56013Sjoerg LLVM_ATTRIBUTE_NORETURN void objdump::reportError(Error E, StringRef FileName,
3087330f729Sjoerg StringRef ArchiveName,
3097330f729Sjoerg StringRef ArchitectureName) {
3107330f729Sjoerg assert(E);
311*82d56013Sjoerg outs().flush();
3127330f729Sjoerg WithColor::error(errs(), ToolName);
3137330f729Sjoerg if (ArchiveName != "")
3147330f729Sjoerg errs() << ArchiveName << "(" << FileName << ")";
3157330f729Sjoerg else
3167330f729Sjoerg errs() << "'" << FileName << "'";
3177330f729Sjoerg if (!ArchitectureName.empty())
3187330f729Sjoerg errs() << " (for architecture " << ArchitectureName << ")";
319*82d56013Sjoerg errs() << ": ";
320*82d56013Sjoerg logAllUnhandledErrors(std::move(E), errs());
3217330f729Sjoerg exit(1);
3227330f729Sjoerg }
3237330f729Sjoerg
reportCmdLineWarning(const Twine & Message)324*82d56013Sjoerg static void reportCmdLineWarning(const Twine &Message) {
3257330f729Sjoerg WithColor::warning(errs(), ToolName) << Message << "\n";
3267330f729Sjoerg }
3277330f729Sjoerg
reportCmdLineError(const Twine & Message)328*82d56013Sjoerg LLVM_ATTRIBUTE_NORETURN static void reportCmdLineError(const Twine &Message) {
3297330f729Sjoerg WithColor::error(errs(), ToolName) << Message << "\n";
3307330f729Sjoerg exit(1);
3317330f729Sjoerg }
3327330f729Sjoerg
warnOnNoMatchForSections()3337330f729Sjoerg static void warnOnNoMatchForSections() {
3347330f729Sjoerg SetVector<StringRef> MissingSections;
3357330f729Sjoerg for (StringRef S : FilterSections) {
3367330f729Sjoerg if (FoundSectionSet.count(S))
3377330f729Sjoerg return;
3387330f729Sjoerg // User may specify a unnamed section. Don't warn for it.
3397330f729Sjoerg if (!S.empty())
3407330f729Sjoerg MissingSections.insert(S);
3417330f729Sjoerg }
3427330f729Sjoerg
3437330f729Sjoerg // Warn only if no section in FilterSections is matched.
3447330f729Sjoerg for (StringRef S : MissingSections)
3457330f729Sjoerg reportCmdLineWarning("section '" + S +
3467330f729Sjoerg "' mentioned in a -j/--section option, but not "
3477330f729Sjoerg "found in any input file");
3487330f729Sjoerg }
3497330f729Sjoerg
getTarget(const ObjectFile * Obj)3507330f729Sjoerg static const Target *getTarget(const ObjectFile *Obj) {
3517330f729Sjoerg // Figure out the target triple.
3527330f729Sjoerg Triple TheTriple("unknown-unknown-unknown");
3537330f729Sjoerg if (TripleName.empty()) {
3547330f729Sjoerg TheTriple = Obj->makeTriple();
3557330f729Sjoerg } else {
3567330f729Sjoerg TheTriple.setTriple(Triple::normalize(TripleName));
3577330f729Sjoerg auto Arch = Obj->getArch();
3587330f729Sjoerg if (Arch == Triple::arm || Arch == Triple::armeb)
3597330f729Sjoerg Obj->setARMSubArch(TheTriple);
3607330f729Sjoerg }
3617330f729Sjoerg
3627330f729Sjoerg // Get the target specific parser.
3637330f729Sjoerg std::string Error;
3647330f729Sjoerg const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
3657330f729Sjoerg Error);
3667330f729Sjoerg if (!TheTarget)
3677330f729Sjoerg reportError(Obj->getFileName(), "can't find target: " + Error);
3687330f729Sjoerg
3697330f729Sjoerg // Update the triple name and return the found target.
3707330f729Sjoerg TripleName = TheTriple.getTriple();
3717330f729Sjoerg return TheTarget;
3727330f729Sjoerg }
3737330f729Sjoerg
isRelocAddressLess(RelocationRef A,RelocationRef B)374*82d56013Sjoerg bool objdump::isRelocAddressLess(RelocationRef A, RelocationRef B) {
3757330f729Sjoerg return A.getOffset() < B.getOffset();
3767330f729Sjoerg }
3777330f729Sjoerg
getRelocationValueString(const RelocationRef & Rel,SmallVectorImpl<char> & Result)3787330f729Sjoerg static Error getRelocationValueString(const RelocationRef &Rel,
3797330f729Sjoerg SmallVectorImpl<char> &Result) {
3807330f729Sjoerg const ObjectFile *Obj = Rel.getObject();
3817330f729Sjoerg if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj))
3827330f729Sjoerg return getELFRelocationValueString(ELF, Rel, Result);
3837330f729Sjoerg if (auto *COFF = dyn_cast<COFFObjectFile>(Obj))
3847330f729Sjoerg return getCOFFRelocationValueString(COFF, Rel, Result);
3857330f729Sjoerg if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj))
3867330f729Sjoerg return getWasmRelocationValueString(Wasm, Rel, Result);
3877330f729Sjoerg if (auto *MachO = dyn_cast<MachOObjectFile>(Obj))
3887330f729Sjoerg return getMachORelocationValueString(MachO, Rel, Result);
389*82d56013Sjoerg if (auto *XCOFF = dyn_cast<XCOFFObjectFile>(Obj))
390*82d56013Sjoerg return getXCOFFRelocationValueString(XCOFF, Rel, Result);
3917330f729Sjoerg llvm_unreachable("unknown object file format");
3927330f729Sjoerg }
3937330f729Sjoerg
3947330f729Sjoerg /// Indicates whether this relocation should hidden when listing
3957330f729Sjoerg /// relocations, usually because it is the trailing part of a multipart
3967330f729Sjoerg /// relocation that will be printed as part of the leading relocation.
getHidden(RelocationRef RelRef)3977330f729Sjoerg static bool getHidden(RelocationRef RelRef) {
3987330f729Sjoerg auto *MachO = dyn_cast<MachOObjectFile>(RelRef.getObject());
3997330f729Sjoerg if (!MachO)
4007330f729Sjoerg return false;
4017330f729Sjoerg
4027330f729Sjoerg unsigned Arch = MachO->getArch();
4037330f729Sjoerg DataRefImpl Rel = RelRef.getRawDataRefImpl();
4047330f729Sjoerg uint64_t Type = MachO->getRelocationType(Rel);
4057330f729Sjoerg
4067330f729Sjoerg // On arches that use the generic relocations, GENERIC_RELOC_PAIR
4077330f729Sjoerg // is always hidden.
4087330f729Sjoerg if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc)
4097330f729Sjoerg return Type == MachO::GENERIC_RELOC_PAIR;
4107330f729Sjoerg
4117330f729Sjoerg if (Arch == Triple::x86_64) {
4127330f729Sjoerg // On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows
4137330f729Sjoerg // an X86_64_RELOC_SUBTRACTOR.
4147330f729Sjoerg if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) {
4157330f729Sjoerg DataRefImpl RelPrev = Rel;
4167330f729Sjoerg RelPrev.d.a--;
4177330f729Sjoerg uint64_t PrevType = MachO->getRelocationType(RelPrev);
4187330f729Sjoerg if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR)
4197330f729Sjoerg return true;
4207330f729Sjoerg }
4217330f729Sjoerg }
4227330f729Sjoerg
4237330f729Sjoerg return false;
4247330f729Sjoerg }
4257330f729Sjoerg
4267330f729Sjoerg namespace {
4277330f729Sjoerg
428*82d56013Sjoerg /// Get the column at which we want to start printing the instruction
429*82d56013Sjoerg /// disassembly, taking into account anything which appears to the left of it.
getInstStartColumn(const MCSubtargetInfo & STI)430*82d56013Sjoerg unsigned getInstStartColumn(const MCSubtargetInfo &STI) {
431*82d56013Sjoerg return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24;
4327330f729Sjoerg }
4337330f729Sjoerg
isAArch64Elf(const ObjectFile * Obj)4347330f729Sjoerg static bool isAArch64Elf(const ObjectFile *Obj) {
4357330f729Sjoerg const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);
4367330f729Sjoerg return Elf && Elf->getEMachine() == ELF::EM_AARCH64;
4377330f729Sjoerg }
4387330f729Sjoerg
isArmElf(const ObjectFile * Obj)4397330f729Sjoerg static bool isArmElf(const ObjectFile *Obj) {
4407330f729Sjoerg const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);
4417330f729Sjoerg return Elf && Elf->getEMachine() == ELF::EM_ARM;
4427330f729Sjoerg }
4437330f729Sjoerg
hasMappingSymbols(const ObjectFile * Obj)4447330f729Sjoerg static bool hasMappingSymbols(const ObjectFile *Obj) {
4457330f729Sjoerg return isArmElf(Obj) || isAArch64Elf(Obj);
4467330f729Sjoerg }
4477330f729Sjoerg
printRelocation(formatted_raw_ostream & OS,StringRef FileName,const RelocationRef & Rel,uint64_t Address,bool Is64Bits)448*82d56013Sjoerg static void printRelocation(formatted_raw_ostream &OS, StringRef FileName,
449*82d56013Sjoerg const RelocationRef &Rel, uint64_t Address,
450*82d56013Sjoerg bool Is64Bits) {
4517330f729Sjoerg StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64 ": " : "\t\t\t%08" PRIx64 ": ";
4527330f729Sjoerg SmallString<16> Name;
4537330f729Sjoerg SmallString<32> Val;
4547330f729Sjoerg Rel.getTypeName(Name);
4557330f729Sjoerg if (Error E = getRelocationValueString(Rel, Val))
4567330f729Sjoerg reportError(std::move(E), FileName);
457*82d56013Sjoerg OS << format(Fmt.data(), Address) << Name << "\t" << Val;
4587330f729Sjoerg }
4597330f729Sjoerg
4607330f729Sjoerg class PrettyPrinter {
4617330f729Sjoerg public:
4627330f729Sjoerg virtual ~PrettyPrinter() = default;
463*82d56013Sjoerg virtual void
printInst(MCInstPrinter & IP,const MCInst * MI,ArrayRef<uint8_t> Bytes,object::SectionedAddress Address,formatted_raw_ostream & OS,StringRef Annot,MCSubtargetInfo const & STI,SourcePrinter * SP,StringRef ObjectFilename,std::vector<RelocationRef> * Rels,LiveVariablePrinter & LVP)464*82d56013Sjoerg printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
465*82d56013Sjoerg object::SectionedAddress Address, formatted_raw_ostream &OS,
466*82d56013Sjoerg StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
467*82d56013Sjoerg StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
468*82d56013Sjoerg LiveVariablePrinter &LVP) {
4697330f729Sjoerg if (SP && (PrintSource || PrintLines))
470*82d56013Sjoerg SP->printSourceLine(OS, Address, ObjectFilename, LVP);
471*82d56013Sjoerg LVP.printBetweenInsts(OS, false);
4727330f729Sjoerg
4737330f729Sjoerg size_t Start = OS.tell();
474*82d56013Sjoerg if (LeadingAddr)
4757330f729Sjoerg OS << format("%8" PRIx64 ":", Address.Address);
476*82d56013Sjoerg if (ShowRawInsn) {
4777330f729Sjoerg OS << ' ';
4787330f729Sjoerg dumpBytes(Bytes, OS);
4797330f729Sjoerg }
4807330f729Sjoerg
4817330f729Sjoerg // The output of printInst starts with a tab. Print some spaces so that
4827330f729Sjoerg // the tab has 1 column and advances to the target tab stop.
483*82d56013Sjoerg unsigned TabStop = getInstStartColumn(STI);
4847330f729Sjoerg unsigned Column = OS.tell() - Start;
4857330f729Sjoerg OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8);
4867330f729Sjoerg
487*82d56013Sjoerg if (MI) {
488*82d56013Sjoerg // See MCInstPrinter::printInst. On targets where a PC relative immediate
489*82d56013Sjoerg // is relative to the next instruction and the length of a MCInst is
490*82d56013Sjoerg // difficult to measure (x86), this is the address of the next
491*82d56013Sjoerg // instruction.
492*82d56013Sjoerg uint64_t Addr =
493*82d56013Sjoerg Address.Address + (STI.getTargetTriple().isX86() ? Bytes.size() : 0);
494*82d56013Sjoerg IP.printInst(MI, Addr, "", STI, OS);
495*82d56013Sjoerg } else
4967330f729Sjoerg OS << "\t<unknown>";
4977330f729Sjoerg }
4987330f729Sjoerg };
4997330f729Sjoerg PrettyPrinter PrettyPrinterInst;
5007330f729Sjoerg
5017330f729Sjoerg class HexagonPrettyPrinter : public PrettyPrinter {
5027330f729Sjoerg public:
printLead(ArrayRef<uint8_t> Bytes,uint64_t Address,formatted_raw_ostream & OS)5037330f729Sjoerg void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address,
504*82d56013Sjoerg formatted_raw_ostream &OS) {
5057330f729Sjoerg uint32_t opcode =
5067330f729Sjoerg (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0];
507*82d56013Sjoerg if (LeadingAddr)
5087330f729Sjoerg OS << format("%8" PRIx64 ":", Address);
509*82d56013Sjoerg if (ShowRawInsn) {
5107330f729Sjoerg OS << "\t";
5117330f729Sjoerg dumpBytes(Bytes.slice(0, 4), OS);
5127330f729Sjoerg OS << format("\t%08" PRIx32, opcode);
5137330f729Sjoerg }
5147330f729Sjoerg }
printInst(MCInstPrinter & IP,const MCInst * MI,ArrayRef<uint8_t> Bytes,object::SectionedAddress Address,formatted_raw_ostream & OS,StringRef Annot,MCSubtargetInfo const & STI,SourcePrinter * SP,StringRef ObjectFilename,std::vector<RelocationRef> * Rels,LiveVariablePrinter & LVP)5157330f729Sjoerg void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
516*82d56013Sjoerg object::SectionedAddress Address, formatted_raw_ostream &OS,
5177330f729Sjoerg StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
518*82d56013Sjoerg StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
519*82d56013Sjoerg LiveVariablePrinter &LVP) override {
5207330f729Sjoerg if (SP && (PrintSource || PrintLines))
521*82d56013Sjoerg SP->printSourceLine(OS, Address, ObjectFilename, LVP, "");
5227330f729Sjoerg if (!MI) {
5237330f729Sjoerg printLead(Bytes, Address.Address, OS);
5247330f729Sjoerg OS << " <unknown>";
5257330f729Sjoerg return;
5267330f729Sjoerg }
5277330f729Sjoerg std::string Buffer;
5287330f729Sjoerg {
5297330f729Sjoerg raw_string_ostream TempStream(Buffer);
530*82d56013Sjoerg IP.printInst(MI, Address.Address, "", STI, TempStream);
5317330f729Sjoerg }
5327330f729Sjoerg StringRef Contents(Buffer);
5337330f729Sjoerg // Split off bundle attributes
5347330f729Sjoerg auto PacketBundle = Contents.rsplit('\n');
5357330f729Sjoerg // Split off first instruction from the rest
5367330f729Sjoerg auto HeadTail = PacketBundle.first.split('\n');
5377330f729Sjoerg auto Preamble = " { ";
5387330f729Sjoerg auto Separator = "";
5397330f729Sjoerg
5407330f729Sjoerg // Hexagon's packets require relocations to be inline rather than
5417330f729Sjoerg // clustered at the end of the packet.
5427330f729Sjoerg std::vector<RelocationRef>::const_iterator RelCur = Rels->begin();
5437330f729Sjoerg std::vector<RelocationRef>::const_iterator RelEnd = Rels->end();
5447330f729Sjoerg auto PrintReloc = [&]() -> void {
5457330f729Sjoerg while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) {
5467330f729Sjoerg if (RelCur->getOffset() == Address.Address) {
547*82d56013Sjoerg printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false);
5487330f729Sjoerg return;
5497330f729Sjoerg }
5507330f729Sjoerg ++RelCur;
5517330f729Sjoerg }
5527330f729Sjoerg };
5537330f729Sjoerg
5547330f729Sjoerg while (!HeadTail.first.empty()) {
5557330f729Sjoerg OS << Separator;
5567330f729Sjoerg Separator = "\n";
5577330f729Sjoerg if (SP && (PrintSource || PrintLines))
558*82d56013Sjoerg SP->printSourceLine(OS, Address, ObjectFilename, LVP, "");
5597330f729Sjoerg printLead(Bytes, Address.Address, OS);
5607330f729Sjoerg OS << Preamble;
5617330f729Sjoerg Preamble = " ";
5627330f729Sjoerg StringRef Inst;
5637330f729Sjoerg auto Duplex = HeadTail.first.split('\v');
5647330f729Sjoerg if (!Duplex.second.empty()) {
5657330f729Sjoerg OS << Duplex.first;
5667330f729Sjoerg OS << "; ";
5677330f729Sjoerg Inst = Duplex.second;
5687330f729Sjoerg }
5697330f729Sjoerg else
5707330f729Sjoerg Inst = HeadTail.first;
5717330f729Sjoerg OS << Inst;
5727330f729Sjoerg HeadTail = HeadTail.second.split('\n');
5737330f729Sjoerg if (HeadTail.first.empty())
5747330f729Sjoerg OS << " } " << PacketBundle.second;
5757330f729Sjoerg PrintReloc();
5767330f729Sjoerg Bytes = Bytes.slice(4);
5777330f729Sjoerg Address.Address += 4;
5787330f729Sjoerg }
5797330f729Sjoerg }
5807330f729Sjoerg };
5817330f729Sjoerg HexagonPrettyPrinter HexagonPrettyPrinterInst;
5827330f729Sjoerg
5837330f729Sjoerg class AMDGCNPrettyPrinter : public PrettyPrinter {
5847330f729Sjoerg public:
printInst(MCInstPrinter & IP,const MCInst * MI,ArrayRef<uint8_t> Bytes,object::SectionedAddress Address,formatted_raw_ostream & OS,StringRef Annot,MCSubtargetInfo const & STI,SourcePrinter * SP,StringRef ObjectFilename,std::vector<RelocationRef> * Rels,LiveVariablePrinter & LVP)5857330f729Sjoerg void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
586*82d56013Sjoerg object::SectionedAddress Address, formatted_raw_ostream &OS,
5877330f729Sjoerg StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
588*82d56013Sjoerg StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
589*82d56013Sjoerg LiveVariablePrinter &LVP) override {
5907330f729Sjoerg if (SP && (PrintSource || PrintLines))
591*82d56013Sjoerg SP->printSourceLine(OS, Address, ObjectFilename, LVP);
5927330f729Sjoerg
5937330f729Sjoerg if (MI) {
5947330f729Sjoerg SmallString<40> InstStr;
5957330f729Sjoerg raw_svector_ostream IS(InstStr);
5967330f729Sjoerg
597*82d56013Sjoerg IP.printInst(MI, Address.Address, "", STI, IS);
5987330f729Sjoerg
5997330f729Sjoerg OS << left_justify(IS.str(), 60);
6007330f729Sjoerg } else {
6017330f729Sjoerg // an unrecognized encoding - this is probably data so represent it
6027330f729Sjoerg // using the .long directive, or .byte directive if fewer than 4 bytes
6037330f729Sjoerg // remaining
6047330f729Sjoerg if (Bytes.size() >= 4) {
6057330f729Sjoerg OS << format("\t.long 0x%08" PRIx32 " ",
6067330f729Sjoerg support::endian::read32<support::little>(Bytes.data()));
6077330f729Sjoerg OS.indent(42);
6087330f729Sjoerg } else {
6097330f729Sjoerg OS << format("\t.byte 0x%02" PRIx8, Bytes[0]);
6107330f729Sjoerg for (unsigned int i = 1; i < Bytes.size(); i++)
6117330f729Sjoerg OS << format(", 0x%02" PRIx8, Bytes[i]);
6127330f729Sjoerg OS.indent(55 - (6 * Bytes.size()));
6137330f729Sjoerg }
6147330f729Sjoerg }
6157330f729Sjoerg
6167330f729Sjoerg OS << format("// %012" PRIX64 ":", Address.Address);
6177330f729Sjoerg if (Bytes.size() >= 4) {
6187330f729Sjoerg // D should be casted to uint32_t here as it is passed by format to
6197330f729Sjoerg // snprintf as vararg.
6207330f729Sjoerg for (uint32_t D : makeArrayRef(
6217330f729Sjoerg reinterpret_cast<const support::little32_t *>(Bytes.data()),
6227330f729Sjoerg Bytes.size() / 4))
6237330f729Sjoerg OS << format(" %08" PRIX32, D);
6247330f729Sjoerg } else {
6257330f729Sjoerg for (unsigned char B : Bytes)
6267330f729Sjoerg OS << format(" %02" PRIX8, B);
6277330f729Sjoerg }
6287330f729Sjoerg
6297330f729Sjoerg if (!Annot.empty())
6307330f729Sjoerg OS << " // " << Annot;
6317330f729Sjoerg }
6327330f729Sjoerg };
6337330f729Sjoerg AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst;
6347330f729Sjoerg
6357330f729Sjoerg class BPFPrettyPrinter : public PrettyPrinter {
6367330f729Sjoerg public:
printInst(MCInstPrinter & IP,const MCInst * MI,ArrayRef<uint8_t> Bytes,object::SectionedAddress Address,formatted_raw_ostream & OS,StringRef Annot,MCSubtargetInfo const & STI,SourcePrinter * SP,StringRef ObjectFilename,std::vector<RelocationRef> * Rels,LiveVariablePrinter & LVP)6377330f729Sjoerg void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
638*82d56013Sjoerg object::SectionedAddress Address, formatted_raw_ostream &OS,
6397330f729Sjoerg StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP,
640*82d56013Sjoerg StringRef ObjectFilename, std::vector<RelocationRef> *Rels,
641*82d56013Sjoerg LiveVariablePrinter &LVP) override {
6427330f729Sjoerg if (SP && (PrintSource || PrintLines))
643*82d56013Sjoerg SP->printSourceLine(OS, Address, ObjectFilename, LVP);
644*82d56013Sjoerg if (LeadingAddr)
6457330f729Sjoerg OS << format("%8" PRId64 ":", Address.Address / 8);
646*82d56013Sjoerg if (ShowRawInsn) {
6477330f729Sjoerg OS << "\t";
6487330f729Sjoerg dumpBytes(Bytes, OS);
6497330f729Sjoerg }
6507330f729Sjoerg if (MI)
651*82d56013Sjoerg IP.printInst(MI, Address.Address, "", STI, OS);
6527330f729Sjoerg else
6537330f729Sjoerg OS << "\t<unknown>";
6547330f729Sjoerg }
6557330f729Sjoerg };
6567330f729Sjoerg BPFPrettyPrinter BPFPrettyPrinterInst;
6577330f729Sjoerg
selectPrettyPrinter(Triple const & Triple)6587330f729Sjoerg PrettyPrinter &selectPrettyPrinter(Triple const &Triple) {
6597330f729Sjoerg switch(Triple.getArch()) {
6607330f729Sjoerg default:
6617330f729Sjoerg return PrettyPrinterInst;
6627330f729Sjoerg case Triple::hexagon:
6637330f729Sjoerg return HexagonPrettyPrinterInst;
6647330f729Sjoerg case Triple::amdgcn:
6657330f729Sjoerg return AMDGCNPrettyPrinterInst;
6667330f729Sjoerg case Triple::bpfel:
6677330f729Sjoerg case Triple::bpfeb:
6687330f729Sjoerg return BPFPrettyPrinterInst;
6697330f729Sjoerg }
6707330f729Sjoerg }
6717330f729Sjoerg }
6727330f729Sjoerg
getElfSymbolType(const ObjectFile * Obj,const SymbolRef & Sym)6737330f729Sjoerg static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) {
6747330f729Sjoerg assert(Obj->isELF());
6757330f729Sjoerg if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
676*82d56013Sjoerg return unwrapOrError(Elf32LEObj->getSymbol(Sym.getRawDataRefImpl()),
677*82d56013Sjoerg Obj->getFileName())
678*82d56013Sjoerg ->getType();
6797330f729Sjoerg if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
680*82d56013Sjoerg return unwrapOrError(Elf64LEObj->getSymbol(Sym.getRawDataRefImpl()),
681*82d56013Sjoerg Obj->getFileName())
682*82d56013Sjoerg ->getType();
6837330f729Sjoerg if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
684*82d56013Sjoerg return unwrapOrError(Elf32BEObj->getSymbol(Sym.getRawDataRefImpl()),
685*82d56013Sjoerg Obj->getFileName())
686*82d56013Sjoerg ->getType();
6877330f729Sjoerg if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj))
688*82d56013Sjoerg return unwrapOrError(Elf64BEObj->getSymbol(Sym.getRawDataRefImpl()),
689*82d56013Sjoerg Obj->getFileName())
690*82d56013Sjoerg ->getType();
6917330f729Sjoerg llvm_unreachable("Unsupported binary format");
6927330f729Sjoerg }
6937330f729Sjoerg
6947330f729Sjoerg template <class ELFT> static void
addDynamicElfSymbols(const ELFObjectFile<ELFT> * Obj,std::map<SectionRef,SectionSymbolsTy> & AllSymbols)6957330f729Sjoerg addDynamicElfSymbols(const ELFObjectFile<ELFT> *Obj,
6967330f729Sjoerg std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
6977330f729Sjoerg for (auto Symbol : Obj->getDynamicSymbolIterators()) {
6987330f729Sjoerg uint8_t SymbolType = Symbol.getELFType();
6997330f729Sjoerg if (SymbolType == ELF::STT_SECTION)
7007330f729Sjoerg continue;
7017330f729Sjoerg
7027330f729Sjoerg uint64_t Address = unwrapOrError(Symbol.getAddress(), Obj->getFileName());
7037330f729Sjoerg // ELFSymbolRef::getAddress() returns size instead of value for common
7047330f729Sjoerg // symbols which is not desirable for disassembly output. Overriding.
7057330f729Sjoerg if (SymbolType == ELF::STT_COMMON)
706*82d56013Sjoerg Address = unwrapOrError(Obj->getSymbol(Symbol.getRawDataRefImpl()),
707*82d56013Sjoerg Obj->getFileName())
708*82d56013Sjoerg ->st_value;
7097330f729Sjoerg
7107330f729Sjoerg StringRef Name = unwrapOrError(Symbol.getName(), Obj->getFileName());
7117330f729Sjoerg if (Name.empty())
7127330f729Sjoerg continue;
7137330f729Sjoerg
7147330f729Sjoerg section_iterator SecI =
7157330f729Sjoerg unwrapOrError(Symbol.getSection(), Obj->getFileName());
7167330f729Sjoerg if (SecI == Obj->section_end())
7177330f729Sjoerg continue;
7187330f729Sjoerg
7197330f729Sjoerg AllSymbols[*SecI].emplace_back(Address, Name, SymbolType);
7207330f729Sjoerg }
7217330f729Sjoerg }
7227330f729Sjoerg
7237330f729Sjoerg static void
addDynamicElfSymbols(const ObjectFile * Obj,std::map<SectionRef,SectionSymbolsTy> & AllSymbols)7247330f729Sjoerg addDynamicElfSymbols(const ObjectFile *Obj,
7257330f729Sjoerg std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
7267330f729Sjoerg assert(Obj->isELF());
7277330f729Sjoerg if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
7287330f729Sjoerg addDynamicElfSymbols(Elf32LEObj, AllSymbols);
7297330f729Sjoerg else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
7307330f729Sjoerg addDynamicElfSymbols(Elf64LEObj, AllSymbols);
7317330f729Sjoerg else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
7327330f729Sjoerg addDynamicElfSymbols(Elf32BEObj, AllSymbols);
7337330f729Sjoerg else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj))
7347330f729Sjoerg addDynamicElfSymbols(Elf64BEObj, AllSymbols);
7357330f729Sjoerg else
7367330f729Sjoerg llvm_unreachable("Unsupported binary format");
7377330f729Sjoerg }
7387330f729Sjoerg
addPltEntries(const ObjectFile * Obj,std::map<SectionRef,SectionSymbolsTy> & AllSymbols,StringSaver & Saver)7397330f729Sjoerg static void addPltEntries(const ObjectFile *Obj,
7407330f729Sjoerg std::map<SectionRef, SectionSymbolsTy> &AllSymbols,
7417330f729Sjoerg StringSaver &Saver) {
7427330f729Sjoerg Optional<SectionRef> Plt = None;
7437330f729Sjoerg for (const SectionRef &Section : Obj->sections()) {
7447330f729Sjoerg Expected<StringRef> SecNameOrErr = Section.getName();
7457330f729Sjoerg if (!SecNameOrErr) {
7467330f729Sjoerg consumeError(SecNameOrErr.takeError());
7477330f729Sjoerg continue;
7487330f729Sjoerg }
7497330f729Sjoerg if (*SecNameOrErr == ".plt")
7507330f729Sjoerg Plt = Section;
7517330f729Sjoerg }
7527330f729Sjoerg if (!Plt)
7537330f729Sjoerg return;
7547330f729Sjoerg if (auto *ElfObj = dyn_cast<ELFObjectFileBase>(Obj)) {
7557330f729Sjoerg for (auto PltEntry : ElfObj->getPltAddresses()) {
756*82d56013Sjoerg if (PltEntry.first) {
757*82d56013Sjoerg SymbolRef Symbol(*PltEntry.first, ElfObj);
7587330f729Sjoerg uint8_t SymbolType = getElfSymbolType(Obj, Symbol);
759*82d56013Sjoerg if (Expected<StringRef> NameOrErr = Symbol.getName()) {
760*82d56013Sjoerg if (!NameOrErr->empty())
7617330f729Sjoerg AllSymbols[*Plt].emplace_back(
762*82d56013Sjoerg PltEntry.second, Saver.save((*NameOrErr + "@plt").str()),
763*82d56013Sjoerg SymbolType);
764*82d56013Sjoerg continue;
765*82d56013Sjoerg } else {
766*82d56013Sjoerg // The warning has been reported in disassembleObject().
767*82d56013Sjoerg consumeError(NameOrErr.takeError());
768*82d56013Sjoerg }
769*82d56013Sjoerg }
770*82d56013Sjoerg reportWarning("PLT entry at 0x" + Twine::utohexstr(PltEntry.second) +
771*82d56013Sjoerg " references an invalid symbol",
772*82d56013Sjoerg Obj->getFileName());
7737330f729Sjoerg }
7747330f729Sjoerg }
7757330f729Sjoerg }
7767330f729Sjoerg
7777330f729Sjoerg // Normally the disassembly output will skip blocks of zeroes. This function
7787330f729Sjoerg // returns the number of zero bytes that can be skipped when dumping the
7797330f729Sjoerg // disassembly of the instructions in Buf.
countSkippableZeroBytes(ArrayRef<uint8_t> Buf)7807330f729Sjoerg static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) {
7817330f729Sjoerg // Find the number of leading zeroes.
7827330f729Sjoerg size_t N = 0;
7837330f729Sjoerg while (N < Buf.size() && !Buf[N])
7847330f729Sjoerg ++N;
7857330f729Sjoerg
7867330f729Sjoerg // We may want to skip blocks of zero bytes, but unless we see
7877330f729Sjoerg // at least 8 of them in a row.
7887330f729Sjoerg if (N < 8)
7897330f729Sjoerg return 0;
7907330f729Sjoerg
7917330f729Sjoerg // We skip zeroes in multiples of 4 because do not want to truncate an
7927330f729Sjoerg // instruction if it starts with a zero byte.
7937330f729Sjoerg return N & ~0x3;
7947330f729Sjoerg }
7957330f729Sjoerg
7967330f729Sjoerg // Returns a map from sections to their relocations.
7977330f729Sjoerg static std::map<SectionRef, std::vector<RelocationRef>>
getRelocsMap(object::ObjectFile const & Obj)7987330f729Sjoerg getRelocsMap(object::ObjectFile const &Obj) {
7997330f729Sjoerg std::map<SectionRef, std::vector<RelocationRef>> Ret;
8007330f729Sjoerg uint64_t I = (uint64_t)-1;
8017330f729Sjoerg for (SectionRef Sec : Obj.sections()) {
8027330f729Sjoerg ++I;
8037330f729Sjoerg Expected<section_iterator> RelocatedOrErr = Sec.getRelocatedSection();
8047330f729Sjoerg if (!RelocatedOrErr)
8057330f729Sjoerg reportError(Obj.getFileName(),
8067330f729Sjoerg "section (" + Twine(I) +
8077330f729Sjoerg "): failed to get a relocated section: " +
8087330f729Sjoerg toString(RelocatedOrErr.takeError()));
8097330f729Sjoerg
8107330f729Sjoerg section_iterator Relocated = *RelocatedOrErr;
8117330f729Sjoerg if (Relocated == Obj.section_end() || !checkSectionFilter(*Relocated).Keep)
8127330f729Sjoerg continue;
8137330f729Sjoerg std::vector<RelocationRef> &V = Ret[*Relocated];
814*82d56013Sjoerg append_range(V, Sec.relocations());
8157330f729Sjoerg // Sort relocations by address.
8167330f729Sjoerg llvm::stable_sort(V, isRelocAddressLess);
8177330f729Sjoerg }
8187330f729Sjoerg return Ret;
8197330f729Sjoerg }
8207330f729Sjoerg
8217330f729Sjoerg // Used for --adjust-vma to check if address should be adjusted by the
8227330f729Sjoerg // specified value for a given section.
8237330f729Sjoerg // For ELF we do not adjust non-allocatable sections like debug ones,
8247330f729Sjoerg // because they are not loadable.
8257330f729Sjoerg // TODO: implement for other file formats.
shouldAdjustVA(const SectionRef & Section)8267330f729Sjoerg static bool shouldAdjustVA(const SectionRef &Section) {
8277330f729Sjoerg const ObjectFile *Obj = Section.getObject();
828*82d56013Sjoerg if (Obj->isELF())
8297330f729Sjoerg return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC;
8307330f729Sjoerg return false;
8317330f729Sjoerg }
8327330f729Sjoerg
8337330f729Sjoerg
8347330f729Sjoerg typedef std::pair<uint64_t, char> MappingSymbolPair;
getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols,uint64_t Address)8357330f729Sjoerg static char getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols,
8367330f729Sjoerg uint64_t Address) {
8377330f729Sjoerg auto It =
8387330f729Sjoerg partition_point(MappingSymbols, [Address](const MappingSymbolPair &Val) {
8397330f729Sjoerg return Val.first <= Address;
8407330f729Sjoerg });
8417330f729Sjoerg // Return zero for any address before the first mapping symbol; this means
8427330f729Sjoerg // we should use the default disassembly mode, depending on the target.
8437330f729Sjoerg if (It == MappingSymbols.begin())
8447330f729Sjoerg return '\x00';
8457330f729Sjoerg return (It - 1)->second;
8467330f729Sjoerg }
8477330f729Sjoerg
dumpARMELFData(uint64_t SectionAddr,uint64_t Index,uint64_t End,const ObjectFile * Obj,ArrayRef<uint8_t> Bytes,ArrayRef<MappingSymbolPair> MappingSymbols,raw_ostream & OS)848*82d56013Sjoerg static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index,
849*82d56013Sjoerg uint64_t End, const ObjectFile *Obj,
850*82d56013Sjoerg ArrayRef<uint8_t> Bytes,
851*82d56013Sjoerg ArrayRef<MappingSymbolPair> MappingSymbols,
852*82d56013Sjoerg raw_ostream &OS) {
8537330f729Sjoerg support::endianness Endian =
8547330f729Sjoerg Obj->isLittleEndian() ? support::little : support::big;
855*82d56013Sjoerg OS << format("%8" PRIx64 ":\t", SectionAddr + Index);
8567330f729Sjoerg if (Index + 4 <= End) {
857*82d56013Sjoerg dumpBytes(Bytes.slice(Index, 4), OS);
858*82d56013Sjoerg OS << "\t.word\t"
859*82d56013Sjoerg << format_hex(support::endian::read32(Bytes.data() + Index, Endian),
860*82d56013Sjoerg 10);
861*82d56013Sjoerg return 4;
8627330f729Sjoerg }
863*82d56013Sjoerg if (Index + 2 <= End) {
864*82d56013Sjoerg dumpBytes(Bytes.slice(Index, 2), OS);
865*82d56013Sjoerg OS << "\t\t.short\t"
866*82d56013Sjoerg << format_hex(support::endian::read16(Bytes.data() + Index, Endian),
867*82d56013Sjoerg 6);
868*82d56013Sjoerg return 2;
8697330f729Sjoerg }
870*82d56013Sjoerg dumpBytes(Bytes.slice(Index, 1), OS);
871*82d56013Sjoerg OS << "\t\t.byte\t" << format_hex(Bytes[0], 4);
872*82d56013Sjoerg return 1;
8737330f729Sjoerg }
8747330f729Sjoerg
dumpELFData(uint64_t SectionAddr,uint64_t Index,uint64_t End,ArrayRef<uint8_t> Bytes)8757330f729Sjoerg static void dumpELFData(uint64_t SectionAddr, uint64_t Index, uint64_t End,
8767330f729Sjoerg ArrayRef<uint8_t> Bytes) {
8777330f729Sjoerg // print out data up to 8 bytes at a time in hex and ascii
8787330f729Sjoerg uint8_t AsciiData[9] = {'\0'};
8797330f729Sjoerg uint8_t Byte;
8807330f729Sjoerg int NumBytes = 0;
8817330f729Sjoerg
8827330f729Sjoerg for (; Index < End; ++Index) {
8837330f729Sjoerg if (NumBytes == 0)
8847330f729Sjoerg outs() << format("%8" PRIx64 ":", SectionAddr + Index);
8857330f729Sjoerg Byte = Bytes.slice(Index)[0];
8867330f729Sjoerg outs() << format(" %02x", Byte);
8877330f729Sjoerg AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.';
8887330f729Sjoerg
8897330f729Sjoerg uint8_t IndentOffset = 0;
8907330f729Sjoerg NumBytes++;
8917330f729Sjoerg if (Index == End - 1 || NumBytes > 8) {
8927330f729Sjoerg // Indent the space for less than 8 bytes data.
8937330f729Sjoerg // 2 spaces for byte and one for space between bytes
8947330f729Sjoerg IndentOffset = 3 * (8 - NumBytes);
8957330f729Sjoerg for (int Excess = NumBytes; Excess < 8; Excess++)
8967330f729Sjoerg AsciiData[Excess] = '\0';
8977330f729Sjoerg NumBytes = 8;
8987330f729Sjoerg }
8997330f729Sjoerg if (NumBytes == 8) {
9007330f729Sjoerg AsciiData[8] = '\0';
9017330f729Sjoerg outs() << std::string(IndentOffset, ' ') << " ";
9027330f729Sjoerg outs() << reinterpret_cast<char *>(AsciiData);
9037330f729Sjoerg outs() << '\n';
9047330f729Sjoerg NumBytes = 0;
9057330f729Sjoerg }
9067330f729Sjoerg }
9077330f729Sjoerg }
9087330f729Sjoerg
createSymbolInfo(const ObjectFile * Obj,const SymbolRef & Symbol)909*82d56013Sjoerg SymbolInfoTy objdump::createSymbolInfo(const ObjectFile *Obj,
910*82d56013Sjoerg const SymbolRef &Symbol) {
911*82d56013Sjoerg const StringRef FileName = Obj->getFileName();
912*82d56013Sjoerg const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
913*82d56013Sjoerg const StringRef Name = unwrapOrError(Symbol.getName(), FileName);
914*82d56013Sjoerg
915*82d56013Sjoerg if (Obj->isXCOFF() && SymbolDescription) {
916*82d56013Sjoerg const auto *XCOFFObj = cast<XCOFFObjectFile>(Obj);
917*82d56013Sjoerg DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl();
918*82d56013Sjoerg
919*82d56013Sjoerg const uint32_t SymbolIndex = XCOFFObj->getSymbolIndex(SymbolDRI.p);
920*82d56013Sjoerg Optional<XCOFF::StorageMappingClass> Smc =
921*82d56013Sjoerg getXCOFFSymbolCsectSMC(XCOFFObj, Symbol);
922*82d56013Sjoerg return SymbolInfoTy(Addr, Name, Smc, SymbolIndex,
923*82d56013Sjoerg isLabel(XCOFFObj, Symbol));
924*82d56013Sjoerg } else
925*82d56013Sjoerg return SymbolInfoTy(Addr, Name,
926*82d56013Sjoerg Obj->isELF() ? getElfSymbolType(Obj, Symbol)
927*82d56013Sjoerg : (uint8_t)ELF::STT_NOTYPE);
928*82d56013Sjoerg }
929*82d56013Sjoerg
createDummySymbolInfo(const ObjectFile * Obj,const uint64_t Addr,StringRef & Name,uint8_t Type)930*82d56013Sjoerg static SymbolInfoTy createDummySymbolInfo(const ObjectFile *Obj,
931*82d56013Sjoerg const uint64_t Addr, StringRef &Name,
932*82d56013Sjoerg uint8_t Type) {
933*82d56013Sjoerg if (Obj->isXCOFF() && SymbolDescription)
934*82d56013Sjoerg return SymbolInfoTy(Addr, Name, None, None, false);
935*82d56013Sjoerg else
936*82d56013Sjoerg return SymbolInfoTy(Addr, Name, Type);
937*82d56013Sjoerg }
938*82d56013Sjoerg
939*82d56013Sjoerg static void
collectLocalBranchTargets(ArrayRef<uint8_t> Bytes,const MCInstrAnalysis * MIA,MCDisassembler * DisAsm,MCInstPrinter * IP,const MCSubtargetInfo * STI,uint64_t SectionAddr,uint64_t Start,uint64_t End,std::unordered_map<uint64_t,std::string> & Labels)940*82d56013Sjoerg collectLocalBranchTargets(ArrayRef<uint8_t> Bytes, const MCInstrAnalysis *MIA,
941*82d56013Sjoerg MCDisassembler *DisAsm, MCInstPrinter *IP,
942*82d56013Sjoerg const MCSubtargetInfo *STI, uint64_t SectionAddr,
943*82d56013Sjoerg uint64_t Start, uint64_t End,
944*82d56013Sjoerg std::unordered_map<uint64_t, std::string> &Labels) {
945*82d56013Sjoerg // So far only supports X86.
946*82d56013Sjoerg if (!STI->getTargetTriple().isX86())
947*82d56013Sjoerg return;
948*82d56013Sjoerg
949*82d56013Sjoerg Labels.clear();
950*82d56013Sjoerg unsigned LabelCount = 0;
951*82d56013Sjoerg Start += SectionAddr;
952*82d56013Sjoerg End += SectionAddr;
953*82d56013Sjoerg uint64_t Index = Start;
954*82d56013Sjoerg while (Index < End) {
955*82d56013Sjoerg // Disassemble a real instruction and record function-local branch labels.
956*82d56013Sjoerg MCInst Inst;
957*82d56013Sjoerg uint64_t Size;
958*82d56013Sjoerg bool Disassembled = DisAsm->getInstruction(
959*82d56013Sjoerg Inst, Size, Bytes.slice(Index - SectionAddr), Index, nulls());
960*82d56013Sjoerg if (Size == 0)
961*82d56013Sjoerg Size = 1;
962*82d56013Sjoerg
963*82d56013Sjoerg if (Disassembled && MIA) {
964*82d56013Sjoerg uint64_t Target;
965*82d56013Sjoerg bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target);
966*82d56013Sjoerg if (TargetKnown && (Target >= Start && Target < End) &&
967*82d56013Sjoerg !Labels.count(Target))
968*82d56013Sjoerg Labels[Target] = ("L" + Twine(LabelCount++)).str();
969*82d56013Sjoerg }
970*82d56013Sjoerg
971*82d56013Sjoerg Index += Size;
972*82d56013Sjoerg }
973*82d56013Sjoerg }
974*82d56013Sjoerg
975*82d56013Sjoerg // Create an MCSymbolizer for the target and add it to the MCDisassembler.
976*82d56013Sjoerg // This is currently only used on AMDGPU, and assumes the format of the
977*82d56013Sjoerg // void * argument passed to AMDGPU's createMCSymbolizer.
addSymbolizer(MCContext & Ctx,const Target * Target,StringRef TripleName,MCDisassembler * DisAsm,uint64_t SectionAddr,ArrayRef<uint8_t> Bytes,SectionSymbolsTy & Symbols,std::vector<std::unique_ptr<std::string>> & SynthesizedLabelNames)978*82d56013Sjoerg static void addSymbolizer(
979*82d56013Sjoerg MCContext &Ctx, const Target *Target, StringRef TripleName,
980*82d56013Sjoerg MCDisassembler *DisAsm, uint64_t SectionAddr, ArrayRef<uint8_t> Bytes,
981*82d56013Sjoerg SectionSymbolsTy &Symbols,
982*82d56013Sjoerg std::vector<std::unique_ptr<std::string>> &SynthesizedLabelNames) {
983*82d56013Sjoerg
984*82d56013Sjoerg std::unique_ptr<MCRelocationInfo> RelInfo(
985*82d56013Sjoerg Target->createMCRelocationInfo(TripleName, Ctx));
986*82d56013Sjoerg if (!RelInfo)
987*82d56013Sjoerg return;
988*82d56013Sjoerg std::unique_ptr<MCSymbolizer> Symbolizer(Target->createMCSymbolizer(
989*82d56013Sjoerg TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo)));
990*82d56013Sjoerg MCSymbolizer *SymbolizerPtr = &*Symbolizer;
991*82d56013Sjoerg DisAsm->setSymbolizer(std::move(Symbolizer));
992*82d56013Sjoerg
993*82d56013Sjoerg if (!SymbolizeOperands)
994*82d56013Sjoerg return;
995*82d56013Sjoerg
996*82d56013Sjoerg // Synthesize labels referenced by branch instructions by
997*82d56013Sjoerg // disassembling, discarding the output, and collecting the referenced
998*82d56013Sjoerg // addresses from the symbolizer.
999*82d56013Sjoerg for (size_t Index = 0; Index != Bytes.size();) {
1000*82d56013Sjoerg MCInst Inst;
1001*82d56013Sjoerg uint64_t Size;
1002*82d56013Sjoerg DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), SectionAddr + Index,
1003*82d56013Sjoerg nulls());
1004*82d56013Sjoerg if (Size == 0)
1005*82d56013Sjoerg Size = 1;
1006*82d56013Sjoerg Index += Size;
1007*82d56013Sjoerg }
1008*82d56013Sjoerg ArrayRef<uint64_t> LabelAddrsRef = SymbolizerPtr->getReferencedAddresses();
1009*82d56013Sjoerg // Copy and sort to remove duplicates.
1010*82d56013Sjoerg std::vector<uint64_t> LabelAddrs;
1011*82d56013Sjoerg LabelAddrs.insert(LabelAddrs.end(), LabelAddrsRef.begin(),
1012*82d56013Sjoerg LabelAddrsRef.end());
1013*82d56013Sjoerg llvm::sort(LabelAddrs);
1014*82d56013Sjoerg LabelAddrs.resize(std::unique(LabelAddrs.begin(), LabelAddrs.end()) -
1015*82d56013Sjoerg LabelAddrs.begin());
1016*82d56013Sjoerg // Add the labels.
1017*82d56013Sjoerg for (unsigned LabelNum = 0; LabelNum != LabelAddrs.size(); ++LabelNum) {
1018*82d56013Sjoerg auto Name = std::make_unique<std::string>();
1019*82d56013Sjoerg *Name = (Twine("L") + Twine(LabelNum)).str();
1020*82d56013Sjoerg SynthesizedLabelNames.push_back(std::move(Name));
1021*82d56013Sjoerg Symbols.push_back(SymbolInfoTy(
1022*82d56013Sjoerg LabelAddrs[LabelNum], *SynthesizedLabelNames.back(), ELF::STT_NOTYPE));
1023*82d56013Sjoerg }
1024*82d56013Sjoerg llvm::stable_sort(Symbols);
1025*82d56013Sjoerg // Recreate the symbolizer with the new symbols list.
1026*82d56013Sjoerg RelInfo.reset(Target->createMCRelocationInfo(TripleName, Ctx));
1027*82d56013Sjoerg Symbolizer.reset(Target->createMCSymbolizer(
1028*82d56013Sjoerg TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo)));
1029*82d56013Sjoerg DisAsm->setSymbolizer(std::move(Symbolizer));
1030*82d56013Sjoerg }
1031*82d56013Sjoerg
getSegmentName(const MachOObjectFile * MachO,const SectionRef & Section)1032*82d56013Sjoerg static StringRef getSegmentName(const MachOObjectFile *MachO,
1033*82d56013Sjoerg const SectionRef &Section) {
1034*82d56013Sjoerg if (MachO) {
1035*82d56013Sjoerg DataRefImpl DR = Section.getRawDataRefImpl();
1036*82d56013Sjoerg StringRef SegmentName = MachO->getSectionFinalSegmentName(DR);
1037*82d56013Sjoerg return SegmentName;
1038*82d56013Sjoerg }
1039*82d56013Sjoerg return "";
1040*82d56013Sjoerg }
1041*82d56013Sjoerg
disassembleObject(const Target * TheTarget,const ObjectFile * Obj,MCContext & Ctx,MCDisassembler * PrimaryDisAsm,MCDisassembler * SecondaryDisAsm,const MCInstrAnalysis * MIA,MCInstPrinter * IP,const MCSubtargetInfo * PrimarySTI,const MCSubtargetInfo * SecondarySTI,PrettyPrinter & PIP,SourcePrinter & SP,bool InlineRelocs)10427330f729Sjoerg static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj,
10437330f729Sjoerg MCContext &Ctx, MCDisassembler *PrimaryDisAsm,
10447330f729Sjoerg MCDisassembler *SecondaryDisAsm,
10457330f729Sjoerg const MCInstrAnalysis *MIA, MCInstPrinter *IP,
10467330f729Sjoerg const MCSubtargetInfo *PrimarySTI,
10477330f729Sjoerg const MCSubtargetInfo *SecondarySTI,
10487330f729Sjoerg PrettyPrinter &PIP,
10497330f729Sjoerg SourcePrinter &SP, bool InlineRelocs) {
10507330f729Sjoerg const MCSubtargetInfo *STI = PrimarySTI;
10517330f729Sjoerg MCDisassembler *DisAsm = PrimaryDisAsm;
10527330f729Sjoerg bool PrimaryIsThumb = false;
10537330f729Sjoerg if (isArmElf(Obj))
10547330f729Sjoerg PrimaryIsThumb = STI->checkFeatures("+thumb-mode");
10557330f729Sjoerg
10567330f729Sjoerg std::map<SectionRef, std::vector<RelocationRef>> RelocMap;
10577330f729Sjoerg if (InlineRelocs)
10587330f729Sjoerg RelocMap = getRelocsMap(*Obj);
10597330f729Sjoerg bool Is64Bits = Obj->getBytesInAddress() > 4;
10607330f729Sjoerg
10617330f729Sjoerg // Create a mapping from virtual address to symbol name. This is used to
10627330f729Sjoerg // pretty print the symbols while disassembling.
10637330f729Sjoerg std::map<SectionRef, SectionSymbolsTy> AllSymbols;
10647330f729Sjoerg SectionSymbolsTy AbsoluteSymbols;
10657330f729Sjoerg const StringRef FileName = Obj->getFileName();
1066*82d56013Sjoerg const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj);
10677330f729Sjoerg for (const SymbolRef &Symbol : Obj->symbols()) {
1068*82d56013Sjoerg Expected<StringRef> NameOrErr = Symbol.getName();
1069*82d56013Sjoerg if (!NameOrErr) {
1070*82d56013Sjoerg reportWarning(toString(NameOrErr.takeError()), FileName);
1071*82d56013Sjoerg continue;
1072*82d56013Sjoerg }
1073*82d56013Sjoerg if (NameOrErr->empty() && !(Obj->isXCOFF() && SymbolDescription))
10747330f729Sjoerg continue;
10757330f729Sjoerg
1076*82d56013Sjoerg if (Obj->isELF() && getElfSymbolType(Obj, Symbol) == ELF::STT_SECTION)
1077*82d56013Sjoerg continue;
1078*82d56013Sjoerg
1079*82d56013Sjoerg if (MachO) {
1080*82d56013Sjoerg // __mh_(execute|dylib|dylinker|bundle|preload|object)_header are special
1081*82d56013Sjoerg // symbols that support MachO header introspection. They do not bind to
1082*82d56013Sjoerg // code locations and are irrelevant for disassembly.
1083*82d56013Sjoerg if (NameOrErr->startswith("__mh_") && NameOrErr->endswith("_header"))
1084*82d56013Sjoerg continue;
1085*82d56013Sjoerg // Don't ask a Mach-O STAB symbol for its section unless you know that
1086*82d56013Sjoerg // STAB symbol's section field refers to a valid section index. Otherwise
1087*82d56013Sjoerg // the symbol may error trying to load a section that does not exist.
1088*82d56013Sjoerg DataRefImpl SymDRI = Symbol.getRawDataRefImpl();
1089*82d56013Sjoerg uint8_t NType = (MachO->is64Bit() ?
1090*82d56013Sjoerg MachO->getSymbol64TableEntry(SymDRI).n_type:
1091*82d56013Sjoerg MachO->getSymbolTableEntry(SymDRI).n_type);
1092*82d56013Sjoerg if (NType & MachO::N_STAB)
10937330f729Sjoerg continue;
10947330f729Sjoerg }
10957330f729Sjoerg
10967330f729Sjoerg section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);
10977330f729Sjoerg if (SecI != Obj->section_end())
1098*82d56013Sjoerg AllSymbols[*SecI].push_back(createSymbolInfo(Obj, Symbol));
10997330f729Sjoerg else
1100*82d56013Sjoerg AbsoluteSymbols.push_back(createSymbolInfo(Obj, Symbol));
11017330f729Sjoerg }
1102*82d56013Sjoerg
11037330f729Sjoerg if (AllSymbols.empty() && Obj->isELF())
11047330f729Sjoerg addDynamicElfSymbols(Obj, AllSymbols);
11057330f729Sjoerg
11067330f729Sjoerg BumpPtrAllocator A;
11077330f729Sjoerg StringSaver Saver(A);
11087330f729Sjoerg addPltEntries(Obj, AllSymbols, Saver);
11097330f729Sjoerg
1110*82d56013Sjoerg // Create a mapping from virtual address to section. An empty section can
1111*82d56013Sjoerg // cause more than one section at the same address. Sort such sections to be
1112*82d56013Sjoerg // before same-addressed non-empty sections so that symbol lookups prefer the
1113*82d56013Sjoerg // non-empty section.
11147330f729Sjoerg std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses;
11157330f729Sjoerg for (SectionRef Sec : Obj->sections())
11167330f729Sjoerg SectionAddresses.emplace_back(Sec.getAddress(), Sec);
1117*82d56013Sjoerg llvm::stable_sort(SectionAddresses, [](const auto &LHS, const auto &RHS) {
1118*82d56013Sjoerg if (LHS.first != RHS.first)
1119*82d56013Sjoerg return LHS.first < RHS.first;
1120*82d56013Sjoerg return LHS.second.getSize() < RHS.second.getSize();
1121*82d56013Sjoerg });
11227330f729Sjoerg
11237330f729Sjoerg // Linked executables (.exe and .dll files) typically don't include a real
11247330f729Sjoerg // symbol table but they might contain an export table.
11257330f729Sjoerg if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) {
11267330f729Sjoerg for (const auto &ExportEntry : COFFObj->export_directories()) {
11277330f729Sjoerg StringRef Name;
1128*82d56013Sjoerg if (Error E = ExportEntry.getSymbolName(Name))
1129*82d56013Sjoerg reportError(std::move(E), Obj->getFileName());
11307330f729Sjoerg if (Name.empty())
11317330f729Sjoerg continue;
11327330f729Sjoerg
11337330f729Sjoerg uint32_t RVA;
1134*82d56013Sjoerg if (Error E = ExportEntry.getExportRVA(RVA))
1135*82d56013Sjoerg reportError(std::move(E), Obj->getFileName());
11367330f729Sjoerg
11377330f729Sjoerg uint64_t VA = COFFObj->getImageBase() + RVA;
11387330f729Sjoerg auto Sec = partition_point(
11397330f729Sjoerg SectionAddresses, [VA](const std::pair<uint64_t, SectionRef> &O) {
11407330f729Sjoerg return O.first <= VA;
11417330f729Sjoerg });
11427330f729Sjoerg if (Sec != SectionAddresses.begin()) {
11437330f729Sjoerg --Sec;
11447330f729Sjoerg AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE);
11457330f729Sjoerg } else
11467330f729Sjoerg AbsoluteSymbols.emplace_back(VA, Name, ELF::STT_NOTYPE);
11477330f729Sjoerg }
11487330f729Sjoerg }
11497330f729Sjoerg
11507330f729Sjoerg // Sort all the symbols, this allows us to use a simple binary search to find
1151*82d56013Sjoerg // Multiple symbols can have the same address. Use a stable sort to stabilize
1152*82d56013Sjoerg // the output.
1153*82d56013Sjoerg StringSet<> FoundDisasmSymbolSet;
11547330f729Sjoerg for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)
1155*82d56013Sjoerg llvm::stable_sort(SecSyms.second);
1156*82d56013Sjoerg llvm::stable_sort(AbsoluteSymbols);
1157*82d56013Sjoerg
1158*82d56013Sjoerg std::unique_ptr<DWARFContext> DICtx;
1159*82d56013Sjoerg LiveVariablePrinter LVP(*Ctx.getRegisterInfo(), *STI);
1160*82d56013Sjoerg
1161*82d56013Sjoerg if (DbgVariables != DVDisabled) {
1162*82d56013Sjoerg DICtx = DWARFContext::create(*Obj);
1163*82d56013Sjoerg for (const std::unique_ptr<DWARFUnit> &CU : DICtx->compile_units())
1164*82d56013Sjoerg LVP.addCompileUnit(CU->getUnitDIE(false));
1165*82d56013Sjoerg }
1166*82d56013Sjoerg
1167*82d56013Sjoerg LLVM_DEBUG(LVP.dump());
11687330f729Sjoerg
11697330f729Sjoerg for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
11707330f729Sjoerg if (FilterSections.empty() && !DisassembleAll &&
11717330f729Sjoerg (!Section.isText() || Section.isVirtual()))
11727330f729Sjoerg continue;
11737330f729Sjoerg
11747330f729Sjoerg uint64_t SectionAddr = Section.getAddress();
11757330f729Sjoerg uint64_t SectSize = Section.getSize();
11767330f729Sjoerg if (!SectSize)
11777330f729Sjoerg continue;
11787330f729Sjoerg
11797330f729Sjoerg // Get the list of all the symbols in this section.
11807330f729Sjoerg SectionSymbolsTy &Symbols = AllSymbols[Section];
11817330f729Sjoerg std::vector<MappingSymbolPair> MappingSymbols;
11827330f729Sjoerg if (hasMappingSymbols(Obj)) {
11837330f729Sjoerg for (const auto &Symb : Symbols) {
1184*82d56013Sjoerg uint64_t Address = Symb.Addr;
1185*82d56013Sjoerg StringRef Name = Symb.Name;
11867330f729Sjoerg if (Name.startswith("$d"))
11877330f729Sjoerg MappingSymbols.emplace_back(Address - SectionAddr, 'd');
11887330f729Sjoerg if (Name.startswith("$x"))
11897330f729Sjoerg MappingSymbols.emplace_back(Address - SectionAddr, 'x');
11907330f729Sjoerg if (Name.startswith("$a"))
11917330f729Sjoerg MappingSymbols.emplace_back(Address - SectionAddr, 'a');
11927330f729Sjoerg if (Name.startswith("$t"))
11937330f729Sjoerg MappingSymbols.emplace_back(Address - SectionAddr, 't');
11947330f729Sjoerg }
11957330f729Sjoerg }
11967330f729Sjoerg
11977330f729Sjoerg llvm::sort(MappingSymbols);
11987330f729Sjoerg
1199*82d56013Sjoerg ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(
1200*82d56013Sjoerg unwrapOrError(Section.getContents(), Obj->getFileName()));
1201*82d56013Sjoerg
1202*82d56013Sjoerg std::vector<std::unique_ptr<std::string>> SynthesizedLabelNames;
12037330f729Sjoerg if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) {
12047330f729Sjoerg // AMDGPU disassembler uses symbolizer for printing labels
1205*82d56013Sjoerg addSymbolizer(Ctx, TheTarget, TripleName, DisAsm, SectionAddr, Bytes,
1206*82d56013Sjoerg Symbols, SynthesizedLabelNames);
12077330f729Sjoerg }
12087330f729Sjoerg
1209*82d56013Sjoerg StringRef SegmentName = getSegmentName(MachO, Section);
12107330f729Sjoerg StringRef SectionName = unwrapOrError(Section.getName(), Obj->getFileName());
12117330f729Sjoerg // If the section has no symbol at the start, just insert a dummy one.
1212*82d56013Sjoerg if (Symbols.empty() || Symbols[0].Addr != 0) {
1213*82d56013Sjoerg Symbols.insert(Symbols.begin(),
1214*82d56013Sjoerg createDummySymbolInfo(Obj, SectionAddr, SectionName,
1215*82d56013Sjoerg Section.isText() ? ELF::STT_FUNC
1216*82d56013Sjoerg : ELF::STT_OBJECT));
12177330f729Sjoerg }
12187330f729Sjoerg
12197330f729Sjoerg SmallString<40> Comments;
12207330f729Sjoerg raw_svector_ostream CommentStream(Comments);
12217330f729Sjoerg
12227330f729Sjoerg uint64_t VMAAdjustment = 0;
12237330f729Sjoerg if (shouldAdjustVA(Section))
12247330f729Sjoerg VMAAdjustment = AdjustVMA;
12257330f729Sjoerg
12267330f729Sjoerg uint64_t Size;
12277330f729Sjoerg uint64_t Index;
12287330f729Sjoerg bool PrintedSection = false;
12297330f729Sjoerg std::vector<RelocationRef> Rels = RelocMap[Section];
12307330f729Sjoerg std::vector<RelocationRef>::const_iterator RelCur = Rels.begin();
12317330f729Sjoerg std::vector<RelocationRef>::const_iterator RelEnd = Rels.end();
12327330f729Sjoerg // Disassemble symbol by symbol.
12337330f729Sjoerg for (unsigned SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
1234*82d56013Sjoerg std::string SymbolName = Symbols[SI].Name.str();
12357330f729Sjoerg if (Demangle)
12367330f729Sjoerg SymbolName = demangle(SymbolName);
12377330f729Sjoerg
1238*82d56013Sjoerg // Skip if --disassemble-symbols is not empty and the symbol is not in
12397330f729Sjoerg // the list.
1240*82d56013Sjoerg if (!DisasmSymbolSet.empty() && !DisasmSymbolSet.count(SymbolName))
12417330f729Sjoerg continue;
12427330f729Sjoerg
1243*82d56013Sjoerg uint64_t Start = Symbols[SI].Addr;
12447330f729Sjoerg if (Start < SectionAddr || StopAddress <= Start)
12457330f729Sjoerg continue;
12467330f729Sjoerg else
1247*82d56013Sjoerg FoundDisasmSymbolSet.insert(SymbolName);
12487330f729Sjoerg
12497330f729Sjoerg // The end is the section end, the beginning of the next symbol, or
12507330f729Sjoerg // --stop-address.
12517330f729Sjoerg uint64_t End = std::min<uint64_t>(SectionAddr + SectSize, StopAddress);
12527330f729Sjoerg if (SI + 1 < SE)
1253*82d56013Sjoerg End = std::min(End, Symbols[SI + 1].Addr);
12547330f729Sjoerg if (Start >= End || End <= StartAddress)
12557330f729Sjoerg continue;
12567330f729Sjoerg Start -= SectionAddr;
12577330f729Sjoerg End -= SectionAddr;
12587330f729Sjoerg
12597330f729Sjoerg if (!PrintedSection) {
12607330f729Sjoerg PrintedSection = true;
12617330f729Sjoerg outs() << "\nDisassembly of section ";
12627330f729Sjoerg if (!SegmentName.empty())
12637330f729Sjoerg outs() << SegmentName << ",";
12647330f729Sjoerg outs() << SectionName << ":\n";
12657330f729Sjoerg }
12667330f729Sjoerg
12677330f729Sjoerg outs() << '\n';
1268*82d56013Sjoerg if (LeadingAddr)
12697330f729Sjoerg outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ",
12707330f729Sjoerg SectionAddr + Start + VMAAdjustment);
1271*82d56013Sjoerg if (Obj->isXCOFF() && SymbolDescription) {
1272*82d56013Sjoerg outs() << getXCOFFSymbolDescription(Symbols[SI], SymbolName) << ":\n";
1273*82d56013Sjoerg } else
1274*82d56013Sjoerg outs() << '<' << SymbolName << ">:\n";
12757330f729Sjoerg
12767330f729Sjoerg // Don't print raw contents of a virtual section. A virtual section
12777330f729Sjoerg // doesn't have any contents in the file.
12787330f729Sjoerg if (Section.isVirtual()) {
12797330f729Sjoerg outs() << "...\n";
12807330f729Sjoerg continue;
12817330f729Sjoerg }
12827330f729Sjoerg
1283*82d56013Sjoerg auto Status = DisAsm->onSymbolStart(Symbols[SI], Size,
1284*82d56013Sjoerg Bytes.slice(Start, End - Start),
1285*82d56013Sjoerg SectionAddr + Start, CommentStream);
1286*82d56013Sjoerg // To have round trippable disassembly, we fall back to decoding the
1287*82d56013Sjoerg // remaining bytes as instructions.
1288*82d56013Sjoerg //
1289*82d56013Sjoerg // If there is a failure, we disassemble the failed region as bytes before
1290*82d56013Sjoerg // falling back. The target is expected to print nothing in this case.
1291*82d56013Sjoerg //
1292*82d56013Sjoerg // If there is Success or SoftFail i.e no 'real' failure, we go ahead by
1293*82d56013Sjoerg // Size bytes before falling back.
1294*82d56013Sjoerg // So if the entire symbol is 'eaten' by the target:
1295*82d56013Sjoerg // Start += Size // Now Start = End and we will never decode as
1296*82d56013Sjoerg // // instructions
1297*82d56013Sjoerg //
1298*82d56013Sjoerg // Right now, most targets return None i.e ignore to treat a symbol
1299*82d56013Sjoerg // separately. But WebAssembly decodes preludes for some symbols.
1300*82d56013Sjoerg //
1301*82d56013Sjoerg if (Status.hasValue()) {
1302*82d56013Sjoerg if (Status.getValue() == MCDisassembler::Fail) {
1303*82d56013Sjoerg outs() << "// Error in decoding " << SymbolName
1304*82d56013Sjoerg << " : Decoding failed region as bytes.\n";
1305*82d56013Sjoerg for (uint64_t I = 0; I < Size; ++I) {
1306*82d56013Sjoerg outs() << "\t.byte\t " << format_hex(Bytes[I], 1, /*Upper=*/true)
1307*82d56013Sjoerg << "\n";
1308*82d56013Sjoerg }
1309*82d56013Sjoerg }
1310*82d56013Sjoerg } else {
1311*82d56013Sjoerg Size = 0;
1312*82d56013Sjoerg }
13137330f729Sjoerg
13147330f729Sjoerg Start += Size;
13157330f729Sjoerg
13167330f729Sjoerg Index = Start;
13177330f729Sjoerg if (SectionAddr < StartAddress)
13187330f729Sjoerg Index = std::max<uint64_t>(Index, StartAddress - SectionAddr);
13197330f729Sjoerg
13207330f729Sjoerg // If there is a data/common symbol inside an ELF text section and we are
13217330f729Sjoerg // only disassembling text (applicable all architectures), we are in a
13227330f729Sjoerg // situation where we must print the data and not disassemble it.
13237330f729Sjoerg if (Obj->isELF() && !DisassembleAll && Section.isText()) {
1324*82d56013Sjoerg uint8_t SymTy = Symbols[SI].Type;
13257330f729Sjoerg if (SymTy == ELF::STT_OBJECT || SymTy == ELF::STT_COMMON) {
13267330f729Sjoerg dumpELFData(SectionAddr, Index, End, Bytes);
13277330f729Sjoerg Index = End;
13287330f729Sjoerg }
13297330f729Sjoerg }
13307330f729Sjoerg
13317330f729Sjoerg bool CheckARMELFData = hasMappingSymbols(Obj) &&
1332*82d56013Sjoerg Symbols[SI].Type != ELF::STT_OBJECT &&
13337330f729Sjoerg !DisassembleAll;
1334*82d56013Sjoerg bool DumpARMELFData = false;
1335*82d56013Sjoerg formatted_raw_ostream FOS(outs());
1336*82d56013Sjoerg
1337*82d56013Sjoerg std::unordered_map<uint64_t, std::string> AllLabels;
1338*82d56013Sjoerg if (SymbolizeOperands)
1339*82d56013Sjoerg collectLocalBranchTargets(Bytes, MIA, DisAsm, IP, PrimarySTI,
1340*82d56013Sjoerg SectionAddr, Index, End, AllLabels);
1341*82d56013Sjoerg
13427330f729Sjoerg while (Index < End) {
13437330f729Sjoerg // ARM and AArch64 ELF binaries can interleave data and text in the
13447330f729Sjoerg // same section. We rely on the markers introduced to understand what
13457330f729Sjoerg // we need to dump. If the data marker is within a function, it is
13467330f729Sjoerg // denoted as a word/short etc.
1347*82d56013Sjoerg if (CheckARMELFData) {
1348*82d56013Sjoerg char Kind = getMappingSymbolKind(MappingSymbols, Index);
1349*82d56013Sjoerg DumpARMELFData = Kind == 'd';
1350*82d56013Sjoerg if (SecondarySTI) {
1351*82d56013Sjoerg if (Kind == 'a') {
1352*82d56013Sjoerg STI = PrimaryIsThumb ? SecondarySTI : PrimarySTI;
1353*82d56013Sjoerg DisAsm = PrimaryIsThumb ? SecondaryDisAsm : PrimaryDisAsm;
1354*82d56013Sjoerg } else if (Kind == 't') {
1355*82d56013Sjoerg STI = PrimaryIsThumb ? PrimarySTI : SecondarySTI;
1356*82d56013Sjoerg DisAsm = PrimaryIsThumb ? PrimaryDisAsm : SecondaryDisAsm;
1357*82d56013Sjoerg }
1358*82d56013Sjoerg }
13597330f729Sjoerg }
13607330f729Sjoerg
1361*82d56013Sjoerg if (DumpARMELFData) {
1362*82d56013Sjoerg Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes,
1363*82d56013Sjoerg MappingSymbols, FOS);
1364*82d56013Sjoerg } else {
13657330f729Sjoerg // When -z or --disassemble-zeroes are given we always dissasemble
13667330f729Sjoerg // them. Otherwise we might want to skip zero bytes we see.
13677330f729Sjoerg if (!DisassembleZeroes) {
13687330f729Sjoerg uint64_t MaxOffset = End - Index;
1369*82d56013Sjoerg // For --reloc: print zero blocks patched by relocations, so that
13707330f729Sjoerg // relocations can be shown in the dump.
13717330f729Sjoerg if (RelCur != RelEnd)
13727330f729Sjoerg MaxOffset = RelCur->getOffset() - Index;
13737330f729Sjoerg
13747330f729Sjoerg if (size_t N =
13757330f729Sjoerg countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) {
1376*82d56013Sjoerg FOS << "\t\t..." << '\n';
13777330f729Sjoerg Index += N;
13787330f729Sjoerg continue;
13797330f729Sjoerg }
13807330f729Sjoerg }
13817330f729Sjoerg
1382*82d56013Sjoerg // Print local label if there's any.
1383*82d56013Sjoerg auto Iter = AllLabels.find(SectionAddr + Index);
1384*82d56013Sjoerg if (Iter != AllLabels.end())
1385*82d56013Sjoerg FOS << "<" << Iter->second << ">:\n";
13867330f729Sjoerg
13877330f729Sjoerg // Disassemble a real instruction or a data when disassemble all is
13887330f729Sjoerg // provided
13897330f729Sjoerg MCInst Inst;
1390*82d56013Sjoerg bool Disassembled =
1391*82d56013Sjoerg DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
1392*82d56013Sjoerg SectionAddr + Index, CommentStream);
13937330f729Sjoerg if (Size == 0)
13947330f729Sjoerg Size = 1;
13957330f729Sjoerg
1396*82d56013Sjoerg LVP.update({Index, Section.getIndex()},
1397*82d56013Sjoerg {Index + Size, Section.getIndex()}, Index + Size != End);
1398*82d56013Sjoerg
1399*82d56013Sjoerg PIP.printInst(
1400*82d56013Sjoerg *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size),
1401*82d56013Sjoerg {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS,
1402*82d56013Sjoerg "", *STI, &SP, Obj->getFileName(), &Rels, LVP);
1403*82d56013Sjoerg FOS << CommentStream.str();
14047330f729Sjoerg Comments.clear();
14057330f729Sjoerg
1406*82d56013Sjoerg // If disassembly has failed, avoid analysing invalid/incomplete
1407*82d56013Sjoerg // instruction information. Otherwise, try to resolve the target
1408*82d56013Sjoerg // address (jump target or memory operand address) and print it on the
1409*82d56013Sjoerg // right of the instruction.
1410*82d56013Sjoerg if (Disassembled && MIA) {
14117330f729Sjoerg uint64_t Target;
1412*82d56013Sjoerg bool PrintTarget =
1413*82d56013Sjoerg MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target);
1414*82d56013Sjoerg if (!PrintTarget)
1415*82d56013Sjoerg if (Optional<uint64_t> MaybeTarget =
1416*82d56013Sjoerg MIA->evaluateMemoryOperandAddress(
1417*82d56013Sjoerg Inst, SectionAddr + Index, Size)) {
1418*82d56013Sjoerg Target = *MaybeTarget;
1419*82d56013Sjoerg PrintTarget = true;
1420*82d56013Sjoerg // Do not print real address when symbolizing.
1421*82d56013Sjoerg if (!SymbolizeOperands)
1422*82d56013Sjoerg FOS << " # " << Twine::utohexstr(Target);
1423*82d56013Sjoerg }
1424*82d56013Sjoerg if (PrintTarget) {
14257330f729Sjoerg // In a relocatable object, the target's section must reside in
14267330f729Sjoerg // the same section as the call instruction or it is accessed
14277330f729Sjoerg // through a relocation.
14287330f729Sjoerg //
14297330f729Sjoerg // In a non-relocatable object, the target may be in any section.
1430*82d56013Sjoerg // In that case, locate the section(s) containing the target
1431*82d56013Sjoerg // address and find the symbol in one of those, if possible.
14327330f729Sjoerg //
14337330f729Sjoerg // N.B. We don't walk the relocations in the relocatable case yet.
1434*82d56013Sjoerg std::vector<const SectionSymbolsTy *> TargetSectionSymbols;
14357330f729Sjoerg if (!Obj->isRelocatableObject()) {
1436*82d56013Sjoerg auto It = llvm::partition_point(
14377330f729Sjoerg SectionAddresses,
14387330f729Sjoerg [=](const std::pair<uint64_t, SectionRef> &O) {
14397330f729Sjoerg return O.first <= Target;
14407330f729Sjoerg });
1441*82d56013Sjoerg uint64_t TargetSecAddr = 0;
1442*82d56013Sjoerg while (It != SectionAddresses.begin()) {
14437330f729Sjoerg --It;
1444*82d56013Sjoerg if (TargetSecAddr == 0)
1445*82d56013Sjoerg TargetSecAddr = It->first;
1446*82d56013Sjoerg if (It->first != TargetSecAddr)
1447*82d56013Sjoerg break;
1448*82d56013Sjoerg TargetSectionSymbols.push_back(&AllSymbols[It->second]);
1449*82d56013Sjoerg }
14507330f729Sjoerg } else {
1451*82d56013Sjoerg TargetSectionSymbols.push_back(&Symbols);
1452*82d56013Sjoerg }
1453*82d56013Sjoerg TargetSectionSymbols.push_back(&AbsoluteSymbols);
1454*82d56013Sjoerg
1455*82d56013Sjoerg // Find the last symbol in the first candidate section whose
1456*82d56013Sjoerg // offset is less than or equal to the target. If there are no
1457*82d56013Sjoerg // such symbols, try in the next section and so on, before finally
1458*82d56013Sjoerg // using the nearest preceding absolute symbol (if any), if there
1459*82d56013Sjoerg // are no other valid symbols.
1460*82d56013Sjoerg const SymbolInfoTy *TargetSym = nullptr;
1461*82d56013Sjoerg for (const SectionSymbolsTy *TargetSymbols :
1462*82d56013Sjoerg TargetSectionSymbols) {
1463*82d56013Sjoerg auto It = llvm::partition_point(
1464*82d56013Sjoerg *TargetSymbols,
1465*82d56013Sjoerg [=](const SymbolInfoTy &O) { return O.Addr <= Target; });
1466*82d56013Sjoerg if (It != TargetSymbols->begin()) {
1467*82d56013Sjoerg TargetSym = &*(It - 1);
1468*82d56013Sjoerg break;
14697330f729Sjoerg }
14707330f729Sjoerg }
14717330f729Sjoerg
1472*82d56013Sjoerg // Print the labels corresponding to the target if there's any.
1473*82d56013Sjoerg bool LabelAvailable = AllLabels.count(Target);
1474*82d56013Sjoerg if (TargetSym != nullptr) {
1475*82d56013Sjoerg uint64_t TargetAddress = TargetSym->Addr;
14767330f729Sjoerg uint64_t Disp = Target - TargetAddress;
1477*82d56013Sjoerg std::string TargetName = TargetSym->Name.str();
1478*82d56013Sjoerg if (Demangle)
1479*82d56013Sjoerg TargetName = demangle(TargetName);
1480*82d56013Sjoerg
1481*82d56013Sjoerg FOS << " <";
1482*82d56013Sjoerg if (!Disp) {
1483*82d56013Sjoerg // Always Print the binary symbol precisely corresponding to
1484*82d56013Sjoerg // the target address.
1485*82d56013Sjoerg FOS << TargetName;
1486*82d56013Sjoerg } else if (!LabelAvailable) {
1487*82d56013Sjoerg // Always Print the binary symbol plus an offset if there's no
1488*82d56013Sjoerg // local label corresponding to the target address.
1489*82d56013Sjoerg FOS << TargetName << "+0x" << Twine::utohexstr(Disp);
1490*82d56013Sjoerg } else {
1491*82d56013Sjoerg FOS << AllLabels[Target];
1492*82d56013Sjoerg }
1493*82d56013Sjoerg FOS << ">";
1494*82d56013Sjoerg } else if (LabelAvailable) {
1495*82d56013Sjoerg FOS << " <" << AllLabels[Target] << ">";
14967330f729Sjoerg }
14977330f729Sjoerg }
14987330f729Sjoerg }
1499*82d56013Sjoerg }
1500*82d56013Sjoerg
1501*82d56013Sjoerg LVP.printAfterInst(FOS);
1502*82d56013Sjoerg FOS << "\n";
15037330f729Sjoerg
15047330f729Sjoerg // Hexagon does this in pretty printer
15057330f729Sjoerg if (Obj->getArch() != Triple::hexagon) {
1506*82d56013Sjoerg // Print relocation for instruction and data.
15077330f729Sjoerg while (RelCur != RelEnd) {
15087330f729Sjoerg uint64_t Offset = RelCur->getOffset();
15097330f729Sjoerg // If this relocation is hidden, skip it.
15107330f729Sjoerg if (getHidden(*RelCur) || SectionAddr + Offset < StartAddress) {
15117330f729Sjoerg ++RelCur;
15127330f729Sjoerg continue;
15137330f729Sjoerg }
15147330f729Sjoerg
1515*82d56013Sjoerg // Stop when RelCur's offset is past the disassembled
1516*82d56013Sjoerg // instruction/data. Note that it's possible the disassembled data
1517*82d56013Sjoerg // is not the complete data: we might see the relocation printed in
1518*82d56013Sjoerg // the middle of the data, but this matches the binutils objdump
1519*82d56013Sjoerg // output.
15207330f729Sjoerg if (Offset >= Index + Size)
15217330f729Sjoerg break;
15227330f729Sjoerg
15237330f729Sjoerg // When --adjust-vma is used, update the address printed.
15247330f729Sjoerg if (RelCur->getSymbol() != Obj->symbol_end()) {
15257330f729Sjoerg Expected<section_iterator> SymSI =
15267330f729Sjoerg RelCur->getSymbol()->getSection();
15277330f729Sjoerg if (SymSI && *SymSI != Obj->section_end() &&
15287330f729Sjoerg shouldAdjustVA(**SymSI))
15297330f729Sjoerg Offset += AdjustVMA;
15307330f729Sjoerg }
15317330f729Sjoerg
1532*82d56013Sjoerg printRelocation(FOS, Obj->getFileName(), *RelCur,
1533*82d56013Sjoerg SectionAddr + Offset, Is64Bits);
1534*82d56013Sjoerg LVP.printAfterOtherLine(FOS, true);
15357330f729Sjoerg ++RelCur;
15367330f729Sjoerg }
15377330f729Sjoerg }
15387330f729Sjoerg
15397330f729Sjoerg Index += Size;
15407330f729Sjoerg }
15417330f729Sjoerg }
15427330f729Sjoerg }
1543*82d56013Sjoerg StringSet<> MissingDisasmSymbolSet =
1544*82d56013Sjoerg set_difference(DisasmSymbolSet, FoundDisasmSymbolSet);
1545*82d56013Sjoerg for (StringRef Sym : MissingDisasmSymbolSet.keys())
1546*82d56013Sjoerg reportWarning("failed to disassemble missing symbol " + Sym, FileName);
15477330f729Sjoerg }
15487330f729Sjoerg
disassembleObject(const ObjectFile * Obj,bool InlineRelocs)15497330f729Sjoerg static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
15507330f729Sjoerg const Target *TheTarget = getTarget(Obj);
15517330f729Sjoerg
15527330f729Sjoerg // Package up features to be passed to target/subtarget
15537330f729Sjoerg SubtargetFeatures Features = Obj->getFeatures();
15547330f729Sjoerg if (!MAttrs.empty())
15557330f729Sjoerg for (unsigned I = 0; I != MAttrs.size(); ++I)
15567330f729Sjoerg Features.AddFeature(MAttrs[I]);
15577330f729Sjoerg
15587330f729Sjoerg std::unique_ptr<const MCRegisterInfo> MRI(
15597330f729Sjoerg TheTarget->createMCRegInfo(TripleName));
15607330f729Sjoerg if (!MRI)
15617330f729Sjoerg reportError(Obj->getFileName(),
15627330f729Sjoerg "no register info for target " + TripleName);
15637330f729Sjoerg
15647330f729Sjoerg // Set up disassembler.
15657330f729Sjoerg MCTargetOptions MCOptions;
15667330f729Sjoerg std::unique_ptr<const MCAsmInfo> AsmInfo(
15677330f729Sjoerg TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
15687330f729Sjoerg if (!AsmInfo)
15697330f729Sjoerg reportError(Obj->getFileName(),
15707330f729Sjoerg "no assembly info for target " + TripleName);
1571*82d56013Sjoerg
1572*82d56013Sjoerg if (MCPU.empty())
1573*82d56013Sjoerg MCPU = Obj->tryGetCPUName().getValueOr("").str();
1574*82d56013Sjoerg
15757330f729Sjoerg std::unique_ptr<const MCSubtargetInfo> STI(
15767330f729Sjoerg TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
15777330f729Sjoerg if (!STI)
15787330f729Sjoerg reportError(Obj->getFileName(),
15797330f729Sjoerg "no subtarget info for target " + TripleName);
15807330f729Sjoerg std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
15817330f729Sjoerg if (!MII)
15827330f729Sjoerg reportError(Obj->getFileName(),
15837330f729Sjoerg "no instruction info for target " + TripleName);
1584*82d56013Sjoerg MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get());
15857330f729Sjoerg // FIXME: for now initialize MCObjectFileInfo with default values
1586*82d56013Sjoerg std::unique_ptr<MCObjectFileInfo> MOFI(
1587*82d56013Sjoerg TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
1588*82d56013Sjoerg Ctx.setObjectFileInfo(MOFI.get());
15897330f729Sjoerg
15907330f729Sjoerg std::unique_ptr<MCDisassembler> DisAsm(
15917330f729Sjoerg TheTarget->createMCDisassembler(*STI, Ctx));
15927330f729Sjoerg if (!DisAsm)
15937330f729Sjoerg reportError(Obj->getFileName(), "no disassembler for target " + TripleName);
15947330f729Sjoerg
15957330f729Sjoerg // If we have an ARM object file, we need a second disassembler, because
15967330f729Sjoerg // ARM CPUs have two different instruction sets: ARM mode, and Thumb mode.
15977330f729Sjoerg // We use mapping symbols to switch between the two assemblers, where
15987330f729Sjoerg // appropriate.
15997330f729Sjoerg std::unique_ptr<MCDisassembler> SecondaryDisAsm;
16007330f729Sjoerg std::unique_ptr<const MCSubtargetInfo> SecondarySTI;
16017330f729Sjoerg if (isArmElf(Obj) && !STI->checkFeatures("+mclass")) {
16027330f729Sjoerg if (STI->checkFeatures("+thumb-mode"))
16037330f729Sjoerg Features.AddFeature("-thumb-mode");
16047330f729Sjoerg else
16057330f729Sjoerg Features.AddFeature("+thumb-mode");
16067330f729Sjoerg SecondarySTI.reset(TheTarget->createMCSubtargetInfo(TripleName, MCPU,
16077330f729Sjoerg Features.getString()));
16087330f729Sjoerg SecondaryDisAsm.reset(TheTarget->createMCDisassembler(*SecondarySTI, Ctx));
16097330f729Sjoerg }
16107330f729Sjoerg
16117330f729Sjoerg std::unique_ptr<const MCInstrAnalysis> MIA(
16127330f729Sjoerg TheTarget->createMCInstrAnalysis(MII.get()));
16137330f729Sjoerg
16147330f729Sjoerg int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
16157330f729Sjoerg std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
16167330f729Sjoerg Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
16177330f729Sjoerg if (!IP)
16187330f729Sjoerg reportError(Obj->getFileName(),
16197330f729Sjoerg "no instruction printer for target " + TripleName);
16207330f729Sjoerg IP->setPrintImmHex(PrintImmHex);
1621*82d56013Sjoerg IP->setPrintBranchImmAsAddress(true);
1622*82d56013Sjoerg IP->setSymbolizeOperands(SymbolizeOperands);
1623*82d56013Sjoerg IP->setMCInstrAnalysis(MIA.get());
16247330f729Sjoerg
16257330f729Sjoerg PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName));
16267330f729Sjoerg SourcePrinter SP(Obj, TheTarget->getName());
16277330f729Sjoerg
16287330f729Sjoerg for (StringRef Opt : DisassemblerOptions)
16297330f729Sjoerg if (!IP->applyTargetSpecificCLOption(Opt))
16307330f729Sjoerg reportError(Obj->getFileName(),
16317330f729Sjoerg "Unrecognized disassembler option: " + Opt);
16327330f729Sjoerg
16337330f729Sjoerg disassembleObject(TheTarget, Obj, Ctx, DisAsm.get(), SecondaryDisAsm.get(),
16347330f729Sjoerg MIA.get(), IP.get(), STI.get(), SecondarySTI.get(), PIP,
16357330f729Sjoerg SP, InlineRelocs);
16367330f729Sjoerg }
16377330f729Sjoerg
printRelocations(const ObjectFile * Obj)1638*82d56013Sjoerg void objdump::printRelocations(const ObjectFile *Obj) {
16397330f729Sjoerg StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 :
16407330f729Sjoerg "%08" PRIx64;
16417330f729Sjoerg // Regular objdump doesn't print relocations in non-relocatable object
16427330f729Sjoerg // files.
16437330f729Sjoerg if (!Obj->isRelocatableObject())
16447330f729Sjoerg return;
16457330f729Sjoerg
16467330f729Sjoerg // Build a mapping from relocation target to a vector of relocation
16477330f729Sjoerg // sections. Usually, there is an only one relocation section for
16487330f729Sjoerg // each relocated section.
16497330f729Sjoerg MapVector<SectionRef, std::vector<SectionRef>> SecToRelSec;
16507330f729Sjoerg uint64_t Ndx;
16517330f729Sjoerg for (const SectionRef &Section : ToolSectionFilter(*Obj, &Ndx)) {
16527330f729Sjoerg if (Section.relocation_begin() == Section.relocation_end())
16537330f729Sjoerg continue;
16547330f729Sjoerg Expected<section_iterator> SecOrErr = Section.getRelocatedSection();
16557330f729Sjoerg if (!SecOrErr)
16567330f729Sjoerg reportError(Obj->getFileName(),
16577330f729Sjoerg "section (" + Twine(Ndx) +
16587330f729Sjoerg "): unable to get a relocation target: " +
16597330f729Sjoerg toString(SecOrErr.takeError()));
16607330f729Sjoerg SecToRelSec[**SecOrErr].push_back(Section);
16617330f729Sjoerg }
16627330f729Sjoerg
16637330f729Sjoerg for (std::pair<SectionRef, std::vector<SectionRef>> &P : SecToRelSec) {
16647330f729Sjoerg StringRef SecName = unwrapOrError(P.first.getName(), Obj->getFileName());
1665*82d56013Sjoerg outs() << "\nRELOCATION RECORDS FOR [" << SecName << "]:\n";
1666*82d56013Sjoerg uint32_t OffsetPadding = (Obj->getBytesInAddress() > 4 ? 16 : 8);
1667*82d56013Sjoerg uint32_t TypePadding = 24;
1668*82d56013Sjoerg outs() << left_justify("OFFSET", OffsetPadding) << " "
1669*82d56013Sjoerg << left_justify("TYPE", TypePadding) << " "
1670*82d56013Sjoerg << "VALUE\n";
16717330f729Sjoerg
16727330f729Sjoerg for (SectionRef Section : P.second) {
16737330f729Sjoerg for (const RelocationRef &Reloc : Section.relocations()) {
16747330f729Sjoerg uint64_t Address = Reloc.getOffset();
16757330f729Sjoerg SmallString<32> RelocName;
16767330f729Sjoerg SmallString<32> ValueStr;
16777330f729Sjoerg if (Address < StartAddress || Address > StopAddress || getHidden(Reloc))
16787330f729Sjoerg continue;
16797330f729Sjoerg Reloc.getTypeName(RelocName);
16807330f729Sjoerg if (Error E = getRelocationValueString(Reloc, ValueStr))
16817330f729Sjoerg reportError(std::move(E), Obj->getFileName());
16827330f729Sjoerg
1683*82d56013Sjoerg outs() << format(Fmt.data(), Address) << " "
1684*82d56013Sjoerg << left_justify(RelocName, TypePadding) << " " << ValueStr
1685*82d56013Sjoerg << "\n";
16867330f729Sjoerg }
16877330f729Sjoerg }
16887330f729Sjoerg }
16897330f729Sjoerg }
16907330f729Sjoerg
printDynamicRelocations(const ObjectFile * Obj)1691*82d56013Sjoerg void objdump::printDynamicRelocations(const ObjectFile *Obj) {
16927330f729Sjoerg // For the moment, this option is for ELF only
16937330f729Sjoerg if (!Obj->isELF())
16947330f729Sjoerg return;
16957330f729Sjoerg
16967330f729Sjoerg const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);
16977330f729Sjoerg if (!Elf || Elf->getEType() != ELF::ET_DYN) {
16987330f729Sjoerg reportError(Obj->getFileName(), "not a dynamic object");
16997330f729Sjoerg return;
17007330f729Sjoerg }
17017330f729Sjoerg
17027330f729Sjoerg std::vector<SectionRef> DynRelSec = Obj->dynamic_relocation_sections();
17037330f729Sjoerg if (DynRelSec.empty())
17047330f729Sjoerg return;
17057330f729Sjoerg
17067330f729Sjoerg outs() << "DYNAMIC RELOCATION RECORDS\n";
17077330f729Sjoerg StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
17087330f729Sjoerg for (const SectionRef &Section : DynRelSec)
17097330f729Sjoerg for (const RelocationRef &Reloc : Section.relocations()) {
17107330f729Sjoerg uint64_t Address = Reloc.getOffset();
17117330f729Sjoerg SmallString<32> RelocName;
17127330f729Sjoerg SmallString<32> ValueStr;
17137330f729Sjoerg Reloc.getTypeName(RelocName);
17147330f729Sjoerg if (Error E = getRelocationValueString(Reloc, ValueStr))
17157330f729Sjoerg reportError(std::move(E), Obj->getFileName());
17167330f729Sjoerg outs() << format(Fmt.data(), Address) << " " << RelocName << " "
17177330f729Sjoerg << ValueStr << "\n";
17187330f729Sjoerg }
17197330f729Sjoerg }
17207330f729Sjoerg
17217330f729Sjoerg // Returns true if we need to show LMA column when dumping section headers. We
17227330f729Sjoerg // show it only when the platform is ELF and either we have at least one section
17237330f729Sjoerg // whose VMA and LMA are different and/or when --show-lma flag is used.
shouldDisplayLMA(const ObjectFile * Obj)17247330f729Sjoerg static bool shouldDisplayLMA(const ObjectFile *Obj) {
17257330f729Sjoerg if (!Obj->isELF())
17267330f729Sjoerg return false;
17277330f729Sjoerg for (const SectionRef &S : ToolSectionFilter(*Obj))
17287330f729Sjoerg if (S.getAddress() != getELFSectionLMA(S))
17297330f729Sjoerg return true;
17307330f729Sjoerg return ShowLMA;
17317330f729Sjoerg }
17327330f729Sjoerg
getMaxSectionNameWidth(const ObjectFile * Obj)17337330f729Sjoerg static size_t getMaxSectionNameWidth(const ObjectFile *Obj) {
17347330f729Sjoerg // Default column width for names is 13 even if no names are that long.
17357330f729Sjoerg size_t MaxWidth = 13;
17367330f729Sjoerg for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
17377330f729Sjoerg StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());
17387330f729Sjoerg MaxWidth = std::max(MaxWidth, Name.size());
17397330f729Sjoerg }
17407330f729Sjoerg return MaxWidth;
17417330f729Sjoerg }
17427330f729Sjoerg
printSectionHeaders(const ObjectFile * Obj)1743*82d56013Sjoerg void objdump::printSectionHeaders(const ObjectFile *Obj) {
17447330f729Sjoerg size_t NameWidth = getMaxSectionNameWidth(Obj);
17457330f729Sjoerg size_t AddressWidth = 2 * Obj->getBytesInAddress();
17467330f729Sjoerg bool HasLMAColumn = shouldDisplayLMA(Obj);
1747*82d56013Sjoerg outs() << "\nSections:\n";
17487330f729Sjoerg if (HasLMAColumn)
1749*82d56013Sjoerg outs() << "Idx " << left_justify("Name", NameWidth) << " Size "
17507330f729Sjoerg << left_justify("VMA", AddressWidth) << " "
17517330f729Sjoerg << left_justify("LMA", AddressWidth) << " Type\n";
17527330f729Sjoerg else
1753*82d56013Sjoerg outs() << "Idx " << left_justify("Name", NameWidth) << " Size "
17547330f729Sjoerg << left_justify("VMA", AddressWidth) << " Type\n";
17557330f729Sjoerg
17567330f729Sjoerg uint64_t Idx;
17577330f729Sjoerg for (const SectionRef &Section : ToolSectionFilter(*Obj, &Idx)) {
17587330f729Sjoerg StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());
17597330f729Sjoerg uint64_t VMA = Section.getAddress();
17607330f729Sjoerg if (shouldAdjustVA(Section))
17617330f729Sjoerg VMA += AdjustVMA;
17627330f729Sjoerg
17637330f729Sjoerg uint64_t Size = Section.getSize();
17647330f729Sjoerg
17657330f729Sjoerg std::string Type = Section.isText() ? "TEXT" : "";
17667330f729Sjoerg if (Section.isData())
17677330f729Sjoerg Type += Type.empty() ? "DATA" : " DATA";
17687330f729Sjoerg if (Section.isBSS())
17697330f729Sjoerg Type += Type.empty() ? "BSS" : " BSS";
17707330f729Sjoerg
17717330f729Sjoerg if (HasLMAColumn)
17727330f729Sjoerg outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth,
17737330f729Sjoerg Name.str().c_str(), Size)
17747330f729Sjoerg << format_hex_no_prefix(VMA, AddressWidth) << " "
17757330f729Sjoerg << format_hex_no_prefix(getELFSectionLMA(Section), AddressWidth)
17767330f729Sjoerg << " " << Type << "\n";
17777330f729Sjoerg else
17787330f729Sjoerg outs() << format("%3" PRIu64 " %-*s %08" PRIx64 " ", Idx, NameWidth,
17797330f729Sjoerg Name.str().c_str(), Size)
17807330f729Sjoerg << format_hex_no_prefix(VMA, AddressWidth) << " " << Type << "\n";
17817330f729Sjoerg }
17827330f729Sjoerg }
17837330f729Sjoerg
printSectionContents(const ObjectFile * Obj)1784*82d56013Sjoerg void objdump::printSectionContents(const ObjectFile *Obj) {
1785*82d56013Sjoerg const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj);
1786*82d56013Sjoerg
17877330f729Sjoerg for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
17887330f729Sjoerg StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());
17897330f729Sjoerg uint64_t BaseAddr = Section.getAddress();
17907330f729Sjoerg uint64_t Size = Section.getSize();
17917330f729Sjoerg if (!Size)
17927330f729Sjoerg continue;
17937330f729Sjoerg
1794*82d56013Sjoerg outs() << "Contents of section ";
1795*82d56013Sjoerg StringRef SegmentName = getSegmentName(MachO, Section);
1796*82d56013Sjoerg if (!SegmentName.empty())
1797*82d56013Sjoerg outs() << SegmentName << ",";
1798*82d56013Sjoerg outs() << Name << ":\n";
17997330f729Sjoerg if (Section.isBSS()) {
18007330f729Sjoerg outs() << format("<skipping contents of bss section at [%04" PRIx64
18017330f729Sjoerg ", %04" PRIx64 ")>\n",
18027330f729Sjoerg BaseAddr, BaseAddr + Size);
18037330f729Sjoerg continue;
18047330f729Sjoerg }
18057330f729Sjoerg
18067330f729Sjoerg StringRef Contents = unwrapOrError(Section.getContents(), Obj->getFileName());
18077330f729Sjoerg
18087330f729Sjoerg // Dump out the content as hex and printable ascii characters.
18097330f729Sjoerg for (std::size_t Addr = 0, End = Contents.size(); Addr < End; Addr += 16) {
18107330f729Sjoerg outs() << format(" %04" PRIx64 " ", BaseAddr + Addr);
18117330f729Sjoerg // Dump line of hex.
18127330f729Sjoerg for (std::size_t I = 0; I < 16; ++I) {
18137330f729Sjoerg if (I != 0 && I % 4 == 0)
18147330f729Sjoerg outs() << ' ';
18157330f729Sjoerg if (Addr + I < End)
18167330f729Sjoerg outs() << hexdigit((Contents[Addr + I] >> 4) & 0xF, true)
18177330f729Sjoerg << hexdigit(Contents[Addr + I] & 0xF, true);
18187330f729Sjoerg else
18197330f729Sjoerg outs() << " ";
18207330f729Sjoerg }
18217330f729Sjoerg // Print ascii.
18227330f729Sjoerg outs() << " ";
18237330f729Sjoerg for (std::size_t I = 0; I < 16 && Addr + I < End; ++I) {
18247330f729Sjoerg if (isPrint(static_cast<unsigned char>(Contents[Addr + I]) & 0xFF))
18257330f729Sjoerg outs() << Contents[Addr + I];
18267330f729Sjoerg else
18277330f729Sjoerg outs() << ".";
18287330f729Sjoerg }
18297330f729Sjoerg outs() << "\n";
18307330f729Sjoerg }
18317330f729Sjoerg }
18327330f729Sjoerg }
18337330f729Sjoerg
printSymbolTable(const ObjectFile * O,StringRef ArchiveName,StringRef ArchitectureName,bool DumpDynamic)1834*82d56013Sjoerg void objdump::printSymbolTable(const ObjectFile *O, StringRef ArchiveName,
1835*82d56013Sjoerg StringRef ArchitectureName, bool DumpDynamic) {
1836*82d56013Sjoerg if (O->isCOFF() && !DumpDynamic) {
1837*82d56013Sjoerg outs() << "\nSYMBOL TABLE:\n";
1838*82d56013Sjoerg printCOFFSymbolTable(cast<const COFFObjectFile>(O));
18397330f729Sjoerg return;
18407330f729Sjoerg }
18417330f729Sjoerg
18427330f729Sjoerg const StringRef FileName = O->getFileName();
1843*82d56013Sjoerg
1844*82d56013Sjoerg if (!DumpDynamic) {
1845*82d56013Sjoerg outs() << "\nSYMBOL TABLE:\n";
1846*82d56013Sjoerg for (auto I = O->symbol_begin(); I != O->symbol_end(); ++I)
1847*82d56013Sjoerg printSymbol(O, *I, FileName, ArchiveName, ArchitectureName, DumpDynamic);
1848*82d56013Sjoerg return;
1849*82d56013Sjoerg }
1850*82d56013Sjoerg
1851*82d56013Sjoerg outs() << "\nDYNAMIC SYMBOL TABLE:\n";
1852*82d56013Sjoerg if (!O->isELF()) {
1853*82d56013Sjoerg reportWarning(
1854*82d56013Sjoerg "this operation is not currently supported for this file format",
1855*82d56013Sjoerg FileName);
1856*82d56013Sjoerg return;
1857*82d56013Sjoerg }
1858*82d56013Sjoerg
1859*82d56013Sjoerg const ELFObjectFileBase *ELF = cast<const ELFObjectFileBase>(O);
1860*82d56013Sjoerg for (auto I = ELF->getDynamicSymbolIterators().begin();
1861*82d56013Sjoerg I != ELF->getDynamicSymbolIterators().end(); ++I)
1862*82d56013Sjoerg printSymbol(O, *I, FileName, ArchiveName, ArchitectureName, DumpDynamic);
1863*82d56013Sjoerg }
1864*82d56013Sjoerg
printSymbol(const ObjectFile * O,const SymbolRef & Symbol,StringRef FileName,StringRef ArchiveName,StringRef ArchitectureName,bool DumpDynamic)1865*82d56013Sjoerg void objdump::printSymbol(const ObjectFile *O, const SymbolRef &Symbol,
1866*82d56013Sjoerg StringRef FileName, StringRef ArchiveName,
1867*82d56013Sjoerg StringRef ArchitectureName, bool DumpDynamic) {
1868*82d56013Sjoerg const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(O);
18697330f729Sjoerg uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName, ArchiveName,
18707330f729Sjoerg ArchitectureName);
18717330f729Sjoerg if ((Address < StartAddress) || (Address > StopAddress))
1872*82d56013Sjoerg return;
1873*82d56013Sjoerg SymbolRef::Type Type =
1874*82d56013Sjoerg unwrapOrError(Symbol.getType(), FileName, ArchiveName, ArchitectureName);
1875*82d56013Sjoerg uint32_t Flags =
1876*82d56013Sjoerg unwrapOrError(Symbol.getFlags(), FileName, ArchiveName, ArchitectureName);
1877*82d56013Sjoerg
1878*82d56013Sjoerg // Don't ask a Mach-O STAB symbol for its section unless you know that
1879*82d56013Sjoerg // STAB symbol's section field refers to a valid section index. Otherwise
1880*82d56013Sjoerg // the symbol may error trying to load a section that does not exist.
1881*82d56013Sjoerg bool IsSTAB = false;
1882*82d56013Sjoerg if (MachO) {
1883*82d56013Sjoerg DataRefImpl SymDRI = Symbol.getRawDataRefImpl();
1884*82d56013Sjoerg uint8_t NType =
1885*82d56013Sjoerg (MachO->is64Bit() ? MachO->getSymbol64TableEntry(SymDRI).n_type
1886*82d56013Sjoerg : MachO->getSymbolTableEntry(SymDRI).n_type);
1887*82d56013Sjoerg if (NType & MachO::N_STAB)
1888*82d56013Sjoerg IsSTAB = true;
1889*82d56013Sjoerg }
1890*82d56013Sjoerg section_iterator Section = IsSTAB
1891*82d56013Sjoerg ? O->section_end()
1892*82d56013Sjoerg : unwrapOrError(Symbol.getSection(), FileName,
18937330f729Sjoerg ArchiveName, ArchitectureName);
1894*82d56013Sjoerg
18957330f729Sjoerg StringRef Name;
18967330f729Sjoerg if (Type == SymbolRef::ST_Debug && Section != O->section_end()) {
18977330f729Sjoerg if (Expected<StringRef> NameOrErr = Section->getName())
18987330f729Sjoerg Name = *NameOrErr;
18997330f729Sjoerg else
19007330f729Sjoerg consumeError(NameOrErr.takeError());
19017330f729Sjoerg
19027330f729Sjoerg } else {
19037330f729Sjoerg Name = unwrapOrError(Symbol.getName(), FileName, ArchiveName,
19047330f729Sjoerg ArchitectureName);
19057330f729Sjoerg }
19067330f729Sjoerg
19077330f729Sjoerg bool Global = Flags & SymbolRef::SF_Global;
19087330f729Sjoerg bool Weak = Flags & SymbolRef::SF_Weak;
19097330f729Sjoerg bool Absolute = Flags & SymbolRef::SF_Absolute;
19107330f729Sjoerg bool Common = Flags & SymbolRef::SF_Common;
19117330f729Sjoerg bool Hidden = Flags & SymbolRef::SF_Hidden;
19127330f729Sjoerg
19137330f729Sjoerg char GlobLoc = ' ';
1914*82d56013Sjoerg if ((Section != O->section_end() || Absolute) && !Weak)
19157330f729Sjoerg GlobLoc = Global ? 'g' : 'l';
1916*82d56013Sjoerg char IFunc = ' ';
1917*82d56013Sjoerg if (O->isELF()) {
1918*82d56013Sjoerg if (ELFSymbolRef(Symbol).getELFType() == ELF::STT_GNU_IFUNC)
1919*82d56013Sjoerg IFunc = 'i';
1920*82d56013Sjoerg if (ELFSymbolRef(Symbol).getBinding() == ELF::STB_GNU_UNIQUE)
1921*82d56013Sjoerg GlobLoc = 'u';
1922*82d56013Sjoerg }
1923*82d56013Sjoerg
1924*82d56013Sjoerg char Debug = ' ';
1925*82d56013Sjoerg if (DumpDynamic)
1926*82d56013Sjoerg Debug = 'D';
1927*82d56013Sjoerg else if (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File)
1928*82d56013Sjoerg Debug = 'd';
1929*82d56013Sjoerg
19307330f729Sjoerg char FileFunc = ' ';
19317330f729Sjoerg if (Type == SymbolRef::ST_File)
19327330f729Sjoerg FileFunc = 'f';
19337330f729Sjoerg else if (Type == SymbolRef::ST_Function)
19347330f729Sjoerg FileFunc = 'F';
19357330f729Sjoerg else if (Type == SymbolRef::ST_Data)
19367330f729Sjoerg FileFunc = 'O';
19377330f729Sjoerg
1938*82d56013Sjoerg const char *Fmt = O->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
19397330f729Sjoerg
19407330f729Sjoerg outs() << format(Fmt, Address) << " "
19417330f729Sjoerg << GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' '
19427330f729Sjoerg << (Weak ? 'w' : ' ') // Weak?
19437330f729Sjoerg << ' ' // Constructor. Not supported yet.
19447330f729Sjoerg << ' ' // Warning. Not supported yet.
1945*82d56013Sjoerg << IFunc // Indirect reference to another symbol.
19467330f729Sjoerg << Debug // Debugging (d) or dynamic (D) symbol.
19477330f729Sjoerg << FileFunc // Name of function (F), file (f) or object (O).
19487330f729Sjoerg << ' ';
19497330f729Sjoerg if (Absolute) {
19507330f729Sjoerg outs() << "*ABS*";
19517330f729Sjoerg } else if (Common) {
19527330f729Sjoerg outs() << "*COM*";
19537330f729Sjoerg } else if (Section == O->section_end()) {
19547330f729Sjoerg outs() << "*UND*";
19557330f729Sjoerg } else {
1956*82d56013Sjoerg StringRef SegmentName = getSegmentName(MachO, *Section);
1957*82d56013Sjoerg if (!SegmentName.empty())
19587330f729Sjoerg outs() << SegmentName << ",";
1959*82d56013Sjoerg StringRef SectionName = unwrapOrError(Section->getName(), FileName);
19607330f729Sjoerg outs() << SectionName;
19617330f729Sjoerg }
19627330f729Sjoerg
1963*82d56013Sjoerg if (Common || O->isELF()) {
19647330f729Sjoerg uint64_t Val =
19657330f729Sjoerg Common ? Symbol.getAlignment() : ELFSymbolRef(Symbol).getSize();
1966*82d56013Sjoerg outs() << '\t' << format(Fmt, Val);
19677330f729Sjoerg }
19687330f729Sjoerg
1969*82d56013Sjoerg if (O->isELF()) {
19707330f729Sjoerg uint8_t Other = ELFSymbolRef(Symbol).getOther();
19717330f729Sjoerg switch (Other) {
19727330f729Sjoerg case ELF::STV_DEFAULT:
19737330f729Sjoerg break;
19747330f729Sjoerg case ELF::STV_INTERNAL:
19757330f729Sjoerg outs() << " .internal";
19767330f729Sjoerg break;
19777330f729Sjoerg case ELF::STV_HIDDEN:
19787330f729Sjoerg outs() << " .hidden";
19797330f729Sjoerg break;
19807330f729Sjoerg case ELF::STV_PROTECTED:
19817330f729Sjoerg outs() << " .protected";
19827330f729Sjoerg break;
19837330f729Sjoerg default:
19847330f729Sjoerg outs() << format(" 0x%02x", Other);
19857330f729Sjoerg break;
19867330f729Sjoerg }
19877330f729Sjoerg } else if (Hidden) {
19887330f729Sjoerg outs() << " .hidden";
19897330f729Sjoerg }
19907330f729Sjoerg
19917330f729Sjoerg if (Demangle)
1992*82d56013Sjoerg outs() << ' ' << demangle(std::string(Name)) << '\n';
19937330f729Sjoerg else
19947330f729Sjoerg outs() << ' ' << Name << '\n';
19957330f729Sjoerg }
19967330f729Sjoerg
printUnwindInfo(const ObjectFile * O)19977330f729Sjoerg static void printUnwindInfo(const ObjectFile *O) {
19987330f729Sjoerg outs() << "Unwind info:\n\n";
19997330f729Sjoerg
20007330f729Sjoerg if (const COFFObjectFile *Coff = dyn_cast<COFFObjectFile>(O))
20017330f729Sjoerg printCOFFUnwindInfo(Coff);
20027330f729Sjoerg else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O))
20037330f729Sjoerg printMachOUnwindInfo(MachO);
20047330f729Sjoerg else
20057330f729Sjoerg // TODO: Extract DWARF dump tool to objdump.
20067330f729Sjoerg WithColor::error(errs(), ToolName)
20077330f729Sjoerg << "This operation is only currently supported "
20087330f729Sjoerg "for COFF and MachO object files.\n";
20097330f729Sjoerg }
20107330f729Sjoerg
20117330f729Sjoerg /// Dump the raw contents of the __clangast section so the output can be piped
20127330f729Sjoerg /// into llvm-bcanalyzer.
printRawClangAST(const ObjectFile * Obj)2013*82d56013Sjoerg static void printRawClangAST(const ObjectFile *Obj) {
20147330f729Sjoerg if (outs().is_displayed()) {
20157330f729Sjoerg WithColor::error(errs(), ToolName)
20167330f729Sjoerg << "The -raw-clang-ast option will dump the raw binary contents of "
20177330f729Sjoerg "the clang ast section.\n"
20187330f729Sjoerg "Please redirect the output to a file or another program such as "
20197330f729Sjoerg "llvm-bcanalyzer.\n";
20207330f729Sjoerg return;
20217330f729Sjoerg }
20227330f729Sjoerg
20237330f729Sjoerg StringRef ClangASTSectionName("__clangast");
2024*82d56013Sjoerg if (Obj->isCOFF()) {
20257330f729Sjoerg ClangASTSectionName = "clangast";
20267330f729Sjoerg }
20277330f729Sjoerg
20287330f729Sjoerg Optional<object::SectionRef> ClangASTSection;
20297330f729Sjoerg for (auto Sec : ToolSectionFilter(*Obj)) {
20307330f729Sjoerg StringRef Name;
20317330f729Sjoerg if (Expected<StringRef> NameOrErr = Sec.getName())
20327330f729Sjoerg Name = *NameOrErr;
20337330f729Sjoerg else
20347330f729Sjoerg consumeError(NameOrErr.takeError());
20357330f729Sjoerg
20367330f729Sjoerg if (Name == ClangASTSectionName) {
20377330f729Sjoerg ClangASTSection = Sec;
20387330f729Sjoerg break;
20397330f729Sjoerg }
20407330f729Sjoerg }
20417330f729Sjoerg if (!ClangASTSection)
20427330f729Sjoerg return;
20437330f729Sjoerg
20447330f729Sjoerg StringRef ClangASTContents = unwrapOrError(
20457330f729Sjoerg ClangASTSection.getValue().getContents(), Obj->getFileName());
20467330f729Sjoerg outs().write(ClangASTContents.data(), ClangASTContents.size());
20477330f729Sjoerg }
20487330f729Sjoerg
printFaultMaps(const ObjectFile * Obj)20497330f729Sjoerg static void printFaultMaps(const ObjectFile *Obj) {
20507330f729Sjoerg StringRef FaultMapSectionName;
20517330f729Sjoerg
2052*82d56013Sjoerg if (Obj->isELF()) {
20537330f729Sjoerg FaultMapSectionName = ".llvm_faultmaps";
2054*82d56013Sjoerg } else if (Obj->isMachO()) {
20557330f729Sjoerg FaultMapSectionName = "__llvm_faultmaps";
20567330f729Sjoerg } else {
20577330f729Sjoerg WithColor::error(errs(), ToolName)
20587330f729Sjoerg << "This operation is only currently supported "
20597330f729Sjoerg "for ELF and Mach-O executable files.\n";
20607330f729Sjoerg return;
20617330f729Sjoerg }
20627330f729Sjoerg
20637330f729Sjoerg Optional<object::SectionRef> FaultMapSection;
20647330f729Sjoerg
20657330f729Sjoerg for (auto Sec : ToolSectionFilter(*Obj)) {
20667330f729Sjoerg StringRef Name;
20677330f729Sjoerg if (Expected<StringRef> NameOrErr = Sec.getName())
20687330f729Sjoerg Name = *NameOrErr;
20697330f729Sjoerg else
20707330f729Sjoerg consumeError(NameOrErr.takeError());
20717330f729Sjoerg
20727330f729Sjoerg if (Name == FaultMapSectionName) {
20737330f729Sjoerg FaultMapSection = Sec;
20747330f729Sjoerg break;
20757330f729Sjoerg }
20767330f729Sjoerg }
20777330f729Sjoerg
20787330f729Sjoerg outs() << "FaultMap table:\n";
20797330f729Sjoerg
20807330f729Sjoerg if (!FaultMapSection.hasValue()) {
20817330f729Sjoerg outs() << "<not found>\n";
20827330f729Sjoerg return;
20837330f729Sjoerg }
20847330f729Sjoerg
20857330f729Sjoerg StringRef FaultMapContents =
20867330f729Sjoerg unwrapOrError(FaultMapSection.getValue().getContents(), Obj->getFileName());
20877330f729Sjoerg FaultMapParser FMP(FaultMapContents.bytes_begin(),
20887330f729Sjoerg FaultMapContents.bytes_end());
20897330f729Sjoerg
20907330f729Sjoerg outs() << FMP;
20917330f729Sjoerg }
20927330f729Sjoerg
printPrivateFileHeaders(const ObjectFile * O,bool OnlyFirst)20937330f729Sjoerg static void printPrivateFileHeaders(const ObjectFile *O, bool OnlyFirst) {
20947330f729Sjoerg if (O->isELF()) {
20957330f729Sjoerg printELFFileHeader(O);
20967330f729Sjoerg printELFDynamicSection(O);
20977330f729Sjoerg printELFSymbolVersionInfo(O);
20987330f729Sjoerg return;
20997330f729Sjoerg }
21007330f729Sjoerg if (O->isCOFF())
21017330f729Sjoerg return printCOFFFileHeader(O);
21027330f729Sjoerg if (O->isWasm())
21037330f729Sjoerg return printWasmFileHeader(O);
21047330f729Sjoerg if (O->isMachO()) {
21057330f729Sjoerg printMachOFileHeader(O);
21067330f729Sjoerg if (!OnlyFirst)
21077330f729Sjoerg printMachOLoadCommands(O);
21087330f729Sjoerg return;
21097330f729Sjoerg }
21107330f729Sjoerg reportError(O->getFileName(), "Invalid/Unsupported object file format");
21117330f729Sjoerg }
21127330f729Sjoerg
printFileHeaders(const ObjectFile * O)21137330f729Sjoerg static void printFileHeaders(const ObjectFile *O) {
21147330f729Sjoerg if (!O->isELF() && !O->isCOFF())
21157330f729Sjoerg reportError(O->getFileName(), "Invalid/Unsupported object file format");
21167330f729Sjoerg
21177330f729Sjoerg Triple::ArchType AT = O->getArch();
21187330f729Sjoerg outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n";
21197330f729Sjoerg uint64_t Address = unwrapOrError(O->getStartAddress(), O->getFileName());
21207330f729Sjoerg
21217330f729Sjoerg StringRef Fmt = O->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
21227330f729Sjoerg outs() << "start address: "
2123*82d56013Sjoerg << "0x" << format(Fmt.data(), Address) << "\n";
21247330f729Sjoerg }
21257330f729Sjoerg
printArchiveChild(StringRef Filename,const Archive::Child & C)21267330f729Sjoerg static void printArchiveChild(StringRef Filename, const Archive::Child &C) {
21277330f729Sjoerg Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
21287330f729Sjoerg if (!ModeOrErr) {
21297330f729Sjoerg WithColor::error(errs(), ToolName) << "ill-formed archive entry.\n";
21307330f729Sjoerg consumeError(ModeOrErr.takeError());
21317330f729Sjoerg return;
21327330f729Sjoerg }
21337330f729Sjoerg sys::fs::perms Mode = ModeOrErr.get();
21347330f729Sjoerg outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
21357330f729Sjoerg outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
21367330f729Sjoerg outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
21377330f729Sjoerg outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
21387330f729Sjoerg outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
21397330f729Sjoerg outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
21407330f729Sjoerg outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
21417330f729Sjoerg outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
21427330f729Sjoerg outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
21437330f729Sjoerg
21447330f729Sjoerg outs() << " ";
21457330f729Sjoerg
21467330f729Sjoerg outs() << format("%d/%d %6" PRId64 " ", unwrapOrError(C.getUID(), Filename),
21477330f729Sjoerg unwrapOrError(C.getGID(), Filename),
21487330f729Sjoerg unwrapOrError(C.getRawSize(), Filename));
21497330f729Sjoerg
21507330f729Sjoerg StringRef RawLastModified = C.getRawLastModified();
21517330f729Sjoerg unsigned Seconds;
21527330f729Sjoerg if (RawLastModified.getAsInteger(10, Seconds))
21537330f729Sjoerg outs() << "(date: \"" << RawLastModified
21547330f729Sjoerg << "\" contains non-decimal chars) ";
21557330f729Sjoerg else {
21567330f729Sjoerg // Since ctime(3) returns a 26 character string of the form:
21577330f729Sjoerg // "Sun Sep 16 01:03:52 1973\n\0"
21587330f729Sjoerg // just print 24 characters.
21597330f729Sjoerg time_t t = Seconds;
21607330f729Sjoerg outs() << format("%.24s ", ctime(&t));
21617330f729Sjoerg }
21627330f729Sjoerg
21637330f729Sjoerg StringRef Name = "";
21647330f729Sjoerg Expected<StringRef> NameOrErr = C.getName();
21657330f729Sjoerg if (!NameOrErr) {
21667330f729Sjoerg consumeError(NameOrErr.takeError());
21677330f729Sjoerg Name = unwrapOrError(C.getRawName(), Filename);
21687330f729Sjoerg } else {
21697330f729Sjoerg Name = NameOrErr.get();
21707330f729Sjoerg }
21717330f729Sjoerg outs() << Name << "\n";
21727330f729Sjoerg }
21737330f729Sjoerg
21747330f729Sjoerg // For ELF only now.
shouldWarnForInvalidStartStopAddress(ObjectFile * Obj)21757330f729Sjoerg static bool shouldWarnForInvalidStartStopAddress(ObjectFile *Obj) {
21767330f729Sjoerg if (const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj)) {
21777330f729Sjoerg if (Elf->getEType() != ELF::ET_REL)
21787330f729Sjoerg return true;
21797330f729Sjoerg }
21807330f729Sjoerg return false;
21817330f729Sjoerg }
21827330f729Sjoerg
checkForInvalidStartStopAddress(ObjectFile * Obj,uint64_t Start,uint64_t Stop)21837330f729Sjoerg static void checkForInvalidStartStopAddress(ObjectFile *Obj,
21847330f729Sjoerg uint64_t Start, uint64_t Stop) {
21857330f729Sjoerg if (!shouldWarnForInvalidStartStopAddress(Obj))
21867330f729Sjoerg return;
21877330f729Sjoerg
21887330f729Sjoerg for (const SectionRef &Section : Obj->sections())
21897330f729Sjoerg if (ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC) {
21907330f729Sjoerg uint64_t BaseAddr = Section.getAddress();
21917330f729Sjoerg uint64_t Size = Section.getSize();
21927330f729Sjoerg if ((Start < BaseAddr + Size) && Stop > BaseAddr)
21937330f729Sjoerg return;
21947330f729Sjoerg }
21957330f729Sjoerg
2196*82d56013Sjoerg if (!HasStartAddressFlag)
21977330f729Sjoerg reportWarning("no section has address less than 0x" +
21987330f729Sjoerg Twine::utohexstr(Stop) + " specified by --stop-address",
21997330f729Sjoerg Obj->getFileName());
2200*82d56013Sjoerg else if (!HasStopAddressFlag)
22017330f729Sjoerg reportWarning("no section has address greater than or equal to 0x" +
22027330f729Sjoerg Twine::utohexstr(Start) + " specified by --start-address",
22037330f729Sjoerg Obj->getFileName());
22047330f729Sjoerg else
22057330f729Sjoerg reportWarning("no section overlaps the range [0x" +
22067330f729Sjoerg Twine::utohexstr(Start) + ",0x" + Twine::utohexstr(Stop) +
22077330f729Sjoerg ") specified by --start-address/--stop-address",
22087330f729Sjoerg Obj->getFileName());
22097330f729Sjoerg }
22107330f729Sjoerg
dumpObject(ObjectFile * O,const Archive * A=nullptr,const Archive::Child * C=nullptr)22117330f729Sjoerg static void dumpObject(ObjectFile *O, const Archive *A = nullptr,
22127330f729Sjoerg const Archive::Child *C = nullptr) {
22137330f729Sjoerg // Avoid other output when using a raw option.
22147330f729Sjoerg if (!RawClangAST) {
22157330f729Sjoerg outs() << '\n';
22167330f729Sjoerg if (A)
22177330f729Sjoerg outs() << A->getFileName() << "(" << O->getFileName() << ")";
22187330f729Sjoerg else
22197330f729Sjoerg outs() << O->getFileName();
2220*82d56013Sjoerg outs() << ":\tfile format " << O->getFileFormatName().lower() << "\n";
22217330f729Sjoerg }
22227330f729Sjoerg
2223*82d56013Sjoerg if (HasStartAddressFlag || HasStopAddressFlag)
22247330f729Sjoerg checkForInvalidStartStopAddress(O, StartAddress, StopAddress);
22257330f729Sjoerg
22267330f729Sjoerg // Note: the order here matches GNU objdump for compatability.
22277330f729Sjoerg StringRef ArchiveName = A ? A->getFileName() : "";
22287330f729Sjoerg if (ArchiveHeaders && !MachOOpt && C)
22297330f729Sjoerg printArchiveChild(ArchiveName, *C);
22307330f729Sjoerg if (FileHeaders)
22317330f729Sjoerg printFileHeaders(O);
22327330f729Sjoerg if (PrivateHeaders || FirstPrivateHeader)
22337330f729Sjoerg printPrivateFileHeaders(O, FirstPrivateHeader);
22347330f729Sjoerg if (SectionHeaders)
22357330f729Sjoerg printSectionHeaders(O);
22367330f729Sjoerg if (SymbolTable)
22377330f729Sjoerg printSymbolTable(O, ArchiveName);
2238*82d56013Sjoerg if (DynamicSymbolTable)
2239*82d56013Sjoerg printSymbolTable(O, ArchiveName, /*ArchitectureName=*/"",
2240*82d56013Sjoerg /*DumpDynamic=*/true);
22417330f729Sjoerg if (DwarfDumpType != DIDT_Null) {
22427330f729Sjoerg std::unique_ptr<DIContext> DICtx = DWARFContext::create(*O);
22437330f729Sjoerg // Dump the complete DWARF structure.
22447330f729Sjoerg DIDumpOptions DumpOpts;
22457330f729Sjoerg DumpOpts.DumpType = DwarfDumpType;
22467330f729Sjoerg DICtx->dump(outs(), DumpOpts);
22477330f729Sjoerg }
22487330f729Sjoerg if (Relocations && !Disassemble)
22497330f729Sjoerg printRelocations(O);
22507330f729Sjoerg if (DynamicRelocations)
22517330f729Sjoerg printDynamicRelocations(O);
22527330f729Sjoerg if (SectionContents)
22537330f729Sjoerg printSectionContents(O);
22547330f729Sjoerg if (Disassemble)
22557330f729Sjoerg disassembleObject(O, Relocations);
22567330f729Sjoerg if (UnwindInfo)
22577330f729Sjoerg printUnwindInfo(O);
22587330f729Sjoerg
22597330f729Sjoerg // Mach-O specific options:
22607330f729Sjoerg if (ExportsTrie)
22617330f729Sjoerg printExportsTrie(O);
22627330f729Sjoerg if (Rebase)
22637330f729Sjoerg printRebaseTable(O);
22647330f729Sjoerg if (Bind)
22657330f729Sjoerg printBindTable(O);
22667330f729Sjoerg if (LazyBind)
22677330f729Sjoerg printLazyBindTable(O);
22687330f729Sjoerg if (WeakBind)
22697330f729Sjoerg printWeakBindTable(O);
22707330f729Sjoerg
22717330f729Sjoerg // Other special sections:
22727330f729Sjoerg if (RawClangAST)
22737330f729Sjoerg printRawClangAST(O);
22747330f729Sjoerg if (FaultMapSection)
22757330f729Sjoerg printFaultMaps(O);
22767330f729Sjoerg }
22777330f729Sjoerg
dumpObject(const COFFImportFile * I,const Archive * A,const Archive::Child * C=nullptr)22787330f729Sjoerg static void dumpObject(const COFFImportFile *I, const Archive *A,
22797330f729Sjoerg const Archive::Child *C = nullptr) {
22807330f729Sjoerg StringRef ArchiveName = A ? A->getFileName() : "";
22817330f729Sjoerg
22827330f729Sjoerg // Avoid other output when using a raw option.
22837330f729Sjoerg if (!RawClangAST)
22847330f729Sjoerg outs() << '\n'
22857330f729Sjoerg << ArchiveName << "(" << I->getFileName() << ")"
22867330f729Sjoerg << ":\tfile format COFF-import-file"
22877330f729Sjoerg << "\n\n";
22887330f729Sjoerg
22897330f729Sjoerg if (ArchiveHeaders && !MachOOpt && C)
22907330f729Sjoerg printArchiveChild(ArchiveName, *C);
22917330f729Sjoerg if (SymbolTable)
22927330f729Sjoerg printCOFFSymbolTable(I);
22937330f729Sjoerg }
22947330f729Sjoerg
22957330f729Sjoerg /// Dump each object file in \a a;
dumpArchive(const Archive * A)22967330f729Sjoerg static void dumpArchive(const Archive *A) {
22977330f729Sjoerg Error Err = Error::success();
22987330f729Sjoerg unsigned I = -1;
22997330f729Sjoerg for (auto &C : A->children(Err)) {
23007330f729Sjoerg ++I;
23017330f729Sjoerg Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
23027330f729Sjoerg if (!ChildOrErr) {
23037330f729Sjoerg if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
23047330f729Sjoerg reportError(std::move(E), getFileNameForError(C, I), A->getFileName());
23057330f729Sjoerg continue;
23067330f729Sjoerg }
23077330f729Sjoerg if (ObjectFile *O = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
23087330f729Sjoerg dumpObject(O, A, &C);
23097330f729Sjoerg else if (COFFImportFile *I = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))
23107330f729Sjoerg dumpObject(I, A, &C);
23117330f729Sjoerg else
23127330f729Sjoerg reportError(errorCodeToError(object_error::invalid_file_type),
23137330f729Sjoerg A->getFileName());
23147330f729Sjoerg }
23157330f729Sjoerg if (Err)
23167330f729Sjoerg reportError(std::move(Err), A->getFileName());
23177330f729Sjoerg }
23187330f729Sjoerg
23197330f729Sjoerg /// Open file and figure out how to dump it.
dumpInput(StringRef file)23207330f729Sjoerg static void dumpInput(StringRef file) {
23217330f729Sjoerg // If we are using the Mach-O specific object file parser, then let it parse
23227330f729Sjoerg // the file and process the command line options. So the -arch flags can
23237330f729Sjoerg // be used to select specific slices, etc.
23247330f729Sjoerg if (MachOOpt) {
23257330f729Sjoerg parseInputMachO(file);
23267330f729Sjoerg return;
23277330f729Sjoerg }
23287330f729Sjoerg
23297330f729Sjoerg // Attempt to open the binary.
23307330f729Sjoerg OwningBinary<Binary> OBinary = unwrapOrError(createBinary(file), file);
23317330f729Sjoerg Binary &Binary = *OBinary.getBinary();
23327330f729Sjoerg
23337330f729Sjoerg if (Archive *A = dyn_cast<Archive>(&Binary))
23347330f729Sjoerg dumpArchive(A);
23357330f729Sjoerg else if (ObjectFile *O = dyn_cast<ObjectFile>(&Binary))
23367330f729Sjoerg dumpObject(O);
23377330f729Sjoerg else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary))
23387330f729Sjoerg parseInputMachO(UB);
23397330f729Sjoerg else
23407330f729Sjoerg reportError(errorCodeToError(object_error::invalid_file_type), file);
23417330f729Sjoerg }
2342*82d56013Sjoerg
2343*82d56013Sjoerg template <typename T>
parseIntArg(const llvm::opt::InputArgList & InputArgs,int ID,T & Value)2344*82d56013Sjoerg static void parseIntArg(const llvm::opt::InputArgList &InputArgs, int ID,
2345*82d56013Sjoerg T &Value) {
2346*82d56013Sjoerg if (const opt::Arg *A = InputArgs.getLastArg(ID)) {
2347*82d56013Sjoerg StringRef V(A->getValue());
2348*82d56013Sjoerg if (!llvm::to_integer(V, Value, 0)) {
2349*82d56013Sjoerg reportCmdLineError(A->getSpelling() +
2350*82d56013Sjoerg ": expected a non-negative integer, but got '" + V +
2351*82d56013Sjoerg "'");
2352*82d56013Sjoerg }
2353*82d56013Sjoerg }
2354*82d56013Sjoerg }
2355*82d56013Sjoerg
2356*82d56013Sjoerg static std::vector<std::string>
commaSeparatedValues(const llvm::opt::InputArgList & InputArgs,int ID)2357*82d56013Sjoerg commaSeparatedValues(const llvm::opt::InputArgList &InputArgs, int ID) {
2358*82d56013Sjoerg std::vector<std::string> Values;
2359*82d56013Sjoerg for (StringRef Value : InputArgs.getAllArgValues(ID)) {
2360*82d56013Sjoerg llvm::SmallVector<StringRef, 2> SplitValues;
2361*82d56013Sjoerg llvm::SplitString(Value, SplitValues, ",");
2362*82d56013Sjoerg for (StringRef SplitValue : SplitValues)
2363*82d56013Sjoerg Values.push_back(SplitValue.str());
2364*82d56013Sjoerg }
2365*82d56013Sjoerg return Values;
2366*82d56013Sjoerg }
2367*82d56013Sjoerg
parseOtoolOptions(const llvm::opt::InputArgList & InputArgs)2368*82d56013Sjoerg static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) {
2369*82d56013Sjoerg MachOOpt = true;
2370*82d56013Sjoerg FullLeadingAddr = true;
2371*82d56013Sjoerg PrintImmHex = true;
2372*82d56013Sjoerg
2373*82d56013Sjoerg ArchName = InputArgs.getLastArgValue(OTOOL_arch).str();
2374*82d56013Sjoerg LinkOptHints = InputArgs.hasArg(OTOOL_C);
2375*82d56013Sjoerg if (InputArgs.hasArg(OTOOL_d))
2376*82d56013Sjoerg FilterSections.push_back("__DATA,__data");
2377*82d56013Sjoerg DylibId = InputArgs.hasArg(OTOOL_D);
2378*82d56013Sjoerg UniversalHeaders = InputArgs.hasArg(OTOOL_f);
2379*82d56013Sjoerg DataInCode = InputArgs.hasArg(OTOOL_G);
2380*82d56013Sjoerg FirstPrivateHeader = InputArgs.hasArg(OTOOL_h);
2381*82d56013Sjoerg IndirectSymbols = InputArgs.hasArg(OTOOL_I);
2382*82d56013Sjoerg ShowRawInsn = InputArgs.hasArg(OTOOL_j);
2383*82d56013Sjoerg PrivateHeaders = InputArgs.hasArg(OTOOL_l);
2384*82d56013Sjoerg DylibsUsed = InputArgs.hasArg(OTOOL_L);
2385*82d56013Sjoerg MCPU = InputArgs.getLastArgValue(OTOOL_mcpu_EQ).str();
2386*82d56013Sjoerg ObjcMetaData = InputArgs.hasArg(OTOOL_o);
2387*82d56013Sjoerg DisSymName = InputArgs.getLastArgValue(OTOOL_p).str();
2388*82d56013Sjoerg InfoPlist = InputArgs.hasArg(OTOOL_P);
2389*82d56013Sjoerg Relocations = InputArgs.hasArg(OTOOL_r);
2390*82d56013Sjoerg if (const Arg *A = InputArgs.getLastArg(OTOOL_s)) {
2391*82d56013Sjoerg auto Filter = (A->getValue(0) + StringRef(",") + A->getValue(1)).str();
2392*82d56013Sjoerg FilterSections.push_back(Filter);
2393*82d56013Sjoerg }
2394*82d56013Sjoerg if (InputArgs.hasArg(OTOOL_t))
2395*82d56013Sjoerg FilterSections.push_back("__TEXT,__text");
2396*82d56013Sjoerg Verbose = InputArgs.hasArg(OTOOL_v) || InputArgs.hasArg(OTOOL_V) ||
2397*82d56013Sjoerg InputArgs.hasArg(OTOOL_o);
2398*82d56013Sjoerg SymbolicOperands = InputArgs.hasArg(OTOOL_V);
2399*82d56013Sjoerg if (InputArgs.hasArg(OTOOL_x))
2400*82d56013Sjoerg FilterSections.push_back(",__text");
2401*82d56013Sjoerg LeadingAddr = LeadingHeaders = !InputArgs.hasArg(OTOOL_X);
2402*82d56013Sjoerg
2403*82d56013Sjoerg InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT);
2404*82d56013Sjoerg if (InputFilenames.empty())
2405*82d56013Sjoerg reportCmdLineError("no input file");
2406*82d56013Sjoerg
2407*82d56013Sjoerg for (const Arg *A : InputArgs) {
2408*82d56013Sjoerg const Option &O = A->getOption();
2409*82d56013Sjoerg if (O.getGroup().isValid() && O.getGroup().getID() == OTOOL_grp_obsolete) {
2410*82d56013Sjoerg reportCmdLineWarning(O.getPrefixedName() +
2411*82d56013Sjoerg " is obsolete and not implemented");
2412*82d56013Sjoerg }
2413*82d56013Sjoerg }
2414*82d56013Sjoerg }
2415*82d56013Sjoerg
parseObjdumpOptions(const llvm::opt::InputArgList & InputArgs)2416*82d56013Sjoerg static void parseObjdumpOptions(const llvm::opt::InputArgList &InputArgs) {
2417*82d56013Sjoerg parseIntArg(InputArgs, OBJDUMP_adjust_vma_EQ, AdjustVMA);
2418*82d56013Sjoerg AllHeaders = InputArgs.hasArg(OBJDUMP_all_headers);
2419*82d56013Sjoerg ArchName = InputArgs.getLastArgValue(OBJDUMP_arch_name_EQ).str();
2420*82d56013Sjoerg ArchiveHeaders = InputArgs.hasArg(OBJDUMP_archive_headers);
2421*82d56013Sjoerg Demangle = InputArgs.hasArg(OBJDUMP_demangle);
2422*82d56013Sjoerg Disassemble = InputArgs.hasArg(OBJDUMP_disassemble);
2423*82d56013Sjoerg DisassembleAll = InputArgs.hasArg(OBJDUMP_disassemble_all);
2424*82d56013Sjoerg SymbolDescription = InputArgs.hasArg(OBJDUMP_symbol_description);
2425*82d56013Sjoerg DisassembleSymbols =
2426*82d56013Sjoerg commaSeparatedValues(InputArgs, OBJDUMP_disassemble_symbols_EQ);
2427*82d56013Sjoerg DisassembleZeroes = InputArgs.hasArg(OBJDUMP_disassemble_zeroes);
2428*82d56013Sjoerg if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_dwarf_EQ)) {
2429*82d56013Sjoerg DwarfDumpType =
2430*82d56013Sjoerg StringSwitch<DIDumpType>(A->getValue()).Case("frames", DIDT_DebugFrame);
2431*82d56013Sjoerg }
2432*82d56013Sjoerg DynamicRelocations = InputArgs.hasArg(OBJDUMP_dynamic_reloc);
2433*82d56013Sjoerg FaultMapSection = InputArgs.hasArg(OBJDUMP_fault_map_section);
2434*82d56013Sjoerg FileHeaders = InputArgs.hasArg(OBJDUMP_file_headers);
2435*82d56013Sjoerg SectionContents = InputArgs.hasArg(OBJDUMP_full_contents);
2436*82d56013Sjoerg PrintLines = InputArgs.hasArg(OBJDUMP_line_numbers);
2437*82d56013Sjoerg InputFilenames = InputArgs.getAllArgValues(OBJDUMP_INPUT);
2438*82d56013Sjoerg MachOOpt = InputArgs.hasArg(OBJDUMP_macho);
2439*82d56013Sjoerg MCPU = InputArgs.getLastArgValue(OBJDUMP_mcpu_EQ).str();
2440*82d56013Sjoerg MAttrs = commaSeparatedValues(InputArgs, OBJDUMP_mattr_EQ);
2441*82d56013Sjoerg ShowRawInsn = !InputArgs.hasArg(OBJDUMP_no_show_raw_insn);
2442*82d56013Sjoerg LeadingAddr = !InputArgs.hasArg(OBJDUMP_no_leading_addr);
2443*82d56013Sjoerg RawClangAST = InputArgs.hasArg(OBJDUMP_raw_clang_ast);
2444*82d56013Sjoerg Relocations = InputArgs.hasArg(OBJDUMP_reloc);
2445*82d56013Sjoerg PrintImmHex =
2446*82d56013Sjoerg InputArgs.hasFlag(OBJDUMP_print_imm_hex, OBJDUMP_no_print_imm_hex, false);
2447*82d56013Sjoerg PrivateHeaders = InputArgs.hasArg(OBJDUMP_private_headers);
2448*82d56013Sjoerg FilterSections = InputArgs.getAllArgValues(OBJDUMP_section_EQ);
2449*82d56013Sjoerg SectionHeaders = InputArgs.hasArg(OBJDUMP_section_headers);
2450*82d56013Sjoerg ShowLMA = InputArgs.hasArg(OBJDUMP_show_lma);
2451*82d56013Sjoerg PrintSource = InputArgs.hasArg(OBJDUMP_source);
2452*82d56013Sjoerg parseIntArg(InputArgs, OBJDUMP_start_address_EQ, StartAddress);
2453*82d56013Sjoerg HasStartAddressFlag = InputArgs.hasArg(OBJDUMP_start_address_EQ);
2454*82d56013Sjoerg parseIntArg(InputArgs, OBJDUMP_stop_address_EQ, StopAddress);
2455*82d56013Sjoerg HasStopAddressFlag = InputArgs.hasArg(OBJDUMP_stop_address_EQ);
2456*82d56013Sjoerg SymbolTable = InputArgs.hasArg(OBJDUMP_syms);
2457*82d56013Sjoerg SymbolizeOperands = InputArgs.hasArg(OBJDUMP_symbolize_operands);
2458*82d56013Sjoerg DynamicSymbolTable = InputArgs.hasArg(OBJDUMP_dynamic_syms);
2459*82d56013Sjoerg TripleName = InputArgs.getLastArgValue(OBJDUMP_triple_EQ).str();
2460*82d56013Sjoerg UnwindInfo = InputArgs.hasArg(OBJDUMP_unwind_info);
2461*82d56013Sjoerg Wide = InputArgs.hasArg(OBJDUMP_wide);
2462*82d56013Sjoerg Prefix = InputArgs.getLastArgValue(OBJDUMP_prefix).str();
2463*82d56013Sjoerg parseIntArg(InputArgs, OBJDUMP_prefix_strip, PrefixStrip);
2464*82d56013Sjoerg if (const opt::Arg *A = InputArgs.getLastArg(OBJDUMP_debug_vars_EQ)) {
2465*82d56013Sjoerg DbgVariables = StringSwitch<DebugVarsFormat>(A->getValue())
2466*82d56013Sjoerg .Case("ascii", DVASCII)
2467*82d56013Sjoerg .Case("unicode", DVUnicode);
2468*82d56013Sjoerg }
2469*82d56013Sjoerg parseIntArg(InputArgs, OBJDUMP_debug_vars_indent_EQ, DbgIndent);
2470*82d56013Sjoerg
2471*82d56013Sjoerg parseMachOOptions(InputArgs);
2472*82d56013Sjoerg
2473*82d56013Sjoerg // Parse -M (--disassembler-options) and deprecated
2474*82d56013Sjoerg // --x86-asm-syntax={att,intel}.
2475*82d56013Sjoerg //
2476*82d56013Sjoerg // Note, for x86, the asm dialect (AssemblerDialect) is initialized when the
2477*82d56013Sjoerg // MCAsmInfo is constructed. MCInstPrinter::applyTargetSpecificCLOption is
2478*82d56013Sjoerg // called too late. For now we have to use the internal cl::opt option.
2479*82d56013Sjoerg const char *AsmSyntax = nullptr;
2480*82d56013Sjoerg for (const auto *A : InputArgs.filtered(OBJDUMP_disassembler_options_EQ,
2481*82d56013Sjoerg OBJDUMP_x86_asm_syntax_att,
2482*82d56013Sjoerg OBJDUMP_x86_asm_syntax_intel)) {
2483*82d56013Sjoerg switch (A->getOption().getID()) {
2484*82d56013Sjoerg case OBJDUMP_x86_asm_syntax_att:
2485*82d56013Sjoerg AsmSyntax = "--x86-asm-syntax=att";
2486*82d56013Sjoerg continue;
2487*82d56013Sjoerg case OBJDUMP_x86_asm_syntax_intel:
2488*82d56013Sjoerg AsmSyntax = "--x86-asm-syntax=intel";
2489*82d56013Sjoerg continue;
2490*82d56013Sjoerg }
2491*82d56013Sjoerg
2492*82d56013Sjoerg SmallVector<StringRef, 2> Values;
2493*82d56013Sjoerg llvm::SplitString(A->getValue(), Values, ",");
2494*82d56013Sjoerg for (StringRef V : Values) {
2495*82d56013Sjoerg if (V == "att")
2496*82d56013Sjoerg AsmSyntax = "--x86-asm-syntax=att";
2497*82d56013Sjoerg else if (V == "intel")
2498*82d56013Sjoerg AsmSyntax = "--x86-asm-syntax=intel";
2499*82d56013Sjoerg else
2500*82d56013Sjoerg DisassemblerOptions.push_back(V.str());
2501*82d56013Sjoerg }
2502*82d56013Sjoerg }
2503*82d56013Sjoerg if (AsmSyntax) {
2504*82d56013Sjoerg const char *Argv[] = {"llvm-objdump", AsmSyntax};
2505*82d56013Sjoerg llvm::cl::ParseCommandLineOptions(2, Argv);
2506*82d56013Sjoerg }
2507*82d56013Sjoerg
2508*82d56013Sjoerg // objdump defaults to a.out if no filenames specified.
2509*82d56013Sjoerg if (InputFilenames.empty())
2510*82d56013Sjoerg InputFilenames.push_back("a.out");
2511*82d56013Sjoerg }
25127330f729Sjoerg
main(int argc,char ** argv)25137330f729Sjoerg int main(int argc, char **argv) {
25147330f729Sjoerg using namespace llvm;
25157330f729Sjoerg InitLLVM X(argc, argv);
2516*82d56013Sjoerg
2517*82d56013Sjoerg ToolName = argv[0];
2518*82d56013Sjoerg std::unique_ptr<CommonOptTable> T;
2519*82d56013Sjoerg OptSpecifier Unknown, HelpFlag, HelpHiddenFlag, VersionFlag;
2520*82d56013Sjoerg
2521*82d56013Sjoerg StringRef Stem = sys::path::stem(ToolName);
2522*82d56013Sjoerg auto Is = [=](StringRef Tool) {
2523*82d56013Sjoerg // We need to recognize the following filenames:
2524*82d56013Sjoerg //
2525*82d56013Sjoerg // llvm-objdump -> objdump
2526*82d56013Sjoerg // llvm-otool-10.exe -> otool
2527*82d56013Sjoerg // powerpc64-unknown-freebsd13-objdump -> objdump
2528*82d56013Sjoerg auto I = Stem.rfind_lower(Tool);
2529*82d56013Sjoerg return I != StringRef::npos &&
2530*82d56013Sjoerg (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()]));
2531*82d56013Sjoerg };
2532*82d56013Sjoerg if (Is("otool")) {
2533*82d56013Sjoerg T = std::make_unique<OtoolOptTable>();
2534*82d56013Sjoerg Unknown = OTOOL_UNKNOWN;
2535*82d56013Sjoerg HelpFlag = OTOOL_help;
2536*82d56013Sjoerg HelpHiddenFlag = OTOOL_help_hidden;
2537*82d56013Sjoerg VersionFlag = OTOOL_version;
2538*82d56013Sjoerg } else {
2539*82d56013Sjoerg T = std::make_unique<ObjdumpOptTable>();
2540*82d56013Sjoerg Unknown = OBJDUMP_UNKNOWN;
2541*82d56013Sjoerg HelpFlag = OBJDUMP_help;
2542*82d56013Sjoerg HelpHiddenFlag = OBJDUMP_help_hidden;
2543*82d56013Sjoerg VersionFlag = OBJDUMP_version;
2544*82d56013Sjoerg }
2545*82d56013Sjoerg
2546*82d56013Sjoerg BumpPtrAllocator A;
2547*82d56013Sjoerg StringSaver Saver(A);
2548*82d56013Sjoerg opt::InputArgList InputArgs =
2549*82d56013Sjoerg T->parseArgs(argc, argv, Unknown, Saver,
2550*82d56013Sjoerg [&](StringRef Msg) { reportCmdLineError(Msg); });
2551*82d56013Sjoerg
2552*82d56013Sjoerg if (InputArgs.size() == 0 || InputArgs.hasArg(HelpFlag)) {
2553*82d56013Sjoerg T->printHelp(ToolName);
2554*82d56013Sjoerg return 0;
2555*82d56013Sjoerg }
2556*82d56013Sjoerg if (InputArgs.hasArg(HelpHiddenFlag)) {
2557*82d56013Sjoerg T->printHelp(ToolName, /*show_hidden=*/true);
2558*82d56013Sjoerg return 0;
2559*82d56013Sjoerg }
25607330f729Sjoerg
25617330f729Sjoerg // Initialize targets and assembly printers/parsers.
25627330f729Sjoerg InitializeAllTargetInfos();
25637330f729Sjoerg InitializeAllTargetMCs();
25647330f729Sjoerg InitializeAllDisassemblers();
25657330f729Sjoerg
2566*82d56013Sjoerg if (InputArgs.hasArg(VersionFlag)) {
2567*82d56013Sjoerg cl::PrintVersionMessage();
2568*82d56013Sjoerg if (!Is("otool")) {
2569*82d56013Sjoerg outs() << '\n';
2570*82d56013Sjoerg TargetRegistry::printRegisteredTargetsForVersion(outs());
2571*82d56013Sjoerg }
2572*82d56013Sjoerg return 0;
2573*82d56013Sjoerg }
25747330f729Sjoerg
2575*82d56013Sjoerg if (Is("otool"))
2576*82d56013Sjoerg parseOtoolOptions(InputArgs);
2577*82d56013Sjoerg else
2578*82d56013Sjoerg parseObjdumpOptions(InputArgs);
25797330f729Sjoerg
25807330f729Sjoerg if (StartAddress >= StopAddress)
25817330f729Sjoerg reportCmdLineError("start address should be less than stop address");
25827330f729Sjoerg
2583*82d56013Sjoerg // Removes trailing separators from prefix.
2584*82d56013Sjoerg while (!Prefix.empty() && sys::path::is_separator(Prefix.back()))
2585*82d56013Sjoerg Prefix.pop_back();
25867330f729Sjoerg
25877330f729Sjoerg if (AllHeaders)
25887330f729Sjoerg ArchiveHeaders = FileHeaders = PrivateHeaders = Relocations =
25897330f729Sjoerg SectionHeaders = SymbolTable = true;
25907330f729Sjoerg
25917330f729Sjoerg if (DisassembleAll || PrintSource || PrintLines ||
2592*82d56013Sjoerg !DisassembleSymbols.empty())
25937330f729Sjoerg Disassemble = true;
25947330f729Sjoerg
25957330f729Sjoerg if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null &&
25967330f729Sjoerg !DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST &&
25977330f729Sjoerg !Relocations && !SectionHeaders && !SectionContents && !SymbolTable &&
2598*82d56013Sjoerg !DynamicSymbolTable && !UnwindInfo && !FaultMapSection &&
25997330f729Sjoerg !(MachOOpt &&
26007330f729Sjoerg (Bind || DataInCode || DylibId || DylibsUsed || ExportsTrie ||
2601*82d56013Sjoerg FirstPrivateHeader || FunctionStarts || IndirectSymbols || InfoPlist ||
2602*82d56013Sjoerg LazyBind || LinkOptHints || ObjcMetaData || Rebase || Rpaths ||
2603*82d56013Sjoerg UniversalHeaders || WeakBind || !FilterSections.empty()))) {
2604*82d56013Sjoerg T->printHelp(ToolName);
26057330f729Sjoerg return 2;
26067330f729Sjoerg }
26077330f729Sjoerg
2608*82d56013Sjoerg DisasmSymbolSet.insert(DisassembleSymbols.begin(), DisassembleSymbols.end());
26097330f729Sjoerg
26107330f729Sjoerg llvm::for_each(InputFilenames, dumpInput);
26117330f729Sjoerg
26127330f729Sjoerg warnOnNoMatchForSections();
26137330f729Sjoerg
26147330f729Sjoerg return EXIT_SUCCESS;
26157330f729Sjoerg }
2616