📄 tracer.c
字号:
void *f=ts->output.handle;
Tracer_PrintfProc *tprintf = ts->output.tprintf;
Tracer_PutCProc *tputc = ts->output.putc;
int width=8;
switch(packet_type) {
case Trace_BusAccess:
tputc('B',f);
break;
case Trace_MemAccess:
default:
tputc('M',f);
}
if (acc_CYCLE(acc) == acc_Icycle)
{
/* This is used for 2 purposes:
* - SDT 7TDMI ARMulator generates these for 'internal cycles'
* Not bus idles because needed to decode merged IS cycles
* However SDT 7TDMI does not provide correct address.
* - AMBA real bus idle cycles
*/
tputc('I',f); /* has no relevant address or data */
} else {
if (acc_MREQ(acc)) {
/* These casts are needed to remove warnings under MSVC++ */
tputc((char)(acc_SEQ(acc) ? 'S' : 'N'), f);
tputc((char)(acc_READ(acc) ? 'R' : 'W'), f);
switch (acc_WIDTH(acc)) {
case BITS_8: tputc('1',f); width=2; break;
case BITS_16: tputc('2',f); width=4; break;
case BITS_32: tputc('4',f); break;
case BITS_64: tputc('8',f); break;
default: tputc('r',f); break; /* reserved */
}
tputc((char)(acc_OPC(acc) ? 'O' : '_'), f);
tputc((char)(acc_LOCK(acc) ? 'L' : '_'), f);
tputc((char)(acc_SPEC(acc) ? 'S' : '_'), f);
tputc((char)(acc_DMORE(acc) ? 'D' : '_'), f);
if (ts->prop & TRACE_ACCESSHIT)
{
if (packet_type == Trace_MemAccess)
{
uint64 data = 0;
static uint32 pID[2] = {BMPropertyID_MemAccessHit,0};
ATracer *as = &ts->Core_Tracer;
int err = as->mem_ref.master_info(
as->mem_ref.handle, ACCESS_READ_WORD, pID ,&data);
if (err== RDIError_NoError)
{
unsigned ht = (unsigned)data & MemAccessHit_TypeMASK;
tprintf(f,"(%s%c%x)",MemAccessHit_Names1[ht],
"?UIDxxxxxxxxxxxx"[(data>>4)&0xF],
(unsigned)(data>>16));
}
else
{
tprintf(f,"(" "??" ")");
}
}
#if 0
else
{
tprintf(f,"<%u>", (unsigned)packet->type);
}
#endif
}
} else { /* not mreq */
if (as->memfeatures & TRACE_MEMFEATURE_AMBA) {
tputc((char)(acc_SEQ(acc) ? 'r' /* reserved */ : 'A'), f);
tputc((char)(acc_READ(acc) ? 'R' : 'W'), f);
switch (acc_WIDTH(acc)) {
case BITS_8: tputc('1',f); width=2; break;
case BITS_16: tputc('2',f); width=4; break;
case BITS_32: tputc('4',f); break;
case BITS_64: tputc('8',f); break;
default: tputc('_',f); break; /* reserved */
}
tputc((char)(acc_OPC(acc) ? 'O' : '_'), f);
tputc((char)(acc_LOCK(acc) ? 'L' : '_'), f);
tputc((char)(acc_SPEC(acc) ? 'S' : '_'), f);
tputc((char)(acc_DMORE(acc) ? 'D' : '_'), f);
} else if (acc_SPEC(acc)) {
tputc((char)(acc_SEQ(acc) ? 'S' /* reserved */ : 'N'), f);
tputc((char)(acc_READ(acc) ? 'R' : 'W'), f);
switch (acc_WIDTH(acc)) {
case BITS_8: tputc('1',f); width=2; break;
case BITS_16: tputc('2',f); width=4; break;
case BITS_32: tputc('4',f); break;
case BITS_64: tputc('8',f); break;
default: tputc('_',f); break; /* reserved */
}
tputc((char)(acc_OPC(acc) ? 'O' : '_'), f);
tputc((char)(acc_LOCK(acc) ? 'L' : '_'), f);
tputc((char)(acc_SPEC(acc) ? 'S' : '_'), f);
tputc((char)(acc_DMORE(acc) ? 'D' : '_'), f);
} else if (acc_KILL(acc)) {
tputc((char)(acc_SEQ(acc) ? 'S' : 'N'), f);
tputc((char)(acc_READ(acc) ? 'R' : 'W'), f);
switch (acc_WIDTH(acc)) {
case BITS_8: tputc('1',f); width=2; break;
case BITS_16: tputc('2',f); width=4; break;
case BITS_32: tputc('4',f); break;
case BITS_64: tputc('8',f); break;
default: tputc('_',f); break; /* reserved */
}
tputc((char)(acc_OPC(acc) ? 'O' : '_'), f);
tputc((char)(acc_LOCK(acc) ? 'L' : '_'), f);
tputc((char)(acc_KILL(acc) ? 'K' : '_'), f);
tputc((char)(acc_DMORE(acc) ? 'D' : '_'), f);
} else {
tputc((char)(acc_SEQ(acc) ? 'C' : 'I'),f);
if (acc_OPC(acc)) tputc('O', f);
/* Trace time on Bus if we can and should. */
if ((ts->prop & TRACE_TIMESTAMP) &&
packet_type == Trace_BusAccess &&
as->p_ABus != NULL)
{
tprintf(f, " @%08x", (unsigned)as->p_ABus->bus_BusyUntil);
}
}
}
if (as->memfeatures & TRACE_MEMFEATURE_AMBA) {
switch (acc_BURST_TYPE(acc)) {
case acc_burst_none: tputc('_',f); break;
case acc_burst_4word: tputc('4',f); break;
case acc_burst_8word: tputc('8',f); break;
default: tputc('r',f); break; /* reserved */
}
}
if (acc_MREQ(acc) || acc_SPEC(acc) || (as->memfeatures & TRACE_MEMFEATURE_AMBA))
/* no valid address supplied in ARMulator idle cycles */
tprintf(f, " %08lX", addr);
}
return width;
}
static char const *eventSignalNames[] = {
"RESET","UNDEF","SWI","PABORT","DABORT","SE","IRQ","FIQ",
"BreakPt","WatchPt","Stop"
};
/* Purpose: Trigger a breakpoint when on required line. */
static void Tracer_newline(TracerState *ts)
{
void *f=ts->output.handle;
Tracer_PutCProc *tputc = ts->output.putc;
tputc('\n', f);
if (++ts->line_number == ts->break_line) {
/* Maybe RDIError_WatchpointAccessed, or RDIError_UserInterrupt? */
ARMulif_StopExecution(&ts->coredesc,RDIError_BreakpointReached);
}
}
static void tracer_javadis(uint32 instr, ARMword pc, char *buffer)
{
byte bytes[3];
bytes[0]=(byte)instr;
bytes[1]=(byte)(instr>>16);
bytes[2]=(byte)(instr>>24);
if ((instr & JAVA_EXT_MASK) > 0xFF)
{
switch (instr & JAVA_EXT_MASK)
{
case JAVA_EXT_NULL_POINTER:
sprintf(buffer,"Internal_NULL_POINTER");
break;
case JAVA_EXT_ARRAY_BOUNDS:
sprintf(buffer,"Internal_ARRAY_BOUNDS");
break;
case JAVA_EXT_JAVA_DISABLED:
sprintf(buffer,"Internal_JAVA_DISABLED");
break;
case JAVA_EXT_VFP_EXCEPTION:
sprintf(buffer,"Internal_VFP_EXCEPTION");
break;
case JAVA_EXT_PREFETCH_ABORT:
sprintf(buffer,"Internal_PREFETCH_ABORT");
break;
case JAVA_EXT_INVALID_CONFIG:
sprintf(buffer,"Internal_INVALID_CONFIG");
break;
case JAVA_EXT_NOT_FIRST_CYCLE: /* Not expected ! */
sprintf(buffer,"Internal_NOT_FIRST_CYCLE");
break;
case JAVA_EXT_ENTERRINGJAVA:
sprintf(buffer,"Internal_ENTERRINGJAVA");
break;
case JAVA_EXT_BOUNCE2SUPPORT:
sprintf(buffer,"Internal_BOUNCE2SUPPORT");
break;
default:
sprintf(buffer,"Internal_Unknown:0x%03x",
(unsigned)(instr & JAVA_EXT_MASK));
return;
}
return;
}
/* There is a problem with disassembling some opcodes which take extra
* words after them, so we special-case those here. */
switch (bytes[0])
{
case 170: sprintf(buffer,"tableswitch");
break;
case 171: sprintf(buffer,"lookupswitch");
break;
default:
(void)disass_java(bytes,pc,buffer);
}
}
static void tracer_disass(TracerState *ts, Trace_Packet *packet,
uint32 instr, ARMword pc, char *buffer)
{
switch(packet->u.instr.iset)
{
case ISET_THUMB:
{
unsigned top5 = instr>>11;
/* Complications for Thumb 2-instruction BL...
* ARM disass API (current instr, next instr) is not ideal
* for disassembling instructions as they are executed, where
* want to specify current instr & previous instr.
*/
if (instr & 0xFFFF0000) { /* Must already be a double hw instruction */
disass_16(instr >> 16, instr & 0xFFFF, pc, buffer, NULL, cb_proc);
} else if (top5==0x1E) {
strcpy(buffer, "(1st instr of BL pair)");
ts->prev_instr=instr;
} else if (top5==0x1F || top5 == 0x1D) { /* second instruction */
/* if prev_instr is invalid, disass_16 shows "???" */
disass_16(ts->prev_instr,instr,pc-2,buffer,NULL,cb_proc);
} else {
disass_16(instr,0,pc,buffer,NULL,cb_proc);
}
}
break;
case ISET_ARM:
disass(instr,pc,buffer,NULL,cb_proc);
break;
case ISET_JAVA:
tracer_javadis(instr, pc, buffer);
break;
default:
sprintf(buffer,"(UNKNOWN INSTRUCTION SET)");
break;
}
}
/* Tracing for Arch mode.*/
#define UNKNOWN_REG ((ARMword)-1)
static void TraceAccess(TracerState *ts, char id[], ARMword address,
ARMword data, ARMword reg,
Trace_Packet *packet)
{
void *f=ts->output.handle;
Tracer_PrintfProc *tprintf = ts->output.tprintf;
Tracer_PutSProc *tputs = ts->output.puts;
Tracer_PutCProc *tputc = ts->output.putc;
char localid[4];
localid[0] = id[0];
localid[1] = id[1];
localid[2] = id[2];
localid[3] = '\0';
if (localid[0] == 'I') { /* instruction */
switch (localid[1])
{
default:
case 'J': /* JAVA */
case 'A': /* ARM */
tprintf(f,"%3s %08x %08x ", localid, (unsigned)address,
(unsigned)data);
break;
case 'T': /* Thumb */
tprintf(f,"%3s %08x %04x ", localid, (unsigned)address,
(unsigned)data);
break;
}
if (ts->prop & TRACE_DISASS) {
ARMword instr = data; char buffer[256];
ARMword pc = address;
tracer_disass(ts, packet, instr, pc, buffer);
if (!(id[2]=='P')/*executed*/) {
char *p;
for (p=buffer; *p; p++)
if (isupper((int)*p)) *p=(char)tolower((int)*p);
}
tputc(' ', f);
tputs(buffer, f);
}
}
else
{ /* not Instruction */
if (reg != UNKNOWN_REG)
tprintf(f,"%3s %08x %08x %1x", localid, (unsigned)address,
(unsigned)data,(unsigned)reg);
else
tprintf(f,"%3s %08x %08x", localid, (unsigned)address,
(unsigned)data);
}
Tracer_newline(ts);
}
/* Returns RDIError_NoError => data at *data. */
static int tracer_GetCPReg(RDI_ModuleDesc *mdesc,
unsigned32 CPnum,
unsigned32 mask,
unsigned32 *data)
{
return mdesc->rdi->CPread(mdesc->handle, CPnum, mask, data);
}
/* Return True if words are not the same .*/
static bool tracer_word_diff(uint32 *old, uint32 *new, unsigned numwords)
{
while (numwords--)
{
if (*old++ != *new++)
return TRUE;
}
return FALSE;
}
/**/
static void traceRegsAsText(TracerState *ts)
{
if (ts->prop & TRACE_REGISTER) {
void *f=ts->output.handle;
Tracer_PrintfProc *tprintf = ts->output.tprintf;
/* Tracer_PutSProc *tputs = ts->output.puts; */
/* Tracer_PutCProc *tputc = ts->output.putc; */
char nextchar = '\n';
int regnum;
unsigned32 regvalue;
/* We miss out r15 because it's not useful, and is displayed
* differently between 9 and 10 */
for (regnum=0; regnum<16-1; regnum++) {
regvalue=ARMulif_GetReg(&ts->coredesc, CURRENTMODE ,regnum);
if (regvalue != ts->mainregister[regnum]) {
if (nextchar == '\n') tprintf(f,"R ");
else tprintf(f,", ");
tprintf(f, "r%d=%08lx", regnum, regvalue);
nextchar = ',';
ts->mainregister[regnum] = regvalue;
}
}
regvalue=ARMulif_GetCPSR(&ts->coredesc);
if (regvalue != ts->cpsrregister) {
if (nextchar == '\n') tprintf(f,"R ");
else tprintf(f,", ");
tprintf(f, "cpsr=%08lx", regvalue);
nextchar = ',';
ts->cpsrregister = regvalue;
}
regvalue=ARMulif_GetSPSR(&ts->coredesc,CURRENTMODE);
if (regvalue != ts->spsrregister) {
if (nextchar == '\n') tprintf(f,"R ");
else tprintf(f,", ");
tprintf(f, "spsr=%08lx", regvalue);
nextchar = ',';
ts->spsrregister = regvalue;
}
if (nextchar==',') Tracer_newline(ts);
}
if (CVector_Count(&ts->cpregs)) {
void *f=ts->output.handle;
Tracer_PrintfProc *tprintf = ts->output.tprintf;
char nextchar = '\n';
unsigned i;
/* We miss out r15 because the information is provided elsewhere,
* and is displayed
* differently between 9 and 10 */
for (i=0; i < CVector_Count(&ts->cpregs); i++) {
struct CPregTrace *cpr = CVector_At(&ts->cpregs,i);
int err = tracer_GetCPReg(&ts->coredesc, cpr->cpnum, cpr->mask,
cpr->new);/* data */
if (err == RDIError_NoError && cpr->numwords > 0 &&
tracer_word_diff(cpr->old,cpr->new,cpr->numwords))
{
if (nextchar == '\n') tprintf(f,"RCP ");
else tprintf(f,", ");
tprintf(f, "p%dc%d=0x%08lx", cpr->cpnum, cpr->reg,
cpr->new[0]);
{unsigned j;
for (j=1; j< cpr->numwords; j++)
tprintf(f, "_%08lx", cpr->new[j]);
}
nextchar = ',';
{void *temp = cpr->old;
cpr->old=cpr->new; cpr->new=temp;
}
}
}
if (nextchar==',') Tracer_newline(ts);
}
}
static void Tracer_Dispatch(ATracer *as, Trace_Packet *packet)
{
TracerState *ts = as->ts;
void *f=ts->output.handle;
if (ts->prop & TRACE_TEXT) {
Tracer_PrintfProc *tprintf = ts->output.tprintf;
Tracer_PutSProc *tputs = ts->output.puts;
Tracer_PutCProc *tputc = ts->output.putc;
if (ts->prop & TRACE_TIMESTAMP)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -