2011-01-20 06:39:06 +00: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-05 20:27:22 +00:00
|
|
|
// The flags and output of this program should be near identical to those of
|
|
|
|
// binutils objdump.
|
|
|
|
//
|
2011-01-20 06:39:06 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-09-19 17:56:04 +00:00
|
|
|
#include "llvm-objdump.h"
|
2012-12-04 10:44:52 +00:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2011-10-17 17:13:22 +00:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2011-01-20 06:39:06 +00:00
|
|
|
#include "llvm/ADT/Triple.h"
|
|
|
|
#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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2011-01-20 06:39:06 +00:00
|
|
|
#include "llvm/MC/MCDisassembler.h"
|
|
|
|
#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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182628 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 01:07:04 +00:00
|
|
|
#include "llvm/MC/MCInstrAnalysis.h"
|
2012-04-02 06:09:36 +00: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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
#include "llvm/MC/MCObjectFileInfo.h"
|
2012-03-05 19:33:20 +00:00
|
|
|
#include "llvm/MC/MCRegisterInfo.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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
#include "llvm/MC/MCRelocationInfo.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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182628 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 01:07:04 +00:00
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2012-12-04 10:44:52 +00:00
|
|
|
#include "llvm/Object/Archive.h"
|
|
|
|
#include "llvm/Object/COFF.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 :-)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170838 91177308-0d34-0410-b5e6-96231b3b80d8
2012-12-21 03:47:03 +00:00
|
|
|
#include "llvm/Object/MachO.h"
|
2012-12-04 10:44:52 +00:00
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2011-10-08 00:18:30 +00:00
|
|
|
#include "llvm/Support/Casting.h"
|
2011-01-20 06:39:06 +00:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
2011-10-08 00:18:30 +00:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2011-01-20 06:39:06 +00:00
|
|
|
#include "llvm/Support/Format.h"
|
2011-07-25 23:04:36 +00:00
|
|
|
#include "llvm/Support/GraphWriter.h"
|
2011-01-20 06:39:06 +00:00
|
|
|
#include "llvm/Support/Host.h"
|
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
|
|
|
#include "llvm/Support/Signals.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2011-08-24 18:08:43 +00:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2011-01-20 06:39:06 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <algorithm>
|
2012-03-23 11:49:32 +00:00
|
|
|
#include <cctype>
|
2011-01-20 06:39:06 +00:00
|
|
|
#include <cstring>
|
2014-06-12 17:38:55 +00:00
|
|
|
#include <system_error>
|
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>
...
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188890 91177308-0d34-0410-b5e6-96231b3b80d8
2013-08-21 07:29:02 +00:00
|
|
|
|
2011-01-20 06:39:06 +00:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace object;
|
|
|
|
|
2011-09-19 17:56:04 +00:00
|
|
|
static cl::list<std::string>
|
|
|
|
InputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore);
|
2011-01-20 06:39:06 +00:00
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::Disassemble("disassemble",
|
2011-09-19 17:56:04 +00:00
|
|
|
cl::desc("Display assembler mnemonics for the machine instructions"));
|
|
|
|
static cl::alias
|
|
|
|
Disassembled("d", cl::desc("Alias for --disassemble"),
|
|
|
|
cl::aliasopt(Disassemble));
|
2011-01-20 06:39:06 +00:00
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::Relocations("r", cl::desc("Display the relocation entries in the file"));
|
2011-10-08 00:18:30 +00:00
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::SectionContents("s", cl::desc("Display the content of each section"));
|
2011-10-17 17:13:22 +00:00
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::SymbolTable("t", cl::desc("Display the symbol table"));
|
2011-10-18 19:32:17 +00:00
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
|
2014-08-30 00:20:14 +00:00
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::Rebase("rebase", cl::desc("Display mach-o rebasing info"));
|
2014-09-12 21:34:15 +00:00
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::Bind("bind", cl::desc("Display mach-o binding info"));
|
2014-09-16 01:41:51 +00:00
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info"));
|
2014-09-16 01:41:51 +00:00
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::WeakBind("weak-bind", cl::desc("Display mach-o weak binding info"));
|
2014-09-16 01:41:51 +00:00
|
|
|
|
2011-09-19 17:56:04 +00: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 :-)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170838 91177308-0d34-0410-b5e6-96231b3b80d8
2012-12-21 03:47:03 +00:00
|
|
|
MachOOpt("macho", cl::desc("Use MachO specific object file parser"));
|
2011-09-19 17:56:04 +00: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 :-)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170838 91177308-0d34-0410-b5e6-96231b3b80d8
2012-12-21 03:47:03 +00:00
|
|
|
MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachOOpt));
|
2011-07-20 19:37:35 +00:00
|
|
|
|
2011-09-19 17:56:04 +00:00
|
|
|
cl::opt<std::string>
|
|
|
|
llvm::TripleName("triple", cl::desc("Target triple to disassemble for, "
|
|
|
|
"see -version for available targets"));
|
2011-01-20 06:39:06 +00:00
|
|
|
|
2014-08-06 23:24:41 +00: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-19 17:56:04 +00:00
|
|
|
cl::opt<std::string>
|
2014-12-04 23:56:27 +00:00
|
|
|
llvm::ArchName("arch-name", cl::desc("Target arch to disassemble for, "
|
2011-09-19 17:56:04 +00:00
|
|
|
"see -version for available targets"));
|
2011-01-20 06:39:06 +00:00
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::SectionHeaders("section-headers", cl::desc("Display summaries of the "
|
|
|
|
"headers for each section."));
|
2011-10-10 21:21:34 +00: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));
|
|
|
|
|
2014-08-06 23:24:41 +00:00
|
|
|
cl::list<std::string>
|
|
|
|
llvm::MAttrs("mattr",
|
2012-08-28 19:24:49 +00:00
|
|
|
cl::CommaSeparated,
|
|
|
|
cl::desc("Target specific attributes"),
|
|
|
|
cl::value_desc("a1,+a2,-a3,..."));
|
|
|
|
|
2014-09-24 23:08:22 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling "
|
|
|
|
"instructions, do not print "
|
|
|
|
"the instruction bytes."));
|
2012-11-20 22:57:02 +00:00
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information"));
|
2012-12-05 20:12:35 +00:00
|
|
|
|
|
|
|
static cl::alias
|
|
|
|
UnwindInfoShort("u", cl::desc("Alias for --unwind-info"),
|
|
|
|
cl::aliasopt(UnwindInfo));
|
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
cl::opt<bool>
|
|
|
|
llvm::PrivateHeaders("private-headers",
|
|
|
|
cl::desc("Display format specific file headers"));
|
2013-01-06 03:56:49 +00:00
|
|
|
|
|
|
|
static cl::alias
|
|
|
|
PrivateHeadersShort("p", cl::desc("Alias for --private-headers"),
|
|
|
|
cl::aliasopt(PrivateHeaders));
|
|
|
|
|
2011-09-19 17:56:04 +00:00
|
|
|
static StringRef ToolName;
|
2014-11-26 22:17:25 +00:00
|
|
|
static int ReturnValue = EXIT_SUCCESS;
|
2011-06-25 17:55:23 +00:00
|
|
|
|
2014-06-13 03:07:50 +00:00
|
|
|
bool llvm::error(std::error_code EC) {
|
2014-01-25 00:32:01 +00:00
|
|
|
if (!EC)
|
|
|
|
return false;
|
2011-06-25 17:55:23 +00:00
|
|
|
|
2014-01-25 00:32:01 +00:00
|
|
|
outs() << ToolName << ": error reading file: " << EC.message() << ".\n";
|
2011-09-19 17:56:04 +00:00
|
|
|
outs().flush();
|
2014-11-26 22:17:25 +00:00
|
|
|
ReturnValue = EXIT_FAILURE;
|
2011-09-19 17:56:04 +00:00
|
|
|
return true;
|
2011-01-20 06:39:06 +00:00
|
|
|
}
|
|
|
|
|
2014-04-25 04:24:47 +00:00
|
|
|
static const Target *getTarget(const ObjectFile *Obj = nullptr) {
|
2011-01-20 06:39:06 +00:00
|
|
|
// Figure out the target triple.
|
2012-05-08 23:38:45 +00:00
|
|
|
llvm::Triple TheTriple("unknown-unknown-unknown");
|
2011-01-20 07:22:04 +00: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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
if (Obj) {
|
2012-05-08 23:38:45 +00:00
|
|
|
TheTriple.setArch(Triple::ArchType(Obj->getArch()));
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
// TheTriple defaults to ELF, and COFF doesn't have an environment:
|
|
|
|
// the best we can do here is indicate that it is mach-o.
|
|
|
|
if (Obj->isMachO())
|
2014-03-06 20:47:11 +00:00
|
|
|
TheTriple.setObjectFormat(Triple::MachO);
|
2014-04-17 06:17:23 +00:00
|
|
|
|
|
|
|
if (Obj->isCOFF()) {
|
|
|
|
const auto COFFObj = dyn_cast<COFFObjectFile>(Obj);
|
|
|
|
if (COFFObj->getArch() == Triple::thumb)
|
|
|
|
TheTriple.setTriple("thumbv7-windows");
|
|
|
|
}
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
}
|
2011-01-20 07:22:04 +00:00
|
|
|
} else
|
2012-05-08 23:38:45 +00:00
|
|
|
TheTriple.setTriple(Triple::normalize(TripleName));
|
2011-01-20 06:39:06 +00:00
|
|
|
|
|
|
|
// Get the target specific parser.
|
|
|
|
std::string Error;
|
2012-05-08 23:38:45 +00:00
|
|
|
const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple,
|
|
|
|
Error);
|
|
|
|
if (!TheTarget) {
|
|
|
|
errs() << ToolName << ": " << Error;
|
2014-04-25 04:24:47 +00:00
|
|
|
return nullptr;
|
2012-05-08 23:38:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update the triple name and return the found target.
|
|
|
|
TripleName = TheTriple.getTriple();
|
|
|
|
return TheTarget;
|
2011-01-20 06:39:06 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 19:27:31 +00:00
|
|
|
void llvm::DumpBytes(ArrayRef<uint8_t> bytes) {
|
2011-09-19 17:56:04 +00:00
|
|
|
static const char hex_rep[] = "0123456789abcdef";
|
2015-03-18 18:41:23 +00:00
|
|
|
SmallString<64> output;
|
|
|
|
|
|
|
|
for (char i: bytes) {
|
|
|
|
output.push_back(hex_rep[(i & 0xF0) >> 4]);
|
|
|
|
output.push_back(hex_rep[i & 0xF]);
|
|
|
|
output.push_back(' ');
|
2011-01-20 06:39:06 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 18:41:23 +00:00
|
|
|
outs() << output.c_str();
|
2011-01-20 06:39:06 +00:00
|
|
|
}
|
|
|
|
|
2012-12-05 20:12:35 +00:00
|
|
|
bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) {
|
2011-10-13 22:17:18 +00:00
|
|
|
uint64_t a_addr, b_addr;
|
2013-04-25 12:28:45 +00:00
|
|
|
if (error(a.getOffset(a_addr))) return false;
|
|
|
|
if (error(b.getOffset(b_addr))) return false;
|
2011-10-13 22:17:18 +00:00
|
|
|
return a_addr < b_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
|
2012-08-07 17:53:14 +00:00
|
|
|
const Target *TheTarget = getTarget(Obj);
|
|
|
|
// getTarget() will have already issued a diagnostic if necessary, so
|
|
|
|
// just bail here if it failed.
|
|
|
|
if (!TheTarget)
|
2011-01-20 06:39:06 +00:00
|
|
|
return;
|
|
|
|
|
2012-08-28 19:24:49 +00:00
|
|
|
// Package up features to be passed to target/subtarget
|
|
|
|
std::string FeaturesStr;
|
|
|
|
if (MAttrs.size()) {
|
|
|
|
SubtargetFeatures Features;
|
|
|
|
for (unsigned i = 0; i != MAttrs.size(); ++i)
|
|
|
|
Features.AddFeature(MAttrs[i]);
|
|
|
|
FeaturesStr = Features.getString();
|
|
|
|
}
|
|
|
|
|
2014-03-06 05:51:42 +00:00
|
|
|
std::unique_ptr<const MCRegisterInfo> MRI(
|
|
|
|
TheTarget->createMCRegInfo(TripleName));
|
2013-05-16 21:28:23 +00:00
|
|
|
if (!MRI) {
|
|
|
|
errs() << "error: no register info for target " << TripleName << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up disassembler.
|
2014-03-06 05:51:42 +00:00
|
|
|
std::unique_ptr<const MCAsmInfo> AsmInfo(
|
|
|
|
TheTarget->createMCAsmInfo(*MRI, TripleName));
|
2013-05-16 21:28:23 +00:00
|
|
|
if (!AsmInfo) {
|
|
|
|
errs() << "error: no assembly info for target " << TripleName << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-06 05:51:42 +00:00
|
|
|
std::unique_ptr<const MCSubtargetInfo> STI(
|
2014-08-06 23:24:41 +00:00
|
|
|
TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
|
2013-05-16 21:28:23 +00:00
|
|
|
if (!STI) {
|
|
|
|
errs() << "error: no subtarget info for target " << TripleName << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-06 05:51:42 +00:00
|
|
|
std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
if (!MII) {
|
|
|
|
errs() << "error: no instruction info for target " << TripleName << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-15 04:40:56 +00:00
|
|
|
std::unique_ptr<const MCObjectFileInfo> MOFI(new MCObjectFileInfo);
|
|
|
|
MCContext Ctx(AsmInfo.get(), MRI.get(), MOFI.get());
|
|
|
|
|
|
|
|
std::unique_ptr<MCDisassembler> DisAsm(
|
|
|
|
TheTarget->createMCDisassembler(*STI, Ctx));
|
|
|
|
|
2013-05-16 21:28:23 +00:00
|
|
|
if (!DisAsm) {
|
|
|
|
errs() << "error: no disassembler for target " << TripleName << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-06 05:51:42 +00: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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182628 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 01:07:04 +00:00
|
|
|
|
2013-05-16 21:28:23 +00:00
|
|
|
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
|
2014-03-06 05:51:42 +00:00
|
|
|
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
|
2013-05-16 21:28:23 +00:00
|
|
|
AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI));
|
|
|
|
if (!IP) {
|
|
|
|
errs() << "error: no instruction printer for target " << TripleName
|
|
|
|
<< '\n';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-20 22:55:15 +00:00
|
|
|
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "\t\t%016" PRIx64 ": " :
|
|
|
|
"\t\t\t%08" PRIx64 ": ";
|
|
|
|
|
2014-01-25 17:38:19 +00:00
|
|
|
// Create a mapping, RelocSecs = SectionRelocMap[S], where sections
|
|
|
|
// in RelocSecs contain the relocations for section S.
|
2014-06-13 03:07:50 +00:00
|
|
|
std::error_code EC;
|
2014-03-13 14:37:36 +00:00
|
|
|
std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap;
|
|
|
|
for (const SectionRef &Section : Obj->sections()) {
|
|
|
|
section_iterator Sec2 = Section.getRelocatedSection();
|
2014-02-10 20:24:04 +00:00
|
|
|
if (Sec2 != Obj->section_end())
|
2014-03-13 14:37:36 +00:00
|
|
|
SectionRelocMap[*Sec2].push_back(Section);
|
2014-01-25 17:38:19 +00:00
|
|
|
}
|
|
|
|
|
2014-03-13 14:37:36 +00:00
|
|
|
for (const SectionRef &Section : Obj->sections()) {
|
2014-11-17 11:17:17 +00:00
|
|
|
if (!Section.isText() || Section.isVirtual())
|
2014-01-25 00:32:01 +00:00
|
|
|
continue;
|
2011-06-25 17:55:23 +00:00
|
|
|
|
2014-10-08 15:28:58 +00:00
|
|
|
uint64_t SectionAddr = Section.getAddress();
|
|
|
|
uint64_t SectSize = Section.getSize();
|
2014-11-11 09:58:25 +00:00
|
|
|
if (!SectSize)
|
|
|
|
continue;
|
2014-02-24 22:12:11 +00:00
|
|
|
|
2011-07-15 18:39:24 +00:00
|
|
|
// Make a list of all the symbols in this section.
|
2014-03-17 07:28:19 +00:00
|
|
|
std::vector<std::pair<uint64_t, StringRef>> Symbols;
|
|
|
|
for (const SymbolRef &Symbol : Obj->symbols()) {
|
2014-10-08 15:28:58 +00:00
|
|
|
if (Section.containsSymbol(Symbol)) {
|
2011-07-15 18:39:24 +00:00
|
|
|
uint64_t Address;
|
2014-03-17 07:28:19 +00:00
|
|
|
if (error(Symbol.getAddress(Address)))
|
2014-01-25 00:32:01 +00:00
|
|
|
break;
|
|
|
|
if (Address == UnknownAddressOrSize)
|
|
|
|
continue;
|
2012-02-03 04:13:37 +00:00
|
|
|
Address -= SectionAddr;
|
2014-02-24 22:12:11 +00:00
|
|
|
if (Address >= SectSize)
|
|
|
|
continue;
|
2012-02-03 04:13:37 +00:00
|
|
|
|
2011-07-15 18:39:24 +00:00
|
|
|
StringRef Name;
|
2014-03-17 07:28:19 +00:00
|
|
|
if (error(Symbol.getName(Name)))
|
2014-01-25 00:32:01 +00:00
|
|
|
break;
|
2011-07-15 18:39:24 +00:00
|
|
|
Symbols.push_back(std::make_pair(Address, Name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort the symbols by address, just in case they didn't come in that way.
|
|
|
|
array_pod_sort(Symbols.begin(), Symbols.end());
|
|
|
|
|
2011-10-13 22:17:18 +00:00
|
|
|
// Make a list of all the relocations for this section.
|
|
|
|
std::vector<RelocationRef> Rels;
|
|
|
|
if (InlineRelocs) {
|
2014-03-14 14:22:49 +00:00
|
|
|
for (const SectionRef &RelocSec : SectionRelocMap[Section]) {
|
|
|
|
for (const RelocationRef &Reloc : RelocSec.relocations()) {
|
|
|
|
Rels.push_back(Reloc);
|
|
|
|
}
|
2011-10-13 22:17:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort relocations by address.
|
|
|
|
std::sort(Rels.begin(), Rels.end(), RelocAddressLess);
|
|
|
|
|
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 :-)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170838 91177308-0d34-0410-b5e6-96231b3b80d8
2012-12-21 03:47:03 +00:00
|
|
|
StringRef SegmentName = "";
|
2014-01-25 00:32:01 +00:00
|
|
|
if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) {
|
2014-03-13 14:37:36 +00:00
|
|
|
DataRefImpl DR = Section.getRawDataRefImpl();
|
2013-04-18 18:08:55 +00: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 :-)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170838 91177308-0d34-0410-b5e6-96231b3b80d8
2012-12-21 03:47:03 +00:00
|
|
|
}
|
2011-06-25 17:55:23 +00:00
|
|
|
StringRef name;
|
2014-03-13 14:37:36 +00:00
|
|
|
if (error(Section.getName(name)))
|
2014-01-25 00:32:01 +00:00
|
|
|
break;
|
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 :-)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170838 91177308-0d34-0410-b5e6-96231b3b80d8
2012-12-21 03:47:03 +00:00
|
|
|
outs() << "Disassembly of section ";
|
|
|
|
if (!SegmentName.empty())
|
|
|
|
outs() << SegmentName << ",";
|
|
|
|
outs() << name << ':';
|
2011-07-15 18:39:24 +00:00
|
|
|
|
|
|
|
// If the section has no symbols just insert a dummy one and disassemble
|
|
|
|
// the whole section.
|
|
|
|
if (Symbols.empty())
|
|
|
|
Symbols.push_back(std::make_pair(0, name));
|
2011-01-20 06:39:06 +00:00
|
|
|
|
2014-06-26 22:52:05 +00: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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
|
2014-11-12 02:04:27 +00:00
|
|
|
StringRef BytesStr;
|
|
|
|
if (error(Section.getContents(BytesStr)))
|
2014-01-25 00:32:01 +00:00
|
|
|
break;
|
2014-11-12 14:01:17 +00:00
|
|
|
ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
|
|
|
|
BytesStr.size());
|
2014-11-12 02:04:27 +00:00
|
|
|
|
2011-01-20 06:39:06 +00:00
|
|
|
uint64_t Size;
|
|
|
|
uint64_t Index;
|
2011-07-15 18:39:24 +00:00
|
|
|
|
2011-10-13 22:17:18 +00:00
|
|
|
std::vector<RelocationRef>::const_iterator rel_cur = Rels.begin();
|
|
|
|
std::vector<RelocationRef>::const_iterator rel_end = Rels.end();
|
2011-07-15 18:39:24 +00:00
|
|
|
// Disassemble symbol by symbol.
|
|
|
|
for (unsigned si = 0, se = Symbols.size(); si != se; ++si) {
|
2014-08-17 16:31:39 +00:00
|
|
|
|
2011-07-15 18:39:24 +00:00
|
|
|
uint64_t Start = Symbols[si].first;
|
2014-08-17 16:31:39 +00:00
|
|
|
// The end is either the section end or the beginning of the next symbol.
|
|
|
|
uint64_t End = (si == se - 1) ? SectSize : Symbols[si + 1].first;
|
|
|
|
// If this symbol has the same address as the next symbol, then skip it.
|
|
|
|
if (Start == End)
|
2011-10-13 20:37:08 +00:00
|
|
|
continue;
|
|
|
|
|
2011-07-15 18:39:24 +00:00
|
|
|
outs() << '\n' << Symbols[si].second << ":\n";
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2014-01-25 00:32:01 +00:00
|
|
|
raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
|
2011-07-15 18:39:24 +00:00
|
|
|
#else
|
2014-01-25 00:32:01 +00:00
|
|
|
raw_ostream &DebugOut = nulls();
|
2011-07-15 18:39:24 +00:00
|
|
|
#endif
|
|
|
|
|
2011-09-19 17:56:04 +00:00
|
|
|
for (Index = Start; Index < End; Index += Size) {
|
|
|
|
MCInst Inst;
|
|
|
|
|
2014-11-12 02:04:27 +00:00
|
|
|
if (DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
|
|
|
|
SectionAddr + Index, DebugOut,
|
|
|
|
CommentStream)) {
|
2012-11-20 22:57:02 +00:00
|
|
|
outs() << format("%8" PRIx64 ":", SectionAddr + Index);
|
|
|
|
if (!NoShowRawInsn) {
|
|
|
|
outs() << "\t";
|
2015-03-18 19:27:31 +00:00
|
|
|
DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, Size));
|
2012-11-20 22:57:02 +00:00
|
|
|
}
|
2015-03-27 20:36:02 +00:00
|
|
|
IP->printInst(&Inst, outs(), "", *STI);
|
2014-06-26 22:52:05 +00:00
|
|
|
outs() << CommentStream.str();
|
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).
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182625 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-24 00:39:57 +00:00
|
|
|
Comments.clear();
|
2011-09-19 17:56:04 +00:00
|
|
|
outs() << "\n";
|
|
|
|
} else {
|
|
|
|
errs() << ToolName << ": warning: invalid instruction encoding\n";
|
|
|
|
if (Size == 0)
|
|
|
|
Size = 1; // skip illegible bytes
|
2011-07-20 19:37:35 +00:00
|
|
|
}
|
2011-10-13 22:17:18 +00:00
|
|
|
|
|
|
|
// Print relocation for instruction.
|
|
|
|
while (rel_cur != rel_end) {
|
2011-10-25 20:35:53 +00:00
|
|
|
bool hidden = false;
|
2011-10-13 22:17:18 +00:00
|
|
|
uint64_t addr;
|
|
|
|
SmallString<16> name;
|
|
|
|
SmallString<32> val;
|
2011-10-25 20:35:53 +00:00
|
|
|
|
|
|
|
// If this relocation is hidden, skip it.
|
|
|
|
if (error(rel_cur->getHidden(hidden))) goto skip_print_rel;
|
|
|
|
if (hidden) goto skip_print_rel;
|
|
|
|
|
2013-04-25 12:28:45 +00:00
|
|
|
if (error(rel_cur->getOffset(addr))) goto skip_print_rel;
|
2011-10-13 22:17:18 +00:00
|
|
|
// Stop when rel_cur's address is past the current instruction.
|
2011-10-25 20:15:39 +00:00
|
|
|
if (addr >= Index + Size) break;
|
2011-10-13 22:17:18 +00:00
|
|
|
if (error(rel_cur->getTypeName(name))) goto skip_print_rel;
|
|
|
|
if (error(rel_cur->getValueString(val))) goto skip_print_rel;
|
|
|
|
|
2014-03-20 22:55:15 +00:00
|
|
|
outs() << format(Fmt.data(), SectionAddr + addr) << name
|
2012-03-10 02:04:38 +00:00
|
|
|
<< "\t" << val << "\n";
|
2011-10-13 22:17:18 +00:00
|
|
|
|
|
|
|
skip_print_rel:
|
|
|
|
++rel_cur;
|
|
|
|
}
|
2011-07-20 19:37:35 +00:00
|
|
|
}
|
2011-01-20 06:39:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
void llvm::PrintRelocations(const ObjectFile *Obj) {
|
2014-03-20 22:55:15 +00:00
|
|
|
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 :
|
|
|
|
"%08" PRIx64;
|
2014-08-17 19:09:37 +00:00
|
|
|
// Regular objdump doesn't print relocations in non-relocatable object
|
|
|
|
// files.
|
|
|
|
if (!Obj->isRelocatableObject())
|
|
|
|
return;
|
|
|
|
|
2014-03-13 14:37:36 +00:00
|
|
|
for (const SectionRef &Section : Obj->sections()) {
|
|
|
|
if (Section.relocation_begin() == Section.relocation_end())
|
2011-10-08 00:18:30 +00:00
|
|
|
continue;
|
|
|
|
StringRef secname;
|
2014-03-13 14:37:36 +00:00
|
|
|
if (error(Section.getName(secname)))
|
|
|
|
continue;
|
2011-10-08 00:18:30 +00:00
|
|
|
outs() << "RELOCATION RECORDS FOR [" << secname << "]:\n";
|
2014-03-14 14:22:49 +00:00
|
|
|
for (const RelocationRef &Reloc : Section.relocations()) {
|
2011-10-25 20:35:53 +00:00
|
|
|
bool hidden;
|
2011-10-08 00:18:30 +00:00
|
|
|
uint64_t address;
|
|
|
|
SmallString<32> relocname;
|
|
|
|
SmallString<32> valuestr;
|
2014-03-14 14:22:49 +00:00
|
|
|
if (error(Reloc.getHidden(hidden)))
|
|
|
|
continue;
|
|
|
|
if (hidden)
|
|
|
|
continue;
|
|
|
|
if (error(Reloc.getTypeName(relocname)))
|
|
|
|
continue;
|
|
|
|
if (error(Reloc.getOffset(address)))
|
|
|
|
continue;
|
|
|
|
if (error(Reloc.getValueString(valuestr)))
|
|
|
|
continue;
|
2014-03-20 22:55:15 +00:00
|
|
|
outs() << format(Fmt.data(), address) << " " << relocname << " "
|
|
|
|
<< valuestr << "\n";
|
2011-10-08 00:18:30 +00:00
|
|
|
}
|
|
|
|
outs() << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
void llvm::PrintSectionHeaders(const ObjectFile *Obj) {
|
2011-10-10 21:21:34 +00:00
|
|
|
outs() << "Sections:\n"
|
|
|
|
"Idx Name Size Address Type\n";
|
|
|
|
unsigned i = 0;
|
2014-03-13 14:37:36 +00:00
|
|
|
for (const SectionRef &Section : Obj->sections()) {
|
2011-10-10 21:21:34 +00:00
|
|
|
StringRef Name;
|
2014-03-13 14:37:36 +00:00
|
|
|
if (error(Section.getName(Name)))
|
2014-01-25 00:32:01 +00:00
|
|
|
return;
|
2014-10-08 15:28:58 +00: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-10 21:21:34 +00:00
|
|
|
std::string Type = (std::string(Text ? "TEXT " : "") +
|
2011-10-13 20:37:20 +00:00
|
|
|
(Data ? "DATA " : "") + (BSS ? "BSS" : ""));
|
2014-03-13 14:37:36 +00:00
|
|
|
outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", i,
|
|
|
|
Name.str().c_str(), Size, Address, Type.c_str());
|
2011-10-10 21:21:34 +00:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
void llvm::PrintSectionContents(const ObjectFile *Obj) {
|
2014-06-13 03:07:50 +00:00
|
|
|
std::error_code EC;
|
2014-03-13 14:37:36 +00:00
|
|
|
for (const SectionRef &Section : Obj->sections()) {
|
2011-10-17 17:13:22 +00:00
|
|
|
StringRef Name;
|
|
|
|
StringRef Contents;
|
2014-03-13 14:37:36 +00:00
|
|
|
if (error(Section.getName(Name)))
|
|
|
|
continue;
|
2014-10-08 15:28:58 +00:00
|
|
|
uint64_t BaseAddr = Section.getAddress();
|
2014-11-11 09:58:25 +00:00
|
|
|
uint64_t Size = Section.getSize();
|
|
|
|
if (!Size)
|
|
|
|
continue;
|
2011-10-17 17:13:22 +00:00
|
|
|
|
|
|
|
outs() << "Contents of section " << Name << ":\n";
|
2014-11-11 09:58:25 +00:00
|
|
|
if (Section.isBSS()) {
|
2013-04-16 10:53:11 +00:00
|
|
|
outs() << format("<skipping contents of bss section at [%04" PRIx64
|
2014-07-14 16:20:14 +00:00
|
|
|
", %04" PRIx64 ")>\n",
|
|
|
|
BaseAddr, BaseAddr + Size);
|
2013-04-16 10:53:11 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-10-17 17:13:22 +00:00
|
|
|
|
2014-07-14 16:20:14 +00:00
|
|
|
if (error(Section.getContents(Contents)))
|
|
|
|
continue;
|
|
|
|
|
2011-10-17 17:13:22 +00: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 02:04:38 +00:00
|
|
|
outs() << format(" %04" PRIx64 " ", BaseAddr + addr);
|
2011-10-17 17:13:22 +00: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) {
|
2013-02-12 21:21:59 +00:00
|
|
|
if (std::isprint(static_cast<unsigned char>(Contents[addr + i]) & 0xFF))
|
2011-10-17 17:13:22 +00:00
|
|
|
outs() << Contents[addr + i];
|
|
|
|
else
|
|
|
|
outs() << ".";
|
|
|
|
}
|
|
|
|
outs() << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-18 19:32:17 +00:00
|
|
|
static void PrintCOFFSymbolTable(const COFFObjectFile *coff) {
|
2014-09-10 12:51:52 +00:00
|
|
|
for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) {
|
|
|
|
ErrorOr<COFFSymbolRef> Symbol = coff->getSymbol(SI);
|
2014-04-14 02:37:28 +00:00
|
|
|
StringRef Name;
|
2014-09-10 12:51:52 +00:00
|
|
|
if (error(Symbol.getError()))
|
2014-04-14 02:37:28 +00:00
|
|
|
return;
|
|
|
|
|
2014-09-10 12:51:52 +00:00
|
|
|
if (error(coff->getSymbolName(*Symbol, Name)))
|
2014-04-14 02:37:28 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
outs() << "[" << format("%2d", SI) << "]"
|
2014-09-10 12:51:52 +00:00
|
|
|
<< "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"
|
2014-04-14 02:37:28 +00:00
|
|
|
<< "(fl 0x00)" // Flag bits, which COFF doesn't have.
|
2014-09-10 12:51:52 +00:00
|
|
|
<< "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"
|
|
|
|
<< "(scl " << format("%3x", unsigned(Symbol->getStorageClass())) << ") "
|
|
|
|
<< "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
|
|
|
|
<< "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
|
2014-04-14 02:37:28 +00:00
|
|
|
<< Name << "\n";
|
|
|
|
|
2014-09-10 12:51:52 +00:00
|
|
|
for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
|
2014-04-14 02:37:28 +00:00
|
|
|
if (Symbol->isSectionDefinition()) {
|
2011-10-18 19:32:17 +00:00
|
|
|
const coff_aux_section_definition *asd;
|
2014-04-14 02:37:28 +00:00
|
|
|
if (error(coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd)))
|
2011-10-18 19:32:17 +00:00
|
|
|
return;
|
2014-04-13 03:11:08 +00:00
|
|
|
|
2014-09-15 19:42:42 +00:00
|
|
|
int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());
|
|
|
|
|
2011-10-18 19:32:17 +00:00
|
|
|
outs() << "AUX "
|
|
|
|
<< format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
|
|
|
|
, unsigned(asd->Length)
|
|
|
|
, unsigned(asd->NumberOfRelocations)
|
|
|
|
, unsigned(asd->NumberOfLinenumbers)
|
|
|
|
, unsigned(asd->CheckSum))
|
|
|
|
<< format("assoc %d comdat %d\n"
|
2014-09-15 19:42:42 +00:00
|
|
|
, unsigned(AuxNumber)
|
2011-10-18 19:32:17 +00:00
|
|
|
, unsigned(asd->Selection));
|
2014-04-14 02:37:28 +00:00
|
|
|
} else if (Symbol->isFileRecord()) {
|
2014-09-10 12:51:52 +00:00
|
|
|
const char *FileName;
|
|
|
|
if (error(coff->getAuxSymbol<char>(SI + 1, FileName)))
|
2014-04-13 22:54:11 +00:00
|
|
|
return;
|
2014-04-14 02:37:23 +00:00
|
|
|
|
2014-09-10 12:51:52 +00:00
|
|
|
StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
|
|
|
|
coff->getSymbolTableEntrySize());
|
2014-04-14 02:37:23 +00:00
|
|
|
outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n';
|
2014-04-14 16:38:25 +00:00
|
|
|
|
2014-09-10 12:51:52 +00:00
|
|
|
SI = SI + Symbol->getNumberOfAuxSymbols();
|
2014-04-14 16:38:25 +00:00
|
|
|
break;
|
2014-04-14 02:37:23 +00:00
|
|
|
} else {
|
|
|
|
outs() << "AUX Unknown\n";
|
2014-04-13 03:11:08 +00:00
|
|
|
}
|
2011-10-18 19:32:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 21:47:46 +00:00
|
|
|
void llvm::PrintSymbolTable(const ObjectFile *o) {
|
2011-10-18 19:32:17 +00:00
|
|
|
outs() << "SYMBOL TABLE:\n";
|
|
|
|
|
2014-03-18 18:58:51 +00:00
|
|
|
if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o)) {
|
2011-10-18 19:32:17 +00:00
|
|
|
PrintCOFFSymbolTable(coff);
|
2014-03-18 18:58:51 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (const SymbolRef &Symbol : o->symbols()) {
|
|
|
|
StringRef Name;
|
|
|
|
uint64_t Address;
|
|
|
|
SymbolRef::Type Type;
|
|
|
|
uint64_t Size;
|
|
|
|
uint32_t Flags = Symbol.getFlags();
|
|
|
|
section_iterator Section = o->section_end();
|
|
|
|
if (error(Symbol.getName(Name)))
|
|
|
|
continue;
|
|
|
|
if (error(Symbol.getAddress(Address)))
|
|
|
|
continue;
|
|
|
|
if (error(Symbol.getType(Type)))
|
|
|
|
continue;
|
|
|
|
if (error(Symbol.getSize(Size)))
|
|
|
|
continue;
|
|
|
|
if (error(Symbol.getSection(Section)))
|
|
|
|
continue;
|
2011-10-18 19:32:17 +00:00
|
|
|
|
2014-03-18 18:58:51 +00:00
|
|
|
bool Global = Flags & SymbolRef::SF_Global;
|
|
|
|
bool Weak = Flags & SymbolRef::SF_Weak;
|
|
|
|
bool Absolute = Flags & SymbolRef::SF_Absolute;
|
2015-01-23 20:06:24 +00:00
|
|
|
bool Common = Flags & SymbolRef::SF_Common;
|
|
|
|
|
|
|
|
if (Common) {
|
|
|
|
uint32_t Alignment;
|
|
|
|
if (error(Symbol.getAlignment(Alignment)))
|
|
|
|
Alignment = 0;
|
|
|
|
Address = Size;
|
|
|
|
Size = Alignment;
|
|
|
|
}
|
2014-03-18 18:58:51 +00:00
|
|
|
if (Address == UnknownAddressOrSize)
|
|
|
|
Address = 0;
|
|
|
|
if (Size == UnknownAddressOrSize)
|
|
|
|
Size = 0;
|
|
|
|
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-23 20:06:24 +00:00
|
|
|
} else if (Common) {
|
|
|
|
outs() << "*COM*";
|
2014-03-18 18:58:51 +00: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-18 19:32:17 +00:00
|
|
|
}
|
2014-03-18 18:58:51 +00:00
|
|
|
StringRef SectionName;
|
|
|
|
if (error(Section->getName(SectionName)))
|
|
|
|
SectionName = "";
|
|
|
|
outs() << SectionName;
|
2011-10-18 19:32:17 +00:00
|
|
|
}
|
2014-03-18 18:58:51 +00:00
|
|
|
outs() << '\t'
|
|
|
|
<< format("%08" PRIx64 " ", Size)
|
|
|
|
<< Name
|
|
|
|
<< '\n';
|
2011-10-18 19:32:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-05 20:12:35 +00: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 13:07:19 +00:00
|
|
|
} else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
|
|
|
printMachOUnwindInfo(MachO);
|
|
|
|
else {
|
2012-12-05 20:12:35 +00:00
|
|
|
// TODO: Extract DWARF dump tool to objdump.
|
|
|
|
errs() << "This operation is only currently supported "
|
2014-08-01 13:07:19 +00:00
|
|
|
"for COFF and MachO object files.\n";
|
2012-12-05 20:12:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
void llvm::printExportsTrie(const ObjectFile *o) {
|
2014-08-30 00:20:14 +00: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
void llvm::printRebaseTable(const ObjectFile *o) {
|
2014-09-12 21:34:15 +00:00
|
|
|
outs() << "Rebase table:\n";
|
|
|
|
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
|
|
|
printMachORebaseTable(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
void llvm::printBindTable(const ObjectFile *o) {
|
2014-09-16 01:41:51 +00:00
|
|
|
outs() << "Bind table:\n";
|
|
|
|
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
|
|
|
printMachOBindTable(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
void llvm::printLazyBindTable(const ObjectFile *o) {
|
2014-09-16 01:41:51 +00:00
|
|
|
outs() << "Lazy bind table:\n";
|
|
|
|
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
|
|
|
printMachOLazyBindTable(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-07 21:02:18 +00:00
|
|
|
void llvm::printWeakBindTable(const ObjectFile *o) {
|
2014-09-16 01:41:51 +00:00
|
|
|
outs() << "Weak bind table:\n";
|
|
|
|
if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
|
|
|
|
printMachOWeakBindTable(MachO);
|
|
|
|
else {
|
|
|
|
errs() << "This operation is only currently supported "
|
|
|
|
"for Mach-O executable files.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-09-12 21:34:15 +00:00
|
|
|
|
2013-09-27 21:04:00 +00:00
|
|
|
static void printPrivateFileHeader(const ObjectFile *o) {
|
|
|
|
if (o->isELF()) {
|
|
|
|
printELFFileHeader(o);
|
|
|
|
} else if (o->isCOFF()) {
|
|
|
|
printCOFFFileHeader(o);
|
2014-08-22 20:35:18 +00:00
|
|
|
} else if (o->isMachO()) {
|
|
|
|
printMachOFileHeader(o);
|
2013-09-27 21:04:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-08 00:18:30 +00:00
|
|
|
static void DumpObject(const ObjectFile *o) {
|
2011-10-17 17:13:22 +00:00
|
|
|
outs() << '\n';
|
|
|
|
outs() << o->getFileName()
|
|
|
|
<< ":\tfile format " << o->getFileFormatName() << "\n\n";
|
|
|
|
|
2011-10-08 00:18:30 +00:00
|
|
|
if (Disassemble)
|
2011-10-13 22:17:18 +00:00
|
|
|
DisassembleObject(o, Relocations);
|
|
|
|
if (Relocations && !Disassemble)
|
2011-10-08 00:18:30 +00:00
|
|
|
PrintRelocations(o);
|
2011-10-10 21:21:34 +00:00
|
|
|
if (SectionHeaders)
|
|
|
|
PrintSectionHeaders(o);
|
2011-10-17 17:13:22 +00:00
|
|
|
if (SectionContents)
|
|
|
|
PrintSectionContents(o);
|
2011-10-18 19:32:17 +00:00
|
|
|
if (SymbolTable)
|
|
|
|
PrintSymbolTable(o);
|
2012-12-05 20:12:35 +00:00
|
|
|
if (UnwindInfo)
|
|
|
|
PrintUnwindInfo(o);
|
2013-09-27 21:04:00 +00:00
|
|
|
if (PrivateHeaders)
|
|
|
|
printPrivateFileHeader(o);
|
2014-08-30 00:20:14 +00:00
|
|
|
if (ExportsTrie)
|
|
|
|
printExportsTrie(o);
|
2014-09-12 21:34:15 +00:00
|
|
|
if (Rebase)
|
|
|
|
printRebaseTable(o);
|
2014-09-16 01:41:51 +00:00
|
|
|
if (Bind)
|
|
|
|
printBindTable(o);
|
|
|
|
if (LazyBind)
|
|
|
|
printLazyBindTable(o);
|
|
|
|
if (WeakBind)
|
|
|
|
printWeakBindTable(o);
|
2011-10-08 00:18:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Dump each object file in \a a;
|
|
|
|
static void DumpArchive(const Archive *a) {
|
2014-01-25 00:32:01 +00:00
|
|
|
for (Archive::child_iterator i = a->child_begin(), e = a->child_end(); i != e;
|
|
|
|
++i) {
|
2014-06-16 16:08:36 +00:00
|
|
|
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary();
|
|
|
|
if (std::error_code EC = ChildOrErr.getError()) {
|
2011-11-16 01:24:41 +00:00
|
|
|
// Ignore non-object files.
|
2014-01-25 00:32:01 +00:00
|
|
|
if (EC != object_error::invalid_file_type)
|
|
|
|
errs() << ToolName << ": '" << a->getFileName() << "': " << EC.message()
|
2011-11-16 01:24:41 +00:00
|
|
|
<< ".\n";
|
2011-10-08 00:18:30 +00:00
|
|
|
continue;
|
|
|
|
}
|
2014-06-16 16:08:36 +00:00
|
|
|
if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
|
2011-10-08 00:18:30 +00:00
|
|
|
DumpObject(o);
|
|
|
|
else
|
|
|
|
errs() << ToolName << ": '" << a->getFileName() << "': "
|
|
|
|
<< "Unrecognized file type.\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Open file and figure out how to dump it.
|
|
|
|
static void DumpInput(StringRef file) {
|
|
|
|
// If file isn't stdin, check that it exists.
|
|
|
|
if (file != "-" && !sys::fs::exists(file)) {
|
|
|
|
errs() << ToolName << ": '" << file << "': " << "No such file\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-07 21:02:18 +00: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 00:18:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to open the binary.
|
2014-08-19 18:44:46 +00:00
|
|
|
ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
|
2014-06-13 03:07:50 +00:00
|
|
|
if (std::error_code EC = BinaryOrErr.getError()) {
|
2014-01-15 19:37:43 +00:00
|
|
|
errs() << ToolName << ": '" << file << "': " << EC.message() << ".\n";
|
2011-10-08 00:18:30 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-08-19 18:44:46 +00:00
|
|
|
Binary &Binary = *BinaryOrErr.get().getBinary();
|
2011-10-08 00:18:30 +00:00
|
|
|
|
2014-08-01 14:31:55 +00:00
|
|
|
if (Archive *a = dyn_cast<Archive>(&Binary))
|
2011-10-08 00:18:30 +00:00
|
|
|
DumpArchive(a);
|
2014-08-01 14:31:55 +00:00
|
|
|
else if (ObjectFile *o = dyn_cast<ObjectFile>(&Binary))
|
2011-10-08 00:18:30 +00:00
|
|
|
DumpObject(o);
|
2012-08-07 17:53:14 +00:00
|
|
|
else
|
2011-10-08 00:18:30 +00:00
|
|
|
errs() << ToolName << ": '" << file << "': " << "Unrecognized file type.\n";
|
|
|
|
}
|
|
|
|
|
2011-01-20 06:39:06 +00:00
|
|
|
int main(int argc, char **argv) {
|
|
|
|
// Print a stack trace if we signal out.
|
|
|
|
sys::PrintStackTraceOnErrorSignal();
|
|
|
|
PrettyStackTraceProgram X(argc, argv);
|
|
|
|
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
|
|
|
|
|
|
|
// Initialize targets and assembly printers/parsers.
|
|
|
|
llvm::InitializeAllTargetInfos();
|
2011-07-22 21:58:54 +00:00
|
|
|
llvm::InitializeAllTargetMCs();
|
2011-01-20 06:39:06 +00:00
|
|
|
llvm::InitializeAllAsmParsers();
|
|
|
|
llvm::InitializeAllDisassemblers();
|
|
|
|
|
2012-05-03 23:20:10 +00:00
|
|
|
// Register the target printer for --version.
|
|
|
|
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
|
|
|
|
|
2011-01-20 06:39:06 +00:00
|
|
|
cl::ParseCommandLineOptions(argc, argv, "llvm object file dumper\n");
|
|
|
|
TripleName = Triple::normalize(TripleName);
|
|
|
|
|
|
|
|
ToolName = argv[0];
|
|
|
|
|
|
|
|
// Defaults to a.out if no filenames specified.
|
|
|
|
if (InputFilenames.size() == 0)
|
|
|
|
InputFilenames.push_back("a.out");
|
|
|
|
|
2011-10-18 19:32:17 +00:00
|
|
|
if (!Disassemble
|
|
|
|
&& !Relocations
|
|
|
|
&& !SectionHeaders
|
|
|
|
&& !SectionContents
|
2012-12-05 20:12:35 +00:00
|
|
|
&& !SymbolTable
|
2013-01-06 03:56:49 +00:00
|
|
|
&& !UnwindInfo
|
2014-08-30 00:20:14 +00:00
|
|
|
&& !PrivateHeaders
|
2014-09-12 21:34:15 +00:00
|
|
|
&& !ExportsTrie
|
2014-09-16 01:41:51 +00:00
|
|
|
&& !Rebase
|
|
|
|
&& !Bind
|
|
|
|
&& !LazyBind
|
2015-01-09 19:22:37 +00:00
|
|
|
&& !WeakBind
|
2015-01-15 23:19:11 +00:00
|
|
|
&& !(UniversalHeaders && MachOOpt)
|
2015-01-22 18:55:27 +00:00
|
|
|
&& !(ArchiveHeaders && MachOOpt)
|
2015-01-23 18:52:17 +00:00
|
|
|
&& !(IndirectSymbols && MachOOpt)
|
2015-01-27 21:28:24 +00:00
|
|
|
&& !(DataInCode && MachOOpt)
|
2015-01-31 00:37:11 +00:00
|
|
|
&& !(LinkOptHints && MachOOpt)
|
2015-03-11 22:06:32 +00:00
|
|
|
&& !(InfoPlist && MachOOpt)
|
2015-03-16 20:08:09 +00:00
|
|
|
&& !(DylibsUsed && MachOOpt)
|
|
|
|
&& !(DylibId && MachOOpt)
|
2015-01-31 00:37:11 +00:00
|
|
|
&& !(DumpSections.size() != 0 && MachOOpt)) {
|
2011-01-20 06:39:06 +00:00
|
|
|
cl::PrintHelpMessage();
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2011-10-08 00:18:30 +00:00
|
|
|
std::for_each(InputFilenames.begin(), InputFilenames.end(),
|
|
|
|
DumpInput);
|
2011-01-20 06:39:06 +00:00
|
|
|
|
2014-11-26 22:17:25 +00:00
|
|
|
return ReturnValue;
|
2011-01-20 06:39:06 +00:00
|
|
|
}
|