2011-09-19 17:56:04 +00:00
|
|
|
//===-- MachODump.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 file implements the MachO-specific dumper for llvm-objdump.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm-objdump.h"
|
|
|
|
#include "llvm/ADT/OwningPtr.h"
|
|
|
|
#include "llvm/ADT/STLExtras.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/ADT/StringExtras.h"
|
2012-12-04 10:44:52 +00:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2011-09-21 01:13:19 +00:00
|
|
|
#include "llvm/DebugInfo/DIContext.h"
|
2011-09-19 17:56:04 +00:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
|
|
#include "llvm/MC/MCDisassembler.h"
|
|
|
|
#include "llvm/MC/MCInst.h"
|
|
|
|
#include "llvm/MC/MCInstPrinter.h"
|
|
|
|
#include "llvm/MC/MCInstrAnalysis.h"
|
|
|
|
#include "llvm/MC/MCInstrDesc.h"
|
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
2012-03-05 19:33:20 +00:00
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
2011-09-19 17:56:04 +00:00
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2012-12-04 10:44:52 +00:00
|
|
|
#include "llvm/Object/MachO.h"
|
2013-04-13 01:45:40 +00:00
|
|
|
#include "llvm/Support/Casting.h"
|
2011-09-19 17:56:04 +00:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/Format.h"
|
|
|
|
#include "llvm/Support/GraphWriter.h"
|
2012-12-04 10:44:52 +00:00
|
|
|
#include "llvm/Support/MachO.h"
|
2011-09-19 17:56:04 +00:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
|
|
#include "llvm/Support/TargetSelect.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "llvm/Support/system_error.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cstring>
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace object;
|
|
|
|
|
2011-09-21 01:13:19 +00:00
|
|
|
static cl::opt<bool>
|
|
|
|
UseDbg("g", cl::desc("Print line information from debug info if available"));
|
|
|
|
|
|
|
|
static cl::opt<std::string>
|
|
|
|
DSYMFile("dsym", cl::desc("Use .dSYM file for debug info"));
|
|
|
|
|
2013-04-18 18:08:55 +00:00
|
|
|
static const Target *GetTarget(const MachOObjectFile *MachOObj) {
|
2011-09-19 17:56:04 +00:00
|
|
|
// Figure out the target triple.
|
2012-02-03 06:35:22 +00:00
|
|
|
if (TripleName.empty()) {
|
|
|
|
llvm::Triple TT("unknown-unknown-unknown");
|
2013-04-11 03:34:37 +00:00
|
|
|
TT.setArch(Triple::ArchType(MachOObj->getArch()));
|
2012-02-03 06:35:22 +00:00
|
|
|
TripleName = TT.str();
|
2011-09-19 17:56:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the target specific parser.
|
|
|
|
std::string Error;
|
|
|
|
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
|
|
|
|
if (TheTarget)
|
|
|
|
return TheTarget;
|
|
|
|
|
|
|
|
errs() << "llvm-objdump: error: unable to get target for '" << TripleName
|
|
|
|
<< "', see --version and --triple.\n";
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-17 21:37:35 +00:00
|
|
|
struct SymbolSorter {
|
|
|
|
bool operator()(const SymbolRef &A, const SymbolRef &B) {
|
|
|
|
SymbolRef::Type AType, BType;
|
|
|
|
A.getType(AType);
|
|
|
|
B.getType(BType);
|
|
|
|
|
|
|
|
uint64_t AAddr, BAddr;
|
|
|
|
if (AType != SymbolRef::ST_Function)
|
|
|
|
AAddr = 0;
|
|
|
|
else
|
|
|
|
A.getAddress(AAddr);
|
|
|
|
if (BType != SymbolRef::ST_Function)
|
|
|
|
BAddr = 0;
|
|
|
|
else
|
|
|
|
B.getAddress(BAddr);
|
|
|
|
return AAddr < BAddr;
|
|
|
|
}
|
2011-09-19 17:56:04 +00:00
|
|
|
};
|
|
|
|
|
2013-06-06 17:20:50 +00:00
|
|
|
// Types for the storted data in code table that is built before disassembly
|
|
|
|
// and the predicate function to sort them.
|
|
|
|
typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
|
|
|
|
typedef std::vector<DiceTableEntry> DiceTable;
|
|
|
|
typedef DiceTable::iterator dice_table_iterator;
|
|
|
|
|
|
|
|
static bool
|
|
|
|
compareDiceTableEntries(const DiceTableEntry i,
|
|
|
|
const DiceTableEntry j) {
|
|
|
|
return i.first == j.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DumpDataInCode(const char *bytes, uint64_t Size,
|
|
|
|
unsigned short Kind) {
|
|
|
|
uint64_t Value;
|
|
|
|
|
|
|
|
switch (Kind) {
|
|
|
|
case macho::Data:
|
|
|
|
switch (Size) {
|
|
|
|
case 4:
|
|
|
|
Value = bytes[3] << 24 |
|
|
|
|
bytes[2] << 16 |
|
|
|
|
bytes[1] << 8 |
|
|
|
|
bytes[0];
|
|
|
|
outs() << "\t.long " << Value;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Value = bytes[1] << 8 |
|
|
|
|
bytes[0];
|
|
|
|
outs() << "\t.short " << Value;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
Value = bytes[0];
|
|
|
|
outs() << "\t.byte " << Value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
outs() << "\t@ KIND_DATA\n";
|
|
|
|
break;
|
|
|
|
case macho::JumpTable8:
|
|
|
|
Value = bytes[0];
|
|
|
|
outs() << "\t.byte " << Value << "\t@ KIND_JUMP_TABLE8";
|
|
|
|
break;
|
|
|
|
case macho::JumpTable16:
|
|
|
|
Value = bytes[1] << 8 |
|
|
|
|
bytes[0];
|
|
|
|
outs() << "\t.short " << Value << "\t@ KIND_JUMP_TABLE16";
|
|
|
|
break;
|
|
|
|
case macho::JumpTable32:
|
|
|
|
Value = bytes[3] << 24 |
|
|
|
|
bytes[2] << 16 |
|
|
|
|
bytes[1] << 8 |
|
|
|
|
bytes[0];
|
|
|
|
outs() << "\t.long " << Value << "\t@ KIND_JUMP_TABLE32";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
outs() << "\t@ data in code kind = " << Kind << "\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-13 01:45:40 +00:00
|
|
|
static void
|
2013-04-18 18:08:55 +00:00
|
|
|
getSectionsAndSymbols(const macho::Header Header,
|
|
|
|
MachOObjectFile *MachOObj,
|
2013-04-13 01:45:40 +00:00
|
|
|
std::vector<SectionRef> &Sections,
|
|
|
|
std::vector<SymbolRef> &Symbols,
|
2013-06-06 17:20:50 +00:00
|
|
|
SmallVectorImpl<uint64_t> &FoundFns,
|
|
|
|
uint64_t &BaseSegmentAddress) {
|
2011-10-17 21:37:35 +00:00
|
|
|
error_code ec;
|
|
|
|
for (symbol_iterator SI = MachOObj->begin_symbols(),
|
|
|
|
SE = MachOObj->end_symbols(); SI != SE; SI.increment(ec))
|
|
|
|
Symbols.push_back(*SI);
|
|
|
|
|
|
|
|
for (section_iterator SI = MachOObj->begin_sections(),
|
|
|
|
SE = MachOObj->end_sections(); SI != SE; SI.increment(ec)) {
|
|
|
|
SectionRef SR = *SI;
|
|
|
|
StringRef SectName;
|
|
|
|
SR.getName(SectName);
|
|
|
|
Sections.push_back(*SI);
|
|
|
|
}
|
2011-09-21 01:13:19 +00:00
|
|
|
|
2013-04-18 18:08:55 +00:00
|
|
|
MachOObjectFile::LoadCommandInfo Command =
|
|
|
|
MachOObj->getFirstLoadCommandInfo();
|
2013-06-06 17:20:50 +00:00
|
|
|
bool BaseSegmentAddressSet = false;
|
2013-04-19 11:36:47 +00:00
|
|
|
for (unsigned i = 0; ; ++i) {
|
2013-04-18 18:08:55 +00:00
|
|
|
if (Command.C.Type == macho::LCT_FunctionStarts) {
|
2011-09-21 01:13:19 +00:00
|
|
|
// We found a function starts segment, parse the addresses for later
|
|
|
|
// consumption.
|
2013-04-18 18:08:55 +00:00
|
|
|
macho::LinkeditDataLoadCommand LLC =
|
|
|
|
MachOObj->getLinkeditDataLoadCommand(Command);
|
2011-09-21 01:13:19 +00:00
|
|
|
|
2013-04-18 18:08:55 +00:00
|
|
|
MachOObj->ReadULEB128s(LLC.DataOffset, FoundFns);
|
2011-09-21 22:16:43 +00:00
|
|
|
}
|
2013-06-06 17:20:50 +00:00
|
|
|
else if (Command.C.Type == macho::LCT_Segment) {
|
|
|
|
macho::SegmentLoadCommand SLC =
|
|
|
|
MachOObj->getSegmentLoadCommand(Command);
|
|
|
|
StringRef SegName = SLC.Name;
|
|
|
|
if(!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
|
|
|
|
BaseSegmentAddressSet = true;
|
|
|
|
BaseSegmentAddress = SLC.VMAddress;
|
|
|
|
}
|
|
|
|
}
|
2013-04-19 11:36:47 +00:00
|
|
|
|
|
|
|
if (i == Header.NumLoadCommands - 1)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
Command = MachOObj->getNextLoadCommandInfo(Command);
|
2011-09-21 22:16:43 +00:00
|
|
|
}
|
2011-09-21 01:13:19 +00:00
|
|
|
}
|
|
|
|
|
2013-04-13 01:45:40 +00:00
|
|
|
static void DisassembleInputMachO2(StringRef Filename,
|
2013-04-18 18:08:55 +00:00
|
|
|
MachOObjectFile *MachOOF);
|
2013-04-13 01:45:40 +00:00
|
|
|
|
2011-09-19 17:56:04 +00:00
|
|
|
void llvm::DisassembleInputMachO(StringRef Filename) {
|
|
|
|
OwningPtr<MemoryBuffer> Buff;
|
|
|
|
|
|
|
|
if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
|
|
|
|
errs() << "llvm-objdump: " << Filename << ": " << ec.message() << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-18 18:08:55 +00:00
|
|
|
OwningPtr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile*>(
|
2011-10-17 21:37:35 +00:00
|
|
|
ObjectFile::createMachOObjectFile(Buff.take())));
|
2011-09-19 17:56:04 +00:00
|
|
|
|
2013-04-18 18:08:55 +00:00
|
|
|
DisassembleInputMachO2(Filename, MachOOF.get());
|
2013-04-13 01:45:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void DisassembleInputMachO2(StringRef Filename,
|
2013-04-18 18:08:55 +00:00
|
|
|
MachOObjectFile *MachOOF) {
|
2013-04-13 01:45:40 +00:00
|
|
|
const Target *TheTarget = GetTarget(MachOOF);
|
2011-09-19 17:56:04 +00:00
|
|
|
if (!TheTarget) {
|
|
|
|
// GetTarget prints out stuff.
|
|
|
|
return;
|
|
|
|
}
|
2011-10-10 13:10:09 +00:00
|
|
|
OwningPtr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
|
2011-09-19 17:56:04 +00:00
|
|
|
OwningPtr<MCInstrAnalysis>
|
2011-10-10 13:10:09 +00:00
|
|
|
InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo.get()));
|
2011-09-19 17:56:04 +00:00
|
|
|
|
|
|
|
// Set up disassembler.
|
2013-05-13 01:16:13 +00:00
|
|
|
OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
|
|
|
|
OwningPtr<const MCAsmInfo> AsmInfo(
|
|
|
|
TheTarget->createMCAsmInfo(*MRI, TripleName));
|
2011-09-19 17:56:04 +00:00
|
|
|
OwningPtr<const MCSubtargetInfo>
|
|
|
|
STI(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
|
|
|
|
OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI));
|
|
|
|
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
|
2012-04-02 06:09:36 +00:00
|
|
|
OwningPtr<MCInstPrinter>
|
|
|
|
IP(TheTarget->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *InstrInfo,
|
|
|
|
*MRI, *STI));
|
2011-09-20 17:53:01 +00:00
|
|
|
|
|
|
|
if (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) {
|
2011-10-07 19:25:47 +00:00
|
|
|
errs() << "error: couldn't initialize disassembler for target "
|
2011-09-20 17:53:01 +00:00
|
|
|
<< TripleName << '\n';
|
2011-09-19 17:56:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-09-20 17:53:01 +00:00
|
|
|
outs() << '\n' << Filename << ":\n\n";
|
2011-09-19 17:56:04 +00:00
|
|
|
|
2013-04-18 18:08:55 +00:00
|
|
|
macho::Header Header = MachOOF->getHeader();
|
2011-09-19 17:56:04 +00:00
|
|
|
|
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
|
|
|
// FIXME: FoundFns isn't used anymore. Using symbols/LC_FUNCTION_STARTS to
|
|
|
|
// determine function locations will eventually go in MCObjectDisassembler.
|
|
|
|
// FIXME: Using the -cfg command line option, this code used to be able to
|
|
|
|
// annotate relocations with the referenced symbol's name, and if this was
|
|
|
|
// inside a __[cf]string section, the data it points to. This is now replaced
|
|
|
|
// by the upcoming MCSymbolizer, which needs the appropriate setup done above.
|
2011-10-17 21:37:35 +00:00
|
|
|
std::vector<SectionRef> Sections;
|
|
|
|
std::vector<SymbolRef> Symbols;
|
2011-09-19 17:56:04 +00:00
|
|
|
SmallVector<uint64_t, 8> FoundFns;
|
2013-06-06 17:20:50 +00:00
|
|
|
uint64_t BaseSegmentAddress;
|
2011-09-19 17:56:04 +00:00
|
|
|
|
2013-06-06 17:20:50 +00:00
|
|
|
getSectionsAndSymbols(Header, MachOOF, Sections, Symbols, FoundFns,
|
|
|
|
BaseSegmentAddress);
|
2011-09-19 17:56:04 +00:00
|
|
|
|
2011-09-21 01:13:19 +00:00
|
|
|
// Make a copy of the unsorted symbol list. FIXME: duplication
|
2011-10-17 21:37:35 +00:00
|
|
|
std::vector<SymbolRef> UnsortedSymbols(Symbols);
|
2011-09-19 17:56:04 +00:00
|
|
|
// Sort the symbols by address, just in case they didn't come in that way.
|
2011-10-17 21:37:35 +00:00
|
|
|
std::sort(Symbols.begin(), Symbols.end(), SymbolSorter());
|
2011-09-19 17:56:04 +00:00
|
|
|
|
2013-06-06 17:20:50 +00:00
|
|
|
// Build a data in code table that is sorted on by the address of each entry.
|
|
|
|
uint64_t BaseAddress = 0;
|
|
|
|
if (Header.FileType == macho::HFT_Object)
|
|
|
|
Sections[0].getAddress(BaseAddress);
|
|
|
|
else
|
|
|
|
BaseAddress = BaseSegmentAddress;
|
|
|
|
DiceTable Dices;
|
|
|
|
error_code ec;
|
|
|
|
for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices();
|
|
|
|
DI != DE; DI.increment(ec)){
|
|
|
|
uint32_t Offset;
|
|
|
|
DI->getOffset(Offset);
|
|
|
|
Dices.push_back(std::make_pair(BaseAddress + Offset, *DI));
|
|
|
|
}
|
|
|
|
array_pod_sort(Dices.begin(), Dices.end());
|
|
|
|
|
2011-09-19 17:56:04 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
|
|
|
|
#else
|
|
|
|
raw_ostream &DebugOut = nulls();
|
|
|
|
#endif
|
|
|
|
|
2011-09-21 01:13:19 +00:00
|
|
|
OwningPtr<DIContext> diContext;
|
2013-04-13 01:45:40 +00:00
|
|
|
ObjectFile *DbgObj = MachOOF;
|
2011-09-21 01:13:19 +00:00
|
|
|
// Try to find debug info and set up the DIContext for it.
|
|
|
|
if (UseDbg) {
|
|
|
|
// A separate DSym file path was specified, parse it as a macho file,
|
|
|
|
// get the sections and supply it to the section name parsing machinery.
|
|
|
|
if (!DSYMFile.empty()) {
|
|
|
|
OwningPtr<MemoryBuffer> Buf;
|
|
|
|
if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile.c_str(), Buf)) {
|
|
|
|
errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n';
|
|
|
|
return;
|
|
|
|
}
|
2012-11-12 21:40:38 +00:00
|
|
|
DbgObj = ObjectFile::createMachOObjectFile(Buf.take());
|
2011-09-21 01:13:19 +00:00
|
|
|
}
|
|
|
|
|
2012-11-12 21:40:38 +00:00
|
|
|
// Setup the DIContext
|
|
|
|
diContext.reset(DIContext::getDWARFContext(DbgObj));
|
2011-09-21 01:13:19 +00:00
|
|
|
}
|
|
|
|
|
2011-09-19 17:56:04 +00:00
|
|
|
for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
|
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
|
|
|
|
|
|
|
bool SectIsText = false;
|
|
|
|
Sections[SectIdx].isText(SectIsText);
|
|
|
|
if (SectIsText == false)
|
|
|
|
continue;
|
|
|
|
|
2011-10-17 21:37:35 +00:00
|
|
|
StringRef SectName;
|
|
|
|
if (Sections[SectIdx].getName(SectName) ||
|
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
|
|
|
SectName != "__text")
|
2011-09-20 17:53:01 +00:00
|
|
|
continue; // Skip non-text sections
|
2011-09-19 17:56:04 +00: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 :-)
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
|
|
|
DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
|
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-04-05 15:15:22 +00:00
|
|
|
StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);
|
|
|
|
if (SegmentName != "__TEXT")
|
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
|
|
|
continue;
|
|
|
|
|
2011-10-17 21:37:35 +00:00
|
|
|
StringRef Bytes;
|
|
|
|
Sections[SectIdx].getContents(Bytes);
|
2011-09-19 17:56:04 +00:00
|
|
|
StringRefMemoryObject memoryObject(Bytes);
|
|
|
|
bool symbolTableWorked = false;
|
|
|
|
|
2011-09-20 17:53:01 +00:00
|
|
|
// Parse relocations.
|
2011-11-07 17:21:36 +00:00
|
|
|
std::vector<std::pair<uint64_t, SymbolRef> > Relocs;
|
2011-10-17 21:37:35 +00:00
|
|
|
error_code ec;
|
|
|
|
for (relocation_iterator RI = Sections[SectIdx].begin_relocations(),
|
|
|
|
RE = Sections[SectIdx].end_relocations(); RI != RE; RI.increment(ec)) {
|
|
|
|
uint64_t RelocOffset, SectionAddress;
|
2013-04-25 12:28:45 +00:00
|
|
|
RI->getOffset(RelocOffset);
|
2011-10-17 21:37:35 +00:00
|
|
|
Sections[SectIdx].getAddress(SectionAddress);
|
|
|
|
RelocOffset -= SectionAddress;
|
|
|
|
|
2013-06-05 01:33:53 +00:00
|
|
|
symbol_iterator RelocSym = RI->getSymbol();
|
2011-10-17 21:37:35 +00:00
|
|
|
|
2013-06-05 01:33:53 +00:00
|
|
|
Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
|
2011-09-19 17:56:04 +00:00
|
|
|
}
|
|
|
|
array_pod_sort(Relocs.begin(), Relocs.end());
|
|
|
|
|
2011-09-20 17:53:01 +00:00
|
|
|
// Disassemble symbol by symbol.
|
2011-09-19 17:56:04 +00:00
|
|
|
for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
|
2011-10-17 21:37:35 +00:00
|
|
|
StringRef SymName;
|
|
|
|
Symbols[SymIdx].getName(SymName);
|
|
|
|
|
|
|
|
SymbolRef::Type ST;
|
|
|
|
Symbols[SymIdx].getType(ST);
|
|
|
|
if (ST != SymbolRef::ST_Function)
|
|
|
|
continue;
|
|
|
|
|
2011-09-20 17:53:01 +00:00
|
|
|
// Make sure the symbol is defined in this section.
|
2011-10-17 21:37:35 +00:00
|
|
|
bool containsSym = false;
|
|
|
|
Sections[SectIdx].containsSymbol(Symbols[SymIdx], containsSym);
|
|
|
|
if (!containsSym)
|
2011-09-19 17:56:04 +00:00
|
|
|
continue;
|
|
|
|
|
2011-09-20 17:53:01 +00:00
|
|
|
// Start at the address of the symbol relative to the section's address.
|
2012-02-03 05:42:17 +00:00
|
|
|
uint64_t SectionAddress = 0;
|
2011-10-17 21:37:35 +00:00
|
|
|
uint64_t Start = 0;
|
2012-02-03 05:42:17 +00:00
|
|
|
Sections[SectIdx].getAddress(SectionAddress);
|
2011-11-29 17:40:10 +00:00
|
|
|
Symbols[SymIdx].getAddress(Start);
|
2012-02-03 05:42:17 +00:00
|
|
|
Start -= SectionAddress;
|
2011-10-17 21:37:35 +00:00
|
|
|
|
2011-09-20 17:53:01 +00:00
|
|
|
// Stop disassembling either at the beginning of the next symbol or at
|
|
|
|
// the end of the section.
|
2012-05-15 18:57:14 +00:00
|
|
|
bool containsNextSym = false;
|
2011-10-17 21:37:35 +00:00
|
|
|
uint64_t NextSym = 0;
|
|
|
|
uint64_t NextSymIdx = SymIdx+1;
|
|
|
|
while (Symbols.size() > NextSymIdx) {
|
|
|
|
SymbolRef::Type NextSymType;
|
|
|
|
Symbols[NextSymIdx].getType(NextSymType);
|
|
|
|
if (NextSymType == SymbolRef::ST_Function) {
|
|
|
|
Sections[SectIdx].containsSymbol(Symbols[NextSymIdx],
|
|
|
|
containsNextSym);
|
2011-11-29 17:40:10 +00:00
|
|
|
Symbols[NextSymIdx].getAddress(NextSym);
|
2012-02-03 05:42:17 +00:00
|
|
|
NextSym -= SectionAddress;
|
2011-10-17 21:37:35 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
++NextSymIdx;
|
|
|
|
}
|
2011-09-19 17:56:04 +00:00
|
|
|
|
2011-10-17 21:37:35 +00:00
|
|
|
uint64_t SectSize;
|
|
|
|
Sections[SectIdx].getSize(SectSize);
|
|
|
|
uint64_t End = containsNextSym ? NextSym : SectSize;
|
|
|
|
uint64_t Size;
|
2011-09-19 17:56:04 +00:00
|
|
|
|
|
|
|
symbolTableWorked = true;
|
|
|
|
|
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
|
|
|
outs() << SymName << ":\n";
|
|
|
|
DILineInfo lastLine;
|
|
|
|
for (uint64_t Index = Start; Index < End; Index += Size) {
|
|
|
|
MCInst Inst;
|
|
|
|
|
2013-06-06 17:20:50 +00:00
|
|
|
uint64_t SectAddress = 0;
|
|
|
|
Sections[SectIdx].getAddress(SectAddress);
|
|
|
|
outs() << format("%8" PRIx64 ":\t", SectAddress + Index);
|
|
|
|
|
|
|
|
// Check the data in code table here to see if this is data not an
|
|
|
|
// instruction to be disassembled.
|
|
|
|
DiceTable Dice;
|
|
|
|
Dice.push_back(std::make_pair(SectAddress + Index, DiceRef()));
|
|
|
|
dice_table_iterator DTI = std::search(Dices.begin(), Dices.end(),
|
|
|
|
Dice.begin(), Dice.end(),
|
|
|
|
compareDiceTableEntries);
|
|
|
|
if (DTI != Dices.end()){
|
|
|
|
uint16_t Length;
|
|
|
|
DTI->second.getLength(Length);
|
|
|
|
DumpBytes(StringRef(Bytes.data() + Index, Length));
|
|
|
|
uint16_t Kind;
|
|
|
|
DTI->second.getKind(Kind);
|
|
|
|
DumpDataInCode(Bytes.data() + Index, Length, Kind);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
|
|
|
|
DebugOut, nulls())) {
|
|
|
|
DumpBytes(StringRef(Bytes.data() + Index, Size));
|
|
|
|
IP->printInst(&Inst, outs(), "");
|
|
|
|
|
|
|
|
// Print debug info.
|
|
|
|
if (diContext) {
|
|
|
|
DILineInfo dli =
|
|
|
|
diContext->getLineInfoForAddress(SectAddress + Index);
|
|
|
|
// Print valid line info if it changed.
|
|
|
|
if (dli != lastLine && dli.getLine() != 0)
|
|
|
|
outs() << "\t## " << dli.getFileName() << ':'
|
|
|
|
<< dli.getLine() << ':' << dli.getColumn();
|
|
|
|
lastLine = dli;
|
2011-09-19 17:56:04 +00:00
|
|
|
}
|
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
|
|
|
outs() << "\n";
|
|
|
|
} else {
|
|
|
|
errs() << "llvm-objdump: warning: invalid instruction encoding\n";
|
|
|
|
if (Size == 0)
|
|
|
|
Size = 1; // skip illegible bytes
|
2011-09-19 17:56:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
if (!symbolTableWorked) {
|
2012-05-18 00:13:56 +00:00
|
|
|
// Reading the symbol table didn't work, disassemble the whole section.
|
|
|
|
uint64_t SectAddress;
|
|
|
|
Sections[SectIdx].getAddress(SectAddress);
|
|
|
|
uint64_t SectSize;
|
|
|
|
Sections[SectIdx].getSize(SectSize);
|
|
|
|
uint64_t InstSize;
|
|
|
|
for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {
|
2012-07-19 00:17:40 +00:00
|
|
|
MCInst Inst;
|
|
|
|
|
|
|
|
if (DisAsm->getInstruction(Inst, InstSize, memoryObject, Index,
|
|
|
|
DebugOut, nulls())) {
|
|
|
|
outs() << format("%8" PRIx64 ":\t", SectAddress + Index);
|
|
|
|
DumpBytes(StringRef(Bytes.data() + Index, InstSize));
|
|
|
|
IP->printInst(&Inst, outs(), "");
|
|
|
|
outs() << "\n";
|
|
|
|
} else {
|
|
|
|
errs() << "llvm-objdump: warning: invalid instruction encoding\n";
|
|
|
|
if (InstSize == 0)
|
|
|
|
InstSize = 1; // skip illegible bytes
|
|
|
|
}
|
2012-05-18 00:13:56 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-19 17:56:04 +00:00
|
|
|
}
|
|
|
|
}
|