#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include "sym.h"
#include "decode.h"
#include "core.h"
#include "Scanalyzer.h"
#include "misc.h"
int forcefetch = 0;
int s64bit = 0;
char *spaces = " ";
void checkrg(regfile *rg);
uint8_t *InvokeScanalyzer(char is64Bit, char shouldDisassemble, uint64_t addr, uint64_t size, uint32_t* mem, char* library, char* function) {
symdesc xsym;
uint8_t *isnflgs;
s64bit = is64Bit;
image = 1;
dis = shouldDisassemble;
ctrace = 0;
trace = 0;
stats = 0;
level = 0;
corehd = 0;
quikcore = 0;
(void)syminitcore((uint32_t *)mem, addr, size);
int32_t ret = symindex(-1, &xsym); if(ret) { printf("File does not contain a __text section\n");
return 0;
}
isnflgs = Scanalyzer(addr, addr, size, mem, library, function);
symfree();
return isnflgs;
}
uint8_t *Scanalyzer(uint64_t entry, uint64_t addr, uint64_t bytes, uint32_t *mem, char *fname, char *function) {
istate *is;
regfile *rg;
uint8_t *isnflgs;
uint64_t funcstart;
int i, insts;
if(stats | trace) printf("\nTracing analysis of %s in %s\n\n", function, fname);
insts = (bytes + 3) / 4;
if(!insts) return (uint8_t *)0;
isnflgs = malloc(insts);
if(!isnflgs) {
printf("Can't allocate instruction flags block\n");
return 0;
}
bzero((void *)isnflgs, insts);
if(dis || trace) {
disbuf = malloc(insts * 512);
if(!disbuf) {
printf("Can't allocate dissasembly output buffer\n");
free(isnflgs);
return 0;
}
bzero((void *)disbuf, insts * 512);
}
level = 0;
is = getistate(0);
is->fstart = addr;
is->fsize = bytes;
rg = getregfile(0);
for(i = 0; i < 32; i++) rg->gprs[i] = 0xFFFFFFFFD0000000ULL | (i << 20);
rg->gprs[1] = 0xFFFFFFFFC0000000ULL;
rg->trakGpr[1] = gTstack | gTset;
rg->sprs[sPlr] = 0xFFFFFFFF80000000ULL;
is->exit = 0xFFFFFFFF80000000ULL;
rg->trakSpr[sPlr] = gTlr | gTset;
rg->sprs[sPctr] = addr;
rg->trakSpr[sPctr] = gTinfnc | gTset;
if(s64bit) {
rg->sprs[sPmsr] = 0x800000000000ULL;
rg->addrmask = 0xFFFFFFFFFFFFFFFFULL;
rg->ifaddrmask = 0xFFFFFFFFFFFFFFFCULL;
}
else {
rg->sprs[sPmsr] = 0x000000000000ULL;
rg->addrmask = 0x00000000FFFFFFFFULL;
rg->ifaddrmask = 0x00000000FFFFFFFCULL;
}
funcstart = rg->pc = entry & rg->ifaddrmask;
for(i = 0; i < 32; i++) {
rg->vprs[i].vw[0] = 0x7FFFDEAD;
rg->vprs[i].vw[1] = 0x7FFFDEAD;
rg->vprs[i].vw[2] = 0x7FFFDEAD;
rg->vprs[i].vw[3] = 0x7FFFDEAD;
rg->trakVpr[i] = gTset;
}
rg->sprs[sPvscr] = 0;
rg->sprs[sPvscr + 1] = 0x0000000000010000ULL;
rg->trakSpr[sPvscr] = gTset;
for(i = 0; i < 32; i += 2) {
rg->fprs[i] = 0xC24BC19587859393ULL;
rg->fprs[i + 1] = 0xE681A2C88599855AULL;
rg->trakFpr[i] = gTset;
rg->trakFpr[i + 1] = gTset;
}
scancode(is, rg, isnflgs);
if(forcefetch) {
for(i = 0; i < insts; i++) {
if(isnflgs[i]) continue;
rg->pc = (addr + (i * 4)) & rg->ifaddrmask;
scancode(is, rg, isnflgs);
}
}
if(dis) disassemble(addr, mem, isnflgs, insts, fname, function);
gendtrace(addr, funcstart, mem, isnflgs, insts, fname, function);
tossistate(is);
tossregfile(rg);
freecore();
if(disbuf) free(disbuf);
disbuf = (disb *)0;
if(stats | trace) {
printf("\n");
printf("istatemalloc = %10d, istatefree = %10d\n", istatemalloc, istatefree);
printf("regmalloc = %10d, regfree = %10d\n", regmalloc, regfree);
printf("coremalloc = %10d, corefree = %10d\n", coremalloc, corefree);
}
return isnflgs;
}
void scancode(istate *is, regfile *rg, uint8_t *isnflgs) {
istate *ist;
regfile *rgt;
uint32_t offs, xoffs;
char xfunc[512];
char extra[512];
char dumpdata[512];
char traktrak[512];
uint64_t instruction, signmask, btstart, bttarg, memaddr, btentry;
uint8_t trak, *srcaddr;
int i, msz, wsz, treg, isnkind;
while(1) {
checkrg(rg);
btstart = 0;
if(rg->pc & 3) {
printf("***** Unaligned PC address: %08X.%08X\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc);
exit(1);
}
offs = rg->pc - is->fstart;
if(offs >= is->fsize) {
if(trace) printf(" (Instruction address (%08X.%08X) outside of function, exiting)\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc);
return;
}
offs = offs / 4;
if(isnflgs[offs] & ~isnBTarg) {
if(trace) printf(" (Instruction at %08X.%08X previously seen, exiting)\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc);
return;
}
readcore(rg, rg->pc, 4, rg->ifaddrmask, 0, &instruction, &trak);
is->instimg = (uint32_t)instruction;
is->pc = rg->pc;
decode((uint32_t)instruction, rg->pc, is, rg);
isnkind = is->opr;
if(is->mods & modRsvn) isnkind = isRsvn;
isnflgs[offs] = (isnflgs[offs] & isnBTarg) | isnkind;
if(is->opr == isInvalid) {
if(disbuf) sprintf((char *)&disbuf[offs].out[0], "%08X .long 0x%08X * %c%c%c%c *", (uint32_t)instruction, (uint32_t)instruction,
xtran[(uint8_t)(instruction >> 24)], xtran[(uint8_t)(instruction >> 16)],
xtran[(uint8_t)(instruction >> 8)], xtran[(uint8_t)instruction]);
if(trace) printf("%08X.%08X %02X %s\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, isnflgs[offs], &disbuf[offs].out[0]);
rg->pc = rg->pc + 4;
rg->pc &= rg->ifaddrmask;
continue;
}
if(is->mods & modPrv) isnflgs[offs] |= isnPriv;
extra[0] = 0;
traktrak[0] = 0;
dumpdata[0] = 0;
switch(is->opr) {
case isScalar:
is->trakResult &= ~gTinfnc;
if((is->targtype == rfGpr) &&
!(is->trakResult & gTundef) &&
((is->result - is->fstart) < is->fsize)) {
is->trakResult |= gTinfnc;
if((is->result & 3) == 0) {
if(trace) printf(" (Potential branch table at %08X.%08X)\n", (uint32_t)(is->result >> 32), (uint32_t)is->result);
readcore(rg, is->result, 4, rg->ifaddrmask, 0, &btentry, &trak);
if(btentry & 0x0000000080000000ULL) btentry |= 0xFFFFFFFF00000000ULL;
bttarg = btentry + is->result;
if(trace) printf(" (Fetched entry %08llX relocates to %08X.%08X)\n", btentry, (uint32_t)(bttarg >> 32), (uint32_t)bttarg);
if(((bttarg - is->fstart) < is->fsize) && (is->result != 0)) {
is->trakResult |= gTbrtbl;
if(trace) printf(" (Branch table found at %08X.%08X)\n", (uint32_t)(is->result >> 32), (uint32_t)is->result);
}
else {
if(trace) printf(" (Branch table not found at %08X.%08X)\n", (uint32_t)(is->result >> 32), (uint32_t)is->result);
}
}
}
if(disbuf) {
sprintf(traktrak, "%02X %02X %02X %02X %02X %02X = %02X", is->trakExplicit, is->trakTarget, is->trakSourcea, is->trakSourceb,
is->trakSourcec, is->trakSourced, is->trakResult);
if(!(is->trakResult & gTundef)) sprintf(extra, "(%08X.%08X)", (uint32_t)(is->result >> 32), (uint32_t)is->result);
sprintf((char *)&disbuf[offs].out[0], "%08X %-12s%-20s %s %s", (uint32_t)instruction, is->op, is->oper, traktrak, extra);
if(trace) printf("%08X.%08X %02X %s\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, isnflgs[offs], (char *)&disbuf[offs].out[0]);
}
complete(is, rg);
rg->pc += 4;
rg->pc &= rg->ifaddrmask;
if((rg->pc - is->fstart) >= is->fsize) isnflgs[offs] |= isnExit;
break;
case isBrCond:
case isBranch:
is->btarg &= rg->ifaddrmask;
is->trakBtarg &= ~gTinfnc;
if(!(is->trakBtarg & gTundef) &&
((is->btarg - is->fstart) < is->fsize)) is->trakBtarg |= gTinfnc;
if(disbuf) sprintf(traktrak, "%02X %02X %02X %02X %02X %02X = %02X", is->trakExplicit, is->trakTarget, is->trakSourcea, is->trakSourceb,
is->trakSourcec, is->trakSourced, is->trakBtarg);
if(is->mods & modSetLR) {
if((is->trakBtarg & gTundef) || (is->btarg != ((rg->pc + 4) & rg->ifaddrmask))) {
isnflgs[offs] |= isnCall;
}
}
if(is->trakBtarg & gTundef) isnflgs[offs] |= isnExit;
else {
if(!(is->trakBtarg & gTinfnc)) {
if(!(is->mods & modSetLR)) isnflgs[offs] |= isnExit;
if(disbuf) {
symaddr(is->btarg, xfunc);
sprintf(extra, "(%08X.%08X) ---> %s", (uint32_t)(is->btarg >> 32), (uint32_t)is->btarg, xfunc);
}
}
else {
isnflgs[(is->btarg - is->fstart) / 4] |= isnBTarg;
if(disbuf) sprintf(extra, "(%08X.%08X)", (uint32_t)(is->btarg >> 32), (uint32_t)is->btarg);
}
}
if(disbuf) {
sprintf((char *)&disbuf[offs].out[0], "%08X %-12s%-20s %s %s", (uint32_t)instruction, is->op, is->oper, traktrak, extra);
if(trace) printf("%08X.%08X %02X %s\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, isnflgs[offs], (char *)&disbuf[offs].out[0]);
}
if(is->mods & modSetLR) {
rg->sprs[sPlr] = rg->pc + 4;
rg->sprs[sPlr] &= rg->ifaddrmask;
rg->trakSpr[sPlr] = gTlr | gTgen | gTset;
rg->trakSpr[sPlr] &= ~gTinfnc;
if((rg->sprs[sPlr] - is->fstart) < is->fsize) rg->trakSpr[sPlr] |= gTinfnc;
if(trace) printf(" (LR set to %08X.%08X)\n", (uint32_t)((rg->pc + 4) >> 32), (uint32_t)(rg->pc + 4));
}
if(is->opr == isBrCond) {
level++;
if(trace) printf(" (Taken conditional branch from %08X.%08X to %08X.%08X, lvl=%d)\n",
(uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, (uint32_t)(is->btarg >> 32), (uint32_t)is->btarg, level);
ist = getistate(is);
rgt = getregfile(rg);
rgt->pc = is->btarg;
scancode(ist, rgt, isnflgs);
tossistate(ist);
tossregfile(rgt);
level--;
if(trace) printf(" (Not taken conditional branch from %08X.%08X, lvl=%d)\n",
(uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, level);
rg->pc = rg->pc + 4;
rg->pc &= rg->ifaddrmask;
if((rg->pc - is->fstart) >=is->fsize) isnflgs[offs] |= isnExit;
}
else {
if(isnflgs[offs] & isnCall) {
if(is->trakBtarg & gTinfnc) {
level++;
if(trace) printf(" (Call from %08X.%08X to %08X.%08X - internal function, lvl=%d)\n",
(uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, (uint32_t)(is->btarg >> 32), (uint32_t)is->btarg, level);
ist = getistate(is);
ist->clevel++;
ist->freturn = rg->pc + 4;
rg->pc = is->btarg;
scancode(ist, rg, isnflgs);
level--;
if(trace) printf(" (Return from %08X.%08X to %08X.%08X - internal function, lvl=%d)\n",
(uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, (uint32_t)(ist->freturn >> 32), (uint32_t)ist->freturn, level);
rg->pc = ist->freturn;
tossistate(ist);
}
else {
rg->pc = rg->pc + 4;
rg->pc &= rg->ifaddrmask;
}
if((rg->pc - is->fstart) >= is->fsize) isnflgs[offs] |= isnExit;
}
else {
if(isnflgs[offs] & isnExit) {
if(trace) {
if(is->trakBtarg & gTundef) printf(" (Uncond branch from %08X.%08X to %08X.%08X - unknown address, exiting)...\n",
(uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, (uint32_t)(is->btarg >> 32), (uint32_t)is->btarg);
else printf(" (Uncond branch from %08X.%08X to %08X.%08X - out of function, exiting...)\n",
(uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, (uint32_t)(is->btarg >> 32), (uint32_t)is->btarg);
}
return;
}
else {
if(is->mods & (modLR | modCTR)) {
if(is->clevel && (is->freturn == is->btarg)) {
return;
}
}
rg->pc = is->btarg;
if(trace) printf(" (Unconditional branch to %08X.%08X)\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc);
}
}
}
break;
case isWrite:
dumpdata[0] = 0;
if(disbuf) sprintf(traktrak, "%02X %02X %02X %02X %02X %02X = %02X", is->trakExplicit, is->trakTarget, is->trakSourcea,
is->trakSourceb, is->trakSourcec, is->trakSourced, is->trakBtarg);
if(!(is->mods & modUnimpl) && is->trakBtarg && !(is->trakBtarg & gTundef)) {
treg = is->target;
memaddr = is->btarg;
msz = is->memsize;
if(is->mods & modM4) wsz = 4;
else if(is->mods & modM8) wsz = 8;
else wsz = is->memsize;
if(disbuf) sprintf(extra, "(%08X.%08X) -", (uint32_t)((memaddr & rg->addrmask) >> 32), (uint32_t)(memaddr & rg->addrmask));
while(msz) {
if(wsz > msz) wsz = msz;
srcaddr = (uint8_t *)&rg->rgx[is->targtype - 1][treg];
srcaddr = srcaddr + (8 - wsz);
trak = rg->trx[is->targtype - 1][treg];
trak |= gTset;
writecore(rg, memaddr, wsz, rg->addrmask, 0, srcaddr, trak);
if(disbuf) {
sprintf(dumpdata, "%s %02X/", dumpdata, trak);
for(i = 0; i < wsz; i++) sprintf(dumpdata, "%s%02X", dumpdata, srcaddr[i]);
}
memaddr += wsz;
msz = msz - wsz;
treg++;
}
}
if(disbuf) {
sprintf((char *)&disbuf[offs].out[0], "%08X %-12s%-20s %s %s%s", (uint32_t)instruction, is->op, is->oper, traktrak, extra, dumpdata);
if(trace) printf("%08X.%08X %02X %s\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, isnflgs[offs], (char *)&disbuf[offs].out[0]);
}
if(is->mods & modUpd) {
rg->gprs[is->sourcea] = is->btarg;
rg->trakGpr[is->sourcea] = is->trakBtarg | gTset;
if(trace) printf(" (R%d set to %08X.%08X, trak = %02X)\n", is->sourcea, (uint32_t)(is->btarg >> 32), (uint32_t)is->btarg, is->trakBtarg);
}
rg->pc += 4;
rg->pc &= rg->ifaddrmask;
if((rg->pc - is->fstart) >= is->fsize) isnflgs[offs] |= isnExit;
break;
case isRead:
if(disbuf) sprintf(traktrak, "%02X %02X %02X %02X %02X %02X = %02X", is->trakExplicit, is->trakTarget, is->trakSourcea,
is->trakSourceb, is->trakSourcec, is->trakSourced, is->trakBtarg);
if(!(is->mods & modUnimpl) && (is->targtype != rfNone) && !(is->trakBtarg & gTundef)) {
treg = is->target;
memaddr = is->btarg;
msz = is->memsize;
if(is->mods & modM4) wsz = 4;
else if(is->mods & modM8) wsz = 8;
else wsz = is->memsize;
if(disbuf) sprintf(extra, "(%08X.%08X) -", (uint32_t)((memaddr & rg->addrmask) >> 32), (uint32_t)(memaddr & rg->addrmask));
while(msz) {
if(wsz > msz) wsz = msz;
srcaddr = (uint8_t *)&rg->rgx[is->targtype - 1][treg];
srcaddr = srcaddr + (8 - wsz);
readcore(rg, memaddr, wsz, rg->addrmask, 0, &is->result, &is->trakResult);
if(is->mods & modSxtnd) {
signmask = 0xFFFFFFFFFFFFFFFFULL << ((is->memsize * 8) - 1);
if(is->result & signmask) is->result |= signmask;
}
rg->rgx[is->targtype - 1][treg] = is->result;
if((is->targtype == rfGpr) && ((is->result - is->fstart) < is->fsize)) is->trakResult |= gTinfnc;
trak = rg->trx[is->targtype - 1][treg] = is->trakResult;
if(disbuf) {
sprintf(dumpdata, "%s %02X/", dumpdata, trak);
for(i = 0; i < wsz; i++) sprintf(dumpdata, "%s%02X", dumpdata, srcaddr[i]);
}
memaddr += wsz;
msz = msz - wsz;
treg++;
}
}
if(disbuf) {
sprintf((char *)&disbuf[offs].out[0], "%08X %-12s%-20s %s %s%s", (uint32_t)instruction, is->op, is->oper, traktrak, extra, dumpdata);
if(trace) printf("%08X.%08X %02X %s\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, isnflgs[offs], (char *)&disbuf[offs].out[0]);
}
if(is->mods & modUpd) {
rg->gprs[is->sourcea] = is->btarg;
rg->trakGpr[is->sourcea] = is->trakBtarg | gTset;
if(trace) printf(" (R%d set to %08X.%08X, trak = %02X)\n", is->sourcea, (uint32_t)(is->btarg >> 32), (uint32_t)is->btarg, is->trakBtarg);
}
rg->pc += 4;
rg->pc &= rg->ifaddrmask;
if((rg->pc - is->fstart) >= is->fsize) isnflgs[offs] |= isnExit;
if((is->mods & modUnimpl) || (is->targtype != rfGpr)) break;
if(!(is->trakBtarg & gTbrtbl)) break;
btstart = is->btarg;
while(!((is->trakBtarg | is->trakResult) & gTundef)) {
xoffs = ((btstart + is->result) - is->fstart);
if(!is->result) break;
if((is->result & 3) != 0) break;
if(xoffs >= is->fsize) break;
isnflgs[(is->btarg - is->fstart) / 4] = isBranchTbl;
level++;
if(trace) printf(" (Branch table entry at %08X.%08X [%08X.%08X], branch to %08X.%08X, lvl=%d)\n",
(uint32_t)(is->btarg >> 32), (uint32_t)is->btarg,
(uint32_t)(is->result >> 32), (uint32_t)is->result,
(uint32_t)((btstart + is->result) >> 32), (uint32_t)(btstart + is->result),
level);
ist = getistate(is);
rgt = getregfile(rg);
rgt->pc = (btstart + is->result) & rg->ifaddrmask;
isnflgs[(rgt->pc - is->fstart) / 4] |= isnBTarg;
if(disbuf) {
sprintf(extra, "0x%08X", (uint32_t)is->result);
sprintf(dumpdata, "---> %08X.%08X", (uint32_t)(rgt->pc >> 32), (uint32_t)rgt->pc);
sprintf((char *)&disbuf[(is->btarg - is->fstart) / 4].out[0],
"%08X %-12s%-20s %s", (uint32_t)is->result, ".long", extra, dumpdata);
}
scancode(ist, rgt, isnflgs);
tossistate(ist);
tossregfile(rgt);
level--;
if(trace) printf(" (Return from branch table entry at %08X.%08X, lvl=%d\n",
(uint32_t)(is->btarg >> 32), (uint32_t)is->btarg, level);
is->btarg = is->btarg + 4;
if((is->btarg - is->fstart) >= is->fsize) break;
readcore(rg, is->btarg, 4, rg->ifaddrmask, 0, &is->result, &is->trakResult);
}
btstart = 0;
break;
default:
if(disbuf) {
sprintf((char *)&disbuf[offs].out[0], "%08X %-12s%-20s", (uint32_t)instruction, is->op, is->oper);
if(trace) printf("%08X.%08X %02X %s\n", (uint32_t)(rg->pc >> 32), (uint32_t)rg->pc, isnflgs[offs], (char *)&disbuf[offs].out[0]);
}
complete(is, rg);
rg->pc += 4;
rg->pc &= rg->ifaddrmask;
if((rg->pc - is->fstart) >= is->fsize) isnflgs[offs] |= isnExit;
break;
}
}
printf("\n");
return;
}
void complete(istate *is, regfile *rg) {
if(is->targtype == rfNone) return;
if(is->target == -1) return;
if(is->targtype > rfSpr) diedie("bad targtype");
if(is->target > 32) diedie("bad target");
if(is->targtype != rfVpr) {
((uint64_t *)(rg->rgx[is->targtype - 1]))[is->target] = is->result;
((uint8_t *)(rg->trx[is->targtype - 1]))[is->target] = is->trakResult;
}
else {
rg->vprs[is->target].vw[0] = ((vrs *)&is->result)->vw[0];
rg->vprs[is->target].vw[1] = ((vrs *)&is->result)->vw[1];
rg->vprs[is->target].vw[2] = ((vrs *)&is->result)->vw[2];
rg->vprs[is->target].vw[3] = ((vrs *)&is->result)->vw[3];
rg->trakVpr[is->target] = is->trakResult;
}
checkrg(rg);
}
void checkrg(regfile *rg) {
corebk *xcore;
int i;
while(rg) {
if(rg->rgx[rfGpr - 1] != &rg->gprs[0]) diedie("trashed gpr xlate");
if(rg->rgx[rfFpr - 1] != &rg->fprs[0]) diedie("trashed fpr xlate");
if(rg->rgx[rfVpr - 1] != (uint64_t *)&rg->vprs[0]) diedie("trashed vpr xlate");
if(rg->rgx[rfSpr - 1] != &rg->sprs[0]) diedie("trashed spr xlate");
if(rg->trx[rfGpr - 1] != &rg->trakGpr[0]) diedie("trashed gpr tracking xlate");
if(rg->trx[rfFpr - 1] != &rg->trakFpr[0]) diedie("trashed fpr tracking xlate");
if(rg->trx[rfVpr - 1] != &rg->trakVpr[0]) diedie("trashed vpr tracking xlate");
if(rg->trx[rfSpr - 1] != &rg->trakSpr[0]) diedie("trashed spr tracking xlate");
rg = rg->rgBack;
}
xcore = corehd;
while(xcore) {
for(i = 0; i < sizeof(corebk); i++) {
if((i >= 8) && (i < 12)) continue;
if(((char *)xcore)[i] != 0x55) {
diedie("free core overlay");
break;
}
}
xcore = xcore->core;
}
}