]> git.saurik.com Git - apple/ld64.git/blobdiff - ld64-134.9/src/other/ObjectDump.cpp
ld64-134.9.tar.gz
[apple/ld64.git] / ld64-134.9 / src / other / ObjectDump.cpp
diff --git a/ld64-134.9/src/other/ObjectDump.cpp b/ld64-134.9/src/other/ObjectDump.cpp
new file mode 100644 (file)
index 0000000..cc673a3
--- /dev/null
@@ -0,0 +1,1247 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <mach-o/nlist.h>
+#include <mach-o/stab.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+#include "MachOFileAbstraction.hpp"
+#include "parsers/macho_relocatable_file.h"
+#include "parsers/lto_file.h"
+
+static bool                    sDumpContent= true;
+static bool                    sDumpStabs      = false;
+static bool                    sSort           = true;
+static bool                    sNMmode         = false;
+static bool                    sShowSection                    = true;
+static bool                    sShowDefinitionKind             = true;
+static bool                    sShowCombineKind                = true;
+static bool                    sShowLineInfo                   = true;
+
+static cpu_type_t              sPreferredArch = 0xFFFFFFFF;
+static cpu_subtype_t   sPreferredSubArch = 0xFFFFFFFF;
+static const char* sMatchName = NULL;
+static int sPrintRestrict;
+static int sPrintAlign;
+static int sPrintName;
+
+ __attribute__((noreturn))
+void throwf(const char* format, ...) 
+{
+       va_list list;
+       char*   p;
+       va_start(list, format);
+       vasprintf(&p, format, list);
+       va_end(list);
+       
+       const char*     t = p;
+       throw t;
+}
+
+void warning(const char* format, ...)
+{
+       va_list list;
+       fprintf(stderr, "warning: ");
+       va_start(list, format);
+       vfprintf(stderr, format, list);
+       va_end(list);
+       fprintf(stderr, "\n");
+}
+
+static void dumpStabs(const std::vector<ld::relocatable::File::Stab>* stabs)
+{
+       // debug info
+       printf("stabs: (%lu)\n", stabs->size());
+       for (std::vector<ld::relocatable::File::Stab>::const_iterator it = stabs->begin(); it != stabs->end(); ++it ) {
+               const ld::relocatable::File::Stab& stab = *it;
+               const char* code = "?????";
+               switch (stab.type) {
+                       case N_GSYM:
+                               code = " GSYM";
+                               break;
+                       case N_FNAME:
+                               code = "FNAME";
+                               break;
+                       case N_FUN:
+                               code = "  FUN";
+                               break;
+                       case N_STSYM:
+                               code = "STSYM";
+                               break;
+                       case N_LCSYM:
+                               code = "LCSYM";
+                               break;
+                       case N_BNSYM:
+                               code = "BNSYM";
+                               break;
+                       case N_OPT:
+                               code = "  OPT";
+                               break;
+                       case N_RSYM:
+                               code = " RSYM";
+                               break;
+                       case N_SLINE:
+                               code = "SLINE";
+                               break;
+                       case N_ENSYM:
+                               code = "ENSYM";
+                               break;
+                       case N_SSYM:
+                               code = " SSYM";
+                               break;
+                       case N_SO:
+                               code = "   SO";
+                               break;
+                       case N_OSO:
+                               code = "  OSO";
+                               break;
+                       case N_LSYM:
+                               code = " LSYM";
+                               break;
+                       case N_BINCL:
+                               code = "BINCL";
+                               break;
+                       case N_SOL:
+                               code = "  SOL";
+                               break;
+                       case N_PARAMS:
+                               code = "PARMS";
+                               break;
+                       case N_VERSION:
+                               code = " VERS";
+                               break;
+                       case N_OLEVEL:
+                               code = "OLEVL";
+                               break;
+                       case N_PSYM:
+                               code = " PSYM";
+                               break;
+                       case N_EINCL:
+                               code = "EINCL";
+                               break;
+                       case N_ENTRY:
+                               code = "ENTRY";
+                               break;
+                       case N_LBRAC:
+                               code = "LBRAC";
+                               break;
+                       case N_EXCL:
+                               code = " EXCL";
+                               break;
+                       case N_RBRAC:
+                               code = "RBRAC";
+                               break;
+                       case N_BCOMM:
+                               code = "BCOMM";
+                               break;
+                       case N_ECOMM:
+                               code = "ECOMM";
+                               break;
+                       case N_LENG:
+                               code =  "LENG";
+                               break;
+               }
+               printf("  [atom=%20s] %02X %04X %s %s\n", ((stab.atom != NULL) ? stab.atom->name() : ""), stab.other, stab.desc, code, stab.string);
+       }
+}
+
+#if 0
+static void dumpAtomLikeNM(ld::Atom* atom)
+{
+       uint32_t size = atom->size();
+       
+       const char* visibility;
+       switch ( atom->scope() ) {
+               case ld::Atom::scopeTranslationUnit:
+                       visibility = "internal";
+                       break;
+               case ld::Atom::scopeLinkageUnit:
+                       visibility = "hidden  ";
+                       break;
+               case ld::Atom::scopeGlobal:
+                       visibility = "global  ";
+                       break;
+               default:
+                       visibility = "        ";
+                       break;
+       }
+
+       const char* kind;
+       switch ( atom->definitionKind() ) {
+               case ld::Atom::kRegularDefinition:
+                       kind = "regular  ";
+                       break;
+               case ld::Atom::kTentativeDefinition:
+                       kind = "tentative";
+                       break;
+               case ld::Atom::kWeakDefinition:
+                       kind = "weak     ";
+                       break;
+               case ld::Atom::kAbsoluteSymbol:
+                       kind = "absolute ";
+                       break;
+               default:
+                       kind = "         ";
+                       break;
+       }
+
+       printf("0x%08X %s %s %s\n", size, visibility, kind, atom->name());
+}
+
+
+static void dumpAtom(ld::Atom* atom)
+{
+       if(sMatchName && strcmp(sMatchName, atom->name()))
+               return;
+
+       //printf("atom:    %p\n", atom);
+       
+       // name
+       if(!sPrintRestrict || sPrintName)
+               printf("name:    %s\n",  atom->name());
+       
+       // scope
+       if(!sPrintRestrict)
+               switch ( atom->scope() ) {
+               case ld::Atom::scopeTranslationUnit:
+                       printf("scope:   translation unit\n");
+                       break;
+               case ld::Atom::scopeLinkageUnit:
+                       printf("scope:   linkage unit\n");
+                       break;
+               case ld::Atom::scopeGlobal:
+                       printf("scope:   global\n");
+                       break;
+               default:
+                       printf("scope:   unknown\n");
+               }
+       
+       // kind
+       if(!sPrintRestrict)
+               switch ( atom->definitionKind() ) {
+               case ld::Atom::kRegularDefinition:
+                       printf("kind:     regular\n");
+                       break;
+               case ld::Atom::kWeakDefinition:
+                       printf("kind:     weak\n");
+                       break;
+               case ld::Atom::kTentativeDefinition:
+                       printf("kind:     tentative\n");
+                       break;
+               case ld::Atom::kExternalDefinition:
+                       printf("kind:     import\n");
+                       break;
+               case ld::Atom::kExternalWeakDefinition:
+                       printf("kind:     weak import\n");
+                       break;
+               case ld::Atom::kAbsoluteSymbol:
+                       printf("kind:     absolute symbol\n");
+                       break;
+               default:
+                       printf("kind:   unknown\n");
+               }
+
+       // segment and section
+       if(!sPrintRestrict && (atom->section().sectionName() != NULL) )
+               printf("section: %s,%s\n", atom->section().segmentName(), atom->section().sectionName());
+
+       // attributes
+       if(!sPrintRestrict) {
+               printf("attrs:   ");
+               if ( atom->dontDeadStrip() )
+                       printf("dont-dead-strip ");
+               if ( atom->isThumb() )
+                       printf("thumb ");
+               printf("\n");
+       }
+       
+       // size
+       if(!sPrintRestrict)
+               printf("size:    0x%012llX\n", atom->size());
+       
+       // alignment
+       if(!sPrintRestrict || sPrintAlign)
+               printf("align:    %u mod %u\n", atom->alignment().modulus, (1 << atom->alignment().powerOf2) );
+
+       // content
+       if (!sPrintRestrict && sDumpContent ) { 
+               uint64_t size = atom->size();
+               if ( size < 4096 ) {
+                       uint8_t content[size];
+                       atom->copyRawContent(content);
+                       printf("content: ");
+                       if ( atom->contentType() == ld::Atom::typeCString ) {
+                               printf("\"");
+                               for (unsigned int i=0; i < size; ++i) {
+                                       if(content[i]<'!' || content[i]>=127)
+                                               printf("\\%o", content[i]);
+                                       else
+                                               printf("%c", content[i]);
+                               }
+                               printf("\"");
+                       }
+                       else {
+                               for (unsigned int i=0; i < size; ++i)
+                                       printf("%02X ", content[i]);
+                       }
+               }
+               printf("\n");
+       }
+       
+       // unwind info
+       if(!sPrintRestrict) {
+               if ( atom->beginUnwind() != atom->endUnwind() ) {
+                       printf("unwind encodings:\n");
+                       for (ld::Atom::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) {
+                               printf("\t 0x%04X  0x%08X\n", it->startOffset, it->unwindInfo);
+                       }
+               }
+       }
+#if 0  
+       // references
+       if(!sPrintRestrict) {
+               std::vector<ObjectFile::Reference*>&  references = atom->getReferences();
+               const int refCount = references.size();
+               printf("references: (%u)\n", refCount);
+               for (int i=0; i < refCount; ++i) {
+                       ObjectFile::Reference* ref = references[i];
+                       printf("   %s\n", ref->getDescription());
+               }
+       }
+#endif 
+       // line info
+       if(!sPrintRestrict) {
+               if ( atom->beginLineInfo() != atom->endLineInfo() ) {
+                       printf("line info:\n");
+                       for (ld::Atom::LineInfo::iterator it = atom->beginLineInfo(); it != atom->endLineInfo(); ++it) {
+                               printf("   offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+                       }
+               }
+       }
+
+       if(!sPrintRestrict)
+               printf("\n");
+}
+#endif
+struct AtomSorter
+{
+     bool operator()(const ld::Atom* left, const ld::Atom* right)
+     {
+               if ( left == right )
+                       return false;
+               // first sort by segment name
+               int diff = strcmp(left->section().segmentName(), right->section().segmentName());
+               if ( diff != 0 )
+                       return (diff > 0);
+               
+               // then sort by section name
+               diff = strcmp(left->section().sectionName(), right->section().sectionName());
+               if ( diff != 0 )
+                       return (diff < 0);
+               
+               // then sort by atom name
+               diff = strcmp(left->name(), right->name());
+               if ( diff != 0 )
+                       return (diff < 0);
+               
+               // if cstring, sort by content
+               if ( left->contentType() == ld::Atom::typeCString ) {
+                       diff = strcmp((char*)left->rawContentPointer(), (char*)right->rawContentPointer());
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               else if ( left->section().type() == ld::Section::typeCStringPointer ) {
+                       // if pointer to c-string sort by name
+                       const char* leftString = NULL;
+                       assert(left->fixupsBegin() != left->fixupsEnd());
+                       for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+                               if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+                                       const ld::Atom* cstringAtom = fit->u.target;
+                                       assert(cstringAtom->contentType() == ld::Atom::typeCString);
+                                       leftString = (char*)cstringAtom->rawContentPointer();
+                               }
+                       }
+                       const char* rightString = NULL;
+                       assert(right->fixupsBegin() != right->fixupsEnd());
+                       for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+                               if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+                                       const ld::Atom* cstringAtom = fit->u.target;
+                                       assert(cstringAtom->contentType() == ld::Atom::typeCString);
+                                       rightString = (char*)cstringAtom->rawContentPointer();
+                               }
+                       }
+                       assert(leftString != NULL);
+                       assert(rightString != NULL);
+                       diff = strcmp(leftString, rightString);
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               else if ( left->section().type() == ld::Section::typeLiteral4 ) {
+                       // if literal sort by content
+                       uint32_t leftValue  = *(uint32_t*)left->rawContentPointer();
+                       uint32_t rightValue = *(uint32_t*)right->rawContentPointer();
+                       diff = (leftValue - rightValue);
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               else if ( left->section().type() == ld::Section::typeCFI ) {
+                       // if __he_frame sort by address
+                       diff = (left->objectAddress() - right->objectAddress());
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               else if ( left->section().type() == ld::Section::typeNonLazyPointer ) {
+                       // if non-lazy-pointer sort by name
+                       const char* leftString = NULL;
+                       assert(left->fixupsBegin() != left->fixupsEnd());
+                       for (ld::Fixup::iterator fit = left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+                               if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+                                       leftString = fit->u.name;
+                               }
+                               else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                       leftString = fit->u.target->name();
+                               }
+                       }
+                       const char* rightString = NULL;
+                       assert(right->fixupsBegin() != right->fixupsEnd());
+                       for (ld::Fixup::iterator fit = right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+                               if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+                                       rightString = fit->u.name;
+                               }
+                               else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                       rightString = fit->u.target->name();
+                               }
+                       }
+                       assert(leftString != NULL);
+                       assert(rightString != NULL);
+                       diff = strcmp(leftString, rightString);
+                       if ( diff != 0 )
+                               return (diff < 0);
+               }
+               
+               // else sort by size
+               return (left->size() < right->size());
+     }
+};
+
+
+class dumper : public ld::File::AtomHandler
+{
+public:
+                       void dump();
+       virtual void doAtom(const ld::Atom&);
+       virtual void doFile(const ld::File&) {} 
+private:
+       void                    dumpAtom(const ld::Atom& atom);
+       const char*             scopeString(const ld::Atom&);
+       const char*             definitionString(const ld::Atom&);
+       const char*             combineString(const ld::Atom&);
+       const char*             inclusionString(const ld::Atom&);
+       const char*             attributeString(const ld::Atom&);
+       const char*             makeName(const ld::Atom& atom);
+       const char*             referenceTargetAtomName(const ld::Fixup* ref);
+       void                    dumpFixup(const ld::Fixup* ref);
+       
+       uint64_t                addressOfFirstAtomInSection(const ld::Section&);
+       
+       std::vector<const ld::Atom*> _atoms;
+};
+
+const char*    dumper::scopeString(const ld::Atom& atom)
+{
+       switch ( (ld::Atom::Scope)atom.scope() ) {
+               case ld::Atom::scopeTranslationUnit:
+                       return "translation-unit";
+               case ld::Atom::scopeLinkageUnit:
+                       return "hidden";
+               case ld::Atom::scopeGlobal:
+                       if ( atom.autoHide() )
+                               return "global but automatically hidden";
+                       else
+                               return "global";
+       }
+       return "UNKNOWN";       
+}
+
+const char*    dumper::definitionString(const ld::Atom& atom)
+{
+       switch ( (ld::Atom::Definition)atom.definition() ) {
+               case ld::Atom::definitionRegular:
+                       return "regular";
+               case ld::Atom::definitionTentative:
+                       return "tentative";
+               case ld::Atom::definitionAbsolute:
+                       return "absolute";
+               case ld::Atom::definitionProxy:
+                       return "proxy";
+               }
+       return "UNKNOWN";       
+}
+
+const char*    dumper::combineString(const ld::Atom& atom)
+{
+       switch ( (ld::Atom::Combine)atom.combine() ) {
+               case ld::Atom::combineNever:
+                       return "never";
+               case ld::Atom::combineByName:
+                       return "by-name";
+               case ld::Atom::combineByNameAndContent:
+                       return "by-name-and-content";
+               case ld::Atom::combineByNameAndReferences:
+                       return "by-name-and-references";
+               }
+       return "UNKNOWN";       
+}
+
+const char*    dumper::inclusionString(const ld::Atom& atom)
+{
+       switch ( (ld::Atom::SymbolTableInclusion)atom.symbolTableInclusion() ) {
+               case ld::Atom::symbolTableNotIn:
+                       return "not in";
+               case ld::Atom::symbolTableNotInFinalLinkedImages:
+                       return "not in final linked images";
+               case ld::Atom::symbolTableIn:
+                       return "in";
+               case ld::Atom::symbolTableInAndNeverStrip:
+                       return "in and never strip";
+               case ld::Atom::symbolTableInAsAbsolute:
+                       return "in as absolute";
+               case ld::Atom::symbolTableInWithRandomAutoStripLabel:
+                       return "in as random auto-strip label";
+               }
+       return "UNKNOWN";       
+}
+
+
+
+const char*    dumper::attributeString(const ld::Atom& atom)
+{
+       static char buffer[256];
+       buffer[0] = '\0';
+       
+       if ( atom.dontDeadStrip() )
+               strcat(buffer, "dont-dead-strip ");
+
+       if ( atom.isThumb() )
+               strcat(buffer, "thumb ");
+               
+       if ( atom.isAlias() )
+               strcat(buffer, "alias ");
+               
+       if ( atom.contentType() == ld::Atom::typeResolver )
+               strcat(buffer, "resolver ");
+               
+       return buffer;
+}
+
+const char* dumper::makeName(const ld::Atom& atom)
+{
+       static char buffer[4096];
+       strcpy(buffer, "???");
+       switch ( atom.symbolTableInclusion() ) {
+               case ld::Atom::symbolTableNotIn:
+                       if ( atom.contentType() == ld::Atom::typeCString ) {
+                               strcpy(buffer, "cstring=");
+                               strlcat(buffer, (char*)atom.rawContentPointer(), 4096);
+                       }
+                       else if ( atom.section().type() == ld::Section::typeLiteral4 ) {
+                               char temp[16];
+                               strcpy(buffer, "literal4=");
+                               uint32_t value = *(uint32_t*)atom.rawContentPointer();
+                               sprintf(temp, "0x%08X", value);
+                               strcat(buffer, temp);
+                       }
+                       else if ( atom.section().type() == ld::Section::typeLiteral8 ) {
+                               char temp[32];
+                               strcpy(buffer, "literal8=");
+                               uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
+                               uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
+                               sprintf(temp, "0x%08X%08X", value1, value2);
+                               strcat(buffer, temp);
+                       }
+                       else if ( atom.section().type() == ld::Section::typeLiteral16 ) {
+                               char temp[64];
+                               strcpy(buffer, "literal16=");
+                               uint32_t value1 = *(uint32_t*)atom.rawContentPointer();
+                               uint32_t value2 = ((uint32_t*)atom.rawContentPointer())[1];
+                               uint32_t value3 = ((uint32_t*)atom.rawContentPointer())[2];
+                               uint32_t value4 = ((uint32_t*)atom.rawContentPointer())[3];
+                               sprintf(temp, "0x%08X%08X%08X%08X", value1, value2, value3, value4);
+                               strcat(buffer, temp);
+                       }
+                       else if ( atom.section().type() == ld::Section::typeCStringPointer ) {
+                               assert(atom.fixupsBegin() != atom.fixupsEnd());
+                               for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+                                       if ( fit->binding == ld::Fixup::bindingByContentBound ) {
+                                               const ld::Atom* cstringAtom = fit->u.target;
+                                               if ( (cstringAtom != NULL) && (cstringAtom->contentType() == ld::Atom::typeCString) ) {
+                                                       strlcpy(buffer, atom.name(), 4096);
+                                                       strlcat(buffer, "=", 4096);
+                                                       strlcat(buffer, (char*)cstringAtom->rawContentPointer(), 4096);
+                                               }
+                                       }
+                               }
+                       }
+                       else if ( atom.section().type() == ld::Section::typeNonLazyPointer ) {
+                               assert(atom.fixupsBegin() != atom.fixupsEnd());
+                               for (ld::Fixup::iterator fit = atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+                                       if ( fit->binding == ld::Fixup::bindingByNameUnbound ) {
+                                               strcpy(buffer, "non-lazy-pointer-to:");
+                                               strlcat(buffer, fit->u.name, 4096);
+                                               return buffer;
+                                       }
+                                       else if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                               strcpy(buffer, "non-lazy-pointer-to-local:");
+                                               strlcat(buffer, fit->u.target->name(), 4096);
+                                               return buffer;
+                                       }
+                               }
+                               strlcpy(buffer, atom.name(), 4096);
+                       }
+                       else {
+                               uint64_t sectAddr = addressOfFirstAtomInSection(atom.section());
+                               sprintf(buffer, "%s@%s+0x%08llX", atom.name(), atom.section().sectionName(), atom.objectAddress()-sectAddr);
+                       }
+                       break;
+               case ld::Atom::symbolTableNotInFinalLinkedImages:
+               case ld::Atom::symbolTableIn:
+               case ld::Atom::symbolTableInAndNeverStrip:
+               case ld::Atom::symbolTableInAsAbsolute:
+               case ld::Atom::symbolTableInWithRandomAutoStripLabel:
+                       strlcpy(buffer, atom.name(), 4096);
+                       break;
+       }
+       return buffer;
+}
+
+const char* dumper::referenceTargetAtomName(const ld::Fixup* ref)
+{
+       static char buffer[4096];
+       switch ( ref->binding ) {
+               case ld::Fixup::bindingNone:
+                       return "NO BINDING";
+               case ld::Fixup::bindingByNameUnbound:
+                       strcpy(buffer, "by-name(");
+                       strlcat(buffer, ref->u.name, 4096);
+                       strlcat(buffer, ")", 4096);
+                       return buffer;
+                       //return ref->u.name;
+               case ld::Fixup::bindingByContentBound:
+                       strcpy(buffer, "by-content(");
+                       strlcat(buffer, makeName(*ref->u.target), 4096);
+                       strlcat(buffer, ")", 4096);
+                       return buffer;
+               case ld::Fixup::bindingDirectlyBound:
+                       strcpy(buffer, "direct(");
+                       strlcat(buffer, makeName(*ref->u.target), 4096);
+                       strlcat(buffer, ")", 4096);
+                       return buffer;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       return "BOUND INDIRECTLY";
+       }
+       return "BAD BINDING";
+}
+
+
+void dumper::dumpFixup(const ld::Fixup* ref)
+{
+       if ( ref->weakImport ) {
+               printf("weak_import ");
+       }
+       switch ( (ld::Fixup::Kind)(ref->kind) ) {
+               case ld::Fixup::kindNone:
+                       printf("none");
+                       break;
+               case ld::Fixup::kindNoneFollowOn:
+                       printf("followed by %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindNoneGroupSubordinate:
+                       printf("group subordinate %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindNoneGroupSubordinateFDE:
+                       printf("group subordinate FDE %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                       printf("group subordinate LSDA %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                       printf("group subordinate personality %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSetTargetAddress:
+                       printf("%s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSubtractTargetAddress:
+                       printf(" - %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindAddAddend:
+                       printf(" + 0x%llX", ref->u.addend);
+                       break;
+               case ld::Fixup::kindSubtractAddend:
+                       printf(" - 0x%llX", ref->u.addend);
+                       break;
+               case ld::Fixup::kindSetTargetImageOffset:
+                       printf("imageOffset(%s)", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSetTargetSectionOffset:
+                       printf("sectionOffset(%s)", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStore8:
+                       printf(", then store byte");
+                       break;
+               case ld::Fixup::kindStoreLittleEndian16:
+                       printf(", then store 16-bit little endian");
+                       break;
+               case ld::Fixup::kindStoreLittleEndianLow24of32:
+                       printf(", then store low 24-bit little endian");
+                       break;
+               case ld::Fixup::kindStoreLittleEndian32:
+                       printf(", then store 32-bit little endian");
+                       break;
+               case ld::Fixup::kindStoreLittleEndian64:
+                       printf(", then store 64-bit little endian");
+                       break;
+               case ld::Fixup::kindStoreBigEndian16:
+                       printf(", then store 16-bit big endian");
+                       break;
+               case ld::Fixup::kindStoreBigEndianLow24of32:
+                       printf(", then store low 24-bit big endian");
+                       break;
+               case ld::Fixup::kindStoreBigEndian32:
+                       printf(", then store 32-bit big endian");
+                       break;
+               case ld::Fixup::kindStoreBigEndian64:
+                       printf(", then store 64-bit big endian");
+                       break;
+               case ld::Fixup::kindStoreX86BranchPCRel8:
+                       printf(", then store as x86 8-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreX86BranchPCRel32:
+                       printf(", then store as x86 32-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel8:
+                       printf(", then store as x86 8-bit pcrel");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel16:
+                       printf(", then store as x86 16-bit pcrel");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32:
+                       printf(", then store as x86 32-bit pcrel");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32_1:
+                       printf(", then store as x86 32-bit pcrel from +1");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32_2:
+                       printf(", then store as x86 32-bit pcrel from +2");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32_4:
+                       printf(", then store as x86 32-bit pcrel from +4");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+                       printf(", then store as x86 32-bit pcrel GOT load");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+                       printf(", then store as x86 32-bit pcrel GOT load -> LEA");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32GOT:
+                       printf(", then store as x86 32-bit pcrel GOT access");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                       printf(", then store as x86 32-bit pcrel TLV load");
+                       break;
+               case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+                       printf(", then store as x86 32-bit pcrel TLV load");
+                       break;
+               case ld::Fixup::kindStoreX86Abs32TLVLoad:
+                       printf(", then store as x86 32-bit absolute TLV load");
+                       break;
+               case ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA:
+                       printf(", then store as x86 32-bit absolute TLV load -> LEA");
+                       break;
+               case ld::Fixup::kindStoreARMBranch24:
+                       printf(", then store as ARM 24-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreThumbBranch22:
+                       printf(", then store as Thumb 22-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreARMLoad12:
+                       printf(", then store as ARM 12-bit pcrel load");
+                       break;
+               case ld::Fixup::kindStoreARMLow16:
+                       printf(", then store low-16 in ARM movw");
+                       break;
+               case ld::Fixup::kindStoreARMHigh16:
+                       printf(", then store high-16 in ARM movt");
+                       break;
+               case ld::Fixup::kindStoreThumbLow16:
+                       printf(", then store low-16 in Thumb movw");
+                       break;
+               case ld::Fixup::kindStoreThumbHigh16:
+                       printf(", then store high-16 in Thumb movt");
+                       break;
+               case ld::Fixup::kindDtraceExtra:
+                       printf("dtrace static probe extra info");
+                       break;
+               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+                       printf("x86 dtrace static probe site");
+                       break;
+               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                       printf("x86 dtrace static is-enabled site");
+                       break;
+               case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+                       printf("ARM dtrace static probe site");
+                       break;
+               case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+                       printf("ARM dtrace static is-enabled site");
+                       break;
+               case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+                       printf("Thumb dtrace static probe site");
+                       break;
+               case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+                       printf("Thumb dtrace static is-enabled site");
+                       break;
+               case ld::Fixup::kindLazyTarget:
+                       printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSetLazyOffset:
+                       printf("offset of lazy binding info for %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindDataInCodeStartData:
+                       printf("start of data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeStartJT8:
+                       printf("start of jump table 8 data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeStartJT16:
+                       printf("start of jump table 16 data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeStartJT32:
+                       printf("start of jump table 32 data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeStartJTA32:
+                       printf("start of jump table absolute 32 data in code");
+                       break;
+               case ld::Fixup::kindDataInCodeEnd:
+                       printf("end of data in code");
+                       break;
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                       printf("store 64-bit little endian address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                       printf("store 32-bit big endian address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressBigEndian64:
+                       printf("store 64-bit big endian address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                       printf("x86 store 32-bit pc-rel address of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+                       printf("x86 store 32-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       printf("x86 store 32-bit pc-rel GOT load of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                       printf("x86 store 32-bit pc-rel lea of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                       printf("x86 store 32-bit pc-rel TLV load of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+                       printf("x86 store 32-bit pc-rel TLV lea of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+                       printf("x86 store 32-bit absolute TLV load of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
+                       printf("x86 store 32-bit absolute TLV lea of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                       printf("ARM store 24-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                       printf("Thumb store 22-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARMLoad12:
+                       printf("ARM store 12-bit pc-rel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindSetTargetTLVTemplateOffset:
+               case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
+               case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
+                       printf("tlv template offset of %s", referenceTargetAtomName(ref));
+               //default:
+               //      printf("unknown fixup");
+               //      break;
+       }
+}
+
+uint64_t dumper::addressOfFirstAtomInSection(const ld::Section& sect)
+{
+       uint64_t lowestAddr = (uint64_t)(-1);
+       for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               if ( &atom->section() == &sect ) {
+                       if ( atom->objectAddress() < lowestAddr )
+                               lowestAddr = atom->objectAddress();
+               }
+       }
+       return lowestAddr;
+}
+
+void dumper::doAtom(const ld::Atom& atom)
+{
+       if ( (sMatchName != NULL) && (strcmp(sMatchName, atom.name()) != 0) )
+               return;
+       _atoms.push_back(&atom);
+}
+
+void dumper::dump()
+{      
+       if ( sSort ) 
+               std::sort(_atoms.begin(), _atoms.end(), AtomSorter());
+
+       for (std::vector<const ld::Atom*>::iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               this->dumpAtom(**it);
+       }
+}      
+
+void dumper::dumpAtom(const ld::Atom& atom)
+{              
+       printf("name:     %s\n", makeName(atom)); 
+       printf("size:     0x%0llX\n", atom.size());
+       printf("align:    %u mod %u\n", atom.alignment().modulus, (1 << atom.alignment().powerOf2) );
+       printf("scope:    %s\n", scopeString(atom));
+       if ( sShowDefinitionKind ) 
+               printf("def:      %s\n", definitionString(atom));
+       if ( sShowCombineKind )
+               printf("combine:  %s\n", combineString(atom));
+       printf("symbol:   %s\n", inclusionString(atom));
+       printf("attrs:    %s\n", attributeString(atom));
+       if ( sShowSection )
+               printf("section:  %s,%s\n", atom.section().segmentName(), atom.section().sectionName());
+       if ( atom.beginUnwind() != atom.endUnwind() ) {
+               uint32_t lastOffset = 0;
+               uint32_t lastCUE = 0;
+               bool first = true;
+               const char* label = "unwind:";
+               for (ld::Atom::UnwindInfo::iterator it=atom.beginUnwind(); it != atom.endUnwind(); ++it) {
+                       if ( !first ) {
+                               printf("%s   0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, it->startOffset, lastCUE);
+                               label = "       ";
+                       }
+                       lastOffset = it->startOffset;
+                       lastCUE = it->unwindInfo;
+                       first = false;
+               }
+               printf("%s   0x%08X -> 0x%08X: 0x%08X\n", label, lastOffset, (uint32_t)atom.size(), lastCUE);
+       }
+       if ( atom.contentType() == ld::Atom::typeCString ) {
+               uint8_t buffer[atom.size()+2];
+               atom.copyRawContent(buffer);
+               buffer[atom.size()] = '\0';
+               printf("content:  \"%s\"\n", buffer);
+       }
+       if ( atom.fixupsBegin() != atom.fixupsEnd() ) {
+               printf("fixups:\n");
+               for (unsigned int off=0; off < atom.size()+1; ++off) {
+                       for (ld::Fixup::iterator it = atom.fixupsBegin(); it != atom.fixupsEnd(); ++it) {
+                               if ( it->offsetInAtom == off ) {
+                                       switch ( it->clusterSize ) {
+                                               case ld::Fixup::k1of1:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       break;
+                                               case ld::Fixup::k1of2:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       break;
+                                               case ld::Fixup::k1of3:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       break;
+                                               case ld::Fixup::k1of4:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       break;
+                                               case ld::Fixup::k1of5:
+                                                       printf("    0x%04X ", it->offsetInAtom);
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       ++it;
+                                                       dumpFixup(it);
+                                                       break;
+                                               default:
+                                                       printf("   BAD CLUSTER SIZE: cluster=%d\n", it->clusterSize);
+                                       }
+                                       printf("\n");
+                               }
+                       }
+               }
+       }
+       if ( sShowLineInfo ) {
+               if ( atom.beginLineInfo() != atom.endLineInfo() ) {
+                       printf("line info:\n");
+                       for (ld::Atom::LineInfo::iterator it = atom.beginLineInfo(); it != atom.endLineInfo(); ++it) {
+                               printf("   offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName);
+                       }
+               }
+       }
+       
+       printf("\n");
+}
+
+static void dumpFile(ld::relocatable::File* file)
+{
+       // stabs debug info
+       if ( sDumpStabs && (file->debugInfo() == ld::relocatable::File::kDebugInfoStabs) ) {
+               const std::vector<ld::relocatable::File::Stab>* stabs = file->stabs();
+               if ( stabs != NULL )
+                       dumpStabs(stabs);
+       }
+       // dump atoms
+       dumper d;
+       file->forEachAtom(d);
+       d.dump();
+
+#if 0  
+       // get all atoms
+       std::vector<ObjectFile::Atom*> atoms = reader->getAtoms();
+       
+       // make copy of vector and sort (so output is canonical)
+       std::vector<ObjectFile::Atom*> sortedAtoms(atoms);
+       if ( sSort )
+               std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter());
+       
+       for(std::vector<ObjectFile::Atom*>::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) {
+               if ( sNMmode )
+                       dumpAtomLikeNM(*it);
+               else
+                       dumpAtom(*it);
+       }
+#endif
+}
+
+
+static ld::relocatable::File* createReader(const char* path)
+{
+       struct stat stat_buf;
+       
+       int fd = ::open(path, O_RDONLY, 0);
+       if ( fd == -1 )
+               throwf("cannot open file: %s", path);
+       ::fstat(fd, &stat_buf);
+       uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       ::close(fd);
+       if ( p == (uint8_t*)(-1) )
+               throwf("cannot mmap file: %s", path);
+       const mach_header* mh = (mach_header*)p;
+       uint64_t fileLen = stat_buf.st_size;
+       bool foundFatSlice = false;
+       if ( mh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
+               const struct fat_header* fh = (struct fat_header*)p;
+               const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
+               if ( (uint32_t)sPreferredArch ==  0xFFFFFFFF ) {
+                       // just dump first slice of fat .o file
+                       if ( OSSwapBigToHostInt32(fh->nfat_arch) > 0 )  {
+                               p = p + OSSwapBigToHostInt32(archs[0].offset);
+                               mh = (struct mach_header*)p;
+                               fileLen = OSSwapBigToHostInt32(archs[0].size);
+                               sPreferredArch = OSSwapBigToHostInt32(archs[0].cputype);
+                               sPreferredSubArch = OSSwapBigToHostInt32(archs[0].cpusubtype);
+                               foundFatSlice = true;
+                       }
+               }
+               else {
+                       for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
+                               if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) {
+                                       if ( ((uint32_t)sPreferredSubArch == 0xFFFFFFFF) || ((uint32_t)sPreferredSubArch == OSSwapBigToHostInt32(archs[i].cpusubtype)) ) {
+                                               p = p + OSSwapBigToHostInt32(archs[i].offset);
+                                               mh = (struct mach_header*)p;
+                                               fileLen = OSSwapBigToHostInt32(archs[i].size);
+                                               foundFatSlice = true;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       mach_o::relocatable::ParserOptions objOpts;
+       objOpts.architecture            = sPreferredArch;
+       objOpts.objSubtypeMustMatch = false;
+       objOpts.logAllFiles                     = false;
+       objOpts.convertUnwindInfo       = true;
+       objOpts.subType                         = sPreferredSubArch;
+#if 1
+       if ( ! foundFatSlice ) {
+               cpu_type_t archOfObj;
+               cpu_subtype_t subArchOfObj;
+               if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj) ) {
+                       objOpts.architecture = archOfObj;
+                       objOpts.subType = subArchOfObj;
+               }
+       }
+
+       ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), objOpts);
+       if ( objResult != NULL )
+               return objResult;
+
+       // see if it is an llvm object file
+       objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), sPreferredArch, sPreferredSubArch, false);
+       if ( objResult != NULL ) 
+               return objResult;
+
+       throwf("not a mach-o object file: %s", path);
+#else
+       // for peformance testing
+       for (int i=0; i < 500; ++i ) {
+               ld::relocatable::File* objResult = mach_o::relocatable::parse(p, fileLen, path, stat_buf.st_mtime, 0, objOpts);
+               delete objResult;
+       }
+       exit(0);
+#endif
+}
+
+static
+void
+usage()
+{
+       fprintf(stderr, "ObjectDump options:\n"
+                       "\t-no_content\tdon't dump contents\n"
+                       "\t-no_section\tdon't dump section name\n"
+                       "\t-no_defintion\tdon't dump definition kind\n"
+                       "\t-no_combine\tdon't dump combine mode\n"
+                       "\t-stabs\t\tdump stabs\n"
+                       "\t-arch aaa\tonly dump info about arch aaa\n"
+                       "\t-only sym\tonly dump info about sym\n"
+                       "\t-align\t\tonly print alignment info\n"
+                       "\t-name\t\tonly print symbol names\n"
+               );
+}
+
+int main(int argc, const char* argv[])
+{
+       if(argc<2) {
+               usage();
+               return 0;
+       }
+
+       try {
+               for(int i=1; i < argc; ++i) {
+                       const char* arg = argv[i];
+                       if ( arg[0] == '-' ) {
+                               if ( strcmp(arg, "-no_content") == 0 ) {
+                                       sDumpContent = false;
+                               }
+                               else if ( strcmp(arg, "-nm") == 0 ) {
+                                       sNMmode = true;
+                               }
+                               else if ( strcmp(arg, "-stabs") == 0 ) {
+                                       sDumpStabs = true;
+                               }
+                               else if ( strcmp(arg, "-no_sort") == 0 ) {
+                                       sSort = false;
+                               }
+                               else if ( strcmp(arg, "-no_section") == 0 ) {
+                                       sShowSection = false;
+                               }
+                               else if ( strcmp(arg, "-no_definition") == 0 ) {
+                                       sShowDefinitionKind = false;
+                               }
+                               else if ( strcmp(arg, "-no_combine") == 0 ) {
+                                       sShowCombineKind = false;
+                               }
+                               else if ( strcmp(arg, "-no_line_info") == 0 ) {
+                                       sShowLineInfo = false;
+                               }
+                               else if ( strcmp(arg, "-arch") == 0 ) {
+                                       const char* archName = argv[++i];
+                                       if ( archName == NULL )
+                                               throw "-arch missing architecture name";
+                                       bool found = false;
+                                       for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+                                               if ( strcmp(t->archName,archName) == 0 ) {
+                                                       sPreferredArch = t->cpuType;
+                                                       if ( t->isSubType )
+                                                               sPreferredSubArch = t->cpuSubType;
+                                                       found = true;
+                                               }
+                                       }
+                                       if ( !found )
+                                               throwf("unknown architecture %s", archName);
+                               }
+                               else if ( strcmp(arg, "-only") == 0 ) {
+                                       sMatchName = ++i<argc? argv[i]: NULL;
+                               }
+                               else if ( strcmp(arg, "-align") == 0 ) {
+                                       sPrintRestrict = true;
+                                       sPrintAlign = true;
+                               }
+                               else if ( strcmp(arg, "-name") == 0 ) {
+                                       sPrintRestrict = true;
+                                       sPrintName = true;
+                               }
+                               else {
+                                       usage();
+                                       throwf("unknown option: %s\n", arg);
+                               }
+                       }
+                       else {
+                               ld::relocatable::File* reader = createReader(arg);
+                               dumpFile(reader);
+                       }
+               }
+       }
+       catch (const char* msg) {
+               fprintf(stderr, "ObjDump failed: %s\n", msg);
+               return 1;
+       }
+       
+       return 0;
+}