Parser
QNX SDP8.0System Analysis Toolkit (SAT) User's GuideUser
This program reads the events file or output generated by the data-capture program and does some simple parsing of just the expected events in that data set.
#include <sys/trace.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
// The events for the _NTO_TRACE_THREAD classes (for the most part)
// correspond to the thread states defined in <sys/states.h>:
// STATE_DEAD, /* 0 0x00 */
// STATE_RUNNING, /* 1 0x01 */
// STATE_READY, /* 2 0x02 */
// STATE_STOPPED, /* 3 0x03 */
//
// STATE_SEND, /* 4 0x04 */
// STATE_RECEIVE, /* 5 0x05 */
// STATE_REPLY, /* 6 0x06 */
//
// STATE_STACK, /* 7 0x07 */
// STATE_WAITTHREAD, /* 8 0x08 */
// STATE_WAITPAGE, /* 9 0x09 */
//
// STATE_SIGSUSPEND, /* 10 0x0a */
// STATE_SIGWAITINFO, /* 11 0x0b */
// STATE_NANOSLEEP, /* 12 0x0c */
// STATE_MUTEX, /* 13 0x0d */
// STATE_CONDVAR, /* 14 0x0e */
// STATE_JOIN, /* 15 0x0f */
// STATE_INTR, /* 16 0x10 */
// STATE_SEM, /* 17 0x11 */
// STATE_WAITCTX, /* 18 0x12 */
//
// STATE_MAX = 24
//
// There are two additional events:
// enum _TRACE_THREAD_STATE {
// _TRACE_THREAD_CREATE = STATE_MAX,
// _TRACE_THREAD_DESTROY,
// _TRACE_MAX_TH_STATE_NUM
// };
char *thread_events[26] =
{
"DEAD", // 0
"RUNNING",
"READY",
"STOPPED",
"SEND" ,
"RECEIVE", // 5
"REPLY",
"STACK",
"WAITTHREAD",
"WAITPAGE",
"SIGSUSPEND", //10
"SIGWAITINFO",
"NANOSLEEP",
"MUTEX",
"CONDVAR",
"JOIN", // 15
"INTR",
"SEM",
"WAITCTX",
"INVAL",
"INVAL",
"INVAL", // 23
"CREATE", // 24
"DESTROY" // 25
};
void internal_to_external (unsigned int_class,
unsigned int_event,
unsigned *ext_class,
unsigned *ext_event)
{
int event_64 = 0;
*ext_class = -1;
*ext_event = -1;
switch (int_class)
{
case _TRACE_COMM_C:
*ext_class = _NTO_TRACE_COMM;
*ext_event = int_event;
break;
case _TRACE_CONTROL_C:
*ext_class = _NTO_TRACE_CONTROL;
*ext_event = int_event;
break;
case _TRACE_INT_C:
*ext_event = _NTO_TRACE_INT;
*ext_event = int_event;
break;
case _TRACE_KER_CALL_C:
/* Remove _NTO_TRACE_KERCALL64 if it's set. */
if (int_event & _NTO_TRACE_KERCALL64)
{
event_64 = 1;
int_event = int_event & ~_NTO_TRACE_KERCALL64;
}
/* Determine the class and event. */
if (int_event < _TRACE_MAX_KER_CALL_NUM)
{
*ext_class = _NTO_TRACE_KERCALLENTER;
*ext_event = int_event;
}
else if (int_event < 2 * _TRACE_MAX_KER_CALL_NUM)
{
*ext_class = _NTO_TRACE_KERCALLEXIT;
*ext_event = int_event - _TRACE_MAX_KER_CALL_NUM;
}
else if (int_event < 3 * _TRACE_MAX_KER_CALL_NUM)
{
*ext_class = _NTO_TRACE_KERCALLINT;
*ext_event = int_event - 2 * _TRACE_MAX_KER_CALL_NUM;
}
else
{
printf ("Unknown kernel event: %d\n", int_event);
}
/* Add _NTO_TRACE_KERCALL64 to the external event
if it was set for the internal event. */
if (event_64)
{
*ext_event = *ext_event | _NTO_TRACE_KERCALL64;
}
break;
case _TRACE_PR_TH_C:
*ext_event = -1;
if (int_event >= (2 * _TRACE_MAX_TH_STATE_NUM))
{
*ext_class = _NTO_TRACE_PROCESS;
*ext_event = 1 << ((int_event >> 6) -1);
}
else if (int_event >= _TRACE_MAX_TH_STATE_NUM)
{
*ext_event = 1 << (int_event - _TRACE_MAX_TH_STATE_NUM);
}
else
{
*ext_class = _NTO_TRACE_THREAD;
*ext_event = 1 << int_event;
}
break;
case _TRACE_SEC_C:
*ext_class = _NTO_TRACE_SEC;
*ext_event = int_event;
break;
case _TRACE_SYSTEM_C:
*ext_class = _NTO_TRACE_SYSTEM;
*ext_event = int_event;
break;
case _TRACE_USER_C:
*ext_class = _NTO_TRACE_USER;
*ext_event = int_event;
break;
default:
printf ("Unknown class: %d\n", int_class);
}
}
int main()
{
struct traceevent *tv;
int i;
char buf[64 * sizeof *tv ];
int nb;
unsigned internal_class, internal_event, cpu;
unsigned external_class, external_event, event_type;
char name_buff[1024];
int name_index;
while(1)
{
nb = read( 0, buf, sizeof(buf));
if( nb <= 0 )
{
return 0;
}
for( i = 0; i < nb/sizeof *tv; i++)
{
tv = (struct traceevent *)&buf[i*sizeof *tv];
/* The header includes the internal class and event numbers, the CPU index, and
the type of event (simple or combine). */
internal_class = _NTO_TRACE_GETEVENT_C(tv->header);
internal_event = _NTO_TRACE_GETEVENT(tv->header);
cpu = _NTO_TRACE_GETCPU(tv->header);
event_type = _TRACE_GET_STRUCT(tv->header);
switch (event_type)
{
case _TRACE_STRUCT_S:
printf("S ");
break;
case _TRACE_STRUCT_CB:
printf("CB ");
break;
case _TRACE_STRUCT_CC:
printf("CC ");
break;
case _TRACE_STRUCT_CE:
printf("CE ");
break;
default:
printf("? ");
}
/* Convert the internal class and event numbers into external ones. */
internal_to_external (internal_class,
internal_event,
&external_class,
&external_event);
if( _NTO_TRACE_PROCESS == external_class )
{
switch (external_event)
{
case _NTO_TRACE_PROCCREATE:
printf("_NTO_TRACE_PROCESS, _NTO_TRACE_PROCCREATE, cpu: %d, timestamp: %8x, ppid:%d, pid:%d\n",
cpu, tv->data[0], tv->data[1], tv->data[2]);
break;
case _NTO_TRACE_PROCCREATE_NAME:
if ((event_type == _TRACE_STRUCT_CB) || (event_type == _TRACE_STRUCT_S))
{
/* The first combine event includes the parent's pid and
the pid of the new process. */
printf("_NTO_TRACE_PROCESS, _NTO_TRACE_PROCCREATE_NAME, cpu: %d, timestamp: %8x, ppid:%d, pid:%d\n",
cpu, tv->data[0], tv->data[1], tv->data[2]);
memset (name_buff, 0, sizeof(name_buff));
name_index = 0;
}
else
{
/* Subsequent combine events include parts of the name. */
memcpy (name_buff + name_index,
&(tv->data[1]),
sizeof(unsigned int));
memcpy (name_buff + name_index + sizeof(unsigned int),
&(tv->data[2]),
sizeof(unsigned int));
name_index += 2 * sizeof(unsigned int);
if (event_type == _TRACE_STRUCT_CE)
{
/* This is the last of the combine events. */
printf("_NTO_TRACE_PROCESS, _NTO_TRACE_PROCCREATE_NAME, cpu: %d, timestamp: %8x, %s\n",
cpu, tv->data[0], name_buff);
}
}
break;
case _NTO_TRACE_PROCDESTROY:
printf("_NTO_TRACE_PROCESS, _NTO_TRACE_PROCDESTROY, cpu: %d, timestamp: %8x, ppid:%d, pid:%d\n",
cpu, tv->data[0], tv->data[1], tv->data[2]);
break;
case _NTO_TRACE_PROCDESTROY_NAME: // Not used.
printf("_NTO_TRACE_PROCESS, _NTO_TRACE_PROCDESTROY_NAME, cpu: %d, timestamp: %8x, ppid:%d, pid:%d\n",
cpu, tv->data[0], tv->data[1], tv->data[2]);
break;
case _NTO_TRACE_PROCTHREAD_NAME:
if ((event_type == _TRACE_STRUCT_CB) || (event_type == _TRACE_STRUCT_S))
{
/* The first combine event includes the pid and tid. */
printf("_NTO_TRACE_PROCESS, _NTO_TRACE_PROCTHREAD_NAME, cpu: %d, timestamp: %8x, pid:%d, tid:%d\n",
cpu, tv->data[0], tv->data[1], tv->data[2]);
memset (name_buff, 0, sizeof(name_buff));
name_index = 0;
}
else
{
/* Subsequent combine events include parts of the name. */
memcpy (name_buff + name_index,
&(tv->data[1]),
sizeof(unsigned int));
memcpy (name_buff + name_index + sizeof(unsigned int),
&(tv->data[2]),
sizeof(unsigned int));
name_index += 2 * sizeof(unsigned int);
if (event_type == _TRACE_STRUCT_CE)
{
/* This is the last of the combine events. */
printf("_NTO_TRACE_PROCESS, _NTO_TRACE_PROCTHREAD_NAME, cpu: %d, timestamp: %8x, %s\n",
cpu, tv->data[0], name_buff);
}
}
break;
default:
printf("_NTO_TRACE_PROCESS, Unknown event: %d, cpu: %d, timestamp: %8x, pid:%d, tid:%d\n",
external_event, cpu, tv->data[0], tv->data[1], tv->data[2]);
}
}
else if (_NTO_TRACE_THREAD == external_class)
{
/* The data for all the THREAD events includes the process and thread IDs.
The internal event corresponds to the thread state. */
printf("_NTO_TRACE_THREAD, _NTO_TRACE_TH%s, cpu: %d, timestamp: %8x, pid:%d, tid:%d\n",
thread_events[internal_event], cpu, tv->data[0], tv->data[1],
tv->data[2]);
}
else if ( _NTO_TRACE_CONTROL == external_class )
{
switch (external_event)
{
case _NTO_TRACE_CONTROLBUFFER:
/* The data includes the sequence number of the buffer and
the number of event slots in it. */
printf("_NTO_TRACE_CONTROL,_NTO_TRACE_CONTROLBUFFER, cpu:%d, timestamp:%8x, sequence:%d, number of events:%d\n",
cpu, tv->data[0], tv->data[1], tv->data[2]);
break;
case _NTO_TRACE_CONTROLTIME:
/* The data includes the full time stamp. */
printf("_NTO_TRACE_CONTROL, _NTO_TRACE_CONTROLTIME, cpu:%d, timestamp:%8x, msb:%x, lsb:%x\n",
cpu, tv->data[0], tv->data[1], tv->data[2]);
break;
default:
printf("_NTO_TRACE_CONTROL, Unknown event:%d, cpu:%d, timestamp:%8x, d1:%x, d2:%x\n",
external_event, cpu, tv->data[0], tv->data[1], tv->data[2]);
}
}
else
{
printf("Unhandled class:%d, event:%d, cpu:%d, timestamp:%8x, d1:%x, d2:%x\n",
external_class, external_event, cpu, tv->data[0], tv->data[1],
tv->data[2]);
}
}
}
}
Page updated: