X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/9d2e0767a8f401be0067937f63a08b1c4f79297d..55e3d2f687f4ed9653982dbda92c6a055b0a8350:/src/other/ObjectDump.cpp diff --git a/src/other/ObjectDump.cpp b/src/other/ObjectDump.cpp new file mode 100644 index 0000000..c2ae578 --- /dev/null +++ b/src/other/ObjectDump.cpp @@ -0,0 +1,516 @@ +/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- + * + * Copyright (c) 2005-2006 Apple Computer, 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 +#include +#include +#include +#include + +#include "MachOReaderRelocatable.hpp" + +#define LTO_SUPPORT 1 + +#if LTO_SUPPORT + #include "LTOReader.hpp" +#endif + +static bool sDumpContent= true; +static bool sDumpStabs = false; +static bool sSort = true; +static bool sNMmode = false; +static cpu_type_t sPreferredArch = CPU_TYPE_POWERPC64; +static const char* sMatchName; +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(std::vector* stabs) +{ + // debug info + printf("stabs: (%lu)\n", stabs->size()); + for (std::vector::iterator it = stabs->begin(); it != stabs->end(); ++it ) { + ObjectFile::Reader::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->getDisplayName() : ""), stab.other, stab.desc, code, stab.string); + } +} + + +static void dumpAtomLikeNM(ObjectFile::Atom* atom) +{ + uint32_t size = atom->getSize(); + + const char* visibility; + switch ( atom->getScope() ) { + case ObjectFile::Atom::scopeTranslationUnit: + visibility = "internal"; + break; + case ObjectFile::Atom::scopeLinkageUnit: + visibility = "hidden "; + break; + case ObjectFile::Atom::scopeGlobal: + visibility = "global "; + break; + default: + visibility = " "; + break; + } + + const char* kind; + switch ( atom->getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + kind = "regular "; + break; + case ObjectFile::Atom::kTentativeDefinition: + kind = "tentative"; + break; + case ObjectFile::Atom::kWeakDefinition: + kind = "weak "; + break; + case ObjectFile::Atom::kAbsoluteSymbol: + kind = "absolute "; + break; + default: + kind = " "; + break; + } + + printf("0x%08X %s %s %s\n", size, visibility, kind, atom->getDisplayName()); +} + + +static void dumpAtom(ObjectFile::Atom* atom) +{ + if(sMatchName && strcmp(sMatchName, atom->getDisplayName())) + return; + + //printf("atom: %p\n", atom); + + // name + if(!sPrintRestrict || sPrintName) + printf("name: %s\n", atom->getDisplayName()); + + // scope + if(!sPrintRestrict) + switch ( atom->getScope() ) { + case ObjectFile::Atom::scopeTranslationUnit: + printf("scope: translation unit\n"); + break; + case ObjectFile::Atom::scopeLinkageUnit: + printf("scope: linkage unit\n"); + break; + case ObjectFile::Atom::scopeGlobal: + printf("scope: global\n"); + break; + default: + printf("scope: unknown\n"); + } + + // kind + if(!sPrintRestrict) + switch ( atom->getDefinitionKind() ) { + case ObjectFile::Atom::kRegularDefinition: + printf("kind: regular\n"); + break; + case ObjectFile::Atom::kWeakDefinition: + printf("kind: weak\n"); + break; + case ObjectFile::Atom::kTentativeDefinition: + printf("kind: tentative\n"); + break; + case ObjectFile::Atom::kExternalDefinition: + printf("kind: import\n"); + break; + case ObjectFile::Atom::kExternalWeakDefinition: + printf("kind: weak import\n"); + break; + case ObjectFile::Atom::kAbsoluteSymbol: + printf("kind: absolute symbol\n"); + break; + default: + printf("kind: unknown\n"); + } + + // segment and section + if(!sPrintRestrict && (atom->getSectionName() != NULL) ) + printf("section: %s,%s\n", atom->getSegment().getName(), atom->getSectionName()); + + // attributes + if(!sPrintRestrict) { + printf("attrs: "); + if ( atom->dontDeadStrip() ) + printf("dont-dead-strip "); + if ( atom->isZeroFill() ) + printf("zero-fill "); + if ( atom->isThumb() ) + printf("thumb "); + printf("\n"); + } + + // size + if(!sPrintRestrict) + printf("size: 0x%012llX\n", atom->getSize()); + + // alignment + if(!sPrintRestrict || sPrintAlign) + printf("align: %u mod %u\n", atom->getAlignment().modulus, (1 << atom->getAlignment().powerOf2) ); + + // content + if (!sPrintRestrict && sDumpContent ) { + uint64_t size = atom->getSize(); + if ( size < 4096 ) { + uint8_t content[size]; + atom->copyRawContent(content); + printf("content: "); + if ( atom->getContentType() == ObjectFile::Atom::kCStringType ) { + 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 (ObjectFile::UnwindInfo::iterator it = atom->beginUnwind(); it != atom->endUnwind(); ++it) { + printf("\t 0x%04X 0x%08X\n", it->startOffset, it->unwindInfo); + } + } + } + + // references + if(!sPrintRestrict) { + std::vector& 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()); + } + } + + // line info + if(!sPrintRestrict) { + std::vector* lineInfo = atom->getLineInfo(); + if ( (lineInfo != NULL) && (lineInfo->size() > 0) ) { + printf("line info: (%lu)\n", lineInfo->size()); + for (std::vector::iterator it = lineInfo->begin(); it != lineInfo->end(); ++it) { + printf(" offset 0x%04X, line %d, file %s\n", it->atomOffset, it->lineNumber, it->fileName); + } + } + } + + if(!sPrintRestrict) + printf("\n"); +} + +struct AtomSorter +{ + bool operator()(const ObjectFile::Atom* left, const ObjectFile::Atom* right) + { + if ( left == right ) + return false; + int name = strcmp(left->getDisplayName(), right->getDisplayName()); + if ( name == 0 ) + return (left->getSize() < right->getSize()); + else + return ( name < 0); + } +}; + + +static void dumpFile(ObjectFile::Reader* reader) +{ + // stabs debug info + if ( sDumpStabs && (reader->getDebugInfoKind() == ObjectFile::Reader::kDebugInfoStabs) ) { + std::vector* stabs = reader->getStabs(); + if ( stabs != NULL ) + dumpStabs(stabs); + } + + // get all atoms + std::vector atoms = reader->getAtoms(); + + // make copy of vector and sort (so output is canonical) + std::vector sortedAtoms(atoms); + if ( sSort ) + std::sort(sortedAtoms.begin(), sortedAtoms.end(), AtomSorter()); + + for(std::vector::iterator it=sortedAtoms.begin(); it != sortedAtoms.end(); ++it) { + if ( sNMmode ) + dumpAtomLikeNM(*it); + else + dumpAtom(*it); + } +} + + +static ObjectFile::Reader* createReader(const char* path, const ObjectFile::ReaderOptions& options) +{ + 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); + const mach_header* mh = (mach_header*)p; + 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)); + for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { + if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)sPreferredArch ) { + p = p + OSSwapBigToHostInt32(archs[i].offset); + mh = (struct mach_header*)p; + } + } + } + if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); + else if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); + else if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); + else if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); + else if ( mach_o::relocatable::Reader::validFile(p) ) + return new mach_o::relocatable::Reader::Reader(p, path, 0, options, 0); +#if LTO_SUPPORT + if ( lto::Reader::validFile(p, stat_buf.st_size, 0) ) { + return new lto::Reader(p, stat_buf.st_size, path, 0, options, 0); + } +#endif + + throwf("not a mach-o object file: %s", path); +} + +static +void +usage() +{ + fprintf(stderr, "ObjectDump options:\n" + "\t-no_content\tdon't dump contents\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; + } + + ObjectFile::ReaderOptions options; + options.fAddCompactUnwindEncoding = true; + 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, "-arch") == 0 ) { + const char* arch = ++i