755 lines
33 KiB
C++
755 lines
33 KiB
C++
|
/**************************** macho.cpp *******************************
|
||
|
* Author: Agner Fog
|
||
|
* Date created: 2007-01-06
|
||
|
* Last modified: 2008-06-02
|
||
|
* Project: objconv
|
||
|
* Module: macho.cpp
|
||
|
* Description:
|
||
|
* Module for reading Mach-O files
|
||
|
*
|
||
|
* Class CMACHO is used for reading, interpreting and dumping Mach-O files.
|
||
|
*
|
||
|
* Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
|
||
|
*****************************************************************************/
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
// Machine names
|
||
|
SIntTxt MacMachineNames[] = {
|
||
|
{MAC_CPU_TYPE_I386, "Intel 32 bit"},
|
||
|
{MAC_CPU_TYPE_X86_64, "Intel 64 bit"},
|
||
|
{MAC_CPU_TYPE_ARM, "Arm"},
|
||
|
{MAC_CPU_TYPE_SPARC, "Sparc"},
|
||
|
{MAC_CPU_TYPE_POWERPC, "Power PC 32 bit"},
|
||
|
{MAC_CPU_TYPE_POWERPC64, "Power PC 64 bit"}
|
||
|
};
|
||
|
|
||
|
// CPU subtype names
|
||
|
SIntTxt MacCPUSubtypeNames[] = {
|
||
|
{MAC_CPU_SUBTYPE_POWERPC_ALL, "Power PC All"},
|
||
|
{MAC_CPU_SUBTYPE_I386_ALL, "Intel All"}
|
||
|
};
|
||
|
|
||
|
// File type names
|
||
|
SIntTxt MacFileTypeNames[] = {
|
||
|
{MAC_OBJECT, "Relocatable object file"},
|
||
|
{MAC_EXECUTE, "demand paged executable file"},
|
||
|
{MAC_FVMLIB, "fixed VM shared library file"},
|
||
|
{MAC_CORE, "core file"},
|
||
|
{MAC_PRELOAD, "preloaded executable file"},
|
||
|
{MAC_DYLIB, "dynamicly bound shared library file"},
|
||
|
{MAC_DYLINKER, "dynamic link editor"},
|
||
|
{MAC_BUNDLE, "dynamicly bound bundle file"}
|
||
|
};
|
||
|
|
||
|
// Command type names
|
||
|
SIntTxt MacCommandTypeNames[] = {
|
||
|
{MAC_LC_SEGMENT, "Segment"},
|
||
|
{MAC_LC_SYMTAB, "Symbol table"},
|
||
|
{MAC_LC_SYMSEG, "gdb symbol table info (obsolete)"},
|
||
|
{MAC_LC_THREAD, "thread"},
|
||
|
{MAC_LC_UNIXTHREAD, "unix thread"},
|
||
|
{MAC_LC_LOADFVMLIB, "load a specified fixed VM shared library"},
|
||
|
{MAC_LC_IDFVMLIB, "fixed VM shared library identification"},
|
||
|
{MAC_LC_IDENT, "object identification info (obsolete)"},
|
||
|
{MAC_LC_FVMFILE, "fixed VM file inclusion (internal use)"},
|
||
|
{MAC_LC_PREPAGE, "prepage command (internal use)"},
|
||
|
{MAC_LC_DYSYMTAB, "dynamic link-edit symbol table info"},
|
||
|
{MAC_LC_LOAD_DYLIB, "load a dynamicly linked shared library"},
|
||
|
{MAC_LC_ID_DYLIB, "dynamicly linked shared lib identification"},
|
||
|
{MAC_LC_LOAD_DYLINKER, "load a dynamic linker"},
|
||
|
{MAC_LC_ID_DYLINKER, "dynamic linker identification"},
|
||
|
{MAC_LC_PREBOUND_DYLIB, "modules prebound for a dynamicly linked shared library"},
|
||
|
{MAC_LC_ROUTINES, "image routines"},
|
||
|
{MAC_LC_SUB_FRAMEWORK, "sub framework"},
|
||
|
{MAC_LC_SUB_UMBRELLA, "sub umbrella"},
|
||
|
{MAC_LC_SUB_CLIENT, "sub client"},
|
||
|
{MAC_LC_SUB_LIBRARY, "sub library"},
|
||
|
{MAC_LC_TWOLEVEL_HINTS, "two-level namespace lookup hints"},
|
||
|
{MAC_LC_PREBIND_CKSUM, "prebind checksum"},
|
||
|
{MAC_LC_LOAD_WEAK_DYLIB&0xFF, "load a dynamically linked shared library, all symbols weak"},
|
||
|
{MAC_LC_SEGMENT_64, "64-bit segment"},
|
||
|
{MAC_LC_ROUTINES_64, "64-bit image routine"},
|
||
|
{MAC_LC_UUID, "uuid"}
|
||
|
};
|
||
|
|
||
|
// Relocation type names, 32 bit
|
||
|
SIntTxt Mac32RelocationTypeNames[] = {
|
||
|
{MAC32_RELOC_VANILLA, "Generic"},
|
||
|
{MAC32_RELOC_PAIR, "Second entry of a pair"},
|
||
|
{MAC32_RELOC_SECTDIFF, "Section diff"},
|
||
|
{MAC32_RELOC_PB_LA_PTR, "Prebound lazy "},
|
||
|
{MAC32_RELOC_LOCAL_SECTDIFF, "SectDif local"}
|
||
|
};
|
||
|
|
||
|
// Relocation type names, 64 bit
|
||
|
SIntTxt Mac64RelocationTypeNames[] = {
|
||
|
{MAC64_RELOC_UNSIGNED, "absolute address"},
|
||
|
{MAC64_RELOC_SIGNED, "signed 32-bit displ."},
|
||
|
{MAC64_RELOC_BRANCH, "Rel. jump 32-bit displ."},
|
||
|
{MAC64_RELOC_GOT_LOAD, "MOVQ load of a GOT entry"},
|
||
|
{MAC64_RELOC_GOT, "other GOT reference"},
|
||
|
{MAC64_RELOC_SUBTRACTOR, "Subtractor"},
|
||
|
{MAC64_RELOC_SIGNED_1, "signed 32-bit displacement with -1 addend"},
|
||
|
{MAC64_RELOC_SIGNED_2, "signed 32-bit displacement with -2 addend"},
|
||
|
{MAC64_RELOC_SIGNED_4, "signed 32-bit displacement with -4 addend"}
|
||
|
};
|
||
|
|
||
|
// Symbol type names
|
||
|
SIntTxt MacSymbolTypeNames[] = {
|
||
|
{MAC_N_UNDF, "Undefined, no section"},
|
||
|
{MAC_N_ABS, "Absolute, no section"},
|
||
|
{MAC_N_SECT, "Defined"},
|
||
|
{MAC_N_PBUD, "Prebound undefined (defined in a dylib)"},
|
||
|
{MAC_N_INDR, "Indirect"}
|
||
|
};
|
||
|
|
||
|
// Symbol reference type names
|
||
|
SIntTxt MacSymbolReferenceTypeNames[] = {
|
||
|
{MAC_REF_FLAG_UNDEFINED_NON_LAZY, "External non lazy"},
|
||
|
{MAC_REF_FLAG_UNDEFINED_LAZY, "External lazy (function call)"},
|
||
|
{MAC_REF_FLAG_DEFINED, "Defined public"},
|
||
|
{MAC_REF_FLAG_PRIVATE_DEFINED, "Defined private"},
|
||
|
{MAC_REF_FLAG_PRIVATE_UNDEFINED_NON_LAZY, "Private undefined non lazy"},
|
||
|
{MAC_REF_FLAG_PRIVATE_UNDEFINED_LAZY, "Private undefined lazy"}
|
||
|
};
|
||
|
|
||
|
// Symbol descriptor flag names
|
||
|
SIntTxt MacSymbolDescriptorFlagNames[] = {
|
||
|
{MAC_REFERENCED_DYNAMICALLY, "Referenced dynamically"},
|
||
|
// {MAC_N_DESC_DISCARDED, "Discarded"},
|
||
|
{MAC_N_NO_DEAD_STRIP, "Don't dead-strip"},
|
||
|
{MAC_N_WEAK_REF, "Weak external"},
|
||
|
{MAC_N_WEAK_DEF, "Weak public"}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
// Class CMACHO members:
|
||
|
// Constructor
|
||
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
|
||
|
CMACHO<MACSTRUCTURES>::CMACHO() {
|
||
|
// Set everything to zero
|
||
|
memset(this, 0, sizeof(*this));
|
||
|
}
|
||
|
|
||
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
|
||
|
void CMACHO<MACSTRUCTURES>::ParseFile(){
|
||
|
// Load and parse file buffer
|
||
|
FileHeader = *(TMAC_header*)Buf(); // Copy file header
|
||
|
|
||
|
// Loop through file commands
|
||
|
uint32 cmd, cmdsize;
|
||
|
uint32 currentoffset = sizeof(TMAC_header);
|
||
|
for (uint32 i = 1; i <= FileHeader.ncmds; i++) {
|
||
|
if (currentoffset >= this->GetDataSize()) {
|
||
|
err.submit(2016); return;
|
||
|
}
|
||
|
uint8 * currentp = (uint8*)(Buf() + currentoffset);
|
||
|
cmd = ((MAC_load_command*)currentp) -> cmd;
|
||
|
cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
|
||
|
// Interpret specific command type
|
||
|
switch(cmd) {
|
||
|
case MAC_LC_SEGMENT: {
|
||
|
if (WordSize != 32) err.submit(2320); // mixed segment size
|
||
|
MAC_segment_command_32 * sh = (MAC_segment_command_32*)currentp;
|
||
|
SegmentOffset = sh->fileoff; // File offset of segment
|
||
|
SegmentSize = sh->filesize; // Size of segment
|
||
|
NumSections = sh->nsects; // Number of sections
|
||
|
SectionHeaderOffset = currentoffset + sizeof(TMAC_segment_command); // File offset of section headers
|
||
|
if (!ImageBase && strcmp(sh->segname, "__TEXT")==0) ImageBase = sh->vmaddr; // Find image base
|
||
|
break;}
|
||
|
|
||
|
case MAC_LC_SEGMENT_64: {
|
||
|
if (WordSize != 64) err.submit(2320); // mixed segment size
|
||
|
MAC_segment_command_64 * sh = (MAC_segment_command_64*)currentp;
|
||
|
SegmentOffset = (uint32)sh->fileoff; // File offset of segment
|
||
|
SegmentSize = (uint32)sh->filesize; // Size of segment
|
||
|
NumSections = sh->nsects; // Number of sections
|
||
|
SectionHeaderOffset = currentoffset + sizeof(TMAC_segment_command); // File offset of section headers
|
||
|
if (!ImageBase && strcmp(sh->segname, "__TEXT")==0) ImageBase = sh->vmaddr; // Find image base
|
||
|
break;}
|
||
|
|
||
|
case MAC_LC_SYMTAB: {
|
||
|
MAC_symtab_command * sh = (MAC_symtab_command*)currentp;
|
||
|
SymTabOffset = sh->symoff; // File offset of symbol table
|
||
|
SymTabNumber = sh->nsyms; // Number of entries in symbol table
|
||
|
StringTabOffset = sh->stroff; // File offset of string table
|
||
|
StringTabSize = sh->strsize; // Size of string table
|
||
|
break;}
|
||
|
|
||
|
case MAC_LC_DYSYMTAB: {
|
||
|
MAC_dysymtab_command * sh = (MAC_dysymtab_command*)currentp;
|
||
|
ilocalsym = sh->ilocalsym; // index to local symbols
|
||
|
nlocalsym = sh->nlocalsym; // number of local symbols
|
||
|
iextdefsym = sh->iextdefsym; // index to externally defined symbols
|
||
|
nextdefsym = sh->nextdefsym; // number of externally defined symbols
|
||
|
iundefsym = sh->iundefsym; // index to undefined symbols
|
||
|
nundefsym = sh->nundefsym; // number of undefined symbols
|
||
|
IndirectSymTabOffset = sh->indirectsymoff;// file offset to the indirect symbol table
|
||
|
IndirectSymTabNumber = sh->nindirectsyms; // number of indirect symbol table entries
|
||
|
break;}
|
||
|
}
|
||
|
currentoffset += cmdsize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Debug dump
|
||
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
|
||
|
void CMACHO<MACSTRUCTURES>::Dump(int options) {
|
||
|
uint32 icmd; // Command index
|
||
|
int32 isec1; // Section index within segment
|
||
|
int32 isec2; // Section index global
|
||
|
int32 nsect; // Number of sections in segment
|
||
|
|
||
|
if (options & DUMP_FILEHDR) {
|
||
|
// File header
|
||
|
printf("\nDump of Mach-O file %s", FileName);
|
||
|
printf("\n-----------------------------------------------");
|
||
|
printf("\nFile size: 0x%X", this->GetDataSize());
|
||
|
printf("\nFile header:");
|
||
|
printf("\n CPU type: %s, subtype: %s",
|
||
|
Lookup(MacMachineNames, FileHeader.cputype),
|
||
|
Lookup(MacCPUSubtypeNames, FileHeader.cpusubtype));
|
||
|
|
||
|
printf("\n File type: %s - %s",
|
||
|
GetFileFormatName(FileType), Lookup(MacFileTypeNames, FileHeader.filetype));
|
||
|
|
||
|
printf("\n Number of load commands: %i, Size of commands: 0x%X, Flags: %X",
|
||
|
FileHeader.ncmds, FileHeader.sizeofcmds, FileHeader.flags);
|
||
|
}
|
||
|
|
||
|
uint32 cmd; // Load command
|
||
|
uint32 cmdsize; // Command size
|
||
|
// Pointer to current position
|
||
|
uint8 * currentp = (uint8*)(Buf() + sizeof(TMAC_header));
|
||
|
|
||
|
// Loop through file commands
|
||
|
for (icmd = 1; icmd <= FileHeader.ncmds; icmd++) {
|
||
|
cmd = ((MAC_load_command*)currentp) -> cmd;
|
||
|
cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
|
||
|
|
||
|
if (options & DUMP_SECTHDR) {
|
||
|
// Dump command header
|
||
|
printf("\n\nCommand %i: %s, size: 0x%X", icmd,
|
||
|
Lookup(MacCommandTypeNames, cmd), cmdsize);
|
||
|
|
||
|
// Interpret specific command type
|
||
|
switch(cmd) {
|
||
|
case MAC_LC_SEGMENT: {
|
||
|
MAC_segment_command_32 * sh = (MAC_segment_command_32*)currentp;
|
||
|
printf("\n Name: %s, Memory address 0x%X, Memory size 0x%X"
|
||
|
"\n File offset 0x%X, File size 0x%X, Maxprot 0x%X, Initprot 0x%X"
|
||
|
"\n Number of sections %i, Flags 0x%X",
|
||
|
sh->segname, sh->vmaddr, sh->vmsize,
|
||
|
sh->fileoff, sh->filesize, sh->maxprot, sh->initprot,
|
||
|
sh->nsects, sh->flags);
|
||
|
break;}
|
||
|
|
||
|
case MAC_LC_SEGMENT_64: {
|
||
|
MAC_segment_command_64 * sh = (MAC_segment_command_64*)currentp;
|
||
|
printf("\n Name: %s, \n Memory address 0x%08X%08X, Memory size 0x%08X%08X"
|
||
|
"\n File offset 0x%08X%08X, File size 0x%08X%08X\n Maxprot 0x%X, Initprot 0x%X"
|
||
|
"\n Number of sections %i, Flags 0x%X",
|
||
|
sh->segname, (uint32)(sh->vmaddr>>32), (uint32)sh->vmaddr,
|
||
|
(uint32)(sh->vmsize>>32), (uint32)sh->vmsize,
|
||
|
(uint32)(sh->fileoff>>32), (uint32)sh->fileoff,
|
||
|
(uint32)(sh->filesize>>32), (uint32)sh->filesize,
|
||
|
sh->maxprot, sh->initprot,
|
||
|
sh->nsects, sh->flags);
|
||
|
break;}
|
||
|
|
||
|
case MAC_LC_SYMTAB: {
|
||
|
MAC_symtab_command * sh = (MAC_symtab_command*)currentp;
|
||
|
printf("\n Symbol table offset 0x%X, number of symbols %i,"
|
||
|
"\n String table offset 0x%X, String table size 0x%X",
|
||
|
sh->symoff, sh->nsyms, sh->stroff, sh->strsize);
|
||
|
break;}
|
||
|
|
||
|
case MAC_LC_DYSYMTAB: {
|
||
|
MAC_dysymtab_command * sh = (MAC_dysymtab_command*)currentp;
|
||
|
printf("\n Index to local symbols %i, number of local symbols %i,"
|
||
|
"\n Index to external symbols %i, number of external symbols %i,"
|
||
|
"\n Index to undefined symbols %i, number of undefined symbols %i,"
|
||
|
"\n File offset to TOC 0x%X, number of entries in TOC %i,",
|
||
|
sh->ilocalsym, sh->nlocalsym, sh->iextdefsym, sh->nextdefsym,
|
||
|
sh->iundefsym, sh->nundefsym, sh->tocoff, sh->ntoc);
|
||
|
printf("\n File offset to module table 0x%X, Number of module table entries %i,"
|
||
|
"\n Offset to referenced symbol table 0x%X, Number of referenced symtab entries %i"
|
||
|
"\n Offset to indirect symbol table 0x%X, Number of indirect symtab entries %i"
|
||
|
"\n Offset to external relocation entries 0x%X, Number of external reloc. entries %i"
|
||
|
"\n Offset to local relocation entries 0x%X, Number of local reloc. entries %i",
|
||
|
sh->modtaboff, sh->nmodtab, sh->extrefsymoff, sh->nextrefsyms,
|
||
|
sh->indirectsymoff, sh->nindirectsyms, sh->extreloff, sh->nextrel,
|
||
|
sh->locreloff, sh->nlocrel);
|
||
|
break;}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
currentp += cmdsize;
|
||
|
}
|
||
|
|
||
|
// Dump section headers
|
||
|
if (options & DUMP_SECTHDR) {
|
||
|
printf("\n\nSections:");
|
||
|
|
||
|
// Reset current pointer
|
||
|
currentp = (uint8*)(Buf() + sizeof(TMAC_header));
|
||
|
isec2 = 0;
|
||
|
|
||
|
// Loop through load commands
|
||
|
for (icmd = 1; icmd <= FileHeader.ncmds; icmd++) {
|
||
|
cmd = ((MAC_load_command*)currentp) -> cmd;
|
||
|
cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
|
||
|
|
||
|
if (cmd == MAC_LC_SEGMENT) {
|
||
|
// This is a 32-bit segment command
|
||
|
// Number of sections in segment
|
||
|
nsect = ((MAC_segment_command_32*)currentp) -> nsects;
|
||
|
|
||
|
// Find first section header
|
||
|
MAC_section_32 * sectp = (MAC_section_32*)(currentp + sizeof(MAC_segment_command_32));
|
||
|
|
||
|
// Loop through section headers
|
||
|
for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) {
|
||
|
printf("\n\nSection %i: Name: %s, Segment: %s.",
|
||
|
++isec2, sectp->sectname, sectp->segname);
|
||
|
printf("\n Memory address 0x%X, Size 0x%X, File offset 0x%X"
|
||
|
"\n Alignment %i, Reloc. ent. offset 0x%X, Num reloc. %i"
|
||
|
"\n Flags 0x%X, reserved1 0x%X, reserved2 0x%X",
|
||
|
sectp->addr, sectp->size, sectp->offset, 1 << sectp->align,
|
||
|
sectp->reloff, sectp->nreloc, sectp->flags,
|
||
|
sectp->reserved1, sectp->reserved2);
|
||
|
|
||
|
if (sectp->nreloc && (options & DUMP_RELTAB)) {
|
||
|
// Dump relocations
|
||
|
printf("\n Relocations:");
|
||
|
if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;}
|
||
|
MAC_relocation_info * relp = (MAC_relocation_info*)(Buf() + sectp->reloff);
|
||
|
for (uint32 r = 1; r <= sectp->nreloc; r++, relp++) {
|
||
|
if (relp->r_address & R_SCATTERED) {
|
||
|
// scattered relocation into
|
||
|
MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp;
|
||
|
|
||
|
if (!(scatp->r_type & MAC32_RELOC_PAIR)) {
|
||
|
printf ("\n Offset: 0x%X, Value: 0x%X, Length: %i, Scat. Type: %s",
|
||
|
scatp->r_address, scatp->r_value, 1 << scatp->r_length,
|
||
|
Lookup(Mac32RelocationTypeNames, scatp->r_type));
|
||
|
if (scatp->r_address < sectp->size) {
|
||
|
printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+scatp->r_address));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// Second entry of a pair
|
||
|
printf ("\n Offset2: 0x%X, Value2: 0x%X, Length2: %i",
|
||
|
scatp->r_address, scatp->r_value, 1 << scatp->r_length);
|
||
|
}
|
||
|
if (scatp->r_pcrel) printf(", PC relative");
|
||
|
}
|
||
|
else {
|
||
|
// non-scattered
|
||
|
if (relp->r_extern) printf ("\n Symbol number %i, ", relp->r_symbolnum);
|
||
|
else printf ("\n Section: %i, ", relp->r_symbolnum);
|
||
|
printf ("Offset: 0x%X, ", relp->r_address);
|
||
|
if (relp->r_pcrel) printf ("PC relative, ");
|
||
|
printf ("\n Length: %i, Extern: %i, Type: %s",
|
||
|
1 << relp->r_length, relp->r_extern,
|
||
|
Lookup(Mac32RelocationTypeNames, relp->r_type));
|
||
|
if (relp->r_address < sectp->size) {
|
||
|
printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+relp->r_address));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (cmd == MAC_LC_SEGMENT_64) {
|
||
|
// This is a 64-bit segment command
|
||
|
// Number of sections in segment
|
||
|
nsect = ((MAC_segment_command_64*)currentp) -> nsects;
|
||
|
|
||
|
// Find first section header
|
||
|
MAC_section_64 * sectp = (MAC_section_64*)(currentp + sizeof(MAC_segment_command_64));
|
||
|
|
||
|
// Loop through section headers
|
||
|
for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) {
|
||
|
printf("\n\nSection %i: Name: %s, Segment: %s.",
|
||
|
++isec2, sectp->sectname, sectp->segname);
|
||
|
printf("\n Memory address 0x%X, Size 0x%X, File offset 0x%X"
|
||
|
"\n Alignment %i, Reloc. ent. offset 0x%X, Num reloc. %i"
|
||
|
"\n Flags 0x%X, reserved1 0x%X, reserved2 0x%X",
|
||
|
(uint32)sectp->addr, (uint32)sectp->size, sectp->offset, 1 << sectp->align,
|
||
|
sectp->reloff, sectp->nreloc, sectp->flags,
|
||
|
sectp->reserved1, sectp->reserved2);
|
||
|
|
||
|
if (sectp->nreloc && (options & DUMP_RELTAB)) {
|
||
|
// Dump relocations
|
||
|
printf("\n Relocations:");
|
||
|
MAC_relocation_info * relp = (MAC_relocation_info*)(Buf() + sectp->reloff);
|
||
|
for (uint32 r = 1; r <= sectp->nreloc; r++, relp++) {
|
||
|
if (relp->r_address & R_SCATTERED) {
|
||
|
// scattered relocation into (not used in 64-bit Mach-O)
|
||
|
MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp;
|
||
|
if (!(scatp->r_type & MAC32_RELOC_PAIR)) {
|
||
|
printf ("\n Unexpected scattered relocation. Offset: 0x%X, Value: 0x%X, Length: %i, Scat. Type: %s",
|
||
|
scatp->r_address, scatp->r_value, 1 << scatp->r_length,
|
||
|
Lookup(Mac64RelocationTypeNames, scatp->r_type));
|
||
|
if (scatp->r_address < sectp->size) {
|
||
|
printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+scatp->r_address));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// Second entry of a pair
|
||
|
printf ("\n Offset2: 0x%X, Value2: 0x%X, Length2: %i",
|
||
|
scatp->r_address, scatp->r_value, 1 << scatp->r_length);
|
||
|
}
|
||
|
if (scatp->r_pcrel) printf(", PC relative");
|
||
|
}
|
||
|
else {
|
||
|
// non-scattered
|
||
|
if (relp->r_extern) printf ("\n Symbol number %i, ", relp->r_symbolnum);
|
||
|
else printf ("\n Section: %i, ", relp->r_symbolnum);
|
||
|
printf ("Offset: 0x%X, ", relp->r_address);
|
||
|
if (relp->r_pcrel) printf ("PC relative, ");
|
||
|
printf ("\n Length: %i, Extern: %i, Type: %s",
|
||
|
1 << relp->r_length, relp->r_extern,
|
||
|
Lookup(Mac64RelocationTypeNames, relp->r_type));
|
||
|
if (relp->r_type != MAC64_RELOC_SUBTRACTOR && relp->r_address < sectp->size) {
|
||
|
// Print inline addend
|
||
|
if (relp->r_length == 3) {
|
||
|
// 8 bytes inline addend
|
||
|
printf(", Inline: 0x%08X%08X", *(int32*)(Buf()+sectp->offset+relp->r_address+4), *(int32*)(Buf()+sectp->offset+relp->r_address));
|
||
|
}
|
||
|
else {
|
||
|
// 4 bytes inline addend
|
||
|
printf(", Inline: 0x%08X", *(int32*)(Buf()+sectp->offset+relp->r_address));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
currentp += cmdsize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// pointer to string table
|
||
|
char * strtab = (char*)(Buf() + StringTabOffset);
|
||
|
// pointer to symbol table
|
||
|
TMAC_nlist * symp0 = (TMAC_nlist*)(Buf() + SymTabOffset);
|
||
|
|
||
|
// Dump symbol table
|
||
|
if (options & DUMP_SYMTAB) {
|
||
|
printf("\n\nSymbol table:");
|
||
|
uint32 i;
|
||
|
TMAC_nlist * symp;
|
||
|
|
||
|
// loop through symbol table
|
||
|
for (i = 0, symp = symp0; i < SymTabNumber; i++, symp++) {
|
||
|
|
||
|
// Header for first symbol of each category: (alphabetical within each category)
|
||
|
if (i == ilocalsym && nlocalsym) printf("\n\n Local symbols:");
|
||
|
if (i == iextdefsym && nextdefsym) printf("\n\n Public symbols:");
|
||
|
if (i == iundefsym && nundefsym) printf("\n\n External symbols:");
|
||
|
|
||
|
if (symp->n_strx < StringTabSize && !(symp->n_type & MAC_N_STAB)) {
|
||
|
printf("\n %2i %s, Section %i, Value 0x%X\n ",
|
||
|
i, strtab + symp->n_strx, symp->n_sect, uint32(symp->n_value));
|
||
|
}
|
||
|
else {
|
||
|
printf("\n String table offset: 0x%X, Section %i, Value 0x%X\n ",
|
||
|
symp->n_strx, symp->n_sect, uint32(symp->n_value));
|
||
|
}
|
||
|
|
||
|
if (symp->n_type & MAC_N_STAB) {
|
||
|
printf ("Debug symbol, stab = 0x%X, ", symp->n_type);
|
||
|
}
|
||
|
else {
|
||
|
if (symp->n_type & MAC_N_PEXT) printf ("Private external (limited global scope), ");
|
||
|
if (symp->n_type & MAC_N_EXT ) printf ("External, ");
|
||
|
printf("%s", Lookup(MacSymbolTypeNames, symp->n_type & MAC_N_TYPE));
|
||
|
}
|
||
|
printf("\n Reference type: %s, Flags: ",
|
||
|
Lookup(MacSymbolReferenceTypeNames, symp->n_desc & MAC_REF_TYPE));
|
||
|
for (uint32 f = MAC_REFERENCED_DYNAMICALLY; f <= MAC_N_WEAK_DEF; f <<= 1) {
|
||
|
if (symp->n_desc & f) {
|
||
|
printf("%s, ", Lookup(MacSymbolDescriptorFlagNames, f));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Check if indirect symbol table is valid
|
||
|
if (IndirectSymTabNumber && IndirectSymTabOffset + IndirectSymTabNumber*4 < this->GetDataSize()) {
|
||
|
|
||
|
// Write indirect symbol table
|
||
|
printf("\n\n Indirect symbols:");
|
||
|
|
||
|
// loop through indirect symbol table
|
||
|
uint32 * IndSymip = (uint32*)(Buf() + IndirectSymTabOffset);
|
||
|
|
||
|
for (i = 0; i < IndirectSymTabNumber; i++, IndSymip++) {
|
||
|
|
||
|
// Check if index within symbol table
|
||
|
if (*IndSymip >= SymTabNumber) {
|
||
|
//err.submit(2016);
|
||
|
printf("\n Unknown(0x%X)", *IndSymip);
|
||
|
continue;
|
||
|
}
|
||
|
// Find record
|
||
|
TMAC_nlist * pIndSym = symp0 + *IndSymip;
|
||
|
// Find name
|
||
|
uint32 StringIndex = pIndSym->n_strx;
|
||
|
if (StringIndex >= StringTabSize) {
|
||
|
err.submit(2035); continue;
|
||
|
}
|
||
|
// print name
|
||
|
printf("\n %s", strtab + StringIndex);
|
||
|
// print type, etc.
|
||
|
printf(", type 0x%X, sect %i, desc 0x%X, val 0x%X",
|
||
|
pIndSym->n_type, pIndSym->n_sect, pIndSym->n_desc, uint32(pIndSym->n_value));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Dump string table
|
||
|
if (options & DUMP_STRINGTB) {
|
||
|
printf("\n\nString table:");
|
||
|
uint32 str = 0, istr = 0;
|
||
|
while (str < StringTabSize) {
|
||
|
char * p = (char*)(Buf() + StringTabOffset + str);
|
||
|
printf("\n %3i: %s", str, p);
|
||
|
istr++; str += (uint32)strlen(p) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
|
||
|
void CMACHO<MACSTRUCTURES>::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
|
||
|
// Make list of public names
|
||
|
uint32 i;
|
||
|
SStringEntry se; // Entry in Index
|
||
|
|
||
|
// Interpret header:
|
||
|
ParseFile();
|
||
|
|
||
|
// pointer to string table
|
||
|
char * strtab = (char*)(Buf() + StringTabOffset);
|
||
|
|
||
|
// loop through public symbol table
|
||
|
TMAC_nlist * symp = (TMAC_nlist*)(Buf() + SymTabOffset + iextdefsym * sizeof(TMAC_nlist));
|
||
|
for (i = 0; i < nextdefsym; i++, symp++) {
|
||
|
if (symp->n_strx < StringTabSize && !(symp->n_type & MAC_N_STAB)) {
|
||
|
// Public symbol found
|
||
|
se.Member = m;
|
||
|
// Store name
|
||
|
se.String = Strings->PushString(strtab + symp->n_strx);
|
||
|
// Store name index
|
||
|
Index->Push(se);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Member functions for class MacSymbolTableBuilder
|
||
|
|
||
|
template <class TMAC_nlist, class MInt>
|
||
|
MacSymbolTableBuilder<TMAC_nlist, MInt>::MacSymbolTableBuilder() { // Constructor
|
||
|
sorted = 0;
|
||
|
}
|
||
|
|
||
|
template <class TMAC_nlist, class MInt>
|
||
|
void MacSymbolTableBuilder<TMAC_nlist, MInt>::AddSymbol(int OldIndex, const char * name, int type, int Desc, int section, MInt value) {
|
||
|
// Add symbol to list
|
||
|
MacSymbolRecord<TMAC_nlist> rec;
|
||
|
memset(&rec, 0, sizeof(rec)); // Set to zero
|
||
|
/* !!
|
||
|
if (GetNumEntries() == 0) {
|
||
|
// First record must indicate empty string
|
||
|
rec.Name = StringBuffer.PushString(""); // Empty string
|
||
|
Push(&rec, sizeof(rec)); // Put empty record in memory buffer
|
||
|
}
|
||
|
*/
|
||
|
rec.n_type = (uint8)type; // Copy values
|
||
|
rec.n_sect = (uint8)section;
|
||
|
rec.n_desc = (int16)Desc;
|
||
|
rec.n_value = value;
|
||
|
rec.Name = StringBuffer.PushString(name); // Copy name and store index
|
||
|
rec.OldIndex = OldIndex; // Remember old index
|
||
|
Push(&rec, sizeof(rec)); // Put in memory buffer
|
||
|
sorted = 0; // Remember not sorted
|
||
|
}
|
||
|
|
||
|
template <class TMAC_nlist, class MInt>
|
||
|
void MacSymbolTableBuilder<TMAC_nlist, MInt>::SortList() {
|
||
|
// Sort the list
|
||
|
if (sorted) return; // allready sorted
|
||
|
|
||
|
MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf(); // Point to list
|
||
|
|
||
|
// Simple Shell sort with Sedgewick gaps:
|
||
|
int i, j, k, gap, n = (int)GetNumEntries();
|
||
|
for (k = 15; k >= 0; k--) {
|
||
|
gap = (1 << 2 * k) | (3 << k >> 1) | 1; // Sedgewick gap grants O(N^4/3)
|
||
|
for (i = gap; i < n; i++) {
|
||
|
MacSymbolRecord<TMAC_nlist> key = p[i];
|
||
|
char * strkey = StringBuffer.Buf() + key.Name;
|
||
|
for (j = i - gap; j >= 0 && strcmp(strkey, StringBuffer.Buf() + p[j].Name) < 0; j -= gap) {
|
||
|
p[j + gap] = p[j];
|
||
|
}
|
||
|
p[j + gap] = key;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sorted = 1;
|
||
|
}
|
||
|
|
||
|
template <class TMAC_nlist, class MInt>
|
||
|
int MacSymbolTableBuilder<TMAC_nlist, MInt>::TranslateIndex(int OldIndex) {
|
||
|
// Translate old index to new index (0-based)
|
||
|
// Returns -1 if not found
|
||
|
|
||
|
// Don't sort list. This would change indices if __mh_executer_header added later
|
||
|
// if (!sorted) SortList();
|
||
|
|
||
|
MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf(); // Point to list
|
||
|
|
||
|
// Search through list for OldIndex
|
||
|
for (int i = 0; i < (int)GetNumEntries(); i++) {
|
||
|
if (p[i].OldIndex == OldIndex) {
|
||
|
// Match found
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
// Not found
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
template <class TMAC_nlist, class MInt>
|
||
|
void MacSymbolTableBuilder<TMAC_nlist, MInt>::StoreList(CMemoryBuffer * SymbolTable, CMemoryBuffer * StringTable) {
|
||
|
// Store sorted list in buffers
|
||
|
|
||
|
// Don't sort list unless commanded to do so. Will mess up indices
|
||
|
// if (!sorted) SortList(); // Make sure list is sorted
|
||
|
|
||
|
MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf(); // Point to list
|
||
|
|
||
|
for (uint32 i = 0; i < GetNumEntries(); i++, p++) {
|
||
|
p->n_strx = StringTable->PushString(StringBuffer.Buf()+p->Name); // Put name in string table
|
||
|
SymbolTable->Push(p, sizeof(TMAC_nlist)); // Store only the TMAC_nlist part of the record in SymbolTable
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <class TMAC_nlist, class MInt>
|
||
|
int MacSymbolTableBuilder<TMAC_nlist, MInt>::Search(const char * name) {
|
||
|
// Search for name. Return -1 if not found.
|
||
|
MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf(); // Point to list
|
||
|
for (int i = 0; i < (int)GetNumEntries(); i++) {
|
||
|
if (strcmp(StringBuffer.Buf()+p[i].Name, name) == 0) {
|
||
|
return i; // Found
|
||
|
}
|
||
|
}
|
||
|
return -1; // Not found
|
||
|
}
|
||
|
|
||
|
template <class TMAC_nlist, class MInt>
|
||
|
MacSymbolRecord<TMAC_nlist> & MacSymbolTableBuilder<TMAC_nlist, MInt>::operator[] (uint32 i) {
|
||
|
// Access member
|
||
|
uint32 Offset = i * sizeof(MacSymbolRecord<TMAC_nlist>);
|
||
|
if (i + sizeof(MacSymbolRecord<TMAC_nlist>) > this->GetDataSize()) {
|
||
|
err.submit(9003); Offset = 0;
|
||
|
}
|
||
|
return Get<MacSymbolRecord<TMAC_nlist> >(Offset);
|
||
|
}
|
||
|
|
||
|
|
||
|
/****** Class CMACUNIV for parsing Macintosh universal binary *************/
|
||
|
CMACUNIV::CMACUNIV() {
|
||
|
// Default constructor
|
||
|
}
|
||
|
|
||
|
|
||
|
void CMACUNIV::Go(int options) {
|
||
|
// Apply command options to all components
|
||
|
|
||
|
// Check file size
|
||
|
if (GetDataSize() < 28) return;
|
||
|
|
||
|
// Read number of components
|
||
|
uint32 NumComponents = EndianChange(Get<MAC_UNIV_FAT_HEADER>(0).num_arch);
|
||
|
if (NumComponents == 0 || NumComponents > 10) {
|
||
|
// Number of components too big or too small
|
||
|
err.submit(2701, NumComponents);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
uint32 i; // Component number
|
||
|
uint32 fo; // File offset of component pointer
|
||
|
CConverter ComponentBuffer; // Used for converting component
|
||
|
CConverter OutputBuffer; // Temporary storage of output file
|
||
|
int DesiredWordSize = cmd.DesiredWordSize; // Desired word size, if specified on command line
|
||
|
|
||
|
// Loop through components
|
||
|
for (i = 0, fo = sizeof(MAC_UNIV_FAT_HEADER); i < NumComponents; i++, fo += sizeof(MAC_UNIV_FAT_ARCH)) {
|
||
|
|
||
|
// Get component pointer
|
||
|
MAC_UNIV_FAT_ARCH & ComponentPointer = Get<MAC_UNIV_FAT_ARCH>(fo);
|
||
|
|
||
|
// Get offset and size of component
|
||
|
uint32 ComponentOffset = EndianChange(ComponentPointer.offset);
|
||
|
uint32 ComponentSize = EndianChange(ComponentPointer.size);
|
||
|
|
||
|
// Check within range
|
||
|
if (ComponentOffset + ComponentSize > GetDataSize()) {
|
||
|
err.submit(2016);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Put component into buffer
|
||
|
ComponentBuffer.Reset();
|
||
|
ComponentBuffer.Push(Buf() + ComponentOffset, ComponentSize);
|
||
|
|
||
|
// Indicate component
|
||
|
printf("\n\n\nComponent file number %i:\n", i + 1);
|
||
|
|
||
|
// Check type
|
||
|
uint32 ComponentType = ComponentBuffer.GetFileType();
|
||
|
if (DesiredWordSize && DesiredWordSize != ComponentBuffer.WordSize) {
|
||
|
err.submit(1151, ComponentBuffer.WordSize);
|
||
|
}
|
||
|
else if (ComponentType != FILETYPE_MACHO_LE) {
|
||
|
// Format not supported
|
||
|
printf(" Format not supported: %s", GetFileFormatName(ComponentType));
|
||
|
}
|
||
|
else {
|
||
|
// Format OK. Handle component
|
||
|
if (cmd.DumpOptions == 0 && OutputBuffer.GetDataSize()) {
|
||
|
// More than one component that can be converted
|
||
|
err.submit(1150);
|
||
|
}
|
||
|
else {
|
||
|
// Transfer filenames
|
||
|
ComponentBuffer.FileName = FileName;
|
||
|
ComponentBuffer.OutputFileName = OutputFileName;
|
||
|
// Do command
|
||
|
ComponentBuffer.Go();
|
||
|
// Is there an output file?
|
||
|
if (cmd.DumpOptions == 0) {
|
||
|
// Save output file
|
||
|
ComponentBuffer >> OutputBuffer;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Is there an output file?
|
||
|
if (OutputBuffer.GetDataSize()) {
|
||
|
// Take over output file and skip remaining components
|
||
|
*this << OutputBuffer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Make template instances for 32 and 64 bits
|
||
|
template class CMACHO<MAC32STRUCTURES>;
|
||
|
template class CMACHO<MAC64STRUCTURES>;
|
||
|
template class MacSymbolTableBuilder<MAC_nlist_32, int32>;
|
||
|
template class MacSymbolTableBuilder<MAC_nlist_64, int64>;
|