#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/fat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <mach/thread_status.h>
#include <mach/machine.h>
#include <mach/ppc/thread_status.h>
#include "sym.h"
extern int errno;
int image = 0;
int sortname(const void *a, const void *b);
int sortaddr(const void *a, const void *b);
void *bsrch(void *key, void *base, unsigned int num, unsigned int size, int (*compare) (void *, void *));
int srchaddr(void *key, void *b);
int srchname(void *key, void *b);
typedef struct sectdef {
uint32_t start;
uint32_t size;
int code;
struct section *sectp;
char *core;
uint32_t nxtassgn;
} sectdef;
char *sym = 0;
char *symH = 0;
char *symN = 0;
char *strings = 0;
int rsymc = 0;
char *nullname = 0;
sectdef sctn[256];
int sectno = 0;
uint64_t entryaddr = 0xFFFFFFFFFFFFFFFFULL;
uint64_t textaddr = 0;
uint64_t textsize = 0;
uint32_t textsect = 0xFFFFFFFF;
struct section imgsect = {
.sectname = "Image",
.segname = "Image",
.addr = 0,
.size = 0,
.offset = 0,
.align = 2,
.nreloc = 0,
.flags = S_REGULAR | S_ATTR_SOME_INSTRUCTIONS,
.reserved1 = 0,
.reserved2 = 0
};
int syminitcore(uint32_t *coreimage, uint64_t vmaddr, uint64_t ssize) {
symH = (char *)0;
symN = (char *)0;
strings = (char *)0;
rsymc = 0;
nullname = (char *)0;
sectno = 0;
entryaddr = 0xFFFFFFFFFFFFFFFFULL;
sym = (char*)coreimage;
textaddr = vmaddr;
textsize = ssize;
textsect = 0;
return 0;
}
#if defined(BILLANGELL)
int syminit(char *fname) {
int i, j, symfile;
uint64_t ssize;
struct fat_header *fheader;
struct mach_header *mheader;
struct load_command *ncmd;
struct segment_command *segcmd;
struct symtab_command *symtab = 0;
struct ppc_thread_state *regstate;
struct fat_arch *farch;
struct section *sect;
struct section *nsect;
struct nlist *symbs, *symb, *symbn, *symSortAddr, *symSortName;
unsigned int symcount;
unsigned int strsize;
uint32_t fatoff;
symfile = open(fname, O_RDONLY, 0);
if (symfile < 0) {
printf("Can't open symbol/image file, errno = %d\n", errno);
return 1 ;
}
ssize = lseek(symfile, 0, SEEK_END);
(void)lseek(symfile, 0, SEEK_SET);
sym = mmap(0, ssize, PROT_READ | PROT_WRITE, MAP_PRIVATE, symfile, 0);
if((uint32_t)sym == 0xFFFFFFFF) {
printf("Failed to map symbol/image file, errno = %d\n", errno);
return(1);
}
close(symfile);
#if 0
sctn[0].sddr = 0;
sctn[0].size = 0;
sctn[0].offset = 0;
sctn[0].sddr = 0;
sctn[0].sddr = 0;
#endif
textaddr = 0;
textsize = ssize;
textsect = 0;
if(image) {
loadsyms(fname);
return 0;
}
fheader = (struct fat_header *)sym;
mheader = (struct mach_header *)sym;
fatoff = 0;
if(fheader->magic == FAT_MAGIC) {
farch = (struct fat_arch *)((uint32_t)fheader + sizeof(struct fat_header));
for(i = 0; i < fheader->nfat_arch; i++) {
if(farch[i].cputype == CPU_TYPE_POWERPC) break;
}
if(i >= fheader->nfat_arch) {
printf("Could not find PPC 32-bit in fat header\n");
return (1);
}
mheader = (struct mach_header *)(sym + farch[i].offset);
fatoff = farch[i].offset;
}
#define dmacho 0
#if dmacho
printf(" magic = %08X\n", mheader->magic);
printf(" cputype = %08X\n", mheader->cputype);
printf("cpusubtype = %08X\n", mheader->cpusubtype);
printf(" filetype = %08X\n", mheader->filetype);
printf(" ncmds = %08X\n", mheader->ncmds);
printf("sizeofcmds = %08X\n", mheader->sizeofcmds);
printf(" flags = %08X\n", mheader->flags);
printf("\n\nCommands:\n\n");
#endif
sectno = 0;
ncmd = (struct load_command *)((unsigned int)mheader + sizeof(struct mach_header));
for(i = 0; i < mheader->ncmds; i++) {
switch (ncmd->cmd) {
case LC_SEGMENT:
segcmd = (struct segment_command *)ncmd;
#if dmacho
printf("LC_SEGMENT\n");
printf(" name = %s\n", segcmd->segname);
printf(" vmaddr = %08X\n", segcmd->vmaddr);
printf(" vmsize = %08X\n", segcmd->vmsize);
printf(" fileoff = %08X (%08X)\n", segcmd->fileoff, segcmd->fileoff + fatoff);
printf(" filesize = %08X\n", segcmd->filesize);
printf(" maxprot = %08X\n", segcmd->maxprot);
printf(" initprot = %08X\n", segcmd->initprot);
printf(" nsects = %08X\n", segcmd->nsects);
printf(" flags = %08X\n", segcmd->flags);
printf("\n Sections:\n");
#endif
nsect = (struct section *)((unsigned int)segcmd + sizeof(struct segment_command));
for(j = 0; j < segcmd->nsects; j++) {
sect = nsect;
nsect++;
sectno++;
#if dmacho
printf(" Section name = %s\n", sect->sectname);
printf(" Segment name = %s\n", sect->segname);
printf(" section numb = %8d\n", sectno);
printf(" addr = %08X\n", sect->addr);
printf(" size = %08X\n", sect->size);
printf(" offset = %08X (%08X)\n", sect->offset, sect->offset + fatoff);
printf(" align = %08X\n", sect->align);
printf(" relocoff = %08X\n", sect->reloff);
printf(" num reloc = %08X\n", sect->nreloc);
printf(" flags = %08X\n", sect->flags);
printf(" reserved1 = %08X\n", sect->reserved1);
printf(" reserved2 = %08X\n", sect->reserved2);
#endif
if(sect->flags & S_ATTR_PURE_INSTRUCTIONS) sctn[sectno].code = 1;
else sctn[sectno].code = 0;
sctn[sectno].start = sect->addr;
sctn[sectno].size = sect->size;
sctn[sectno].sectp = sect;
sctn[sectno].core = (char *)((unsigned int)mheader + sect->offset);
sctn[sectno].nxtassgn = sect->addr;
if(!strcmp(sect->sectname, "__text")) {
textaddr = sect->addr;
textsize = sect->size;
textsect = sectno;
#if dmacho
printf("__text section: addr = %016llX, size = %016llX, sectno = %d\n", textaddr, textsize, textsect);
#endif
}
}
break;
case LC_SYMTAB:
symtab = (struct symtab_command *)ncmd;
#if dmacho
printf("LC_SYMTAB\n");
printf(" offset = %08X\n", symtab->symoff);
printf(" number = %08X\n", symtab->nsyms);
printf(" string offset = %08X (%08X)\n", symtab->stroff, symtab->stroff + fatoff);
printf("string table size = %08X\n", symtab->strsize);
#endif
break;
case LC_SYMSEG:
#if dmacho
printf("LC_SYMSEG\n");
#endif
break;
case LC_THREAD:
#if dmacho
printf("LC_THREAD\n");
#endif
goto snarfaddr;
case LC_UNIXTHREAD:
#if dmacho
printf("LC_UNIXTHREAD\n");
#endif
snarfaddr:
regstate = (struct ppc_thread_state *)((uint32_t)ncmd + sizeof(struct load_command) + 8);
entryaddr = regstate->srr0;
#if dmacho
printf(" starting address = %08X.%08X\n", (uint32_t)(entryaddr >> 32), (uint32_t)entryaddr);
#endif
break;
case LC_LOADFVMLIB:
#if dmacho
printf("LC_LOADFVMLIB\n");
#endif
break;
case LC_IDFVMLIB:
#if dmacho
printf("LC_IDFVMLIB\n");
#endif
break;
case LC_IDENT:
#if dmacho
printf("LC_IDENT\n");
#endif
break;
case LC_FVMFILE:
#if dmacho
printf("LC_FVMFILE\n");
#endif
break;
case LC_PREPAGE:
#if dmacho
printf("LC_PREPAGE\n");
#endif
break;
case LC_DYSYMTAB:
#if dmacho
printf("LC_DYSYMTAB\n");
#endif
break;
case LC_LOAD_DYLIB:
#if dmacho
printf("LC_LOAD_DYLIB\n");
#endif
break;
case LC_ID_DYLIB:
#if dmacho
printf("LC_ID_DYLIB\n");
#endif
break;
case LC_LOAD_DYLINKER:
#if dmacho
printf("LC_LOAD_DYLINKER\n");
#endif
break;
case LC_ID_DYLINKER:
#if dmacho
printf("LC_ID_DYLINKER\n");
#endif
break;
case LC_PREBOUND_DYLIB:
#if dmacho
printf("LC_PREBOUND_DYLIB\n");
#endif
break;
case LC_ROUTINES:
#if dmacho
printf("LC_ROUTINES\n");
#endif
break;
case LC_SUB_FRAMEWORK:
#if dmacho
printf("LC_SUB_FRAMEWORK\n");
#endif
break;
case LC_SUB_UMBRELLA:
#if dmacho
printf("LC_SUB_UMBRELLA\n");
#endif
break;
case LC_SUB_CLIENT:
#if dmacho
printf("LC_SUB_CLIENT\n");
#endif
break;
case LC_SUB_LIBRARY:
#if dmacho
printf("LC_SUB_LIBRARY\n");
#endif
break;
case LC_TWOLEVEL_HINTS:
#if dmacho
printf("LC_TWOLEVEL_HINTS\n");
#endif
break;
case LC_PREBIND_CKSUM:
#if dmacho
printf("LC_PREBIND_CKSUM\n");
#endif
break;
case LC_LOAD_WEAK_DYLIB:
#if dmacho
printf("LC_LOAD_WEAK_DYLIB\n");
#endif
break;
case LC_SEGMENT_64:
#if dmacho
printf("LC_SEGMENT_64\n");
#endif
break;
case LC_ROUTINES_64:
#if dmacho
printf("LC_ROUTINES_64\n");
#endif
break;
default:
#if dmacho
printf("Unknown command: %08X\n", ncmd->cmd);
#endif
break;
}
ncmd = (struct load_command *)((unsigned int)ncmd + ncmd->cmdsize);
}
symbs = (struct nlist *)(symtab->symoff + (unsigned int)mheader);
symcount = symtab->nsyms;
strings = (char *)(symtab->stroff + (unsigned int)mheader);
strsize = symtab->strsize;
symb = symbs;
rsymc = 0;
for(i = 0; i < symcount; i++) {
if(!(symb->n_type & N_STAB)) {
rsymc++;
}
symb++;
}
symH = malloc(rsymc * sizeof(struct nlist));
if(!symH) {
printf("Can't get storage for address sorted symbol table\n");
return(1);
}
symN = malloc(rsymc * sizeof(struct nlist));
if(!symN) {
free(symH);
printf("Can't get storage for name sorted symbol table\n");
return(1);
}
symb = (struct nlist *)symH;
symbn = (struct nlist *)symN;
j = 0;
for(i = 0; i < symcount; i++) {
if(!(symbs[i].n_type & N_STAB)) {
symb[j] = symbs[i];
symbn[j] = symbs[i];
j++;
}
else {
}
}
symSortAddr = symb;
qsort((void *)symSortAddr, rsymc, sizeof(struct nlist), sortaddr);
symSortName = symbn;
qsort((void *)symSortName, rsymc, sizeof(struct nlist), sortname);
return 0;
}
#endif
void symfree(void) {
if(symH) free(symH);
symH = 0;
if(symN) free(symN);
symN = 0;
return;
}
int sortaddr(const void *a, const void *b) {
if(((struct nlist *)a)->n_value == ((struct nlist *)b)->n_value) return 0;
if((uint32_t)((struct nlist *)a)->n_value > (uint32_t)((struct nlist *)b)->n_value) return 1;
return -1;
}
int sortname(const void *a, const void *b) {
return(strcmp((char *)(&strings[((struct nlist *)a)->n_un.n_strx]),
(char *)(&strings[((struct nlist *)b)->n_un.n_strx])));
}
void *bsrch(void *key, void *base, unsigned int num, unsigned int size, int (*compare) (void *, void *)) {
unsigned int top, bot, probe;
int rslt;
bot = 0;
top = num - 1;
while(1) {
probe = (top + bot) >> 1;
rslt = compare(key, (void *)&(((char *)base)[probe * size]));
if(!rslt) return ((void *)&(((char *)base)[probe * size]));
if(rslt < 0) {
if(!probe) return (void *)0;
top = probe - 1;
}
else bot = probe + 1;
if(top <= bot) {
if(0 > compare(key, (void *)&(((char *)base)[bot * size]))) bot = bot - 1;
return ((void *)&(((char *)base)[(bot) * size]));
}
}
}
int srchaddr(void *key, void *b) {
if(*(unsigned int *)key == ((struct nlist *)b)->n_value) return 0;
if(*(unsigned int *)key > ((struct nlist *)b)->n_value) return 1;
return -1;
}
int srchname(void *key, void *a) {
return(strcmp((char *)key, (char *)(&strings[((struct nlist *)a)->n_un.n_strx])));
}
int symindex(uint32_t index, symdesc *symd) {
struct nlist *symb;
char *sy;
int eat;
symb = (struct nlist *)symH;
if(index == 0) {
symd->val = 0;
symd->index = 0;
symd->type = 0;
symd->size = 0;
symd->sect = 0;
symd->name = nullname;
return 0;
}
else if(index == -1) {
if(textsize) {
symd->val = textaddr;
symd->index = -1;
symd->type = 1;
symd->size = textsize;
symd->sect = textsect;
symd->name = "__text";
return 0;
}
else if(image) {
symd->val = 0;
symd->index = -1;
symd->type = 1;
symd->size = textsize;
symd->sect = 0;
symd->name = "CoreImage";
return 0;
}
else return 1;
}
if(index >= rsymc) return 1;
symd->val = (uint64_t)symb[index].n_value;
symd->index = index;
symd->type = sctn[symb[index].n_sect].code;
symd->sect = symb[index].n_sect;
if((index <= rsymc) && (symd->sect == symb[index + 1].n_sect)) {
symd->size = (uint64_t)symb[index + 1].n_value - symd->val;
}
else {
symd->size = sctn[symb[index].n_sect].size - (symd->val - sctn[symb[index].n_sect].start);
}
sy = &strings[symb[index].n_un.n_strx];
if(sy[0] && (sy[0] == '_')) eat = 1;
else eat = 0;
symd->name = &sy[eat];
return 0;
}
void symaddr(uint32_t addr, char *symbol) {
struct nlist *symb;
uint32_t disp;
int32_t eat;
char *sy;
if(!rsymc) {
sprintf(symbol, "%X", addr);
return;
}
symb = bsrch((void *)&addr, (void *)symH, rsymc, sizeof(struct nlist), srchaddr);
if(!(uint32_t)symb) {
sprintf(symbol, "%X", addr);
return;
}
disp = addr - symb->n_value;
sy = &strings[symb->n_un.n_strx];
if(sy[0] && (sy[0] == '_')) eat = 1;
else eat = 0;
if(!disp)sprintf(symbol, "%s", &sy[eat]);
else sprintf(symbol, "%s+%X", &sy[eat], disp);
return;
}
uint64_t symsym(char *symbol) {
struct nlist *symb;
char reqsym[256];
if(!rsymc) {
return 0xFFFFFFFFFFFFFFFFLL;
}
reqsym[0] = '_';
strncpy(&reqsym[1], symbol, 255);
symb = bsrch(&reqsym[0], (void *)symN, rsymc, sizeof(struct nlist), srchname);
if(strcmp((char *)(&strings[symb->n_un.n_strx]), &reqsym[0])) {
symb = bsrch(&reqsym[1], (void *)symN, rsymc, sizeof(struct nlist), srchname);
if(strcmp((char *)(&strings[symb->n_un.n_strx]), &reqsym[1])) {
return 0xFFFFFFFFFFFFFFFFLL;
}
}
return symb->n_value;
}
uint32_t symfetch(uint64_t addr, uint32_t bytes, uint32_t align, char *buffer) {
int i, gsect;
uint32_t rem, pad, sz, sstart, ssize;
uint64_t end;
char *curbyte, *score;
if(!align) align = 1;
if(!image) {
gsect = -1;
for(i = 1; i < (sectno + 1); i++) {
if(sctn[i].size == 0) continue;
end = (uint64_t)sctn[i].start + sctn[i].size - 1;
if((addr < ((uint64_t)sctn[i].start & -align)) || (addr > end)) {
if(((uint64_t)sctn[i].start - addr) >= align) continue;
}
gsect = i;
sstart = sctn[gsect].start;
ssize = sctn[gsect].size;
score = sctn[gsect].core;
break;
}
if(gsect < 0) return 0;
}
else {
end = textaddr + textsize - 1;
if((addr < (textaddr & -align)) || (addr > end)) {
if((textaddr - addr) >= align) return 0;
}
sstart = textaddr;
ssize = textsize;
score = sym;
}
pad = 0;
sz = bytes;
if(addr < (uint64_t)sstart) {
pad = (uint64_t)sstart - addr;
for(i = 0; i < pad; i++) buffer[i] = 0xAA;
addr += pad;
buffer += pad;
sz -= pad;
}
rem = (sstart + ssize) - addr;
if(rem < sz) sz = rem;
curbyte = (char *)(score + (addr - sstart));
bcopy(curbyte, buffer, sz);
rem = bytes - pad - sz;
if(rem >= bytes) {
printf("Blood squeezed from turnip, addr = %08X.%08X, size = %d\n", (uint32_t)(addr >> 32), (uint32_t)addr, bytes);
exit(1);
}
for(i = 0; i < rem; i++) buffer[sz + i] = 0xAA;
return 1;
}
uint64_t symstart(void) {
return entryaddr;
}
void loadsyms(char *image) {
char symfile[512];
symfile[0] = 0;
strncpy(symfile, image, 255);
strncat(symfile, ".sym", 511);
return;
}