00001
00002
00003 #include "IgTools/IgTrace/src/IgTrace.h"
00004 #include "IgTools/IgTrace/src/IgTraceAtomic.h"
00005 #include "IgTools/IgHook/interface/IgHookTrace.h"
00006 #include <sys/types.h>
00007 #include <sys/time.h>
00008 #include <cstdlib>
00009 #include <cstdio>
00010 #include <cstdarg>
00011 #include <cerrno>
00012 #include <cstring>
00013 #include <unistd.h>
00014
00015 #ifdef __APPLE__
00016 # include <crt_externs.h>
00017 # define program_invocation_name **_NSGetArgv()
00018 #endif
00019
00020
00021
00022
00023
00025 struct IgTraceFilter
00026 {
00027 IgTraceFilter *nextFilter;
00028 char *extraInfo;
00029 char *functionName;
00030 char *libraryName;
00031 };
00032
00033
00034
00035
00036
00037
00038
00039 static IgTraceAtomic s_enabled = 0;
00040 static bool s_initialized = false;
00041 static bool s_activated = false;
00042 static volatile int s_quitting = 0;
00043 static IgTraceFilter *s_filters = 0;
00044
00045
00046
00047
00054 bool
00055 IgTrace::initialize (void)
00056 {
00057 if (! s_initialized)
00058 {
00059 s_initialized = true;
00060
00061 const char *options = IgTrace::options ();
00062 if (! options || ! *options)
00063 {
00064 IgTrace::debug ("$IGTRACE not set, not tracing this process\n");
00065 return s_activated = false;
00066 }
00067 while (options && *options)
00068 {
00069 while (*options == ' ' || *options == ',')
00070 ++options;
00071
00072 if (! strncmp (options, "igtrace:reject='", 16))
00073 {
00074 options += 16;
00075
00076 const char *info = options;
00077 int infolen = 0;
00078 while (*options && *options != '\'' && *options != ':')
00079 ++options, ++infolen;
00080 if (*options == ':')
00081 ++options;
00082
00083 const char *func = options;
00084 int funclen = 0;
00085 while (*options && *options != '\'' && *options != ':')
00086 ++options, ++funclen;
00087 if (*options == ':')
00088 ++options;
00089
00090 const char *lib = options;
00091 int liblen = 0;
00092 while (*options && *options != '\'' && *options != ':')
00093 ++options, ++liblen;
00094
00095 IgTraceFilter *f = new IgTraceFilter;
00096 f->nextFilter = 0;
00097 f->extraInfo = (infolen ? strndup (info, infolen) : 0);
00098 f->functionName = (funclen ? strndup (func, funclen) : 0);
00099 f->libraryName = (liblen ? strndup (lib, liblen) : 0);
00100
00101 IgTraceFilter **chain = &s_filters;
00102 while (*chain)
00103 chain = &(*chain)->nextFilter;
00104
00105 *chain = f;
00106
00107 while (*options && *options != '\'')
00108 ++options;
00109 }
00110 else
00111 options++;
00112
00113 while (*options && *options != ',' && *options != ' ')
00114 options++;
00115 }
00116
00117 const char *target = getenv ("IGTRACE_TARGET");
00118 if (target && ! strstr (program_invocation_name, target))
00119 {
00120 IgTrace::debug ("Current process not selected for tracing:"
00121 " process '%s' does not match '%s'\n",
00122 program_invocation_name, target);
00123 return s_activated = false;
00124 }
00125
00126 IgTrace::debug ("Activated in %s\n", program_invocation_name);
00127 IgTrace::debug ("Options: %s\n", IgTrace::options ());
00128 s_activated = true;
00129 s_enabled = 1;
00130 }
00131
00132 if (! s_activated)
00133 return false;
00134
00135 return true;
00136 }
00137
00143 bool
00144 IgTrace::enabled (void)
00145 {
00146 return s_enabled > 0;
00147 }
00148
00154 bool
00155 IgTrace::enable (void)
00156 {
00157 IgTraceAtomic newval = IgTraceAtomicInc (&s_enabled);
00158 return newval > 0;
00159 }
00160
00166 bool
00167 IgTrace::disable (void)
00168 {
00169 IgTraceAtomic newval = IgTraceAtomicDec (&s_enabled);
00170 return newval >= 0;
00171 }
00172
00174 const char *
00175 IgTrace::options (void)
00176 {
00177 static const char *s_options = getenv ("IGTRACE");
00178 return s_options;
00179 }
00180
00182 int
00183 IgTrace::panic (const char *file, int line, const char *func, const char *expr)
00184 {
00185 IgTrace::disable ();
00186
00187 #if __linux
00188 fprintf (stderr, "%s: ", program_invocation_name);
00189 #endif
00190 fprintf (stderr, "%s:%d: %s: assertion failure: %s\n", file, line, func, expr);
00191
00192 void *trace [128];
00193 int levels = IgHookTrace::stacktrace (trace, 128);
00194 for (int i = 2; i < levels; ++i)
00195 {
00196 const char *sym = 0;
00197 const char *lib = 0;
00198 int offset = 0;
00199 int liboffset = 0;
00200 IgHookTrace::symbol (trace [i], sym, lib, offset, liboffset);
00201 fprintf (stderr, " %p %s + %d [%s + %d]\n", trace [i], sym, offset, lib, liboffset);
00202 }
00203
00204
00205 IgTrace::enable ();
00206 return 1;
00207 }
00208
00211 void
00212 IgTrace::debug (const char *format, ...)
00213 {
00214 static const char *debugging = getenv ("IGTRACE_DEBUGGING");
00215 if (debugging)
00216 {
00217 timeval tv;
00218 gettimeofday (&tv, 0);
00219 fprintf (stderr, "*** IgTrace(%lu, %.3f): ",
00220 (unsigned long) getpid(),
00221 tv.tv_sec + 1e-6*tv.tv_usec);
00222
00223 va_list args;
00224 va_start (args, format);
00225 vfprintf (stderr, format, args);
00226 va_end (args);
00227 }
00228 }
00229
00231 const char *
00232 IgTrace::program (void)
00233 {
00234 return program_invocation_name;
00235 }
00236
00238 bool
00239 IgTrace::filter (const char *info, void *stack [], int depth)
00240 {
00241 bool pass = true;
00242 IgTraceFilter *f = s_filters;
00243 while (f && pass)
00244 {
00245 if (info && f->extraInfo && strstr (info, f->extraInfo))
00246 pass = false;
00247
00248 for (int i = 0; i < depth && pass; ++i)
00249 {
00250 bool passthis = true;
00251 const char *sym = 0;
00252 const char *lib = 0;
00253 int junk = 0;
00254
00255 if (! IgHookTrace::symbol (stack[i], sym, lib, junk, junk))
00256 continue;
00257
00258 if (passthis && sym && f->functionName && strstr (sym, f->functionName))
00259 passthis = false;
00260
00261 if (passthis && lib && f->libraryName && strstr (lib, f->libraryName))
00262 passthis = false;
00263
00264 if (! passthis)
00265 pass = false;
00266 }
00267
00268 f = f->nextFilter;
00269 }
00270
00271 return pass;
00272 }
00273
00275 static bool autoboot = IgTrace::initialize ();