📄 tracer.c
字号:
option=ToolConf_Lookup(ts->config, ARMulCnf_Pipe);
if (option) {
ts->prop|=TRACE_PIPE;
ts->output.handle=(void *)popen(option,"w");
if (ts->output.handle == NULL) {
Hostif_ConsolePrint(ts->hostif,
"Could not open pipe to '%s' - abandoning trace.\n",
option);
return 0;
}
ts->output.write = (Tracer_WriteProc *)fwrite;
ts->output.close = (Tracer_CloseProc *)pclose;
ts->output.flush = (Tracer_FlushProc *)fflush;
return 1;
}
#endif
fprintf(stderr,"No trace file configured - abandoning trace.\n");
return 1;
}
static void Tracer_Close(TracerState *ts)
{
if (ts->output.close)
ts->output.close(ts->output.handle);
}
static void Tracer_Flush(TracerState *ts)
{
if (ts->output.flush)
ts->output.flush(ts->output.handle);
}
static GenericCallbackFunc Tracer_NumberedEventHandler;
static unsigned Tracer_NumberedEventHandler(void *handle, void *data)
{
ARMul_Event *evt = (ARMul_Event *)data;
TracerState *ts=(TracerState *)handle;
unsigned int event = evt->event;
/* ARMword addr1 = evt->data1; ARMword addr2 = evt->data2; */
/* look at my set of handled events */
TSEventNumberRecord *thing =
(TSEventNumberRecord*)hash_Get(ts->ts_EventNumHash,event);
#if 0
Hostif_ConsolePrint(ts->hostif, /*ts->config,*/
"\nTracer_NumberedEventHandler event 0x%08x %p %s\n",
(unsigned)event, thing,
(thing != NULL) ? thing->name : "?");
#endif
if (thing != NULL)
{
/* Trace thing.name, evt->data1, evt->data2 */
void *f=ts->output.handle;
Tracer_PrintfProc *tprintf = ts->output.tprintf;
#ifdef OldCode
tprintf(f,"E %s 0x%08x 0x%08x", thing->name,
(unsigned)evt->data1, (unsigned)evt->data2);
#else /* Make it look more like the old events */
tprintf(f,"E %08lX %08lX %x %s",
(unsigned)evt->data1, (unsigned)evt->data2,
(unsigned)evt->event, thing->name);
#endif
Tracer_newline(ts);
if (ts->prop & TRACE_UNBUFF)
Tracer_Flush(ts);
/* !Todo: Remember this event so we don't
* bother with the old event-format if we get the same event there.
* (or some other duplication-avoidance-strategy)
*/
}
return FALSE;
}
/*
* The function is called from the ARMulator when rdi_log & 16 is true.
* It is used to generate an executed instruction stream trace.
*/
static GenericCallbackFunc Tracer_EventHandler;
static unsigned Tracer_EventHandler(void *handle, void *data)
{
ARMul_Event *evt = (ARMul_Event *)data;
TracerState *ts=(TracerState *)handle;
Trace_Packet packet;
unsigned int event = evt->event;
ARMword addr1 = evt->data1; ARMword addr2 = evt->data2;
/* Mask events */
if ((event & ts->event_mask)!=ts->event_set)
return FALSE;
if ((ts->prop & TRACE_RANGE) && (addr1<ts->range_lo ||
(addr1>=ts->range_hi && ts->range_hi!=0)))
/* range test fails */
return FALSE;
if (ts->sample_base) {
if (ts->sample--) /* not this one */
return FALSE;
ts->sample=ts->sample_base-1;
}
packet.type=Trace_Event;
packet.u.event.addr=addr1;
packet.u.event.addr2=addr2;
packet.u.event.type=event;
Tracer_Dispatch(&ts->Core_Tracer,&packet);
if (ts->prop & TRACE_UNBUFF)
Tracer_Flush(ts);
return FALSE;
}
/*
* this function is called for every instruction.
* Preconds:
* . ts->Core_Tracer initialised.
*/
static void trace_func(void *handle, ARMword pc, ARMword instr,
ARMword cpsr, ARMword condpassed)
{
TracerState *ts=(TracerState *)handle;
Trace_Packet packet;
#if 0
ts->output.tprintf(ts->output.handle,
"trace_func pc:%08x i:%08x cpsr:%08x it:%u\n",
(unsigned)pc,(unsigned)instr,(unsigned)cpsr,(unsigned)condpassed);
#endif
if ((ts->prop & TRACE_RANGE) && (pc<ts->range_lo ||
(pc>=ts->range_hi && ts->range_hi!=0)))
/* range test fails */
{
#if 0
ts->output.tprintf(ts->output.handle,
"trace_func range test fails.\n");
#endif
return;
}
packet.u.instr.iset = ((cpsr >> (24-1)) & 2) /* J BIT -> bit 1 */
| ((cpsr >> 5) & 1); /* T BIT -> bit 0 */
if (packet.u.instr.iset == ISET_JAVA)
{
/* Don't trace cycles which are not the first for each java-opcode,
* or other things which are not real java opcodes
* (e.g. prefetch abort) -
* the disassembler will not understand. */
if (ts->prop & TRACE_JAZELLEFAKEOPCODES)
{
/* This is only for debugging the core model. */
if ((instr & JAVA_EXT_MASK) == JAVA_EXT_NOT_FIRST_CYCLE)
{
return;
}
}
else
{
/* This is more generally useful. */
if ((instr & JAVA_EXT_MASK) > 255)
return;
}
/* condpassed is not useful for Java bytecodes. */
packet.u.instr.executed = TRUE;
}
else
{
packet.u.instr.executed = (unsigned char)(condpassed & 1);
}
if (ts->sample_base) {
if (ts->sample--) /* not this one */
return;
ts->sample=ts->sample_base-1;
}
packet.type=Trace_Instr;
packet.u.instr.pc=pc;
packet.u.instr.instr=instr;
Tracer_Dispatch(&ts->Core_Tracer,&packet);
if (ts->prop & TRACE_UNBUFF)
Tracer_Flush(ts);
}
static int TraceX(ATracer *as, ARMword addr, uint32 *data, int rv,
unsigned acc,
int packet_type)
{
TracerState *ts = as->ts;
Trace_Packet packet;
if ((ts->prop & TRACE_RANGE) && (addr<ts->range_lo ||
(addr>=ts->range_hi && ts->range_hi!=0)))
{
/* range test fails */
#ifdef VERBOSE_BUS
printf("!Tracer_MemAccess - out of range!\n");
#endif
return rv;
}
if (ts->sample_base) {
if (ts->sample--) /* not this one */
{
return rv;
}
ts->sample=ts->sample_base-1;
}
if (/* (ts->prop & TRACE_MEM) && */
((ts->prop & TRACE_WAITS) || (rv != 0)) &&
((ts->prop & TRACE_NONACC) || acc_ACCOUNT(acc)) &&
((ts->prop & TRACE_IDLE) || !ACCESS_IS_IDLE(acc)) &&
/* We always care about prefetch-aborts! */
((ts->prop & TRACE_OPCODEFETCH) || !acc_OPC(acc) || rv < 0)
)
{
packet.type=packet_type; /* E.g. Trace_MemAccess */
packet.u.mem_access.acc=acc;
packet.u.mem_access.addr=addr;
packet.u.mem_access.predict=as->current;
/* packet.u.mem_access.word1=(acc_MREQ(acc) ? *word : 0); -- original */
packet.u.mem_access.word1=(data != NULL) ? *data : 0;
if (acc_WIDTH(acc) == BITS_64)
packet.u.mem_access.word2=(data != NULL) ? data[1] : 0;
packet.u.mem_access.rv=rv;
Tracer_Dispatch(as,&packet);
if (ts->prop & TRACE_UNBUFF)
Tracer_Flush(ts);
/* Use ts->advance to store predicted cycle information, then
* delay into ts->current to check prediction against actual. */
if (acc_ACCOUNT(acc) && rv != 0) {
as->current=as->advance;
}
}
#ifdef VERBOSE_NOSEND
else
{
printf("!Tracer_MemAccess - not sending packet!\n");
}
#endif
return rv;
}
/* Function called when RDI_LOG changes, so we can control logging
* memory accesses */
/* <<<< Pass-thru functions */
static void TraceNextCycle(void *handle,ARMword addr,ARMul_acc acc)
{
ATracer *as = (ATracer *)handle;
/* TracerState *ts = as->ts; */
as->child.x.pipe.next(as->child.handle,addr,acc);
/* NextCycle info before non-accounted accesses should
* - ideally not happen
* - be marked as non-accounted if it does happen
* This enables the NextCycle info from the previous child
* access to relate to the next child access regardless of
* intervening non-accounted accesses.
*/
if (acc_ACCOUNT(acc)) {
/* store next cycle information */
as->advance.addr = addr;
as->advance.acc = acc;
}
}
static void TraceNextDCycle(void *handle,ARMword addr, ARMword data, ARMul_acc acc)
{
ATracer *as = (ATracer *)handle;
/* TracerState *ts = (TracerState *)handle;*/
as->child.x.pipe_arm9.dside_next(as->child.handle,addr,data,acc);
/* NextCycle info before non-accounted accesses should
* - ideally not happen
* - be marked as non-accounted if it does happen
* This enables the NextCycle info from the previous real
* access to relate to the next real access regardless of
* intervening non-accounted accesses.
*/
if (acc_ACCOUNT(acc)) {
/* store next cycle information */
as->dside_advance.addr=addr;
as->dside_advance.acc=acc;
}
}
static void TraceNextICycle(void *handle,ARMword addr,ARMul_acc acc)
{
ATracer *as = (ATracer *)handle;
as->child.x.pipe_arm9.iside_next(as->child.handle,addr,acc);
/* NextCycle info before non-accounted accesses should
* - ideally not happen
* - be marked as non-accounted if it does happen
* This enables the NextCycle info from the previous child
* access to relate to the next child access regardless of
* intervening non-accounted accesses.
*/
if (acc_ACCOUNT(acc)) {
/* store next cycle information */
as->iside_advance.addr = addr;
as->iside_advance.acc = acc;
}
}
/* Pipelined Multi-Layer AHB memory interface functions */
static unsigned int TraceMultiLayerRegister(void *handle, tag_t hint)
{
/* AHB Layer registration */
ATracer *as = (ATracer *)handle;
return as->child.x.pipe_multi_layer.register_layer(as->child.handle, hint);
}
static unsigned long TraceMultiLayerDeltaCycles(void *handle, unsigned int layer_id)
{
ATracer *as = (ATracer *)handle;
return (as->child.x.pipe_multi_layer.delta_cycles(as->child.handle, layer_id));
}
static void TraceBusMultiLayerNext(void *handle, unsigned int layer_id, ARMword address, ARMword *data, ARMul_acc acc)
{
ATracer *as = (ATracer *)handle;
as->child.x.pipe_multi_layer.next_access(as->child.handle, layer_id, address, data, acc);
/* NextCycle info before non-accounted accesses should
* - ideally not happen
* - be marked as non-accounted if it does happen
* This enables the NextCycle info from the previous child
* access to relate to the next child access regardless of
* intervening non-accounted accesses.
*/
if (acc_ACCOUNT(acc)) {
/* store next cycle information */
as->advance.addr = address;
as->advance.acc = acc;
}
}
static int TraceBusMultiLayerCurrent(void *handle, unsigned int layer_id, ARMword address,
ARMword *data, ARMul_acc acc)
{
ATracer *as = (ATracer *)handle;
int err = as->child.x.pipe_multi_layer.current_access(as->child.handle, layer_id, address, data, acc);
TraceX(as, address, data, err, acc, as->as_TraceType);
return err;
}
static unsigned long TraceDeltaCycles(void *handle)
{
ATracer *as = (ATracer *)handle;
return (as->child.x.pipe.delta_cycles(as->child.handle));
}
static void TraceCoreException(void *handle,ARMword address,
ARMword penc)
{
ATracer *as = (ATracer *)handle;
as->child.x.arm8.core_exception(as->child.handle,address,penc);
}
static unsigned int TraceDataCacheBusy(void *handle)
{
ATracer *as = (ATracer *)handle;
return as->child.x.strongarm.data_cache_busy(as->child.handle);
}
static void TraceBusMemAccessHarvard(void *handle,
ARMword daddr,ARMword *dword, ARMul_acc dacc, int *drv,
ARMword iaddr,ARMword *iword, ARMul_acc iacc, int *irv)
{
ATracer *as=(ATracer *)handle;
TracerState *ts = as->ts;
as->child.x.pipe_arm9.harvard_access(as->child.handle,
daddr, dword, dacc, drv,
iaddr, iword, iacc, irv);
if ((ts->prop & TRACE_WAITS) || (*irv && *drv)) { /* ARM9 waits for this! */
as->current = as->dside_current;
/* The checks for *drv may not have the desired effect? */
if (*drv) { /* Don't bother with all those waits! */
TraceX(as, daddr, dword, *drv, dacc, as->as_TraceType);
}
as->current = as->iside_current;
if (*irv) { /* Don't trace all those waits! */
TraceX(as, iaddr, iword, *irv, iacc, as->as_TraceType);
}
}
if (!(ts->prop & TRACE_RANGE) || ((daddr>=ts->range_lo) && (daddr>=ts->range_hi))) {
if (acc_ACCOUNT(dacc) && (*drv != 0)) {
as->dside_current=as->dside_advance; /* delay next cycle information by 1 cycle */
}
}
if (!(ts->prop & TRACE_RANGE) || ((iaddr>=ts->range_lo) && (iaddr>=ts->range_hi))) {
if (acc_ACCOUNT(i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -