forked from KolibriOS/kolibrios
Added objconv port.
git-svn-id: svn://kolibrios.org@9683 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
754
programs/develop/objconv/macho.cpp
Normal file
754
programs/develop/objconv/macho.cpp
Normal file
@@ -0,0 +1,754 @@
|
||||
/**************************** 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>;
|
Reference in New Issue
Block a user