Data-capture program

QNX SDP8.0System Analysis Toolkit (SAT) User's GuideUser

This program creates the kernel trace buffers, captures the data, and writes it to standard output. You'd normally redirect the output to a file.

The basic steps in this program are as follows:

  1. Get memory for the kernel buffers.
  2. Configure the kernel buffers.
  3. Indicate which events to collect (thread events and control events).
  4. Attach a handler.
  5. Start tracing:
    • In the handler, copy the data and schedule a thread.
    • In the thread, write the data to stdout.
Note: This program needs to run with the PROCMGR_AID_INTERRUPT, PROCMGR_AID_MEM_PHYS, and PROCMGR_AID_TRACE abilities enabled.
#include <sys/trace.h>
#include <sys/neutrino.h>
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

struct my_buf
{
   unsigned nbytes;
   char data[16*1024];
} my_bufs[4];

int cur_my_buf;

tracebuf_t *kbufs;
paddr_t paddr; // A pointer to physical kernel memory
int hookid;

struct sigevent notify_ev;

const struct sigevent *got_buf( int info )
{
   int ind;
   tracebuf_t *tbuf;

   ind = _TRACE_GET_BUFFNUM(info);
   tbuf = &kbufs[ind];

   my_bufs[ind].nbytes = tbuf->h.num_events * sizeof(struct traceevent);
   memcpy( my_bufs[ind].data, tbuf->data, my_bufs[ind].nbytes );

   notify_ev.sigev_value.sival_int = ind;
   return &notify_ev;
}

void sig_cleanup(int signo )
{
   TraceEvent( _NTO_TRACE_STOP );
   TraceEvent(_NTO_TRACE_DEALLOCBUFFER);
   InterruptDetach( hookid );
}

int main()
{
   int ret;
   int coid;
   int chid;
   struct _pulse pmsg;
   rcvid_t rcvid;

   signal( SIGINT, sig_cleanup );

   ret = ThreadCtl(_NTO_TCTL_IO, 0);
   if (-1 == ret )
   {
      perror( "ThreadCtl");
      return 1;
   }

   // This may be dangerous: if anyone else is tracing, this may break them.
   // But it should allow us to run again if killed without cleaning up.
   TraceEvent(_NTO_TRACE_DEALLOCBUFFER);
   TraceEvent( _NTO_TRACE_STOP );

   // Ask the kernel for four buffers.
   ret = TraceEvent(_NTO_TRACE_ALLOCBUFFER, 4, &paddr);
   if( -1 == ret )
   {
      perror( "TraceEvent Alloc Bufs");
      return 1;
   }

   // Get a vaddr for this memory.
   kbufs = mmap( 0, 4 * sizeof(tracebuf_t), PROT_READ | PROT_WRITE,
                 MAP_PHYS | MAP_SHARED, NOFD, paddr );
   if( MAP_FAILED == kbufs )
   {
      perror("mmap");
      return 1;
   }

   chid = ChannelCreate(_NTO_CHF_PRIVATE);
   coid = ConnectAttach( 0, 0, chid, _NTO_SIDE_CHANNEL, 0 );

   SIGEV_PULSE_INIT( &notify_ev, coid, 15, 1, 0 );

   // Attach the notification handler for the _NTO_HOOK_TRACE synthetic interrupt
   // that the kernel uses to tell us about a full buffer.
   hookid = InterruptHookTrace( got_buf, 0 );

   // Indicate which events we want.

   // Turn off all filters, putting us in default (nothing) state.
   TraceEvent(_NTO_TRACE_DELALLCLASSES);
   TraceEvent(_NTO_TRACE_CLRCLASSPID, _NTO_TRACE_KERCALL);
   TraceEvent(_NTO_TRACE_CLRCLASSTID, _NTO_TRACE_KERCALL);
   TraceEvent(_NTO_TRACE_CLRCLASSPID, _NTO_TRACE_THREAD);
   TraceEvent(_NTO_TRACE_CLRCLASSTID, _NTO_TRACE_THREAD);

   // Ask for thread and process events.
   TraceEvent(_NTO_TRACE_ADDCLASS, _NTO_TRACE_THREAD);
   TraceEvent(_NTO_TRACE_ADDCLASS, _NTO_TRACE_PROCESS);

   // Ask for control events.
   TraceEvent(_NTO_TRACE_ADDCLASS, _NTO_TRACE_CONTROL );

   // Set fast mode for all classes.
   TraceEvent( _NTO_TRACE_SETALLCLASSESFAST );

   // Make sure we are in linear (not ring) mode; as buffers fill,
   // we will be notified
   TraceEvent(_NTO_TRACE_SETLINEARMODE);

   // Start tracing.
   TraceEvent( _NTO_TRACE_START );

   while(1)
   {
      rcvid = MsgReceive( chid, &pmsg, sizeof(pmsg), 0 );
      if( -1 == rcvid )
      {
         perror("MsgReceive");
         return 1;
      }
      if( 0 == rcvid )
      {
         if (pmsg.code == 1 )
         {
            ret = write( 1, my_bufs[pmsg.value.sival_int].data,
                         my_bufs[pmsg.value.sival_int].nbytes );
            if( -1 == ret )
            {
               perror("write");
               return 1;
            }
         }
      }
      // We do not need a message error case, since it is a private channel,
      // so nobody should be able to attach to it or send me messages.
   }
}
Page updated: