1218885Sdim//===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This program is a utility that works like binutils "objdump", that is, it 11218885Sdim// dumps out a plethora of information about an object file depending on the 12218885Sdim// flags. 13218885Sdim// 14249423Sdim// The flags and output of this program should be near identical to those of 15249423Sdim// binutils objdump. 16249423Sdim// 17218885Sdim//===----------------------------------------------------------------------===// 18218885Sdim 19226584Sdim#include "llvm-objdump.h" 20218885Sdim#include "llvm/ADT/OwningPtr.h" 21249423Sdim#include "llvm/ADT/STLExtras.h" 22234353Sdim#include "llvm/ADT/StringExtras.h" 23218885Sdim#include "llvm/ADT/Triple.h" 24218885Sdim#include "llvm/MC/MCAsmInfo.h" 25263508Sdim#include "llvm/MC/MCAtom.h" 26263508Sdim#include "llvm/MC/MCContext.h" 27218885Sdim#include "llvm/MC/MCDisassembler.h" 28263508Sdim#include "llvm/MC/MCFunction.h" 29218885Sdim#include "llvm/MC/MCInst.h" 30218885Sdim#include "llvm/MC/MCInstPrinter.h" 31263508Sdim#include "llvm/MC/MCInstrAnalysis.h" 32234353Sdim#include "llvm/MC/MCInstrInfo.h" 33263508Sdim#include "llvm/MC/MCModule.h" 34263508Sdim#include "llvm/MC/MCModuleYAML.h" 35263508Sdim#include "llvm/MC/MCObjectDisassembler.h" 36263508Sdim#include "llvm/MC/MCObjectFileInfo.h" 37263508Sdim#include "llvm/MC/MCObjectSymbolizer.h" 38234353Sdim#include "llvm/MC/MCRegisterInfo.h" 39263508Sdim#include "llvm/MC/MCRelocationInfo.h" 40226584Sdim#include "llvm/MC/MCSubtargetInfo.h" 41249423Sdim#include "llvm/Object/Archive.h" 42249423Sdim#include "llvm/Object/COFF.h" 43249423Sdim#include "llvm/Object/MachO.h" 44249423Sdim#include "llvm/Object/ObjectFile.h" 45226584Sdim#include "llvm/Support/Casting.h" 46218885Sdim#include "llvm/Support/CommandLine.h" 47218885Sdim#include "llvm/Support/Debug.h" 48226584Sdim#include "llvm/Support/FileSystem.h" 49218885Sdim#include "llvm/Support/Format.h" 50226584Sdim#include "llvm/Support/GraphWriter.h" 51218885Sdim#include "llvm/Support/Host.h" 52218885Sdim#include "llvm/Support/ManagedStatic.h" 53218885Sdim#include "llvm/Support/MemoryBuffer.h" 54218885Sdim#include "llvm/Support/MemoryObject.h" 55218885Sdim#include "llvm/Support/PrettyStackTrace.h" 56218885Sdim#include "llvm/Support/Signals.h" 57218885Sdim#include "llvm/Support/SourceMgr.h" 58226584Sdim#include "llvm/Support/TargetRegistry.h" 59226584Sdim#include "llvm/Support/TargetSelect.h" 60218885Sdim#include "llvm/Support/raw_ostream.h" 61218885Sdim#include "llvm/Support/system_error.h" 62218885Sdim#include <algorithm> 63234353Sdim#include <cctype> 64218885Sdim#include <cstring> 65263508Sdim 66218885Sdimusing namespace llvm; 67218885Sdimusing namespace object; 68218885Sdim 69226584Sdimstatic cl::list<std::string> 70226584SdimInputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore); 71218885Sdim 72226584Sdimstatic cl::opt<bool> 73226584SdimDisassemble("disassemble", 74226584Sdim cl::desc("Display assembler mnemonics for the machine instructions")); 75226584Sdimstatic cl::alias 76226584SdimDisassembled("d", cl::desc("Alias for --disassemble"), 77226584Sdim cl::aliasopt(Disassemble)); 78218885Sdim 79226584Sdimstatic cl::opt<bool> 80226584SdimRelocations("r", cl::desc("Display the relocation entries in the file")); 81226584Sdim 82226584Sdimstatic cl::opt<bool> 83234353SdimSectionContents("s", cl::desc("Display the content of each section")); 84234353Sdim 85234353Sdimstatic cl::opt<bool> 86234353SdimSymbolTable("t", cl::desc("Display the symbol table")); 87234353Sdim 88234353Sdimstatic cl::opt<bool> 89249423SdimMachOOpt("macho", cl::desc("Use MachO specific object file parser")); 90226584Sdimstatic cl::alias 91249423SdimMachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachOOpt)); 92226584Sdim 93226584Sdimcl::opt<std::string> 94226584Sdimllvm::TripleName("triple", cl::desc("Target triple to disassemble for, " 95226584Sdim "see -version for available targets")); 96226584Sdim 97226584Sdimcl::opt<std::string> 98226584Sdimllvm::ArchName("arch", cl::desc("Target arch to disassemble for, " 99218885Sdim "see -version for available targets")); 100218885Sdim 101226584Sdimstatic cl::opt<bool> 102226584SdimSectionHeaders("section-headers", cl::desc("Display summaries of the headers " 103226584Sdim "for each section.")); 104226584Sdimstatic cl::alias 105226584SdimSectionHeadersShort("headers", cl::desc("Alias for --section-headers"), 106226584Sdim cl::aliasopt(SectionHeaders)); 107226584Sdimstatic cl::alias 108226584SdimSectionHeadersShorter("h", cl::desc("Alias for --section-headers"), 109226584Sdim cl::aliasopt(SectionHeaders)); 110218885Sdim 111243830Sdimstatic cl::list<std::string> 112243830SdimMAttrs("mattr", 113243830Sdim cl::CommaSeparated, 114243830Sdim cl::desc("Target specific attributes"), 115243830Sdim cl::value_desc("a1,+a2,-a3,...")); 116243830Sdim 117249423Sdimstatic cl::opt<bool> 118249423SdimNoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling instructions, " 119249423Sdim "do not print the instruction bytes.")); 120249423Sdim 121249423Sdimstatic cl::opt<bool> 122249423SdimUnwindInfo("unwind-info", cl::desc("Display unwind information")); 123249423Sdim 124249423Sdimstatic cl::alias 125249423SdimUnwindInfoShort("u", cl::desc("Alias for --unwind-info"), 126249423Sdim cl::aliasopt(UnwindInfo)); 127249423Sdim 128249423Sdimstatic cl::opt<bool> 129249423SdimPrivateHeaders("private-headers", 130249423Sdim cl::desc("Display format specific file headers")); 131249423Sdim 132249423Sdimstatic cl::alias 133249423SdimPrivateHeadersShort("p", cl::desc("Alias for --private-headers"), 134249423Sdim cl::aliasopt(PrivateHeaders)); 135249423Sdim 136263508Sdimstatic cl::opt<bool> 137263508SdimSymbolize("symbolize", cl::desc("When disassembling instructions, " 138263508Sdim "try to symbolize operands.")); 139263508Sdim 140263508Sdimstatic cl::opt<bool> 141263508SdimCFG("cfg", cl::desc("Create a CFG for every function found in the object" 142263508Sdim " and write it to a graphviz file")); 143263508Sdim 144263508Sdim// FIXME: Does it make sense to have a dedicated tool for yaml cfg output? 145263508Sdimstatic cl::opt<std::string> 146263508SdimYAMLCFG("yaml-cfg", 147263508Sdim cl::desc("Create a CFG and write it as a YAML MCModule."), 148263508Sdim cl::value_desc("yaml output file")); 149263508Sdim 150226584Sdimstatic StringRef ToolName; 151224133Sdim 152249423Sdimbool llvm::error(error_code ec) { 153226584Sdim if (!ec) return false; 154224133Sdim 155226584Sdim outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; 156226584Sdim outs().flush(); 157226584Sdim return true; 158218885Sdim} 159218885Sdim 160239462Sdimstatic const Target *getTarget(const ObjectFile *Obj = NULL) { 161218885Sdim // Figure out the target triple. 162239462Sdim llvm::Triple TheTriple("unknown-unknown-unknown"); 163218885Sdim if (TripleName.empty()) { 164263508Sdim if (Obj) { 165239462Sdim TheTriple.setArch(Triple::ArchType(Obj->getArch())); 166263508Sdim // TheTriple defaults to ELF, and COFF doesn't have an environment: 167263508Sdim // the best we can do here is indicate that it is mach-o. 168263508Sdim if (Obj->isMachO()) 169263508Sdim TheTriple.setEnvironment(Triple::MachO); 170263508Sdim } 171218885Sdim } else 172239462Sdim TheTriple.setTriple(Triple::normalize(TripleName)); 173218885Sdim 174218885Sdim // Get the target specific parser. 175218885Sdim std::string Error; 176239462Sdim const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple, 177239462Sdim Error); 178239462Sdim if (!TheTarget) { 179239462Sdim errs() << ToolName << ": " << Error; 180239462Sdim return 0; 181239462Sdim } 182218885Sdim 183239462Sdim // Update the triple name and return the found target. 184239462Sdim TripleName = TheTriple.getTriple(); 185239462Sdim return TheTarget; 186218885Sdim} 187218885Sdim 188263508Sdim// Write a graphviz file for the CFG inside an MCFunction. 189263508Sdim// FIXME: Use GraphWriter 190263508Sdimstatic void emitDOTFile(const char *FileName, const MCFunction &f, 191263508Sdim MCInstPrinter *IP) { 192263508Sdim // Start a new dot file. 193263508Sdim std::string Error; 194263508Sdim raw_fd_ostream Out(FileName, Error); 195263508Sdim if (!Error.empty()) { 196263508Sdim errs() << "llvm-objdump: warning: " << Error << '\n'; 197263508Sdim return; 198263508Sdim } 199234353Sdim 200263508Sdim Out << "digraph \"" << f.getName() << "\" {\n"; 201263508Sdim Out << "graph [ rankdir = \"LR\" ];\n"; 202263508Sdim for (MCFunction::const_iterator i = f.begin(), e = f.end(); i != e; ++i) { 203263508Sdim // Only print blocks that have predecessors. 204263508Sdim bool hasPreds = (*i)->pred_begin() != (*i)->pred_end(); 205263508Sdim 206263508Sdim if (!hasPreds && i != f.begin()) 207263508Sdim continue; 208263508Sdim 209263508Sdim Out << '"' << (*i)->getInsts()->getBeginAddr() << "\" [ label=\"<a>"; 210263508Sdim // Print instructions. 211263508Sdim for (unsigned ii = 0, ie = (*i)->getInsts()->size(); ii != ie; 212263508Sdim ++ii) { 213263508Sdim if (ii != 0) // Not the first line, start a new row. 214263508Sdim Out << '|'; 215263508Sdim if (ii + 1 == ie) // Last line, add an end id. 216263508Sdim Out << "<o>"; 217263508Sdim 218263508Sdim // Escape special chars and print the instruction in mnemonic form. 219263508Sdim std::string Str; 220263508Sdim raw_string_ostream OS(Str); 221263508Sdim IP->printInst(&(*i)->getInsts()->at(ii).Inst, OS, ""); 222263508Sdim Out << DOT::EscapeString(OS.str()); 223263508Sdim } 224263508Sdim Out << "\" shape=\"record\" ];\n"; 225263508Sdim 226263508Sdim // Add edges. 227263508Sdim for (MCBasicBlock::succ_const_iterator si = (*i)->succ_begin(), 228263508Sdim se = (*i)->succ_end(); si != se; ++si) 229263508Sdim Out << (*i)->getInsts()->getBeginAddr() << ":o -> " 230263508Sdim << (*si)->getInsts()->getBeginAddr() << ":a\n"; 231263508Sdim } 232263508Sdim Out << "}\n"; 233263508Sdim} 234263508Sdim 235226584Sdimvoid llvm::DumpBytes(StringRef bytes) { 236226584Sdim static const char hex_rep[] = "0123456789abcdef"; 237218885Sdim // FIXME: The real way to do this is to figure out the longest instruction 238218885Sdim // and align to that size before printing. I'll fix this when I get 239218885Sdim // around to outputting relocations. 240218885Sdim // 15 is the longest x86 instruction 241218885Sdim // 3 is for the hex rep of a byte + a space. 242218885Sdim // 1 is for the null terminator. 243218885Sdim enum { OutputSize = (15 * 3) + 1 }; 244218885Sdim char output[OutputSize]; 245218885Sdim 246218885Sdim assert(bytes.size() <= 15 247218885Sdim && "DumpBytes only supports instructions of up to 15 bytes"); 248218885Sdim memset(output, ' ', sizeof(output)); 249218885Sdim unsigned index = 0; 250218885Sdim for (StringRef::iterator i = bytes.begin(), 251218885Sdim e = bytes.end(); i != e; ++i) { 252218885Sdim output[index] = hex_rep[(*i & 0xF0) >> 4]; 253218885Sdim output[index + 1] = hex_rep[*i & 0xF]; 254218885Sdim index += 3; 255218885Sdim } 256218885Sdim 257218885Sdim output[sizeof(output) - 1] = 0; 258218885Sdim outs() << output; 259218885Sdim} 260218885Sdim 261249423Sdimbool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) { 262226584Sdim uint64_t a_addr, b_addr; 263251662Sdim if (error(a.getOffset(a_addr))) return false; 264251662Sdim if (error(b.getOffset(b_addr))) return false; 265226584Sdim return a_addr < b_addr; 266226584Sdim} 267218885Sdim 268226584Sdimstatic void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { 269239462Sdim const Target *TheTarget = getTarget(Obj); 270239462Sdim // getTarget() will have already issued a diagnostic if necessary, so 271239462Sdim // just bail here if it failed. 272239462Sdim if (!TheTarget) 273218885Sdim return; 274218885Sdim 275243830Sdim // Package up features to be passed to target/subtarget 276243830Sdim std::string FeaturesStr; 277243830Sdim if (MAttrs.size()) { 278243830Sdim SubtargetFeatures Features; 279243830Sdim for (unsigned i = 0; i != MAttrs.size(); ++i) 280243830Sdim Features.AddFeature(MAttrs[i]); 281243830Sdim FeaturesStr = Features.getString(); 282243830Sdim } 283243830Sdim 284263508Sdim OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); 285263508Sdim if (!MRI) { 286263508Sdim errs() << "error: no register info for target " << TripleName << "\n"; 287263508Sdim return; 288263508Sdim } 289263508Sdim 290263508Sdim // Set up disassembler. 291263508Sdim OwningPtr<const MCAsmInfo> AsmInfo( 292263508Sdim TheTarget->createMCAsmInfo(*MRI, TripleName)); 293263508Sdim if (!AsmInfo) { 294263508Sdim errs() << "error: no assembly info for target " << TripleName << "\n"; 295263508Sdim return; 296263508Sdim } 297263508Sdim 298263508Sdim OwningPtr<const MCSubtargetInfo> STI( 299263508Sdim TheTarget->createMCSubtargetInfo(TripleName, "", FeaturesStr)); 300263508Sdim if (!STI) { 301263508Sdim errs() << "error: no subtarget info for target " << TripleName << "\n"; 302263508Sdim return; 303263508Sdim } 304263508Sdim 305263508Sdim OwningPtr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo()); 306263508Sdim if (!MII) { 307263508Sdim errs() << "error: no instruction info for target " << TripleName << "\n"; 308263508Sdim return; 309263508Sdim } 310263508Sdim 311263508Sdim OwningPtr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); 312263508Sdim if (!DisAsm) { 313263508Sdim errs() << "error: no disassembler for target " << TripleName << "\n"; 314263508Sdim return; 315263508Sdim } 316263508Sdim 317263508Sdim OwningPtr<const MCObjectFileInfo> MOFI; 318263508Sdim OwningPtr<MCContext> Ctx; 319263508Sdim 320263508Sdim if (Symbolize) { 321263508Sdim MOFI.reset(new MCObjectFileInfo); 322263508Sdim Ctx.reset(new MCContext(AsmInfo.get(), MRI.get(), MOFI.get())); 323263508Sdim OwningPtr<MCRelocationInfo> RelInfo( 324263508Sdim TheTarget->createMCRelocationInfo(TripleName, *Ctx.get())); 325263508Sdim if (RelInfo) { 326263508Sdim OwningPtr<MCSymbolizer> Symzer( 327263508Sdim MCObjectSymbolizer::createObjectSymbolizer(*Ctx.get(), RelInfo, Obj)); 328263508Sdim if (Symzer) 329263508Sdim DisAsm->setSymbolizer(Symzer); 330263508Sdim } 331263508Sdim } 332263508Sdim 333263508Sdim OwningPtr<const MCInstrAnalysis> 334263508Sdim MIA(TheTarget->createMCInstrAnalysis(MII.get())); 335263508Sdim 336263508Sdim int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 337263508Sdim OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( 338263508Sdim AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI)); 339263508Sdim if (!IP) { 340263508Sdim errs() << "error: no instruction printer for target " << TripleName 341263508Sdim << '\n'; 342263508Sdim return; 343263508Sdim } 344263508Sdim 345263508Sdim if (CFG || !YAMLCFG.empty()) { 346263508Sdim OwningPtr<MCObjectDisassembler> OD( 347263508Sdim new MCObjectDisassembler(*Obj, *DisAsm, *MIA)); 348263508Sdim OwningPtr<MCModule> Mod(OD->buildModule(/* withCFG */ true)); 349263508Sdim for (MCModule::const_atom_iterator AI = Mod->atom_begin(), 350263508Sdim AE = Mod->atom_end(); 351263508Sdim AI != AE; ++AI) { 352263508Sdim outs() << "Atom " << (*AI)->getName() << ": \n"; 353263508Sdim if (const MCTextAtom *TA = dyn_cast<MCTextAtom>(*AI)) { 354263508Sdim for (MCTextAtom::const_iterator II = TA->begin(), IE = TA->end(); 355263508Sdim II != IE; 356263508Sdim ++II) { 357263508Sdim IP->printInst(&II->Inst, outs(), ""); 358263508Sdim outs() << "\n"; 359263508Sdim } 360263508Sdim } 361263508Sdim } 362263508Sdim if (CFG) { 363263508Sdim for (MCModule::const_func_iterator FI = Mod->func_begin(), 364263508Sdim FE = Mod->func_end(); 365263508Sdim FI != FE; ++FI) { 366263508Sdim static int filenum = 0; 367263508Sdim emitDOTFile((Twine((*FI)->getName()) + "_" + 368263508Sdim utostr(filenum) + ".dot").str().c_str(), 369263508Sdim **FI, IP.get()); 370263508Sdim ++filenum; 371263508Sdim } 372263508Sdim } 373263508Sdim if (!YAMLCFG.empty()) { 374263508Sdim std::string Error; 375263508Sdim raw_fd_ostream YAMLOut(YAMLCFG.c_str(), Error); 376263508Sdim if (!Error.empty()) { 377263508Sdim errs() << ToolName << ": warning: " << Error << '\n'; 378263508Sdim return; 379263508Sdim } 380263508Sdim mcmodule2yaml(YAMLOut, *Mod, *MII, *MRI); 381263508Sdim } 382263508Sdim } 383263508Sdim 384263508Sdim 385224133Sdim error_code ec; 386226584Sdim for (section_iterator i = Obj->begin_sections(), 387226584Sdim e = Obj->end_sections(); 388226584Sdim i != e; i.increment(ec)) { 389224133Sdim if (error(ec)) break; 390224133Sdim bool text; 391224133Sdim if (error(i->isText(text))) break; 392224133Sdim if (!text) continue; 393218885Sdim 394226584Sdim uint64_t SectionAddr; 395226584Sdim if (error(i->getAddress(SectionAddr))) break; 396226584Sdim 397224133Sdim // Make a list of all the symbols in this section. 398224133Sdim std::vector<std::pair<uint64_t, StringRef> > Symbols; 399226584Sdim for (symbol_iterator si = Obj->begin_symbols(), 400226584Sdim se = Obj->end_symbols(); 401226584Sdim si != se; si.increment(ec)) { 402224133Sdim bool contains; 403224133Sdim if (!error(i->containsSymbol(*si, contains)) && contains) { 404224133Sdim uint64_t Address; 405234353Sdim if (error(si->getAddress(Address))) break; 406249423Sdim if (Address == UnknownAddressOrSize) continue; 407234353Sdim Address -= SectionAddr; 408234353Sdim 409224133Sdim StringRef Name; 410224133Sdim if (error(si->getName(Name))) break; 411224133Sdim Symbols.push_back(std::make_pair(Address, Name)); 412224133Sdim } 413224133Sdim } 414224133Sdim 415224133Sdim // Sort the symbols by address, just in case they didn't come in that way. 416224133Sdim array_pod_sort(Symbols.begin(), Symbols.end()); 417224133Sdim 418226584Sdim // Make a list of all the relocations for this section. 419226584Sdim std::vector<RelocationRef> Rels; 420226584Sdim if (InlineRelocs) { 421226584Sdim for (relocation_iterator ri = i->begin_relocations(), 422226584Sdim re = i->end_relocations(); 423239462Sdim ri != re; ri.increment(ec)) { 424226584Sdim if (error(ec)) break; 425226584Sdim Rels.push_back(*ri); 426226584Sdim } 427226584Sdim } 428226584Sdim 429226584Sdim // Sort relocations by address. 430226584Sdim std::sort(Rels.begin(), Rels.end(), RelocAddressLess); 431226584Sdim 432249423Sdim StringRef SegmentName = ""; 433251662Sdim if (const MachOObjectFile *MachO = 434251662Sdim dyn_cast<const MachOObjectFile>(Obj)) { 435249423Sdim DataRefImpl DR = i->getRawDataRefImpl(); 436251662Sdim SegmentName = MachO->getSectionFinalSegmentName(DR); 437249423Sdim } 438224133Sdim StringRef name; 439224133Sdim if (error(i->getName(name))) break; 440249423Sdim outs() << "Disassembly of section "; 441249423Sdim if (!SegmentName.empty()) 442249423Sdim outs() << SegmentName << ","; 443249423Sdim outs() << name << ':'; 444224133Sdim 445224133Sdim // If the section has no symbols just insert a dummy one and disassemble 446224133Sdim // the whole section. 447224133Sdim if (Symbols.empty()) 448224133Sdim Symbols.push_back(std::make_pair(0, name)); 449224133Sdim 450218885Sdim 451263508Sdim SmallString<40> Comments; 452263508Sdim raw_svector_ostream CommentStream(Comments); 453218885Sdim 454224133Sdim StringRef Bytes; 455224133Sdim if (error(i->getContents(Bytes))) break; 456263508Sdim StringRefMemoryObject memoryObject(Bytes, SectionAddr); 457218885Sdim uint64_t Size; 458218885Sdim uint64_t Index; 459224133Sdim uint64_t SectSize; 460224133Sdim if (error(i->getSize(SectSize))) break; 461218885Sdim 462226584Sdim std::vector<RelocationRef>::const_iterator rel_cur = Rels.begin(); 463226584Sdim std::vector<RelocationRef>::const_iterator rel_end = Rels.end(); 464224133Sdim // Disassemble symbol by symbol. 465224133Sdim for (unsigned si = 0, se = Symbols.size(); si != se; ++si) { 466224133Sdim uint64_t Start = Symbols[si].first; 467226584Sdim uint64_t End; 468226584Sdim // The end is either the size of the section or the beginning of the next 469226584Sdim // symbol. 470226584Sdim if (si == se - 1) 471226584Sdim End = SectSize; 472226584Sdim // Make sure this symbol takes up space. 473226584Sdim else if (Symbols[si + 1].first != Start) 474226584Sdim End = Symbols[si + 1].first - 1; 475226584Sdim else 476226584Sdim // This symbol has the same address as the next symbol. Skip it. 477226584Sdim continue; 478226584Sdim 479224133Sdim outs() << '\n' << Symbols[si].second << ":\n"; 480218885Sdim 481224133Sdim#ifndef NDEBUG 482224133Sdim raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); 483224133Sdim#else 484224133Sdim raw_ostream &DebugOut = nulls(); 485224133Sdim#endif 486224133Sdim 487226584Sdim for (Index = Start; Index < End; Index += Size) { 488226584Sdim MCInst Inst; 489226584Sdim 490263508Sdim if (DisAsm->getInstruction(Inst, Size, memoryObject, 491263508Sdim SectionAddr + Index, 492263508Sdim DebugOut, CommentStream)) { 493249423Sdim outs() << format("%8" PRIx64 ":", SectionAddr + Index); 494249423Sdim if (!NoShowRawInsn) { 495249423Sdim outs() << "\t"; 496249423Sdim DumpBytes(StringRef(Bytes.data() + Index, Size)); 497249423Sdim } 498226584Sdim IP->printInst(&Inst, outs(), ""); 499263508Sdim outs() << CommentStream.str(); 500263508Sdim Comments.clear(); 501224133Sdim outs() << "\n"; 502224133Sdim } else { 503224133Sdim errs() << ToolName << ": warning: invalid instruction encoding\n"; 504224133Sdim if (Size == 0) 505224133Sdim Size = 1; // skip illegible bytes 506224133Sdim } 507226584Sdim 508226584Sdim // Print relocation for instruction. 509226584Sdim while (rel_cur != rel_end) { 510234353Sdim bool hidden = false; 511226584Sdim uint64_t addr; 512226584Sdim SmallString<16> name; 513226584Sdim SmallString<32> val; 514234353Sdim 515234353Sdim // If this relocation is hidden, skip it. 516234353Sdim if (error(rel_cur->getHidden(hidden))) goto skip_print_rel; 517234353Sdim if (hidden) goto skip_print_rel; 518234353Sdim 519251662Sdim if (error(rel_cur->getOffset(addr))) goto skip_print_rel; 520226584Sdim // Stop when rel_cur's address is past the current instruction. 521234353Sdim if (addr >= Index + Size) break; 522226584Sdim if (error(rel_cur->getTypeName(name))) goto skip_print_rel; 523226584Sdim if (error(rel_cur->getValueString(val))) goto skip_print_rel; 524226584Sdim 525234353Sdim outs() << format("\t\t\t%8" PRIx64 ": ", SectionAddr + addr) << name 526234353Sdim << "\t" << val << "\n"; 527226584Sdim 528226584Sdim skip_print_rel: 529226584Sdim ++rel_cur; 530226584Sdim } 531218885Sdim } 532218885Sdim } 533218885Sdim } 534218885Sdim} 535218885Sdim 536226584Sdimstatic void PrintRelocations(const ObjectFile *o) { 537226584Sdim error_code ec; 538226584Sdim for (section_iterator si = o->begin_sections(), se = o->end_sections(); 539226584Sdim si != se; si.increment(ec)){ 540226584Sdim if (error(ec)) return; 541226584Sdim if (si->begin_relocations() == si->end_relocations()) 542226584Sdim continue; 543226584Sdim StringRef secname; 544226584Sdim if (error(si->getName(secname))) continue; 545226584Sdim outs() << "RELOCATION RECORDS FOR [" << secname << "]:\n"; 546226584Sdim for (relocation_iterator ri = si->begin_relocations(), 547226584Sdim re = si->end_relocations(); 548226584Sdim ri != re; ri.increment(ec)) { 549226584Sdim if (error(ec)) return; 550226584Sdim 551234353Sdim bool hidden; 552226584Sdim uint64_t address; 553226584Sdim SmallString<32> relocname; 554226584Sdim SmallString<32> valuestr; 555234353Sdim if (error(ri->getHidden(hidden))) continue; 556234353Sdim if (hidden) continue; 557226584Sdim if (error(ri->getTypeName(relocname))) continue; 558251662Sdim if (error(ri->getOffset(address))) continue; 559226584Sdim if (error(ri->getValueString(valuestr))) continue; 560226584Sdim outs() << address << " " << relocname << " " << valuestr << "\n"; 561226584Sdim } 562226584Sdim outs() << "\n"; 563226584Sdim } 564226584Sdim} 565226584Sdim 566226584Sdimstatic void PrintSectionHeaders(const ObjectFile *o) { 567226584Sdim outs() << "Sections:\n" 568226584Sdim "Idx Name Size Address Type\n"; 569226584Sdim error_code ec; 570226584Sdim unsigned i = 0; 571226584Sdim for (section_iterator si = o->begin_sections(), se = o->end_sections(); 572226584Sdim si != se; si.increment(ec)) { 573226584Sdim if (error(ec)) return; 574226584Sdim StringRef Name; 575226584Sdim if (error(si->getName(Name))) return; 576226584Sdim uint64_t Address; 577226584Sdim if (error(si->getAddress(Address))) return; 578226584Sdim uint64_t Size; 579226584Sdim if (error(si->getSize(Size))) return; 580226584Sdim bool Text, Data, BSS; 581226584Sdim if (error(si->isText(Text))) return; 582226584Sdim if (error(si->isData(Data))) return; 583226584Sdim if (error(si->isBSS(BSS))) return; 584226584Sdim std::string Type = (std::string(Text ? "TEXT " : "") + 585226584Sdim (Data ? "DATA " : "") + (BSS ? "BSS" : "")); 586249423Sdim outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", 587234353Sdim i, Name.str().c_str(), Size, Address, Type.c_str()); 588226584Sdim ++i; 589226584Sdim } 590226584Sdim} 591226584Sdim 592234353Sdimstatic void PrintSectionContents(const ObjectFile *o) { 593234353Sdim error_code ec; 594234353Sdim for (section_iterator si = o->begin_sections(), 595234353Sdim se = o->end_sections(); 596234353Sdim si != se; si.increment(ec)) { 597234353Sdim if (error(ec)) return; 598234353Sdim StringRef Name; 599234353Sdim StringRef Contents; 600234353Sdim uint64_t BaseAddr; 601251662Sdim bool BSS; 602234353Sdim if (error(si->getName(Name))) continue; 603234353Sdim if (error(si->getContents(Contents))) continue; 604234353Sdim if (error(si->getAddress(BaseAddr))) continue; 605251662Sdim if (error(si->isBSS(BSS))) continue; 606234353Sdim 607234353Sdim outs() << "Contents of section " << Name << ":\n"; 608251662Sdim if (BSS) { 609251662Sdim outs() << format("<skipping contents of bss section at [%04" PRIx64 610251662Sdim ", %04" PRIx64 ")>\n", BaseAddr, 611251662Sdim BaseAddr + Contents.size()); 612251662Sdim continue; 613251662Sdim } 614234353Sdim 615234353Sdim // Dump out the content as hex and printable ascii characters. 616234353Sdim for (std::size_t addr = 0, end = Contents.size(); addr < end; addr += 16) { 617234353Sdim outs() << format(" %04" PRIx64 " ", BaseAddr + addr); 618234353Sdim // Dump line of hex. 619234353Sdim for (std::size_t i = 0; i < 16; ++i) { 620234353Sdim if (i != 0 && i % 4 == 0) 621234353Sdim outs() << ' '; 622234353Sdim if (addr + i < end) 623234353Sdim outs() << hexdigit((Contents[addr + i] >> 4) & 0xF, true) 624234353Sdim << hexdigit(Contents[addr + i] & 0xF, true); 625234353Sdim else 626234353Sdim outs() << " "; 627234353Sdim } 628234353Sdim // Print ascii. 629234353Sdim outs() << " "; 630234353Sdim for (std::size_t i = 0; i < 16 && addr + i < end; ++i) { 631249423Sdim if (std::isprint(static_cast<unsigned char>(Contents[addr + i]) & 0xFF)) 632234353Sdim outs() << Contents[addr + i]; 633234353Sdim else 634234353Sdim outs() << "."; 635234353Sdim } 636234353Sdim outs() << "\n"; 637234353Sdim } 638234353Sdim } 639234353Sdim} 640234353Sdim 641234353Sdimstatic void PrintCOFFSymbolTable(const COFFObjectFile *coff) { 642234353Sdim const coff_file_header *header; 643234353Sdim if (error(coff->getHeader(header))) return; 644234353Sdim int aux_count = 0; 645234353Sdim const coff_symbol *symbol = 0; 646234353Sdim for (int i = 0, e = header->NumberOfSymbols; i != e; ++i) { 647234353Sdim if (aux_count--) { 648234353Sdim // Figure out which type of aux this is. 649234353Sdim if (symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC 650234353Sdim && symbol->Value == 0) { // Section definition. 651234353Sdim const coff_aux_section_definition *asd; 652234353Sdim if (error(coff->getAuxSymbol<coff_aux_section_definition>(i, asd))) 653234353Sdim return; 654234353Sdim outs() << "AUX " 655234353Sdim << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x " 656234353Sdim , unsigned(asd->Length) 657234353Sdim , unsigned(asd->NumberOfRelocations) 658234353Sdim , unsigned(asd->NumberOfLinenumbers) 659234353Sdim , unsigned(asd->CheckSum)) 660234353Sdim << format("assoc %d comdat %d\n" 661234353Sdim , unsigned(asd->Number) 662234353Sdim , unsigned(asd->Selection)); 663239462Sdim } else 664234353Sdim outs() << "AUX Unknown\n"; 665234353Sdim } else { 666234353Sdim StringRef name; 667234353Sdim if (error(coff->getSymbol(i, symbol))) return; 668234353Sdim if (error(coff->getSymbolName(symbol, name))) return; 669234353Sdim outs() << "[" << format("%2d", i) << "]" 670234353Sdim << "(sec " << format("%2d", int(symbol->SectionNumber)) << ")" 671234353Sdim << "(fl 0x00)" // Flag bits, which COFF doesn't have. 672234353Sdim << "(ty " << format("%3x", unsigned(symbol->Type)) << ")" 673234353Sdim << "(scl " << format("%3x", unsigned(symbol->StorageClass)) << ") " 674234353Sdim << "(nx " << unsigned(symbol->NumberOfAuxSymbols) << ") " 675234353Sdim << "0x" << format("%08x", unsigned(symbol->Value)) << " " 676234353Sdim << name << "\n"; 677234353Sdim aux_count = symbol->NumberOfAuxSymbols; 678234353Sdim } 679234353Sdim } 680234353Sdim} 681234353Sdim 682234353Sdimstatic void PrintSymbolTable(const ObjectFile *o) { 683234353Sdim outs() << "SYMBOL TABLE:\n"; 684234353Sdim 685234353Sdim if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o)) 686234353Sdim PrintCOFFSymbolTable(coff); 687234353Sdim else { 688234353Sdim error_code ec; 689234353Sdim for (symbol_iterator si = o->begin_symbols(), 690234353Sdim se = o->end_symbols(); si != se; si.increment(ec)) { 691234353Sdim if (error(ec)) return; 692234353Sdim StringRef Name; 693234353Sdim uint64_t Address; 694234353Sdim SymbolRef::Type Type; 695234353Sdim uint64_t Size; 696234353Sdim uint32_t Flags; 697234353Sdim section_iterator Section = o->end_sections(); 698234353Sdim if (error(si->getName(Name))) continue; 699234353Sdim if (error(si->getAddress(Address))) continue; 700234353Sdim if (error(si->getFlags(Flags))) continue; 701234353Sdim if (error(si->getType(Type))) continue; 702234353Sdim if (error(si->getSize(Size))) continue; 703234353Sdim if (error(si->getSection(Section))) continue; 704234353Sdim 705234353Sdim bool Global = Flags & SymbolRef::SF_Global; 706234353Sdim bool Weak = Flags & SymbolRef::SF_Weak; 707234353Sdim bool Absolute = Flags & SymbolRef::SF_Absolute; 708234353Sdim 709234353Sdim if (Address == UnknownAddressOrSize) 710234353Sdim Address = 0; 711234353Sdim if (Size == UnknownAddressOrSize) 712234353Sdim Size = 0; 713234353Sdim char GlobLoc = ' '; 714234353Sdim if (Type != SymbolRef::ST_Unknown) 715234353Sdim GlobLoc = Global ? 'g' : 'l'; 716234353Sdim char Debug = (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File) 717234353Sdim ? 'd' : ' '; 718234353Sdim char FileFunc = ' '; 719234353Sdim if (Type == SymbolRef::ST_File) 720234353Sdim FileFunc = 'f'; 721234353Sdim else if (Type == SymbolRef::ST_Function) 722234353Sdim FileFunc = 'F'; 723234353Sdim 724249423Sdim const char *Fmt = o->getBytesInAddress() > 4 ? "%016" PRIx64 : 725249423Sdim "%08" PRIx64; 726249423Sdim 727249423Sdim outs() << format(Fmt, Address) << " " 728234353Sdim << GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' ' 729234353Sdim << (Weak ? 'w' : ' ') // Weak? 730234353Sdim << ' ' // Constructor. Not supported yet. 731234353Sdim << ' ' // Warning. Not supported yet. 732234353Sdim << ' ' // Indirect reference to another symbol. 733234353Sdim << Debug // Debugging (d) or dynamic (D) symbol. 734234353Sdim << FileFunc // Name of function (F), file (f) or object (O). 735234353Sdim << ' '; 736234353Sdim if (Absolute) 737234353Sdim outs() << "*ABS*"; 738234353Sdim else if (Section == o->end_sections()) 739234353Sdim outs() << "*UND*"; 740234353Sdim else { 741251662Sdim if (const MachOObjectFile *MachO = 742251662Sdim dyn_cast<const MachOObjectFile>(o)) { 743249423Sdim DataRefImpl DR = Section->getRawDataRefImpl(); 744251662Sdim StringRef SegmentName = MachO->getSectionFinalSegmentName(DR); 745249423Sdim outs() << SegmentName << ","; 746249423Sdim } 747234353Sdim StringRef SectionName; 748234353Sdim if (error(Section->getName(SectionName))) 749234353Sdim SectionName = ""; 750234353Sdim outs() << SectionName; 751234353Sdim } 752234353Sdim outs() << '\t' 753234353Sdim << format("%08" PRIx64 " ", Size) 754234353Sdim << Name 755234353Sdim << '\n'; 756234353Sdim } 757234353Sdim } 758234353Sdim} 759234353Sdim 760249423Sdimstatic void PrintUnwindInfo(const ObjectFile *o) { 761249423Sdim outs() << "Unwind info:\n\n"; 762249423Sdim 763249423Sdim if (const COFFObjectFile *coff = dyn_cast<COFFObjectFile>(o)) { 764249423Sdim printCOFFUnwindInfo(coff); 765249423Sdim } else { 766249423Sdim // TODO: Extract DWARF dump tool to objdump. 767249423Sdim errs() << "This operation is only currently supported " 768249423Sdim "for COFF object files.\n"; 769249423Sdim return; 770249423Sdim } 771249423Sdim} 772249423Sdim 773263508Sdimstatic void printPrivateFileHeader(const ObjectFile *o) { 774263508Sdim if (o->isELF()) { 775263508Sdim printELFFileHeader(o); 776263508Sdim } else if (o->isCOFF()) { 777263508Sdim printCOFFFileHeader(o); 778263508Sdim } 779263508Sdim} 780263508Sdim 781226584Sdimstatic void DumpObject(const ObjectFile *o) { 782234353Sdim outs() << '\n'; 783234353Sdim outs() << o->getFileName() 784234353Sdim << ":\tfile format " << o->getFileFormatName() << "\n\n"; 785234353Sdim 786226584Sdim if (Disassemble) 787226584Sdim DisassembleObject(o, Relocations); 788226584Sdim if (Relocations && !Disassemble) 789226584Sdim PrintRelocations(o); 790226584Sdim if (SectionHeaders) 791226584Sdim PrintSectionHeaders(o); 792234353Sdim if (SectionContents) 793234353Sdim PrintSectionContents(o); 794234353Sdim if (SymbolTable) 795234353Sdim PrintSymbolTable(o); 796249423Sdim if (UnwindInfo) 797249423Sdim PrintUnwindInfo(o); 798263508Sdim if (PrivateHeaders) 799263508Sdim printPrivateFileHeader(o); 800226584Sdim} 801226584Sdim 802226584Sdim/// @brief Dump each object file in \a a; 803226584Sdimstatic void DumpArchive(const Archive *a) { 804226584Sdim for (Archive::child_iterator i = a->begin_children(), 805226584Sdim e = a->end_children(); i != e; ++i) { 806226584Sdim OwningPtr<Binary> child; 807226584Sdim if (error_code ec = i->getAsBinary(child)) { 808234353Sdim // Ignore non-object files. 809234353Sdim if (ec != object_error::invalid_file_type) 810234353Sdim errs() << ToolName << ": '" << a->getFileName() << "': " << ec.message() 811234353Sdim << ".\n"; 812226584Sdim continue; 813226584Sdim } 814226584Sdim if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) 815226584Sdim DumpObject(o); 816226584Sdim else 817226584Sdim errs() << ToolName << ": '" << a->getFileName() << "': " 818226584Sdim << "Unrecognized file type.\n"; 819226584Sdim } 820226584Sdim} 821226584Sdim 822226584Sdim/// @brief Open file and figure out how to dump it. 823226584Sdimstatic void DumpInput(StringRef file) { 824226584Sdim // If file isn't stdin, check that it exists. 825226584Sdim if (file != "-" && !sys::fs::exists(file)) { 826226584Sdim errs() << ToolName << ": '" << file << "': " << "No such file\n"; 827226584Sdim return; 828226584Sdim } 829226584Sdim 830249423Sdim if (MachOOpt && Disassemble) { 831226584Sdim DisassembleInputMachO(file); 832226584Sdim return; 833226584Sdim } 834226584Sdim 835226584Sdim // Attempt to open the binary. 836226584Sdim OwningPtr<Binary> binary; 837226584Sdim if (error_code ec = createBinary(file, binary)) { 838226584Sdim errs() << ToolName << ": '" << file << "': " << ec.message() << ".\n"; 839226584Sdim return; 840226584Sdim } 841226584Sdim 842239462Sdim if (Archive *a = dyn_cast<Archive>(binary.get())) 843226584Sdim DumpArchive(a); 844239462Sdim else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) 845226584Sdim DumpObject(o); 846239462Sdim else 847226584Sdim errs() << ToolName << ": '" << file << "': " << "Unrecognized file type.\n"; 848226584Sdim} 849226584Sdim 850218885Sdimint main(int argc, char **argv) { 851218885Sdim // Print a stack trace if we signal out. 852218885Sdim sys::PrintStackTraceOnErrorSignal(); 853218885Sdim PrettyStackTraceProgram X(argc, argv); 854218885Sdim llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 855218885Sdim 856218885Sdim // Initialize targets and assembly printers/parsers. 857218885Sdim llvm::InitializeAllTargetInfos(); 858226584Sdim llvm::InitializeAllTargetMCs(); 859218885Sdim llvm::InitializeAllAsmParsers(); 860218885Sdim llvm::InitializeAllDisassemblers(); 861218885Sdim 862239462Sdim // Register the target printer for --version. 863239462Sdim cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); 864239462Sdim 865218885Sdim cl::ParseCommandLineOptions(argc, argv, "llvm object file dumper\n"); 866218885Sdim TripleName = Triple::normalize(TripleName); 867218885Sdim 868218885Sdim ToolName = argv[0]; 869218885Sdim 870218885Sdim // Defaults to a.out if no filenames specified. 871218885Sdim if (InputFilenames.size() == 0) 872218885Sdim InputFilenames.push_back("a.out"); 873218885Sdim 874234353Sdim if (!Disassemble 875234353Sdim && !Relocations 876234353Sdim && !SectionHeaders 877234353Sdim && !SectionContents 878249423Sdim && !SymbolTable 879249423Sdim && !UnwindInfo 880249423Sdim && !PrivateHeaders) { 881218885Sdim cl::PrintHelpMessage(); 882218885Sdim return 2; 883218885Sdim } 884218885Sdim 885218885Sdim std::for_each(InputFilenames.begin(), InputFilenames.end(), 886226584Sdim DumpInput); 887218885Sdim 888218885Sdim return 0; 889218885Sdim} 890