2011-01-20 14:39:06 +08:00
|
|
|
//===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This program is a utility that works like binutils "objdump", that is, it
|
|
|
|
// dumps out a plethora of information about an object file depending on the
|
|
|
|
// flags.
|
|
|
|
//
|
2013-02-06 04:27:22 +08:00
|
|
|
// The flags and output of this program should be near identical to those of
|
|
|
|
// binutils objdump.
|
|
|
|
//
|
2011-01-20 14:39:06 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-09-20 01:56:04 +08:00
|
|
|
#include "llvm-objdump.h"
|
2015-06-23 02:03:02 +08:00
|
|
|
#include "llvm/ADT/Optional.h"
|
2012-12-04 18:44:52 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2011-10-18 01:13:22 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2018-03-10 03:13:44 +08:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2011-01-20 14:39:06 +08:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2015-06-24 04:09:03 +08:00
|
|
|
#include "llvm/CodeGen/FaultMaps.h"
|
2016-01-26 23:09:42 +08:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
2016-08-16 03:49:24 +08:00
|
|
|
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
|
2018-07-19 00:39:21 +08:00
|
|
|
#include "llvm/Demangle/Demangle.h"
|
2011-01-20 14:39:06 +08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
Add MCSymbolizer for symbolic/annotated disassembly.
This is a basic first step towards symbolization of disassembled
instructions. This used to be done using externally provided (C API)
callbacks. This patch introduces:
- the MCSymbolizer class, that mimics the same functions that were used
in the X86 and ARM disassemblers to symbolize immediate operands and
to annotate loads based off PC (for things like c string literals).
- the MCExternalSymbolizer class, which implements the old C API.
- the MCRelocationInfo class, which provides a way for targets to
translate relocations (either object::RelocationRef, or disassembler
C API VariantKinds) to MCExprs.
- the MCObjectSymbolizer class, which does symbolization using what it
finds in an object::ObjectFile. This makes simple symbolization (with
no fancy relocation stuff) work for all object formats!
- x86-64 Mach-O and ELF MCRelocationInfos.
- A basic ARM Mach-O MCRelocationInfo, that provides just enough to
support the C API VariantKinds.
Most of what works in otool (the only user of the old symbolization API
that I know of) for x86-64 symbolic disassembly (-tvV) works, namely:
- symbol references: call _foo; jmp 15 <_foo+50>
- relocations: call _foo-_bar; call _foo-4
- __cf?string: leaq 193(%rip), %rax ## literal pool for "hello"
Stub support is the main missing part (because libObject doesn't know,
among other things, about mach-o indirect symbols).
As for the MCSymbolizer API, instead of relying on the disassemblers
to call the tryAdding* methods, maybe this could be done automagically
using InstrInfo? For instance, even though PC-relative LEAs are used
to get the address of string literals in a typical Mach-O file, a MOV
would be used in an ELF file. And right now, the explicit symbolization
only recognizes PC-relative LEAs. InstrInfo should have already have
most of what is needed to know what to symbolize, so this can
definitely be improved.
I'd also like to remove object::RelocationRef::getValueString (it seems
only used by relocation printing in objdump), as simply printing the
created MCExpr is definitely enough (and cleaner than string concats).
llvm-svn: 182625
2013-05-24 08:39:57 +08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2016-01-27 00:44:37 +08:00
|
|
|
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
|
|
|
|
#include "llvm/MC/MCDisassembler/MCRelocationInfo.h"
|
2011-01-20 14:39:06 +08:00
|
|
|
#include "llvm/MC/MCInst.h"
|
|
|
|
#include "llvm/MC/MCInstPrinter.h"
|
MC: Disassembled CFG reconstruction.
This patch builds on some existing code to do CFG reconstruction from
a disassembled binary:
- MCModule represents the binary, and has a list of MCAtoms.
- MCAtom represents either disassembled instructions (MCTextAtom), or
contiguous data (MCDataAtom), and covers a specific range of addresses.
- MCBasicBlock and MCFunction form the reconstructed CFG. An MCBB is
backed by an MCTextAtom, and has the usual successors/predecessors.
- MCObjectDisassembler creates a module from an ObjectFile using a
disassembler. It first builds an atom for each section. It can also
construct the CFG, and this splits the text atoms into basic blocks.
MCModule and MCAtom were only sketched out; MCFunction and MCBB were
implemented under the experimental "-cfg" llvm-objdump -macho option.
This cleans them up for further use; llvm-objdump -d -cfg now generates
graphviz files for each function found in the binary.
In the future, MCObjectDisassembler may be the right place to do
"intelligent" disassembly: for example, handling constant islands is just
a matter of splitting the atom, using information that may be available
in the ObjectFile. Also, better initial atom formation than just using
sections is possible using symbols (and things like Mach-O's
function_starts load command).
This brings two minor regressions in llvm-objdump -macho -cfg:
- The printing of a relocation's referenced symbol.
- An annotation on loop BBs, i.e., which are their own successor.
Relocation printing is replaced by the MCSymbolizer; the basic CFG
annotation will be superseded by more related functionality.
llvm-svn: 182628
2013-05-24 09:07:04 +08:00
|
|
|
#include "llvm/MC/MCInstrAnalysis.h"
|
2012-04-02 14:09:36 +08:00
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
Add MCSymbolizer for symbolic/annotated disassembly.
This is a basic first step towards symbolization of disassembled
instructions. This used to be done using externally provided (C API)
callbacks. This patch introduces:
- the MCSymbolizer class, that mimics the same functions that were used
in the X86 and ARM disassemblers to symbolize immediate operands and
to annotate loads based off PC (for things like c string literals).
- the MCExternalSymbolizer class, which implements the old C API.
- the MCRelocationInfo class, which provides a way for targets to
translate relocations (either object::RelocationRef, or disassembler
C API VariantKinds) to MCExprs.
- the MCObjectSymbolizer class, which does symbolization using what it
finds in an object::ObjectFile. This makes simple symbolization (with
no fancy relocation stuff) work for all object formats!
- x86-64 Mach-O and ELF MCRelocationInfos.
- A basic ARM Mach-O MCRelocationInfo, that provides just enough to
support the C API VariantKinds.
Most of what works in otool (the only user of the old symbolization API
that I know of) for x86-64 symbolic disassembly (-tvV) works, namely:
- symbol references: call _foo; jmp 15 <_foo+50>
- relocations: call _foo-_bar; call _foo-4
- __cf?string: leaq 193(%rip), %rax ## literal pool for "hello"
Stub support is the main missing part (because libObject doesn't know,
among other things, about mach-o indirect symbols).
As for the MCSymbolizer API, instead of relying on the disassemblers
to call the tryAdding* methods, maybe this could be done automagically
using InstrInfo? For instance, even though PC-relative LEAs are used
to get the address of string literals in a typical Mach-O file, a MOV
would be used in an ELF file. And right now, the explicit symbolization
only recognizes PC-relative LEAs. InstrInfo should have already have
most of what is needed to know what to symbolize, so this can
definitely be improved.
I'd also like to remove object::RelocationRef::getValueString (it seems
only used by relocation printing in objdump), as simply printing the
created MCExpr is definitely enough (and cleaner than string concats).
llvm-svn: 182625
2013-05-24 08:39:57 +08:00
|
|
|
#include "llvm/MC/MCObjectFileInfo.h"
|
2012-03-06 03:33:20 +08:00
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
MC: Disassembled CFG reconstruction.
This patch builds on some existing code to do CFG reconstruction from
a disassembled binary:
- MCModule represents the binary, and has a list of MCAtoms.
- MCAtom represents either disassembled instructions (MCTextAtom), or
contiguous data (MCDataAtom), and covers a specific range of addresses.
- MCBasicBlock and MCFunction form the reconstructed CFG. An MCBB is
backed by an MCTextAtom, and has the usual successors/predecessors.
- MCObjectDisassembler creates a module from an ObjectFile using a
disassembler. It first builds an atom for each section. It can also
construct the CFG, and this splits the text atoms into basic blocks.
MCModule and MCAtom were only sketched out; MCFunction and MCBB were
implemented under the experimental "-cfg" llvm-objdump -macho option.
This cleans them up for further use; llvm-objdump -d -cfg now generates
graphviz files for each function found in the binary.
In the future, MCObjectDisassembler may be the right place to do
"intelligent" disassembly: for example, handling constant islands is just
a matter of splitting the atom, using information that may be available
in the ObjectFile. Also, better initial atom formation than just using
sections is possible using symbols (and things like Mach-O's
function_starts load command).
This brings two minor regressions in llvm-objdump -macho -cfg:
- The printing of a relocation's referenced symbol.
- An annotation on loop BBs, i.e., which are their own successor.
Relocation printing is replaced by the MCSymbolizer; the basic CFG
annotation will be superseded by more related functionality.
llvm-svn: 182628
2013-05-24 09:07:04 +08:00
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2012-12-04 18:44:52 +08:00
|
|
|
#include "llvm/Object/Archive.h"
|
|
|
|
#include "llvm/Object/COFF.h"
|
2016-08-19 00:39:19 +08:00
|
|
|
#include "llvm/Object/COFFImportFile.h"
|
2016-01-27 00:44:37 +08:00
|
|
|
#include "llvm/Object/ELFObjectFile.h"
|
Add a function to get the segment name of a section.
On MachO, sections also have segment names. When a tool looking at a .o file
prints a segment name, this is what they mean. In reality, a .o has only one
anonymous, segment.
This patch adds a MachO only function to fetch that segment name. I named it
getSectionFinalSegmentName since the main use for the name seems to be inform
the linker with segment this section should go to.
The patch also changes MachOObjectFile::getSectionName to return just the
section name instead of computing SegmentName,SectionName.
The main difference from the previous patch is that it doesn't use
InMemoryStruct. It is extremely dangerous: if the endians match it returns
a pointer to the file buffer, if not, it returns a pointer to an internal buffer
that is overwritten in the next API call.
We should change all of this code to use
support::detail::packed_endian_specific_integral like ELF, but since these
functions only handle strings, they work with big and little endian machines
as is.
I have tested this by installing ubuntu 12.10 ppc on qemu, that is why it took
so long :-)
llvm-svn: 170838
2012-12-21 11:47:03 +08:00
|
|
|
#include "llvm/Object/MachO.h"
|
2018-08-03 08:06:38 +08:00
|
|
|
#include "llvm/Object/MachOUniversal.h"
|
2012-12-04 18:44:52 +08:00
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2017-06-28 04:40:53 +08:00
|
|
|
#include "llvm/Object/Wasm.h"
|
2011-10-08 08:18:30 +08:00
|
|
|
#include "llvm/Support/Casting.h"
|
2011-01-20 14:39:06 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
2015-06-05 02:34:11 +08:00
|
|
|
#include "llvm/Support/Errc.h"
|
2011-10-08 08:18:30 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2011-01-20 14:39:06 +08:00
|
|
|
#include "llvm/Support/Format.h"
|
2011-07-26 07:04:36 +08:00
|
|
|
#include "llvm/Support/GraphWriter.h"
|
2011-01-20 14:39:06 +08:00
|
|
|
#include "llvm/Support/Host.h"
|
2018-04-14 02:26:06 +08:00
|
|
|
#include "llvm/Support/InitLLVM.h"
|
2011-01-20 14:39:06 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2018-08-24 23:21:57 +08:00
|
|
|
#include "llvm/Support/StringSaver.h"
|
2011-08-25 02:08:43 +08:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2011-01-20 14:39:06 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <algorithm>
|
2012-03-23 19:49:32 +08:00
|
|
|
#include <cctype>
|
2011-01-20 14:39:06 +08:00
|
|
|
#include <cstring>
|
2014-06-13 01:38:55 +08:00
|
|
|
#include <system_error>
|
2016-08-16 03:49:24 +08:00
|
|
|
#include <unordered_map>
|
2017-07-20 06:27:28 +08:00
|
|
|
#include <utility>
|
MC CFG: Add YAML MCModule representation to enable MC CFG testing.
Like yaml ObjectFiles, this will be very useful for testing the MC CFG
implementation (mostly MCObjectDisassembler), by matching the output
with YAML, and for potential users of the MC CFG, by using it as an input.
There isn't much to the actual format, it is just a serialization of the
MCModule class. Of note:
- Basic block references (pred/succ, ..) are represented by the BB's
start address.
- Just as in the MC CFG, instructions are MCInsts with a size.
- Operands have a prefix representing the type (only register and
immediate supported here).
- Instruction opcodes are represented by their names; enum values aren't
stable, enum names mostly are: usually, a change to a name would need
lots of changes in the backend anyway.
Same with registers.
All in all, an example is better than 1000 words, here goes:
A simple binary:
Disassembly of section __TEXT,__text:
_main:
100000f9c: 48 8b 46 08 movq 8(%rsi), %rax
100000fa0: 0f be 00 movsbl (%rax), %eax
100000fa3: 3b 04 25 48 00 00 00 cmpl 72, %eax
100000faa: 0f 8c 07 00 00 00 jl 7 <.Lend>
100000fb0: 2b 04 25 48 00 00 00 subl 72, %eax
.Lend:
100000fb7: c3 ret
And the (pretty verbose) generated YAML:
---
Atoms:
- StartAddress: 0x0000000100000F9C
Size: 20
Type: Text
Content:
- Inst: MOV64rm
Size: 4
Ops: [ RRAX, RRSI, I1, R, I8, R ]
- Inst: MOVSX32rm8
Size: 3
Ops: [ REAX, RRAX, I1, R, I0, R ]
- Inst: CMP32rm
Size: 7
Ops: [ REAX, R, I1, R, I72, R ]
- Inst: JL_4
Size: 6
Ops: [ I7 ]
- StartAddress: 0x0000000100000FB0
Size: 7
Type: Text
Content:
- Inst: SUB32rm
Size: 7
Ops: [ REAX, REAX, R, I1, R, I72, R ]
- StartAddress: 0x0000000100000FB7
Size: 1
Type: Text
Content:
- Inst: RET
Size: 1
Ops: [ ]
Functions:
- Name: __text
BasicBlocks:
- Address: 0x0000000100000F9C
Preds: [ ]
Succs: [ 0x0000000100000FB7, 0x0000000100000FB0 ]
<snip>
...
llvm-svn: 188890
2013-08-21 15:29:02 +08:00
|
|
|
|
2011-01-20 14:39:06 +08:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace object;
|
|
|
|
|
2018-06-28 04:45:11 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::AllHeaders("all-headers",
|
|
|
|
cl::desc("Display all available header information"));
|
|
|
|
static cl::alias AllHeadersShort("x", cl::desc("Alias for --all-headers"),
|
|
|
|
cl::aliasopt(AllHeaders));
|
|
|
|
|
2011-09-20 01:56:04 +08:00
|
|
|
static cl::list<std::string>
|
|
|
|
InputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore);
|
2011-01-20 14:39:06 +08:00
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::Disassemble("disassemble",
|
2011-09-20 01:56:04 +08:00
|
|
|
cl::desc("Display assembler mnemonics for the machine instructions"));
|
|
|
|
static cl::alias
|
|
|
|
Disassembled("d", cl::desc("Alias for --disassemble"),
|
2015-07-29 23:45:39 +08:00
|
|
|
cl::aliasopt(Disassemble));
|
|
|
|
|
|
|
|
cl::opt<bool>
|
|
|
|
llvm::DisassembleAll("disassemble-all",
|
|
|
|
cl::desc("Display assembler mnemonics for the machine instructions"));
|
|
|
|
static cl::alias
|
|
|
|
DisassembleAlld("D", cl::desc("Alias for --disassemble-all"),
|
2015-07-24 04:58:49 +08:00
|
|
|
cl::aliasopt(DisassembleAll));
|
2011-01-20 14:39:06 +08:00
|
|
|
|
2018-08-21 06:18:21 +08:00
|
|
|
cl::opt<bool> llvm::Demangle("demangle", cl::desc("Demangle symbols names"),
|
|
|
|
cl::init(false));
|
2018-07-19 00:39:21 +08:00
|
|
|
|
|
|
|
static cl::alias DemangleShort("C", cl::desc("Alias for --demangle"),
|
2018-08-21 06:18:21 +08:00
|
|
|
cl::aliasopt(llvm::Demangle));
|
2018-07-19 00:39:21 +08:00
|
|
|
|
2018-03-10 03:13:44 +08:00
|
|
|
static cl::list<std::string>
|
|
|
|
DisassembleFunctions("df",
|
|
|
|
cl::CommaSeparated,
|
|
|
|
cl::desc("List of functions to disassemble"));
|
|
|
|
static StringSet<> DisasmFuncsSet;
|
|
|
|
|
2015-01-21 05:47:46 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::Relocations("r", cl::desc("Display the relocation entries in the file"));
|
2011-10-08 08:18:30 +08:00
|
|
|
|
2018-06-07 21:30:55 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::DynamicRelocations("dynamic-reloc",
|
|
|
|
cl::desc("Display the dynamic relocation entries in the file"));
|
|
|
|
static cl::alias
|
|
|
|
DynamicRelocationsd("R", cl::desc("Alias for --dynamic-reloc"),
|
|
|
|
cl::aliasopt(DynamicRelocations));
|
|
|
|
|
2015-01-21 05:47:46 +08:00
|
|
|
cl::opt<bool>
|
2018-10-29 18:05:39 +08:00
|
|
|
llvm::SectionContents("full-contents",
|
|
|
|
cl::desc("Display the content of each section"));
|
|
|
|
static cl::alias SectionContentsShort("s",
|
|
|
|
cl::desc("Alias for --full-contents"),
|
|
|
|
cl::aliasopt(SectionContents));
|
2011-10-18 01:13:22 +08:00
|
|
|
|
2018-10-31 13:45:01 +08:00
|
|
|
cl::opt<bool> llvm::SymbolTable("syms", cl::desc("Display the symbol table"));
|
|
|
|
static cl::alias SymbolTableShort("t", cl::desc("Alias for --syms"),
|
|
|
|
cl::aliasopt(llvm::SymbolTable));
|
2011-10-19 03:32:17 +08:00
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
|
2014-08-30 08:20:14 +08:00
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::Rebase("rebase", cl::desc("Display mach-o rebasing info"));
|
2014-09-13 05:34:15 +08:00
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::Bind("bind", cl::desc("Display mach-o binding info"));
|
2014-09-16 09:41:51 +08:00
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info"));
|
2014-09-16 09:41:51 +08:00
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::WeakBind("weak-bind", cl::desc("Display mach-o weak binding info"));
|
2014-09-16 09:41:51 +08:00
|
|
|
|
2015-07-08 10:04:15 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::RawClangAST("raw-clang-ast",
|
|
|
|
cl::desc("Dump the raw binary contents of the clang AST section"));
|
|
|
|
|
2011-09-20 01:56:04 +08:00
|
|
|
static cl::opt<bool>
|
Add a function to get the segment name of a section.
On MachO, sections also have segment names. When a tool looking at a .o file
prints a segment name, this is what they mean. In reality, a .o has only one
anonymous, segment.
This patch adds a MachO only function to fetch that segment name. I named it
getSectionFinalSegmentName since the main use for the name seems to be inform
the linker with segment this section should go to.
The patch also changes MachOObjectFile::getSectionName to return just the
section name instead of computing SegmentName,SectionName.
The main difference from the previous patch is that it doesn't use
InMemoryStruct. It is extremely dangerous: if the endians match it returns
a pointer to the file buffer, if not, it returns a pointer to an internal buffer
that is overwritten in the next API call.
We should change all of this code to use
support::detail::packed_endian_specific_integral like ELF, but since these
functions only handle strings, they work with big and little endian machines
as is.
I have tested this by installing ubuntu 12.10 ppc on qemu, that is why it took
so long :-)
llvm-svn: 170838
2012-12-21 11:47:03 +08:00
|
|
|
MachOOpt("macho", cl::desc("Use MachO specific object file parser"));
|
2011-09-20 01:56:04 +08:00
|
|
|
static cl::alias
|
Add a function to get the segment name of a section.
On MachO, sections also have segment names. When a tool looking at a .o file
prints a segment name, this is what they mean. In reality, a .o has only one
anonymous, segment.
This patch adds a MachO only function to fetch that segment name. I named it
getSectionFinalSegmentName since the main use for the name seems to be inform
the linker with segment this section should go to.
The patch also changes MachOObjectFile::getSectionName to return just the
section name instead of computing SegmentName,SectionName.
The main difference from the previous patch is that it doesn't use
InMemoryStruct. It is extremely dangerous: if the endians match it returns
a pointer to the file buffer, if not, it returns a pointer to an internal buffer
that is overwritten in the next API call.
We should change all of this code to use
support::detail::packed_endian_specific_integral like ELF, but since these
functions only handle strings, they work with big and little endian machines
as is.
I have tested this by installing ubuntu 12.10 ppc on qemu, that is why it took
so long :-)
llvm-svn: 170838
2012-12-21 11:47:03 +08:00
|
|
|
MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachOOpt));
|
2011-07-21 03:37:35 +08:00
|
|
|
|
2011-09-20 01:56:04 +08:00
|
|
|
cl::opt<std::string>
|
|
|
|
llvm::TripleName("triple", cl::desc("Target triple to disassemble for, "
|
|
|
|
"see -version for available targets"));
|
2011-01-20 14:39:06 +08:00
|
|
|
|
2014-08-07 07:24:41 +08:00
|
|
|
cl::opt<std::string>
|
|
|
|
llvm::MCPU("mcpu",
|
|
|
|
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
|
|
|
cl::value_desc("cpu-name"),
|
|
|
|
cl::init(""));
|
|
|
|
|
2011-09-20 01:56:04 +08:00
|
|
|
cl::opt<std::string>
|
2014-12-05 07:56:27 +08:00
|
|
|
llvm::ArchName("arch-name", cl::desc("Target arch to disassemble for, "
|
2011-09-20 01:56:04 +08:00
|
|
|
"see -version for available targets"));
|
2011-01-20 14:39:06 +08:00
|
|
|
|
2015-01-21 05:47:46 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::SectionHeaders("section-headers", cl::desc("Display summaries of the "
|
|
|
|
"headers for each section."));
|
2011-10-11 05:21:34 +08:00
|
|
|
static cl::alias
|
|
|
|
SectionHeadersShort("headers", cl::desc("Alias for --section-headers"),
|
|
|
|
cl::aliasopt(SectionHeaders));
|
|
|
|
static cl::alias
|
|
|
|
SectionHeadersShorter("h", cl::desc("Alias for --section-headers"),
|
|
|
|
cl::aliasopt(SectionHeaders));
|
2015-07-30 03:08:10 +08:00
|
|
|
|
2015-07-29 23:45:39 +08:00
|
|
|
cl::list<std::string>
|
2015-07-30 03:08:10 +08:00
|
|
|
llvm::FilterSections("section", cl::desc("Operate on the specified sections only. "
|
|
|
|
"With -macho dump segment,section"));
|
|
|
|
cl::alias
|
|
|
|
static FilterSectionsj("j", cl::desc("Alias for --section"),
|
|
|
|
cl::aliasopt(llvm::FilterSections));
|
2011-10-11 05:21:34 +08:00
|
|
|
|
2014-08-07 07:24:41 +08:00
|
|
|
cl::list<std::string>
|
|
|
|
llvm::MAttrs("mattr",
|
2012-08-29 03:24:49 +08:00
|
|
|
cl::CommaSeparated,
|
|
|
|
cl::desc("Target specific attributes"),
|
|
|
|
cl::value_desc("a1,+a2,-a3,..."));
|
|
|
|
|
2014-09-25 07:08:22 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling "
|
|
|
|
"instructions, do not print "
|
|
|
|
"the instruction bytes."));
|
2017-02-09 02:11:31 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::NoLeadingAddr("no-leading-addr", cl::desc("Print no leading address"));
|
2012-11-21 06:57:02 +08:00
|
|
|
|
2015-01-21 05:47:46 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information"));
|
2012-12-06 04:12:35 +08:00
|
|
|
|
|
|
|
static cl::alias
|
|
|
|
UnwindInfoShort("u", cl::desc("Alias for --unwind-info"),
|
|
|
|
cl::aliasopt(UnwindInfo));
|
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::PrivateHeaders("private-headers",
|
|
|
|
cl::desc("Display format specific file headers"));
|
2013-01-06 11:56:49 +08:00
|
|
|
|
2016-01-13 08:25:36 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::FirstPrivateHeader("private-header",
|
|
|
|
cl::desc("Display only the first format specific file "
|
|
|
|
"header"));
|
|
|
|
|
2013-01-06 11:56:49 +08:00
|
|
|
static cl::alias
|
|
|
|
PrivateHeadersShort("p", cl::desc("Alias for --private-headers"),
|
|
|
|
cl::aliasopt(PrivateHeaders));
|
|
|
|
|
2018-07-04 23:25:03 +08:00
|
|
|
cl::opt<bool> llvm::FileHeaders(
|
|
|
|
"file-headers",
|
|
|
|
cl::desc("Display the contents of the overall file header"));
|
|
|
|
|
|
|
|
static cl::alias FileHeadersShort("f", cl::desc("Alias for --file-headers"),
|
|
|
|
cl::aliasopt(FileHeaders));
|
|
|
|
|
2018-07-05 22:43:29 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::ArchiveHeaders("archive-headers",
|
|
|
|
cl::desc("Display archive header information"));
|
|
|
|
|
|
|
|
cl::alias
|
|
|
|
ArchiveHeadersShort("a", cl::desc("Alias for --archive-headers"),
|
|
|
|
cl::aliasopt(ArchiveHeaders));
|
|
|
|
|
2015-06-08 05:07:17 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::PrintImmHex("print-imm-hex",
|
2016-04-09 02:15:37 +08:00
|
|
|
cl::desc("Use hex format for immediate values"));
|
2015-06-08 05:07:17 +08:00
|
|
|
|
2015-06-23 02:03:02 +08:00
|
|
|
cl::opt<bool> PrintFaultMaps("fault-map-section",
|
|
|
|
cl::desc("Display contents of faultmap section"));
|
|
|
|
|
2016-01-26 23:09:42 +08:00
|
|
|
cl::opt<DIDumpType> llvm::DwarfDumpType(
|
|
|
|
"dwarf", cl::init(DIDT_Null), cl::desc("Dump of dwarf debug sections:"),
|
2017-09-18 22:15:57 +08:00
|
|
|
cl::values(clEnumValN(DIDT_DebugFrame, "frames", ".debug_frame")));
|
2016-01-26 23:09:42 +08:00
|
|
|
|
2016-08-16 03:49:24 +08:00
|
|
|
cl::opt<bool> PrintSource(
|
|
|
|
"source",
|
|
|
|
cl::desc(
|
2018-02-03 03:20:37 +08:00
|
|
|
"Display source inlined with disassembly. Implies disassemble object"));
|
2016-08-16 03:49:24 +08:00
|
|
|
|
|
|
|
cl::alias PrintSourceShort("S", cl::desc("Alias for -source"),
|
|
|
|
cl::aliasopt(PrintSource));
|
|
|
|
|
|
|
|
cl::opt<bool> PrintLines("line-numbers",
|
|
|
|
cl::desc("Display source line numbers with "
|
|
|
|
"disassembly. Implies disassemble object"));
|
|
|
|
|
|
|
|
cl::alias PrintLinesShort("l", cl::desc("Alias for -line-numbers"),
|
|
|
|
cl::aliasopt(PrintLines));
|
2016-09-13 01:08:22 +08:00
|
|
|
|
|
|
|
cl::opt<unsigned long long>
|
|
|
|
StartAddress("start-address", cl::desc("Disassemble beginning at address"),
|
|
|
|
cl::value_desc("address"), cl::init(0));
|
|
|
|
cl::opt<unsigned long long>
|
|
|
|
StopAddress("stop-address", cl::desc("Stop disassembly at address"),
|
|
|
|
cl::value_desc("address"), cl::init(UINT64_MAX));
|
2011-09-20 01:56:04 +08:00
|
|
|
static StringRef ToolName;
|
2011-06-26 01:55:23 +08:00
|
|
|
|
2017-02-08 17:44:18 +08:00
|
|
|
typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy;
|
|
|
|
|
2015-07-29 23:45:39 +08:00
|
|
|
namespace {
|
2015-07-30 03:08:10 +08:00
|
|
|
typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate;
|
2015-07-29 23:45:39 +08:00
|
|
|
|
|
|
|
class SectionFilterIterator {
|
|
|
|
public:
|
|
|
|
SectionFilterIterator(FilterPredicate P,
|
|
|
|
llvm::object::section_iterator const &I,
|
|
|
|
llvm::object::section_iterator const &E)
|
2016-05-27 22:27:24 +08:00
|
|
|
: Predicate(std::move(P)), Iterator(I), End(E) {
|
2015-07-29 23:45:39 +08:00
|
|
|
ScanPredicate();
|
|
|
|
}
|
2015-09-24 22:52:52 +08:00
|
|
|
const llvm::object::SectionRef &operator*() const { return *Iterator; }
|
2015-07-29 23:45:39 +08:00
|
|
|
SectionFilterIterator &operator++() {
|
|
|
|
++Iterator;
|
|
|
|
ScanPredicate();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
bool operator!=(SectionFilterIterator const &Other) const {
|
|
|
|
return Iterator != Other.Iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void ScanPredicate() {
|
2015-07-30 03:21:13 +08:00
|
|
|
while (Iterator != End && !Predicate(*Iterator)) {
|
2015-07-29 23:45:39 +08:00
|
|
|
++Iterator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FilterPredicate Predicate;
|
|
|
|
llvm::object::section_iterator Iterator;
|
|
|
|
llvm::object::section_iterator End;
|
|
|
|
};
|
|
|
|
|
|
|
|
class SectionFilter {
|
|
|
|
public:
|
|
|
|
SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O)
|
2016-05-27 22:27:24 +08:00
|
|
|
: Predicate(std::move(P)), Object(O) {}
|
2015-07-29 23:45:39 +08:00
|
|
|
SectionFilterIterator begin() {
|
|
|
|
return SectionFilterIterator(Predicate, Object.section_begin(),
|
|
|
|
Object.section_end());
|
|
|
|
}
|
|
|
|
SectionFilterIterator end() {
|
|
|
|
return SectionFilterIterator(Predicate, Object.section_end(),
|
|
|
|
Object.section_end());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
FilterPredicate Predicate;
|
|
|
|
llvm::object::ObjectFile const &Object;
|
|
|
|
};
|
|
|
|
SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O) {
|
2016-08-12 11:55:06 +08:00
|
|
|
return SectionFilter(
|
|
|
|
[](llvm::object::SectionRef const &S) {
|
|
|
|
if (FilterSections.empty())
|
|
|
|
return true;
|
|
|
|
llvm::StringRef String;
|
|
|
|
std::error_code error = S.getName(String);
|
|
|
|
if (error)
|
|
|
|
return false;
|
|
|
|
return is_contained(FilterSections, String);
|
|
|
|
},
|
|
|
|
O);
|
2015-07-29 23:45:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-05 15:18:31 +08:00
|
|
|
void llvm::error(std::error_code EC) {
|
2014-01-25 08:32:01 +08:00
|
|
|
if (!EC)
|
2015-08-05 15:18:31 +08:00
|
|
|
return;
|
2011-06-26 01:55:23 +08:00
|
|
|
|
2015-12-26 02:16:45 +08:00
|
|
|
errs() << ToolName << ": error reading file: " << EC.message() << ".\n";
|
|
|
|
errs().flush();
|
2015-08-06 08:18:52 +08:00
|
|
|
exit(1);
|
2011-01-20 14:39:06 +08:00
|
|
|
}
|
|
|
|
|
2016-06-29 07:16:13 +08:00
|
|
|
LLVM_ATTRIBUTE_NORETURN void llvm::error(Twine Message) {
|
|
|
|
errs() << ToolName << ": " << Message << ".\n";
|
|
|
|
errs().flush();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2018-07-19 00:39:21 +08:00
|
|
|
void llvm::warn(StringRef Message) {
|
|
|
|
errs() << ToolName << ": warning: " << Message << ".\n";
|
|
|
|
errs().flush();
|
|
|
|
}
|
|
|
|
|
2016-11-17 06:17:38 +08:00
|
|
|
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
|
|
|
|
Twine Message) {
|
|
|
|
errs() << ToolName << ": '" << File << "': " << Message << ".\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2015-12-29 21:41:02 +08:00
|
|
|
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
|
|
|
|
std::error_code EC) {
|
2015-06-05 02:34:11 +08:00
|
|
|
assert(EC);
|
|
|
|
errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n";
|
2015-08-05 15:18:31 +08:00
|
|
|
exit(1);
|
2015-06-05 02:34:11 +08:00
|
|
|
}
|
|
|
|
|
2016-04-07 06:14:09 +08:00
|
|
|
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef File,
|
|
|
|
llvm::Error E) {
|
|
|
|
assert(E);
|
|
|
|
std::string Buf;
|
|
|
|
raw_string_ostream OS(Buf);
|
|
|
|
logAllUnhandledErrors(std::move(E), OS, "");
|
|
|
|
OS.flush();
|
2016-05-06 01:43:35 +08:00
|
|
|
errs() << ToolName << ": '" << File << "': " << Buf;
|
2016-04-07 06:14:09 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2016-05-18 01:10:12 +08:00
|
|
|
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName,
|
|
|
|
StringRef FileName,
|
2016-06-01 04:35:34 +08:00
|
|
|
llvm::Error E,
|
|
|
|
StringRef ArchitectureName) {
|
2016-05-18 01:10:12 +08:00
|
|
|
assert(E);
|
|
|
|
errs() << ToolName << ": ";
|
|
|
|
if (ArchiveName != "")
|
|
|
|
errs() << ArchiveName << "(" << FileName << ")";
|
|
|
|
else
|
2016-10-27 06:37:52 +08:00
|
|
|
errs() << "'" << FileName << "'";
|
2016-06-01 04:35:34 +08:00
|
|
|
if (!ArchitectureName.empty())
|
|
|
|
errs() << " (for architecture " << ArchitectureName << ")";
|
2016-05-18 01:10:12 +08:00
|
|
|
std::string Buf;
|
|
|
|
raw_string_ostream OS(Buf);
|
|
|
|
logAllUnhandledErrors(std::move(E), OS, "");
|
|
|
|
OS.flush();
|
2016-10-27 06:37:52 +08:00
|
|
|
errs() << ": " << Buf;
|
2016-05-18 01:10:12 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
LLVM_ATTRIBUTE_NORETURN void llvm::report_error(StringRef ArchiveName,
|
|
|
|
const object::Archive::Child &C,
|
2016-06-01 04:35:34 +08:00
|
|
|
llvm::Error E,
|
|
|
|
StringRef ArchitectureName) {
|
2016-07-30 01:44:13 +08:00
|
|
|
Expected<StringRef> NameOrErr = C.getName();
|
2016-05-18 01:10:12 +08:00
|
|
|
// TODO: if we have a error getting the name then it would be nice to print
|
|
|
|
// the index of which archive member this is and or its offset in the
|
|
|
|
// archive instead of "???" as the name.
|
2016-07-30 01:44:13 +08:00
|
|
|
if (!NameOrErr) {
|
|
|
|
consumeError(NameOrErr.takeError());
|
2016-06-01 04:35:34 +08:00
|
|
|
llvm::report_error(ArchiveName, "???", std::move(E), ArchitectureName);
|
2016-07-30 01:44:13 +08:00
|
|
|
} else
|
2016-06-01 04:35:34 +08:00
|
|
|
llvm::report_error(ArchiveName, NameOrErr.get(), std::move(E),
|
|
|
|
ArchitectureName);
|
2016-05-18 01:10:12 +08:00
|
|
|
}
|
|
|
|
|
2014-04-25 12:24:47 +08:00
|
|
|
static const Target *getTarget(const ObjectFile *Obj = nullptr) {
|
2011-01-20 14:39:06 +08:00
|
|
|
// Figure out the target triple.
|
2012-05-09 07:38:45 +08:00
|
|
|
llvm::Triple TheTriple("unknown-unknown-unknown");
|
2011-01-20 15:22:04 +08:00
|
|
|
if (TripleName.empty()) {
|
Add MCSymbolizer for symbolic/annotated disassembly.
This is a basic first step towards symbolization of disassembled
instructions. This used to be done using externally provided (C API)
callbacks. This patch introduces:
- the MCSymbolizer class, that mimics the same functions that were used
in the X86 and ARM disassemblers to symbolize immediate operands and
to annotate loads based off PC (for things like c string literals).
- the MCExternalSymbolizer class, which implements the old C API.
- the MCRelocationInfo class, which provides a way for targets to
translate relocations (either object::RelocationRef, or disassembler
C API VariantKinds) to MCExprs.
- the MCObjectSymbolizer class, which does symbolization using what it
finds in an object::ObjectFile. This makes simple symbolization (with
no fancy relocation stuff) work for all object formats!
- x86-64 Mach-O and ELF MCRelocationInfos.
- A basic ARM Mach-O MCRelocationInfo, that provides just enough to
support the C API VariantKinds.
Most of what works in otool (the only user of the old symbolization API
that I know of) for x86-64 symbolic disassembly (-tvV) works, namely:
- symbol references: call _foo; jmp 15 <_foo+50>
- relocations: call _foo-_bar; call _foo-4
- __cf?string: leaq 193(%rip), %rax ## literal pool for "hello"
Stub support is the main missing part (because libObject doesn't know,
among other things, about mach-o indirect symbols).
As for the MCSymbolizer API, instead of relying on the disassemblers
to call the tryAdding* methods, maybe this could be done automagically
using InstrInfo? For instance, even though PC-relative LEAs are used
to get the address of string literals in a typical Mach-O file, a MOV
would be used in an ELF file. And right now, the explicit symbolization
only recognizes PC-relative LEAs. InstrInfo should have already have
most of what is needed to know what to symbolize, so this can
definitely be improved.
I'd also like to remove object::RelocationRef::getValueString (it seems
only used by relocation printing in objdump), as simply printing the
created MCExpr is definitely enough (and cleaner than string concats).
llvm-svn: 182625
2013-05-24 08:39:57 +08:00
|
|
|
if (Obj) {
|
2017-09-19 10:22:48 +08:00
|
|
|
TheTriple = Obj->makeTriple();
|
Add MCSymbolizer for symbolic/annotated disassembly.
This is a basic first step towards symbolization of disassembled
instructions. This used to be done using externally provided (C API)
callbacks. This patch introduces:
- the MCSymbolizer class, that mimics the same functions that were used
in the X86 and ARM disassemblers to symbolize immediate operands and
to annotate loads based off PC (for things like c string literals).
- the MCExternalSymbolizer class, which implements the old C API.
- the MCRelocationInfo class, which provides a way for targets to
translate relocations (either object::RelocationRef, or disassembler
C API VariantKinds) to MCExprs.
- the MCObjectSymbolizer class, which does symbolization using what it
finds in an object::ObjectFile. This makes simple symbolization (with
no fancy relocation stuff) work for all object formats!
- x86-64 Mach-O and ELF MCRelocationInfos.
- A basic ARM Mach-O MCRelocationInfo, that provides just enough to
support the C API VariantKinds.
Most of what works in otool (the only user of the old symbolization API
that I know of) for x86-64 symbolic disassembly (-tvV) works, namely:
- symbol references: call _foo; jmp 15 <_foo+50>
- relocations: call _foo-_bar; call _foo-4
- __cf?string: leaq 193(%rip), %rax ## literal pool for "hello"
Stub support is the main missing part (because libObject doesn't know,
among other things, about mach-o indirect symbols).
As for the MCSymbolizer API, instead of relying on the disassemblers
to call the tryAdding* methods, maybe this could be done automagically
using InstrInfo? For instance, even though PC-relative LEAs are used
to get the address of string literals in a typical Mach-O file, a MOV
would be used in an ELF file. And right now, the explicit symbolization
only recognizes PC-relative LEAs. InstrInfo should have already have
most of what is needed to know what to symbolize, so this can
definitely be improved.
I'd also like to remove object::RelocationRef::getValueString (it seems
only used by relocation printing in objdump), as simply printing the
created MCExpr is definitely enough (and cleaner than string concats).
llvm-svn: 182625
2013-05-24 08:39:57 +08:00
|
|
|
}
|
2017-01-18 21:52:12 +08:00
|
|
|
} else {
|
2012-05-09 07:38:45 +08:00
|
|
|
TheTriple.setTriple(Triple::normalize(TripleName));
|
2017-09-19 10:22:48 +08:00
|
|
|
|
2017-01-18 21:52:12 +08:00
|
|
|
// Use the triple, but also try to combine with ARM build attributes.
|
|
|
|
if (Obj) {
|
|
|
|
auto Arch = Obj->getArch();
|
|
|
|
if (Arch == Triple::arm || Arch == Triple::armeb) {
|
|
|
|
Obj->setARMSubArch(TheTriple);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-01-20 14:39:06 +08:00
|
|
|
|
|
|
|
// Get the target specific parser.
|
|
|
|
std::string Error;
|
2012-05-09 07:38:45 +08:00
|
|
|
const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
|
|
|
|
Error);
|
2016-11-17 06:17:38 +08:00
|
|
|
if (!TheTarget) {
|
|
|
|
if (Obj)
|
|
|
|
report_error(Obj->getFileName(), "can't find target: " + Error);
|
|
|
|
else
|
|
|
|
error("can't find target: " + Error);
|
|
|
|
}
|
2012-05-09 07:38:45 +08:00
|
|
|
|
|
|
|
// Update the triple name and return the found target.
|
|
|
|
TripleName = TheTriple.getTriple();
|
|
|
|
return TheTarget;
|
2011-01-20 14:39:06 +08:00
|
|
|
}
|
|
|
|
|
2012-12-06 04:12:35 +08:00
|
|
|
bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) {
|
2015-07-06 23:47:43 +08:00
|
|
|
return a.getOffset() < b.getOffset();
|
2011-10-14 06:17:18 +08:00
|
|
|
}
|
|
|
|
|
2015-06-03 12:48:06 +08:00
|
|
|
template <class ELFT>
|
|
|
|
static std::error_code getRelocationValueString(const ELFObjectFile<ELFT> *Obj,
|
2015-08-11 04:50:40 +08:00
|
|
|
const RelocationRef &RelRef,
|
2015-06-03 12:48:06 +08:00
|
|
|
SmallVectorImpl<char> &Result) {
|
2015-08-11 04:50:40 +08:00
|
|
|
DataRefImpl Rel = RelRef.getRawDataRefImpl();
|
|
|
|
|
2015-06-03 12:48:06 +08:00
|
|
|
typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
|
|
|
|
typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr;
|
2015-07-02 22:21:38 +08:00
|
|
|
typedef typename ELFObjectFile<ELFT>::Elf_Rela Elf_Rela;
|
|
|
|
|
2015-06-03 12:48:06 +08:00
|
|
|
const ELFFile<ELFT> &EF = *Obj->getELFFile();
|
|
|
|
|
2016-11-16 13:10:28 +08:00
|
|
|
auto SecOrErr = EF.getSection(Rel.d.a);
|
|
|
|
if (!SecOrErr)
|
|
|
|
return errorToErrorCode(SecOrErr.takeError());
|
2015-07-01 20:56:27 +08:00
|
|
|
const Elf_Shdr *Sec = *SecOrErr;
|
2016-11-16 13:10:28 +08:00
|
|
|
auto SymTabOrErr = EF.getSection(Sec->sh_link);
|
|
|
|
if (!SymTabOrErr)
|
|
|
|
return errorToErrorCode(SymTabOrErr.takeError());
|
2015-07-01 20:56:27 +08:00
|
|
|
const Elf_Shdr *SymTab = *SymTabOrErr;
|
2015-06-29 20:38:31 +08:00
|
|
|
assert(SymTab->sh_type == ELF::SHT_SYMTAB ||
|
|
|
|
SymTab->sh_type == ELF::SHT_DYNSYM);
|
2016-11-16 13:10:28 +08:00
|
|
|
auto StrTabSec = EF.getSection(SymTab->sh_link);
|
|
|
|
if (!StrTabSec)
|
|
|
|
return errorToErrorCode(StrTabSec.takeError());
|
|
|
|
auto StrTabOrErr = EF.getStringTable(*StrTabSec);
|
|
|
|
if (!StrTabOrErr)
|
|
|
|
return errorToErrorCode(StrTabOrErr.takeError());
|
2015-06-29 22:39:25 +08:00
|
|
|
StringRef StrTab = *StrTabOrErr;
|
2015-06-03 12:48:06 +08:00
|
|
|
int64_t addend = 0;
|
2018-06-07 21:30:55 +08:00
|
|
|
// If there is no Symbol associated with the relocation, we set the undef
|
|
|
|
// boolean value to 'true'. This will prevent us from calling functions that
|
|
|
|
// requires the relocation to be associated with a symbol.
|
|
|
|
bool undef = false;
|
2015-07-01 20:56:27 +08:00
|
|
|
switch (Sec->sh_type) {
|
2015-06-03 12:48:06 +08:00
|
|
|
default:
|
|
|
|
return object_error::parse_failed;
|
|
|
|
case ELF::SHT_REL: {
|
|
|
|
// TODO: Read implicit addend from section data.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ELF::SHT_RELA: {
|
2015-07-02 22:21:38 +08:00
|
|
|
const Elf_Rela *ERela = Obj->getRela(Rel);
|
|
|
|
addend = ERela->r_addend;
|
2018-06-07 21:30:55 +08:00
|
|
|
undef = ERela->getSymbol(false) == 0;
|
2015-06-03 12:48:06 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-06-03 13:14:22 +08:00
|
|
|
StringRef Target;
|
2018-06-07 21:30:55 +08:00
|
|
|
if (!undef) {
|
|
|
|
symbol_iterator SI = RelRef.getSymbol();
|
|
|
|
const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl());
|
|
|
|
if (symb->getType() == ELF::STT_SECTION) {
|
|
|
|
Expected<section_iterator> SymSI = SI->getSection();
|
|
|
|
if (!SymSI)
|
|
|
|
return errorToErrorCode(SymSI.takeError());
|
|
|
|
const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl());
|
|
|
|
auto SecName = EF.getSectionName(SymSec);
|
|
|
|
if (!SecName)
|
|
|
|
return errorToErrorCode(SecName.takeError());
|
|
|
|
Target = *SecName;
|
|
|
|
} else {
|
|
|
|
Expected<StringRef> SymName = symb->getName(StrTab);
|
|
|
|
if (!SymName)
|
|
|
|
return errorToErrorCode(SymName.takeError());
|
|
|
|
Target = *SymName;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
Target = "*ABS*";
|
2018-06-01 13:31:58 +08:00
|
|
|
|
|
|
|
// Default scheme is to print Target, as well as "+ <addend>" for nonzero
|
|
|
|
// addend. Should be acceptable for all normal purposes.
|
|
|
|
std::string fmtbuf;
|
|
|
|
raw_string_ostream fmt(fmtbuf);
|
|
|
|
fmt << Target;
|
|
|
|
if (addend != 0)
|
|
|
|
fmt << (addend < 0 ? "" : "+") << addend;
|
|
|
|
fmt.flush();
|
|
|
|
Result.append(fmtbuf.begin(), fmtbuf.end());
|
2015-06-09 23:20:42 +08:00
|
|
|
return std::error_code();
|
2015-06-03 12:48:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static std::error_code getRelocationValueString(const ELFObjectFileBase *Obj,
|
2015-08-11 04:50:40 +08:00
|
|
|
const RelocationRef &Rel,
|
2015-06-03 12:48:06 +08:00
|
|
|
SmallVectorImpl<char> &Result) {
|
|
|
|
if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj))
|
|
|
|
return getRelocationValueString(ELF32LE, Rel, Result);
|
|
|
|
if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj))
|
|
|
|
return getRelocationValueString(ELF64LE, Rel, Result);
|
|
|
|
if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj))
|
|
|
|
return getRelocationValueString(ELF32BE, Rel, Result);
|
|
|
|
auto *ELF64BE = cast<ELF64BEObjectFile>(Obj);
|
|
|
|
return getRelocationValueString(ELF64BE, Rel, Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::error_code getRelocationValueString(const COFFObjectFile *Obj,
|
|
|
|
const RelocationRef &Rel,
|
|
|
|
SmallVectorImpl<char> &Result) {
|
|
|
|
symbol_iterator SymI = Rel.getSymbol();
|
2016-04-21 05:24:34 +08:00
|
|
|
Expected<StringRef> SymNameOrErr = SymI->getName();
|
|
|
|
if (!SymNameOrErr)
|
|
|
|
return errorToErrorCode(SymNameOrErr.takeError());
|
2015-07-03 04:55:21 +08:00
|
|
|
StringRef SymName = *SymNameOrErr;
|
2015-06-03 12:48:06 +08:00
|
|
|
Result.append(SymName.begin(), SymName.end());
|
2015-06-09 23:20:42 +08:00
|
|
|
return std::error_code();
|
2015-06-03 12:48:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void printRelocationTargetName(const MachOObjectFile *O,
|
|
|
|
const MachO::any_relocation_info &RE,
|
|
|
|
raw_string_ostream &fmt) {
|
|
|
|
bool IsScattered = O->isRelocationScattered(RE);
|
|
|
|
|
|
|
|
// Target of a scattered relocation is an address. In the interest of
|
|
|
|
// generating pretty output, scan through the symbol table looking for a
|
|
|
|
// symbol that aligns with that address. If we find one, print it.
|
|
|
|
// Otherwise, we just print the hex address of the target.
|
|
|
|
if (IsScattered) {
|
|
|
|
uint32_t Val = O->getPlainRelocationSymbolNum(RE);
|
|
|
|
|
|
|
|
for (const SymbolRef &Symbol : O->symbols()) {
|
|
|
|
std::error_code ec;
|
2016-06-25 02:24:42 +08:00
|
|
|
Expected<uint64_t> Addr = Symbol.getAddress();
|
2016-11-17 06:17:38 +08:00
|
|
|
if (!Addr)
|
|
|
|
report_error(O->getFileName(), Addr.takeError());
|
2015-07-04 02:19:00 +08:00
|
|
|
if (*Addr != Val)
|
2015-06-03 12:48:06 +08:00
|
|
|
continue;
|
2016-04-21 05:24:34 +08:00
|
|
|
Expected<StringRef> Name = Symbol.getName();
|
2016-11-17 06:17:38 +08:00
|
|
|
if (!Name)
|
|
|
|
report_error(O->getFileName(), Name.takeError());
|
2015-07-03 04:55:21 +08:00
|
|
|
fmt << *Name;
|
2015-06-03 12:48:06 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we couldn't find a symbol that this relocation refers to, try
|
|
|
|
// to find a section beginning instead.
|
2015-07-29 23:45:39 +08:00
|
|
|
for (const SectionRef &Section : ToolSectionFilter(*O)) {
|
2015-06-03 12:48:06 +08:00
|
|
|
std::error_code ec;
|
|
|
|
|
|
|
|
StringRef Name;
|
|
|
|
uint64_t Addr = Section.getAddress();
|
|
|
|
if (Addr != Val)
|
|
|
|
continue;
|
|
|
|
if ((ec = Section.getName(Name)))
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(O->getFileName(), ec);
|
2015-06-03 12:48:06 +08:00
|
|
|
fmt << Name;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt << format("0x%x", Val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef S;
|
|
|
|
bool isExtern = O->getPlainRelocationExternal(RE);
|
|
|
|
uint64_t Val = O->getPlainRelocationSymbolNum(RE);
|
|
|
|
|
2017-07-14 01:03:02 +08:00
|
|
|
if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) {
|
2017-08-07 20:29:38 +08:00
|
|
|
fmt << format("0x%0" PRIx64, Val);
|
2017-07-14 01:03:02 +08:00
|
|
|
return;
|
|
|
|
} else if (isExtern) {
|
2015-06-03 12:48:06 +08:00
|
|
|
symbol_iterator SI = O->symbol_begin();
|
|
|
|
advance(SI, Val);
|
2016-04-21 05:24:34 +08:00
|
|
|
Expected<StringRef> SOrErr = SI->getName();
|
2016-11-17 06:17:38 +08:00
|
|
|
if (!SOrErr)
|
|
|
|
report_error(O->getFileName(), SOrErr.takeError());
|
2015-08-05 15:18:31 +08:00
|
|
|
S = *SOrErr;
|
2015-06-03 12:48:06 +08:00
|
|
|
} else {
|
|
|
|
section_iterator SI = O->section_begin();
|
|
|
|
// Adjust for the fact that sections are 1-indexed.
|
2017-11-04 05:32:44 +08:00
|
|
|
if (Val == 0) {
|
|
|
|
fmt << "0 (?,?)";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
uint32_t i = Val - 1;
|
|
|
|
while (i != 0 && SI != O->section_end()) {
|
|
|
|
i--;
|
|
|
|
advance(SI, 1);
|
|
|
|
}
|
|
|
|
if (SI == O->section_end())
|
|
|
|
fmt << Val << " (?,?)";
|
|
|
|
else
|
|
|
|
SI->getName(S);
|
2015-06-03 12:48:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fmt << S;
|
|
|
|
}
|
|
|
|
|
2017-06-28 04:40:53 +08:00
|
|
|
static std::error_code getRelocationValueString(const WasmObjectFile *Obj,
|
|
|
|
const RelocationRef &RelRef,
|
|
|
|
SmallVectorImpl<char> &Result) {
|
|
|
|
const wasm::WasmRelocation& Rel = Obj->getWasmRelocation(RelRef);
|
2018-04-27 00:41:51 +08:00
|
|
|
symbol_iterator SI = RelRef.getSymbol();
|
2017-06-28 04:40:53 +08:00
|
|
|
std::string fmtbuf;
|
|
|
|
raw_string_ostream fmt(fmtbuf);
|
2018-04-27 01:05:04 +08:00
|
|
|
if (SI == Obj->symbol_end()) {
|
|
|
|
// Not all wasm relocations have symbols associated with them.
|
|
|
|
// In particular R_WEBASSEMBLY_TYPE_INDEX_LEB.
|
2018-04-27 00:41:51 +08:00
|
|
|
fmt << Rel.Index;
|
|
|
|
} else {
|
2018-04-27 01:05:04 +08:00
|
|
|
Expected<StringRef> SymNameOrErr = SI->getName();
|
|
|
|
if (!SymNameOrErr)
|
|
|
|
return errorToErrorCode(SymNameOrErr.takeError());
|
2018-04-27 00:41:51 +08:00
|
|
|
StringRef SymName = *SymNameOrErr;
|
|
|
|
Result.append(SymName.begin(), SymName.end());
|
|
|
|
}
|
|
|
|
fmt << (Rel.Addend < 0 ? "" : "+") << Rel.Addend;
|
2017-06-28 04:40:53 +08:00
|
|
|
fmt.flush();
|
|
|
|
Result.append(fmtbuf.begin(), fmtbuf.end());
|
|
|
|
return std::error_code();
|
|
|
|
}
|
|
|
|
|
2015-06-03 12:48:06 +08:00
|
|
|
static std::error_code getRelocationValueString(const MachOObjectFile *Obj,
|
|
|
|
const RelocationRef &RelRef,
|
|
|
|
SmallVectorImpl<char> &Result) {
|
|
|
|
DataRefImpl Rel = RelRef.getRawDataRefImpl();
|
|
|
|
MachO::any_relocation_info RE = Obj->getRelocation(Rel);
|
|
|
|
|
|
|
|
unsigned Arch = Obj->getArch();
|
|
|
|
|
|
|
|
std::string fmtbuf;
|
|
|
|
raw_string_ostream fmt(fmtbuf);
|
|
|
|
unsigned Type = Obj->getAnyRelocationType(RE);
|
|
|
|
bool IsPCRel = Obj->getAnyRelocationPCRel(RE);
|
|
|
|
|
|
|
|
// Determine any addends that should be displayed with the relocation.
|
|
|
|
// These require decoding the relocation type, which is triple-specific.
|
|
|
|
|
|
|
|
// X86_64 has entirely custom relocation types.
|
|
|
|
if (Arch == Triple::x86_64) {
|
|
|
|
bool isPCRel = Obj->getAnyRelocationPCRel(RE);
|
|
|
|
|
|
|
|
switch (Type) {
|
|
|
|
case MachO::X86_64_RELOC_GOT_LOAD:
|
|
|
|
case MachO::X86_64_RELOC_GOT: {
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
fmt << "@GOT";
|
|
|
|
if (isPCRel)
|
|
|
|
fmt << "PCREL";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MachO::X86_64_RELOC_SUBTRACTOR: {
|
|
|
|
DataRefImpl RelNext = Rel;
|
|
|
|
Obj->moveRelocationNext(RelNext);
|
|
|
|
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
|
|
|
|
|
|
|
|
// X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type
|
|
|
|
// X86_64_RELOC_UNSIGNED.
|
|
|
|
// NOTE: Scattered relocations don't exist on x86_64.
|
|
|
|
unsigned RType = Obj->getAnyRelocationType(RENext);
|
|
|
|
if (RType != MachO::X86_64_RELOC_UNSIGNED)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after "
|
|
|
|
"X86_64_RELOC_SUBTRACTOR.");
|
2015-06-03 12:48:06 +08:00
|
|
|
|
|
|
|
// The X86_64_RELOC_UNSIGNED contains the minuend symbol;
|
|
|
|
// X86_64_RELOC_SUBTRACTOR contains the subtrahend.
|
|
|
|
printRelocationTargetName(Obj, RENext, fmt);
|
|
|
|
fmt << "-";
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MachO::X86_64_RELOC_TLV:
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
fmt << "@TLV";
|
|
|
|
if (isPCRel)
|
|
|
|
fmt << "P";
|
|
|
|
break;
|
|
|
|
case MachO::X86_64_RELOC_SIGNED_1:
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
fmt << "-1";
|
|
|
|
break;
|
|
|
|
case MachO::X86_64_RELOC_SIGNED_2:
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
fmt << "-2";
|
|
|
|
break;
|
|
|
|
case MachO::X86_64_RELOC_SIGNED_4:
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
fmt << "-4";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// X86 and ARM share some relocation types in common.
|
|
|
|
} else if (Arch == Triple::x86 || Arch == Triple::arm ||
|
|
|
|
Arch == Triple::ppc) {
|
|
|
|
// Generic relocation types...
|
|
|
|
switch (Type) {
|
|
|
|
case MachO::GENERIC_RELOC_PAIR: // prints no info
|
2015-06-09 23:20:42 +08:00
|
|
|
return std::error_code();
|
2015-06-03 12:48:06 +08:00
|
|
|
case MachO::GENERIC_RELOC_SECTDIFF: {
|
|
|
|
DataRefImpl RelNext = Rel;
|
|
|
|
Obj->moveRelocationNext(RelNext);
|
|
|
|
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
|
|
|
|
|
|
|
|
// X86 sect diff's must be followed by a relocation of type
|
|
|
|
// GENERIC_RELOC_PAIR.
|
|
|
|
unsigned RType = Obj->getAnyRelocationType(RENext);
|
|
|
|
|
|
|
|
if (RType != MachO::GENERIC_RELOC_PAIR)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
|
|
|
|
"GENERIC_RELOC_SECTDIFF.");
|
2015-06-03 12:48:06 +08:00
|
|
|
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
fmt << "-";
|
|
|
|
printRelocationTargetName(Obj, RENext, fmt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-05-15 03:46:08 +08:00
|
|
|
|
|
|
|
if (Arch == Triple::x86 || Arch == Triple::ppc) {
|
|
|
|
switch (Type) {
|
|
|
|
case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
|
|
|
|
DataRefImpl RelNext = Rel;
|
|
|
|
Obj->moveRelocationNext(RelNext);
|
|
|
|
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
|
|
|
|
|
|
|
|
// X86 sect diff's must be followed by a relocation of type
|
|
|
|
// GENERIC_RELOC_PAIR.
|
|
|
|
unsigned RType = Obj->getAnyRelocationType(RENext);
|
|
|
|
if (RType != MachO::GENERIC_RELOC_PAIR)
|
|
|
|
report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after "
|
|
|
|
"GENERIC_RELOC_LOCAL_SECTDIFF.");
|
|
|
|
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
fmt << "-";
|
|
|
|
printRelocationTargetName(Obj, RENext, fmt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MachO::GENERIC_RELOC_TLV: {
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
fmt << "@TLV";
|
|
|
|
if (IsPCRel)
|
|
|
|
fmt << "P";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
}
|
|
|
|
} else { // ARM-specific relocations
|
|
|
|
switch (Type) {
|
|
|
|
case MachO::ARM_RELOC_HALF:
|
|
|
|
case MachO::ARM_RELOC_HALF_SECTDIFF: {
|
|
|
|
// Half relocations steal a bit from the length field to encode
|
|
|
|
// whether this is an upper16 or a lower16 relocation.
|
|
|
|
bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1;
|
|
|
|
|
|
|
|
if (isUpper)
|
|
|
|
fmt << ":upper16:(";
|
|
|
|
else
|
|
|
|
fmt << ":lower16:(";
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
|
|
|
|
DataRefImpl RelNext = Rel;
|
|
|
|
Obj->moveRelocationNext(RelNext);
|
|
|
|
MachO::any_relocation_info RENext = Obj->getRelocation(RelNext);
|
|
|
|
|
|
|
|
// ARM half relocs must be followed by a relocation of type
|
|
|
|
// ARM_RELOC_PAIR.
|
|
|
|
unsigned RType = Obj->getAnyRelocationType(RENext);
|
|
|
|
if (RType != MachO::ARM_RELOC_PAIR)
|
|
|
|
report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after "
|
|
|
|
"ARM_RELOC_HALF");
|
|
|
|
|
|
|
|
// NOTE: The half of the target virtual address is stashed in the
|
|
|
|
// address field of the secondary relocation, but we can't reverse
|
|
|
|
// engineer the constant offset from it without decoding the movw/movt
|
|
|
|
// instruction to find the other half in its immediate field.
|
|
|
|
|
|
|
|
// ARM_RELOC_HALF_SECTDIFF encodes the second section in the
|
|
|
|
// symbol/section pointer of the follow-on relocation.
|
|
|
|
if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) {
|
|
|
|
fmt << "-";
|
|
|
|
printRelocationTargetName(Obj, RENext, fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt << ")";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: { printRelocationTargetName(Obj, RE, fmt); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
printRelocationTargetName(Obj, RE, fmt);
|
|
|
|
|
|
|
|
fmt.flush();
|
|
|
|
Result.append(fmtbuf.begin(), fmtbuf.end());
|
|
|
|
return std::error_code();
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::error_code getRelocationValueString(const RelocationRef &Rel,
|
|
|
|
SmallVectorImpl<char> &Result) {
|
|
|
|
const ObjectFile *Obj = Rel.getObject();
|
|
|
|
if (auto *ELF = dyn_cast<ELFObjectFileBase>(Obj))
|
|
|
|
return getRelocationValueString(ELF, Rel, Result);
|
|
|
|
if (auto *COFF = dyn_cast<COFFObjectFile>(Obj))
|
|
|
|
return getRelocationValueString(COFF, Rel, Result);
|
|
|
|
if (auto *Wasm = dyn_cast<WasmObjectFile>(Obj))
|
|
|
|
return getRelocationValueString(Wasm, Rel, Result);
|
|
|
|
if (auto *MachO = dyn_cast<MachOObjectFile>(Obj))
|
|
|
|
return getRelocationValueString(MachO, Rel, Result);
|
|
|
|
llvm_unreachable("unknown object file format");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Indicates whether this relocation should hidden when listing
|
|
|
|
/// relocations, usually because it is the trailing part of a multipart
|
|
|
|
/// relocation that will be printed as part of the leading relocation.
|
|
|
|
static bool getHidden(RelocationRef RelRef) {
|
|
|
|
const ObjectFile *Obj = RelRef.getObject();
|
|
|
|
auto *MachO = dyn_cast<MachOObjectFile>(Obj);
|
|
|
|
if (!MachO)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned Arch = MachO->getArch();
|
|
|
|
DataRefImpl Rel = RelRef.getRawDataRefImpl();
|
|
|
|
uint64_t Type = MachO->getRelocationType(Rel);
|
|
|
|
|
|
|
|
// On arches that use the generic relocations, GENERIC_RELOC_PAIR
|
|
|
|
// is always hidden.
|
|
|
|
if (Arch == Triple::x86 || Arch == Triple::arm || Arch == Triple::ppc) {
|
|
|
|
if (Type == MachO::GENERIC_RELOC_PAIR)
|
|
|
|
return true;
|
|
|
|
} else if (Arch == Triple::x86_64) {
|
|
|
|
// On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows
|
|
|
|
// an X86_64_RELOC_SUBTRACTOR.
|
|
|
|
if (Type == MachO::X86_64_RELOC_UNSIGNED && Rel.d.a > 0) {
|
|
|
|
DataRefImpl RelPrev = Rel;
|
|
|
|
RelPrev.d.a--;
|
|
|
|
uint64_t PrevType = MachO->getRelocationType(RelPrev);
|
|
|
|
if (PrevType == MachO::X86_64_RELOC_SUBTRACTOR)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class SourcePrinter {
|
|
|
|
protected:
|
|
|
|
DILineInfo OldLineInfo;
|
|
|
|
const ObjectFile *Obj = nullptr;
|
|
|
|
std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
|
|
|
|
// File name to file contents of source
|
|
|
|
std::unordered_map<std::string, std::unique_ptr<MemoryBuffer>> SourceCache;
|
|
|
|
// Mark the line endings of the cached source
|
|
|
|
std::unordered_map<std::string, std::vector<StringRef>> LineCache;
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool cacheSource(const DILineInfo& LineInfoFile);
|
|
|
|
|
|
|
|
public:
|
|
|
|
SourcePrinter() = default;
|
|
|
|
SourcePrinter(const ObjectFile *Obj, StringRef DefaultArch) : Obj(Obj) {
|
|
|
|
symbolize::LLVMSymbolizer::Options SymbolizerOpts(
|
|
|
|
DILineInfoSpecifier::FunctionNameKind::None, true, false, false,
|
|
|
|
DefaultArch);
|
|
|
|
Symbolizer.reset(new symbolize::LLVMSymbolizer(SymbolizerOpts));
|
|
|
|
}
|
|
|
|
virtual ~SourcePrinter() = default;
|
|
|
|
virtual void printSourceLine(raw_ostream &OS, uint64_t Address,
|
|
|
|
StringRef Delimiter = "; ");
|
|
|
|
};
|
|
|
|
|
|
|
|
bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {
|
|
|
|
std::unique_ptr<MemoryBuffer> Buffer;
|
|
|
|
if (LineInfo.Source) {
|
|
|
|
Buffer = MemoryBuffer::getMemBuffer(*LineInfo.Source);
|
|
|
|
} else {
|
|
|
|
auto BufferOrError = MemoryBuffer::getFile(LineInfo.FileName);
|
|
|
|
if (!BufferOrError)
|
|
|
|
return false;
|
|
|
|
Buffer = std::move(*BufferOrError);
|
|
|
|
}
|
|
|
|
// Chomp the file to get lines
|
|
|
|
size_t BufferSize = Buffer->getBufferSize();
|
|
|
|
const char *BufferStart = Buffer->getBufferStart();
|
|
|
|
for (const char *Start = BufferStart, *End = BufferStart;
|
|
|
|
End < BufferStart + BufferSize; End++)
|
|
|
|
if (*End == '\n' || End == BufferStart + BufferSize - 1 ||
|
|
|
|
(*End == '\r' && *(End + 1) == '\n')) {
|
|
|
|
LineCache[LineInfo.FileName].push_back(StringRef(Start, End - Start));
|
|
|
|
if (*End == '\r')
|
|
|
|
End++;
|
|
|
|
Start = End + 1;
|
|
|
|
}
|
|
|
|
SourceCache[LineInfo.FileName] = std::move(Buffer);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SourcePrinter::printSourceLine(raw_ostream &OS, uint64_t Address,
|
|
|
|
StringRef Delimiter) {
|
|
|
|
if (!Symbolizer)
|
|
|
|
return;
|
|
|
|
DILineInfo LineInfo = DILineInfo();
|
|
|
|
auto ExpectecLineInfo =
|
|
|
|
Symbolizer->symbolizeCode(Obj->getFileName(), Address);
|
|
|
|
if (!ExpectecLineInfo)
|
|
|
|
consumeError(ExpectecLineInfo.takeError());
|
|
|
|
else
|
|
|
|
LineInfo = *ExpectecLineInfo;
|
|
|
|
|
|
|
|
if ((LineInfo.FileName == "<invalid>") || OldLineInfo.Line == LineInfo.Line ||
|
|
|
|
LineInfo.Line == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (PrintLines)
|
|
|
|
OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line << "\n";
|
|
|
|
if (PrintSource) {
|
|
|
|
if (SourceCache.find(LineInfo.FileName) == SourceCache.end())
|
|
|
|
if (!cacheSource(LineInfo))
|
|
|
|
return;
|
|
|
|
auto FileBuffer = SourceCache.find(LineInfo.FileName);
|
|
|
|
if (FileBuffer != SourceCache.end()) {
|
|
|
|
auto LineBuffer = LineCache.find(LineInfo.FileName);
|
|
|
|
if (LineBuffer != LineCache.end()) {
|
|
|
|
if (LineInfo.Line > LineBuffer->second.size())
|
|
|
|
return;
|
|
|
|
// Vector begins at 0, line numbers are non-zero
|
|
|
|
OS << Delimiter << LineBuffer->second[LineInfo.Line - 1].ltrim()
|
|
|
|
<< "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OldLineInfo = LineInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isArmElf(const ObjectFile *Obj) {
|
|
|
|
return (Obj->isELF() &&
|
|
|
|
(Obj->getArch() == Triple::aarch64 ||
|
|
|
|
Obj->getArch() == Triple::aarch64_be ||
|
|
|
|
Obj->getArch() == Triple::arm || Obj->getArch() == Triple::armeb ||
|
|
|
|
Obj->getArch() == Triple::thumb ||
|
|
|
|
Obj->getArch() == Triple::thumbeb));
|
|
|
|
}
|
|
|
|
|
|
|
|
class PrettyPrinter {
|
|
|
|
public:
|
|
|
|
virtual ~PrettyPrinter() = default;
|
|
|
|
virtual void printInst(MCInstPrinter &IP, const MCInst *MI,
|
|
|
|
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
|
|
|
raw_ostream &OS, StringRef Annot,
|
|
|
|
MCSubtargetInfo const &STI, SourcePrinter *SP,
|
|
|
|
std::vector<RelocationRef> *Rels = nullptr) {
|
|
|
|
if (SP && (PrintSource || PrintLines))
|
|
|
|
SP->printSourceLine(OS, Address);
|
|
|
|
if (!NoLeadingAddr)
|
|
|
|
OS << format("%8" PRIx64 ":", Address);
|
|
|
|
if (!NoShowRawInsn) {
|
|
|
|
OS << "\t";
|
|
|
|
dumpBytes(Bytes, OS);
|
|
|
|
}
|
|
|
|
if (MI)
|
|
|
|
IP.printInst(MI, OS, "", STI);
|
|
|
|
else
|
|
|
|
OS << " <unknown>";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
PrettyPrinter PrettyPrinterInst;
|
|
|
|
class HexagonPrettyPrinter : public PrettyPrinter {
|
|
|
|
public:
|
|
|
|
void printLead(ArrayRef<uint8_t> Bytes, uint64_t Address,
|
|
|
|
raw_ostream &OS) {
|
|
|
|
uint32_t opcode =
|
|
|
|
(Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0];
|
|
|
|
if (!NoLeadingAddr)
|
|
|
|
OS << format("%8" PRIx64 ":", Address);
|
|
|
|
if (!NoShowRawInsn) {
|
|
|
|
OS << "\t";
|
|
|
|
dumpBytes(Bytes.slice(0, 4), OS);
|
|
|
|
OS << format("%08" PRIx32, opcode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
|
|
|
|
uint64_t Address, raw_ostream &OS, StringRef Annot,
|
|
|
|
MCSubtargetInfo const &STI, SourcePrinter *SP,
|
|
|
|
std::vector<RelocationRef> *Rels) override {
|
|
|
|
if (SP && (PrintSource || PrintLines))
|
|
|
|
SP->printSourceLine(OS, Address, "");
|
|
|
|
if (!MI) {
|
|
|
|
printLead(Bytes, Address, OS);
|
|
|
|
OS << " <unknown>";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::string Buffer;
|
|
|
|
{
|
|
|
|
raw_string_ostream TempStream(Buffer);
|
|
|
|
IP.printInst(MI, TempStream, "", STI);
|
|
|
|
}
|
|
|
|
StringRef Contents(Buffer);
|
|
|
|
// Split off bundle attributes
|
|
|
|
auto PacketBundle = Contents.rsplit('\n');
|
|
|
|
// Split off first instruction from the rest
|
|
|
|
auto HeadTail = PacketBundle.first.split('\n');
|
|
|
|
auto Preamble = " { ";
|
|
|
|
auto Separator = "";
|
|
|
|
StringRef Fmt = "\t\t\t%08" PRIx64 ": ";
|
|
|
|
std::vector<RelocationRef>::const_iterator rel_cur = Rels->begin();
|
|
|
|
std::vector<RelocationRef>::const_iterator rel_end = Rels->end();
|
|
|
|
|
|
|
|
// Hexagon's packets require relocations to be inline rather than
|
|
|
|
// clustered at the end of the packet.
|
|
|
|
auto PrintReloc = [&]() -> void {
|
|
|
|
while ((rel_cur != rel_end) && (rel_cur->getOffset() <= Address)) {
|
|
|
|
if (rel_cur->getOffset() == Address) {
|
|
|
|
SmallString<16> name;
|
|
|
|
SmallString<32> val;
|
|
|
|
rel_cur->getTypeName(name);
|
|
|
|
error(getRelocationValueString(*rel_cur, val));
|
|
|
|
OS << Separator << format(Fmt.data(), Address) << name << "\t" << val
|
|
|
|
<< "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rel_cur++;
|
2015-06-03 12:48:06 +08:00
|
|
|
}
|
2018-05-15 03:46:08 +08:00
|
|
|
};
|
2015-06-03 12:48:06 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
while(!HeadTail.first.empty()) {
|
|
|
|
OS << Separator;
|
|
|
|
Separator = "\n";
|
|
|
|
if (SP && (PrintSource || PrintLines))
|
|
|
|
SP->printSourceLine(OS, Address, "");
|
|
|
|
printLead(Bytes, Address, OS);
|
|
|
|
OS << Preamble;
|
|
|
|
Preamble = " ";
|
|
|
|
StringRef Inst;
|
|
|
|
auto Duplex = HeadTail.first.split('\v');
|
|
|
|
if(!Duplex.second.empty()){
|
|
|
|
OS << Duplex.first;
|
|
|
|
OS << "; ";
|
|
|
|
Inst = Duplex.second;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Inst = HeadTail.first;
|
|
|
|
OS << Inst;
|
|
|
|
HeadTail = HeadTail.second.split('\n');
|
|
|
|
if (HeadTail.first.empty())
|
|
|
|
OS << " } " << PacketBundle.second;
|
|
|
|
PrintReloc();
|
|
|
|
Bytes = Bytes.slice(4);
|
|
|
|
Address += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
HexagonPrettyPrinter HexagonPrettyPrinterInst;
|
2015-06-03 12:48:06 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
class AMDGCNPrettyPrinter : public PrettyPrinter {
|
|
|
|
public:
|
|
|
|
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
|
|
|
|
uint64_t Address, raw_ostream &OS, StringRef Annot,
|
|
|
|
MCSubtargetInfo const &STI, SourcePrinter *SP,
|
|
|
|
std::vector<RelocationRef> *Rels) override {
|
|
|
|
if (SP && (PrintSource || PrintLines))
|
|
|
|
SP->printSourceLine(OS, Address);
|
2015-06-03 12:48:06 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
typedef support::ulittle32_t U32;
|
2015-06-03 12:48:06 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
if (MI) {
|
|
|
|
SmallString<40> InstStr;
|
|
|
|
raw_svector_ostream IS(InstStr);
|
2015-06-03 12:48:06 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
IP.printInst(MI, IS, "", STI);
|
2015-06-03 12:48:06 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
OS << left_justify(IS.str(), 60);
|
|
|
|
} else {
|
|
|
|
// an unrecognized encoding - this is probably data so represent it
|
|
|
|
// using the .long directive, or .byte directive if fewer than 4 bytes
|
|
|
|
// remaining
|
|
|
|
if (Bytes.size() >= 4) {
|
|
|
|
OS << format("\t.long 0x%08" PRIx32 " ",
|
|
|
|
static_cast<uint32_t>(*reinterpret_cast<const U32*>(Bytes.data())));
|
|
|
|
OS.indent(42);
|
|
|
|
} else {
|
|
|
|
OS << format("\t.byte 0x%02" PRIx8, Bytes[0]);
|
|
|
|
for (unsigned int i = 1; i < Bytes.size(); i++)
|
|
|
|
OS << format(", 0x%02" PRIx8, Bytes[i]);
|
|
|
|
OS.indent(55 - (6 * Bytes.size()));
|
2015-06-03 12:48:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
OS << format("// %012" PRIX64 ": ", Address);
|
|
|
|
if (Bytes.size() >=4) {
|
|
|
|
for (auto D : makeArrayRef(reinterpret_cast<const U32*>(Bytes.data()),
|
|
|
|
Bytes.size() / sizeof(U32)))
|
|
|
|
// D should be explicitly casted to uint32_t here as it is passed
|
|
|
|
// by format to snprintf as vararg.
|
|
|
|
OS << format("%08" PRIX32 " ", static_cast<uint32_t>(D));
|
|
|
|
} else {
|
|
|
|
for (unsigned int i = 0; i < Bytes.size(); i++)
|
|
|
|
OS << format("%02" PRIX8 " ", Bytes[i]);
|
|
|
|
}
|
2015-06-30 11:41:26 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
if (!Annot.empty())
|
|
|
|
OS << "// " << Annot;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
AMDGCNPrettyPrinter AMDGCNPrettyPrinterInst;
|
2015-06-30 11:41:26 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
class BPFPrettyPrinter : public PrettyPrinter {
|
|
|
|
public:
|
|
|
|
void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes,
|
|
|
|
uint64_t Address, raw_ostream &OS, StringRef Annot,
|
|
|
|
MCSubtargetInfo const &STI, SourcePrinter *SP,
|
|
|
|
std::vector<RelocationRef> *Rels) override {
|
|
|
|
if (SP && (PrintSource || PrintLines))
|
|
|
|
SP->printSourceLine(OS, Address);
|
|
|
|
if (!NoLeadingAddr)
|
|
|
|
OS << format("%8" PRId64 ":", Address / 8);
|
|
|
|
if (!NoShowRawInsn) {
|
|
|
|
OS << "\t";
|
|
|
|
dumpBytes(Bytes, OS);
|
2015-06-30 11:41:26 +08:00
|
|
|
}
|
2018-05-15 03:46:08 +08:00
|
|
|
if (MI)
|
|
|
|
IP.printInst(MI, OS, "", STI);
|
|
|
|
else
|
|
|
|
OS << " <unknown>";
|
2015-06-30 11:41:26 +08:00
|
|
|
}
|
2018-05-15 03:46:08 +08:00
|
|
|
};
|
|
|
|
BPFPrettyPrinter BPFPrettyPrinterInst;
|
2015-06-30 11:41:26 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
PrettyPrinter &selectPrettyPrinter(Triple const &Triple) {
|
|
|
|
switch(Triple.getArch()) {
|
|
|
|
default:
|
|
|
|
return PrettyPrinterInst;
|
|
|
|
case Triple::hexagon:
|
|
|
|
return HexagonPrettyPrinterInst;
|
|
|
|
case Triple::amdgcn:
|
|
|
|
return AMDGCNPrettyPrinterInst;
|
|
|
|
case Triple::bpfel:
|
|
|
|
case Triple::bpfeb:
|
|
|
|
return BPFPrettyPrinterInst;
|
|
|
|
}
|
|
|
|
}
|
2015-06-30 11:41:26 +08:00
|
|
|
}
|
|
|
|
|
2016-08-17 18:17:57 +08:00
|
|
|
static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) {
|
|
|
|
assert(Obj->isELF());
|
|
|
|
if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
|
|
|
|
return Elf32LEObj->getSymbol(Sym.getRawDataRefImpl())->getType();
|
|
|
|
if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
|
|
|
|
return Elf64LEObj->getSymbol(Sym.getRawDataRefImpl())->getType();
|
|
|
|
if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
|
|
|
|
return Elf32BEObj->getSymbol(Sym.getRawDataRefImpl())->getType();
|
|
|
|
if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj))
|
|
|
|
return Elf64BEObj->getSymbol(Sym.getRawDataRefImpl())->getType();
|
|
|
|
llvm_unreachable("Unsupported binary format");
|
|
|
|
}
|
|
|
|
|
2017-02-08 17:44:18 +08:00
|
|
|
template <class ELFT> static void
|
|
|
|
addDynamicElfSymbols(const ELFObjectFile<ELFT> *Obj,
|
|
|
|
std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
|
|
|
|
for (auto Symbol : Obj->getDynamicSymbolIterators()) {
|
|
|
|
uint8_t SymbolType = Symbol.getELFType();
|
|
|
|
if (SymbolType != ELF::STT_FUNC || Symbol.getSize() == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Expected<uint64_t> AddressOrErr = Symbol.getAddress();
|
|
|
|
if (!AddressOrErr)
|
|
|
|
report_error(Obj->getFileName(), AddressOrErr.takeError());
|
|
|
|
uint64_t Address = *AddressOrErr;
|
|
|
|
|
|
|
|
Expected<StringRef> Name = Symbol.getName();
|
|
|
|
if (!Name)
|
|
|
|
report_error(Obj->getFileName(), Name.takeError());
|
|
|
|
if (Name->empty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Expected<section_iterator> SectionOrErr = Symbol.getSection();
|
|
|
|
if (!SectionOrErr)
|
|
|
|
report_error(Obj->getFileName(), SectionOrErr.takeError());
|
|
|
|
section_iterator SecI = *SectionOrErr;
|
|
|
|
if (SecI == Obj->section_end())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
addDynamicElfSymbols(const ObjectFile *Obj,
|
|
|
|
std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
|
|
|
|
assert(Obj->isELF());
|
|
|
|
if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
|
|
|
|
addDynamicElfSymbols(Elf32LEObj, AllSymbols);
|
|
|
|
else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
|
|
|
|
addDynamicElfSymbols(Elf64LEObj, AllSymbols);
|
|
|
|
else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
|
|
|
|
addDynamicElfSymbols(Elf32BEObj, AllSymbols);
|
|
|
|
else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj))
|
|
|
|
addDynamicElfSymbols(Elf64BEObj, AllSymbols);
|
|
|
|
else
|
|
|
|
llvm_unreachable("Unsupported binary format");
|
|
|
|
}
|
|
|
|
|
2018-08-24 23:21:57 +08:00
|
|
|
static void addPltEntries(const ObjectFile *Obj,
|
|
|
|
std::map<SectionRef, SectionSymbolsTy> &AllSymbols,
|
|
|
|
StringSaver &Saver) {
|
|
|
|
Optional<SectionRef> Plt = None;
|
|
|
|
for (const SectionRef &Section : Obj->sections()) {
|
|
|
|
StringRef Name;
|
|
|
|
if (Section.getName(Name))
|
|
|
|
continue;
|
|
|
|
if (Name == ".plt")
|
|
|
|
Plt = Section;
|
|
|
|
}
|
|
|
|
if (!Plt)
|
|
|
|
return;
|
|
|
|
if (auto *ElfObj = dyn_cast<ELFObjectFileBase>(Obj)) {
|
|
|
|
for (auto PltEntry : ElfObj->getPltAddresses()) {
|
|
|
|
SymbolRef Symbol(PltEntry.first, ElfObj);
|
|
|
|
|
|
|
|
uint8_t SymbolType = getElfSymbolType(Obj, Symbol);
|
|
|
|
|
|
|
|
Expected<StringRef> NameOrErr = Symbol.getName();
|
|
|
|
if (!NameOrErr)
|
|
|
|
report_error(Obj->getFileName(), NameOrErr.takeError());
|
|
|
|
if (NameOrErr->empty())
|
|
|
|
continue;
|
|
|
|
StringRef Name = Saver.save((*NameOrErr + "@plt").str());
|
|
|
|
|
|
|
|
AllSymbols[*Plt].emplace_back(PltEntry.second, Name, SymbolType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 06:17:18 +08:00
|
|
|
static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
|
2016-09-13 01:08:22 +08:00
|
|
|
if (StartAddress > StopAddress)
|
|
|
|
error("Start address should be less than stop address");
|
|
|
|
|
2012-08-08 01:53:14 +08:00
|
|
|
const Target *TheTarget = getTarget(Obj);
|
2011-01-20 14:39:06 +08:00
|
|
|
|
2012-08-29 03:24:49 +08:00
|
|
|
// Package up features to be passed to target/subtarget
|
2016-06-16 17:17:03 +08:00
|
|
|
SubtargetFeatures Features = Obj->getFeatures();
|
2012-08-29 03:24:49 +08:00
|
|
|
if (MAttrs.size()) {
|
|
|
|
for (unsigned i = 0; i != MAttrs.size(); ++i)
|
|
|
|
Features.AddFeature(MAttrs[i]);
|
|
|
|
}
|
|
|
|
|
2014-03-06 13:51:42 +08:00
|
|
|
std::unique_ptr<const MCRegisterInfo> MRI(
|
|
|
|
TheTarget->createMCRegInfo(TripleName));
|
2015-12-17 09:59:50 +08:00
|
|
|
if (!MRI)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(Obj->getFileName(), "no register info for target " +
|
|
|
|
TripleName);
|
2013-05-17 05:28:23 +08:00
|
|
|
|
|
|
|
// Set up disassembler.
|
2014-03-06 13:51:42 +08:00
|
|
|
std::unique_ptr<const MCAsmInfo> AsmInfo(
|
|
|
|
TheTarget->createMCAsmInfo(*MRI, TripleName));
|
2015-12-17 09:59:50 +08:00
|
|
|
if (!AsmInfo)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(Obj->getFileName(), "no assembly info for target " +
|
|
|
|
TripleName);
|
2014-03-06 13:51:42 +08:00
|
|
|
std::unique_ptr<const MCSubtargetInfo> STI(
|
2016-06-16 17:17:03 +08:00
|
|
|
TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
|
2015-12-17 09:59:50 +08:00
|
|
|
if (!STI)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(Obj->getFileName(), "no subtarget info for target " +
|
|
|
|
TripleName);
|
2014-03-06 13:51:42 +08:00
|
|
|
std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
|
2015-12-17 09:59:50 +08:00
|
|
|
if (!MII)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(Obj->getFileName(), "no instruction info for target " +
|
|
|
|
TripleName);
|
2016-10-06 21:46:08 +08:00
|
|
|
MCObjectFileInfo MOFI;
|
|
|
|
MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI);
|
|
|
|
// FIXME: for now initialize MCObjectFileInfo with default values
|
2017-08-03 04:32:26 +08:00
|
|
|
MOFI.InitMCObjectFileInfo(Triple(TripleName), false, Ctx);
|
2014-04-15 12:40:56 +08:00
|
|
|
|
|
|
|
std::unique_ptr<MCDisassembler> DisAsm(
|
|
|
|
TheTarget->createMCDisassembler(*STI, Ctx));
|
2015-12-17 09:59:50 +08:00
|
|
|
if (!DisAsm)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(Obj->getFileName(), "no disassembler for target " +
|
|
|
|
TripleName);
|
2013-05-17 05:28:23 +08:00
|
|
|
|
2014-03-06 13:51:42 +08:00
|
|
|
std::unique_ptr<const MCInstrAnalysis> MIA(
|
|
|
|
TheTarget->createMCInstrAnalysis(MII.get()));
|
MC: Disassembled CFG reconstruction.
This patch builds on some existing code to do CFG reconstruction from
a disassembled binary:
- MCModule represents the binary, and has a list of MCAtoms.
- MCAtom represents either disassembled instructions (MCTextAtom), or
contiguous data (MCDataAtom), and covers a specific range of addresses.
- MCBasicBlock and MCFunction form the reconstructed CFG. An MCBB is
backed by an MCTextAtom, and has the usual successors/predecessors.
- MCObjectDisassembler creates a module from an ObjectFile using a
disassembler. It first builds an atom for each section. It can also
construct the CFG, and this splits the text atoms into basic blocks.
MCModule and MCAtom were only sketched out; MCFunction and MCBB were
implemented under the experimental "-cfg" llvm-objdump -macho option.
This cleans them up for further use; llvm-objdump -d -cfg now generates
graphviz files for each function found in the binary.
In the future, MCObjectDisassembler may be the right place to do
"intelligent" disassembly: for example, handling constant islands is just
a matter of splitting the atom, using information that may be available
in the ObjectFile. Also, better initial atom formation than just using
sections is possible using symbols (and things like Mach-O's
function_starts load command).
This brings two minor regressions in llvm-objdump -macho -cfg:
- The printing of a relocation's referenced symbol.
- An annotation on loop BBs, i.e., which are their own successor.
Relocation printing is replaced by the MCSymbolizer; the basic CFG
annotation will be superseded by more related functionality.
llvm-svn: 182628
2013-05-24 09:07:04 +08:00
|
|
|
|
2013-05-17 05:28:23 +08:00
|
|
|
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
|
2015-09-16 00:17:27 +08:00
|
|
|
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
|
|
|
|
Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
|
2015-12-17 09:59:50 +08:00
|
|
|
if (!IP)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(Obj->getFileName(), "no instruction printer for target " +
|
|
|
|
TripleName);
|
2015-06-08 05:07:17 +08:00
|
|
|
IP->setPrintImmHex(PrintImmHex);
|
2015-05-29 22:48:25 +08:00
|
|
|
PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName));
|
2013-05-17 05:28:23 +08:00
|
|
|
|
2014-03-21 06:55:15 +08:00
|
|
|
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "\t\t%016" PRIx64 ": " :
|
|
|
|
"\t\t\t%08" PRIx64 ": ";
|
|
|
|
|
2016-08-16 03:49:24 +08:00
|
|
|
SourcePrinter SP(Obj, TheTarget->getName());
|
|
|
|
|
2014-01-26 01:38:19 +08:00
|
|
|
// Create a mapping, RelocSecs = SectionRelocMap[S], where sections
|
|
|
|
// in RelocSecs contain the relocations for section S.
|
2014-06-13 11:07:50 +08:00
|
|
|
std::error_code EC;
|
2014-03-13 22:37:36 +08:00
|
|
|
std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap;
|
2015-07-29 23:45:39 +08:00
|
|
|
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
|
2014-03-13 22:37:36 +08:00
|
|
|
section_iterator Sec2 = Section.getRelocatedSection();
|
2014-02-11 04:24:04 +08:00
|
|
|
if (Sec2 != Obj->section_end())
|
2014-03-13 22:37:36 +08:00
|
|
|
SectionRelocMap[*Sec2].push_back(Section);
|
2014-01-26 01:38:19 +08:00
|
|
|
}
|
|
|
|
|
2015-07-08 06:06:59 +08:00
|
|
|
// Create a mapping from virtual address to symbol name. This is used to
|
2015-11-18 10:49:19 +08:00
|
|
|
// pretty print the symbols while disassembling.
|
|
|
|
std::map<SectionRef, SectionSymbolsTy> AllSymbols;
|
2018-06-29 02:57:13 +08:00
|
|
|
SectionSymbolsTy AbsoluteSymbols;
|
2015-11-18 10:49:19 +08:00
|
|
|
for (const SymbolRef &Symbol : Obj->symbols()) {
|
2016-06-25 02:24:42 +08:00
|
|
|
Expected<uint64_t> AddressOrErr = Symbol.getAddress();
|
2016-11-17 06:17:38 +08:00
|
|
|
if (!AddressOrErr)
|
|
|
|
report_error(Obj->getFileName(), AddressOrErr.takeError());
|
2015-11-18 10:49:19 +08:00
|
|
|
uint64_t Address = *AddressOrErr;
|
|
|
|
|
2016-04-21 05:24:34 +08:00
|
|
|
Expected<StringRef> Name = Symbol.getName();
|
2016-11-17 06:17:38 +08:00
|
|
|
if (!Name)
|
|
|
|
report_error(Obj->getFileName(), Name.takeError());
|
2015-11-18 10:49:19 +08:00
|
|
|
if (Name->empty())
|
|
|
|
continue;
|
2015-07-10 02:11:40 +08:00
|
|
|
|
2016-05-03 04:28:12 +08:00
|
|
|
Expected<section_iterator> SectionOrErr = Symbol.getSection();
|
2016-11-17 06:17:38 +08:00
|
|
|
if (!SectionOrErr)
|
|
|
|
report_error(Obj->getFileName(), SectionOrErr.takeError());
|
2016-08-26 03:41:08 +08:00
|
|
|
|
2016-08-17 18:17:57 +08:00
|
|
|
uint8_t SymbolType = ELF::STT_NOTYPE;
|
2016-08-26 03:41:08 +08:00
|
|
|
if (Obj->isELF())
|
2016-08-17 18:17:57 +08:00
|
|
|
SymbolType = getElfSymbolType(Obj, Symbol);
|
|
|
|
|
2018-06-29 02:57:13 +08:00
|
|
|
section_iterator SecI = *SectionOrErr;
|
|
|
|
if (SecI != Obj->section_end())
|
|
|
|
AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType);
|
|
|
|
else
|
|
|
|
AbsoluteSymbols.emplace_back(Address, *Name, SymbolType);
|
|
|
|
|
2015-07-08 06:06:59 +08:00
|
|
|
|
2015-11-18 10:49:19 +08:00
|
|
|
}
|
2017-02-08 17:44:18 +08:00
|
|
|
if (AllSymbols.empty() && Obj->isELF())
|
|
|
|
addDynamicElfSymbols(Obj, AllSymbols);
|
2015-11-18 10:49:19 +08:00
|
|
|
|
2018-08-24 23:21:57 +08:00
|
|
|
BumpPtrAllocator A;
|
|
|
|
StringSaver Saver(A);
|
|
|
|
addPltEntries(Obj, AllSymbols, Saver);
|
|
|
|
|
2015-11-18 10:49:19 +08:00
|
|
|
// Create a mapping from virtual address to section.
|
|
|
|
std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses;
|
|
|
|
for (SectionRef Sec : Obj->sections())
|
|
|
|
SectionAddresses.emplace_back(Sec.getAddress(), Sec);
|
|
|
|
array_pod_sort(SectionAddresses.begin(), SectionAddresses.end());
|
|
|
|
|
|
|
|
// Linked executables (.exe and .dll files) typically don't include a real
|
|
|
|
// symbol table but they might contain an export table.
|
|
|
|
if (const auto *COFFObj = dyn_cast<COFFObjectFile>(Obj)) {
|
|
|
|
for (const auto &ExportEntry : COFFObj->export_directories()) {
|
|
|
|
StringRef Name;
|
|
|
|
error(ExportEntry.getSymbolName(Name));
|
|
|
|
if (Name.empty())
|
2015-07-08 06:06:59 +08:00
|
|
|
continue;
|
2015-11-18 10:49:19 +08:00
|
|
|
uint32_t RVA;
|
|
|
|
error(ExportEntry.getExportRVA(RVA));
|
|
|
|
|
|
|
|
uint64_t VA = COFFObj->getImageBase() + RVA;
|
|
|
|
auto Sec = std::upper_bound(
|
|
|
|
SectionAddresses.begin(), SectionAddresses.end(), VA,
|
|
|
|
[](uint64_t LHS, const std::pair<uint64_t, SectionRef> &RHS) {
|
|
|
|
return LHS < RHS.first;
|
|
|
|
});
|
|
|
|
if (Sec != SectionAddresses.begin())
|
|
|
|
--Sec;
|
|
|
|
else
|
|
|
|
Sec = SectionAddresses.end();
|
2015-07-08 06:06:59 +08:00
|
|
|
|
2015-11-18 10:49:19 +08:00
|
|
|
if (Sec != SectionAddresses.end())
|
2016-08-17 18:17:57 +08:00
|
|
|
AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE);
|
2018-06-29 02:57:13 +08:00
|
|
|
else
|
|
|
|
AbsoluteSymbols.emplace_back(VA, Name, ELF::STT_NOTYPE);
|
2015-11-18 10:49:19 +08:00
|
|
|
}
|
2015-07-08 06:06:59 +08:00
|
|
|
}
|
|
|
|
|
2015-11-18 10:49:19 +08:00
|
|
|
// Sort all the symbols, this allows us to use a simple binary search to find
|
|
|
|
// a symbol near an address.
|
|
|
|
for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)
|
|
|
|
array_pod_sort(SecSyms.second.begin(), SecSyms.second.end());
|
2018-06-29 02:57:13 +08:00
|
|
|
array_pod_sort(AbsoluteSymbols.begin(), AbsoluteSymbols.end());
|
2015-11-18 10:49:19 +08:00
|
|
|
|
2015-07-29 23:45:39 +08:00
|
|
|
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
|
2015-07-24 04:58:49 +08:00
|
|
|
if (!DisassembleAll && (!Section.isText() || Section.isVirtual()))
|
2014-01-25 08:32:01 +08:00
|
|
|
continue;
|
2011-06-26 01:55:23 +08:00
|
|
|
|
2014-10-08 23:28:58 +08:00
|
|
|
uint64_t SectionAddr = Section.getAddress();
|
|
|
|
uint64_t SectSize = Section.getSize();
|
2014-11-11 17:58:25 +08:00
|
|
|
if (!SectSize)
|
|
|
|
continue;
|
2014-02-25 06:12:11 +08:00
|
|
|
|
2015-11-18 10:49:19 +08:00
|
|
|
// Get the list of all the symbols in this section.
|
|
|
|
SectionSymbolsTy &Symbols = AllSymbols[Section];
|
2015-10-02 05:57:09 +08:00
|
|
|
std::vector<uint64_t> DataMappingSymsAddr;
|
|
|
|
std::vector<uint64_t> TextMappingSymsAddr;
|
2016-08-26 03:41:08 +08:00
|
|
|
if (isArmElf(Obj)) {
|
2015-11-18 10:49:19 +08:00
|
|
|
for (const auto &Symb : Symbols) {
|
2016-08-17 18:17:57 +08:00
|
|
|
uint64_t Address = std::get<0>(Symb);
|
|
|
|
StringRef Name = std::get<1>(Symb);
|
2015-11-18 10:49:19 +08:00
|
|
|
if (Name.startswith("$d"))
|
2015-11-18 12:35:32 +08:00
|
|
|
DataMappingSymsAddr.push_back(Address - SectionAddr);
|
2015-11-18 10:49:19 +08:00
|
|
|
if (Name.startswith("$x"))
|
2015-11-18 12:35:32 +08:00
|
|
|
TextMappingSymsAddr.push_back(Address - SectionAddr);
|
2016-08-26 03:41:08 +08:00
|
|
|
if (Name.startswith("$a"))
|
|
|
|
TextMappingSymsAddr.push_back(Address - SectionAddr);
|
|
|
|
if (Name.startswith("$t"))
|
|
|
|
TextMappingSymsAddr.push_back(Address - SectionAddr);
|
2011-07-16 02:39:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
llvm::sort(C.begin(), C.end(), ...) -> llvm::sort(C, ...)
Summary: The convenience wrapper in STLExtras is available since rL342102.
Reviewers: dblaikie, javed.absar, JDevlieghere, andreadb
Subscribers: MatzeB, sanjoy, arsenm, dschuff, mehdi_amini, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, eraman, aheejin, kbarton, JDevlieghere, javed.absar, gbedwell, jrtc27, mgrang, atanasyan, steven_wu, george.burgess.iv, dexonsmith, kristina, jsji, llvm-commits
Differential Revision: https://reviews.llvm.org/D52573
llvm-svn: 343163
2018-09-27 10:13:45 +08:00
|
|
|
llvm::sort(DataMappingSymsAddr);
|
|
|
|
llvm::sort(TextMappingSymsAddr);
|
2011-07-16 02:39:24 +08:00
|
|
|
|
2016-10-06 21:46:08 +08:00
|
|
|
if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) {
|
|
|
|
// AMDGPU disassembler uses symbolizer for printing labels
|
|
|
|
std::unique_ptr<MCRelocationInfo> RelInfo(
|
|
|
|
TheTarget->createMCRelocationInfo(TripleName, Ctx));
|
|
|
|
if (RelInfo) {
|
|
|
|
std::unique_ptr<MCSymbolizer> Symbolizer(
|
|
|
|
TheTarget->createMCSymbolizer(
|
|
|
|
TripleName, nullptr, nullptr, &Symbols, &Ctx, std::move(RelInfo)));
|
|
|
|
DisAsm->setSymbolizer(std::move(Symbolizer));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-14 06:17:18 +08:00
|
|
|
// Make a list of all the relocations for this section.
|
|
|
|
std::vector<RelocationRef> Rels;
|
|
|
|
if (InlineRelocs) {
|
2014-03-14 22:22:49 +08:00
|
|
|
for (const SectionRef &RelocSec : SectionRelocMap[Section]) {
|
|
|
|
for (const RelocationRef &Reloc : RelocSec.relocations()) {
|
|
|
|
Rels.push_back(Reloc);
|
|
|
|
}
|
2011-10-14 06:17:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort relocations by address.
|
llvm::sort(C.begin(), C.end(), ...) -> llvm::sort(C, ...)
Summary: The convenience wrapper in STLExtras is available since rL342102.
Reviewers: dblaikie, javed.absar, JDevlieghere, andreadb
Subscribers: MatzeB, sanjoy, arsenm, dschuff, mehdi_amini, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, eraman, aheejin, kbarton, JDevlieghere, javed.absar, gbedwell, jrtc27, mgrang, atanasyan, steven_wu, george.burgess.iv, dexonsmith, kristina, jsji, llvm-commits
Differential Revision: https://reviews.llvm.org/D52573
llvm-svn: 343163
2018-09-27 10:13:45 +08:00
|
|
|
llvm::sort(Rels, RelocAddressLess);
|
2011-10-14 06:17:18 +08:00
|
|
|
|
Add a function to get the segment name of a section.
On MachO, sections also have segment names. When a tool looking at a .o file
prints a segment name, this is what they mean. In reality, a .o has only one
anonymous, segment.
This patch adds a MachO only function to fetch that segment name. I named it
getSectionFinalSegmentName since the main use for the name seems to be inform
the linker with segment this section should go to.
The patch also changes MachOObjectFile::getSectionName to return just the
section name instead of computing SegmentName,SectionName.
The main difference from the previous patch is that it doesn't use
InMemoryStruct. It is extremely dangerous: if the endians match it returns
a pointer to the file buffer, if not, it returns a pointer to an internal buffer
that is overwritten in the next API call.
We should change all of this code to use
support::detail::packed_endian_specific_integral like ELF, but since these
functions only handle strings, they work with big and little endian machines
as is.
I have tested this by installing ubuntu 12.10 ppc on qemu, that is why it took
so long :-)
llvm-svn: 170838
2012-12-21 11:47:03 +08:00
|
|
|
StringRef SegmentName = "";
|
2014-01-25 08:32:01 +08:00
|
|
|
if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) {
|
2014-03-13 22:37:36 +08:00
|
|
|
DataRefImpl DR = Section.getRawDataRefImpl();
|
2013-04-19 02:08:55 +08:00
|
|
|
SegmentName = MachO->getSectionFinalSegmentName(DR);
|
Add a function to get the segment name of a section.
On MachO, sections also have segment names. When a tool looking at a .o file
prints a segment name, this is what they mean. In reality, a .o has only one
anonymous, segment.
This patch adds a MachO only function to fetch that segment name. I named it
getSectionFinalSegmentName since the main use for the name seems to be inform
the linker with segment this section should go to.
The patch also changes MachOObjectFile::getSectionName to return just the
section name instead of computing SegmentName,SectionName.
The main difference from the previous patch is that it doesn't use
InMemoryStruct. It is extremely dangerous: if the endians match it returns
a pointer to the file buffer, if not, it returns a pointer to an internal buffer
that is overwritten in the next API call.
We should change all of this code to use
support::detail::packed_endian_specific_integral like ELF, but since these
functions only handle strings, they work with big and little endian machines
as is.
I have tested this by installing ubuntu 12.10 ppc on qemu, that is why it took
so long :-)
llvm-svn: 170838
2012-12-21 11:47:03 +08:00
|
|
|
}
|
2018-03-10 03:13:44 +08:00
|
|
|
StringRef SectionName;
|
|
|
|
error(Section.getName(SectionName));
|
2011-07-16 02:39:24 +08:00
|
|
|
|
2015-06-04 23:01:05 +08:00
|
|
|
// If the section has no symbol at the start, just insert a dummy one.
|
2016-08-17 18:17:57 +08:00
|
|
|
if (Symbols.empty() || std::get<0>(Symbols[0]) != 0) {
|
2018-03-10 03:13:44 +08:00
|
|
|
Symbols.insert(
|
|
|
|
Symbols.begin(),
|
|
|
|
std::make_tuple(SectionAddr, SectionName,
|
|
|
|
Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT));
|
2016-08-17 18:17:57 +08:00
|
|
|
}
|
2014-06-27 06:52:05 +08:00
|
|
|
|
|
|
|
SmallString<40> Comments;
|
|
|
|
raw_svector_ostream CommentStream(Comments);
|
Add MCSymbolizer for symbolic/annotated disassembly.
This is a basic first step towards symbolization of disassembled
instructions. This used to be done using externally provided (C API)
callbacks. This patch introduces:
- the MCSymbolizer class, that mimics the same functions that were used
in the X86 and ARM disassemblers to symbolize immediate operands and
to annotate loads based off PC (for things like c string literals).
- the MCExternalSymbolizer class, which implements the old C API.
- the MCRelocationInfo class, which provides a way for targets to
translate relocations (either object::RelocationRef, or disassembler
C API VariantKinds) to MCExprs.
- the MCObjectSymbolizer class, which does symbolization using what it
finds in an object::ObjectFile. This makes simple symbolization (with
no fancy relocation stuff) work for all object formats!
- x86-64 Mach-O and ELF MCRelocationInfos.
- A basic ARM Mach-O MCRelocationInfo, that provides just enough to
support the C API VariantKinds.
Most of what works in otool (the only user of the old symbolization API
that I know of) for x86-64 symbolic disassembly (-tvV) works, namely:
- symbol references: call _foo; jmp 15 <_foo+50>
- relocations: call _foo-_bar; call _foo-4
- __cf?string: leaq 193(%rip), %rax ## literal pool for "hello"
Stub support is the main missing part (because libObject doesn't know,
among other things, about mach-o indirect symbols).
As for the MCSymbolizer API, instead of relying on the disassemblers
to call the tryAdding* methods, maybe this could be done automagically
using InstrInfo? For instance, even though PC-relative LEAs are used
to get the address of string literals in a typical Mach-O file, a MOV
would be used in an ELF file. And right now, the explicit symbolization
only recognizes PC-relative LEAs. InstrInfo should have already have
most of what is needed to know what to symbolize, so this can
definitely be improved.
I'd also like to remove object::RelocationRef::getValueString (it seems
only used by relocation printing in objdump), as simply printing the
created MCExpr is definitely enough (and cleaner than string concats).
llvm-svn: 182625
2013-05-24 08:39:57 +08:00
|
|
|
|
2014-11-12 10:04:27 +08:00
|
|
|
StringRef BytesStr;
|
2015-08-05 15:18:31 +08:00
|
|
|
error(Section.getContents(BytesStr));
|
2014-11-12 22:01:17 +08:00
|
|
|
ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
|
|
|
|
BytesStr.size());
|
2014-11-12 10:04:27 +08:00
|
|
|
|
2011-01-20 14:39:06 +08:00
|
|
|
uint64_t Size;
|
|
|
|
uint64_t Index;
|
2018-03-10 03:13:44 +08:00
|
|
|
bool PrintedSection = false;
|
2011-07-16 02:39:24 +08:00
|
|
|
|
2011-10-14 06:17:18 +08:00
|
|
|
std::vector<RelocationRef>::const_iterator rel_cur = Rels.begin();
|
|
|
|
std::vector<RelocationRef>::const_iterator rel_end = Rels.end();
|
2011-07-16 02:39:24 +08:00
|
|
|
// Disassemble symbol by symbol.
|
|
|
|
for (unsigned si = 0, se = Symbols.size(); si != se; ++si) {
|
2016-08-17 18:17:57 +08:00
|
|
|
uint64_t Start = std::get<0>(Symbols[si]) - SectionAddr;
|
2015-11-18 10:49:19 +08:00
|
|
|
// The end is either the section end or the beginning of the next
|
|
|
|
// symbol.
|
|
|
|
uint64_t End =
|
2016-08-17 18:17:57 +08:00
|
|
|
(si == se - 1) ? SectSize : std::get<0>(Symbols[si + 1]) - SectionAddr;
|
2015-11-18 10:49:19 +08:00
|
|
|
// Don't try to disassemble beyond the end of section contents.
|
|
|
|
if (End > SectSize)
|
|
|
|
End = SectSize;
|
2014-08-18 00:31:39 +08:00
|
|
|
// If this symbol has the same address as the next symbol, then skip it.
|
2015-11-18 10:49:19 +08:00
|
|
|
if (Start >= End)
|
2011-10-14 04:37:08 +08:00
|
|
|
continue;
|
|
|
|
|
2016-09-13 01:08:22 +08:00
|
|
|
// Check if we need to skip symbol
|
|
|
|
// Skip if the symbol's data is not between StartAddress and StopAddress
|
|
|
|
if (End + SectionAddr < StartAddress ||
|
|
|
|
Start + SectionAddr > StopAddress) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-03-10 03:13:44 +08:00
|
|
|
/// Skip if user requested specific symbols and this is not in the list
|
|
|
|
if (!DisasmFuncsSet.empty() &&
|
|
|
|
!DisasmFuncsSet.count(std::get<1>(Symbols[si])))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!PrintedSection) {
|
|
|
|
PrintedSection = true;
|
|
|
|
outs() << "Disassembly of section ";
|
|
|
|
if (!SegmentName.empty())
|
|
|
|
outs() << SegmentName << ",";
|
|
|
|
outs() << SectionName << ':';
|
|
|
|
}
|
|
|
|
|
2016-09-13 01:08:22 +08:00
|
|
|
// Stop disassembly at the stop address specified
|
|
|
|
if (End + SectionAddr > StopAddress)
|
|
|
|
End = StopAddress - SectionAddr;
|
|
|
|
|
2016-04-07 15:24:01 +08:00
|
|
|
if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) {
|
2016-08-17 18:17:57 +08:00
|
|
|
if (std::get<2>(Symbols[si]) == ELF::STT_AMDGPU_HSA_KERNEL) {
|
|
|
|
// skip amd_kernel_code_t at the begining of kernel symbol (256 bytes)
|
|
|
|
Start += 256;
|
|
|
|
}
|
|
|
|
if (si == se - 1 ||
|
|
|
|
std::get<2>(Symbols[si + 1]) == ELF::STT_AMDGPU_HSA_KERNEL) {
|
|
|
|
// cut trailing zeroes at the end of kernel
|
|
|
|
// cut up to 256 bytes
|
|
|
|
const uint64_t EndAlign = 256;
|
|
|
|
const auto Limit = End - (std::min)(EndAlign, End - Start);
|
|
|
|
while (End > Limit &&
|
|
|
|
*reinterpret_cast<const support::ulittle32_t*>(&Bytes[End - 4]) == 0)
|
|
|
|
End -= 4;
|
|
|
|
}
|
2016-04-07 15:24:01 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 00:39:21 +08:00
|
|
|
auto PrintSymbol = [](StringRef Name) {
|
|
|
|
outs() << '\n' << Name << ":\n";
|
|
|
|
};
|
|
|
|
StringRef SymbolName = std::get<1>(Symbols[si]);
|
2018-08-21 06:18:21 +08:00
|
|
|
if (Demangle) {
|
2018-07-19 00:39:21 +08:00
|
|
|
char *DemangledSymbol = nullptr;
|
|
|
|
size_t Size = 0;
|
2018-08-21 06:18:21 +08:00
|
|
|
int Status = -1;
|
|
|
|
if (SymbolName.startswith("_Z"))
|
|
|
|
DemangledSymbol = itaniumDemangle(SymbolName.data(), DemangledSymbol,
|
|
|
|
&Size, &Status);
|
|
|
|
else if (SymbolName.startswith("?"))
|
|
|
|
DemangledSymbol = microsoftDemangle(SymbolName.data(),
|
|
|
|
DemangledSymbol, &Size, &Status);
|
|
|
|
|
|
|
|
if (Status == 0 && DemangledSymbol)
|
2018-07-19 00:39:21 +08:00
|
|
|
PrintSymbol(StringRef(DemangledSymbol));
|
|
|
|
else
|
|
|
|
PrintSymbol(SymbolName);
|
|
|
|
|
2018-08-21 06:18:21 +08:00
|
|
|
if (DemangledSymbol)
|
2018-07-19 00:39:21 +08:00
|
|
|
free(DemangledSymbol);
|
|
|
|
} else
|
|
|
|
PrintSymbol(SymbolName);
|
2011-07-16 02:39:24 +08:00
|
|
|
|
2018-04-20 01:02:57 +08:00
|
|
|
// Don't print raw contents of a virtual section. A virtual section
|
|
|
|
// doesn't have any contents in the file.
|
|
|
|
if (Section.isVirtual()) {
|
|
|
|
outs() << "...\n";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-07-16 02:39:24 +08:00
|
|
|
#ifndef NDEBUG
|
2014-01-25 08:32:01 +08:00
|
|
|
raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
|
2011-07-16 02:39:24 +08:00
|
|
|
#else
|
2014-01-25 08:32:01 +08:00
|
|
|
raw_ostream &DebugOut = nulls();
|
2011-07-16 02:39:24 +08:00
|
|
|
#endif
|
|
|
|
|
2011-09-20 01:56:04 +08:00
|
|
|
for (Index = Start; Index < End; Index += Size) {
|
|
|
|
MCInst Inst;
|
|
|
|
|
2016-09-13 01:08:22 +08:00
|
|
|
if (Index + SectionAddr < StartAddress ||
|
|
|
|
Index + SectionAddr > StopAddress) {
|
|
|
|
// skip byte by byte till StartAddress is reached
|
|
|
|
Size = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2015-10-02 05:57:09 +08:00
|
|
|
// AArch64 ELF binaries can interleave data and text in the
|
|
|
|
// same section. We rely on the markers introduced to
|
2016-08-26 03:41:08 +08:00
|
|
|
// understand what we need to dump. If the data marker is within a
|
|
|
|
// function, it is denoted as a word/short etc
|
|
|
|
if (isArmElf(Obj) && std::get<2>(Symbols[si]) != ELF::STT_OBJECT &&
|
|
|
|
!DisassembleAll) {
|
2015-10-02 05:57:09 +08:00
|
|
|
uint64_t Stride = 0;
|
|
|
|
|
|
|
|
auto DAI = std::lower_bound(DataMappingSymsAddr.begin(),
|
|
|
|
DataMappingSymsAddr.end(), Index);
|
|
|
|
if (DAI != DataMappingSymsAddr.end() && *DAI == Index) {
|
|
|
|
// Switch to data.
|
|
|
|
while (Index < End) {
|
|
|
|
outs() << format("%8" PRIx64 ":", SectionAddr + Index);
|
|
|
|
outs() << "\t";
|
|
|
|
if (Index + 4 <= End) {
|
|
|
|
Stride = 4;
|
|
|
|
dumpBytes(Bytes.slice(Index, 4), outs());
|
2016-08-26 03:41:08 +08:00
|
|
|
outs() << "\t.word\t";
|
|
|
|
uint32_t Data = 0;
|
|
|
|
if (Obj->isLittleEndian()) {
|
|
|
|
const auto Word =
|
|
|
|
reinterpret_cast<const support::ulittle32_t *>(
|
|
|
|
Bytes.data() + Index);
|
|
|
|
Data = *Word;
|
|
|
|
} else {
|
|
|
|
const auto Word = reinterpret_cast<const support::ubig32_t *>(
|
|
|
|
Bytes.data() + Index);
|
|
|
|
Data = *Word;
|
|
|
|
}
|
|
|
|
outs() << "0x" << format("%08" PRIx32, Data);
|
2015-10-02 05:57:09 +08:00
|
|
|
} else if (Index + 2 <= End) {
|
|
|
|
Stride = 2;
|
|
|
|
dumpBytes(Bytes.slice(Index, 2), outs());
|
2016-08-26 03:41:08 +08:00
|
|
|
outs() << "\t\t.short\t";
|
|
|
|
uint16_t Data = 0;
|
|
|
|
if (Obj->isLittleEndian()) {
|
|
|
|
const auto Short =
|
|
|
|
reinterpret_cast<const support::ulittle16_t *>(
|
|
|
|
Bytes.data() + Index);
|
|
|
|
Data = *Short;
|
|
|
|
} else {
|
|
|
|
const auto Short =
|
|
|
|
reinterpret_cast<const support::ubig16_t *>(Bytes.data() +
|
|
|
|
Index);
|
|
|
|
Data = *Short;
|
|
|
|
}
|
|
|
|
outs() << "0x" << format("%04" PRIx16, Data);
|
2015-10-02 05:57:09 +08:00
|
|
|
} else {
|
|
|
|
Stride = 1;
|
|
|
|
dumpBytes(Bytes.slice(Index, 1), outs());
|
2016-08-26 03:41:08 +08:00
|
|
|
outs() << "\t\t.byte\t";
|
|
|
|
outs() << "0x" << format("%02" PRIx8, Bytes.slice(Index, 1)[0]);
|
2015-10-02 05:57:09 +08:00
|
|
|
}
|
|
|
|
Index += Stride;
|
|
|
|
outs() << "\n";
|
|
|
|
auto TAI = std::lower_bound(TextMappingSymsAddr.begin(),
|
|
|
|
TextMappingSymsAddr.end(), Index);
|
|
|
|
if (TAI != TextMappingSymsAddr.end() && *TAI == Index)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-26 03:41:08 +08:00
|
|
|
// If there is a data symbol inside an ELF text section and we are only
|
|
|
|
// disassembling text (applicable all architectures),
|
|
|
|
// we are in a situation where we must print the data and not
|
|
|
|
// disassemble it.
|
|
|
|
if (Obj->isELF() && std::get<2>(Symbols[si]) == ELF::STT_OBJECT &&
|
|
|
|
!DisassembleAll && Section.isText()) {
|
|
|
|
// print out data up to 8 bytes at a time in hex and ascii
|
|
|
|
uint8_t AsciiData[9] = {'\0'};
|
|
|
|
uint8_t Byte;
|
|
|
|
int NumBytes = 0;
|
|
|
|
|
|
|
|
for (Index = Start; Index < End; Index += 1) {
|
2016-09-13 01:08:22 +08:00
|
|
|
if (((SectionAddr + Index) < StartAddress) ||
|
|
|
|
((SectionAddr + Index) > StopAddress))
|
|
|
|
continue;
|
2016-08-26 03:41:08 +08:00
|
|
|
if (NumBytes == 0) {
|
|
|
|
outs() << format("%8" PRIx64 ":", SectionAddr + Index);
|
|
|
|
outs() << "\t";
|
|
|
|
}
|
|
|
|
Byte = Bytes.slice(Index)[0];
|
|
|
|
outs() << format(" %02x", Byte);
|
2018-07-26 23:31:41 +08:00
|
|
|
AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.';
|
2016-08-26 03:41:08 +08:00
|
|
|
|
|
|
|
uint8_t IndentOffset = 0;
|
|
|
|
NumBytes++;
|
|
|
|
if (Index == End - 1 || NumBytes > 8) {
|
|
|
|
// Indent the space for less than 8 bytes data.
|
|
|
|
// 2 spaces for byte and one for space between bytes
|
|
|
|
IndentOffset = 3 * (8 - NumBytes);
|
|
|
|
for (int Excess = 8 - NumBytes; Excess < 8; Excess++)
|
|
|
|
AsciiData[Excess] = '\0';
|
|
|
|
NumBytes = 8;
|
|
|
|
}
|
|
|
|
if (NumBytes == 8) {
|
|
|
|
AsciiData[8] = '\0';
|
|
|
|
outs() << std::string(IndentOffset, ' ') << " ";
|
|
|
|
outs() << reinterpret_cast<char *>(AsciiData);
|
|
|
|
outs() << '\n';
|
|
|
|
NumBytes = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-02 05:57:09 +08:00
|
|
|
if (Index >= End)
|
|
|
|
break;
|
|
|
|
|
2016-08-26 03:41:08 +08:00
|
|
|
// Disassemble a real instruction or a data when disassemble all is
|
|
|
|
// provided
|
2016-03-19 00:26:48 +08:00
|
|
|
bool Disassembled = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
|
|
|
|
SectionAddr + Index, DebugOut,
|
|
|
|
CommentStream);
|
|
|
|
if (Size == 0)
|
|
|
|
Size = 1;
|
2016-08-16 03:49:24 +08:00
|
|
|
|
2016-03-19 00:26:48 +08:00
|
|
|
PIP.printInst(*IP, Disassembled ? &Inst : nullptr,
|
2016-08-16 03:49:24 +08:00
|
|
|
Bytes.slice(Index, Size), SectionAddr + Index, outs(), "",
|
2018-05-15 03:46:08 +08:00
|
|
|
*STI, &SP, &Rels);
|
2016-03-19 00:26:48 +08:00
|
|
|
outs() << CommentStream.str();
|
|
|
|
Comments.clear();
|
|
|
|
|
|
|
|
// Try to resolve the target of a call, tail call, etc. to a specific
|
|
|
|
// symbol.
|
|
|
|
if (MIA && (MIA->isCall(Inst) || MIA->isUnconditionalBranch(Inst) ||
|
|
|
|
MIA->isConditionalBranch(Inst))) {
|
|
|
|
uint64_t Target;
|
|
|
|
if (MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target)) {
|
|
|
|
// In a relocatable object, the target's section must reside in
|
|
|
|
// the same section as the call instruction or it is accessed
|
|
|
|
// through a relocation.
|
|
|
|
//
|
|
|
|
// In a non-relocatable object, the target may be in any section.
|
|
|
|
//
|
|
|
|
// N.B. We don't walk the relocations in the relocatable case yet.
|
|
|
|
auto *TargetSectionSymbols = &Symbols;
|
|
|
|
if (!Obj->isRelocatableObject()) {
|
|
|
|
auto SectionAddress = std::upper_bound(
|
|
|
|
SectionAddresses.begin(), SectionAddresses.end(), Target,
|
|
|
|
[](uint64_t LHS,
|
|
|
|
const std::pair<uint64_t, SectionRef> &RHS) {
|
|
|
|
return LHS < RHS.first;
|
|
|
|
});
|
|
|
|
if (SectionAddress != SectionAddresses.begin()) {
|
|
|
|
--SectionAddress;
|
|
|
|
TargetSectionSymbols = &AllSymbols[SectionAddress->second];
|
|
|
|
} else {
|
2018-06-29 02:57:13 +08:00
|
|
|
TargetSectionSymbols = &AbsoluteSymbols;
|
2015-11-18 10:49:19 +08:00
|
|
|
}
|
2016-03-19 00:26:48 +08:00
|
|
|
}
|
2015-11-18 10:49:19 +08:00
|
|
|
|
2016-03-19 00:26:48 +08:00
|
|
|
// Find the first symbol in the section whose offset is less than
|
2018-06-29 02:57:13 +08:00
|
|
|
// or equal to the target. If there isn't a section that contains
|
|
|
|
// the target, find the nearest preceding absolute symbol.
|
|
|
|
auto TargetSym = std::upper_bound(
|
|
|
|
TargetSectionSymbols->begin(), TargetSectionSymbols->end(),
|
|
|
|
Target, [](uint64_t LHS,
|
|
|
|
const std::tuple<uint64_t, StringRef, uint8_t> &RHS) {
|
|
|
|
return LHS < std::get<0>(RHS);
|
|
|
|
});
|
|
|
|
if (TargetSym == TargetSectionSymbols->begin()) {
|
|
|
|
TargetSectionSymbols = &AbsoluteSymbols;
|
|
|
|
TargetSym = std::upper_bound(
|
|
|
|
AbsoluteSymbols.begin(), AbsoluteSymbols.end(),
|
2016-03-19 00:26:48 +08:00
|
|
|
Target, [](uint64_t LHS,
|
2016-08-17 18:17:57 +08:00
|
|
|
const std::tuple<uint64_t, StringRef, uint8_t> &RHS) {
|
2018-06-29 02:57:13 +08:00
|
|
|
return LHS < std::get<0>(RHS);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (TargetSym != TargetSectionSymbols->begin()) {
|
|
|
|
--TargetSym;
|
|
|
|
uint64_t TargetAddress = std::get<0>(*TargetSym);
|
|
|
|
StringRef TargetName = std::get<1>(*TargetSym);
|
|
|
|
outs() << " <" << TargetName;
|
|
|
|
uint64_t Disp = Target - TargetAddress;
|
|
|
|
if (Disp)
|
|
|
|
outs() << "+0x" << Twine::utohexstr(Disp);
|
|
|
|
outs() << '>';
|
2015-07-08 06:06:59 +08:00
|
|
|
}
|
|
|
|
}
|
2011-07-21 03:37:35 +08:00
|
|
|
}
|
2016-03-19 00:26:48 +08:00
|
|
|
outs() << "\n";
|
2011-10-14 06:17:18 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
// Hexagon does this in pretty printer
|
|
|
|
if (Obj->getArch() != Triple::hexagon)
|
|
|
|
// Print relocation for instruction.
|
|
|
|
while (rel_cur != rel_end) {
|
|
|
|
bool hidden = getHidden(*rel_cur);
|
|
|
|
uint64_t addr = rel_cur->getOffset();
|
|
|
|
SmallString<16> name;
|
|
|
|
SmallString<32> val;
|
|
|
|
|
|
|
|
// If this relocation is hidden, skip it.
|
|
|
|
if (hidden || ((SectionAddr + addr) < StartAddress)) {
|
|
|
|
++rel_cur;
|
|
|
|
continue;
|
|
|
|
}
|
2011-10-26 04:35:53 +08:00
|
|
|
|
2018-05-15 03:46:08 +08:00
|
|
|
// Stop when rel_cur's address is past the current instruction.
|
|
|
|
if (addr >= Index + Size) break;
|
|
|
|
rel_cur->getTypeName(name);
|
|
|
|
error(getRelocationValueString(*rel_cur, val));
|
|
|
|
outs() << format(Fmt.data(), SectionAddr + addr) << name
|
|
|
|
<< "\t" << val << "\n";
|
2016-09-13 01:08:22 +08:00
|
|
|
++rel_cur;
|
|
|
|
}
|
2011-07-21 03:37:35 +08:00
|
|
|
}
|
2011-01-20 14:39:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-21 05:47:46 +08:00
|
|
|
void llvm::PrintRelocations(const ObjectFile *Obj) {
|
2014-03-21 06:55:15 +08:00
|
|
|
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 :
|
|
|
|
"%08" PRIx64;
|
2016-03-22 04:59:15 +08:00
|
|
|
// Regular objdump doesn't print relocations in non-relocatable object
|
|
|
|
// files.
|
|
|
|
if (!Obj->isRelocatableObject())
|
|
|
|
return;
|
2014-08-18 03:09:37 +08:00
|
|
|
|
2015-07-29 23:45:39 +08:00
|
|
|
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
|
2014-03-13 22:37:36 +08:00
|
|
|
if (Section.relocation_begin() == Section.relocation_end())
|
2011-10-08 08:18:30 +08:00
|
|
|
continue;
|
|
|
|
StringRef secname;
|
2015-08-05 15:18:31 +08:00
|
|
|
error(Section.getName(secname));
|
2011-10-08 08:18:30 +08:00
|
|
|
outs() << "RELOCATION RECORDS FOR [" << secname << "]:\n";
|
2014-03-14 22:22:49 +08:00
|
|
|
for (const RelocationRef &Reloc : Section.relocations()) {
|
2015-06-30 11:41:26 +08:00
|
|
|
bool hidden = getHidden(Reloc);
|
2015-06-30 07:29:12 +08:00
|
|
|
uint64_t address = Reloc.getOffset();
|
2011-10-08 08:18:30 +08:00
|
|
|
SmallString<32> relocname;
|
|
|
|
SmallString<32> valuestr;
|
2016-09-13 01:08:22 +08:00
|
|
|
if (address < StartAddress || address > StopAddress || hidden)
|
2014-03-14 22:22:49 +08:00
|
|
|
continue;
|
2015-06-30 12:08:37 +08:00
|
|
|
Reloc.getTypeName(relocname);
|
2015-08-05 15:18:31 +08:00
|
|
|
error(getRelocationValueString(Reloc, valuestr));
|
2014-03-21 06:55:15 +08:00
|
|
|
outs() << format(Fmt.data(), address) << " " << relocname << " "
|
|
|
|
<< valuestr << "\n";
|
2011-10-08 08:18:30 +08:00
|
|
|
}
|
|
|
|
outs() << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-07 21:30:55 +08:00
|
|
|
void llvm::PrintDynamicRelocations(const ObjectFile *Obj) {
|
|
|
|
|
|
|
|
// For the moment, this option is for ELF only
|
|
|
|
if (!Obj->isELF())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const auto *Elf = dyn_cast<ELFObjectFileBase>(Obj);
|
|
|
|
|
|
|
|
if (!Elf || Elf->getEType() != ELF::ET_DYN) {
|
|
|
|
error("not a dynamic object");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
|
|
|
|
|
|
|
|
std::vector<SectionRef> DynRelSec = Obj->dynamic_relocation_sections();
|
|
|
|
if (DynRelSec.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
outs() << "DYNAMIC RELOCATION RECORDS\n";
|
|
|
|
for (const SectionRef &Section : DynRelSec) {
|
|
|
|
if (Section.relocation_begin() == Section.relocation_end())
|
|
|
|
continue;
|
|
|
|
for (const RelocationRef &Reloc : Section.relocations()) {
|
|
|
|
uint64_t address = Reloc.getOffset();
|
|
|
|
SmallString<32> relocname;
|
|
|
|
SmallString<32> valuestr;
|
|
|
|
Reloc.getTypeName(relocname);
|
|
|
|
error(getRelocationValueString(Reloc, valuestr));
|
|
|
|
outs() << format(Fmt.data(), address) << " " << relocname << " "
|
|
|
|
<< valuestr << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-21 05:47:46 +08:00
|
|
|
void llvm::PrintSectionHeaders(const ObjectFile *Obj) {
|
2011-10-11 05:21:34 +08:00
|
|
|
outs() << "Sections:\n"
|
|
|
|
"Idx Name Size Address Type\n";
|
2015-07-29 23:45:39 +08:00
|
|
|
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
|
2011-10-11 05:21:34 +08:00
|
|
|
StringRef Name;
|
2015-08-05 15:18:31 +08:00
|
|
|
error(Section.getName(Name));
|
2014-10-08 23:28:58 +08:00
|
|
|
uint64_t Address = Section.getAddress();
|
|
|
|
uint64_t Size = Section.getSize();
|
|
|
|
bool Text = Section.isText();
|
|
|
|
bool Data = Section.isData();
|
|
|
|
bool BSS = Section.isBSS();
|
2011-10-11 05:21:34 +08:00
|
|
|
std::string Type = (std::string(Text ? "TEXT " : "") +
|
2011-10-14 04:37:20 +08:00
|
|
|
(Data ? "DATA " : "") + (BSS ? "BSS" : ""));
|
2018-07-18 16:34:35 +08:00
|
|
|
outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n",
|
2018-07-18 17:25:36 +08:00
|
|
|
(unsigned)Section.getIndex(), Name.str().c_str(), Size,
|
|
|
|
Address, Type.c_str());
|
2011-10-11 05:21:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-21 05:47:46 +08:00
|
|
|
void llvm::PrintSectionContents(const ObjectFile *Obj) {
|
2014-06-13 11:07:50 +08:00
|
|
|
std::error_code EC;
|
2015-07-29 23:45:39 +08:00
|
|
|
for (const SectionRef &Section : ToolSectionFilter(*Obj)) {
|
2011-10-18 01:13:22 +08:00
|
|
|
StringRef Name;
|
|
|
|
StringRef Contents;
|
2015-08-05 15:18:31 +08:00
|
|
|
error(Section.getName(Name));
|
2014-10-08 23:28:58 +08:00
|
|
|
uint64_t BaseAddr = Section.getAddress();
|
2014-11-11 17:58:25 +08:00
|
|
|
uint64_t Size = Section.getSize();
|
|
|
|
if (!Size)
|
|
|
|
continue;
|
2011-10-18 01:13:22 +08:00
|
|
|
|
|
|
|
outs() << "Contents of section " << Name << ":\n";
|
2014-11-11 17:58:25 +08:00
|
|
|
if (Section.isBSS()) {
|
2013-04-16 18:53:11 +08:00
|
|
|
outs() << format("<skipping contents of bss section at [%04" PRIx64
|
2014-07-15 00:20:14 +08:00
|
|
|
", %04" PRIx64 ")>\n",
|
|
|
|
BaseAddr, BaseAddr + Size);
|
2013-04-16 18:53:11 +08:00
|
|
|
continue;
|
|
|
|
}
|
2011-10-18 01:13:22 +08:00
|
|
|
|
2015-08-05 15:18:31 +08:00
|
|
|
error(Section.getContents(Contents));
|
2014-07-15 00:20:14 +08:00
|
|
|
|
2011-10-18 01:13:22 +08:00
|
|
|
// Dump out the content as hex and printable ascii characters.
|
|
|
|
for (std::size_t addr = 0, end = Contents.size(); addr < end; addr += 16) {
|
2012-03-10 10:04:38 +08:00
|
|
|
outs() << format(" %04" PRIx64 " ", BaseAddr + addr);
|
2011-10-18 01:13:22 +08:00
|
|
|
// Dump line of hex.
|
|
|
|
for (std::size_t i = 0; i < 16; ++i) {
|
|
|
|
if (i != 0 && i % 4 == 0)
|
|
|
|
outs() << ' ';
|
|
|
|
if (addr + i < end)
|
|
|
|
outs() << hexdigit((Contents[addr + i] >> 4) & 0xF, true)
|
|
|
|
<< hexdigit(Contents[addr + i] & 0xF, true);
|
|
|
|
else
|
|
|
|
outs() << " ";
|
|
|
|
}
|
|
|
|
// Print ascii.
|
|
|
|
outs() << " ";
|
|
|
|
for (std::size_t i = 0; i < 16 && addr + i < end; ++i) {
|
2018-07-26 23:31:41 +08:00
|
|
|
if (isPrint(static_cast<unsigned char>(Contents[addr + i]) & 0xFF))
|
2011-10-18 01:13:22 +08:00
|
|
|
outs() << Contents[addr + i];
|
|
|
|
else
|
|
|
|
outs() << ".";
|
|
|
|
}
|
|
|
|
outs() << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-01 04:35:34 +08:00
|
|
|
void llvm::PrintSymbolTable(const ObjectFile *o, StringRef ArchiveName,
|
|
|
|
StringRef ArchitectureName) {
|
2011-10-19 03:32:17 +08:00
|
|
|
outs() << "SYMBOL TABLE:\n";
|
|
|
|
|
2014-03-19 02:58:51 +08:00
|
|
|
if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o)) {
|
2015-12-20 17:54:34 +08:00
|
|
|
printCOFFSymbolTable(coff);
|
2014-03-19 02:58:51 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (const SymbolRef &Symbol : o->symbols()) {
|
2016-06-25 02:24:42 +08:00
|
|
|
Expected<uint64_t> AddressOrError = Symbol.getAddress();
|
|
|
|
if (!AddressOrError)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(ArchiveName, o->getFileName(), AddressOrError.takeError(),
|
|
|
|
ArchitectureName);
|
2015-07-04 02:19:00 +08:00
|
|
|
uint64_t Address = *AddressOrError;
|
2016-09-13 01:08:22 +08:00
|
|
|
if ((Address < StartAddress) || (Address > StopAddress))
|
|
|
|
continue;
|
2016-05-03 04:28:12 +08:00
|
|
|
Expected<SymbolRef::Type> TypeOrError = Symbol.getType();
|
|
|
|
if (!TypeOrError)
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(ArchiveName, o->getFileName(), TypeOrError.takeError(),
|
|
|
|
ArchitectureName);
|
2016-03-24 04:27:00 +08:00
|
|
|
SymbolRef::Type Type = *TypeOrError;
|
2014-03-19 02:58:51 +08:00
|
|
|
uint32_t Flags = Symbol.getFlags();
|
2016-05-03 04:28:12 +08:00
|
|
|
Expected<section_iterator> SectionOrErr = Symbol.getSection();
|
2016-11-17 06:17:38 +08:00
|
|
|
if (!SectionOrErr)
|
|
|
|
report_error(ArchiveName, o->getFileName(), SectionOrErr.takeError(),
|
|
|
|
ArchitectureName);
|
2015-08-08 07:27:14 +08:00
|
|
|
section_iterator Section = *SectionOrErr;
|
2015-06-03 13:14:22 +08:00
|
|
|
StringRef Name;
|
|
|
|
if (Type == SymbolRef::ST_Debug && Section != o->section_end()) {
|
|
|
|
Section->getName(Name);
|
2015-07-03 04:55:21 +08:00
|
|
|
} else {
|
2016-04-21 05:24:34 +08:00
|
|
|
Expected<StringRef> NameOrErr = Symbol.getName();
|
|
|
|
if (!NameOrErr)
|
2016-06-01 04:35:34 +08:00
|
|
|
report_error(ArchiveName, o->getFileName(), NameOrErr.takeError(),
|
|
|
|
ArchitectureName);
|
2015-07-03 04:55:21 +08:00
|
|
|
Name = *NameOrErr;
|
2015-06-03 13:14:22 +08:00
|
|
|
}
|
2011-10-19 03:32:17 +08:00
|
|
|
|
2014-03-19 02:58:51 +08:00
|
|
|
bool Global = Flags & SymbolRef::SF_Global;
|
|
|
|
bool Weak = Flags & SymbolRef::SF_Weak;
|
|
|
|
bool Absolute = Flags & SymbolRef::SF_Absolute;
|
2015-01-24 04:06:24 +08:00
|
|
|
bool Common = Flags & SymbolRef::SF_Common;
|
2015-05-01 07:08:53 +08:00
|
|
|
bool Hidden = Flags & SymbolRef::SF_Hidden;
|
2015-01-24 04:06:24 +08:00
|
|
|
|
2014-03-19 02:58:51 +08:00
|
|
|
char GlobLoc = ' ';
|
|
|
|
if (Type != SymbolRef::ST_Unknown)
|
|
|
|
GlobLoc = Global ? 'g' : 'l';
|
|
|
|
char Debug = (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File)
|
|
|
|
? 'd' : ' ';
|
|
|
|
char FileFunc = ' ';
|
|
|
|
if (Type == SymbolRef::ST_File)
|
|
|
|
FileFunc = 'f';
|
|
|
|
else if (Type == SymbolRef::ST_Function)
|
|
|
|
FileFunc = 'F';
|
|
|
|
|
|
|
|
const char *Fmt = o->getBytesInAddress() > 4 ? "%016" PRIx64 :
|
|
|
|
"%08" PRIx64;
|
|
|
|
|
|
|
|
outs() << format(Fmt, Address) << " "
|
|
|
|
<< GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' '
|
|
|
|
<< (Weak ? 'w' : ' ') // Weak?
|
|
|
|
<< ' ' // Constructor. Not supported yet.
|
|
|
|
<< ' ' // Warning. Not supported yet.
|
|
|
|
<< ' ' // Indirect reference to another symbol.
|
|
|
|
<< Debug // Debugging (d) or dynamic (D) symbol.
|
|
|
|
<< FileFunc // Name of function (F), file (f) or object (O).
|
|
|
|
<< ' ';
|
|
|
|
if (Absolute) {
|
|
|
|
outs() << "*ABS*";
|
2015-01-24 04:06:24 +08:00
|
|
|
} else if (Common) {
|
|
|
|
outs() << "*COM*";
|
2014-03-19 02:58:51 +08:00
|
|
|
} else if (Section == o->section_end()) {
|
|
|
|
outs() << "*UND*";
|
|
|
|
} else {
|
|
|
|
if (const MachOObjectFile *MachO =
|
|
|
|
dyn_cast<const MachOObjectFile>(o)) {
|
|
|
|
DataRefImpl DR = Section->getRawDataRefImpl();
|
|
|
|
StringRef SegmentName = MachO->getSectionFinalSegmentName(DR);
|
|
|
|
outs() << SegmentName << ",";
|
2011-10-19 03:32:17 +08:00
|
|
|
}
|
2014-03-19 02:58:51 +08:00
|
|
|
StringRef SectionName;
|
2015-08-05 15:18:31 +08:00
|
|
|
error(Section->getName(SectionName));
|
2014-03-19 02:58:51 +08:00
|
|
|
outs() << SectionName;
|
2011-10-19 03:32:17 +08:00
|
|
|
}
|
2015-06-23 23:45:38 +08:00
|
|
|
|
|
|
|
outs() << '\t';
|
2015-06-24 02:34:25 +08:00
|
|
|
if (Common || isa<ELFObjectFileBase>(o)) {
|
2015-06-26 06:10:04 +08:00
|
|
|
uint64_t Val =
|
|
|
|
Common ? Symbol.getAlignment() : ELFSymbolRef(Symbol).getSize();
|
2015-06-24 02:34:25 +08:00
|
|
|
outs() << format("\t %08" PRIx64 " ", Val);
|
|
|
|
}
|
2015-06-23 23:45:38 +08:00
|
|
|
|
2015-05-01 07:08:53 +08:00
|
|
|
if (Hidden) {
|
|
|
|
outs() << ".hidden ";
|
|
|
|
}
|
|
|
|
outs() << Name
|
2014-03-19 02:58:51 +08:00
|
|
|
<< '\n';
|
2011-10-19 03:32:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-06 04:12:35 +08:00
|
|
|
static void PrintUnwindInfo(const ObjectFile *o) {
|
|
|
|
outs() << "Unwind info:\n\n";
|
|
|
|
|
|
|
|
if (const COFFObjectFile *coff = dyn_cast<COFFObjectFile>(o)) {
|
|
|
|
printCOFFUnwindInfo(coff);
|
2014-08-01 21:07:19 +08:00
|
|
|
} else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
|
|
|
printMachOUnwindInfo(MachO);
|
|
|
|
else {
|
2012-12-06 04:12:35 +08:00
|
|
|
// TODO: Extract DWARF dump tool to objdump.
|
|
|
|
errs() << "This operation is only currently supported "
|
2014-08-01 21:07:19 +08:00
|
|
|
"for COFF and MachO object files.\n";
|
2012-12-06 04:12:35 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
void llvm::printExportsTrie(const ObjectFile *o) {
|
2014-08-30 08:20:14 +08:00
|
|
|
outs() << "Exports trie:\n";
|
|
|
|
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
|
|
|
printMachOExportsTrie(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-21 03:46:55 +08:00
|
|
|
void llvm::printRebaseTable(ObjectFile *o) {
|
2014-09-13 05:34:15 +08:00
|
|
|
outs() << "Rebase table:\n";
|
2017-03-21 03:46:55 +08:00
|
|
|
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
2014-09-13 05:34:15 +08:00
|
|
|
printMachORebaseTable(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-21 03:46:55 +08:00
|
|
|
void llvm::printBindTable(ObjectFile *o) {
|
2014-09-16 09:41:51 +08:00
|
|
|
outs() << "Bind table:\n";
|
2017-03-21 03:46:55 +08:00
|
|
|
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
2014-09-16 09:41:51 +08:00
|
|
|
printMachOBindTable(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-21 03:46:55 +08:00
|
|
|
void llvm::printLazyBindTable(ObjectFile *o) {
|
2014-09-16 09:41:51 +08:00
|
|
|
outs() << "Lazy bind table:\n";
|
2017-03-21 03:46:55 +08:00
|
|
|
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
2014-09-16 09:41:51 +08:00
|
|
|
printMachOLazyBindTable(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-21 03:46:55 +08:00
|
|
|
void llvm::printWeakBindTable(ObjectFile *o) {
|
2014-09-16 09:41:51 +08:00
|
|
|
outs() << "Weak bind table:\n";
|
2017-03-21 03:46:55 +08:00
|
|
|
if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
2014-09-16 09:41:51 +08:00
|
|
|
printMachOWeakBindTable(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-09-13 05:34:15 +08:00
|
|
|
|
2015-07-08 10:04:15 +08:00
|
|
|
/// Dump the raw contents of the __clangast section so the output can be piped
|
|
|
|
/// into llvm-bcanalyzer.
|
|
|
|
void llvm::printRawClangAST(const ObjectFile *Obj) {
|
|
|
|
if (outs().is_displayed()) {
|
|
|
|
errs() << "The -raw-clang-ast option will dump the raw binary contents of "
|
|
|
|
"the clang ast section.\n"
|
|
|
|
"Please redirect the output to a file or another program such as "
|
|
|
|
"llvm-bcanalyzer.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ClangASTSectionName("__clangast");
|
|
|
|
if (isa<COFFObjectFile>(Obj)) {
|
|
|
|
ClangASTSectionName = "clangast";
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<object::SectionRef> ClangASTSection;
|
2015-07-29 23:45:39 +08:00
|
|
|
for (auto Sec : ToolSectionFilter(*Obj)) {
|
2015-07-08 10:04:15 +08:00
|
|
|
StringRef Name;
|
|
|
|
Sec.getName(Name);
|
|
|
|
if (Name == ClangASTSectionName) {
|
|
|
|
ClangASTSection = Sec;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ClangASTSection)
|
|
|
|
return;
|
|
|
|
|
|
|
|
StringRef ClangASTContents;
|
2015-08-05 15:18:31 +08:00
|
|
|
error(ClangASTSection.getValue().getContents(ClangASTContents));
|
2015-07-08 10:04:15 +08:00
|
|
|
outs().write(ClangASTContents.data(), ClangASTContents.size());
|
|
|
|
}
|
|
|
|
|
2015-06-23 02:03:02 +08:00
|
|
|
static void printFaultMaps(const ObjectFile *Obj) {
|
|
|
|
const char *FaultMapSectionName = nullptr;
|
|
|
|
|
|
|
|
if (isa<ELFObjectFileBase>(Obj)) {
|
|
|
|
FaultMapSectionName = ".llvm_faultmaps";
|
|
|
|
} else if (isa<MachOObjectFile>(Obj)) {
|
|
|
|
FaultMapSectionName = "__llvm_faultmaps";
|
|
|
|
} else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for ELF and Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<object::SectionRef> FaultMapSection;
|
|
|
|
|
2015-07-29 23:45:39 +08:00
|
|
|
for (auto Sec : ToolSectionFilter(*Obj)) {
|
2015-06-23 02:03:02 +08:00
|
|
|
StringRef Name;
|
|
|
|
Sec.getName(Name);
|
|
|
|
if (Name == FaultMapSectionName) {
|
|
|
|
FaultMapSection = Sec;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
outs() << "FaultMap table:\n";
|
|
|
|
|
|
|
|
if (!FaultMapSection.hasValue()) {
|
|
|
|
outs() << "<not found>\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef FaultMapContents;
|
2015-08-05 15:18:31 +08:00
|
|
|
error(FaultMapSection.getValue().getContents(FaultMapContents));
|
2015-06-23 02:03:02 +08:00
|
|
|
|
|
|
|
FaultMapParser FMP(FaultMapContents.bytes_begin(),
|
|
|
|
FaultMapContents.bytes_end());
|
|
|
|
|
|
|
|
outs() << FMP;
|
|
|
|
}
|
|
|
|
|
2016-09-18 12:39:15 +08:00
|
|
|
static void printPrivateFileHeaders(const ObjectFile *o, bool onlyFirst) {
|
2018-07-25 19:09:20 +08:00
|
|
|
if (o->isELF()) {
|
|
|
|
printELFFileHeader(o);
|
|
|
|
return printELFDynamicSection(o);
|
|
|
|
}
|
2016-09-18 12:39:15 +08:00
|
|
|
if (o->isCOFF())
|
|
|
|
return printCOFFFileHeader(o);
|
2016-12-01 00:49:11 +08:00
|
|
|
if (o->isWasm())
|
|
|
|
return printWasmFileHeader(o);
|
2016-09-18 12:39:15 +08:00
|
|
|
if (o->isMachO()) {
|
2016-01-13 08:25:36 +08:00
|
|
|
printMachOFileHeader(o);
|
2016-09-18 12:39:15 +08:00
|
|
|
if (!onlyFirst)
|
|
|
|
printMachOLoadCommands(o);
|
|
|
|
return;
|
|
|
|
}
|
2016-11-17 06:17:38 +08:00
|
|
|
report_error(o->getFileName(), "Invalid/Unsupported object file format");
|
2013-09-28 05:04:00 +08:00
|
|
|
}
|
|
|
|
|
2018-07-04 23:25:03 +08:00
|
|
|
static void printFileHeaders(const ObjectFile *o) {
|
|
|
|
if (!o->isELF() && !o->isCOFF())
|
|
|
|
report_error(o->getFileName(), "Invalid/Unsupported object file format");
|
|
|
|
|
|
|
|
Triple::ArchType AT = o->getArch();
|
|
|
|
outs() << "architecture: " << Triple::getArchTypeName(AT) << "\n";
|
|
|
|
Expected<uint64_t> StartAddrOrErr = o->getStartAddress();
|
|
|
|
if (!StartAddrOrErr)
|
|
|
|
report_error(o->getFileName(), StartAddrOrErr.takeError());
|
2018-10-20 06:16:49 +08:00
|
|
|
|
|
|
|
StringRef Fmt = o->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64;
|
|
|
|
uint64_t Address = StartAddrOrErr.get();
|
2018-07-04 23:25:03 +08:00
|
|
|
outs() << "start address: "
|
2018-10-20 06:16:49 +08:00
|
|
|
<< "0x" << format(Fmt.data(), Address)
|
2018-07-04 23:25:03 +08:00
|
|
|
<< "\n";
|
|
|
|
}
|
|
|
|
|
2018-07-05 22:43:29 +08:00
|
|
|
static void printArchiveChild(StringRef Filename, const Archive::Child &C) {
|
|
|
|
Expected<sys::fs::perms> ModeOrErr = C.getAccessMode();
|
|
|
|
if (!ModeOrErr) {
|
|
|
|
errs() << "ill-formed archive entry.\n";
|
|
|
|
consumeError(ModeOrErr.takeError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sys::fs::perms Mode = ModeOrErr.get();
|
|
|
|
outs() << ((Mode & sys::fs::owner_read) ? "r" : "-");
|
|
|
|
outs() << ((Mode & sys::fs::owner_write) ? "w" : "-");
|
|
|
|
outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-");
|
|
|
|
outs() << ((Mode & sys::fs::group_read) ? "r" : "-");
|
|
|
|
outs() << ((Mode & sys::fs::group_write) ? "w" : "-");
|
|
|
|
outs() << ((Mode & sys::fs::group_exe) ? "x" : "-");
|
|
|
|
outs() << ((Mode & sys::fs::others_read) ? "r" : "-");
|
|
|
|
outs() << ((Mode & sys::fs::others_write) ? "w" : "-");
|
|
|
|
outs() << ((Mode & sys::fs::others_exe) ? "x" : "-");
|
|
|
|
|
|
|
|
outs() << " ";
|
|
|
|
|
|
|
|
Expected<unsigned> UIDOrErr = C.getUID();
|
|
|
|
if (!UIDOrErr)
|
|
|
|
report_error(Filename, UIDOrErr.takeError());
|
|
|
|
unsigned UID = UIDOrErr.get();
|
|
|
|
outs() << format("%d/", UID);
|
|
|
|
|
|
|
|
Expected<unsigned> GIDOrErr = C.getGID();
|
|
|
|
if (!GIDOrErr)
|
|
|
|
report_error(Filename, GIDOrErr.takeError());
|
|
|
|
unsigned GID = GIDOrErr.get();
|
|
|
|
outs() << format("%-d ", GID);
|
|
|
|
|
|
|
|
Expected<uint64_t> Size = C.getRawSize();
|
|
|
|
if (!Size)
|
|
|
|
report_error(Filename, Size.takeError());
|
|
|
|
outs() << format("%6" PRId64, Size.get()) << " ";
|
|
|
|
|
|
|
|
StringRef RawLastModified = C.getRawLastModified();
|
|
|
|
unsigned Seconds;
|
|
|
|
if (RawLastModified.getAsInteger(10, Seconds))
|
|
|
|
outs() << "(date: \"" << RawLastModified
|
|
|
|
<< "\" contains non-decimal chars) ";
|
|
|
|
else {
|
|
|
|
// Since ctime(3) returns a 26 character string of the form:
|
|
|
|
// "Sun Sep 16 01:03:52 1973\n\0"
|
|
|
|
// just print 24 characters.
|
|
|
|
time_t t = Seconds;
|
|
|
|
outs() << format("%.24s ", ctime(&t));
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef Name = "";
|
|
|
|
Expected<StringRef> NameOrErr = C.getName();
|
|
|
|
if (!NameOrErr) {
|
|
|
|
consumeError(NameOrErr.takeError());
|
|
|
|
Expected<StringRef> RawNameOrErr = C.getRawName();
|
|
|
|
if (!RawNameOrErr)
|
|
|
|
report_error(Filename, NameOrErr.takeError());
|
|
|
|
Name = RawNameOrErr.get();
|
|
|
|
} else {
|
|
|
|
Name = NameOrErr.get();
|
|
|
|
}
|
|
|
|
outs() << Name << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpObject(ObjectFile *o, const Archive *a = nullptr,
|
|
|
|
const Archive::Child *c = nullptr) {
|
2016-05-18 01:10:12 +08:00
|
|
|
StringRef ArchiveName = a != nullptr ? a->getFileName() : "";
|
2015-07-08 10:04:15 +08:00
|
|
|
// Avoid other output when using a raw option.
|
|
|
|
if (!RawClangAST) {
|
|
|
|
outs() << '\n';
|
2016-05-18 01:10:12 +08:00
|
|
|
if (a)
|
|
|
|
outs() << a->getFileName() << "(" << o->getFileName() << ")";
|
|
|
|
else
|
|
|
|
outs() << o->getFileName();
|
|
|
|
outs() << ":\tfile format " << o->getFileFormatName() << "\n\n";
|
2015-07-08 10:04:15 +08:00
|
|
|
}
|
2011-10-18 01:13:22 +08:00
|
|
|
|
2018-10-29 22:17:08 +08:00
|
|
|
if (ArchiveHeaders && !MachOOpt && c)
|
|
|
|
printArchiveChild(ArchiveName, *c);
|
2011-10-08 08:18:30 +08:00
|
|
|
if (Disassemble)
|
2011-10-14 06:17:18 +08:00
|
|
|
DisassembleObject(o, Relocations);
|
|
|
|
if (Relocations && !Disassemble)
|
2011-10-08 08:18:30 +08:00
|
|
|
PrintRelocations(o);
|
2018-06-07 21:30:55 +08:00
|
|
|
if (DynamicRelocations)
|
|
|
|
PrintDynamicRelocations(o);
|
2011-10-11 05:21:34 +08:00
|
|
|
if (SectionHeaders)
|
|
|
|
PrintSectionHeaders(o);
|
2011-10-18 01:13:22 +08:00
|
|
|
if (SectionContents)
|
|
|
|
PrintSectionContents(o);
|
2011-10-19 03:32:17 +08:00
|
|
|
if (SymbolTable)
|
2016-05-18 01:10:12 +08:00
|
|
|
PrintSymbolTable(o, ArchiveName);
|
2012-12-06 04:12:35 +08:00
|
|
|
if (UnwindInfo)
|
|
|
|
PrintUnwindInfo(o);
|
2016-09-18 12:39:15 +08:00
|
|
|
if (PrivateHeaders || FirstPrivateHeader)
|
|
|
|
printPrivateFileHeaders(o, FirstPrivateHeader);
|
2018-07-04 23:25:03 +08:00
|
|
|
if (FileHeaders)
|
|
|
|
printFileHeaders(o);
|
2014-08-30 08:20:14 +08:00
|
|
|
if (ExportsTrie)
|
|
|
|
printExportsTrie(o);
|
2014-09-13 05:34:15 +08:00
|
|
|
if (Rebase)
|
|
|
|
printRebaseTable(o);
|
2014-09-16 09:41:51 +08:00
|
|
|
if (Bind)
|
|
|
|
printBindTable(o);
|
|
|
|
if (LazyBind)
|
|
|
|
printLazyBindTable(o);
|
|
|
|
if (WeakBind)
|
|
|
|
printWeakBindTable(o);
|
2015-07-08 10:04:15 +08:00
|
|
|
if (RawClangAST)
|
|
|
|
printRawClangAST(o);
|
2015-06-23 02:03:02 +08:00
|
|
|
if (PrintFaultMaps)
|
|
|
|
printFaultMaps(o);
|
2016-01-26 23:09:42 +08:00
|
|
|
if (DwarfDumpType != DIDT_Null) {
|
2017-07-20 06:27:28 +08:00
|
|
|
std::unique_ptr<DIContext> DICtx = DWARFContext::create(*o);
|
2016-01-26 23:09:42 +08:00
|
|
|
// Dump the complete DWARF structure.
|
2017-06-02 02:18:23 +08:00
|
|
|
DIDumpOptions DumpOpts;
|
|
|
|
DumpOpts.DumpType = DwarfDumpType;
|
|
|
|
DICtx->dump(outs(), DumpOpts);
|
2016-01-26 23:09:42 +08:00
|
|
|
}
|
2011-10-08 08:18:30 +08:00
|
|
|
}
|
|
|
|
|
2018-07-05 22:43:29 +08:00
|
|
|
static void DumpObject(const COFFImportFile *I, const Archive *A,
|
|
|
|
const Archive::Child *C = nullptr) {
|
2016-08-19 00:39:19 +08:00
|
|
|
StringRef ArchiveName = A ? A->getFileName() : "";
|
|
|
|
|
|
|
|
// Avoid other output when using a raw option.
|
|
|
|
if (!RawClangAST)
|
|
|
|
outs() << '\n'
|
|
|
|
<< ArchiveName << "(" << I->getFileName() << ")"
|
|
|
|
<< ":\tfile format COFF-import-file"
|
|
|
|
<< "\n\n";
|
|
|
|
|
2018-10-29 22:17:08 +08:00
|
|
|
if (ArchiveHeaders && !MachOOpt && C)
|
|
|
|
printArchiveChild(ArchiveName, *C);
|
2016-08-19 00:39:19 +08:00
|
|
|
if (SymbolTable)
|
|
|
|
printCOFFSymbolTable(I);
|
|
|
|
}
|
|
|
|
|
2018-05-02 00:10:38 +08:00
|
|
|
/// Dump each object file in \a a;
|
2011-10-08 08:18:30 +08:00
|
|
|
static void DumpArchive(const Archive *a) {
|
2016-11-11 12:28:40 +08:00
|
|
|
Error Err = Error::success();
|
2016-07-14 10:24:01 +08:00
|
|
|
for (auto &C : a->children(Err)) {
|
2016-05-18 01:10:12 +08:00
|
|
|
Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
|
|
|
|
if (!ChildOrErr) {
|
|
|
|
if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
|
|
|
|
report_error(a->getFileName(), C, std::move(E));
|
|
|
|
continue;
|
|
|
|
}
|
2014-06-17 00:08:36 +08:00
|
|
|
if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
|
2018-07-05 22:43:29 +08:00
|
|
|
DumpObject(o, a, &C);
|
2016-08-19 00:39:19 +08:00
|
|
|
else if (COFFImportFile *I = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))
|
2018-07-05 22:43:29 +08:00
|
|
|
DumpObject(I, a, &C);
|
2011-10-08 08:18:30 +08:00
|
|
|
else
|
2015-06-05 02:34:11 +08:00
|
|
|
report_error(a->getFileName(), object_error::invalid_file_type);
|
2011-10-08 08:18:30 +08:00
|
|
|
}
|
2016-07-14 10:24:01 +08:00
|
|
|
if (Err)
|
|
|
|
report_error(a->getFileName(), std::move(Err));
|
2011-10-08 08:18:30 +08:00
|
|
|
}
|
|
|
|
|
2018-05-02 00:10:38 +08:00
|
|
|
/// Open file and figure out how to dump it.
|
2011-10-08 08:18:30 +08:00
|
|
|
static void DumpInput(StringRef file) {
|
|
|
|
|
2015-01-08 05:02:18 +08:00
|
|
|
// If we are using the Mach-O specific object file parser, then let it parse
|
|
|
|
// the file and process the command line options. So the -arch flags can
|
|
|
|
// be used to select specific slices, etc.
|
|
|
|
if (MachOOpt) {
|
|
|
|
ParseInputMachO(file);
|
2011-10-08 08:18:30 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to open the binary.
|
2016-04-07 06:14:09 +08:00
|
|
|
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
|
|
|
|
if (!BinaryOrErr)
|
2016-05-06 01:43:35 +08:00
|
|
|
report_error(file, BinaryOrErr.takeError());
|
2014-08-20 02:44:46 +08:00
|
|
|
Binary &Binary = *BinaryOrErr.get().getBinary();
|
2011-10-08 08:18:30 +08:00
|
|
|
|
2014-08-01 22:31:55 +08:00
|
|
|
if (Archive *a = dyn_cast<Archive>(&Binary))
|
2011-10-08 08:18:30 +08:00
|
|
|
DumpArchive(a);
|
2014-08-01 22:31:55 +08:00
|
|
|
else if (ObjectFile *o = dyn_cast<ObjectFile>(&Binary))
|
2011-10-08 08:18:30 +08:00
|
|
|
DumpObject(o);
|
2018-08-03 08:06:38 +08:00
|
|
|
else if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Binary))
|
|
|
|
ParseInputMachO(UB);
|
2012-08-08 01:53:14 +08:00
|
|
|
else
|
2015-06-05 02:34:11 +08:00
|
|
|
report_error(file, object_error::invalid_file_type);
|
2011-10-08 08:18:30 +08:00
|
|
|
}
|
|
|
|
|
2011-01-20 14:39:06 +08:00
|
|
|
int main(int argc, char **argv) {
|
2018-04-14 02:26:06 +08:00
|
|
|
InitLLVM X(argc, argv);
|
2011-01-20 14:39:06 +08:00
|
|
|
|
|
|
|
// Initialize targets and assembly printers/parsers.
|
|
|
|
llvm::InitializeAllTargetInfos();
|
2011-07-23 05:58:54 +08:00
|
|
|
llvm::InitializeAllTargetMCs();
|
2011-01-20 14:39:06 +08:00
|
|
|
llvm::InitializeAllDisassemblers();
|
|
|
|
|
2012-05-04 07:20:10 +08:00
|
|
|
// Register the target printer for --version.
|
|
|
|
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
|
|
|
|
|
2011-01-20 14:39:06 +08:00
|
|
|
cl::ParseCommandLineOptions(argc, argv, "llvm object file dumper\n");
|
|
|
|
|
|
|
|
ToolName = argv[0];
|
|
|
|
|
|
|
|
// Defaults to a.out if no filenames specified.
|
|
|
|
if (InputFilenames.size() == 0)
|
|
|
|
InputFilenames.push_back("a.out");
|
|
|
|
|
2018-06-28 04:45:11 +08:00
|
|
|
if (AllHeaders)
|
|
|
|
PrivateHeaders = Relocations = SectionHeaders = SymbolTable = true;
|
|
|
|
|
2016-08-16 03:49:24 +08:00
|
|
|
if (DisassembleAll || PrintSource || PrintLines)
|
2015-07-24 04:58:49 +08:00
|
|
|
Disassemble = true;
|
2018-07-19 00:39:21 +08:00
|
|
|
|
2011-10-19 03:32:17 +08:00
|
|
|
if (!Disassemble
|
|
|
|
&& !Relocations
|
2018-06-07 21:30:55 +08:00
|
|
|
&& !DynamicRelocations
|
2011-10-19 03:32:17 +08:00
|
|
|
&& !SectionHeaders
|
|
|
|
&& !SectionContents
|
2012-12-06 04:12:35 +08:00
|
|
|
&& !SymbolTable
|
2013-01-06 11:56:49 +08:00
|
|
|
&& !UnwindInfo
|
2014-08-30 08:20:14 +08:00
|
|
|
&& !PrivateHeaders
|
2018-07-04 23:25:03 +08:00
|
|
|
&& !FileHeaders
|
2016-01-13 08:25:36 +08:00
|
|
|
&& !FirstPrivateHeader
|
2014-09-13 05:34:15 +08:00
|
|
|
&& !ExportsTrie
|
2014-09-16 09:41:51 +08:00
|
|
|
&& !Rebase
|
|
|
|
&& !Bind
|
|
|
|
&& !LazyBind
|
2015-01-10 03:22:37 +08:00
|
|
|
&& !WeakBind
|
2015-07-08 10:04:15 +08:00
|
|
|
&& !RawClangAST
|
2015-01-16 07:19:11 +08:00
|
|
|
&& !(UniversalHeaders && MachOOpt)
|
2018-07-05 22:43:29 +08:00
|
|
|
&& !ArchiveHeaders
|
2015-01-24 02:52:17 +08:00
|
|
|
&& !(IndirectSymbols && MachOOpt)
|
2015-01-28 05:28:24 +08:00
|
|
|
&& !(DataInCode && MachOOpt)
|
2015-01-31 08:37:11 +08:00
|
|
|
&& !(LinkOptHints && MachOOpt)
|
2015-03-12 06:06:32 +08:00
|
|
|
&& !(InfoPlist && MachOOpt)
|
2015-03-17 04:08:09 +08:00
|
|
|
&& !(DylibsUsed && MachOOpt)
|
|
|
|
&& !(DylibId && MachOOpt)
|
2015-04-02 04:57:01 +08:00
|
|
|
&& !(ObjcMetaData && MachOOpt)
|
2015-07-30 03:08:10 +08:00
|
|
|
&& !(FilterSections.size() != 0 && MachOOpt)
|
2016-01-26 23:09:42 +08:00
|
|
|
&& !PrintFaultMaps
|
|
|
|
&& DwarfDumpType == DIDT_Null) {
|
2011-01-20 14:39:06 +08:00
|
|
|
cl::PrintHelpMessage();
|
2017-12-19 03:46:56 +08:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2018-03-10 03:13:44 +08:00
|
|
|
DisasmFuncsSet.insert(DisassembleFunctions.begin(),
|
|
|
|
DisassembleFunctions.end());
|
|
|
|
|
2017-12-19 03:46:56 +08:00
|
|
|
llvm::for_each(InputFilenames, DumpInput);
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|