diff options
Diffstat (limited to 'tools/llvm-objdump')
-rw-r--r-- | tools/llvm-objdump/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tools/llvm-objdump/MCFunction.cpp | 138 | ||||
-rw-r--r-- | tools/llvm-objdump/MCFunction.h | 100 | ||||
-rw-r--r-- | tools/llvm-objdump/MachODump.cpp | 617 | ||||
-rw-r--r-- | tools/llvm-objdump/Makefile | 3 | ||||
-rw-r--r-- | tools/llvm-objdump/llvm-objdump.cpp | 328 | ||||
-rw-r--r-- | tools/llvm-objdump/llvm-objdump.h | 46 |
7 files changed, 1151 insertions, 84 deletions
diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index 4181b32..f3b2e1f 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + DebugInfo MC MCParser MCDisassembler @@ -8,4 +9,6 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-objdump llvm-objdump.cpp + MachODump.cpp + MCFunction.cpp ) diff --git a/tools/llvm-objdump/MCFunction.cpp b/tools/llvm-objdump/MCFunction.cpp new file mode 100644 index 0000000..5c67f1b --- /dev/null +++ b/tools/llvm-objdump/MCFunction.cpp @@ -0,0 +1,138 @@ +//===-- MCFunction.cpp ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the algorithm to break down a region of machine code +// into basic blocks and try to reconstruct a CFG from it. +// +//===----------------------------------------------------------------------===// + +#include "MCFunction.h" +#include "llvm/ADT/STLExtras.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" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +#include <set> +using namespace llvm; + +MCFunction +MCFunction::createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, + const MemoryObject &Region, uint64_t Start, + uint64_t End, const MCInstrAnalysis *Ana, + raw_ostream &DebugOut, + SmallVectorImpl<uint64_t> &Calls) { + std::vector<MCDecodedInst> Instructions; + std::set<uint64_t> Splits; + Splits.insert(Start); + uint64_t Size; + + MCFunction f(Name); + + { + DenseSet<uint64_t> VisitedInsts; + SmallVector<uint64_t, 16> WorkList; + WorkList.push_back(Start); + // Disassemble code and gather basic block split points. + while (!WorkList.empty()) { + uint64_t Index = WorkList.pop_back_val(); + if (VisitedInsts.find(Index) != VisitedInsts.end()) + continue; // Already visited this location. + + for (;Index < End; Index += Size) { + VisitedInsts.insert(Index); + + MCInst Inst; + if (DisAsm->getInstruction(Inst, Size, Region, Index, DebugOut, nulls())){ + Instructions.push_back(MCDecodedInst(Index, Size, Inst)); + if (Ana->isBranch(Inst)) { + uint64_t targ = Ana->evaluateBranch(Inst, Index, Size); + if (targ != -1ULL && targ == Index+Size) + continue; // Skip nop jumps. + + // If we could determine the branch target, make a note to start a + // new basic block there and add the target to the worklist. + if (targ != -1ULL) { + Splits.insert(targ); + WorkList.push_back(targ); + WorkList.push_back(Index+Size); + } + Splits.insert(Index+Size); + break; + } else if (Ana->isReturn(Inst)) { + // Return instruction. This basic block ends here. + Splits.insert(Index+Size); + break; + } else if (Ana->isCall(Inst)) { + uint64_t targ = Ana->evaluateBranch(Inst, Index, Size); + // Add the call to the call list if the destination is known. + if (targ != -1ULL && targ != Index+Size) + Calls.push_back(targ); + } + } else { + errs().write_hex(Index) << ": warning: invalid instruction encoding\n"; + if (Size == 0) + Size = 1; // skip illegible bytes + } + } + } + } + + // Make sure the instruction list is sorted. + std::sort(Instructions.begin(), Instructions.end()); + + // Create basic blocks. + unsigned ii = 0, ie = Instructions.size(); + for (std::set<uint64_t>::iterator spi = Splits.begin(), + spe = llvm::prior(Splits.end()); spi != spe; ++spi) { + MCBasicBlock BB; + uint64_t BlockEnd = *llvm::next(spi); + // Add instructions to the BB. + for (; ii != ie; ++ii) { + if (Instructions[ii].Address < *spi || + Instructions[ii].Address >= BlockEnd) + break; + BB.addInst(Instructions[ii]); + } + f.addBlock(*spi, BB); + } + + std::sort(f.Blocks.begin(), f.Blocks.end()); + + // Calculate successors of each block. + for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) { + MCBasicBlock &BB = const_cast<MCBasicBlock&>(i->second); + if (BB.getInsts().empty()) continue; + const MCDecodedInst &Inst = BB.getInsts().back(); + + if (Ana->isBranch(Inst.Inst)) { + uint64_t targ = Ana->evaluateBranch(Inst.Inst, Inst.Address, Inst.Size); + if (targ == -1ULL) { + // Indirect branch. Bail and add all blocks of the function as a + // successor. + for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) + BB.addSucc(i->first); + } else if (targ != Inst.Address+Inst.Size) + BB.addSucc(targ); + // Conditional branches can also fall through to the next block. + if (Ana->isConditionalBranch(Inst.Inst) && llvm::next(i) != e) + BB.addSucc(llvm::next(i)->first); + } else { + // No branch. Fall through to the next block. + if (!Ana->isReturn(Inst.Inst) && llvm::next(i) != e) + BB.addSucc(llvm::next(i)->first); + } + } + + return f; +} diff --git a/tools/llvm-objdump/MCFunction.h b/tools/llvm-objdump/MCFunction.h new file mode 100644 index 0000000..6d3a548 --- /dev/null +++ b/tools/llvm-objdump/MCFunction.h @@ -0,0 +1,100 @@ +//===-- MCFunction.h ------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the data structures to hold a CFG reconstructed from +// machine code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECTDUMP_MCFUNCTION_H +#define LLVM_OBJECTDUMP_MCFUNCTION_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/MC/MCInst.h" +#include <map> + +namespace llvm { + +class MCDisassembler; +class MCInstrAnalysis; +class MemoryObject; +class raw_ostream; + +/// MCDecodedInst - Small container to hold an MCInst and associated info like +/// address and size. +struct MCDecodedInst { + uint64_t Address; + uint64_t Size; + MCInst Inst; + + MCDecodedInst() {} + MCDecodedInst(uint64_t Address, uint64_t Size, MCInst Inst) + : Address(Address), Size(Size), Inst(Inst) {} + + bool operator<(const MCDecodedInst &RHS) const { + return Address < RHS.Address; + } +}; + +/// MCBasicBlock - Consists of multiple MCDecodedInsts and a list of successing +/// MCBasicBlocks. +class MCBasicBlock { + std::vector<MCDecodedInst> Insts; + typedef DenseSet<uint64_t> SetTy; + SetTy Succs; +public: + ArrayRef<MCDecodedInst> getInsts() const { return Insts; } + + typedef SetTy::const_iterator succ_iterator; + succ_iterator succ_begin() const { return Succs.begin(); } + succ_iterator succ_end() const { return Succs.end(); } + + bool contains(uint64_t Addr) const { return Succs.count(Addr); } + + void addInst(const MCDecodedInst &Inst) { Insts.push_back(Inst); } + void addSucc(uint64_t Addr) { Succs.insert(Addr); } + + bool operator<(const MCBasicBlock &RHS) const { + return Insts.size() < RHS.Insts.size(); + } +}; + +/// MCFunction - Represents a named function in machine code, containing +/// multiple MCBasicBlocks. +class MCFunction { + const StringRef Name; + // Keep BBs sorted by address. + typedef std::vector<std::pair<uint64_t, MCBasicBlock> > MapTy; + MapTy Blocks; +public: + MCFunction(StringRef Name) : Name(Name) {} + + // Create an MCFunction from a region of binary machine code. + static MCFunction + createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, + const MemoryObject &Region, uint64_t Start, uint64_t End, + const MCInstrAnalysis *Ana, raw_ostream &DebugOut, + SmallVectorImpl<uint64_t> &Calls); + + typedef MapTy::const_iterator iterator; + iterator begin() const { return Blocks.begin(); } + iterator end() const { return Blocks.end(); } + + StringRef getName() const { return Name; } + + MCBasicBlock &addBlock(uint64_t Address, const MCBasicBlock &BB) { + Blocks.push_back(std::make_pair(Address, BB)); + return Blocks.back().second; + } +}; + +} + +#endif diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp new file mode 100644 index 0000000..3f44b29 --- /dev/null +++ b/tools/llvm-objdump/MachODump.cpp @@ -0,0 +1,617 @@ +//===-- 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 "MCFunction.h" +#include "llvm/Support/MachO.h" +#include "llvm/Object/MachOObject.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/DIContext.h" +#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" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/GraphWriter.h" +#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; + +static cl::opt<bool> + CFG("cfg", cl::desc("Create a CFG for every symbol in the object file and" + "write it to a graphviz file (MachO-only)")); + +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")); + +static const Target *GetTarget(const MachOObject *MachOObj) { + // Figure out the target triple. + llvm::Triple TT("unknown-unknown-unknown"); + switch (MachOObj->getHeader().CPUType) { + case llvm::MachO::CPUTypeI386: + TT.setArch(Triple::ArchType(Triple::x86)); + break; + case llvm::MachO::CPUTypeX86_64: + TT.setArch(Triple::ArchType(Triple::x86_64)); + break; + case llvm::MachO::CPUTypeARM: + TT.setArch(Triple::ArchType(Triple::arm)); + break; + case llvm::MachO::CPUTypePowerPC: + TT.setArch(Triple::ArchType(Triple::ppc)); + break; + case llvm::MachO::CPUTypePowerPC64: + TT.setArch(Triple::ArchType(Triple::ppc64)); + break; + } + + TripleName = TT.str(); + + // 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; +} + +struct Section { + char Name[16]; + uint64_t Address; + uint64_t Size; + uint32_t Offset; + uint32_t NumRelocs; + uint64_t RelocTableOffset; +}; + +struct Symbol { + uint64_t Value; + uint32_t StringIndex; + uint8_t SectionIndex; + bool operator<(const Symbol &RHS) const { return Value < RHS.Value; } +}; + +template <typename T> +static Section copySection(const T &Sect) { + Section S; + memcpy(S.Name, Sect->Name, 16); + S.Address = Sect->Address; + S.Size = Sect->Size; + S.Offset = Sect->Offset; + S.NumRelocs = Sect->NumRelocationTableEntries; + S.RelocTableOffset = Sect->RelocationTableOffset; + return S; +} + +template <typename T> +static Symbol copySymbol(const T &STE) { + Symbol S; + S.StringIndex = STE->StringIndex; + S.SectionIndex = STE->SectionIndex; + S.Value = STE->Value; + return S; +} + +// Print additional information about an address, if available. +static void DumpAddress(uint64_t Address, ArrayRef<Section> Sections, + MachOObject *MachOObj, raw_ostream &OS) { + for (unsigned i = 0; i != Sections.size(); ++i) { + uint64_t addr = Address-Sections[i].Address; + if (Sections[i].Address <= Address && + Sections[i].Address + Sections[i].Size > Address) { + StringRef bytes = MachOObj->getData(Sections[i].Offset, + Sections[i].Size); + // Print constant strings. + if (!strcmp(Sections[i].Name, "__cstring")) + OS << '"' << bytes.substr(addr, bytes.find('\0', addr)) << '"'; + // Print constant CFStrings. + if (!strcmp(Sections[i].Name, "__cfstring")) + OS << "@\"" << bytes.substr(addr, bytes.find('\0', addr)) << '"'; + } + } +} + +typedef std::map<uint64_t, MCFunction*> FunctionMapTy; +typedef SmallVector<MCFunction, 16> FunctionListTy; +static void createMCFunctionAndSaveCalls(StringRef Name, + const MCDisassembler *DisAsm, + MemoryObject &Object, uint64_t Start, + uint64_t End, + MCInstrAnalysis *InstrAnalysis, + uint64_t Address, + raw_ostream &DebugOut, + FunctionMapTy &FunctionMap, + FunctionListTy &Functions) { + SmallVector<uint64_t, 16> Calls; + MCFunction f = + MCFunction::createFunctionFromMC(Name, DisAsm, Object, Start, End, + InstrAnalysis, DebugOut, Calls); + Functions.push_back(f); + FunctionMap[Address] = &Functions.back(); + + // Add the gathered callees to the map. + for (unsigned i = 0, e = Calls.size(); i != e; ++i) + FunctionMap.insert(std::make_pair(Calls[i], (MCFunction*)0)); +} + +// Write a graphviz file for the CFG inside an MCFunction. +static void emitDOTFile(const char *FileName, const MCFunction &f, + MCInstPrinter *IP) { + // Start a new dot file. + std::string Error; + raw_fd_ostream Out(FileName, Error); + if (!Error.empty()) { + errs() << "llvm-objdump: warning: " << Error << '\n'; + return; + } + + Out << "digraph " << f.getName() << " {\n"; + Out << "graph [ rankdir = \"LR\" ];\n"; + for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) { + bool hasPreds = false; + // Only print blocks that have predecessors. + // FIXME: Slow. + for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe; + ++pi) + if (pi->second.contains(i->first)) { + hasPreds = true; + break; + } + + if (!hasPreds && i != f.begin()) + continue; + + Out << '"' << i->first << "\" [ label=\"<a>"; + // Print instructions. + for (unsigned ii = 0, ie = i->second.getInsts().size(); ii != ie; + ++ii) { + // Escape special chars and print the instruction in mnemonic form. + std::string Str; + raw_string_ostream OS(Str); + IP->printInst(&i->second.getInsts()[ii].Inst, OS, ""); + Out << DOT::EscapeString(OS.str()) << '|'; + } + Out << "<o>\" shape=\"record\" ];\n"; + + // Add edges. + for (MCBasicBlock::succ_iterator si = i->second.succ_begin(), + se = i->second.succ_end(); si != se; ++si) + Out << i->first << ":o -> " << *si <<":a\n"; + } + Out << "}\n"; +} + +static void getSectionsAndSymbols(const macho::Header &Header, + MachOObject *MachOObj, + InMemoryStruct<macho::SymtabLoadCommand> *SymtabLC, + std::vector<Section> &Sections, + std::vector<Symbol> &Symbols, + SmallVectorImpl<uint64_t> &FoundFns) { + // Make a list of all symbols in the object file. + for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { + const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i); + if (LCI.Command.Type == macho::LCT_Segment) { + InMemoryStruct<macho::SegmentLoadCommand> SegmentLC; + MachOObj->ReadSegmentLoadCommand(LCI, SegmentLC); + + // Store the sections in this segment. + for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) { + InMemoryStruct<macho::Section> Sect; + MachOObj->ReadSection(LCI, SectNum, Sect); + Sections.push_back(copySection(Sect)); + + } + } else if (LCI.Command.Type == macho::LCT_Segment64) { + InMemoryStruct<macho::Segment64LoadCommand> Segment64LC; + MachOObj->ReadSegment64LoadCommand(LCI, Segment64LC); + + // Store the sections in this segment. + for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections; + ++SectNum) { + InMemoryStruct<macho::Section64> Sect64; + MachOObj->ReadSection64(LCI, SectNum, Sect64); + Sections.push_back(copySection(Sect64)); + } + } else if (LCI.Command.Type == macho::LCT_FunctionStarts) { + // We found a function starts segment, parse the addresses for later + // consumption. + InMemoryStruct<macho::LinkeditDataLoadCommand> LLC; + MachOObj->ReadLinkeditDataLoadCommand(LCI, LLC); + + MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns); + } + } + // Store the symbols. + if (SymtabLC) { + for (unsigned i = 0; i != (*SymtabLC)->NumSymbolTableEntries; ++i) { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> STE; + MachOObj->ReadSymbol64TableEntry((*SymtabLC)->SymbolTableOffset, i, + STE); + Symbols.push_back(copySymbol(STE)); + } else { + InMemoryStruct<macho::SymbolTableEntry> STE; + MachOObj->ReadSymbolTableEntry((*SymtabLC)->SymbolTableOffset, i, + STE); + Symbols.push_back(copySymbol(STE)); + } + } + } +} + +void llvm::DisassembleInputMachO(StringRef Filename) { + OwningPtr<MemoryBuffer> Buff; + + if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { + errs() << "llvm-objdump: " << Filename << ": " << ec.message() << "\n"; + return; + } + + OwningPtr<MachOObject> MachOObj(MachOObject::LoadFromBuffer(Buff.take())); + + const Target *TheTarget = GetTarget(MachOObj.get()); + if (!TheTarget) { + // GetTarget prints out stuff. + return; + } + OwningPtr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo()); + OwningPtr<MCInstrAnalysis> + InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo.get())); + + // Set up disassembler. + OwningPtr<const MCAsmInfo> AsmInfo(TheTarget->createMCAsmInfo(TripleName)); + OwningPtr<const MCSubtargetInfo> + STI(TheTarget->createMCSubtargetInfo(TripleName, "", "")); + OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); + int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); + OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( + AsmPrinterVariant, *AsmInfo, *STI)); + + if (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) { + errs() << "error: couldn't initialize disassembler for target " + << TripleName << '\n'; + return; + } + + outs() << '\n' << Filename << ":\n\n"; + + const macho::Header &Header = MachOObj->getHeader(); + + const MachOObject::LoadCommandInfo *SymtabLCI = 0; + // First, find the symbol table segment. + for (unsigned i = 0; i != Header.NumLoadCommands; ++i) { + const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i); + if (LCI.Command.Type == macho::LCT_Symtab) { + SymtabLCI = &LCI; + break; + } + } + + // Read and register the symbol table data. + InMemoryStruct<macho::SymtabLoadCommand> SymtabLC; + MachOObj->ReadSymtabLoadCommand(*SymtabLCI, SymtabLC); + MachOObj->RegisterStringTable(*SymtabLC); + + std::vector<Section> Sections; + std::vector<Symbol> Symbols; + SmallVector<uint64_t, 8> FoundFns; + + getSectionsAndSymbols(Header, MachOObj.get(), &SymtabLC, Sections, Symbols, + FoundFns); + + // Make a copy of the unsorted symbol list. FIXME: duplication + std::vector<Symbol> UnsortedSymbols(Symbols); + // Sort the symbols by address, just in case they didn't come in that way. + array_pod_sort(Symbols.begin(), Symbols.end()); + +#ifndef NDEBUG + raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); +#else + raw_ostream &DebugOut = nulls(); +#endif + + StringRef DebugAbbrevSection, DebugInfoSection, DebugArangesSection, + DebugLineSection, DebugStrSection; + OwningPtr<DIContext> diContext; + OwningPtr<MachOObject> DSYMObj; + MachOObject *DbgInfoObj = MachOObj.get(); + // Try to find debug info and set up the DIContext for it. + if (UseDbg) { + ArrayRef<Section> DebugSections = Sections; + std::vector<Section> DSYMSections; + + // 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; + } + DSYMObj.reset(MachOObject::LoadFromBuffer(Buf.take())); + const macho::Header &Header = DSYMObj->getHeader(); + + std::vector<Symbol> Symbols; + SmallVector<uint64_t, 8> FoundFns; + getSectionsAndSymbols(Header, DSYMObj.get(), 0, DSYMSections, Symbols, + FoundFns); + DebugSections = DSYMSections; + DbgInfoObj = DSYMObj.get(); + } + + // Find the named debug info sections. + for (unsigned SectIdx = 0; SectIdx != DebugSections.size(); SectIdx++) { + if (!strcmp(DebugSections[SectIdx].Name, "__debug_abbrev")) + DebugAbbrevSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_info")) + DebugInfoSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_aranges")) + DebugArangesSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_line")) + DebugLineSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + else if (!strcmp(DebugSections[SectIdx].Name, "__debug_str")) + DebugStrSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset, + DebugSections[SectIdx].Size); + } + + // Setup the DIContext. + diContext.reset(DIContext::getDWARFContext(DbgInfoObj->isLittleEndian(), + DebugInfoSection, + DebugAbbrevSection, + DebugArangesSection, + DebugLineSection, + DebugStrSection)); + } + + FunctionMapTy FunctionMap; + FunctionListTy Functions; + + for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { + if (strcmp(Sections[SectIdx].Name, "__text")) + continue; // Skip non-text sections + + // Insert the functions from the function starts segment into our map. + uint64_t VMAddr = Sections[SectIdx].Address - Sections[SectIdx].Offset; + for (unsigned i = 0, e = FoundFns.size(); i != e; ++i) + FunctionMap.insert(std::make_pair(FoundFns[i]+VMAddr, (MCFunction*)0)); + + StringRef Bytes = MachOObj->getData(Sections[SectIdx].Offset, + Sections[SectIdx].Size); + StringRefMemoryObject memoryObject(Bytes); + bool symbolTableWorked = false; + + // Parse relocations. + std::vector<std::pair<uint64_t, uint32_t> > Relocs; + for (unsigned j = 0; j != Sections[SectIdx].NumRelocs; ++j) { + InMemoryStruct<macho::RelocationEntry> RE; + MachOObj->ReadRelocationEntry(Sections[SectIdx].RelocTableOffset, j, RE); + Relocs.push_back(std::make_pair(RE->Word0, RE->Word1 & 0xffffff)); + } + array_pod_sort(Relocs.begin(), Relocs.end()); + + // Disassemble symbol by symbol. + for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) { + // Make sure the symbol is defined in this section. + if ((unsigned)Symbols[SymIdx].SectionIndex - 1 != SectIdx) + continue; + + // Start at the address of the symbol relative to the section's address. + uint64_t Start = Symbols[SymIdx].Value - Sections[SectIdx].Address; + // Stop disassembling either at the beginning of the next symbol or at + // the end of the section. + uint64_t End = (SymIdx+1 == Symbols.size() || + Symbols[SymIdx].SectionIndex != Symbols[SymIdx+1].SectionIndex) ? + Sections[SectIdx].Size : + Symbols[SymIdx+1].Value - Sections[SectIdx].Address; + uint64_t Size; + + if (Start >= End) + continue; + + symbolTableWorked = true; + + if (!CFG) { + // Normal disassembly, print addresses, bytes and mnemonic form. + outs() << MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex) + << ":\n"; + DILineInfo lastLine; + for (uint64_t Index = Start; Index < End; Index += Size) { + MCInst Inst; + + if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, + DebugOut, nulls())) { + outs() << format("%8llx:\t", Sections[SectIdx].Address + Index); + DumpBytes(StringRef(Bytes.data() + Index, Size)); + IP->printInst(&Inst, outs(), ""); + + // Print debug info. + if (diContext) { + DILineInfo dli = + diContext->getLineInfoForAddress(Sections[SectIdx].Address + + Index); + // Print valid line info if it changed. + if (dli != lastLine && dli.getLine() != 0) + outs() << "\t## " << dli.getFileName() << ':' + << dli.getLine() << ':' << dli.getColumn(); + lastLine = dli; + } + outs() << "\n"; + } else { + errs() << "llvm-objdump: warning: invalid instruction encoding\n"; + if (Size == 0) + Size = 1; // skip illegible bytes + } + } + } else { + // Create CFG and use it for disassembly. + createMCFunctionAndSaveCalls( + MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex), + DisAsm.get(), memoryObject, Start, End, InstrAnalysis.get(), + Start, DebugOut, FunctionMap, Functions); + } + } + + if (CFG) { + if (!symbolTableWorked) { + // Reading the symbol table didn't work, create a big __TEXT symbol. + createMCFunctionAndSaveCalls("__TEXT", DisAsm.get(), memoryObject, + 0, Sections[SectIdx].Size, + InstrAnalysis.get(), + Sections[SectIdx].Offset, DebugOut, + FunctionMap, Functions); + } + for (std::map<uint64_t, MCFunction*>::iterator mi = FunctionMap.begin(), + me = FunctionMap.end(); mi != me; ++mi) + if (mi->second == 0) { + // Create functions for the remaining callees we have gathered, + // but we didn't find a name for them. + SmallVector<uint64_t, 16> Calls; + MCFunction f = + MCFunction::createFunctionFromMC("unknown", DisAsm.get(), + memoryObject, mi->first, + Sections[SectIdx].Size, + InstrAnalysis.get(), DebugOut, + Calls); + Functions.push_back(f); + mi->second = &Functions.back(); + for (unsigned i = 0, e = Calls.size(); i != e; ++i) { + std::pair<uint64_t, MCFunction*> p(Calls[i], (MCFunction*)0); + if (FunctionMap.insert(p).second) + mi = FunctionMap.begin(); + } + } + + DenseSet<uint64_t> PrintedBlocks; + for (unsigned ffi = 0, ffe = Functions.size(); ffi != ffe; ++ffi) { + MCFunction &f = Functions[ffi]; + for (MCFunction::iterator fi = f.begin(), fe = f.end(); fi != fe; ++fi){ + if (!PrintedBlocks.insert(fi->first).second) + continue; // We already printed this block. + + // We assume a block has predecessors when it's the first block after + // a symbol. + bool hasPreds = FunctionMap.find(fi->first) != FunctionMap.end(); + + // See if this block has predecessors. + // FIXME: Slow. + for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe; + ++pi) + if (pi->second.contains(fi->first)) { + hasPreds = true; + break; + } + + // No predecessors, this is a data block. Print as .byte directives. + if (!hasPreds) { + uint64_t End = llvm::next(fi) == fe ? Sections[SectIdx].Size : + llvm::next(fi)->first; + outs() << "# " << End-fi->first << " bytes of data:\n"; + for (unsigned pos = fi->first; pos != End; ++pos) { + outs() << format("%8x:\t", Sections[SectIdx].Address + pos); + DumpBytes(StringRef(Bytes.data() + pos, 1)); + outs() << format("\t.byte 0x%02x\n", (uint8_t)Bytes[pos]); + } + continue; + } + + if (fi->second.contains(fi->first)) // Print a header for simple loops + outs() << "# Loop begin:\n"; + + DILineInfo lastLine; + // Walk over the instructions and print them. + for (unsigned ii = 0, ie = fi->second.getInsts().size(); ii != ie; + ++ii) { + const MCDecodedInst &Inst = fi->second.getInsts()[ii]; + + // If there's a symbol at this address, print its name. + if (FunctionMap.find(Sections[SectIdx].Address + Inst.Address) != + FunctionMap.end()) + outs() << FunctionMap[Sections[SectIdx].Address + Inst.Address]-> + getName() << ":\n"; + + outs() << format("%8llx:\t", Sections[SectIdx].Address + + Inst.Address); + DumpBytes(StringRef(Bytes.data() + Inst.Address, Inst.Size)); + + if (fi->second.contains(fi->first)) // Indent simple loops. + outs() << '\t'; + + IP->printInst(&Inst.Inst, outs(), ""); + + // Look for relocations inside this instructions, if there is one + // print its target and additional information if available. + for (unsigned j = 0; j != Relocs.size(); ++j) + if (Relocs[j].first >= Sections[SectIdx].Address + Inst.Address && + Relocs[j].first < Sections[SectIdx].Address + Inst.Address + + Inst.Size) { + outs() << "\t# " + << MachOObj->getStringAtIndex( + UnsortedSymbols[Relocs[j].second].StringIndex) + << ' '; + DumpAddress(UnsortedSymbols[Relocs[j].second].Value, Sections, + MachOObj.get(), outs()); + } + + // If this instructions contains an address, see if we can evaluate + // it and print additional information. + uint64_t targ = InstrAnalysis->evaluateBranch(Inst.Inst, + Inst.Address, + Inst.Size); + if (targ != -1ULL) + DumpAddress(targ, Sections, MachOObj.get(), outs()); + + // Print debug info. + if (diContext) { + DILineInfo dli = + diContext->getLineInfoForAddress(Sections[SectIdx].Address + + Inst.Address); + // Print valid line info if it changed. + if (dli != lastLine && dli.getLine() != 0) + outs() << "\t## " << dli.getFileName() << ':' + << dli.getLine() << ':' << dli.getColumn(); + lastLine = dli; + } + + outs() << '\n'; + } + } + + emitDOTFile((f.getName().str() + ".dot").c_str(), f, IP.get()); + } + } + } +} diff --git a/tools/llvm-objdump/Makefile b/tools/llvm-objdump/Makefile index 4d7cd34..703bf6c 100644 --- a/tools/llvm-objdump/Makefile +++ b/tools/llvm-objdump/Makefile @@ -9,7 +9,8 @@ LEVEL = ../.. TOOLNAME = llvm-objdump -LINK_COMPONENTS = $(TARGETS_TO_BUILD) MC MCParser MCDisassembler Object +LINK_COMPONENTS = $(TARGETS_TO_BUILD) DebugInfo MC MCParser MCDisassembler \ + Object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 4079e4a..4ae13be 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -13,6 +13,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm-objdump.h" +#include "MCFunction.h" +#include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Triple.h" @@ -21,9 +24,13 @@ #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" +#include "llvm/Support/GraphWriter.h" #include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" @@ -31,44 +38,59 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetSelect.h" #include <algorithm> #include <cstring> using namespace llvm; using namespace object; -namespace { - cl::list<std::string> - InputFilenames(cl::Positional, cl::desc("<input object files>"), - cl::ZeroOrMore); +static cl::list<std::string> +InputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore); - cl::opt<bool> - Disassemble("disassemble", - cl::desc("Display assembler mnemonics for the machine instructions")); - cl::alias - Disassembled("d", cl::desc("Alias for --disassemble"), - cl::aliasopt(Disassemble)); +static cl::opt<bool> +Disassemble("disassemble", + cl::desc("Display assembler mnemonics for the machine instructions")); +static cl::alias +Disassembled("d", cl::desc("Alias for --disassemble"), + cl::aliasopt(Disassemble)); - cl::opt<std::string> - TripleName("triple", cl::desc("Target triple to disassemble for, " +static cl::opt<bool> +Relocations("r", cl::desc("Display the relocation entries in the file")); + +static cl::opt<bool> +MachO("macho", cl::desc("Use MachO specific object file parser")); +static cl::alias +MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachO)); + +cl::opt<std::string> +llvm::TripleName("triple", cl::desc("Target triple to disassemble for, " + "see -version for available targets")); + +cl::opt<std::string> +llvm::ArchName("arch", cl::desc("Target arch to disassemble for, " "see -version for available targets")); - cl::opt<std::string> - ArchName("arch", cl::desc("Target arch to disassemble for, " - "see -version for available targets")); +static cl::opt<bool> +SectionHeaders("section-headers", cl::desc("Display summaries of the headers " + "for each section.")); +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)); - StringRef ToolName; +static StringRef ToolName; - bool error(error_code ec) { - if (!ec) return false; +static bool error(error_code ec) { + if (!ec) return false; - outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; - outs().flush(); - return true; - } + outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; + outs().flush(); + return true; } static const Target *GetTarget(const ObjectFile *Obj = NULL) { @@ -96,27 +118,8 @@ static const Target *GetTarget(const ObjectFile *Obj = NULL) { return 0; } -namespace { -class StringRefMemoryObject : public MemoryObject { -private: - StringRef Bytes; -public: - StringRefMemoryObject(StringRef bytes) : Bytes(bytes) {} - - uint64_t getBase() const { return 0; } - uint64_t getExtent() const { return Bytes.size(); } - - int readByte(uint64_t Addr, uint8_t *Byte) const { - if (Addr > getExtent()) - return -1; - *Byte = Bytes[Addr]; - return 0; - } -}; -} - -static void DumpBytes(StringRef bytes) { - static char hex_rep[] = "0123456789abcdef"; +void llvm::DumpBytes(StringRef bytes) { + static const char hex_rep[] = "0123456789abcdef"; // FIXME: The real way to do this is to figure out the longest instruction // and align to that size before printing. I'll fix this when I get // around to outputting relocations. @@ -141,44 +144,45 @@ static void DumpBytes(StringRef bytes) { outs() << output; } -static void DisassembleInput(const StringRef &Filename) { - OwningPtr<MemoryBuffer> Buff; - - if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { - errs() << ToolName << ": " << Filename << ": " << ec.message() << "\n"; - return; - } - - OwningPtr<ObjectFile> Obj(ObjectFile::createObjectFile(Buff.take())); +static bool RelocAddressLess(RelocationRef a, RelocationRef b) { + uint64_t a_addr, b_addr; + if (error(a.getAddress(a_addr))) return false; + if (error(b.getAddress(b_addr))) return false; + return a_addr < b_addr; +} - const Target *TheTarget = GetTarget(Obj.get()); +static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { + const Target *TheTarget = GetTarget(Obj); if (!TheTarget) { // GetTarget prints out stuff. return; } outs() << '\n'; - outs() << Filename + outs() << Obj->getFileName() << ":\tfile format " << Obj->getFileFormatName() << "\n\n"; error_code ec; - for (ObjectFile::section_iterator i = Obj->begin_sections(), - e = Obj->end_sections(); - i != e; i.increment(ec)) { + for (section_iterator i = Obj->begin_sections(), + e = Obj->end_sections(); + i != e; i.increment(ec)) { if (error(ec)) break; bool text; if (error(i->isText(text))) break; if (!text) continue; + uint64_t SectionAddr; + if (error(i->getAddress(SectionAddr))) break; + // Make a list of all the symbols in this section. std::vector<std::pair<uint64_t, StringRef> > Symbols; - for (ObjectFile::symbol_iterator si = Obj->begin_symbols(), - se = Obj->end_symbols(); - si != se; si.increment(ec)) { + for (symbol_iterator si = Obj->begin_symbols(), + se = Obj->end_symbols(); + si != se; si.increment(ec)) { bool contains; if (!error(i->containsSymbol(*si, contains)) && contains) { uint64_t Address; - if (error(si->getAddress(Address))) break; + if (error(si->getOffset(Address))) break; StringRef Name; if (error(si->getName(Name))) break; Symbols.push_back(std::make_pair(Address, Name)); @@ -188,6 +192,20 @@ static void DisassembleInput(const StringRef &Filename) { // Sort the symbols by address, just in case they didn't come in that way. array_pod_sort(Symbols.begin(), Symbols.end()); + // Make a list of all the relocations for this section. + std::vector<RelocationRef> Rels; + if (InlineRelocs) { + for (relocation_iterator ri = i->begin_relocations(), + re = i->end_relocations(); + ri != re; ri.increment(ec)) { + if (error(ec)) break; + Rels.push_back(*ri); + } + } + + // Sort relocations by address. + std::sort(Rels.begin(), Rels.end(), RelocAddressLess); + StringRef name; if (error(i->getName(name))) break; outs() << "Disassembly of section " << name << ':'; @@ -205,7 +223,16 @@ static void DisassembleInput(const StringRef &Filename) { return; } - OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler()); + OwningPtr<const MCSubtargetInfo> STI( + TheTarget->createMCSubtargetInfo(TripleName, "", "")); + + if (!STI) { + errs() << "error: no subtarget info for target " << TripleName << "\n"; + return; + } + + OwningPtr<const MCDisassembler> DisAsm( + TheTarget->createMCDisassembler(*STI)); if (!DisAsm) { errs() << "error: no disassembler for target " << TripleName << "\n"; return; @@ -213,9 +240,10 @@ static void DisassembleInput(const StringRef &Filename) { int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( - AsmPrinterVariant, *AsmInfo)); + AsmPrinterVariant, *AsmInfo, *STI)); if (!IP) { - errs() << "error: no instruction printer for target " << TripleName << '\n'; + errs() << "error: no instruction printer for target " << TripleName + << '\n'; return; } @@ -227,14 +255,24 @@ static void DisassembleInput(const StringRef &Filename) { uint64_t SectSize; if (error(i->getSize(SectSize))) break; + std::vector<RelocationRef>::const_iterator rel_cur = Rels.begin(); + std::vector<RelocationRef>::const_iterator rel_end = Rels.end(); // Disassemble symbol by symbol. for (unsigned si = 0, se = Symbols.size(); si != se; ++si) { uint64_t Start = Symbols[si].first; - uint64_t End = si == se-1 ? SectSize : Symbols[si + 1].first - 1; - outs() << '\n' << Symbols[si].second << ":\n"; + uint64_t End; + // The end is either the size of the section or the beginning of the next + // symbol. + if (si == se - 1) + End = SectSize; + // Make sure this symbol takes up space. + else if (Symbols[si + 1].first != Start) + End = Symbols[si + 1].first - 1; + else + // This symbol has the same address as the next symbol. Skip it. + continue; - for (Index = Start; Index < End; Index += Size) { - MCInst Inst; + outs() << '\n' << Symbols[si].second << ":\n"; #ifndef NDEBUG raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); @@ -242,23 +280,152 @@ static void DisassembleInput(const StringRef &Filename) { raw_ostream &DebugOut = nulls(); #endif - if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, DebugOut)) { - uint64_t addr; - if (error(i->getAddress(addr))) break; - outs() << format("%8x:\t", addr + Index); + for (Index = Start; Index < End; Index += Size) { + MCInst Inst; + + if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, + DebugOut, nulls())) { + outs() << format("%8x:\t", SectionAddr + Index); DumpBytes(StringRef(Bytes.data() + Index, Size)); - IP->printInst(&Inst, outs()); + IP->printInst(&Inst, outs(), ""); outs() << "\n"; } else { errs() << ToolName << ": warning: invalid instruction encoding\n"; if (Size == 0) Size = 1; // skip illegible bytes } + + // Print relocation for instruction. + while (rel_cur != rel_end) { + uint64_t addr; + SmallString<16> name; + SmallString<32> val; + if (error(rel_cur->getAddress(addr))) goto skip_print_rel; + // Stop when rel_cur's address is past the current instruction. + if (addr > Index + Size) break; + if (error(rel_cur->getTypeName(name))) goto skip_print_rel; + if (error(rel_cur->getValueString(val))) goto skip_print_rel; + + outs() << format("\t\t\t%8x: ", SectionAddr + addr) << name << "\t" + << val << "\n"; + + skip_print_rel: + ++rel_cur; + } } } } } +static void PrintRelocations(const ObjectFile *o) { + error_code ec; + for (section_iterator si = o->begin_sections(), se = o->end_sections(); + si != se; si.increment(ec)){ + if (error(ec)) return; + if (si->begin_relocations() == si->end_relocations()) + continue; + StringRef secname; + if (error(si->getName(secname))) continue; + outs() << "RELOCATION RECORDS FOR [" << secname << "]:\n"; + for (relocation_iterator ri = si->begin_relocations(), + re = si->end_relocations(); + ri != re; ri.increment(ec)) { + if (error(ec)) return; + + uint64_t address; + SmallString<32> relocname; + SmallString<32> valuestr; + if (error(ri->getTypeName(relocname))) continue; + if (error(ri->getAddress(address))) continue; + if (error(ri->getValueString(valuestr))) continue; + outs() << address << " " << relocname << " " << valuestr << "\n"; + } + outs() << "\n"; + } +} + +static void PrintSectionHeaders(const ObjectFile *o) { + outs() << "Sections:\n" + "Idx Name Size Address Type\n"; + error_code ec; + unsigned i = 0; + for (section_iterator si = o->begin_sections(), se = o->end_sections(); + si != se; si.increment(ec)) { + if (error(ec)) return; + StringRef Name; + if (error(si->getName(Name))) return; + uint64_t Address; + if (error(si->getAddress(Address))) return; + uint64_t Size; + if (error(si->getSize(Size))) return; + bool Text, Data, BSS; + if (error(si->isText(Text))) return; + if (error(si->isData(Data))) return; + if (error(si->isBSS(BSS))) return; + std::string Type = (std::string(Text ? "TEXT " : "") + + (Data ? "DATA " : "") + (BSS ? "BSS" : "")); + outs() << format("%3d %-13s %09"PRIx64" %017"PRIx64" %s\n", i, Name.str().c_str(), Size, + Address, Type.c_str()); + ++i; + } +} + +static void DumpObject(const ObjectFile *o) { + if (Disassemble) + DisassembleObject(o, Relocations); + if (Relocations && !Disassemble) + PrintRelocations(o); + if (SectionHeaders) + PrintSectionHeaders(o); +} + +/// @brief Dump each object file in \a a; +static void DumpArchive(const Archive *a) { + for (Archive::child_iterator i = a->begin_children(), + e = a->end_children(); i != e; ++i) { + OwningPtr<Binary> child; + if (error_code ec = i->getAsBinary(child)) { + errs() << ToolName << ": '" << a->getFileName() << "': " << ec.message() + << ".\n"; + continue; + } + if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) + 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; + } + + if (MachO && Disassemble) { + DisassembleInputMachO(file); + return; + } + + // Attempt to open the binary. + OwningPtr<Binary> binary; + if (error_code ec = createBinary(file, binary)) { + errs() << ToolName << ": '" << file << "': " << ec.message() << ".\n"; + return; + } + + if (Archive *a = dyn_cast<Archive>(binary.get())) { + DumpArchive(a); + } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) { + DumpObject(o); + } else { + errs() << ToolName << ": '" << file << "': " << "Unrecognized file type.\n"; + } +} + int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); @@ -267,10 +434,7 @@ int main(int argc, char **argv) { // Initialize targets and assembly printers/parsers. llvm::InitializeAllTargetInfos(); - // FIXME: We shouldn't need to initialize the Target(Machine)s. - llvm::InitializeAllTargets(); - llvm::InitializeAllMCAsmInfos(); - llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); llvm::InitializeAllDisassemblers(); @@ -283,15 +447,13 @@ int main(int argc, char **argv) { if (InputFilenames.size() == 0) InputFilenames.push_back("a.out"); - // -d is the only flag that is currently implemented, so just print help if - // it is not set. - if (!Disassemble) { + if (!Disassemble && !Relocations && !SectionHeaders) { cl::PrintHelpMessage(); return 2; } std::for_each(InputFilenames.begin(), InputFilenames.end(), - DisassembleInput); + DumpInput); return 0; } diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h new file mode 100644 index 0000000..75f852a --- /dev/null +++ b/tools/llvm-objdump/llvm-objdump.h @@ -0,0 +1,46 @@ +//===-- llvm-objdump.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJDUMP_H +#define LLVM_OBJDUMP_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MemoryObject.h" + +namespace llvm { + +extern cl::opt<std::string> TripleName; +extern cl::opt<std::string> ArchName; + +// Various helper functions. +void DumpBytes(StringRef bytes); +void DisassembleInputMachO(StringRef Filename); + +class StringRefMemoryObject : public MemoryObject { +private: + StringRef Bytes; +public: + StringRefMemoryObject(StringRef bytes) : Bytes(bytes) {} + + uint64_t getBase() const { return 0; } + uint64_t getExtent() const { return Bytes.size(); } + + int readByte(uint64_t Addr, uint8_t *Byte) const { + if (Addr >= getExtent()) + return -1; + *Byte = Bytes[Addr]; + return 0; + } +}; + +} + +#endif |