This program reads the events file or output generated by the data-capture program and does some very 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 and _NTO_TRACE_VTHREAD 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_NET_SEND, /* 19 0x13 */ // STATE_NET_REPLY, /* 20 0x14 */ // // 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", "NET_SEND", "NET_REPLY", // 20 "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 = -1; switch (int_event) { case _TRACE_INT_ENTRY: *ext_class = _NTO_TRACE_INTENTER; break; case _TRACE_INT_EXIT: *ext_class = _NTO_TRACE_INTEXIT; break; case _TRACE_INT_HANDLER_ENTRY: *ext_class = _NTO_TRACE_INT_HANDLER_ENTER; break; case _TRACE_INT_HANDLER_EXIT: *ext_class = _NTO_TRACE_INT_HANDLER_EXIT; break; default: printf ("Unknown Interrupt event: %d\n", 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_class = _NTO_TRACE_VTHREAD; *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_VTHREAD == external_class) { /* The data for all the VTHREAD events includes the process and thread IDs. The internal event corresponds to the thread state. */ printf("_NTO_TRACE_VTHREAD, _NTO_TRACE_VTH%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]); } } } }