Warning cleanup. Applying RH's Dyninst patches to 8.1, this one originally by Willia...
[dyninst.git] / dyninstAPI / src / debug.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 // $Id: debug.C,v 1.6 2008/02/23 02:09:05 jaw Exp $
32
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <assert.h>
36 #include <string>
37 #include "common/h/Pair.h"
38 #include "common/h/Vector.h"
39 #include "util.h"
40 #include "BPatch.h"
41 #include "dyninstAPI/src/debug.h"
42 #include "common/h/dthread.h"
43 #include "os.h"
44
45 unsigned long getExecThreadID() {
46 #if defined(os_windows)
47     return (unsigned long) _threadid;
48 #else
49     return (unsigned long) pthread_self();
50 #endif
51 }
52
53 // Make a lock.
54
55 Mutex *debugPrintLock = NULL;
56
57 void BPatch_reportError(int errLevel, int num, const char *str) {
58     BPatch::reportError((BPatchErrorLevel) errLevel, num, str);
59 }
60
61 void
62 dyninst_log_perror(const char* msg) {
63     sprintf(errorLine, "%s: %s\n", msg, strerror(errno));
64     logLine(errorLine);
65     // fprintf(stderr, "%s", log_buffer);
66 }
67 void showInfoCallback(std::string msg)
68 {
69     BPatch::reportError(BPatchWarning, 0, msg.c_str());
70 }
71
72 char errorLine[1024];
73
74 void showErrorCallback(int num, std::string msg)
75 {
76     BPatch::reportError(BPatchSerious, num, msg.c_str());
77 }
78
79 void logLine(const char *line)
80 {
81     BPatch::reportError(BPatchWarning, 0, line);
82 }
83
84 // The unused parameter is used by Paradyn's version of this function.
85 void statusLine(const char *line, bool /* unused */ )
86 {
87     BPatch::reportError(BPatchInfo, 0, line);
88 }
89
90 //  bpfatal, bpsevere, bpwarn, and bpinfo are intended as drop-in 
91 //  replacements for printf.
92 #define ERR_BUF_SIZE 2048 // egad -- 1024 is not large enough
93
94 int bpfatal(const char *format, ...)
95 {
96   if (NULL == format) return -1;
97
98   char errbuf[ERR_BUF_SIZE];
99
100   va_list va;
101   va_start(va, format);
102 #if defined (i386_unknown_nt4_0)
103   _vsnprintf(errbuf, ERR_BUF_SIZE,format, va);
104 #else
105   vsnprintf(errbuf, ERR_BUF_SIZE,format, va);
106 #endif
107   va_end(va);
108
109   BPatch::reportError(BPatchFatal, 0, errbuf);
110
111   return 0;
112 }
113
114
115 int bpfatal_lf(const char *__file__, unsigned int __line__, const char *format, ...)
116 {
117   fprintf(stderr, "%s[%d]\n", __FILE__, __LINE__);
118   if (NULL == format) return -1;
119
120   char errbuf[ERR_BUF_SIZE];
121
122   fprintf(stderr, "%s[%d]\n", __FILE__, __LINE__);
123   int header_len = sprintf(errbuf, "[%ld]%s[%d]: ", getExecThreadID(), __file__, __line__);
124
125   fprintf(stderr, "%s[%d]\n", __FILE__, __LINE__);
126   va_list va;
127   va_start(va, format);
128   VSNPRINTF(errbuf + header_len, ERR_BUF_SIZE,format, va);
129   va_end(va);
130
131   fprintf(stderr, "%s[%d]\n", __FILE__, __LINE__);
132   BPatch::reportError(BPatchFatal, 0, errbuf);
133
134   fprintf(stderr, "%s[%d]\n", __FILE__, __LINE__);
135   return 0;
136 }
137
138 int bperr(const char *format, ...)
139 {
140   if (NULL == format) return -1;
141
142   char errbuf[ERR_BUF_SIZE];
143
144   va_list va;
145   va_start(va, format);
146 #if defined (i386_unknown_nt4_0)
147   int errbuflen = _vsnprintf(errbuf, ERR_BUF_SIZE, format, va);
148 #else
149   int errbuflen = vsnprintf(errbuf, ERR_BUF_SIZE, format, va);
150 #endif
151   va_end(va);
152
153   char syserr[128];
154   if (errno) {
155 #if defined (i386_unknown_nt4_0)
156     int syserrlen = _snprintf(syserr, 128," [%d: %s]", errno, strerror(errno));
157 #else
158     int syserrlen = snprintf(syserr, 128," [%d: %s]", errno, strerror(errno));
159 #endif
160     /* reset errno so that future calls to this function don't report same error */
161     errno = 0; 
162
163     if ((errbuflen + syserrlen) < ERR_BUF_SIZE)
164       strcat(errbuf, syserr);
165     else {
166       BPatch::reportError(BPatchSerious, 0, errbuf);
167       BPatch::reportError(BPatchSerious, 0, syserr);
168       return 0;
169     }
170   }
171   BPatch::reportError(BPatchSerious, 0, errbuf);
172
173   return 0;
174 }
175
176 int bpwarn(const char *format, ...)
177 {
178   if (NULL == format) return -1;
179
180   char errbuf[ERR_BUF_SIZE];
181
182   va_list va;
183   va_start(va, format);
184 #if defined (i386_unknown_nt4_0)
185   _vsnprintf(errbuf, ERR_BUF_SIZE,format, va);
186 #else
187   vsnprintf(errbuf, ERR_BUF_SIZE,format, va);
188 #endif
189   va_end(va);
190
191   BPatch::reportError(BPatchWarning, 0, errbuf);
192
193   return 0;
194 }
195
196 int bpinfo(const char *format, ...)
197 {
198   if (NULL == format) return -1;
199
200   char errbuf[ERR_BUF_SIZE];
201
202   va_list va;
203   va_start(va, format);
204 #if defined (i386_unknown_nt4_0)
205   _vsnprintf(errbuf, ERR_BUF_SIZE, format, va);
206 #else
207   vsnprintf(errbuf, ERR_BUF_SIZE, format, va);
208 #endif
209   va_end(va);
210
211   BPatch::reportError(BPatchInfo, 0, errbuf);
212
213   return 0;
214 }
215
216
217 // Internal debugging
218
219 int dyn_debug_malware = 0;
220 int dyn_debug_trap = 0;
221 int dyn_debug_signal = 0;
222 int dyn_debug_infrpc = 0;
223 int dyn_debug_startup = 0;
224 int dyn_debug_parsing = 0;
225 int dyn_debug_proccontrol = 0;
226 int dyn_debug_stackwalk = 0;
227 int dyn_debug_inst = 0;
228 int dyn_debug_reloc = 0;
229 int dyn_debug_springboard = 0;
230 int dyn_debug_sensitivity = 0;
231 int dyn_debug_dyn_unw = 0;
232 int dyn_debug_mutex = 0;
233 int dyn_debug_dwarf = 0;
234 int dyn_debug_rtlib = 0;
235 int dyn_debug_catchup = 0;
236 int dyn_debug_bpatch = 0;
237 int dyn_debug_regalloc = 0;
238 int dyn_debug_ast = 0;
239 int dyn_debug_write = 0;
240 int dyn_debug_infmalloc = 0;
241 int dyn_debug_crash = 0;
242 char *dyn_debug_crash_debugger = NULL;
243 int dyn_debug_disassemble = 0;
244
245 static char *dyn_debug_write_filename = NULL;
246 static FILE *dyn_debug_write_file = NULL;
247
248 bool init_debug() {
249   static bool init = false;
250   if (init) return true;
251   init = true;
252
253   char *p;
254   if (getenv("DYNINST_DEBUG_MALWARE")) {
255     fprintf(stderr, "Enabling DyninstAPI malware debug\n");
256     dyn_debug_malware = 1;
257   }
258   if (getenv("DYNINST_DEBUG_TRAP")) {
259     fprintf(stderr, "Enabling DyninstAPI debugging using traps\n");
260     dyn_debug_trap = 1;
261   }
262   if (getenv("DYNINST_DEBUG_SPRINGBOARD")) {
263     fprintf(stderr, "Enabling DyninstAPI springboard debug\n");
264     dyn_debug_springboard = 1;
265   }
266   if (getenv("DYNINST_DEBUG_STARTUP")) {
267     fprintf(stderr, "Enabling DyninstAPI startup debug\n");
268     dyn_debug_startup = 1;
269   }
270   if ( (p=getenv("DYNINST_DEBUG_PARSING"))) {
271           if(p[0] != '0') {
272                 fprintf(stderr, "Enabling DyninstAPI parsing debug\n");
273             dyn_debug_parsing = 1;
274           }
275   }
276   if ( (p=getenv("DYNINST_DEBUG_PARSE"))) {
277           if(p[0] != '0') {
278                 fprintf(stderr, "Enabling DyninstAPI parsing debug\n");
279             dyn_debug_parsing = 1;
280           }
281   }
282   if (    getenv("DYNINST_DEBUG_DYNPC")
283        || getenv("DYNINST_DEBUG_FORKEXEC")
284        || getenv("DYNINST_DEBUG_INFRPC")
285        || getenv("DYNINST_DEBUG_SIGNAL")
286        || getenv("DYNINST_DEBUG_INFERIORRPC")
287        || getenv("DYNINST_DEBUG_THREAD")
288        || getenv("DYNINST_DEBUG_MAILBOX")
289        || getenv("DYNINST_DEBUG_DBI")
290      ) 
291   {
292     fprintf(stderr, "Enabling DyninstAPI process control debug\n");
293     dyn_debug_proccontrol = 1;
294   }
295   if (getenv("DYNINST_DEBUG_STACKWALK")) {
296     fprintf(stderr, "Enabling DyninstAPI stack walking debug\n");
297     dyn_debug_stackwalk = 1;
298   }
299   if (getenv("DYNINST_DEBUG_INST")) {
300     fprintf(stderr, "Enabling DyninstAPI inst debug\n");
301     dyn_debug_inst = 1;
302   }
303   if (getenv("DYNINST_DEBUG_RELOC")) {
304     fprintf(stderr, "Enabling DyninstAPI relocation debug\n");
305     dyn_debug_reloc = 1;
306   }
307   if (getenv("DYNINST_DEBUG_RELOCATION")) {
308     fprintf(stderr, "Enabling DyninstAPI relocation debug\n");
309     dyn_debug_reloc = 1;
310   }
311   if (getenv("DYNINST_DEBUG_SENSITIVITY")) {
312     fprintf(stderr, "Enabling DyninstAPI sensitivity debug\n");
313     dyn_debug_sensitivity = 1;
314   }
315   if (getenv("DYNINST_DEBUG_DYN_UNW")) {
316     fprintf(stderr, "Enabling DyninstAPI dynamic unwind debug\n");
317     dyn_debug_dyn_unw = 1;
318     }
319   if (getenv("DYNINST_DEBUG_MUTEX")) {
320     fprintf(stderr, "Enabling DyninstAPI mutex debug\n");
321     dyn_debug_mutex = 1;
322     }
323   if (getenv("DYNINST_DEBUG_RTLIB")) {
324       fprintf(stderr, "Enabling DyninstAPI RTlib debug\n");
325       dyn_debug_rtlib = 1;
326   }
327   if (getenv("DYNINST_DEBUG_CATCHUP")) {
328       fprintf(stderr, "Enabling DyninstAPI catchup debug\n");
329       dyn_debug_catchup = 1;
330   }
331   if (getenv("DYNINST_DEBUG_BPATCH")) {
332       fprintf(stderr, "Enabling DyninstAPI bpatch debug\n");
333       dyn_debug_bpatch = 1;
334   }
335   if (getenv("DYNINST_DEBUG_REGALLOC")) {
336       fprintf(stderr, "Enabling DyninstAPI register allocation debug\n");
337       dyn_debug_regalloc = 1;
338   }
339   if (getenv("DYNINST_DEBUG_AST")) {
340       fprintf(stderr, "Enabling DyninstAPI ast debug\n");
341       dyn_debug_ast = 1;
342   }
343   if ( (p=getenv("DYNINST_DEBUG_WRITE"))) {
344     fprintf(stderr, "Enabling DyninstAPI process write debugging\n");
345     dyn_debug_write = 1;
346     dyn_debug_write_filename = p;
347   }
348   if ( (p=getenv("DYNINST_DEBUG_INFMALLOC")) ||
349        (p=getenv("DYNINST_DEBUG_INFERIORMALLOC"))) {
350     fprintf(stderr, "Enabling DyninstAPI inferior malloc debugging\n");
351     dyn_debug_infmalloc = 1;
352   }
353   if ((p=getenv("DYNINST_DEBUG_CRASH"))) {
354      fprintf(stderr, "Enable DyninstAPI crash debugging\n");
355      dyn_debug_crash = 1;
356      dyn_debug_crash_debugger = p;
357   }
358   if (getenv("DYNINST_DEBUG_DISASS")) {
359       fprintf(stderr, "Enabling DyninstAPI instrumentation disassembly debugging\n");
360       dyn_debug_disassemble = 1;
361   }
362   debugPrintLock = new Mutex();
363
364   return true;
365 }
366
367 int mal_printf(const char *format, ...)
368 {
369   if (!dyn_debug_malware) return 0;
370   if (NULL == format) return -1;
371
372   debugPrintLock->lock();
373
374   va_list va;
375   va_start(va, format);
376   int ret = vfprintf(stderr, format, va);
377   va_end(va);
378
379   debugPrintLock->unlock();
380
381   return ret;
382 }
383
384 int trap_printf(const char *format, ...)
385 {
386   if (!dyn_debug_trap) return 0;
387   if (NULL == format) return -1;
388
389   debugPrintLock->lock();
390
391   va_list va;
392   va_start(va, format);
393   int ret = vfprintf(stderr, format, va);
394   va_end(va);
395
396   debugPrintLock->unlock();
397
398   return ret;
399 }
400
401 int signal_printf_int(const char *format, ...)
402 {
403   if (!dyn_debug_signal) return 0;
404   if (NULL == format) return -1;
405
406   debugPrintLock->lock();
407
408   fprintf(stderr, "[%ld]", getExecThreadID());
409   va_list va;
410   va_start(va, format);
411   int ret = vfprintf(stderr, format, va);
412   va_end(va);
413
414   debugPrintLock->unlock();
415
416   return ret;
417 }
418
419 int inferiorrpc_printf_int(const char *format, ...)
420 {
421   if (!dyn_debug_infrpc) return 0;
422   if (NULL == format) return -1;
423
424   debugPrintLock->lock();
425
426   fprintf(stderr, "[%ld]", getExecThreadID());
427   va_list va;
428   va_start(va, format);
429   int ret = vfprintf(stderr, format, va);
430   va_end(va);
431
432   debugPrintLock->unlock();
433
434   return ret;
435 }
436
437 int startup_printf_int(const char *format, ...)
438 {
439   if (!dyn_debug_startup) return 0;
440   if (NULL == format) return -1;
441
442   debugPrintLock->lock();
443
444   fprintf(stderr, "[%ld]", getExecThreadID());
445   va_list va;
446   va_start(va, format);
447   int ret = vfprintf(stderr, format, va);
448   va_end(va);
449
450   debugPrintLock->unlock();
451
452   return ret;
453 }
454
455 int parsing_printf_int(const char *format, ...)
456 {
457   if (!dyn_debug_parsing) return 0;
458   if (NULL == format) return -1;
459
460   debugPrintLock->lock();
461
462   //fprintf(stderr, "[%ld]", getExecThreadID());
463   va_list va;
464   va_start(va, format);
465
466   int ret = vfprintf(stderr, format, va);
467
468   va_end(va);
469
470   debugPrintLock->unlock();
471
472   return ret;
473 }
474
475 int proccontrol_printf_int(const char *format, ...)
476 {
477   if (!dyn_debug_proccontrol) return 0;
478   if (NULL == format) return -1;
479
480   debugPrintLock->lock();
481
482   fprintf(stderr, "[%ld]", getExecThreadID());
483   va_list va;
484   va_start(va, format);
485   int ret = vfprintf(stderr, format, va);
486   va_end(va);
487
488   debugPrintLock->unlock();
489
490   return ret;
491 }
492
493 int stackwalk_printf_int(const char *format, ...)
494 {
495   if (!dyn_debug_stackwalk) return 0;
496   if (NULL == format) return -1;
497
498   debugPrintLock->lock();
499
500   fprintf(stderr, "[%ld]", getExecThreadID());
501   va_list va;
502   va_start(va, format);
503   int ret = vfprintf(stderr, format, va);
504   va_end(va);
505
506   debugPrintLock->unlock();
507
508   return ret;
509 }
510
511 int inst_printf_int(const char *format, ...)
512 {
513   if (!dyn_debug_inst) return 0;
514   if (NULL == format) return -1;
515
516   debugPrintLock->lock();
517
518   fprintf(stderr, "[%ld]", getExecThreadID());
519   va_list va;
520   va_start(va, format);
521   int ret = vfprintf(stderr, format, va);
522   va_end(va);
523
524   debugPrintLock->unlock();
525
526   return ret;
527 }
528
529 int reloc_printf_int(const char *format, ...)
530 {
531   if (!dyn_debug_reloc) return 0;
532   if (NULL == format) return -1;
533
534   debugPrintLock->lock();
535   
536   fprintf(stderr, "[%ld]", getExecThreadID());
537   va_list va;
538   va_start(va, format);
539   int ret = vfprintf(stderr, format, va);
540   va_end(va);
541
542   debugPrintLock->unlock();
543
544   return ret;
545 }
546
547 int dyn_unw_printf_int(const char *format, ...)
548 {
549   if (!dyn_debug_dyn_unw ) return 0;
550   if (NULL == format) return -1;
551
552   debugPrintLock->lock();
553   
554   fprintf(stderr, "[%ld]", getExecThreadID());
555   va_list va;
556   va_start(va, format);
557   int ret = vfprintf(stderr, format, va);
558   va_end(va);
559
560   debugPrintLock->unlock();
561
562   return ret;
563 }
564
565 int mutex_printf_int(const char *format, ...)
566 {
567   if (!dyn_debug_mutex ) return 0;
568   if (NULL == format) return -1;
569
570   debugPrintLock->lock();
571   
572   fprintf(stderr, "[%ld]", getExecThreadID());
573   va_list va;
574   va_start(va, format);
575   int ret = vfprintf(stderr, format, va);
576   va_end(va);
577
578   debugPrintLock->unlock();
579
580   return ret;
581 }
582
583 int catchup_printf_int(const char *format, ...)
584 {
585
586     if (!dyn_debug_catchup) return 0;
587     if (NULL == format) return -1;
588     
589     debugPrintLock->lock();
590     
591     fprintf(stderr, "[%ld]", getExecThreadID());
592     va_list va;
593     va_start(va, format);
594     int ret = vfprintf(stderr, format, va);
595     va_end(va);
596     
597     debugPrintLock->unlock();
598     
599     return ret;
600 }
601
602 int bpatch_printf(const char *format, ...)
603 {
604   if (!dyn_debug_bpatch) return 0;
605   if (NULL == format) return -1;
606
607   debugPrintLock->lock();
608   
609   fprintf(stderr, "[%ld]", getExecThreadID());
610   va_list va;
611   va_start(va, format);
612   int ret = vfprintf(stderr, format, va);
613   va_end(va);
614
615   debugPrintLock->unlock();
616
617   return ret;
618 }
619
620 int regalloc_printf_int(const char *format, ...)
621 {
622   if (!dyn_debug_regalloc) return 0;
623   if (NULL == format) return -1;
624
625   debugPrintLock->lock();
626   
627   fprintf(stderr, "[%ld]", getExecThreadID());
628   va_list va;
629   va_start(va, format);
630   int ret = vfprintf(stderr, format, va);
631   va_end(va);
632
633   debugPrintLock->unlock();
634
635   return ret;
636 }
637
638 int ast_printf_int(const char *format, ...)
639 {
640   if (!dyn_debug_ast) return 0;
641   if (NULL == format) return -1;
642
643   debugPrintLock->lock();
644   
645   fprintf(stderr, "[%ld]", getExecThreadID());
646   va_list va;
647   va_start(va, format);
648   int ret = vfprintf(stderr, format, va);
649   va_end(va);
650
651   debugPrintLock->unlock();
652
653   return ret;
654 }
655
656 int write_printf_int(const char *format, ...)
657 {
658   if (!dyn_debug_write) return 0;
659   if (NULL == format) return -1;
660
661   debugPrintLock->lock();
662   
663   if (!dyn_debug_write_file) {
664     if (dyn_debug_write_filename && strlen(dyn_debug_write_filename)) {
665       dyn_debug_write_file = fopen(dyn_debug_write_filename, "w");
666     }
667     if (!dyn_debug_write_file) {
668       dyn_debug_write_file = stderr;
669     }
670   }
671
672   va_list va;
673   va_start(va, format);
674   int ret = vfprintf(dyn_debug_write_file, format, va);
675   va_end(va);
676   fflush(dyn_debug_write_file);
677   
678   debugPrintLock->unlock();
679
680   return ret;
681 }
682
683
684 int infmalloc_printf_int(const char *format, ...)
685 {
686   if (!dyn_debug_infmalloc) return 0;
687   if (NULL == format) return -1;
688
689   debugPrintLock->lock();
690   
691   fprintf(stderr, "[%ld]", getExecThreadID());
692   va_list va;
693   va_start(va, format);
694   int ret = vfprintf(stderr, format, va);
695   va_end(va);
696
697   debugPrintLock->unlock();
698
699   return ret;
700 }
701
702
703 StatContainer stats_instru;
704 StatContainer stats_ptrace;
705 StatContainer stats_parse;
706 StatContainer stats_codegen;
707
708 TimeStatistic running_time;
709
710 bool have_stats = 0;
711
712 bool init_stats() {
713     char *p;
714     running_time.start();
715
716     if ((p = getenv("DYNINST_STATS_INST"))) {
717         fprintf(stderr, "Enabling DyninstAPI instrumentation statistics\n");
718         stats_instru.add(INST_GENERATE_TIMER, TimerStat);
719         stats_instru.add(INST_INSTALL_TIMER, TimerStat);
720         stats_instru.add(INST_LINK_TIMER, TimerStat);
721         stats_instru.add(INST_REMOVE_TIMER, TimerStat);
722         stats_instru.add(INST_GENERATE_COUNTER, CountStat);
723         stats_instru.add(INST_INSTALL_COUNTER, CountStat);
724         stats_instru.add(INST_LINK_COUNTER, CountStat);
725         stats_instru.add(INST_REMOVE_COUNTER, CountStat);
726         have_stats = true;
727     }
728     
729
730     if ((p = getenv("DYNINST_STATS_PTRACE"))) {
731         fprintf(stderr, "Enabling DyninstAPI ptrace statistics\n");
732         stats_ptrace.add(PTRACE_WRITE_TIMER, TimerStat);
733         stats_ptrace.add(PTRACE_READ_TIMER, TimerStat);
734
735         stats_ptrace.add(PTRACE_WRITE_COUNTER, CountStat);
736         stats_ptrace.add(PTRACE_READ_COUNTER, CountStat);
737
738         stats_ptrace.add(PTRACE_WRITE_AMOUNT, CountStat);
739         stats_ptrace.add(PTRACE_READ_AMOUNT, CountStat);
740         have_stats = true;
741     }
742     
743     if ((p = getenv("DYNINST_STATS_PARSING"))) {
744         fprintf(stderr, "Enabling DyninstAPI parsing statistics\n");
745         stats_parse.add(PARSE_SYMTAB_TIMER, TimerStat);
746         stats_parse.add(PARSE_ANALYZE_TIMER, TimerStat);
747         have_stats = true;
748     }
749
750     if ((p = getenv("DYNINST_STATS_CODEGEN"))) {
751         fprintf(stderr, "Enabling DyninstAPI code generation statistics\n");
752
753         stats_codegen.add(CODEGEN_AST_TIMER, TimerStat);
754         stats_codegen.add(CODEGEN_AST_COUNTER, CountStat);
755         stats_codegen.add(CODEGEN_REGISTER_TIMER, TimerStat);
756         stats_codegen.add(CODEGEN_LIVENESS_TIMER, TimerStat);
757         have_stats = true;
758     }
759     return have_stats;
760 }
761
762 bool print_stats() {
763     char *p;
764
765     running_time.stop();
766     if (have_stats) 
767         fprintf(stderr, "Running time: %f sec (user), %f sec (system), %f sec (wall)\n",
768                 running_time.usecs(),
769                 running_time.ssecs(),
770                 running_time.wsecs());
771     running_time.start();
772
773     if ((p = getenv("DYNINST_STATS_INST"))) {
774         fprintf(stderr, "Printing DyninstAPI instrumentation statistics\n");
775         fprintf(stderr, "  Generation: %ld calls, %f sec (user), %f sec (system), %f sec (wall)\n",
776                 stats_instru[INST_GENERATE_COUNTER]->value(),
777                 stats_instru[INST_GENERATE_TIMER]->usecs(),
778                 stats_instru[INST_GENERATE_TIMER]->ssecs(),
779                 stats_instru[INST_GENERATE_TIMER]->wsecs());
780         fprintf(stderr, "  Installation: %ld calls, %f sec (user), %f sec (system), %f sec (wall)\n",
781                 stats_instru[INST_INSTALL_COUNTER]->value(),
782                 stats_instru[INST_INSTALL_TIMER]->usecs(),
783                 stats_instru[INST_INSTALL_TIMER]->ssecs(),
784                 stats_instru[INST_INSTALL_TIMER]->wsecs());
785         fprintf(stderr, "  Linking: %ld calls, %f sec (user), %f sec (system), %f sec (wall)\n",
786                 stats_instru[INST_LINK_COUNTER]->value(),
787                 stats_instru[INST_LINK_TIMER]->usecs(),
788                 stats_instru[INST_LINK_TIMER]->ssecs(),
789                 stats_instru[INST_LINK_TIMER]->wsecs());
790         fprintf(stderr, "  Removal: %ld calls, %f sec (user), %f sec (system), %f sec (wall)\n",
791                 stats_instru[INST_REMOVE_COUNTER]->value(),
792                 stats_instru[INST_REMOVE_TIMER]->usecs(),
793                 stats_instru[INST_REMOVE_TIMER]->ssecs(),
794                 stats_instru[INST_REMOVE_TIMER]->wsecs());
795     }
796
797     if ((p = getenv("DYNINST_STATS_PTRACE"))) {
798         fprintf(stderr, "Printing DyninstAPI ptrace statistics\n");
799         fprintf(stderr, "  Write: %ld calls, %ld bytes, %f sec (user), %f sec (system), %f sec (wall)\n",
800                 stats_ptrace[PTRACE_WRITE_COUNTER]->value(),
801                 stats_ptrace[PTRACE_WRITE_AMOUNT]->value(),
802                 stats_ptrace[PTRACE_WRITE_TIMER]->usecs(),
803                 stats_ptrace[PTRACE_WRITE_TIMER]->ssecs(),
804                 stats_ptrace[PTRACE_WRITE_TIMER]->wsecs());
805
806         fprintf(stderr, "  Read: %ld calls, %ld bytes, %f sec (user), %f sec (system), %f sec (wall)\n",
807                 stats_ptrace[PTRACE_READ_COUNTER]->value(),
808                 stats_ptrace[PTRACE_READ_AMOUNT]->value(),
809                 stats_ptrace[PTRACE_READ_TIMER]->usecs(),
810                 stats_ptrace[PTRACE_READ_TIMER]->ssecs(),
811                 stats_ptrace[PTRACE_READ_TIMER]->wsecs());
812     }
813
814     if ((p = getenv("DYNINST_STATS_PARSING"))) {
815         fprintf(stderr, "Printing DyninstAPI parsing statistics\n");
816         fprintf(stderr, "  Symtab parsing:  %f sec (user), %f sec (system), %f sec (wall)\n",
817                 stats_parse[PARSE_SYMTAB_TIMER]->usecs(),
818                 stats_parse[PARSE_SYMTAB_TIMER]->ssecs(),
819                 stats_parse[PARSE_SYMTAB_TIMER]->wsecs());
820         fprintf(stderr, "  Analysis:  %f sec (user), %f sec (system), %f sec (wall)\n",
821                 stats_parse[PARSE_ANALYZE_TIMER]->usecs(),
822                 stats_parse[PARSE_ANALYZE_TIMER]->ssecs(),
823                 stats_parse[PARSE_ANALYZE_TIMER]->wsecs());
824     }
825
826     if ((p = getenv("DYNINST_STATS_CODEGEN"))) {
827         fprintf(stderr, "Printing DyninstAPI code generation statistics\n");
828         fprintf(stderr, "  AST generation: %ld calls, %f sec (user), %f sec (system), %f sec (wall)\n",
829                 stats_codegen[CODEGEN_AST_COUNTER]->value(),
830                 stats_codegen[CODEGEN_AST_TIMER]->usecs(),
831                 stats_codegen[CODEGEN_AST_TIMER]->ssecs(),
832                 stats_codegen[CODEGEN_AST_TIMER]->wsecs());
833
834         fprintf(stderr, "  Register allocation: %f sec (user), %f sec (system), %f sec (wall)\n",
835                 stats_codegen[CODEGEN_REGISTER_TIMER]->usecs(),
836                 stats_codegen[CODEGEN_REGISTER_TIMER]->ssecs(),
837                 stats_codegen[CODEGEN_REGISTER_TIMER]->wsecs());
838         
839         fprintf(stderr, "  Liveness analysis: %f sec (user), %f sec (system), %f sec (wall)\n",
840                 stats_codegen[CODEGEN_LIVENESS_TIMER]->usecs(),
841                 stats_codegen[CODEGEN_LIVENESS_TIMER]->ssecs(),
842                 stats_codegen[CODEGEN_LIVENESS_TIMER]->wsecs());
843     }
844     return true;
845 }
846