Simple utilities sink - stuff that doesn't fit anywhere else / objects in plain C Snapshot
errorp.c
Go to the documentation of this file.
00001 /* Copyright (c) Michael Moser (2011) . 3-clause BSD License applies */
00002 
00003 #include <stdio.h>
00004 #include <stdarg.h>
00005 #include <unistd.h>
00006 #include <errno.h>
00007 #include <string.h>
00008 #include "errorp.h"
00009 #include <sys/types.h>
00010 #include <sys/stat.h>
00011 #include <fcntl.h>
00012 #ifdef __linux__
00013 #include <execinfo.h>
00014 #endif
00015 
00016 #define ERROR_TOKEN "ERROR: "
00017 
00018 #define STACK_FRAMES 30
00019 
00020 #define STACK_START "*** start stack ***\n"
00021 #define STACK_EOF   "\n*** eof stack ***\n\n"
00022 
00023 
00024 static int FD_OUT  = 2;
00025 static int FD_ASSIGNED = 0;
00026 
00027 #ifdef __linux__
00028 static void dump_modules(char *buff, size_t buff_size);
00029 #endif
00030 
00031 int errorp_is_file_open()
00032 {  
00033   return FD_ASSIGNED;
00034 }
00035 
00036 int errorp_open_file(const char *file)
00037 {
00038   int fd;
00039 
00040   fd = open( file , O_CREAT | O_APPEND | O_RDWR, S_IWUSR  | S_IRUSR );
00041   if (fd != -1) {
00042     FD_OUT = fd;
00043     FD_ASSIGNED = 1;
00044   }
00045   return fd;
00046 }
00047 
00048 void errorp_close_file()
00049 {
00050   if (FD_ASSIGNED != 1) {
00051     close( FD_OUT );
00052     FD_OUT = 2;
00053     FD_ASSIGNED = 0;
00054   }
00055 }
00056 
00057 void errorp(int rval, const char *fmt, ... ) 
00058 {
00059   char buff[ 512 ];
00060   char *p, *eof;
00061   va_list ap;
00062   int len, n;
00063 #if __linux__
00064   void *sframes[ STACK_FRAMES + 1 ];
00065   int nframes, i;
00066 #endif
00067 
00068  
00069   p = buff;
00070   eof = p + sizeof( buff );
00071 
00072   strcpy( p, ERROR_TOKEN );
00073   p += strlen( ERROR_TOKEN );
00074 
00075   va_start( ap, fmt );
00076   len =  vsnprintf( p, eof - p - 1, fmt, ap );
00077   va_end( ap );
00078   p += len;
00079 
00080   n = snprintf(p, eof - p - 1, ". returns %d errno %d\n", rval, errno );
00081   p += n;
00082 
00083 #if __linux__
00084   nframes = backtrace( sframes, STACK_FRAMES + 1); \
00085   write( FD_OUT, STACK_START, strlen( STACK_START ) );
00086   
00087   nframes =  backtrace( sframes, STACK_FRAMES );
00088   for (i=0; i<nframes; i++) {
00089     snprintf( buff, sizeof(buff),  "frame %d ip: %p\n", i, sframes[ i ]);
00090     write( FD_OUT , buff, strlen( buff ) );
00091   }
00092 
00093   dump_modules( buff, sizeof(buff) );
00094   write( FD_OUT, STACK_EOF, strlen( STACK_EOF ) );
00095 #endif
00096 }
00097 
00098 void error_dump_string( const char *msg, char *buff, size_t buff_size)
00099 {
00100  #if __linux__
00101   void *sframes[ STACK_FRAMES + 1 ];
00102   int nframes, i;
00103 #endif
00104 
00105 
00106   write( FD_OUT , msg , strlen( msg ) );
00107 
00108 #if __linux__
00109   nframes = backtrace( sframes, STACK_FRAMES + 1); \
00110   write( FD_OUT, STACK_START, strlen( STACK_START ) );
00111   
00112   nframes =  backtrace( sframes, STACK_FRAMES );
00113   for (i=0; i<nframes; i++) {
00114     snprintf( buff, buff_size,  "frame %d ip: %p\n", i, sframes[ i ]);
00115     write( FD_OUT , buff, strlen( buff ) );
00116   }
00117 
00118   dump_modules( buff, buff_size );
00119   write( FD_OUT, STACK_EOF, strlen( STACK_EOF ) );
00120 #endif
00121 }
00122 
00123 #define TOKENS_COUNT        6
00124 #define TOKENS_ADDRESS      0
00125 #define TOKENS_PERMISSIONS  1 
00126 #define TOKENS_FILEOFFSET   2
00127 #define TOKENS_PATH         5
00128 
00129 #ifdef __linux__
00130 static void dump_modules(char *buf, size_t buff_size)
00131 {
00132   int fd, n, i, buf_start;
00133   char line[30];
00134   char *pos, *eof_line, *tokens[ TOKENS_COUNT ];
00135 
00136   sprintf(buf,"/proc/%d/maps", getpid() );
00137 
00138 
00139   fd = open( buf, O_RDONLY );
00140   if (fd == -1) {
00141     return;
00142   }
00143   
00144   buf_start = 0;
00145   while(1) {
00146     n = read(fd, buf + buf_start, buff_size - buf_start );
00147     if (n <= 0) {
00148       break;
00149     }
00150 
00151     pos = buf;
00152     while(1) {
00153 
00154        eof_line = memchr( pos, '\n', buf + buff_size - pos );
00155        if (eof_line == 0) {
00156          break;
00157        }
00158        
00159        *eof_line = '\0';
00160        for(i=0; i< TOKENS_COUNT; i++) {
00161          tokens[ i ] = strtok( !i ? pos : 0," ");
00162          if (! tokens[ i ]) {
00163            break;
00164          }
00165          if (i == TOKENS_PERMISSIONS) {
00166            if (strchr( tokens[i], 'x') == 0) {
00167              break;
00168            }
00169          }
00170        }
00171        if (i == TOKENS_COUNT) {
00172           snprintf(line, sizeof(line) - 1, "\n%s %s ", tokens[ TOKENS_ADDRESS ] , tokens[ TOKENS_FILEOFFSET ]);
00173           write( FD_OUT, line, strlen(line) );
00174           write( FD_OUT, tokens[ TOKENS_PATH ], strlen( tokens[ TOKENS_PATH ] ) );
00175        
00176        }
00177       
00178        pos = eof_line + 1;
00179     }
00180 
00181     buf_start = 0;
00182     if (pos < (buf + buff_size - 1)) {
00183       buf_start = buf + buff_size - pos;
00184       memmove( buf, pos, buf_start ); 
00185     }
00186   }
00187   close(fd);
00188 
00189 }
00190 #endif