File: | build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/tools/llvm-objdump/llvm-objdump.cpp |
Warning: | line 2066, column 33 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | // | |||
9 | // This program is a utility that works like binutils "objdump", that is, it | |||
10 | // dumps out a plethora of information about an object file depending on the | |||
11 | // flags. | |||
12 | // | |||
13 | // The flags and output of this program should be near identical to those of | |||
14 | // binutils objdump. | |||
15 | // | |||
16 | //===----------------------------------------------------------------------===// | |||
17 | ||||
18 | #include "llvm-objdump.h" | |||
19 | #include "COFFDump.h" | |||
20 | #include "ELFDump.h" | |||
21 | #include "MachODump.h" | |||
22 | #include "ObjdumpOptID.h" | |||
23 | #include "SourcePrinter.h" | |||
24 | #include "WasmDump.h" | |||
25 | #include "XCOFFDump.h" | |||
26 | #include "llvm/ADT/IndexedMap.h" | |||
27 | #include "llvm/ADT/Optional.h" | |||
28 | #include "llvm/ADT/STLExtras.h" | |||
29 | #include "llvm/ADT/SetOperations.h" | |||
30 | #include "llvm/ADT/SmallSet.h" | |||
31 | #include "llvm/ADT/StringExtras.h" | |||
32 | #include "llvm/ADT/StringSet.h" | |||
33 | #include "llvm/ADT/Triple.h" | |||
34 | #include "llvm/ADT/Twine.h" | |||
35 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" | |||
36 | #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" | |||
37 | #include "llvm/DebugInfo/Symbolize/Symbolize.h" | |||
38 | #include "llvm/Demangle/Demangle.h" | |||
39 | #include "llvm/MC/MCAsmInfo.h" | |||
40 | #include "llvm/MC/MCContext.h" | |||
41 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" | |||
42 | #include "llvm/MC/MCDisassembler/MCRelocationInfo.h" | |||
43 | #include "llvm/MC/MCInst.h" | |||
44 | #include "llvm/MC/MCInstPrinter.h" | |||
45 | #include "llvm/MC/MCInstrAnalysis.h" | |||
46 | #include "llvm/MC/MCInstrInfo.h" | |||
47 | #include "llvm/MC/MCObjectFileInfo.h" | |||
48 | #include "llvm/MC/MCRegisterInfo.h" | |||
49 | #include "llvm/MC/MCSubtargetInfo.h" | |||
50 | #include "llvm/MC/MCTargetOptions.h" | |||
51 | #include "llvm/MC/TargetRegistry.h" | |||
52 | #include "llvm/Object/Archive.h" | |||
53 | #include "llvm/Object/COFF.h" | |||
54 | #include "llvm/Object/COFFImportFile.h" | |||
55 | #include "llvm/Object/ELFObjectFile.h" | |||
56 | #include "llvm/Object/FaultMapParser.h" | |||
57 | #include "llvm/Object/MachO.h" | |||
58 | #include "llvm/Object/MachOUniversal.h" | |||
59 | #include "llvm/Object/ObjectFile.h" | |||
60 | #include "llvm/Object/Wasm.h" | |||
61 | #include "llvm/Option/Arg.h" | |||
62 | #include "llvm/Option/ArgList.h" | |||
63 | #include "llvm/Option/Option.h" | |||
64 | #include "llvm/Support/Casting.h" | |||
65 | #include "llvm/Support/Debug.h" | |||
66 | #include "llvm/Support/Errc.h" | |||
67 | #include "llvm/Support/FileSystem.h" | |||
68 | #include "llvm/Support/Format.h" | |||
69 | #include "llvm/Support/FormatVariadic.h" | |||
70 | #include "llvm/Support/GraphWriter.h" | |||
71 | #include "llvm/Support/Host.h" | |||
72 | #include "llvm/Support/InitLLVM.h" | |||
73 | #include "llvm/Support/MemoryBuffer.h" | |||
74 | #include "llvm/Support/SourceMgr.h" | |||
75 | #include "llvm/Support/StringSaver.h" | |||
76 | #include "llvm/Support/TargetSelect.h" | |||
77 | #include "llvm/Support/WithColor.h" | |||
78 | #include "llvm/Support/raw_ostream.h" | |||
79 | #include <algorithm> | |||
80 | #include <cctype> | |||
81 | #include <cstring> | |||
82 | #include <system_error> | |||
83 | #include <unordered_map> | |||
84 | #include <utility> | |||
85 | ||||
86 | using namespace llvm; | |||
87 | using namespace llvm::object; | |||
88 | using namespace llvm::objdump; | |||
89 | using namespace llvm::opt; | |||
90 | ||||
91 | namespace { | |||
92 | ||||
93 | class CommonOptTable : public opt::OptTable { | |||
94 | public: | |||
95 | CommonOptTable(ArrayRef<Info> OptionInfos, const char *Usage, | |||
96 | const char *Description) | |||
97 | : OptTable(OptionInfos), Usage(Usage), Description(Description) { | |||
98 | setGroupedShortOptions(true); | |||
99 | } | |||
100 | ||||
101 | void printHelp(StringRef Argv0, bool ShowHidden = false) const { | |||
102 | Argv0 = sys::path::filename(Argv0); | |||
103 | opt::OptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(), Description, | |||
104 | ShowHidden, ShowHidden); | |||
105 | // TODO Replace this with OptTable API once it adds extrahelp support. | |||
106 | outs() << "\nPass @FILE as argument to read options from FILE.\n"; | |||
107 | } | |||
108 | ||||
109 | private: | |||
110 | const char *Usage; | |||
111 | const char *Description; | |||
112 | }; | |||
113 | ||||
114 | // ObjdumpOptID is in ObjdumpOptID.h | |||
115 | ||||
116 | #define PREFIX(NAME, VALUE) const char *const OBJDUMP_##NAME[] = VALUE; | |||
117 | #include "ObjdumpOpts.inc" | |||
118 | #undef PREFIX | |||
119 | ||||
120 | static constexpr opt::OptTable::Info ObjdumpInfoTable[] = { | |||
121 | #define OBJDUMP_nullptr nullptr | |||
122 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
123 | HELPTEXT, METAVAR, VALUES) \ | |||
124 | {OBJDUMP_##PREFIX, NAME, HELPTEXT, \ | |||
125 | METAVAR, OBJDUMP_##ID, opt::Option::KIND##Class, \ | |||
126 | PARAM, FLAGS, OBJDUMP_##GROUP, \ | |||
127 | OBJDUMP_##ALIAS, ALIASARGS, VALUES}, | |||
128 | #include "ObjdumpOpts.inc" | |||
129 | #undef OPTION | |||
130 | #undef OBJDUMP_nullptr | |||
131 | }; | |||
132 | ||||
133 | class ObjdumpOptTable : public CommonOptTable { | |||
134 | public: | |||
135 | ObjdumpOptTable() | |||
136 | : CommonOptTable(ObjdumpInfoTable, " [options] <input object files>", | |||
137 | "llvm object file dumper") {} | |||
138 | }; | |||
139 | ||||
140 | enum OtoolOptID { | |||
141 | OTOOL_INVALID = 0, // This is not an option ID. | |||
142 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
143 | HELPTEXT, METAVAR, VALUES) \ | |||
144 | OTOOL_##ID, | |||
145 | #include "OtoolOpts.inc" | |||
146 | #undef OPTION | |||
147 | }; | |||
148 | ||||
149 | #define PREFIX(NAME, VALUE) const char *const OTOOL_##NAME[] = VALUE; | |||
150 | #include "OtoolOpts.inc" | |||
151 | #undef PREFIX | |||
152 | ||||
153 | static constexpr opt::OptTable::Info OtoolInfoTable[] = { | |||
154 | #define OTOOL_nullptr nullptr | |||
155 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ | |||
156 | HELPTEXT, METAVAR, VALUES) \ | |||
157 | {OTOOL_##PREFIX, NAME, HELPTEXT, \ | |||
158 | METAVAR, OTOOL_##ID, opt::Option::KIND##Class, \ | |||
159 | PARAM, FLAGS, OTOOL_##GROUP, \ | |||
160 | OTOOL_##ALIAS, ALIASARGS, VALUES}, | |||
161 | #include "OtoolOpts.inc" | |||
162 | #undef OPTION | |||
163 | #undef OTOOL_nullptr | |||
164 | }; | |||
165 | ||||
166 | class OtoolOptTable : public CommonOptTable { | |||
167 | public: | |||
168 | OtoolOptTable() | |||
169 | : CommonOptTable(OtoolInfoTable, " [option...] [file...]", | |||
170 | "Mach-O object file displaying tool") {} | |||
171 | }; | |||
172 | ||||
173 | } // namespace | |||
174 | ||||
175 | #define DEBUG_TYPE"objdump" "objdump" | |||
176 | ||||
177 | static uint64_t AdjustVMA; | |||
178 | static bool AllHeaders; | |||
179 | static std::string ArchName; | |||
180 | bool objdump::ArchiveHeaders; | |||
181 | bool objdump::Demangle; | |||
182 | bool objdump::Disassemble; | |||
183 | bool objdump::DisassembleAll; | |||
184 | bool objdump::SymbolDescription; | |||
185 | static std::vector<std::string> DisassembleSymbols; | |||
186 | static bool DisassembleZeroes; | |||
187 | static std::vector<std::string> DisassemblerOptions; | |||
188 | DIDumpType objdump::DwarfDumpType; | |||
189 | static bool DynamicRelocations; | |||
190 | static bool FaultMapSection; | |||
191 | static bool FileHeaders; | |||
192 | bool objdump::SectionContents; | |||
193 | static std::vector<std::string> InputFilenames; | |||
194 | bool objdump::PrintLines; | |||
195 | static bool MachOOpt; | |||
196 | std::string objdump::MCPU; | |||
197 | std::vector<std::string> objdump::MAttrs; | |||
198 | bool objdump::ShowRawInsn; | |||
199 | bool objdump::LeadingAddr; | |||
200 | static bool RawClangAST; | |||
201 | bool objdump::Relocations; | |||
202 | bool objdump::PrintImmHex; | |||
203 | bool objdump::PrivateHeaders; | |||
204 | std::vector<std::string> objdump::FilterSections; | |||
205 | bool objdump::SectionHeaders; | |||
206 | static bool ShowLMA; | |||
207 | bool objdump::PrintSource; | |||
208 | ||||
209 | static uint64_t StartAddress; | |||
210 | static bool HasStartAddressFlag; | |||
211 | static uint64_t StopAddress = UINT64_MAX(18446744073709551615UL); | |||
212 | static bool HasStopAddressFlag; | |||
213 | ||||
214 | bool objdump::SymbolTable; | |||
215 | static bool SymbolizeOperands; | |||
216 | static bool DynamicSymbolTable; | |||
217 | std::string objdump::TripleName; | |||
218 | bool objdump::UnwindInfo; | |||
219 | static bool Wide; | |||
220 | std::string objdump::Prefix; | |||
221 | uint32_t objdump::PrefixStrip; | |||
222 | ||||
223 | DebugVarsFormat objdump::DbgVariables = DVDisabled; | |||
224 | ||||
225 | int objdump::DbgIndent = 52; | |||
226 | ||||
227 | static StringSet<> DisasmSymbolSet; | |||
228 | StringSet<> objdump::FoundSectionSet; | |||
229 | static StringRef ToolName; | |||
230 | ||||
231 | namespace { | |||
232 | struct FilterResult { | |||
233 | // True if the section should not be skipped. | |||
234 | bool Keep; | |||
235 | ||||
236 | // True if the index counter should be incremented, even if the section should | |||
237 | // be skipped. For example, sections may be skipped if they are not included | |||
238 | // in the --section flag, but we still want those to count toward the section | |||
239 | // count. | |||
240 | bool IncrementIndex; | |||
241 | }; | |||
242 | } // namespace | |||
243 | ||||
244 | static FilterResult checkSectionFilter(object::SectionRef S) { | |||
245 | if (FilterSections.empty()) | |||
246 | return {/*Keep=*/true, /*IncrementIndex=*/true}; | |||
247 | ||||
248 | Expected<StringRef> SecNameOrErr = S.getName(); | |||
249 | if (!SecNameOrErr) { | |||
250 | consumeError(SecNameOrErr.takeError()); | |||
251 | return {/*Keep=*/false, /*IncrementIndex=*/false}; | |||
252 | } | |||
253 | StringRef SecName = *SecNameOrErr; | |||
254 | ||||
255 | // StringSet does not allow empty key so avoid adding sections with | |||
256 | // no name (such as the section with index 0) here. | |||
257 | if (!SecName.empty()) | |||
258 | FoundSectionSet.insert(SecName); | |||
259 | ||||
260 | // Only show the section if it's in the FilterSections list, but always | |||
261 | // increment so the indexing is stable. | |||
262 | return {/*Keep=*/is_contained(FilterSections, SecName), | |||
263 | /*IncrementIndex=*/true}; | |||
264 | } | |||
265 | ||||
266 | SectionFilter objdump::ToolSectionFilter(object::ObjectFile const &O, | |||
267 | uint64_t *Idx) { | |||
268 | // Start at UINT64_MAX so that the first index returned after an increment is | |||
269 | // zero (after the unsigned wrap). | |||
270 | if (Idx) | |||
271 | *Idx = UINT64_MAX(18446744073709551615UL); | |||
272 | return SectionFilter( | |||
273 | [Idx](object::SectionRef S) { | |||
274 | FilterResult Result = checkSectionFilter(S); | |||
275 | if (Idx != nullptr && Result.IncrementIndex) | |||
276 | *Idx += 1; | |||
277 | return Result.Keep; | |||
278 | }, | |||
279 | O); | |||
280 | } | |||
281 | ||||
282 | std::string objdump::getFileNameForError(const object::Archive::Child &C, | |||
283 | unsigned Index) { | |||
284 | Expected<StringRef> NameOrErr = C.getName(); | |||
285 | if (NameOrErr) | |||
286 | return std::string(NameOrErr.get()); | |||
287 | // If we have an error getting the name then we print the index of the archive | |||
288 | // member. Since we are already in an error state, we just ignore this error. | |||
289 | consumeError(NameOrErr.takeError()); | |||
290 | return "<file index: " + std::to_string(Index) + ">"; | |||
291 | } | |||
292 | ||||
293 | void objdump::reportWarning(const Twine &Message, StringRef File) { | |||
294 | // Output order between errs() and outs() matters especially for archive | |||
295 | // files where the output is per member object. | |||
296 | outs().flush(); | |||
297 | WithColor::warning(errs(), ToolName) | |||
298 | << "'" << File << "': " << Message << "\n"; | |||
299 | } | |||
300 | ||||
301 | [[noreturn]] void objdump::reportError(StringRef File, const Twine &Message) { | |||
302 | outs().flush(); | |||
303 | WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n"; | |||
304 | exit(1); | |||
305 | } | |||
306 | ||||
307 | [[noreturn]] void objdump::reportError(Error E, StringRef FileName, | |||
308 | StringRef ArchiveName, | |||
309 | StringRef ArchitectureName) { | |||
310 | assert(E)(static_cast <bool> (E) ? void (0) : __assert_fail ("E" , "llvm/tools/llvm-objdump/llvm-objdump.cpp", 310, __extension__ __PRETTY_FUNCTION__)); | |||
311 | outs().flush(); | |||
312 | WithColor::error(errs(), ToolName); | |||
313 | if (ArchiveName != "") | |||
314 | errs() << ArchiveName << "(" << FileName << ")"; | |||
315 | else | |||
316 | errs() << "'" << FileName << "'"; | |||
317 | if (!ArchitectureName.empty()) | |||
318 | errs() << " (for architecture " << ArchitectureName << ")"; | |||
319 | errs() << ": "; | |||
320 | logAllUnhandledErrors(std::move(E), errs()); | |||
321 | exit(1); | |||
322 | } | |||
323 | ||||
324 | static void reportCmdLineWarning(const Twine &Message) { | |||
325 | WithColor::warning(errs(), ToolName) << Message << "\n"; | |||
326 | } | |||
327 | ||||
328 | [[noreturn]] static void reportCmdLineError(const Twine &Message) { | |||
329 | WithColor::error(errs(), ToolName) << Message << "\n"; | |||
330 | exit(1); | |||
331 | } | |||
332 | ||||
333 | static void warnOnNoMatchForSections() { | |||
334 | SetVector<StringRef> MissingSections; | |||
335 | for (StringRef S : FilterSections) { | |||
336 | if (FoundSectionSet.count(S)) | |||
337 | return; | |||
338 | // User may specify a unnamed section. Don't warn for it. | |||
339 | if (!S.empty()) | |||
340 | MissingSections.insert(S); | |||
341 | } | |||
342 | ||||
343 | // Warn only if no section in FilterSections is matched. | |||
344 | for (StringRef S : MissingSections) | |||
345 | reportCmdLineWarning("section '" + S + | |||
346 | "' mentioned in a -j/--section option, but not " | |||
347 | "found in any input file"); | |||
348 | } | |||
349 | ||||
350 | static const Target *getTarget(const ObjectFile *Obj) { | |||
351 | // Figure out the target triple. | |||
352 | Triple TheTriple("unknown-unknown-unknown"); | |||
353 | if (TripleName.empty()) { | |||
354 | TheTriple = Obj->makeTriple(); | |||
355 | } else { | |||
356 | TheTriple.setTriple(Triple::normalize(TripleName)); | |||
357 | auto Arch = Obj->getArch(); | |||
358 | if (Arch == Triple::arm || Arch == Triple::armeb) | |||
359 | Obj->setARMSubArch(TheTriple); | |||
360 | } | |||
361 | ||||
362 | // Get the target specific parser. | |||
363 | std::string Error; | |||
364 | const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple, | |||
365 | Error); | |||
366 | if (!TheTarget) | |||
367 | reportError(Obj->getFileName(), "can't find target: " + Error); | |||
368 | ||||
369 | // Update the triple name and return the found target. | |||
370 | TripleName = TheTriple.getTriple(); | |||
371 | return TheTarget; | |||
372 | } | |||
373 | ||||
374 | bool objdump::isRelocAddressLess(RelocationRef A, RelocationRef B) { | |||
375 | return A.getOffset() < B.getOffset(); | |||
376 | } | |||
377 | ||||
378 | static Error getRelocationValueString(const RelocationRef &Rel, | |||
379 | SmallVectorImpl<char> &Result) { | |||
380 | const ObjectFile *Obj = Rel.getObject(); | |||
381 | if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj)) | |||
382 | return getELFRelocationValueString(ELF, Rel, Result); | |||
383 | if (auto *COFF = dyn_cast<COFFObjectFile>(Obj)) | |||
384 | return getCOFFRelocationValueString(COFF, Rel, Result); | |||
385 | if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj)) | |||
386 | return getWasmRelocationValueString(Wasm, Rel, Result); | |||
387 | if (auto *MachO = dyn_cast<MachOObjectFile>(Obj)) | |||
388 | return getMachORelocationValueString(MachO, Rel, Result); | |||
389 | if (auto *XCOFF = dyn_cast<XCOFFObjectFile>(Obj)) | |||
390 | return getXCOFFRelocationValueString(XCOFF, Rel, Result); | |||
391 | llvm_unreachable("unknown object file format")::llvm::llvm_unreachable_internal("unknown object file format" , "llvm/tools/llvm-objdump/llvm-objdump.cpp", 391); | |||
392 | } | |||
393 | ||||
394 | /// Indicates whether this relocation should hidden when listing | |||
395 | /// relocations, usually because it is the trailing part of a multipart | |||
396 | /// relocation that will be printed as part of the leading relocation. | |||
397 | static bool getHidden(RelocationRef RelRef) { | |||
398 | auto *MachO = dyn_cast<MachOObjectFile>(RelRef.getObject()); | |||
399 | if (!MachO) | |||
400 | return false; | |||
401 | ||||
402 | unsigned Arch = MachO->getArch(); | |||
403 | DataRefImpl Rel = RelRef.getRawDataRefImpl(); | |||
404 | uint64_t Type = MachO->getRelocationType(Rel); | |||
405 | ||||
406 | // On arches that use the generic relocations, GENERIC_RELOC_PAIR | |||
407 | // is always hidden. | |||
408 | if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc) | |||
409 | return Type == MachO::GENERIC_RELOC_PAIR; | |||
410 | ||||
411 | if (Arch == Triple::x86_64) { | |||
412 | // On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows | |||
413 | // an X86_64_RELOC_SUBTRACTOR. | |||
414 | if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) { | |||
415 | DataRefImpl RelPrev = Rel; | |||
416 | RelPrev.d.a--; | |||
417 | uint64_t PrevType = MachO->getRelocationType(RelPrev); | |||
418 | if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR) | |||
419 | return true; | |||
420 | } | |||
421 | } | |||
422 | ||||
423 | return false; | |||
424 | } | |||
425 | ||||
426 | namespace { | |||
427 | ||||
428 | /// Get the column at which we want to start printing the instruction | |||
429 | /// disassembly, taking into account anything which appears to the left of it. | |||
430 | unsigned getInstStartColumn(const MCSubtargetInfo &STI) { | |||
431 | return !ShowRawInsn ? 16 : STI.getTargetTriple().isX86() ? 40 : 24; | |||
432 | } | |||
433 | ||||
434 | static bool isAArch64Elf(const ObjectFile *Obj) { | |||
435 | const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj); | |||
436 | return Elf && Elf->getEMachine() == ELF::EM_AARCH64; | |||
437 | } | |||
438 | ||||
439 | static bool isArmElf(const ObjectFile *Obj) { | |||
440 | const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj); | |||
441 | return Elf && Elf->getEMachine() == ELF::EM_ARM; | |||
442 | } | |||
443 | ||||
444 | static bool isCSKYElf(const ObjectFile *Obj) { | |||
445 | const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj); | |||
446 | return Elf && Elf->getEMachine() == ELF::EM_CSKY; | |||
447 | } | |||
448 | ||||
449 | static bool hasMappingSymbols(const ObjectFile *Obj) { | |||
450 | return isArmElf(Obj) || isAArch64Elf(Obj) || isCSKYElf(Obj) ; | |||
451 | } | |||
452 | ||||
453 | static void printRelocation(formatted_raw_ostream &OS, StringRef FileName, | |||
454 | const RelocationRef &Rel, uint64_t Address, | |||
455 | bool Is64Bits) { | |||
456 | StringRef Fmt = Is64Bits ? "\t\t%016" PRIx64"l" "x" ": " : "\t\t\t%08" PRIx64"l" "x" ": "; | |||
457 | SmallString<16> Name; | |||
458 | SmallString<32> Val; | |||
459 | Rel.getTypeName(Name); | |||
460 | if (Error E = getRelocationValueString(Rel, Val)) | |||
461 | reportError(std::move(E), FileName); | |||
462 | OS << format(Fmt.data(), Address) << Name << "\t" << Val; | |||
463 | } | |||
464 | ||||
465 | class PrettyPrinter { | |||
466 | public: | |||
467 | virtual ~PrettyPrinter() = default; | |||
468 | virtual void | |||
469 | printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, | |||
470 | object::SectionedAddress Address, formatted_raw_ostream &OS, | |||
471 | StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, | |||
472 | StringRef ObjectFilename, std::vector<RelocationRef> *Rels, | |||
473 | LiveVariablePrinter &LVP) { | |||
474 | if (SP && (PrintSource || PrintLines)) | |||
475 | SP->printSourceLine(OS, Address, ObjectFilename, LVP); | |||
476 | LVP.printBetweenInsts(OS, false); | |||
477 | ||||
478 | size_t Start = OS.tell(); | |||
479 | if (LeadingAddr) | |||
480 | OS << format("%8" PRIx64"l" "x" ":", Address.Address); | |||
481 | if (ShowRawInsn) { | |||
482 | OS << ' '; | |||
483 | dumpBytes(Bytes, OS); | |||
484 | } | |||
485 | ||||
486 | // The output of printInst starts with a tab. Print some spaces so that | |||
487 | // the tab has 1 column and advances to the target tab stop. | |||
488 | unsigned TabStop = getInstStartColumn(STI); | |||
489 | unsigned Column = OS.tell() - Start; | |||
490 | OS.indent(Column < TabStop - 1 ? TabStop - 1 - Column : 7 - Column % 8); | |||
491 | ||||
492 | if (MI) { | |||
493 | // See MCInstPrinter::printInst. On targets where a PC relative immediate | |||
494 | // is relative to the next instruction and the length of a MCInst is | |||
495 | // difficult to measure (x86), this is the address of the next | |||
496 | // instruction. | |||
497 | uint64_t Addr = | |||
498 | Address.Address + (STI.getTargetTriple().isX86() ? Bytes.size() : 0); | |||
499 | IP.printInst(MI, Addr, "", STI, OS); | |||
500 | } else | |||
501 | OS << "\t<unknown>"; | |||
502 | } | |||
503 | }; | |||
504 | PrettyPrinter PrettyPrinterInst; | |||
505 | ||||
506 | class HexagonPrettyPrinter : public PrettyPrinter { | |||
507 | public: | |||
508 | void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address, | |||
509 | formatted_raw_ostream &OS) { | |||
510 | uint32_t opcode = | |||
511 | (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0]; | |||
512 | if (LeadingAddr) | |||
513 | OS << format("%8" PRIx64"l" "x" ":", Address); | |||
514 | if (ShowRawInsn) { | |||
515 | OS << "\t"; | |||
516 | dumpBytes(Bytes.slice(0, 4), OS); | |||
517 | OS << format("\t%08" PRIx32"x", opcode); | |||
518 | } | |||
519 | } | |||
520 | void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, | |||
521 | object::SectionedAddress Address, formatted_raw_ostream &OS, | |||
522 | StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, | |||
523 | StringRef ObjectFilename, std::vector<RelocationRef> *Rels, | |||
524 | LiveVariablePrinter &LVP) override { | |||
525 | if (SP && (PrintSource || PrintLines)) | |||
526 | SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); | |||
527 | if (!MI) { | |||
528 | printLead(Bytes, Address.Address, OS); | |||
529 | OS << " <unknown>"; | |||
530 | return; | |||
531 | } | |||
532 | std::string Buffer; | |||
533 | { | |||
534 | raw_string_ostream TempStream(Buffer); | |||
535 | IP.printInst(MI, Address.Address, "", STI, TempStream); | |||
536 | } | |||
537 | StringRef Contents(Buffer); | |||
538 | // Split off bundle attributes | |||
539 | auto PacketBundle = Contents.rsplit('\n'); | |||
540 | // Split off first instruction from the rest | |||
541 | auto HeadTail = PacketBundle.first.split('\n'); | |||
542 | auto Preamble = " { "; | |||
543 | auto Separator = ""; | |||
544 | ||||
545 | // Hexagon's packets require relocations to be inline rather than | |||
546 | // clustered at the end of the packet. | |||
547 | std::vector<RelocationRef>::const_iterator RelCur = Rels->begin(); | |||
548 | std::vector<RelocationRef>::const_iterator RelEnd = Rels->end(); | |||
549 | auto PrintReloc = [&]() -> void { | |||
550 | while ((RelCur != RelEnd) && (RelCur->getOffset() <= Address.Address)) { | |||
551 | if (RelCur->getOffset() == Address.Address) { | |||
552 | printRelocation(OS, ObjectFilename, *RelCur, Address.Address, false); | |||
553 | return; | |||
554 | } | |||
555 | ++RelCur; | |||
556 | } | |||
557 | }; | |||
558 | ||||
559 | while (!HeadTail.first.empty()) { | |||
560 | OS << Separator; | |||
561 | Separator = "\n"; | |||
562 | if (SP && (PrintSource || PrintLines)) | |||
563 | SP->printSourceLine(OS, Address, ObjectFilename, LVP, ""); | |||
564 | printLead(Bytes, Address.Address, OS); | |||
565 | OS << Preamble; | |||
566 | Preamble = " "; | |||
567 | StringRef Inst; | |||
568 | auto Duplex = HeadTail.first.split('\v'); | |||
569 | if (!Duplex.second.empty()) { | |||
570 | OS << Duplex.first; | |||
571 | OS << "; "; | |||
572 | Inst = Duplex.second; | |||
573 | } | |||
574 | else | |||
575 | Inst = HeadTail.first; | |||
576 | OS << Inst; | |||
577 | HeadTail = HeadTail.second.split('\n'); | |||
578 | if (HeadTail.first.empty()) | |||
579 | OS << " } " << PacketBundle.second; | |||
580 | PrintReloc(); | |||
581 | Bytes = Bytes.slice(4); | |||
582 | Address.Address += 4; | |||
583 | } | |||
584 | } | |||
585 | }; | |||
586 | HexagonPrettyPrinter HexagonPrettyPrinterInst; | |||
587 | ||||
588 | class AMDGCNPrettyPrinter : public PrettyPrinter { | |||
589 | public: | |||
590 | void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, | |||
591 | object::SectionedAddress Address, formatted_raw_ostream &OS, | |||
592 | StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, | |||
593 | StringRef ObjectFilename, std::vector<RelocationRef> *Rels, | |||
594 | LiveVariablePrinter &LVP) override { | |||
595 | if (SP && (PrintSource || PrintLines)) | |||
596 | SP->printSourceLine(OS, Address, ObjectFilename, LVP); | |||
597 | ||||
598 | if (MI) { | |||
599 | SmallString<40> InstStr; | |||
600 | raw_svector_ostream IS(InstStr); | |||
601 | ||||
602 | IP.printInst(MI, Address.Address, "", STI, IS); | |||
603 | ||||
604 | OS << left_justify(IS.str(), 60); | |||
605 | } else { | |||
606 | // an unrecognized encoding - this is probably data so represent it | |||
607 | // using the .long directive, or .byte directive if fewer than 4 bytes | |||
608 | // remaining | |||
609 | if (Bytes.size() >= 4) { | |||
610 | OS << format("\t.long 0x%08" PRIx32"x" " ", | |||
611 | support::endian::read32<support::little>(Bytes.data())); | |||
612 | OS.indent(42); | |||
613 | } else { | |||
614 | OS << format("\t.byte 0x%02" PRIx8"x", Bytes[0]); | |||
615 | for (unsigned int i = 1; i < Bytes.size(); i++) | |||
616 | OS << format(", 0x%02" PRIx8"x", Bytes[i]); | |||
617 | OS.indent(55 - (6 * Bytes.size())); | |||
618 | } | |||
619 | } | |||
620 | ||||
621 | OS << format("// %012" PRIX64"l" "X" ":", Address.Address); | |||
622 | if (Bytes.size() >= 4) { | |||
623 | // D should be casted to uint32_t here as it is passed by format to | |||
624 | // snprintf as vararg. | |||
625 | for (uint32_t D : makeArrayRef( | |||
626 | reinterpret_cast<const support::little32_t *>(Bytes.data()), | |||
627 | Bytes.size() / 4)) | |||
628 | OS << format(" %08" PRIX32"X", D); | |||
629 | } else { | |||
630 | for (unsigned char B : Bytes) | |||
631 | OS << format(" %02" PRIX8"X", B); | |||
632 | } | |||
633 | ||||
634 | if (!Annot.empty()) | |||
635 | OS << " // " << Annot; | |||
636 | } | |||
637 | }; | |||
638 | AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst; | |||
639 | ||||
640 | class BPFPrettyPrinter : public PrettyPrinter { | |||
641 | public: | |||
642 | void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, | |||
643 | object::SectionedAddress Address, formatted_raw_ostream &OS, | |||
644 | StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP, | |||
645 | StringRef ObjectFilename, std::vector<RelocationRef> *Rels, | |||
646 | LiveVariablePrinter &LVP) override { | |||
647 | if (SP && (PrintSource || PrintLines)) | |||
648 | SP->printSourceLine(OS, Address, ObjectFilename, LVP); | |||
649 | if (LeadingAddr) | |||
650 | OS << format("%8" PRId64"l" "d" ":", Address.Address / 8); | |||
651 | if (ShowRawInsn) { | |||
652 | OS << "\t"; | |||
653 | dumpBytes(Bytes, OS); | |||
654 | } | |||
655 | if (MI) | |||
656 | IP.printInst(MI, Address.Address, "", STI, OS); | |||
657 | else | |||
658 | OS << "\t<unknown>"; | |||
659 | } | |||
660 | }; | |||
661 | BPFPrettyPrinter BPFPrettyPrinterInst; | |||
662 | ||||
663 | PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { | |||
664 | switch(Triple.getArch()) { | |||
665 | default: | |||
666 | return PrettyPrinterInst; | |||
667 | case Triple::hexagon: | |||
668 | return HexagonPrettyPrinterInst; | |||
669 | case Triple::amdgcn: | |||
670 | return AMDGCNPrettyPrinterInst; | |||
671 | case Triple::bpfel: | |||
672 | case Triple::bpfeb: | |||
673 | return BPFPrettyPrinterInst; | |||
674 | } | |||
675 | } | |||
676 | } | |||
677 | ||||
678 | static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) { | |||
679 | assert(Obj->isELF())(static_cast <bool> (Obj->isELF()) ? void (0) : __assert_fail ("Obj->isELF()", "llvm/tools/llvm-objdump/llvm-objdump.cpp" , 679, __extension__ __PRETTY_FUNCTION__)); | |||
680 | if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj)) | |||
681 | return unwrapOrError(Elf32LEObj->getSymbol(Sym.getRawDataRefImpl()), | |||
682 | Obj->getFileName()) | |||
683 | ->getType(); | |||
684 | if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj)) | |||
685 | return unwrapOrError(Elf64LEObj->getSymbol(Sym.getRawDataRefImpl()), | |||
686 | Obj->getFileName()) | |||
687 | ->getType(); | |||
688 | if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj)) | |||
689 | return unwrapOrError(Elf32BEObj->getSymbol(Sym.getRawDataRefImpl()), | |||
690 | Obj->getFileName()) | |||
691 | ->getType(); | |||
692 | if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj)) | |||
693 | return unwrapOrError(Elf64BEObj->getSymbol(Sym.getRawDataRefImpl()), | |||
694 | Obj->getFileName()) | |||
695 | ->getType(); | |||
696 | llvm_unreachable("Unsupported binary format")::llvm::llvm_unreachable_internal("Unsupported binary format" , "llvm/tools/llvm-objdump/llvm-objdump.cpp", 696); | |||
697 | } | |||
698 | ||||
699 | template <class ELFT> static void | |||
700 | addDynamicElfSymbols(const ELFObjectFile<ELFT> *Obj, | |||
701 | std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { | |||
702 | for (auto Symbol : Obj->getDynamicSymbolIterators()) { | |||
703 | uint8_t SymbolType = Symbol.getELFType(); | |||
704 | if (SymbolType == ELF::STT_SECTION) | |||
705 | continue; | |||
706 | ||||
707 | uint64_t Address = unwrapOrError(Symbol.getAddress(), Obj->getFileName()); | |||
708 | // ELFSymbolRef::getAddress() returns size instead of value for common | |||
709 | // symbols which is not desirable for disassembly output. Overriding. | |||
710 | if (SymbolType == ELF::STT_COMMON) | |||
711 | Address = unwrapOrError(Obj->getSymbol(Symbol.getRawDataRefImpl()), | |||
712 | Obj->getFileName()) | |||
713 | ->st_value; | |||
714 | ||||
715 | StringRef Name = unwrapOrError(Symbol.getName(), Obj->getFileName()); | |||
716 | if (Name.empty()) | |||
717 | continue; | |||
718 | ||||
719 | section_iterator SecI = | |||
720 | unwrapOrError(Symbol.getSection(), Obj->getFileName()); | |||
721 | if (SecI == Obj->section_end()) | |||
722 | continue; | |||
723 | ||||
724 | AllSymbols[*SecI].emplace_back(Address, Name, SymbolType); | |||
725 | } | |||
726 | } | |||
727 | ||||
728 | static void | |||
729 | addDynamicElfSymbols(const ObjectFile *Obj, | |||
730 | std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { | |||
731 | assert(Obj->isELF())(static_cast <bool> (Obj->isELF()) ? void (0) : __assert_fail ("Obj->isELF()", "llvm/tools/llvm-objdump/llvm-objdump.cpp" , 731, __extension__ __PRETTY_FUNCTION__)); | |||
732 | if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj)) | |||
733 | addDynamicElfSymbols(Elf32LEObj, AllSymbols); | |||
734 | else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj)) | |||
735 | addDynamicElfSymbols(Elf64LEObj, AllSymbols); | |||
736 | else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj)) | |||
737 | addDynamicElfSymbols(Elf32BEObj, AllSymbols); | |||
738 | else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj)) | |||
739 | addDynamicElfSymbols(Elf64BEObj, AllSymbols); | |||
740 | else | |||
741 | llvm_unreachable("Unsupported binary format")::llvm::llvm_unreachable_internal("Unsupported binary format" , "llvm/tools/llvm-objdump/llvm-objdump.cpp", 741); | |||
742 | } | |||
743 | ||||
744 | static Optional<SectionRef> getWasmCodeSection(const WasmObjectFile *Obj) { | |||
745 | for (auto SecI : Obj->sections()) { | |||
746 | const WasmSection &Section = Obj->getWasmSection(SecI); | |||
747 | if (Section.Type == wasm::WASM_SEC_CODE) | |||
748 | return SecI; | |||
749 | } | |||
750 | return None; | |||
751 | } | |||
752 | ||||
753 | static void | |||
754 | addMissingWasmCodeSymbols(const WasmObjectFile *Obj, | |||
755 | std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { | |||
756 | Optional<SectionRef> Section = getWasmCodeSection(Obj); | |||
757 | if (!Section) | |||
758 | return; | |||
759 | SectionSymbolsTy &Symbols = AllSymbols[*Section]; | |||
760 | ||||
761 | std::set<uint64_t> SymbolAddresses; | |||
762 | for (const auto &Sym : Symbols) | |||
763 | SymbolAddresses.insert(Sym.Addr); | |||
764 | ||||
765 | for (const wasm::WasmFunction &Function : Obj->functions()) { | |||
766 | uint64_t Address = Function.CodeSectionOffset; | |||
767 | // Only add fallback symbols for functions not already present in the symbol | |||
768 | // table. | |||
769 | if (SymbolAddresses.count(Address)) | |||
770 | continue; | |||
771 | // This function has no symbol, so it should have no SymbolName. | |||
772 | assert(Function.SymbolName.empty())(static_cast <bool> (Function.SymbolName.empty()) ? void (0) : __assert_fail ("Function.SymbolName.empty()", "llvm/tools/llvm-objdump/llvm-objdump.cpp" , 772, __extension__ __PRETTY_FUNCTION__)); | |||
773 | // We use DebugName for the name, though it may be empty if there is no | |||
774 | // "name" custom section, or that section is missing a name for this | |||
775 | // function. | |||
776 | StringRef Name = Function.DebugName; | |||
777 | Symbols.emplace_back(Address, Name, ELF::STT_NOTYPE); | |||
778 | } | |||
779 | } | |||
780 | ||||
781 | static void addPltEntries(const ObjectFile *Obj, | |||
782 | std::map<SectionRef, SectionSymbolsTy> &AllSymbols, | |||
783 | StringSaver &Saver) { | |||
784 | Optional<SectionRef> Plt = None; | |||
785 | for (const SectionRef &Section : Obj->sections()) { | |||
786 | Expected<StringRef> SecNameOrErr = Section.getName(); | |||
787 | if (!SecNameOrErr) { | |||
788 | consumeError(SecNameOrErr.takeError()); | |||
789 | continue; | |||
790 | } | |||
791 | if (*SecNameOrErr == ".plt") | |||
792 | Plt = Section; | |||
793 | } | |||
794 | if (!Plt) | |||
795 | return; | |||
796 | if (auto *ElfObj = dyn_cast<ELFObjectFileBase>(Obj)) { | |||
797 | for (auto PltEntry : ElfObj->getPltAddresses()) { | |||
798 | if (PltEntry.first) { | |||
799 | SymbolRef Symbol(*PltEntry.first, ElfObj); | |||
800 | uint8_t SymbolType = getElfSymbolType(Obj, Symbol); | |||
801 | if (Expected<StringRef> NameOrErr = Symbol.getName()) { | |||
802 | if (!NameOrErr->empty()) | |||
803 | AllSymbols[*Plt].emplace_back( | |||
804 | PltEntry.second, Saver.save((*NameOrErr + "@plt").str()), | |||
805 | SymbolType); | |||
806 | continue; | |||
807 | } else { | |||
808 | // The warning has been reported in disassembleObject(). | |||
809 | consumeError(NameOrErr.takeError()); | |||
810 | } | |||
811 | } | |||
812 | reportWarning("PLT entry at 0x" + Twine::utohexstr(PltEntry.second) + | |||
813 | " references an invalid symbol", | |||
814 | Obj->getFileName()); | |||
815 | } | |||
816 | } | |||
817 | } | |||
818 | ||||
819 | // Normally the disassembly output will skip blocks of zeroes. This function | |||
820 | // returns the number of zero bytes that can be skipped when dumping the | |||
821 | // disassembly of the instructions in Buf. | |||
822 | static size_t countSkippableZeroBytes(ArrayRef<uint8_t> Buf) { | |||
823 | // Find the number of leading zeroes. | |||
824 | size_t N = 0; | |||
825 | while (N < Buf.size() && !Buf[N]) | |||
826 | ++N; | |||
827 | ||||
828 | // We may want to skip blocks of zero bytes, but unless we see | |||
829 | // at least 8 of them in a row. | |||
830 | if (N < 8) | |||
831 | return 0; | |||
832 | ||||
833 | // We skip zeroes in multiples of 4 because do not want to truncate an | |||
834 | // instruction if it starts with a zero byte. | |||
835 | return N & ~0x3; | |||
836 | } | |||
837 | ||||
838 | // Returns a map from sections to their relocations. | |||
839 | static std::map<SectionRef, std::vector<RelocationRef>> | |||
840 | getRelocsMap(object::ObjectFile const &Obj) { | |||
841 | std::map<SectionRef, std::vector<RelocationRef>> Ret; | |||
842 | uint64_t I = (uint64_t)-1; | |||
843 | for (SectionRef Sec : Obj.sections()) { | |||
844 | ++I; | |||
845 | Expected<section_iterator> RelocatedOrErr = Sec.getRelocatedSection(); | |||
846 | if (!RelocatedOrErr) | |||
847 | reportError(Obj.getFileName(), | |||
848 | "section (" + Twine(I) + | |||
849 | "): failed to get a relocated section: " + | |||
850 | toString(RelocatedOrErr.takeError())); | |||
851 | ||||
852 | section_iterator Relocated = *RelocatedOrErr; | |||
853 | if (Relocated == Obj.section_end() || !checkSectionFilter(*Relocated).Keep) | |||
854 | continue; | |||
855 | std::vector<RelocationRef> &V = Ret[*Relocated]; | |||
856 | append_range(V, Sec.relocations()); | |||
857 | // Sort relocations by address. | |||
858 | llvm::stable_sort(V, isRelocAddressLess); | |||
859 | } | |||
860 | return Ret; | |||
861 | } | |||
862 | ||||
863 | // Used for --adjust-vma to check if address should be adjusted by the | |||
864 | // specified value for a given section. | |||
865 | // For ELF we do not adjust non-allocatable sections like debug ones, | |||
866 | // because they are not loadable. | |||
867 | // TODO: implement for other file formats. | |||
868 | static bool shouldAdjustVA(const SectionRef &Section) { | |||
869 | const ObjectFile *Obj = Section.getObject(); | |||
870 | if (Obj->isELF()) | |||
871 | return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC; | |||
872 | return false; | |||
873 | } | |||
874 | ||||
875 | ||||
876 | typedef std::pair<uint64_t, char> MappingSymbolPair; | |||
877 | static char getMappingSymbolKind(ArrayRef<MappingSymbolPair> MappingSymbols, | |||
878 | uint64_t Address) { | |||
879 | auto It = | |||
880 | partition_point(MappingSymbols, [Address](const MappingSymbolPair &Val) { | |||
881 | return Val.first <= Address; | |||
882 | }); | |||
883 | // Return zero for any address before the first mapping symbol; this means | |||
884 | // we should use the default disassembly mode, depending on the target. | |||
885 | if (It == MappingSymbols.begin()) | |||
886 | return '\x00'; | |||
887 | return (It - 1)->second; | |||
888 | } | |||
889 | ||||
890 | static uint64_t dumpARMELFData(uint64_t SectionAddr, uint64_t Index, | |||
891 | uint64_t End, const ObjectFile *Obj, | |||
892 | ArrayRef<uint8_t> Bytes, | |||
893 | ArrayRef<MappingSymbolPair> MappingSymbols, | |||
894 | raw_ostream &OS) { | |||
895 | support::endianness Endian = | |||
896 | Obj->isLittleEndian() ? support::little : support::big; | |||
897 | OS << format("%8" PRIx64"l" "x" ":\t", SectionAddr + Index); | |||
898 | if (Index + 4 <= End) { | |||
899 | dumpBytes(Bytes.slice(Index, 4), OS); | |||
900 | OS << "\t.word\t" | |||
901 | << format_hex(support::endian::read32(Bytes.data() + Index, Endian), | |||
902 | 10); | |||
903 | return 4; | |||
904 | } | |||
905 | if (Index + 2 <= End) { | |||
906 | dumpBytes(Bytes.slice(Index, 2), OS); | |||
907 | OS << "\t\t.short\t" | |||
908 | << format_hex(support::endian::read16(Bytes.data() + Index, Endian), | |||
909 | 6); | |||
910 | return 2; | |||
911 | } | |||
912 | dumpBytes(Bytes.slice(Index, 1), OS); | |||
913 | OS << "\t\t.byte\t" << format_hex(Bytes[0], 4); | |||
914 | return 1; | |||
915 | } | |||
916 | ||||
917 | static void dumpELFData(uint64_t SectionAddr, uint64_t Index, uint64_t End, | |||
918 | ArrayRef<uint8_t> Bytes) { | |||
919 | // print out data up to 8 bytes at a time in hex and ascii | |||
920 | uint8_t AsciiData[9] = {'\0'}; | |||
921 | uint8_t Byte; | |||
922 | int NumBytes = 0; | |||
923 | ||||
924 | for (; Index < End; ++Index) { | |||
925 | if (NumBytes == 0) | |||
926 | outs() << format("%8" PRIx64"l" "x" ":", SectionAddr + Index); | |||
927 | Byte = Bytes.slice(Index)[0]; | |||
928 | outs() << format(" %02x", Byte); | |||
929 | AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.'; | |||
930 | ||||
931 | uint8_t IndentOffset = 0; | |||
932 | NumBytes++; | |||
933 | if (Index == End - 1 || NumBytes > 8) { | |||
934 | // Indent the space for less than 8 bytes data. | |||
935 | // 2 spaces for byte and one for space between bytes | |||
936 | IndentOffset = 3 * (8 - NumBytes); | |||
937 | for (int Excess = NumBytes; Excess < 8; Excess++) | |||
938 | AsciiData[Excess] = '\0'; | |||
939 | NumBytes = 8; | |||
940 | } | |||
941 | if (NumBytes == 8) { | |||
942 | AsciiData[8] = '\0'; | |||
943 | outs() << std::string(IndentOffset, ' ') << " "; | |||
944 | outs() << reinterpret_cast<char *>(AsciiData); | |||
945 | outs() << '\n'; | |||
946 | NumBytes = 0; | |||
947 | } | |||
948 | } | |||
949 | } | |||
950 | ||||
951 | SymbolInfoTy objdump::createSymbolInfo(const ObjectFile *Obj, | |||
952 | const SymbolRef &Symbol) { | |||
953 | const StringRef FileName = Obj->getFileName(); | |||
954 | const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); | |||
955 | const StringRef Name = unwrapOrError(Symbol.getName(), FileName); | |||
956 | ||||
957 | if (Obj->isXCOFF() && SymbolDescription) { | |||
958 | const auto *XCOFFObj = cast<XCOFFObjectFile>(Obj); | |||
959 | DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl(); | |||
960 | ||||
961 | const uint32_t SymbolIndex = XCOFFObj->getSymbolIndex(SymbolDRI.p); | |||
962 | Optional<XCOFF::StorageMappingClass> Smc = | |||
963 | getXCOFFSymbolCsectSMC(XCOFFObj, Symbol); | |||
964 | return SymbolInfoTy(Addr, Name, Smc, SymbolIndex, | |||
965 | isLabel(XCOFFObj, Symbol)); | |||
966 | } else if (Obj->isXCOFF()) { | |||
967 | const SymbolRef::Type SymType = unwrapOrError(Symbol.getType(), FileName); | |||
968 | return SymbolInfoTy(Addr, Name, SymType, true); | |||
969 | } else | |||
970 | return SymbolInfoTy(Addr, Name, | |||
971 | Obj->isELF() ? getElfSymbolType(Obj, Symbol) | |||
972 | : (uint8_t)ELF::STT_NOTYPE); | |||
973 | } | |||
974 | ||||
975 | static SymbolInfoTy createDummySymbolInfo(const ObjectFile *Obj, | |||
976 | const uint64_t Addr, StringRef &Name, | |||
977 | uint8_t Type) { | |||
978 | if (Obj->isXCOFF() && SymbolDescription) | |||
979 | return SymbolInfoTy(Addr, Name, None, None, false); | |||
980 | else | |||
981 | return SymbolInfoTy(Addr, Name, Type); | |||
982 | } | |||
983 | ||||
984 | static void | |||
985 | collectLocalBranchTargets(ArrayRef<uint8_t> Bytes, const MCInstrAnalysis *MIA, | |||
986 | MCDisassembler *DisAsm, MCInstPrinter *IP, | |||
987 | const MCSubtargetInfo *STI, uint64_t SectionAddr, | |||
988 | uint64_t Start, uint64_t End, | |||
989 | std::unordered_map<uint64_t, std::string> &Labels) { | |||
990 | // So far only supports PowerPC and X86. | |||
991 | if (!STI->getTargetTriple().isPPC() && !STI->getTargetTriple().isX86()) | |||
992 | return; | |||
993 | ||||
994 | Labels.clear(); | |||
995 | unsigned LabelCount = 0; | |||
996 | Start += SectionAddr; | |||
997 | End += SectionAddr; | |||
998 | uint64_t Index = Start; | |||
999 | while (Index < End) { | |||
1000 | // Disassemble a real instruction and record function-local branch labels. | |||
1001 | MCInst Inst; | |||
1002 | uint64_t Size; | |||
1003 | bool Disassembled = DisAsm->getInstruction( | |||
1004 | Inst, Size, Bytes.slice(Index - SectionAddr), Index, nulls()); | |||
1005 | if (Size == 0) | |||
1006 | Size = 1; | |||
1007 | ||||
1008 | if (Disassembled && MIA) { | |||
1009 | uint64_t Target; | |||
1010 | bool TargetKnown = MIA->evaluateBranch(Inst, Index, Size, Target); | |||
1011 | // On PowerPC, if the address of a branch is the same as the target, it | |||
1012 | // means that it's a function call. Do not mark the label for this case. | |||
1013 | if (TargetKnown && (Target >= Start && Target < End) && | |||
1014 | !Labels.count(Target) && | |||
1015 | !(STI->getTargetTriple().isPPC() && Target == Index)) | |||
1016 | Labels[Target] = ("L" + Twine(LabelCount++)).str(); | |||
1017 | } | |||
1018 | ||||
1019 | Index += Size; | |||
1020 | } | |||
1021 | } | |||
1022 | ||||
1023 | // Create an MCSymbolizer for the target and add it to the MCDisassembler. | |||
1024 | // This is currently only used on AMDGPU, and assumes the format of the | |||
1025 | // void * argument passed to AMDGPU's createMCSymbolizer. | |||
1026 | static void addSymbolizer( | |||
1027 | MCContext &Ctx, const Target *Target, StringRef TripleName, | |||
1028 | MCDisassembler *DisAsm, uint64_t SectionAddr, ArrayRef<uint8_t> Bytes, | |||
1029 | SectionSymbolsTy &Symbols, | |||
1030 | std::vector<std::unique_ptr<std::string>> &SynthesizedLabelNames) { | |||
1031 | ||||
1032 | std::unique_ptr<MCRelocationInfo> RelInfo( | |||
1033 | Target->createMCRelocationInfo(TripleName, Ctx)); | |||
1034 | if (!RelInfo) | |||
1035 | return; | |||
1036 | std::unique_ptr<MCSymbolizer> Symbolizer(Target->createMCSymbolizer( | |||
1037 | TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo))); | |||
1038 | MCSymbolizer *SymbolizerPtr = &*Symbolizer; | |||
1039 | DisAsm->setSymbolizer(std::move(Symbolizer)); | |||
1040 | ||||
1041 | if (!SymbolizeOperands) | |||
1042 | return; | |||
1043 | ||||
1044 | // Synthesize labels referenced by branch instructions by | |||
1045 | // disassembling, discarding the output, and collecting the referenced | |||
1046 | // addresses from the symbolizer. | |||
1047 | for (size_t Index = 0; Index != Bytes.size();) { | |||
1048 | MCInst Inst; | |||
1049 | uint64_t Size; | |||
1050 | DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), SectionAddr + Index, | |||
1051 | nulls()); | |||
1052 | if (Size == 0) | |||
1053 | Size = 1; | |||
1054 | Index += Size; | |||
1055 | } | |||
1056 | ArrayRef<uint64_t> LabelAddrsRef = SymbolizerPtr->getReferencedAddresses(); | |||
1057 | // Copy and sort to remove duplicates. | |||
1058 | std::vector<uint64_t> LabelAddrs; | |||
1059 | LabelAddrs.insert(LabelAddrs.end(), LabelAddrsRef.begin(), | |||
1060 | LabelAddrsRef.end()); | |||
1061 | llvm::sort(LabelAddrs); | |||
1062 | LabelAddrs.resize(std::unique(LabelAddrs.begin(), LabelAddrs.end()) - | |||
1063 | LabelAddrs.begin()); | |||
1064 | // Add the labels. | |||
1065 | for (unsigned LabelNum = 0; LabelNum != LabelAddrs.size(); ++LabelNum) { | |||
1066 | auto Name = std::make_unique<std::string>(); | |||
1067 | *Name = (Twine("L") + Twine(LabelNum)).str(); | |||
1068 | SynthesizedLabelNames.push_back(std::move(Name)); | |||
1069 | Symbols.push_back(SymbolInfoTy( | |||
1070 | LabelAddrs[LabelNum], *SynthesizedLabelNames.back(), ELF::STT_NOTYPE)); | |||
1071 | } | |||
1072 | llvm::stable_sort(Symbols); | |||
1073 | // Recreate the symbolizer with the new symbols list. | |||
1074 | RelInfo.reset(Target->createMCRelocationInfo(TripleName, Ctx)); | |||
1075 | Symbolizer.reset(Target->createMCSymbolizer( | |||
1076 | TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo))); | |||
1077 | DisAsm->setSymbolizer(std::move(Symbolizer)); | |||
1078 | } | |||
1079 | ||||
1080 | static StringRef getSegmentName(const MachOObjectFile *MachO, | |||
1081 | const SectionRef &Section) { | |||
1082 | if (MachO) { | |||
1083 | DataRefImpl DR = Section.getRawDataRefImpl(); | |||
1084 | StringRef SegmentName = MachO->getSectionFinalSegmentName(DR); | |||
1085 | return SegmentName; | |||
1086 | } | |||
1087 | return ""; | |||
1088 | } | |||
1089 | ||||
1090 | static void emitPostInstructionInfo(formatted_raw_ostream &FOS, | |||
1091 | const MCAsmInfo &MAI, | |||
1092 | const MCSubtargetInfo &STI, | |||
1093 | StringRef Comments, | |||
1094 | LiveVariablePrinter &LVP) { | |||
1095 | do { | |||
1096 | if (!Comments.empty()) { | |||
1097 | // Emit a line of comments. | |||
1098 | StringRef Comment; | |||
1099 | std::tie(Comment, Comments) = Comments.split('\n'); | |||
1100 | // MAI.getCommentColumn() assumes that instructions are printed at the | |||
1101 | // position of 8, while getInstStartColumn() returns the actual position. | |||
1102 | unsigned CommentColumn = | |||
1103 | MAI.getCommentColumn() - 8 + getInstStartColumn(STI); | |||
1104 | FOS.PadToColumn(CommentColumn); | |||
1105 | FOS << MAI.getCommentString() << ' ' << Comment; | |||
1106 | } | |||
1107 | LVP.printAfterInst(FOS); | |||
1108 | FOS << '\n'; | |||
1109 | } while (!Comments.empty()); | |||
1110 | FOS.flush(); | |||
1111 | } | |||
1112 | ||||
1113 | static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, | |||
1114 | MCContext &Ctx, MCDisassembler *PrimaryDisAsm, | |||
1115 | MCDisassembler *SecondaryDisAsm, | |||
1116 | const MCInstrAnalysis *MIA, MCInstPrinter *IP, | |||
1117 | const MCSubtargetInfo *PrimarySTI, | |||
1118 | const MCSubtargetInfo *SecondarySTI, | |||
1119 | PrettyPrinter &PIP, | |||
1120 | SourcePrinter &SP, bool InlineRelocs) { | |||
1121 | const MCSubtargetInfo *STI = PrimarySTI; | |||
1122 | MCDisassembler *DisAsm = PrimaryDisAsm; | |||
1123 | bool PrimaryIsThumb = false; | |||
1124 | if (isArmElf(Obj)) | |||
1125 | PrimaryIsThumb = STI->checkFeatures("+thumb-mode"); | |||
1126 | ||||
1127 | std::map<SectionRef, std::vector<RelocationRef>> RelocMap; | |||
1128 | if (InlineRelocs) | |||
1129 | RelocMap = getRelocsMap(*Obj); | |||
1130 | bool Is64Bits = Obj->getBytesInAddress() > 4; | |||
1131 | ||||
1132 | // Create a mapping from virtual address to symbol name. This is used to | |||
1133 | // pretty print the symbols while disassembling. | |||
1134 | std::map<SectionRef, SectionSymbolsTy> AllSymbols; | |||
1135 | SectionSymbolsTy AbsoluteSymbols; | |||
1136 | const StringRef FileName = Obj->getFileName(); | |||
1137 | const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj); | |||
1138 | for (const SymbolRef &Symbol : Obj->symbols()) { | |||
1139 | Expected<StringRef> NameOrErr = Symbol.getName(); | |||
1140 | if (!NameOrErr) { | |||
1141 | reportWarning(toString(NameOrErr.takeError()), FileName); | |||
1142 | continue; | |||
1143 | } | |||
1144 | if (NameOrErr->empty() && !(Obj->isXCOFF() && SymbolDescription)) | |||
1145 | continue; | |||
1146 | ||||
1147 | if (Obj->isELF() && getElfSymbolType(Obj, Symbol) == ELF::STT_SECTION) | |||
1148 | continue; | |||
1149 | ||||
1150 | if (MachO) { | |||
1151 | // __mh_(execute|dylib|dylinker|bundle|preload|object)_header are special | |||
1152 | // symbols that support MachO header introspection. They do not bind to | |||
1153 | // code locations and are irrelevant for disassembly. | |||
1154 | if (NameOrErr->startswith("__mh_") && NameOrErr->endswith("_header")) | |||
1155 | continue; | |||
1156 | // Don't ask a Mach-O STAB symbol for its section unless you know that | |||
1157 | // STAB symbol's section field refers to a valid section index. Otherwise | |||
1158 | // the symbol may error trying to load a section that does not exist. | |||
1159 | DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); | |||
1160 | uint8_t NType = (MachO->is64Bit() ? | |||
1161 | MachO->getSymbol64TableEntry(SymDRI).n_type: | |||
1162 | MachO->getSymbolTableEntry(SymDRI).n_type); | |||
1163 | if (NType & MachO::N_STAB) | |||
1164 | continue; | |||
1165 | } | |||
1166 | ||||
1167 | section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); | |||
1168 | if (SecI != Obj->section_end()) | |||
1169 | AllSymbols[*SecI].push_back(createSymbolInfo(Obj, Symbol)); | |||
1170 | else | |||
1171 | AbsoluteSymbols.push_back(createSymbolInfo(Obj, Symbol)); | |||
1172 | } | |||
1173 | ||||
1174 | if (AllSymbols.empty() && Obj->isELF()) | |||
1175 | addDynamicElfSymbols(Obj, AllSymbols); | |||
1176 | ||||
1177 | if (Obj->isWasm()) | |||
1178 | addMissingWasmCodeSymbols(cast<WasmObjectFile>(Obj), AllSymbols); | |||
1179 | ||||
1180 | BumpPtrAllocator A; | |||
1181 | StringSaver Saver(A); | |||
1182 | addPltEntries(Obj, AllSymbols, Saver); | |||
1183 | ||||
1184 | // Create a mapping from virtual address to section. An empty section can | |||
1185 | // cause more than one section at the same address. Sort such sections to be | |||
1186 | // before same-addressed non-empty sections so that symbol lookups prefer the | |||
1187 | // non-empty section. | |||
1188 | std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses; | |||
1189 | for (SectionRef Sec : Obj->sections()) | |||
1190 | SectionAddresses.emplace_back(Sec.getAddress(), Sec); | |||
1191 | llvm::stable_sort(SectionAddresses, [](const auto &LHS, const auto &RHS) { | |||
1192 | if (LHS.first != RHS.first) | |||
1193 | return LHS.first < RHS.first; | |||
1194 | return LHS.second.getSize() < RHS.second.getSize(); | |||
1195 | }); | |||
1196 | ||||
1197 | // Linked executables (.exe and .dll files) typically don't include a real | |||
1198 | // symbol table but they might contain an export table. | |||
1199 | if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) { | |||
1200 | for (const auto &ExportEntry : COFFObj->export_directories()) { | |||
1201 | StringRef Name; | |||
1202 | if (Error E = ExportEntry.getSymbolName(Name)) | |||
1203 | reportError(std::move(E), Obj->getFileName()); | |||
1204 | if (Name.empty()) | |||
1205 | continue; | |||
1206 | ||||
1207 | uint32_t RVA; | |||
1208 | if (Error E = ExportEntry.getExportRVA(RVA)) | |||
1209 | reportError(std::move(E), Obj->getFileName()); | |||
1210 | ||||
1211 | uint64_t VA = COFFObj->getImageBase() + RVA; | |||
1212 | auto Sec = partition_point( | |||
1213 | SectionAddresses, [VA](const std::pair<uint64_t, SectionRef> &O) { | |||
1214 | return O.first <= VA; | |||
1215 | }); | |||
1216 | if (Sec != SectionAddresses.begin()) { | |||
1217 | --Sec; | |||
1218 | AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE); | |||
1219 | } else | |||
1220 | AbsoluteSymbols.emplace_back(VA, Name, ELF::STT_NOTYPE); | |||
1221 | } | |||
1222 | } | |||
1223 | ||||
1224 | // Sort all the symbols, this allows us to use a simple binary search to find | |||
1225 | // Multiple symbols can have the same address. Use a stable sort to stabilize | |||
1226 | // the output. | |||
1227 | StringSet<> FoundDisasmSymbolSet; | |||
1228 | for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) | |||
1229 | llvm::stable_sort(SecSyms.second); | |||
1230 | llvm::stable_sort(AbsoluteSymbols); | |||
1231 | ||||
1232 | std::unique_ptr<DWARFContext> DICtx; | |||
1233 | LiveVariablePrinter LVP(*Ctx.getRegisterInfo(), *STI); | |||
1234 | ||||
1235 | if (DbgVariables != DVDisabled) { | |||
1236 | DICtx = DWARFContext::create(*Obj); | |||
1237 | for (const std::unique_ptr<DWARFUnit> &CU : DICtx->compile_units()) | |||
1238 | LVP.addCompileUnit(CU->getUnitDIE(false)); | |||
1239 | } | |||
1240 | ||||
1241 | LLVM_DEBUG(LVP.dump())do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("objdump")) { LVP.dump(); } } while (false); | |||
1242 | ||||
1243 | for (const SectionRef &Section : ToolSectionFilter(*Obj)) { | |||
1244 | if (FilterSections.empty() && !DisassembleAll && | |||
1245 | (!Section.isText() || Section.isVirtual())) | |||
1246 | continue; | |||
1247 | ||||
1248 | uint64_t SectionAddr = Section.getAddress(); | |||
1249 | uint64_t SectSize = Section.getSize(); | |||
1250 | if (!SectSize) | |||
1251 | continue; | |||
1252 | ||||
1253 | // Get the list of all the symbols in this section. | |||
1254 | SectionSymbolsTy &Symbols = AllSymbols[Section]; | |||
1255 | std::vector<MappingSymbolPair> MappingSymbols; | |||
1256 | if (hasMappingSymbols(Obj)) { | |||
1257 | for (const auto &Symb : Symbols) { | |||
1258 | uint64_t Address = Symb.Addr; | |||
1259 | StringRef Name = Symb.Name; | |||
1260 | if (Name.startswith("$d")) | |||
1261 | MappingSymbols.emplace_back(Address - SectionAddr, 'd'); | |||
1262 | if (Name.startswith("$x")) | |||
1263 | MappingSymbols.emplace_back(Address - SectionAddr, 'x'); | |||
1264 | if (Name.startswith("$a")) | |||
1265 | MappingSymbols.emplace_back(Address - SectionAddr, 'a'); | |||
1266 | if (Name.startswith("$t")) | |||
1267 | MappingSymbols.emplace_back(Address - SectionAddr, 't'); | |||
1268 | } | |||
1269 | } | |||
1270 | ||||
1271 | llvm::sort(MappingSymbols); | |||
1272 | ||||
1273 | ArrayRef<uint8_t> Bytes = arrayRefFromStringRef( | |||
1274 | unwrapOrError(Section.getContents(), Obj->getFileName())); | |||
1275 | ||||
1276 | std::vector<std::unique_ptr<std::string>> SynthesizedLabelNames; | |||
1277 | if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) { | |||
1278 | // AMDGPU disassembler uses symbolizer for printing labels | |||
1279 | addSymbolizer(Ctx, TheTarget, TripleName, DisAsm, SectionAddr, Bytes, | |||
1280 | Symbols, SynthesizedLabelNames); | |||
1281 | } | |||
1282 | ||||
1283 | StringRef SegmentName = getSegmentName(MachO, Section); | |||
1284 | StringRef SectionName = unwrapOrError(Section.getName(), Obj->getFileName()); | |||
1285 | // If the section has no symbol at the start, just insert a dummy one. | |||
1286 | if (Symbols.empty() || Symbols[0].Addr != 0) { | |||
1287 | Symbols.insert(Symbols.begin(), | |||
1288 | createDummySymbolInfo(Obj, SectionAddr, SectionName, | |||
1289 | Section.isText() ? ELF::STT_FUNC | |||
1290 | : ELF::STT_OBJECT)); | |||
1291 | } | |||
1292 | ||||
1293 | SmallString<40> Comments; | |||
1294 | raw_svector_ostream CommentStream(Comments); | |||
1295 | ||||
1296 | uint64_t VMAAdjustment = 0; | |||
1297 | if (shouldAdjustVA(Section)) | |||
1298 | VMAAdjustment = AdjustVMA; | |||
1299 | ||||
1300 | // In executable and shared objects, r_offset holds a virtual address. | |||
1301 | // Subtract SectionAddr from the r_offset field of a relocation to get | |||
1302 | // the section offset. | |||
1303 | uint64_t RelAdjustment = Obj->isRelocatableObject() ? 0 : SectionAddr; | |||
1304 | uint64_t Size; | |||
1305 | uint64_t Index; | |||
1306 | bool PrintedSection = false; | |||
1307 | std::vector<RelocationRef> Rels = RelocMap[Section]; | |||
1308 | std::vector<RelocationRef>::const_iterator RelCur = Rels.begin(); | |||
1309 | std::vector<RelocationRef>::const_iterator RelEnd = Rels.end(); | |||
1310 | // Disassemble symbol by symbol. | |||
1311 | for (unsigned SI = 0, SE = Symbols.size(); SI != SE; ++SI) { | |||
1312 | std::string SymbolName = Symbols[SI].Name.str(); | |||
1313 | if (Demangle) | |||
1314 | SymbolName = demangle(SymbolName); | |||
1315 | ||||
1316 | // Skip if --disassemble-symbols is not empty and the symbol is not in | |||
1317 | // the list. | |||
1318 | if (!DisasmSymbolSet.empty() && !DisasmSymbolSet.count(SymbolName)) | |||
1319 | continue; | |||
1320 | ||||
1321 | uint64_t Start = Symbols[SI].Addr; | |||
1322 | if (Start < SectionAddr || StopAddress <= Start) | |||
1323 | continue; | |||
1324 | else | |||
1325 | FoundDisasmSymbolSet.insert(SymbolName); | |||
1326 | ||||
1327 | // The end is the section end, the beginning of the next symbol, or | |||
1328 | // --stop-address. | |||
1329 | uint64_t End = std::min<uint64_t>(SectionAddr + SectSize, StopAddress); | |||
1330 | if (SI + 1 < SE) | |||
1331 | End = std::min(End, Symbols[SI + 1].Addr); | |||
1332 | if (Start >= End || End <= StartAddress) | |||
1333 | continue; | |||
1334 | Start -= SectionAddr; | |||
1335 | End -= SectionAddr; | |||
1336 | ||||
1337 | if (!PrintedSection) { | |||
1338 | PrintedSection = true; | |||
1339 | outs() << "\nDisassembly of section "; | |||
1340 | if (!SegmentName.empty()) | |||
1341 | outs() << SegmentName << ","; | |||
1342 | outs() << SectionName << ":\n"; | |||
1343 | } | |||
1344 | ||||
1345 | outs() << '\n'; | |||
1346 | if (LeadingAddr) | |||
1347 | outs() << format(Is64Bits ? "%016" PRIx64"l" "x" " " : "%08" PRIx64"l" "x" " ", | |||
1348 | SectionAddr + Start + VMAAdjustment); | |||
1349 | if (Obj->isXCOFF() && SymbolDescription) { | |||
1350 | outs() << getXCOFFSymbolDescription(Symbols[SI], SymbolName) << ":\n"; | |||
1351 | } else | |||
1352 | outs() << '<' << SymbolName << ">:\n"; | |||
1353 | ||||
1354 | // Don't print raw contents of a virtual section. A virtual section | |||
1355 | // doesn't have any contents in the file. | |||
1356 | if (Section.isVirtual()) { | |||
1357 | outs() << "...\n"; | |||
1358 | continue; | |||
1359 | } | |||
1360 | ||||
1361 | auto Status = DisAsm->onSymbolStart(Symbols[SI], Size, | |||
1362 | Bytes.slice(Start, End - Start), | |||
1363 | SectionAddr + Start, CommentStream); | |||
1364 | // To have round trippable disassembly, we fall back to decoding the | |||
1365 | // remaining bytes as instructions. | |||
1366 | // | |||
1367 | // If there is a failure, we disassemble the failed region as bytes before | |||
1368 | // falling back. The target is expected to print nothing in this case. | |||
1369 | // | |||
1370 | // If there is Success or SoftFail i.e no 'real' failure, we go ahead by | |||
1371 | // Size bytes before falling back. | |||
1372 | // So if the entire symbol is 'eaten' by the target: | |||
1373 | // Start += Size // Now Start = End and we will never decode as | |||
1374 | // // instructions | |||
1375 | // | |||
1376 | // Right now, most targets return None i.e ignore to treat a symbol | |||
1377 | // separately. But WebAssembly decodes preludes for some symbols. | |||
1378 | // | |||
1379 | if (Status.hasValue()) { | |||
1380 | if (Status.getValue() == MCDisassembler::Fail) { | |||
1381 | outs() << "// Error in decoding " << SymbolName | |||
1382 | << " : Decoding failed region as bytes.\n"; | |||
1383 | for (uint64_t I = 0; I < Size; ++I) { | |||
1384 | outs() << "\t.byte\t " << format_hex(Bytes[I], 1, /*Upper=*/true) | |||
1385 | << "\n"; | |||
1386 | } | |||
1387 | } | |||
1388 | } else { | |||
1389 | Size = 0; | |||
1390 | } | |||
1391 | ||||
1392 | Start += Size; | |||
1393 | ||||
1394 | Index = Start; | |||
1395 | if (SectionAddr < StartAddress) | |||
1396 | Index = std::max<uint64_t>(Index, StartAddress - SectionAddr); | |||
1397 | ||||
1398 | // If there is a data/common symbol inside an ELF text section and we are | |||
1399 | // only disassembling text (applicable all architectures), we are in a | |||
1400 | // situation where we must print the data and not disassemble it. | |||
1401 | if (Obj->isELF() && !DisassembleAll && Section.isText()) { | |||
1402 | uint8_t SymTy = Symbols[SI].Type; | |||
1403 | if (SymTy == ELF::STT_OBJECT || SymTy == ELF::STT_COMMON) { | |||
1404 | dumpELFData(SectionAddr, Index, End, Bytes); | |||
1405 | Index = End; | |||
1406 | } | |||
1407 | } | |||
1408 | ||||
1409 | bool CheckARMELFData = hasMappingSymbols(Obj) && | |||
1410 | Symbols[SI].Type != ELF::STT_OBJECT && | |||
1411 | !DisassembleAll; | |||
1412 | bool DumpARMELFData = false; | |||
1413 | formatted_raw_ostream FOS(outs()); | |||
1414 | ||||
1415 | std::unordered_map<uint64_t, std::string> AllLabels; | |||
1416 | if (SymbolizeOperands) | |||
1417 | collectLocalBranchTargets(Bytes, MIA, DisAsm, IP, PrimarySTI, | |||
1418 | SectionAddr, Index, End, AllLabels); | |||
1419 | ||||
1420 | while (Index < End) { | |||
1421 | // ARM and AArch64 ELF binaries can interleave data and text in the | |||
1422 | // same section. We rely on the markers introduced to understand what | |||
1423 | // we need to dump. If the data marker is within a function, it is | |||
1424 | // denoted as a word/short etc. | |||
1425 | if (CheckARMELFData) { | |||
1426 | char Kind = getMappingSymbolKind(MappingSymbols, Index); | |||
1427 | DumpARMELFData = Kind == 'd'; | |||
1428 | if (SecondarySTI) { | |||
1429 | if (Kind == 'a') { | |||
1430 | STI = PrimaryIsThumb ? SecondarySTI : PrimarySTI; | |||
1431 | DisAsm = PrimaryIsThumb ? SecondaryDisAsm : PrimaryDisAsm; | |||
1432 | } else if (Kind == 't') { | |||
1433 | STI = PrimaryIsThumb ? PrimarySTI : SecondarySTI; | |||
1434 | DisAsm = PrimaryIsThumb ? PrimaryDisAsm : SecondaryDisAsm; | |||
1435 | } | |||
1436 | } | |||
1437 | } | |||
1438 | ||||
1439 | if (DumpARMELFData) { | |||
1440 | Size = dumpARMELFData(SectionAddr, Index, End, Obj, Bytes, | |||
1441 | MappingSymbols, FOS); | |||
1442 | } else { | |||
1443 | // When -z or --disassemble-zeroes are given we always dissasemble | |||
1444 | // them. Otherwise we might want to skip zero bytes we see. | |||
1445 | if (!DisassembleZeroes) { | |||
1446 | uint64_t MaxOffset = End - Index; | |||
1447 | // For --reloc: print zero blocks patched by relocations, so that | |||
1448 | // relocations can be shown in the dump. | |||
1449 | if (RelCur != RelEnd) | |||
1450 | MaxOffset = std::min(RelCur->getOffset() - RelAdjustment - Index, | |||
1451 | MaxOffset); | |||
1452 | ||||
1453 | if (size_t N = | |||
1454 | countSkippableZeroBytes(Bytes.slice(Index, MaxOffset))) { | |||
1455 | FOS << "\t\t..." << '\n'; | |||
1456 | Index += N; | |||
1457 | continue; | |||
1458 | } | |||
1459 | } | |||
1460 | ||||
1461 | // Print local label if there's any. | |||
1462 | auto Iter = AllLabels.find(SectionAddr + Index); | |||
1463 | if (Iter != AllLabels.end()) | |||
1464 | FOS << "<" << Iter->second << ">:\n"; | |||
1465 | ||||
1466 | // Disassemble a real instruction or a data when disassemble all is | |||
1467 | // provided | |||
1468 | MCInst Inst; | |||
1469 | bool Disassembled = | |||
1470 | DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), | |||
1471 | SectionAddr + Index, CommentStream); | |||
1472 | if (Size == 0) | |||
1473 | Size = 1; | |||
1474 | ||||
1475 | LVP.update({Index, Section.getIndex()}, | |||
1476 | {Index + Size, Section.getIndex()}, Index + Size != End); | |||
1477 | ||||
1478 | IP->setCommentStream(CommentStream); | |||
1479 | ||||
1480 | PIP.printInst( | |||
1481 | *IP, Disassembled ? &Inst : nullptr, Bytes.slice(Index, Size), | |||
1482 | {SectionAddr + Index + VMAAdjustment, Section.getIndex()}, FOS, | |||
1483 | "", *STI, &SP, Obj->getFileName(), &Rels, LVP); | |||
1484 | ||||
1485 | IP->setCommentStream(llvm::nulls()); | |||
1486 | ||||
1487 | // If disassembly has failed, avoid analysing invalid/incomplete | |||
1488 | // instruction information. Otherwise, try to resolve the target | |||
1489 | // address (jump target or memory operand address) and print it on the | |||
1490 | // right of the instruction. | |||
1491 | if (Disassembled && MIA) { | |||
1492 | // Branch targets are printed just after the instructions. | |||
1493 | llvm::raw_ostream *TargetOS = &FOS; | |||
1494 | uint64_t Target; | |||
1495 | bool PrintTarget = | |||
1496 | MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target); | |||
1497 | if (!PrintTarget) | |||
1498 | if (Optional<uint64_t> MaybeTarget = | |||
1499 | MIA->evaluateMemoryOperandAddress( | |||
1500 | Inst, STI, SectionAddr + Index, Size)) { | |||
1501 | Target = *MaybeTarget; | |||
1502 | PrintTarget = true; | |||
1503 | // Do not print real address when symbolizing. | |||
1504 | if (!SymbolizeOperands) { | |||
1505 | // Memory operand addresses are printed as comments. | |||
1506 | TargetOS = &CommentStream; | |||
1507 | *TargetOS << "0x" << Twine::utohexstr(Target); | |||
1508 | } | |||
1509 | } | |||
1510 | if (PrintTarget) { | |||
1511 | // In a relocatable object, the target's section must reside in | |||
1512 | // the same section as the call instruction or it is accessed | |||
1513 | // through a relocation. | |||
1514 | // | |||
1515 | // In a non-relocatable object, the target may be in any section. | |||
1516 | // In that case, locate the section(s) containing the target | |||
1517 | // address and find the symbol in one of those, if possible. | |||
1518 | // | |||
1519 | // N.B. We don't walk the relocations in the relocatable case yet. | |||
1520 | std::vector<const SectionSymbolsTy *> TargetSectionSymbols; | |||
1521 | if (!Obj->isRelocatableObject()) { | |||
1522 | auto It = llvm::partition_point( | |||
1523 | SectionAddresses, | |||
1524 | [=](const std::pair<uint64_t, SectionRef> &O) { | |||
1525 | return O.first <= Target; | |||
1526 | }); | |||
1527 | uint64_t TargetSecAddr = 0; | |||
1528 | while (It != SectionAddresses.begin()) { | |||
1529 | --It; | |||
1530 | if (TargetSecAddr == 0) | |||
1531 | TargetSecAddr = It->first; | |||
1532 | if (It->first != TargetSecAddr) | |||
1533 | break; | |||
1534 | TargetSectionSymbols.push_back(&AllSymbols[It->second]); | |||
1535 | } | |||
1536 | } else { | |||
1537 | TargetSectionSymbols.push_back(&Symbols); | |||
1538 | } | |||
1539 | TargetSectionSymbols.push_back(&AbsoluteSymbols); | |||
1540 | ||||
1541 | // Find the last symbol in the first candidate section whose | |||
1542 | // offset is less than or equal to the target. If there are no | |||
1543 | // such symbols, try in the next section and so on, before finally | |||
1544 | // using the nearest preceding absolute symbol (if any), if there | |||
1545 | // are no other valid symbols. | |||
1546 | const SymbolInfoTy *TargetSym = nullptr; | |||
1547 | for (const SectionSymbolsTy *TargetSymbols : | |||
1548 | TargetSectionSymbols) { | |||
1549 | auto It = llvm::partition_point( | |||
1550 | *TargetSymbols, | |||
1551 | [=](const SymbolInfoTy &O) { return O.Addr <= Target; }); | |||
1552 | if (It != TargetSymbols->begin()) { | |||
1553 | TargetSym = &*(It - 1); | |||
1554 | break; | |||
1555 | } | |||
1556 | } | |||
1557 | ||||
1558 | // Print the labels corresponding to the target if there's any. | |||
1559 | bool LabelAvailable = AllLabels.count(Target); | |||
1560 | if (TargetSym != nullptr) { | |||
1561 | uint64_t TargetAddress = TargetSym->Addr; | |||
1562 | uint64_t Disp = Target - TargetAddress; | |||
1563 | std::string TargetName = TargetSym->Name.str(); | |||
1564 | if (Demangle) | |||
1565 | TargetName = demangle(TargetName); | |||
1566 | ||||
1567 | *TargetOS << " <"; | |||
1568 | if (!Disp) { | |||
1569 | // Always Print the binary symbol precisely corresponding to | |||
1570 | // the target address. | |||
1571 | *TargetOS << TargetName; | |||
1572 | } else if (!LabelAvailable) { | |||
1573 | // Always Print the binary symbol plus an offset if there's no | |||
1574 | // local label corresponding to the target address. | |||
1575 | *TargetOS << TargetName << "+0x" << Twine::utohexstr(Disp); | |||
1576 | } else { | |||
1577 | *TargetOS << AllLabels[Target]; | |||
1578 | } | |||
1579 | *TargetOS << ">"; | |||
1580 | } else if (LabelAvailable) { | |||
1581 | *TargetOS << " <" << AllLabels[Target] << ">"; | |||
1582 | } | |||
1583 | // By convention, each record in the comment stream should be | |||
1584 | // terminated. | |||
1585 | if (TargetOS == &CommentStream) | |||
1586 | *TargetOS << "\n"; | |||
1587 | } | |||
1588 | } | |||
1589 | } | |||
1590 | ||||
1591 | assert(Ctx.getAsmInfo())(static_cast <bool> (Ctx.getAsmInfo()) ? void (0) : __assert_fail ("Ctx.getAsmInfo()", "llvm/tools/llvm-objdump/llvm-objdump.cpp" , 1591, __extension__ __PRETTY_FUNCTION__)); | |||
1592 | emitPostInstructionInfo(FOS, *Ctx.getAsmInfo(), *STI, | |||
1593 | CommentStream.str(), LVP); | |||
1594 | Comments.clear(); | |||
1595 | ||||
1596 | // Hexagon does this in pretty printer | |||
1597 | if (Obj->getArch() != Triple::hexagon) { | |||
1598 | // Print relocation for instruction and data. | |||
1599 | while (RelCur != RelEnd) { | |||
1600 | uint64_t Offset = RelCur->getOffset() - RelAdjustment; | |||
1601 | // If this relocation is hidden, skip it. | |||
1602 | if (getHidden(*RelCur) || SectionAddr + Offset < StartAddress) { | |||
1603 | ++RelCur; | |||
1604 | continue; | |||
1605 | } | |||
1606 | ||||
1607 | // Stop when RelCur's offset is past the disassembled | |||
1608 | // instruction/data. Note that it's possible the disassembled data | |||
1609 | // is not the complete data: we might see the relocation printed in | |||
1610 | // the middle of the data, but this matches the binutils objdump | |||
1611 | // output. | |||
1612 | if (Offset >= Index + Size) | |||
1613 | break; | |||
1614 | ||||
1615 | // When --adjust-vma is used, update the address printed. | |||
1616 | if (RelCur->getSymbol() != Obj->symbol_end()) { | |||
1617 | Expected<section_iterator> SymSI = | |||
1618 | RelCur->getSymbol()->getSection(); | |||
1619 | if (SymSI && *SymSI != Obj->section_end() && | |||
1620 | shouldAdjustVA(**SymSI)) | |||
1621 | Offset += AdjustVMA; | |||
1622 | } | |||
1623 | ||||
1624 | printRelocation(FOS, Obj->getFileName(), *RelCur, | |||
1625 | SectionAddr + Offset, Is64Bits); | |||
1626 | LVP.printAfterOtherLine(FOS, true); | |||
1627 | ++RelCur; | |||
1628 | } | |||
1629 | } | |||
1630 | ||||
1631 | Index += Size; | |||
1632 | } | |||
1633 | } | |||
1634 | } | |||
1635 | StringSet<> MissingDisasmSymbolSet = | |||
1636 | set_difference(DisasmSymbolSet, FoundDisasmSymbolSet); | |||
1637 | for (StringRef Sym : MissingDisasmSymbolSet.keys()) | |||
1638 | reportWarning("failed to disassemble missing symbol " + Sym, FileName); | |||
1639 | } | |||
1640 | ||||
1641 | static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) { | |||
1642 | const Target *TheTarget = getTarget(Obj); | |||
1643 | ||||
1644 | // Package up features to be passed to target/subtarget | |||
1645 | SubtargetFeatures Features = Obj->getFeatures(); | |||
1646 | if (!MAttrs.empty()) | |||
1647 | for (unsigned I = 0; I != MAttrs.size(); ++I) | |||
1648 | Features.AddFeature(MAttrs[I]); | |||
1649 | ||||
1650 | std::unique_ptr<const MCRegisterInfo> MRI( | |||
1651 | TheTarget->createMCRegInfo(TripleName)); | |||
1652 | if (!MRI) | |||
1653 | reportError(Obj->getFileName(), | |||
1654 | "no register info for target " + TripleName); | |||
1655 | ||||
1656 | // Set up disassembler. | |||
1657 | MCTargetOptions MCOptions; | |||
1658 | std::unique_ptr<const MCAsmInfo> AsmInfo( | |||
1659 | TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); | |||
1660 | if (!AsmInfo) | |||
1661 | reportError(Obj->getFileName(), | |||
1662 | "no assembly info for target " + TripleName); | |||
1663 | ||||
1664 | if (MCPU.empty()) | |||
1665 | MCPU = Obj->tryGetCPUName().getValueOr("").str(); | |||
1666 | ||||
1667 | std::unique_ptr<const MCSubtargetInfo> STI( | |||
1668 | TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString())); | |||
1669 | if (!STI) | |||
1670 | reportError(Obj->getFileName(), | |||
1671 | "no subtarget info for target " + TripleName); | |||
1672 | std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo()); | |||
1673 | if (!MII) | |||
1674 | reportError(Obj->getFileName(), | |||
1675 | "no instruction info for target " + TripleName); | |||
1676 | MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get()); | |||
1677 | // FIXME: for now initialize MCObjectFileInfo with default values | |||
1678 | std::unique_ptr<MCObjectFileInfo> MOFI( | |||
1679 | TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false)); | |||
1680 | Ctx.setObjectFileInfo(MOFI.get()); | |||
1681 | ||||
1682 | std::unique_ptr<MCDisassembler> DisAsm( | |||
1683 | TheTarget->createMCDisassembler(*STI, Ctx)); | |||
1684 | if (!DisAsm) | |||
1685 | reportError(Obj->getFileName(), "no disassembler for target " + TripleName); | |||
1686 | ||||
1687 | // If we have an ARM object file, we need a second disassembler, because | |||
1688 | // ARM CPUs have two different instruction sets: ARM mode, and Thumb mode. | |||
1689 | // We use mapping symbols to switch between the two assemblers, where | |||
1690 | // appropriate. | |||
1691 | std::unique_ptr<MCDisassembler> SecondaryDisAsm; | |||
1692 | std::unique_ptr<const MCSubtargetInfo> SecondarySTI; | |||
1693 | if (isArmElf(Obj) && !STI->checkFeatures("+mclass")) { | |||
1694 | if (STI->checkFeatures("+thumb-mode")) | |||
1695 | Features.AddFeature("-thumb-mode"); | |||
1696 | else | |||
1697 | Features.AddFeature("+thumb-mode"); | |||
1698 | SecondarySTI.reset(TheTarget->createMCSubtargetInfo(TripleName, MCPU, | |||
1699 | Features.getString())); | |||
1700 | SecondaryDisAsm.reset(TheTarget->createMCDisassembler(*SecondarySTI, Ctx)); | |||
1701 | } | |||
1702 | ||||
1703 | std::unique_ptr<const MCInstrAnalysis> MIA( | |||
1704 | TheTarget->createMCInstrAnalysis(MII.get())); | |||
1705 | ||||
1706 | int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); | |||
1707 | std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( | |||
1708 | Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); | |||
1709 | if (!IP) | |||
1710 | reportError(Obj->getFileName(), | |||
1711 | "no instruction printer for target " + TripleName); | |||
1712 | IP->setPrintImmHex(PrintImmHex); | |||
1713 | IP->setPrintBranchImmAsAddress(true); | |||
1714 | IP->setSymbolizeOperands(SymbolizeOperands); | |||
1715 | IP->setMCInstrAnalysis(MIA.get()); | |||
1716 | ||||
1717 | PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName)); | |||
1718 | SourcePrinter SP(Obj, TheTarget->getName()); | |||
1719 | ||||
1720 | for (StringRef Opt : DisassemblerOptions) | |||
1721 | if (!IP->applyTargetSpecificCLOption(Opt)) | |||
1722 | reportError(Obj->getFileName(), | |||
1723 | "Unrecognized disassembler option: " + Opt); | |||
1724 | ||||
1725 | disassembleObject(TheTarget, Obj, Ctx, DisAsm.get(), SecondaryDisAsm.get(), | |||
1726 | MIA.get(), IP.get(), STI.get(), SecondarySTI.get(), PIP, | |||
1727 | SP, InlineRelocs); | |||
1728 | } | |||
1729 | ||||
1730 | void objdump::printRelocations(const ObjectFile *Obj) { | |||
1731 | StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64"l" "x" : | |||
1732 | "%08" PRIx64"l" "x"; | |||
1733 | // Regular objdump doesn't print relocations in non-relocatable object | |||
1734 | // files. | |||
1735 | if (!Obj->isRelocatableObject()) | |||
1736 | return; | |||
1737 | ||||
1738 | // Build a mapping from relocation target to a vector of relocation | |||
1739 | // sections. Usually, there is an only one relocation section for | |||
1740 | // each relocated section. | |||
1741 | MapVector<SectionRef, std::vector<SectionRef>> SecToRelSec; | |||
1742 | uint64_t Ndx; | |||
1743 | for (const SectionRef &Section : ToolSectionFilter(*Obj, &Ndx)) { | |||
1744 | if (Section.relocation_begin() == Section.relocation_end()) | |||
1745 | continue; | |||
1746 | Expected<section_iterator> SecOrErr = Section.getRelocatedSection(); | |||
1747 | if (!SecOrErr) | |||
1748 | reportError(Obj->getFileName(), | |||
1749 | "section (" + Twine(Ndx) + | |||
1750 | "): unable to get a relocation target: " + | |||
1751 | toString(SecOrErr.takeError())); | |||
1752 | SecToRelSec[**SecOrErr].push_back(Section); | |||
1753 | } | |||
1754 | ||||
1755 | for (std::pair<SectionRef, std::vector<SectionRef>> &P : SecToRelSec) { | |||
1756 | StringRef SecName = unwrapOrError(P.first.getName(), Obj->getFileName()); | |||
1757 | outs() << "\nRELOCATION RECORDS FOR [" << SecName << "]:\n"; | |||
1758 | uint32_t OffsetPadding = (Obj->getBytesInAddress() > 4 ? 16 : 8); | |||
1759 | uint32_t TypePadding = 24; | |||
1760 | outs() << left_justify("OFFSET", OffsetPadding) << " " | |||
1761 | << left_justify("TYPE", TypePadding) << " " | |||
1762 | << "VALUE\n"; | |||
1763 | ||||
1764 | for (SectionRef Section : P.second) { | |||
1765 | for (const RelocationRef &Reloc : Section.relocations()) { | |||
1766 | uint64_t Address = Reloc.getOffset(); | |||
1767 | SmallString<32> RelocName; | |||
1768 | SmallString<32> ValueStr; | |||
1769 | if (Address < StartAddress || Address > StopAddress || getHidden(Reloc)) | |||
1770 | continue; | |||
1771 | Reloc.getTypeName(RelocName); | |||
1772 | if (Error E = getRelocationValueString(Reloc, ValueStr)) | |||
1773 | reportError(std::move(E), Obj->getFileName()); | |||
1774 | ||||
1775 | outs() << format(Fmt.data(), Address) << " " | |||
1776 | << left_justify(RelocName, TypePadding) << " " << ValueStr | |||
1777 | << "\n"; | |||
1778 | } | |||
1779 | } | |||
1780 | } | |||
1781 | } | |||
1782 | ||||
1783 | void objdump::printDynamicRelocations(const ObjectFile *Obj) { | |||
1784 | // For the moment, this option is for ELF only | |||
1785 | if (!Obj->isELF()) | |||
1786 | return; | |||
1787 | ||||
1788 | const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj); | |||
1789 | if (!Elf || !any_of(Elf->sections(), [](const ELFSectionRef Sec) { | |||
1790 | return Sec.getType() == ELF::SHT_DYNAMIC; | |||
1791 | })) { | |||
1792 | reportError(Obj->getFileName(), "not a dynamic object"); | |||
1793 | return; | |||
1794 | } | |||
1795 | ||||
1796 | std::vector<SectionRef> DynRelSec = Obj->dynamic_relocation_sections(); | |||
1797 | if (DynRelSec.empty()) | |||
1798 | return; | |||
1799 | ||||
1800 | outs() << "\nDYNAMIC RELOCATION RECORDS\n"; | |||
1801 | const uint32_t OffsetPadding = (Obj->getBytesInAddress() > 4 ? 16 : 8); | |||
1802 | const uint32_t TypePadding = 24; | |||
1803 | outs() << left_justify("OFFSET", OffsetPadding) << ' ' | |||
1804 | << left_justify("TYPE", TypePadding) << " VALUE\n"; | |||
1805 | ||||
1806 | StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64"l" "x" : "%08" PRIx64"l" "x"; | |||
1807 | for (const SectionRef &Section : DynRelSec) | |||
1808 | for (const RelocationRef &Reloc : Section.relocations()) { | |||
1809 | uint64_t Address = Reloc.getOffset(); | |||
1810 | SmallString<32> RelocName; | |||
1811 | SmallString<32> ValueStr; | |||
1812 | Reloc.getTypeName(RelocName); | |||
1813 | if (Error E = getRelocationValueString(Reloc, ValueStr)) | |||
1814 | reportError(std::move(E), Obj->getFileName()); | |||
1815 | outs() << format(Fmt.data(), Address) << ' ' | |||
1816 | << left_justify(RelocName, TypePadding) << ' ' << ValueStr << '\n'; | |||
1817 | } | |||
1818 | } | |||
1819 | ||||
1820 | // Returns true if we need to show LMA column when dumping section headers. We | |||
1821 | // show it only when the platform is ELF and either we have at least one section | |||
1822 | // whose VMA and LMA are different and/or when --show-lma flag is used. | |||
1823 | static bool shouldDisplayLMA(const ObjectFile *Obj) { | |||
1824 | if (!Obj->isELF()) | |||
1825 | return false; | |||
1826 | for (const SectionRef &S : ToolSectionFilter(*Obj)) | |||
1827 | if (S.getAddress() != getELFSectionLMA(S)) | |||
1828 | return true; | |||
1829 | return ShowLMA; | |||
1830 | } | |||
1831 | ||||
1832 | static size_t getMaxSectionNameWidth(const ObjectFile *Obj) { | |||
1833 | // Default column width for names is 13 even if no names are that long. | |||
1834 | size_t MaxWidth = 13; | |||
1835 | for (const SectionRef &Section : ToolSectionFilter(*Obj)) { | |||
1836 | StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); | |||
1837 | MaxWidth = std::max(MaxWidth, Name.size()); | |||
1838 | } | |||
1839 | return MaxWidth; | |||
1840 | } | |||
1841 | ||||
1842 | void objdump::printSectionHeaders(const ObjectFile *Obj) { | |||
1843 | size_t NameWidth = getMaxSectionNameWidth(Obj); | |||
1844 | size_t AddressWidth = 2 * Obj->getBytesInAddress(); | |||
1845 | bool HasLMAColumn = shouldDisplayLMA(Obj); | |||
1846 | outs() << "\nSections:\n"; | |||
1847 | if (HasLMAColumn) | |||
1848 | outs() << "Idx " << left_justify("Name", NameWidth) << " Size " | |||
1849 | << left_justify("VMA", AddressWidth) << " " | |||
1850 | << left_justify("LMA", AddressWidth) << " Type\n"; | |||
1851 | else | |||
1852 | outs() << "Idx " << left_justify("Name", NameWidth) << " Size " | |||
1853 | << left_justify("VMA", AddressWidth) << " Type\n"; | |||
1854 | ||||
1855 | uint64_t Idx; | |||
1856 | for (const SectionRef &Section : ToolSectionFilter(*Obj, &Idx)) { | |||
1857 | StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); | |||
1858 | uint64_t VMA = Section.getAddress(); | |||
1859 | if (shouldAdjustVA(Section)) | |||
1860 | VMA += AdjustVMA; | |||
1861 | ||||
1862 | uint64_t Size = Section.getSize(); | |||
1863 | ||||
1864 | std::string Type = Section.isText() ? "TEXT" : ""; | |||
1865 | if (Section.isData()) | |||
1866 | Type += Type.empty() ? "DATA" : ", DATA"; | |||
1867 | if (Section.isBSS()) | |||
1868 | Type += Type.empty() ? "BSS" : ", BSS"; | |||
1869 | if (Section.isDebugSection()) | |||
1870 | Type += Type.empty() ? "DEBUG" : ", DEBUG"; | |||
1871 | ||||
1872 | if (HasLMAColumn) | |||
1873 | outs() << format("%3" PRIu64"l" "u" " %-*s %08" PRIx64"l" "x" " ", Idx, NameWidth, | |||
1874 | Name.str().c_str(), Size) | |||
1875 | << format_hex_no_prefix(VMA, AddressWidth) << " " | |||
1876 | << format_hex_no_prefix(getELFSectionLMA(Section), AddressWidth) | |||
1877 | << " " << Type << "\n"; | |||
1878 | else | |||
1879 | outs() << format("%3" PRIu64"l" "u" " %-*s %08" PRIx64"l" "x" " ", Idx, NameWidth, | |||
1880 | Name.str().c_str(), Size) | |||
1881 | << format_hex_no_prefix(VMA, AddressWidth) << " " << Type << "\n"; | |||
1882 | } | |||
1883 | } | |||
1884 | ||||
1885 | void objdump::printSectionContents(const ObjectFile *Obj) { | |||
1886 | const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj); | |||
1887 | ||||
1888 | for (const SectionRef &Section : ToolSectionFilter(*Obj)) { | |||
1889 | StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); | |||
1890 | uint64_t BaseAddr = Section.getAddress(); | |||
1891 | uint64_t Size = Section.getSize(); | |||
1892 | if (!Size) | |||
1893 | continue; | |||
1894 | ||||
1895 | outs() << "Contents of section "; | |||
1896 | StringRef SegmentName = getSegmentName(MachO, Section); | |||
1897 | if (!SegmentName.empty()) | |||
1898 | outs() << SegmentName << ","; | |||
1899 | outs() << Name << ":\n"; | |||
1900 | if (Section.isBSS()) { | |||
1901 | outs() << format("<skipping contents of bss section at [%04" PRIx64"l" "x" | |||
1902 | ", %04" PRIx64"l" "x" ")>\n", | |||
1903 | BaseAddr, BaseAddr + Size); | |||
1904 | continue; | |||
1905 | } | |||
1906 | ||||
1907 | StringRef Contents = unwrapOrError(Section.getContents(), Obj->getFileName()); | |||
1908 | ||||
1909 | // Dump out the content as hex and printable ascii characters. | |||
1910 | for (std::size_t Addr = 0, End = Contents.size(); Addr < End; Addr += 16) { | |||
1911 | outs() << format(" %04" PRIx64"l" "x" " ", BaseAddr + Addr); | |||
1912 | // Dump line of hex. | |||
1913 | for (std::size_t I = 0; I < 16; ++I) { | |||
1914 | if (I != 0 && I % 4 == 0) | |||
1915 | outs() << ' '; | |||
1916 | if (Addr + I < End) | |||
1917 | outs() << hexdigit((Contents[Addr + I] >> 4) & 0xF, true) | |||
1918 | << hexdigit(Contents[Addr + I] & 0xF, true); | |||
1919 | else | |||
1920 | outs() << " "; | |||
1921 | } | |||
1922 | // Print ascii. | |||
1923 | outs() << " "; | |||
1924 | for (std::size_t I = 0; I < 16 && Addr + I < End; ++I) { | |||
1925 | if (isPrint(static_cast<unsigned char>(Contents[Addr + I]) & 0xFF)) | |||
1926 | outs() << Contents[Addr + I]; | |||
1927 | else | |||
1928 | outs() << "."; | |||
1929 | } | |||
1930 | outs() << "\n"; | |||
1931 | } | |||
1932 | } | |||
1933 | } | |||
1934 | ||||
1935 | void objdump::printSymbolTable(const ObjectFile *O, StringRef ArchiveName, | |||
1936 | StringRef ArchitectureName, bool DumpDynamic) { | |||
1937 | if (O->isCOFF() && !DumpDynamic) { | |||
1938 | outs() << "\nSYMBOL TABLE:\n"; | |||
1939 | printCOFFSymbolTable(cast<const COFFObjectFile>(O)); | |||
1940 | return; | |||
1941 | } | |||
1942 | ||||
1943 | const StringRef FileName = O->getFileName(); | |||
1944 | ||||
1945 | if (!DumpDynamic) { | |||
1946 | outs() << "\nSYMBOL TABLE:\n"; | |||
1947 | for (auto I = O->symbol_begin(); I != O->symbol_end(); ++I) | |||
1948 | printSymbol(O, *I, {}, FileName, ArchiveName, ArchitectureName, | |||
1949 | DumpDynamic); | |||
1950 | return; | |||
1951 | } | |||
1952 | ||||
1953 | outs() << "\nDYNAMIC SYMBOL TABLE:\n"; | |||
1954 | if (!O->isELF()) { | |||
1955 | reportWarning( | |||
1956 | "this operation is not currently supported for this file format", | |||
1957 | FileName); | |||
1958 | return; | |||
1959 | } | |||
1960 | ||||
1961 | const ELFObjectFileBase *ELF = cast<const ELFObjectFileBase>(O); | |||
1962 | auto Symbols = ELF->getDynamicSymbolIterators(); | |||
1963 | Expected<std::vector<VersionEntry>> SymbolVersionsOrErr = | |||
1964 | ELF->readDynsymVersions(); | |||
1965 | if (!SymbolVersionsOrErr) { | |||
1966 | reportWarning(toString(SymbolVersionsOrErr.takeError()), FileName); | |||
1967 | SymbolVersionsOrErr = std::vector<VersionEntry>(); | |||
1968 | (void)!SymbolVersionsOrErr; | |||
1969 | } | |||
1970 | for (auto &Sym : Symbols) | |||
1971 | printSymbol(O, Sym, *SymbolVersionsOrErr, FileName, ArchiveName, | |||
1972 | ArchitectureName, DumpDynamic); | |||
1973 | } | |||
1974 | ||||
1975 | void objdump::printSymbol(const ObjectFile *O, const SymbolRef &Symbol, | |||
1976 | ArrayRef<VersionEntry> SymbolVersions, | |||
1977 | StringRef FileName, StringRef ArchiveName, | |||
1978 | StringRef ArchitectureName, bool DumpDynamic) { | |||
1979 | const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(O); | |||
| ||||
1980 | uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName, ArchiveName, | |||
1981 | ArchitectureName); | |||
1982 | if ((Address < StartAddress) || (Address > StopAddress)) | |||
1983 | return; | |||
1984 | SymbolRef::Type Type = | |||
1985 | unwrapOrError(Symbol.getType(), FileName, ArchiveName, ArchitectureName); | |||
1986 | uint32_t Flags = | |||
1987 | unwrapOrError(Symbol.getFlags(), FileName, ArchiveName, ArchitectureName); | |||
1988 | ||||
1989 | // Don't ask a Mach-O STAB symbol for its section unless you know that | |||
1990 | // STAB symbol's section field refers to a valid section index. Otherwise | |||
1991 | // the symbol may error trying to load a section that does not exist. | |||
1992 | bool IsSTAB = false; | |||
1993 | if (MachO
| |||
1994 | DataRefImpl SymDRI = Symbol.getRawDataRefImpl(); | |||
1995 | uint8_t NType = | |||
1996 | (MachO->is64Bit() ? MachO->getSymbol64TableEntry(SymDRI).n_type | |||
1997 | : MachO->getSymbolTableEntry(SymDRI).n_type); | |||
1998 | if (NType & MachO::N_STAB) | |||
1999 | IsSTAB = true; | |||
2000 | } | |||
2001 | section_iterator Section = IsSTAB |
5.1 | 'IsSTAB' is false |
13.1 | 'Type' is not equal to ST_Debug |
15.1 | 'Type' is not equal to ST_File |
24.1 | 'Absolute' is false |
32 | Called C++ object pointer is null |