#include <vector>
#include <set>
-#include <ext/hash_set>
+#include <unordered_set>
+#include "configure.h"
#include "MachOFileAbstraction.hpp"
#include "Architectures.hpp"
#include "MachOTrie.hpp"
+#include "../ld/code-sign-blobs/superblob.h"
static bool printRebase = false;
static bool printBind = false;
static bool printSharedRegion = false;
static bool printFunctionStarts = false;
static bool printDylibs = false;
+static bool printDRs = false;
+static bool printDataCode = false;
static cpu_type_t sPreferredArch = 0;
static cpu_type_t sPreferredSubArch = 0;
typedef typename A::P::E E;
typedef typename A::P::uint_t pint_t;
- class CStringEquals
- {
- public:
- bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
- };
-
- typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> StringSet;
-
DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch);
void printRebaseInfo();
void printRebaseInfoOpcodes();
void printSharedRegionInfo();
void printFunctionStartsInfo();
void printDylibsInfo();
+ void printDRInfo();
+ void printDataInCode();
void printFunctionStartLine(uint64_t addr);
const uint8_t* printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind);
pint_t relocBase();
const macho_dyld_info_command<P>* fInfo;
const macho_linkedit_data_command<P>* fSharedRegionInfo;
const macho_linkedit_data_command<P>* fFunctionStartsInfo;
+ const macho_linkedit_data_command<P>* fDataInCode;
+ const macho_linkedit_data_command<P>* fDRInfo;
uint64_t fBaseAddress;
const macho_dysymtab_command<P>* fDynamicSymbolTable;
const macho_segment_command<P>* fFirstSegment;
switch (header->filetype()) {
case MH_EXECUTE:
case MH_DYLIB:
+ case MH_DYLIB_STUB:
case MH_BUNDLE:
case MH_DYLINKER:
return true;
switch (header->filetype()) {
case MH_EXECUTE:
case MH_DYLIB:
+ case MH_DYLIB_STUB:
case MH_BUNDLE:
case MH_DYLINKER:
return true;
switch (header->filetype()) {
case MH_EXECUTE:
case MH_DYLIB:
+ case MH_DYLIB_STUB:
case MH_BUNDLE:
case MH_DYLINKER:
return true;
switch (header->filetype()) {
case MH_EXECUTE:
case MH_DYLIB:
+ case MH_DYLIB_STUB:
case MH_BUNDLE:
case MH_DYLINKER:
return true;
return false;
}
+#if SUPPORT_ARCH_arm_any
template <>
bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
{
return false;
if ( header->cputype() != CPU_TYPE_ARM )
return false;
+ switch (header->filetype()) {
+ case MH_EXECUTE:
+ case MH_DYLIB:
+ case MH_DYLIB_STUB:
+ case MH_BUNDLE:
+ case MH_DYLINKER:
+ return true;
+ }
+ return false;
+}
+#endif
+
+#if SUPPORT_ARCH_arm64
+template <>
+bool DyldInfoPrinter<arm64>::validFile(const uint8_t* fileContent)
+{
+ const macho_header<P>* header = (const macho_header<P>*)fileContent;
+ if ( header->magic() != MH_MAGIC_64 )
+ return false;
+ if ( header->cputype() != CPU_TYPE_ARM64 )
+ return false;
switch (header->filetype()) {
case MH_EXECUTE:
case MH_DYLIB:
}
return false;
}
+#endif
template <typename A>
DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
: fHeader(NULL), fLength(fileLength),
fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL),
- fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL),
+ fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), fDataInCode(NULL), fDRInfo(NULL),
fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL),
fWriteableSegmentWithAddrOver4G(false)
{
case LC_FUNCTION_STARTS:
fFunctionStartsInfo = (macho_linkedit_data_command<P>*)cmd;
break;
+ case LC_DATA_IN_CODE:
+ fDataInCode = (macho_linkedit_data_command<P>*)cmd;
+ break;
+ case LC_DYLIB_CODE_SIGN_DRS:
+ fDRInfo = (macho_linkedit_data_command<P>*)cmd;
+ break;
}
cmd = (const macho_load_command<P>*)endOfCmd;
}
if ( printArch ) {
- switch ( fHeader->cputype() ) {
- case CPU_TYPE_I386:
- printf("for arch i386:\n");
- break;
- case CPU_TYPE_X86_64:
- printf("for arch x86_64:\n");
- break;
- case CPU_TYPE_POWERPC:
- printf("for arch ppc:\n");
- break;
- case CPU_TYPE_ARM:
- for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
- if ( (cpu_subtype_t)fHeader->cpusubtype() == t->subType) {
- printf("for arch %s:\n", t->subTypeName);
- break;
- }
- }
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( (cpu_type_t)fHeader->cputype() == t->cpuType ) {
+ if ( t->isSubType && ((cpu_subtype_t)fHeader->cpusubtype() != t->cpuSubType) )
+ continue;
+ printf("for arch %s:\n", t->archName);
+ }
}
}
-
if ( printRebase ) {
if ( fInfo != NULL )
printRebaseInfo();
printFunctionStartsInfo();
if ( printDylibs )
printDylibsInfo();
+ if ( printDRs )
+ printDRInfo();
+ if ( printDataCode )
+ printDataInCode();
}
static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
if (p == end)
throwf("malformed sleb128");
byte = *p++;
- result |= ((byte & 0x7f) << bit);
+ result |= (((int64_t)(byte & 0x7f)) << bit);
bit += 7;
} while (byte & 0x80);
// sign extend negative numbers
uint64_t segOffset = 0;
uint32_t count;
uint32_t skip;
- int segIndex;
+ int segIndex = 0;
pint_t segStartAddr = 0;
const char* segName = "??";
const char* typeName = "??";
parseTrie(start, end, list);
//std::sort(list.begin(), list.end(), SortExportsByAddress());
for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
- if ( it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
- if ( it->importName[0] == '\0' )
- fprintf(stdout, "[re-export] %s from dylib=%llu\n", it->name, it->other);
- else
- fprintf(stdout, "[re-export] %s from dylib=%llu named=%s\n", it->name, it->other, it->importName);
- }
- else {
- const char* flags = "";
- if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
- flags = "[weak_def] ";
- else if ( (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL )
- flags = "[per-thread] ";
- if ( it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
- flags = "[resolver] ";
- fprintf(stdout, "0x%08llX %s%s (resolver=0x%08llX)\n", fBaseAddress+it->address, flags, it->name, it->other);
+ const bool reExport = (it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT);
+ const bool weakDef = (it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+ const bool threadLocal = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+ const bool abs = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+ const bool resolver = (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+ if ( reExport )
+ printf("[re-export] ");
+ else
+ printf("0x%08llX ", fBaseAddress+it->address);
+ printf("%s", it->name);
+ if ( weakDef || threadLocal || resolver || abs ) {
+ bool needComma = false;
+ printf(" [");
+ if ( weakDef ) {
+ printf("weak_def");
+ needComma = true;
}
- else {
- fprintf(stdout, "0x%08llX %s%s\n", fBaseAddress+it->address, flags, it->name);
+ if ( threadLocal ) {
+ if ( needComma )
+ printf(", ");
+ printf("per-thread");
+ needComma = true;
+ }
+ if ( abs ) {
+ if ( needComma )
+ printf(", ");
+ printf("absolute");
+ needComma = true;
+ }
+ if ( resolver ) {
+ if ( needComma )
+ printf(", ");
+ printf("resolver=0x%08llX", it->other);
+ needComma = true;
}
+ printf("]");
}
+ if ( reExport ) {
+ if ( it->importName[0] == '\0' )
+ printf(" (from %s)", fDylibs[it->other - 1]);
+ else
+ printf(" (%s from %s)", it->importName, fDylibs[it->other - 1]);
+ }
+ printf("\n");
}
}
}
char* cummulativeString, int curStrOffset)
{
const uint8_t* const me = p;
- const uint8_t terminalSize = read_uleb128(p, end);
+ const uint64_t terminalSize = read_uleb128(p, end);
const uint8_t* children = p + terminalSize;
if ( terminalSize != 0 ) {
uint32_t flags = read_uleb128(p, end);
printf("[addr=0x%06llX] ", address);
else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
+ else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE)
+ printf("[flags=ABSOLUTE addr=0x%06llX] ", address);
else
printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
}
kindStr = "64-bit pointer";
break;
case 3:
- kindStr = "ppc hi16";
+#if SUPPORT_ARCH_arm64
+ if ( fHeader->cputype() == CPU_TYPE_ARM64 )
+ kindStr = "arm64 ADRP";
+ else
+#endif
+ kindStr = "ppc hi16";
break;
case 4:
kindStr = "32-bit offset to IMPORT";
}
}
+#if SUPPORT_ARCH_arm_any
template <>
void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
{
else
printf("0x%0llX %s\n", addr, symbolNameForAddress(addr));
}
+#endif
template <typename A>
void DyldInfoPrinter<A>::printFunctionStartLine(uint64_t addr)
}
}
+template <typename A>
+void DyldInfoPrinter<A>::printDRInfo()
+{
+ if ( fDRInfo == NULL ) {
+ printf("no Designated Requirements info\n");
+ }
+ else {
+ printf("dylibs DRs\n");
+ const uint8_t* start = ((uint8_t*)fHeader + fDRInfo->dataoff());
+ //const uint8_t* end = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
+ typedef Security::SuperBlob<Security::kSecCodeMagicDRList> DRListSuperBlob;
+ typedef Security::SuperBlob<Security::kSecCodeMagicRequirementSet> InternalRequirementsSetBlob;
+ const DRListSuperBlob* topBlob = (DRListSuperBlob*)start;
+ if ( topBlob->validateBlob(fDRInfo->datasize()) ) {
+ if ( topBlob->count() == fDylibLoadCommands.size() ) {
+ for(unsigned i=0; i < topBlob->count(); ++i) {
+ printf(" %-20s ", fDylibs[i]);
+ const Security::BlobCore* item = topBlob->find(i);
+ if ( item != NULL ) {
+ const uint8_t* itemStart = (uint8_t*)item;
+ const uint8_t* itemEnd = itemStart + item->length();
+ for(const uint8_t* p=itemStart; p < itemEnd; ++p)
+ printf("%02X ", *p);
+ }
+ else {
+ printf("no DR info");
+ }
+ printf("\n");
+ }
+ }
+ else {
+ fprintf(stderr, "superblob of DRs has a different number of elements than dylib load commands\n");
+ }
+ }
+ else {
+ fprintf(stderr, "superblob of DRs invalid\n");
+ }
+ }
+}
+
+
+
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printDataInCode()
+{
+ if ( fDataInCode == NULL ) {
+ printf("no data-in-code info\n");
+ }
+ else {
+ printf("offset length data-kind\n");
+ const macho_data_in_code_entry<P>* start = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff());
+ const macho_data_in_code_entry<P>* end = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff() + fDataInCode->datasize());
+ for (const macho_data_in_code_entry<P>* p=start; p < end; ++p) {
+ const char* kindStr = "???";
+ switch ( p->kind() ) {
+ case 1:
+ kindStr = "data";
+ break;
+ case 2:
+ kindStr = "jumptable8";
+ break;
+ case 3:
+ kindStr = "jumptable16";
+ break;
+ case 4:
+ kindStr = "jumptable32";
+ break;
+ case 5:
+ kindStr = "jumptable32absolute";
+ break;
+ }
+ printf("0x%08X 0x%04X %s\n", p->offset(), p->length(), kindStr);
+ }
+ }
+}
+
+
template <>
ppc::P::uint_t DyldInfoPrinter<ppc>::relocBase()
template <>
x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
{
- // check for split-seg
return fFirstWritableSegment->vmaddr();
}
+#if SUPPORT_ARCH_arm_any
template <>
arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
{
else
return fFirstSegment->vmaddr();
}
+#endif
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t DyldInfoPrinter<arm64>::relocBase()
+{
+ return fFirstWritableSegment->vmaddr();
+}
+#endif
template <>
const char* DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
{
if ( r_type == GENERIC_RELOC_VANILLA )
return "pointer";
- else if ( r_type == PPC_RELOC_PB_LA_PTR )
- return "pb pointer";
else
return "??";
}
return "??";
}
+#if SUPPORT_ARCH_arm_any
template <>
const char* DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
{
else
return "??";
}
-
+#endif
+
+#if SUPPORT_ARCH_arm64
+template <>
+const char* DyldInfoPrinter<arm64>::relocTypeName(uint8_t r_type)
+{
+ if ( r_type == ARM64_RELOC_UNSIGNED )
+ return "pointer";
+ return "??";
+}
+#endif
template <typename A>
void DyldInfoPrinter<A>::printRelocRebaseInfo()
else
throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
break;
+#if SUPPORT_ARCH_arm_any
case CPU_TYPE_ARM:
if ( DyldInfoPrinter<arm>::validFile(p + offset) )
DyldInfoPrinter<arm>::make(p + offset, size, path, (sPreferredArch == 0));
else
throw "in universal file, arm slice does not contain arm mach-o";
break;
+#endif
+#if SUPPORT_ARCH_arm64
+ case CPU_TYPE_ARM64:
+ if ( DyldInfoPrinter<arm64>::validFile(p + offset) )
+ DyldInfoPrinter<arm64>::make(p + offset, size, path, (sPreferredArch == 0));
+ else
+ throw "in universal file, arm64 slice does not contain arm mach-o";
+ break;
+#endif
default:
throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
}
else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
DyldInfoPrinter<x86_64>::make(p, length, path, false);
}
+#if SUPPORT_ARCH_arm_any
else if ( DyldInfoPrinter<arm>::validFile(p) ) {
DyldInfoPrinter<arm>::make(p, length, path, false);
}
+#endif
+#if SUPPORT_ARCH_arm64
+ else if ( DyldInfoPrinter<arm64>::validFile(p) ) {
+ DyldInfoPrinter<arm64>::make(p, length, path, false);
+ }
+#endif
else {
throw "not a known file type";
}
{
fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
"\t-dylibs print dependent dylibs\n"
+ "\t-dr print dependent dylibs and show any recorded DR info\n"
"\t-rebase print addresses dyld will adjust if file not loaded at preferred address\n"
"\t-bind print addresses dyld will set based on symbolic lookups\n"
"\t-weak_bind print symbols which dyld must coalesce\n"
"\t-opcodes print opcodes used to generate the rebase and binding information\n"
"\t-function_starts print table of function start addresses\n"
"\t-export_dot print a GraphViz .dot file of the exported symbols trie\n"
+ "\t-data_in_code print any data-in-code inforamtion\n"
);
}
sPreferredArch = CPU_TYPE_I386;
else if ( strcmp(arch, "x86_64") == 0 )
sPreferredArch = CPU_TYPE_X86_64;
+#if SUPPORT_ARCH_arm64
+ else if ( strcmp(arch, "arm64") == 0 )
+ sPreferredArch = CPU_TYPE_ARM64;
+#endif
else {
+ if ( arch == NULL )
+ throw "-arch missing architecture name";
bool found = false;
- for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
- if ( strcmp(t->subTypeName,arch) == 0 ) {
- sPreferredArch = CPU_TYPE_ARM;
- sPreferredSubArch = t->subType;
+ for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+ if ( strcmp(t->archName,arch) == 0 ) {
+ sPreferredArch = t->cpuType;
+ if ( t->isSubType )
+ sPreferredSubArch = t->cpuSubType;
found = true;
break;
}
else if ( strcmp(arg, "-dylibs") == 0 ) {
printDylibs = true;
}
+ else if ( strcmp(arg, "-dr") == 0 ) {
+ printDRs = true;
+ }
+ else if ( strcmp(arg, "-data_in_code") == 0 ) {
+ printDataCode = true;
+ }
else {
throwf("unknown option: %s\n", arg);
}