added attach command.
[dyninst.git] / dyner / src / dyner.C
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <tcl.h>
5
6 #if defined(i386_unknown_nt4_0)
7 #include <windows.h>
8 #include <winbase.h>
9 #else
10 #include <unistd.h>
11 #endif
12
13 #include "BPatch.h"
14 #include "BPatch_type.h"
15 #include "BPatch_Vector.h"
16 #include "BPatch_thread.h"
17 #include "BPatch_snippet.h"
18 #include "dynerList.h"
19 #include "breakpoint.h"
20
21 extern "C" {
22 #if !defined(i386_unknown_nt4_0)
23 #if defined(i386_unknown_linux2_0)
24         void usleep(unsigned int);
25 #else
26         int usleep(useconds_t);
27 #endif
28 #endif
29
30         void set_lex_input(char *s);
31         int dynerparse();
32 }
33
34 extern int dynerdebug;
35
36 int debugPrint = 0;
37 BPatch_point *targetPoint;
38 bool errorLoggingOff = false;
39
40 // control debug printf statements
41 #define dprintf if (debugPrint) printf
42
43 class ListElem {
44 public:
45     int                      number;
46     char                     *function;
47     BPatch_procedureLocation where;
48     BPatch_callWhen          when;
49     BPatchSnippetHandle      *handle;
50 };
51
52 class BPListElem: public ListElem {
53 public:
54     char                     *condition;
55     int                      lineNum;
56
57     BPListElem(int _number, char *_function, BPatch_procedureLocation _where,
58                BPatch_callWhen _when, char *_condition,
59                BPatchSnippetHandle *_handle, int _lineNum);
60     ~BPListElem();
61     void Print();
62 };
63
64 class runtimeVar {
65 public:
66     runtimeVar(BPatch_variableExpr *v, char *n) { var = v, name = strdup(n); }
67     BPatch_variableExpr *var;
68     char *name;
69     bool readValue(void *buf) { return var->readValue(buf); }
70 };
71
72 class IPListElem: public ListElem {
73 public:
74     char                     *statement;
75     bool                     trace;
76
77     IPListElem(int _number, char *_function, BPatch_procedureLocation _where,
78                BPatch_callWhen _when, char *_condition,
79                BPatchSnippetHandle *_handle, bool forTrace);
80     ~IPListElem();
81 };
82
83 BPatch *bpatch;
84 BPatch_thread *appThread = NULL;
85 BPatch_image *appImage = NULL;
86 static BPatch_variableExpr *bpNumber = NULL;
87 static int bpCtr = 1;
88 static int ipCtr = 1;
89 static DynerList<BPListElem *> bplist;
90 static DynerList<IPListElem *> iplist;
91 static DynerList<runtimeVar *> varList;
92
93
94 bool name2loc(char *s, BPatch_procedureLocation &where,
95               BPatch_callWhen &when)
96 {
97     if (!strcmp(s, "entry")) {
98         where = BPatch_entry;
99         when = BPatch_callBefore;
100     } else if (!strcmp(s, "exit")) {
101         where = BPatch_exit;
102         /* This is not supported anymore!
103         when = BPatch_callBefore;
104         */
105         when = BPatch_callAfter;
106     } else if (!strcmp(s, "preCall")) {
107         where = BPatch_subroutine;
108         when = BPatch_callBefore;
109     } else if (!strcmp(s, "postCall")) {
110         where = BPatch_subroutine;
111         when = BPatch_callAfter;
112     } else {
113         return false;
114     }
115     return true;
116 }
117
118 char *loc2name(BPatch_procedureLocation where, BPatch_callWhen when)
119 {
120     switch (where) {
121       case BPatch_entry:
122         return "entry";
123       case BPatch_exit:
124         return "exit";
125       case BPatch_subroutine:
126         if (when == BPatch_callBefore) return "preCall";
127         else return "postCall";
128       default:
129         return "<error>";
130     };
131 }
132
133 BPListElem::BPListElem(int _number, char *_function,
134     BPatch_procedureLocation _where, BPatch_callWhen _when, char *_condition,
135     BPatchSnippetHandle *_handle, int _lineNum)
136 {
137     number = _number;
138     function = strdup(_function);
139     where = _where;
140     when = _when;
141     if (_condition)
142         condition = strdup(_condition);
143     else
144         condition = NULL;
145     handle = _handle;
146     lineNum = _lineNum;
147 }
148
149 BPListElem::~BPListElem()
150 {
151     free(function);
152     if (condition) free(condition);
153 }
154
155 void BPListElem::Print()
156 {
157     printf("%2d: ", number);
158     if (lineNum) 
159         printf("%s:%d", function, lineNum);
160     else
161         printf("%s (%s)", function,
162                 loc2name(where, when));
163
164     if (condition)
165         printf(", condition %s\n", condition);
166     else
167         printf("\n");
168 }
169
170 IPListElem::IPListElem(int _number, char *_function,
171     BPatch_procedureLocation _where, BPatch_callWhen _when, char *_statement,
172     BPatchSnippetHandle *_handle, bool _trace)
173 {
174     number = _number;
175     function = strdup(_function);
176     where = _where;
177     when = _when;
178     statement = strdup(_statement);
179     handle = _handle;
180     trace = _trace;
181 }
182
183 IPListElem::~IPListElem()
184 {
185     free(function);
186     free(statement);
187     if (handle) {
188         if (appThread)
189                 appThread->deleteSnippet(handle);
190
191         delete handle;
192     }
193 }
194
195 BPListElem *findBP(int n)
196 {
197     DynerList<BPListElem *>::iterator i;
198
199     for (i = bplist.begin(); i != bplist.end(); i++) {
200         if ((*i)->number == n) return (*i);
201     }
202
203     return NULL;
204 }
205
206 int help(ClientData, Tcl_Interp *, int, char **)
207 {
208
209     printf("at <function> [entry|exit|preCall|postCall] <statement> - insert statement\n");
210     printf("at termination <statement> - Execute <statement> at program exit callback\n");
211     printf("attach <pid> <program> - attach dyner to a running program\n");
212     printf("declare <type> <variable> - create a new variable of type <type>\n");
213     printf("deletebreak <breakpoint number ...> - delete breakpoint(s)\n");
214     printf("break <function> [entry|exit|preCall|postCall] [<condition>] - set a (conditional)\n");
215     printf("     break point at specified points of <function>\n");
216     printf("break <file name:line number> [<condition>] - set an arbitrary (conditional) break\n");
217     printf("     point at <line number> of <file name>\n");
218     printf("listbreak - list break points\n");
219     printf("load <program> [arguments] [< filename] [> filename] - load a program\n");
220     printf("load library <lib name> - load a dynamically linked library\n");
221     printf("load source <C++ file name> - Create a dynamically linked library from a \n");
222     printf("     C++ source file and load it to address space. All the functions and variables \n");
223     printf("     in the source file will be available for instrumentation\n");
224     printf("run - run or continue the loaded program\n");
225     printf("show [modules|functions|variables] - display module names, global functions\n");
226     printf("      and variables\n");
227     printf("show functions in <module> - display function names declared in <module>\n");
228     printf("show [parameters|variables] in <function> - display local variables or parameters of\n");
229     printf("     <function>\n");
230     printf("count <function> - At the end of execution display how many times <function> is called\n");
231     printf("replace function <function1> with <function2> - Replace all calls to <function1> with\n");
232     printf("     calls to <function2>\n");
233     printf("replace call <function1>[:n] with <function2> - All the calls or the nth function call \n");
234     printf("     in <function1> are/is changed to the function <function2>\n");
235     printf("trace <function> - Print a message at the entry and exit of <function>\n");
236     printf("trace functions in <module> - Print a message at the entry and exit of all functions\n");
237     printf("     declared in <module>\n");
238     printf("untrace <function> - Undo the effects of trace command for <function>\n");
239     printf("untrace functions in <module> - Undo the effects of trace command for all functions\n");
240     printf("     declared in <module>\n");
241     printf("mutations [enable|disable] - Enable or disable the execution of snippets\n");
242     printf("removecall <function>[:n] - Remove all the calls or n'th call in <function>\n");
243     //printf("dump <file name> - Write the in-memory version of the program to the specified file\n");
244     printf("detach - remove all the code inserted into target program\n");
245     printf("source <file name> - Execute dyner commands stored in the file <file name>\n");
246     printf("kill - Terminate the execution of target program\n");
247     printf("print <Variable> - Display the data type and value of dyner variable\n");
248     printf("whatis [-scope <function>] <variable> - Display detailed information about\n");
249     printf("     variables in the target program. Local variables and parameters are\n");
250     printf("     searched in the <function>.\n");
251     return TCL_OK;
252 }
253
254 bool haveApp()
255 {
256     if (appThread == NULL) {
257         fprintf(stderr, "No application loaded.\n");
258         return false;
259     }
260
261     if (appThread->isTerminated()) {
262         fprintf(stderr, "The application has exited.\n");
263         return false;
264     }
265
266     return true;
267 }
268
269 BPatch_module *FindModule(char *name) {
270
271     //Locate the module using module name 
272     BPatch_Vector<BPatch_module *> *modules = appImage->getModules();
273
274     if (!modules) {
275         printf("Can not get module info !\n");
276         return NULL;
277     }
278
279     char modName[1024];
280     BPatch_module *module = NULL;
281
282     for(int i=0; i<modules->size(); ++i) {
283         (*modules)[i]->getName(modName, 1024);
284
285         if (!strcmp(modName, name)) {
286                 module = (*modules)[i];
287                 break;
288         }
289     }
290
291     if (!module) {
292         printf("Module %s is not found !\n", name);
293         return NULL;
294     }
295
296     return module;
297 }
298
299 int loadApp(char *pathname, char **args)
300 {
301     printf("Loading \"%s\"\n", pathname);
302
303     if (appThread != NULL) delete appThread;
304     bplist.clear();
305     iplist.clear();
306     varList.clear();
307     appThread = bpatch->createProcess(pathname, args);
308     bpNumber = NULL;
309
310     if (!appThread || appThread->isTerminated()) {
311         fprintf(stderr, "Unable to run test program.\n");
312         appThread = NULL;
313         return TCL_ERROR;
314     }
315
316     // Read the program's image and get an associated image object
317     appImage = appThread->getImage();
318
319     if (!appImage) return TCL_ERROR;
320
321     //Create type info
322     appImage->getModules();
323
324     return TCL_OK;
325
326 }
327
328
329 int loadLib(char *libName) {
330     if (!haveApp()) return TCL_ERROR;
331
332     if (appThread->loadLibrary(libName))
333         return TCL_OK;
334
335     return TCL_ERROR;
336 }
337
338 int loadSource(char *inp) {
339     if (!haveApp()) return TCL_ERROR;
340
341     //Create shared object file name
342     char *ptr = strrchr(inp, '/');
343     if (ptr)
344         ptr++;
345     else
346         ptr = inp;
347
348     char fname[1024];
349     sprintf(fname, "./%s", ptr);
350
351     ptr = strrchr(fname+2, '.'); //Ignore first 2 chars ('./')
352     if (ptr)
353         sprintf(ptr+1,"so");
354     else
355         strcat(fname,".so");
356
357     //First ensure that there is no .so file for the input file
358     unlink(fname);
359     
360     //Create a shared object from input file
361     char cmdBuf[1024];
362     sprintf(cmdBuf,"g++ -g -fPIC -shared -o %s %s", fname, inp);
363
364     system(cmdBuf);
365
366     //Test whether or not shared object is created
367     FILE *fp = fopen(fname,"rb");
368     if (!fp) {
369         printf("Error in compilation of %s\n", inp);
370         return TCL_ERROR;
371     }
372     fclose(fp);
373
374     //Now dynamically link the file
375     return loadLib(fname);
376 }
377
378 int loadCommand(ClientData, Tcl_Interp *, int argc, char *argv[])
379 {
380     if (argc == 3) {
381         if (!strcmp(argv[1], "library"))
382                 return loadLib(argv[2]);
383         if (!strcmp(argv[1], "source"))
384                 return loadSource(argv[2]);
385     }
386
387     if (argc < 2) {
388         printf("Usage load <program> [<arguments>]\n");
389         printf("or    load library <lib name>\n");
390         printf("or    load source <C++ file name>\n");
391         return TCL_ERROR;
392     }
393
394     return loadApp(argv[1], &argv[1]);
395 }
396
397 int attachPid(ClientData, Tcl_Interp *, int argc, char *argv[])
398 {
399     int pid;
400     char *pathName = "";
401
402     if ((argc < 2) || (argc > 3)) {
403         printf("Usage attach <pid> <program>\n");
404         return TCL_ERROR;
405     }
406
407     if (appThread != NULL) delete appThread;
408     bplist.clear();
409     iplist.clear();
410     varList.clear();
411
412     pid = atoi(argv[1]);
413     if (argc == 3) pathName = argv[2];
414
415     appThread = bpatch->attachProcess(pathName, pid);
416     bpNumber = NULL;
417
418     if (!appThread || !appThread->getImage() || appThread->isTerminated()) {
419         fprintf(stderr, "Unable to attach to pid %d\n", pid);
420         appThread = NULL;
421         return TCL_ERROR;
422     }
423
424     // Read the program's image and get an associated image object
425     appImage = appThread->getImage();
426
427     if (!appImage) return TCL_ERROR;
428
429     //Create type info
430     appImage->getModules();
431
432     return TCL_OK;
433 }
434
435
436 int listBreak(ClientData, Tcl_Interp *, int, char **)
437 {
438     if (!haveApp()) return TCL_ERROR;
439
440     BPListElem *curr;
441     DynerList<BPListElem *>::iterator i;
442
443     for (i = bplist.begin(); i != bplist.end(); i++) {
444         curr = (BPListElem *) *i;
445         curr->Print();
446     }
447
448     return TCL_OK;
449 }
450
451 int deleteBreak(ClientData, Tcl_Interp *, int argc, char *argv[])
452 {
453     if (!haveApp()) return TCL_ERROR;
454
455     if (argc < 2) {
456         printf("Specify breakpoint(s) to delete.\n");
457         return TCL_ERROR;
458     }
459
460     int ret = TCL_OK;
461     for (int j = 1; j < argc; j++) {
462         int n = atoi(argv[j]);
463
464         BPListElem *i = findBP(n);
465         if (i == NULL) {
466             printf("No such breakpoint: %d\n", n);
467             ret = TCL_ERROR;
468         } else {
469             appThread->deleteSnippet(i->handle);
470             bplist.erase(i);
471             delete i;
472             printf("Breakpoint %d deleted.\n", n);
473         }
474     }
475
476     return ret;
477 }
478
479 int runApp(ClientData, Tcl_Interp *, int, char **)
480 {
481     if (!haveApp()) return TCL_ERROR;
482
483     if (bpNumber) {
484         int inval = -1;
485         bpNumber->writeValue(&inval);
486     }
487
488     // Start of code to continue the process.
489     dprintf("starting program execution.\n");
490     appThread->continueExecution();
491
492     while (!appThread->isStopped() && !appThread->isTerminated())
493 #if defined(i386_unknown_nt4_0)
494         Sleep(1);
495 #else
496         usleep(250);
497 #endif
498
499     int bp = -1;
500     if (bpNumber) bpNumber->readValue(&bp);
501
502     if (appThread->isTerminated()) {
503         printf("\nApplication exited.\n");
504     } else if (appThread->isStopped() && bp > 0) {
505         printf("\nStopped at break point %d.\n", bp);
506         ListElem *i = findBP(bp);
507         if (i != NULL) {
508             BPListElem *curr = (BPListElem *) i;
509             curr->Print();
510         }
511     } else {
512         printf("\nStopped.\n");
513     }
514
515     return TCL_OK;
516 }
517
518 int killApp(ClientData, Tcl_Interp *, int, char **)
519 {
520     if (!haveApp()) return TCL_ERROR;
521
522     appThread->terminateExecution();
523
524     return TCL_OK;
525 }
526
527 extern BPatch_snippet *parse_result;
528 int condBreak(ClientData, Tcl_Interp *, int argc, char *argv[])
529 {
530     if (argc < 2) {
531         printf("Usage: break <function> [entry|exit|preCall|postCall] [<condition>]\n");
532         printf("or     break <file name:line number> [<condition>]\n");
533         return TCL_ERROR;
534     }
535
536     if (!haveApp()) return TCL_ERROR;
537
538     if (bpNumber == NULL) {
539         bpNumber = appThread->malloc(*appImage->findType("int"));
540         if (bpNumber == NULL) {
541             fprintf(stderr, "Unable to allocate memory in the inferior process.\n");
542             exit(1);
543         }
544     }
545
546     int expr_start = 2;
547     int lineNum = 0;
548     BPatch_procedureLocation where;
549     BPatch_callWhen when;
550
551     BPatch_Vector<BPatch_point *> *points;
552     char *ptr = strchr(argv[1],':');
553     if (ptr) {
554         //Arbitrary break point, first find module name
555         expr_start = 2;
556         where = BPatch_entry;
557         when = BPatch_callBefore;
558         *ptr = '\0';
559         lineNum = atoi(ptr+1);
560         BPatch_Vector<unsigned long> absAddrVec;
561
562         if (!appImage->getLineToAddr(argv[1], lineNum, absAddrVec, true)) {
563                 printf("Can not get arbitrary break point address!\n");
564                 return TCL_ERROR;
565         }
566         points = new BPatch_Vector<BPatch_point *>;
567         //Find BPatch_point from the first absolute address
568         points->push_back(appImage->createInstPointAtAddr((void *)absAddrVec[0]));
569     }
570     else {
571         if ( (argc > 2) && name2loc(argv[2], where, when)) {
572                 expr_start = 3;
573         } else {
574                 where = BPatch_entry;
575                 when = BPatch_callBefore;
576         }
577
578         points = appImage->findProcedurePoint(argv[1], where);
579
580         if (points == NULL) {
581                 printf("Unable to locate function %s\n", argv[1]);
582                 return TCL_ERROR;
583         }
584     }
585
586     char *line_buf = NULL;
587
588     if (argc > 3) {
589         // Count up how large a buffer we need for the whole line
590         int line_len = 0;
591         int i = 0;
592         for (i = expr_start; i < argc; i++)
593                 line_len += strlen(argv[i]) + 1;
594         line_len++;
595         // Make the buffer and copy the line into it
596         line_buf = new char[line_len];
597         *line_buf = '\0';
598         for (i = expr_start; i < argc; i++) {
599                 strcat(line_buf, argv[i]);
600                 if (i != argc-1) strcat(line_buf, " ");
601         }
602
603         set_lex_input(line_buf);
604         if (dynerparse() != 0) {
605                 fprintf(stderr, "Breakpoint not set due to error.\n");
606                 delete line_buf;
607                 return TCL_ERROR;
608         }
609
610         if (parse_type != parsed_bool) {
611                 fprintf(stderr, "Breakpoint not set due error, expression not boolean.\n");
612                 delete line_buf;
613                 delete parse_result;
614                 return TCL_ERROR;
615         }
616     }
617
618     // Make a snippet to tell us which breakpoint it is
619     BPatch_arithExpr storeBPNum(BPatch_assign,
620                                 *bpNumber, BPatch_constExpr(bpCtr));
621
622     // Make a snippet to break at the breakpoint
623     BPatch_function *breakFunc = appImage->findFunction("DYNINSTbreakPoint");
624     if (breakFunc == NULL) {
625         fprintf(stderr, "Unable to find function DYNINSTbreakPoint (required for setting break points)\n");
626         if (argc > 3) {
627                 delete parse_result;
628                 delete line_buf;
629         }
630         return TCL_ERROR;
631     }
632
633     BPatch_Vector<BPatch_snippet *> nullArgs;
634     BPatch_funcCallExpr callBreak(*breakFunc, nullArgs);
635
636     // store the break point number, then  break
637     BPatch_arithExpr doBreak(BPatch_seq, storeBPNum, callBreak);
638     
639     BPatch_snippet *brSnippet = (BPatch_snippet *) &doBreak;
640
641     if (argc > 3) {
642         // Call the break snippet conditionally
643         BPatch_ifExpr condBreak(*(BPatch_boolExpr *)parse_result, doBreak); 
644         brSnippet = (BPatch_snippet *) &condBreak; 
645         delete parse_result;
646         delete line_buf;
647     }
648
649     BPatchSnippetHandle *handle =
650         appThread->insertSnippet(*brSnippet, *points, when,BPatch_lastSnippet);
651     if (handle == 0) {
652         fprintf(stderr, "Error inserting snippet.\n");
653         if (line_buf) delete line_buf;
654         return TCL_ERROR;
655     }
656
657     BPListElem *bpl =
658         new BPListElem(bpCtr, argv[1], where, when, line_buf, handle, lineNum);
659     if (line_buf) delete line_buf;
660
661     bplist.push_back(bpl);
662
663     printf("Breakpoint %d set.\n", bpCtr);
664     bpCtr++;
665
666     return TCL_OK;
667 }
668 /*
669  * void printPtr( )
670  *
671  * This function recursively goes through the BPatch_type pointers until
672  * it gets to the base type and prints that name.  The base type can be
673  * a builtin type or an enum, struct, or union.  The default case handles
674  * unknown pointer types.  -- jdd 5/27/99
675  */
676 void printPtr( BPatch_type * type )
677 {
678   if( type->getDataClass() == BPatch_pointer ){
679     printPtr( type->getConstituentType() );
680     printf("*");
681   }
682   else if((type->getDataClass() == BPatch_scalar)||(type->getDataClass() == BPatch_built_inType)||
683         (type->getDataClass() == BPatchSymTypeRange)){
684     printf("%s ", type->getName());
685   }
686   else{
687     switch( type->getDataClass() ){
688     case BPatch_enumerated:
689       printf("enum %s ", type->getName());
690       break;
691     case BPatch_structure:
692       printf("struct %s ", type->getName());
693       break;
694     case BPatch_union:
695       printf("union %s ", type->getName());
696       break;
697     default:
698       printf("Undefined POINTER: %s", type->getName());
699       break;
700     }
701   }
702   
703 }
704 /*
705  * printArray()
706  *
707  * This function prints arrays of various dimension, 1D to 3D. It first
708  * checks how many dimensions the array is and then prints it out.
709  * The default case handles the unknown. --jdd 5/27/99
710  */
711  
712 void printArray(BPatch_type * type )
713 {
714   int j = 0;
715   if(type->getConstituentType()){
716     j++;
717     if(type->getConstituentType()->getConstituentType()){
718       j++;
719       if(type->getConstituentType()->getConstituentType()->getConstituentType()){
720         j++;
721       }
722     }
723   }
724   switch(j){
725   case 3:
726     
727     //3D array
728     printf("    %s is an array [%s..%s][%s..%s][%s..%s] of %s\n",
729            type->getName(), type->getLow(), type->getHigh(),
730            type->getConstituentType()->getLow(),
731            type->getConstituentType()->getHigh(),
732            type->getConstituentType()->getConstituentType()->getLow(),
733            type->getConstituentType()->getConstituentType()->getHigh(),
734            type->getConstituentType()->getConstituentType()->getConstituentType()->getName());
735     break;
736   case 2:
737         
738     //2D array
739     printf("    %s is an array [%s..%s][%s..%s] of %s\n", type->getName(), 
740            type->getLow(), type->getHigh(),
741            type->getConstituentType()->getLow(),
742            type->getConstituentType()->getHigh(),
743            type->getConstituentType()->getConstituentType()->getName());
744     break;
745   case 1:
746     printf("    %s is an array [%s..%s] of %s\n", type->getName(),
747            type->getLow(), type->getHigh(), 
748            type->getConstituentType()->getName());
749     break;
750   default:
751     printf("Unable to process array %s\n", type->getName());
752     break;
753   }
754 }
755
756 BPatch_snippet *termStatement = NULL;
757
758 void exitCallback(BPatch_thread *thread, int) {
759     if (termStatement == NULL)
760         return;
761
762     BPatch_snippet *stmt = termStatement;
763     termStatement = NULL;
764     thread->oneTimeCode(*stmt);
765     delete stmt;
766 }
767
768 int instTermStatement(int argc, char *argv[])
769 {
770     int expr_start = 2;
771
772     // Count up how large a buffer we need for the whole line
773     int line_len = 0;
774     int i = 0;
775     for (i = expr_start; i < argc; i++)
776         line_len += strlen(argv[i]) + 1;
777     line_len += 2;
778     // Make the buffer and copy the line into it
779     char *line_buf = new char[line_len];
780     *line_buf = '\0';
781     for (i = expr_start; i < argc; i++) {
782         strcat(line_buf, argv[i]);
783         if (i != argc-1) strcat(line_buf, " ");
784     }
785     strcat(line_buf, "\n");
786
787     // printf("calling parse of %s\n", line_buf);
788     set_lex_input(line_buf);
789     if (dynerparse() != 0) {
790         fprintf(stderr, "Instrumentation not set due to error.\n");
791         delete line_buf;
792         return TCL_ERROR;
793     }
794
795     if (parse_type != parsed_statement) {
796         fprintf(stderr, "code not inserted, expression is not a statement.\n");
797         delete line_buf;
798         delete parse_result;
799         return TCL_ERROR;
800     }
801
802     termStatement = parse_result;
803     return TCL_OK;
804 }
805
806 int instStatement(ClientData, Tcl_Interp *, int argc, char *argv[])
807 {
808     if (!haveApp()) return TCL_ERROR;
809
810     if (argc < 3) {
811         printf("Usage: at <function> [entry|exit|preCall|postCall] <statement>\n");
812         printf("or     at termination <statement>\n");
813         return TCL_ERROR;
814     }
815
816     if (!strcmp(argv[1], "termination"))
817         return instTermStatement(argc, argv);
818
819     int expr_start = 2;
820     BPatch_procedureLocation where;
821     BPatch_callWhen when;
822
823     if (name2loc(argv[2], where, when)) {
824         expr_start = 3;
825     } else {
826         where = BPatch_entry;
827         when = BPatch_callBefore;
828     }
829
830     BPatch_function *func = appImage->findFunction(argv[1]);
831     if (func == NULL) {
832         fprintf(stderr, "Unable to locate function: %s\n", argv[1]);
833         return TCL_ERROR;
834     }
835
836     BPatch_Vector<BPatch_point *> *points = func->findPoint(where);
837                                 // appImage->findProcedurePoint(argv[1], where);
838
839     if (points == NULL) {
840         fprintf(stderr, "Unable to locate function: %s\n", argv[1]);
841         return TCL_ERROR;
842     }
843
844     //Assign targetPoint using function entry point
845     targetPoint = (*(func->findPoint(BPatch_entry)))[0];
846
847     bool trace = false;
848     if (!strcmp(argv[argc-1], "trace")) {
849         //This statement is used for tracing the functions
850         trace = true;
851         argc--;
852     }
853
854     // Count up how large a buffer we need for the whole line
855     int line_len = 0;
856     int i = 0;
857     for (i = expr_start; i < argc; i++)
858         line_len += strlen(argv[i]) + 1;
859     line_len += 2;
860     // Make the buffer and copy the line into it
861     char *line_buf = new char[line_len];
862     *line_buf = '\0';
863     for (i = expr_start; i < argc; i++) {
864         strcat(line_buf, argv[i]);
865         if (i != argc-1) strcat(line_buf, " ");
866     }
867     strcat(line_buf, "\n");
868
869     // printf("calling parse of %s\n", line_buf);
870     set_lex_input(line_buf);
871     if (dynerparse() != 0) {
872         fprintf(stderr, "Instrumentation not set due to error.\n");
873         delete line_buf;
874         targetPoint = NULL;
875         return TCL_ERROR;
876     }
877
878     targetPoint = NULL;
879
880     if (parse_type != parsed_statement) {
881         fprintf(stderr, "code not inserted, expression is not a statement.\n");
882         delete line_buf;
883         delete parse_result;
884         return TCL_ERROR;
885     }
886
887     BPatchSnippetHandle *handle =
888         appThread->insertSnippet(*parse_result, *points, when,BPatch_lastSnippet);
889     if (handle == 0) {
890         fprintf(stderr, "Error inserting snippet.\n");
891         delete line_buf;
892         return TCL_ERROR;
893     }
894
895     IPListElem *snl =
896         new IPListElem(ipCtr, argv[1], where, when, line_buf, handle, trace);
897     delete line_buf;
898
899     iplist.push_back(snl);
900
901     // printf("Inst point %d set.\n", ipCtr);
902     ipCtr++;
903
904     return TCL_OK;
905 }
906
907 void printVarRecursive(BPatch_variableExpr *var, int level)
908 {
909     int iVal;
910     int pVal;
911     float fVal;
912
913     BPatch_dataClass dc;
914     BPatch_type *type = (BPatch_type *) var->getType();
915
916     dc = type->getDataClass();
917     if (!strcmp(type->getName(), "int")) {
918         /* print out the integer */
919         var->readValue((void *) &iVal);
920         printf("%d\n", iVal);
921     } else if (!strcmp(type->getName(), "float")) {
922         /* print out the float */
923         var->readValue((void *) &fVal);
924         printf("%f\n", fVal);
925     } else if (dc == BPatch_pointer) {
926         /* print out the float */
927         var->readValue((void *) &pVal);
928         printf("0x%x\n", pVal);
929     } else if (dc == BPatch_structure) {
930         printf("struct {\n");
931         level++;
932         BPatch_Vector<BPatch_variableExpr *> *fields = var->getComponents();
933         for (int i=0; i < fields->size(); i++) {
934              BPatch_variableExpr *fieldVar = (*fields)[i];
935              for (int i=0;i < level; i++) printf("    ");
936              printf("%s = ", fieldVar->getName());
937              printVarRecursive(fieldVar, level);
938         }
939         level--;
940         printf("}\n");
941     } else if (dc == BPatch_array) {
942         printf("<arrays not yet implemented>\n");
943     } else {
944         printf("<unknown type>\n");
945     }
946 }
947
948 int printVar(ClientData, Tcl_Interp *, int, char *argv[])
949 {
950     //if (!haveApp()) return TCL_ERROR;
951
952     BPatch_variableExpr *var = findVariable(argv[1]);
953     if (!var) {
954         printf("%s is not defined\n", argv[1]);
955         return TCL_ERROR;
956     }
957
958     printf("    %s = ", argv[1]);
959     printVarRecursive(var, 1);
960
961     return TCL_OK;
962 }
963
964 /*
965  * declare <type> <variable name>
966  */
967 int newVar(ClientData, Tcl_Interp *, int argc, char *argv[])
968 {
969     if (argc != 3) {
970         printf("Usage: declare <type> <variable name>\n");
971         return TCL_ERROR;
972     }
973
974     if (!haveApp()) return TCL_ERROR;
975
976     BPatch_type *type = appImage->findType(argv[1]);
977     if (!type) {
978         printf("type %s is not defined\n", argv[1]);
979         return TCL_ERROR;
980     }
981
982     BPatch_variableExpr *newVar = appThread->malloc(*type);
983     if (!newVar) {
984         printf("Unable to create variable.\n");
985         return TCL_ERROR;
986     }
987
988     varList.push_back(new runtimeVar(newVar, argv[2]));
989
990     return TCL_OK;
991 }
992
993 BPatch_variableExpr *findVariable(char *name)
994 {
995     BPatch_variableExpr *var;
996     DynerList<runtimeVar *>::iterator i;
997
998     // First look for runtime created variables
999     for (i = varList.begin(); i != varList.end(); i++) {
1000         if (!strcmp(name, (*i)->name)) {
1001             var = new BPatch_variableExpr(*((*i)->var));
1002             return (var);
1003         }
1004     }
1005
1006     // Now check the function locals
1007     if (targetPoint) {
1008         var = appImage->findVariable(*targetPoint, name);
1009         if (var) return var;
1010     }
1011
1012     // Check global vars in the mutatee
1013     errorLoggingOff = true;
1014     var = appImage->findVariable(name);
1015     errorLoggingOff = false;
1016
1017     if (var) return var;
1018
1019     printf("Unable to locate variable %s\n", name);
1020     return NULL;
1021 }
1022
1023 /* 
1024  * int whatisParam()
1025  *
1026  * This function is an extension to the "whatis" command.  This function
1027  * processes the command: whatis -scope <function> <variable>. If the
1028  * <function> is undefined then TCL_ERROR is returned.  Otherwise, the
1029  * local variable collection is searched first; followed by the parameter
1030  * collection; and finally the Global collection is searched last. If the
1031  * <variable> is not found, then "<variable> is not defined" is reported
1032  * to the user. --jdd 5/27/98
1033  */
1034 int whatisParam(ClientData, Tcl_Interp *, int, char *argv[])
1035 {
1036   if (!haveApp()) return TCL_ERROR;
1037   BPatch_function * func = appImage->findBPFunction(argv[2]);
1038   //printf("func is %x\n", func);
1039   if(!func){
1040     printf("%s is not defined\n", argv[3]);
1041     return TCL_ERROR;
1042   }
1043   
1044   
1045   BPatch_localVar * lvar = func->findLocalVar(argv[3]);
1046   if(lvar){
1047     BPatch_type *type = lvar->getType();
1048     if( type ){
1049       switch (type->getDataClass()) {
1050       case BPatch_array:
1051         printArray( type );
1052         break;
1053         
1054       case BPatch_pointer:
1055         printPtr( type );
1056         printf("\t %s\n", argv[3]);
1057         break;
1058         
1059       default:
1060         printf("    %s is of type %s \n", argv[3], type->getName());
1061         break;
1062       }
1063     }
1064     //print local variable info
1065     printf("        %s is a local variable in function %s\n", lvar->getName(),
1066            argv[2]);
1067     printf("        Declared on line %d and has a Frame offset of %d\n",
1068            lvar->getLineNum(), lvar->getFrameOffset());
1069   }
1070   else{
1071     lvar = func->findLocalParam(argv[3]);
1072     
1073     if (!lvar) {
1074       BPatch_variableExpr *var = findVariable(argv[3]);
1075       if(!var){
1076         // do something else ??
1077         //int ret = whatisType(cd, interp, argc, argv);
1078         return TCL_OK;
1079       }
1080       BPatch_type *type = (BPatch_type *) var->getType();
1081       switch (type->getDataClass()) {
1082       case BPatch_array:
1083         printArray( type );
1084         break;
1085         
1086       case BPatch_pointer:
1087         printPtr( type );
1088         printf("\t %s\n", argv[3]);
1089         break;
1090         
1091       default:
1092         printf("    %s is of type %s \n", argv[3], type->getName());
1093         break;
1094       }
1095      printf("      %s is a Global variable\n", argv[3]);
1096     }
1097     else{
1098       BPatch_type *lType = (BPatch_type *) lvar->getType();
1099       if (lType){
1100         switch (lType->getDataClass()) {
1101         case BPatch_array:
1102           printArray( lType );
1103           break;
1104           
1105         case BPatch_pointer:
1106           printPtr( lType );
1107           printf("\t %s\n", argv[3]);
1108           break;
1109           
1110         default:
1111           printf("    %s is of type %s \n", argv[3], lType->getName());
1112           break;
1113         }
1114         printf("       %s is a parameter of the function %s\n",lvar->getName(),
1115            argv[2]);
1116         printf("       Declared on line %d and has a Frame offset of %d\n",
1117            lvar->getLineNum(), lvar->getFrameOffset());
1118       }
1119       else{
1120         printf("   unknown type %s\n", lvar->getName());
1121       }
1122     }   
1123   }
1124   return TCL_OK;
1125 }
1126
1127 /*
1128  * int whatisFunc()
1129  *
1130  * This function is an extension to the "whatis" command.  This function
1131  * searches all of the modules to find the BPatch_function with the name
1132  * given be argv[1]. If no such function is found, then TCL_ERROR is returned.
1133  * This is the last function in the chain of "whatis" command functions to
1134  * be executed in the search for argv[1]. --jdd 5/27/99
1135  */
1136  
1137 int whatisFunc(ClientData, Tcl_Interp *, int, char *argv[])
1138 {
1139     if (!haveApp()) return TCL_ERROR;
1140     // If the function is found it returns the BPatch_function.
1141     // findFunction() creates a new BPatch_function so it is not
1142     // used here. --jdd 5/27/99
1143     BPatch_function * func = appImage->findBPFunction(argv[1]);
1144     
1145     if(!func){
1146       printf("%s is not defined\n", argv[1]);
1147       return TCL_ERROR;
1148     }
1149     printf("    Function %s ", argv[1]);
1150     BPatch_type * retType = func->getReturnType();
1151     if(retType)
1152       switch(retType->getDataClass()){
1153       case BPatch_scalar:
1154       case BPatch_built_inType:
1155       case BPatchSymTypeRange:
1156         printf("  with return type %s\n",retType->getName() );
1157         break;
1158       case BPatch_array:
1159         printf("  with return type ");
1160         printArray( retType );
1161         printf("\n");
1162         break;
1163           
1164       case BPatch_pointer:
1165         printf("  with return type ");
1166         printPtr( retType );
1167         printf("\n");
1168         break;
1169         
1170       default:
1171         printf("    %s has unknown return type %s %d\n",argv[1],
1172                retType->getName(), retType->getID());
1173         break;
1174       }
1175     else
1176       printf("   unknown return type for %s\n", argv[1]);
1177     BPatch_Vector<BPatch_localVar *> *params = func->getParams();
1178     if( params->size())
1179       printf("        Parameters: \n");
1180     for (int i=0; i < params->size(); i++) {
1181       BPatch_localVar *localVar = (*params)[i];
1182       BPatch_type *lType = (BPatch_type *) localVar->getType();
1183       if (lType){
1184         if( (lType->getDataClass())  == BPatch_pointer){
1185           printPtr(lType);
1186           printf(" \t %s\n", localVar->getName());
1187         }
1188         else if( (lType->getDataClass()) == BPatch_array){
1189           printArray( lType );
1190         }
1191         else
1192           printf("        %s %s\n",lType->getName(), localVar->getName());
1193         
1194       }
1195       else{
1196         printf("   unknown type %s\n", localVar->getName());
1197       }
1198     }    
1199     return TCL_OK;
1200 }
1201
1202 /*
1203  * int whatisType()
1204  *
1205  * This function is an extension to the "whatis" command.  This function
1206  * searches for the type collection of the all the modules looking for
1207  * the type specified by argv[1]. If it is not found, then whatisFunc()
1208  * is called. This is function is called by whatisVar if a variable is
1209  * not found. -- jdd 5/27/99
1210  */
1211  
1212 int whatisType(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
1213 {
1214     if (!haveApp()) return TCL_ERROR;
1215     
1216     BPatch_type *type = appImage->findType(argv[1]);
1217     if (!type) {
1218       int ret = whatisFunc(cd, interp, argc, argv);
1219       return ret;
1220     }
1221
1222     BPatch_dataClass dc = type->getDataClass();
1223     switch (dc) {
1224     case BPatch_structure: {
1225       printf("    struct %s {\n", argv[1]);
1226       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1227       for (int i=0; i < fields->size(); i++) {
1228         BPatch_field *field = (*fields)[i];
1229         BPatch_type *fType = (BPatch_type *) field->getType();
1230         if (fType){
1231           switch (fType->getDataClass()) {
1232           case BPatch_array:
1233             printArray( fType );
1234             printf("  %s\n", field->getName());
1235             break;
1236         
1237           case BPatch_pointer:
1238             printPtr( fType );
1239             printf("  %s\n", field->getName());
1240             break;
1241         
1242           default:
1243             printf("        %s %s\n", fType->getName(), field->getName());
1244             break;
1245           }
1246         }
1247         else{
1248           printf("   unknown type %s\n", field->getName());
1249         }
1250       }
1251       printf("    }\n");
1252       break;
1253     }
1254     case BPatch_union: {
1255       printf("    union %s {\n", argv[1]);
1256       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1257       for (int i=0; i < fields->size(); i++) {
1258         BPatch_field *field = (*fields)[i];
1259         BPatch_type *fType = (BPatch_type *) field->getType();
1260         if (fType){
1261           switch (fType->getDataClass()) {
1262           case BPatch_array:
1263             printArray( fType );
1264             printf("  %s\n", field->getName());
1265             break;
1266         
1267           case BPatch_pointer:
1268             printPtr( fType );
1269             printf("  %s\n", field->getName());
1270             break;
1271             
1272           default:
1273             printf("        %s %s\n", fType->getName(), field->getName());
1274             break;
1275           }
1276         }
1277         else{
1278           printf("        unknown type %s\n", field->getName());
1279         }
1280       }
1281       printf("    }\n");
1282       break;
1283     }
1284     case BPatch_enumerated: {
1285       printf("    enum %s {\n", argv[1]);
1286       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1287       for (int i=0; i < fields->size(); i++) {
1288         BPatch_field *field = (*fields)[i];
1289         printf("        %s    \t%d\n", field->getName(),
1290                field->getValue());
1291       }
1292       printf("    }\n");
1293       break;
1294     }
1295     case BPatch_array:
1296       printArray( type );
1297       break;
1298       
1299     case BPatch_scalar:
1300     case BPatch_built_inType:
1301       printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1302       break;
1303       
1304     case BPatch_pointer:
1305       printPtr( type );
1306       printf("\t %s\n", argv[1]);
1307       /*
1308       printf("    %s is pointer to type %s\n", argv[1], 
1309              type->getConstituentType()->getName());*/
1310       break;
1311     case BPatchSymTypeRange:
1312       if(type->getConstituentType())
1313         printf("    %s is a %s of size %d\n",argv[1],
1314                (type->getConstituentType())->getName(),type->getSize());
1315       else
1316         printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1317       if( type->getLow() ){
1318          printf("        with range %s to %s\n", type->getLow(),
1319                 type->getHigh());
1320       }
1321       break;
1322     default:
1323       printf("%s is of an unknown data class %d\n", argv[1],
1324              dc);
1325       break;
1326     }
1327     
1328     return TCL_OK;
1329 }
1330
1331 /*
1332  * int whatisVar()
1333  *
1334  * This function is an extension to the "whatis" command.  This function
1335  * searches the process for the variable named by argv[1] and then searches
1336  * all the Global variables for all the modules to find the variable
1337  * specified by argv[1].  If nothing is found, then whatisType() is called. If
1338  * whatisType() finds nothing, whatisFunc() is called.  If the command is
1339  * of the form "whatis -scope <function> <variable>", then whatisParam() is
1340  * called skipping all other attempts to find the variable. -- jdd 5/27/99
1341  */
1342
1343 int whatisVar(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
1344 {
1345     if (!haveApp()) return TCL_ERROR;
1346     
1347     if (argc == 4){ //looking for a local variable
1348       if(!(strcmp(argv[1], "-scope"))){
1349         int ret = whatisParam(cd, interp, argc, argv );
1350         return ret;
1351       } else {
1352         printf("inavlid argument %s\n", argv[1]);
1353         return TCL_ERROR;
1354       }
1355     }
1356
1357     BPatch_variableExpr *var = findVariable(argv[1]);
1358     if (!var) {
1359         int ret = whatisType(cd, interp, argc, argv);
1360         return ret;
1361     }
1362
1363     BPatch_type *type = (BPatch_type *) var->getType();
1364     switch (type->getDataClass()) {
1365     case BPatch_structure: {
1366       printf("    struct %s {\n", argv[1]);
1367       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1368       for (int i=0; i < fields->size(); i++) {
1369         BPatch_field *field = (BPatch_field *) (*fields)[i];
1370         BPatch_type *fType = (BPatch_type *) field->getType();
1371         if (fType){
1372           printf("        %s %s\n", fType->getName(), field->getName());
1373         }
1374         else{
1375           printf("   unknown type %s\n", field->getName());
1376         }
1377       }
1378       printf("    }\n");
1379       break;
1380     }
1381     case BPatch_union: {
1382       printf("    union %s {\n", argv[1]);
1383       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1384       for (int i=0; i < fields->size(); i++) {
1385         BPatch_field *field = (*fields)[i];
1386         BPatch_type *fType = (BPatch_type *) field->getType();
1387         if (fType){
1388           printf("        %s %s\n", fType->getName(), field->getName());
1389         }
1390         else{
1391           printf("        unknown type %s\n", field->getName());
1392         }
1393       }
1394       printf("    }\n");
1395       break;
1396     }
1397     case BPatch_enumerated: {
1398       printf("    enum %s {\n", argv[1]);
1399       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1400       for (int i=0; i < fields->size(); i++) {
1401         BPatch_field *field = (*fields)[i];
1402         printf("        %s    \t%d\n", field->getName(),
1403                field->getValue());
1404       }
1405       printf("    }\n");
1406       break;
1407     }
1408     case BPatch_array:
1409       printArray(type);
1410       break;
1411    
1412     case BPatch_pointer:
1413       printPtr( type );
1414       printf("\t %s\n", argv[1]);
1415       /*
1416       printf("    %s is pointer to type %s\n", argv[1], 
1417              type->getConstituentType()->getName());*/
1418       break;
1419     case BPatchSymTypeRange:
1420       if(type->getConstituentType())
1421         printf("    %s is a %s of size %d\n",argv[1],
1422                (type->getConstituentType())->getName(),type->getSize());
1423       else
1424         printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1425       if( type->getLow() ){
1426         printf("        with range %s to %s\n", type->getLow(),
1427                type->getHigh());
1428       }
1429       break;
1430     case BPatch_scalar:
1431     case BPatch_built_inType:
1432       printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1433       break;
1434       
1435     default:
1436       printf("    %s is of type %s \n", argv[1], type->getName());
1437       //int ret = whatisType(cd, interp, argc, argv);
1438       break;
1439     }
1440     
1441     return TCL_OK;
1442 }
1443
1444 const int DYNINST_NO_ERROR = -1;
1445
1446 void errorFunc(BPatchErrorLevel level, int num, const char **params)
1447 {
1448     char line[256];
1449
1450     if (errorLoggingOff) return;
1451
1452     if ((num == 0) && ((level == BPatchWarning) || (level == BPatchInfo))) {
1453          // these are old warnings/status info from paradyn
1454          return;
1455     }
1456
1457     const char *msg = bpatch->getEnglishErrorString(num);
1458     bpatch->formatErrorString(line, sizeof(line), msg, params);
1459
1460     if (num != DYNINST_NO_ERROR) {
1461         printf("Error #%d (level %d): %s\n", num, level, line);
1462
1463         // We consider some errors fatal.
1464         if (num == 101) {
1465             exit(-1);
1466         }
1467     }
1468 }
1469
1470 /* This function prints type information. */
1471 void PrintTypeInfo(char *var, BPatch_type *type) {
1472       if (!type) {
1473         printf("NO RETURN TYPE INFO for %s\n", var);
1474         return;
1475       }
1476
1477       switch(type->getDataClass()){
1478       case BPatch_array:
1479         printArray( type );
1480         printf(" %s\n", var);
1481         break;
1482           
1483       case BPatch_pointer:
1484         printPtr( type );
1485         printf(" %s\n", var);
1486         break;
1487         
1488       default:
1489         printf("%s %s\n", type->getName(), var);
1490         break;
1491       }
1492 }
1493
1494 /* This function displays all the functions in the executable or the functions in a module
1495  * if a module name is provided.
1496  */
1497 int ShowFunctions(int argc, char *argv[]) {
1498     BPatch_Vector<BPatch_function *> *functions = NULL;
1499
1500     if (argc == 2) 
1501         functions = appImage->getProcedures();
1502     else if ( (argc == 4) && (!strcmp(argv[2], "in")) ) {
1503         BPatch_module *module = FindModule(argv[3]);
1504         if (!module)
1505                 return TCL_ERROR;
1506
1507         //Get the module functions
1508         functions = module->getProcedures();
1509     }
1510     else {
1511         printf("Syntax error !\n");
1512         return TCL_ERROR;
1513     }
1514
1515     if (!functions) {
1516         printf("Can not get function list!\n");
1517         return TCL_ERROR;
1518     }
1519
1520     //Now print all the functions in the module
1521     char funcName[1024];
1522     for(int i=0; i<functions->size(); ++i) {
1523         (*functions)[i]->getName(funcName, 1024);
1524         PrintTypeInfo(funcName, (*functions)[i]->getReturnType());
1525     }
1526
1527     return TCL_OK;
1528 }
1529
1530 /* Finds all the modules in the executable and displays the module names */
1531 int ShowModules()
1532 {
1533     char modName[1024];
1534     BPatch_Vector<BPatch_module *> *modules = appImage->getModules();
1535
1536     if (!modules) {
1537         printf("Can not get module info !\n");
1538         return TCL_ERROR;
1539     }
1540
1541     for(int i=0; i<modules->size(); ++i) {
1542         (*modules)[i]->getName(modName, 1024);
1543         printf("%s\n", modName);
1544     }
1545
1546     return TCL_OK;
1547 }
1548
1549 /*
1550  * This function finds and prints all the parameters
1551  * of a function whose name is given as input.
1552  */
1553 int ShowParameters(int argc, char *argv[]) {
1554     if ( (argc != 4) || (strcmp(argv[2], "in")) ) {
1555         printf("Usage: show parameters in <function>\n");
1556         return TCL_ERROR;
1557     }
1558
1559     BPatch_function *fp = appImage->findFunction(argv[3]);
1560
1561     if (!fp) {
1562         printf("Invalid function name: %s\n", argv[3]);
1563         return TCL_ERROR;
1564     }
1565
1566     BPatch_Vector<BPatch_localVar *> *params = fp->getParams();
1567     for(int i=0; i<params->size(); ++i) {
1568         PrintTypeInfo((char *) (*params)[i]->getName(), (*params)[i]->getType());
1569     }
1570
1571     return TCL_OK;
1572 }
1573
1574 /*
1575  * This function finds and prints all the local variables
1576  * of a function whose name is given as input.
1577  */
1578 int ShowLocalVars(char *funcName) {
1579     BPatch_function *fp = appImage->findFunction(funcName);
1580
1581     if (!fp) {
1582         printf("Invalid function name: %s\n", funcName);
1583         return TCL_ERROR;
1584     }
1585
1586     BPatch_Vector<BPatch_localVar *> *vars = fp->getVars();
1587     for(int i=0; i<vars->size(); ++i) {
1588         PrintTypeInfo((char *) (*vars)[i]->getName(), (*vars)[i]->getType());
1589     }
1590
1591     delete vars;
1592
1593     return TCL_OK;
1594 }
1595
1596 /* Finds all the global vars in the executable and prints their names. */
1597 int ShowGlobalVars() {
1598     BPatch_Vector<BPatch_variableExpr *> *vars = appImage->getGlobalVariables();
1599
1600     if (!vars) {
1601         printf("Can not get global variable info !\n");
1602         return TCL_ERROR;
1603     }
1604
1605     for(int i=0; i<vars->size(); ++i) {
1606         PrintTypeInfo((*vars)[i]->getName(), (BPatch_type *) (*vars)[i]->getType());
1607     }
1608
1609     return TCL_OK;
1610 }
1611
1612 /* Finds all global variables or local variables in the function */
1613 int ShowVariables(int argc, char *argv[])
1614 {
1615     if (argc == 2)
1616         return ShowGlobalVars();
1617
1618     if ( (argc == 4) && (!strcmp(argv[2], "in")) )
1619         return ShowLocalVars(argv[3]);
1620
1621     //Should not reach here!
1622     return TCL_ERROR;
1623 }
1624
1625 /* Displays either modules or functions in a specific module in the executable */
1626
1627 int showCommand(ClientData, Tcl_Interp *, int argc, char *argv[])
1628 {
1629     if (!haveApp()) return TCL_ERROR;
1630
1631     if (argc == 1) {
1632         printf("Usage: show [modules|functions|variables]\n");
1633         printf("or     show functions in <module>\n");
1634         printf("or     show [variables|parameters] in <function>\n");
1635         return TCL_ERROR;
1636     }
1637
1638     if (!strcmp(argv[1], "modules"))
1639         return ShowModules();
1640
1641     if (!strcmp(argv[1], "functions"))
1642         return ShowFunctions(argc, argv);
1643
1644     if (!strcmp(argv[1], "variables"))
1645         return ShowVariables(argc, argv);
1646
1647     if (!strcmp(argv[1], "parameters"))
1648         return ShowParameters(argc, argv);
1649
1650     printf("Syntax error!\n");
1651     return TCL_ERROR;
1652 }
1653
1654 /* Displays how many times input fcn is called */
1655 int countCommand(ClientData, Tcl_Interp *interp, int argc, char *argv[])
1656 {
1657     if (!haveApp()) return TCL_ERROR;
1658
1659     if (argc != 2) {
1660         printf("Usage: count <function>\n");
1661         return TCL_ERROR;
1662     }
1663
1664     BPatch_function *fp = appImage->findFunction(argv[1]);
1665
1666     if (!fp) {
1667         printf("Invalid function name: %s\n", argv[1]);
1668         return TCL_ERROR;
1669     }
1670
1671     char *fcnName = argv[1];
1672     char cmdBuf[1024];
1673
1674     sprintf(cmdBuf, "declare int _%s_cnt", fcnName);
1675     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1676         return TCL_ERROR;
1677
1678     sprintf(cmdBuf, "at main entry { _%s_cnt = 0; }", fcnName);
1679     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1680         return TCL_ERROR;
1681
1682     sprintf(cmdBuf, "at %s entry { _%s_cnt++; }", fcnName, fcnName);
1683     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1684         return TCL_ERROR;
1685
1686     sprintf(cmdBuf, "at main exit { printf(\"%s called %%d times\\n\", _%s_cnt); }", 
1687                                                                         fcnName, fcnName);
1688     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1689         return TCL_ERROR;
1690
1691     return TCL_OK;
1692 }
1693
1694 /*
1695  * Replace all calls to fcn1 with calls fcn2
1696  */
1697 int repFunc(char *name1, char *name2) {
1698
1699     BPatch_function *func1 = appImage->findFunction(name1);
1700     if (!func1) {
1701         printf("Invalid function name: %s\n", name1);
1702         return TCL_ERROR;
1703     }
1704
1705     BPatch_function *func2 = appImage->findFunction(name2);
1706     if (!func2) {
1707         printf("Invalid function name: %s\n", name2);
1708         return TCL_ERROR;
1709     }
1710
1711     if (appThread->replaceFunction(*func1, *func2))
1712         return TCL_OK;
1713
1714     return TCL_ERROR;
1715 }
1716
1717 /*
1718  * Replace all or n'th call in func1 with a call to func2
1719  */
1720 int repCall(char *func1, char *func2) {
1721
1722     // Replace function calls
1723     int n = -1;
1724     char *ptr = strchr(func1,':');
1725     if (ptr) {
1726         *ptr = '\0';
1727         n = atoi(ptr+1) - 1;
1728         if (n == -1) {
1729                 printf("Invalid number is entered!\n");
1730                 return TCL_ERROR;
1731         }
1732     }
1733
1734     BPatch_function *newFunc = appImage->findFunction(func2);
1735     if (func2 == NULL) {
1736         printf("Invalid function name: %s\n", func2);
1737         return TCL_ERROR;
1738     }
1739
1740     BPatch_Vector<BPatch_point *> *points = appImage->findProcedurePoint(func1, 
1741                                                                         BPatch_subroutine);
1742     if (points == NULL) {
1743         printf("Could not locate function %s\n", func1);
1744         return TCL_ERROR;
1745     }
1746
1747     if (points->size() == 0) {
1748         printf("Function %s has no calls!\n", func1);
1749         return TCL_ERROR;
1750     }
1751
1752     if (n > points->size()) {
1753         printf("Function %s does not have %d calls!\n", func1, n);
1754         return TCL_ERROR;
1755     }
1756
1757     if (n == -1) {
1758         //Remove all function calls
1759         for(int i=0; i<points->size(); ++i) {
1760                 if (!appThread->replaceFunctionCall(*((*points)[i]), *newFunc) ) {
1761                         printf("Unable to replace call %d !\n", i);
1762                         return TCL_ERROR;
1763                 }
1764         }
1765         return TCL_OK;
1766     }
1767
1768     //Replace n'th function call
1769     if (!appThread->replaceFunctionCall(*((*points)[n]), *newFunc) ) {
1770         printf("Unable to replace call %d !\n", n);
1771         return TCL_ERROR;
1772     }
1773
1774     return TCL_OK;
1775 }
1776
1777 /*
1778  * Replaces functions or function calls with input function
1779  */
1780 int replaceCommand(ClientData, Tcl_Interp *, int argc, char *argv[])
1781 {
1782     if (!haveApp()) return TCL_ERROR;
1783
1784     if ( (argc != 5) || ( (strcmp(argv[1], "function")) && (strcmp(argv[1], "call")) )
1785                          || (strcmp(argv[3], "with")) ) 
1786     {
1787         printf("Usage: replace function <function1> with <function2>\n");
1788         printf("or     replace call <function1>[:n] with <function2>\n");
1789         return TCL_ERROR;
1790     }
1791
1792     if (!strcmp(argv[1], "function"))
1793         return repFunc(argv[2], argv[4]);
1794
1795     if (!strcmp(argv[1], "call"))
1796         return repCall(argv[2], argv[4]);
1797
1798     printf("Invalid option %s\n", argv[1]);
1799     return TCL_ERROR;
1800 }
1801
1802 /*
1803  * Print a message while entering a function
1804  */
1805 int traceFunc(Tcl_Interp *interp, char *name) {
1806     BPatch_function *func = appImage->findFunction(name);
1807     if (!func) {
1808         printf("Invalid function name: %s\n", name);
1809         return TCL_ERROR;
1810     }
1811
1812     char cmdBuf[1024];
1813     sprintf(cmdBuf, 
1814         "at %s entry { printf(\"Entering function %s\\n\"); } trace", name, name);
1815     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1816         return TCL_ERROR;
1817
1818     sprintf(cmdBuf, 
1819         "at %s exit { printf(\"Exiting function %s\\n\"); } trace", name, name);
1820     return Tcl_Eval(interp, cmdBuf);
1821 }
1822
1823 /*
1824  * Trace all the function in a module
1825  */
1826 int traceMod(Tcl_Interp *interp, char *name) {
1827     BPatch_Vector<BPatch_function *> *functions = NULL;
1828
1829     BPatch_module *module = FindModule(name);
1830     if (!module)
1831         return TCL_ERROR;
1832
1833     //Get the module functions
1834     functions = module->getProcedures();
1835
1836     if (!functions) {
1837         printf("Can not get function list!\n");
1838         return TCL_ERROR;
1839     }
1840
1841     //Now print all the functions in the module
1842     char funcName[1024];
1843     for(int i=0; i<functions->size(); ++i) {
1844         (*functions)[i]->getName(funcName, 1024);
1845         if (traceFunc(interp, funcName) == TCL_ERROR)
1846                 return TCL_ERROR;
1847     }
1848
1849     return TCL_OK;
1850 }
1851
1852 /*
1853  * Trace functions alone or in a module
1854  */
1855 int traceCommand(ClientData, Tcl_Interp *interp, int argc, char *argv[])
1856 {
1857     if (!haveApp()) return TCL_ERROR;
1858
1859     if (argc < 3) {
1860         printf("Usage: trace function <function>\n");
1861         printf("or     trace functions in <module>\n");
1862         return TCL_ERROR;
1863     }
1864
1865     if (!strcmp(argv[1], "function"))
1866         return traceFunc(interp, argv[2]);
1867
1868     if (!strcmp(argv[1], "functions") && !strcmp(argv[2], "in"))
1869         return traceMod(interp, argv[3]);
1870
1871     return TCL_ERROR;
1872 }
1873
1874 int untraceFunc(char *name)
1875 {
1876     DynerList<IPListElem *>::iterator i;
1877
1878     i = iplist.begin(); 
1879
1880     while(i != iplist.end()) {
1881         IPListElem *ip = *i;
1882
1883         i++;
1884
1885         if (ip->trace && !strcmp(name, ip->function)) {
1886                 iplist.erase(ip);
1887                 delete ip;
1888         }
1889     }
1890
1891     return TCL_OK;
1892 }
1893
1894 int untraceMod(char *name)
1895 {
1896     BPatch_Vector<BPatch_function *> *functions = NULL;
1897
1898     BPatch_module *module = FindModule(name);
1899     if (!module)
1900         return TCL_ERROR;
1901
1902     //Get the module functions
1903     functions = module->getProcedures();
1904
1905     if (!functions) {
1906         printf("Can not get function list in the module!\n");
1907         return TCL_ERROR;
1908     }
1909
1910     //Now print all the functions in the module
1911     char funcName[1024];
1912     for(int i=0; i<functions->size(); ++i) {
1913         (*functions)[i]->getName(funcName, 1024);
1914         if (untraceFunc(funcName) == TCL_ERROR)
1915                 return TCL_ERROR;
1916     }
1917
1918     return TCL_OK;
1919 }
1920
1921 /*
1922  * Deletes trace effects
1923  */
1924 int untraceCommand(ClientData, Tcl_Interp *, int argc, char *argv[])
1925 {
1926     if (!haveApp()) return TCL_ERROR;
1927
1928     if (argc < 3) {
1929         printf("Usage: untrace <function>\n");
1930         printf("or     untrace functions in <module>\n");
1931         return TCL_ERROR;
1932     }
1933
1934     if (!strcmp(argv[1], "function"))
1935         return untraceFunc(argv[2]);
1936
1937     if (!strcmp(argv[1], "functions") && !strcmp(argv[2], "in"))
1938         return untraceMod(argv[3]);
1939
1940     return TCL_ERROR;
1941 }
1942
1943 /*
1944  * Enable or disable the execution of snippets
1945  */
1946 int mutationsCommand(ClientData, Tcl_Interp *, int argc, char *argv[])
1947 {
1948     if (argc != 2) {
1949         printf("Usage: mutations [enable|disable]\n");
1950         return TCL_ERROR;
1951     }
1952
1953     if (!haveApp()) return TCL_ERROR;
1954
1955     if (!strcmp(argv[1], "enable")) {
1956         appThread->setMutationsActive(true);
1957         return TCL_OK;
1958     }
1959
1960     if (!strcmp(argv[1], "disable")) {
1961         appThread->setMutationsActive(false);
1962         return TCL_OK;
1963     }
1964
1965     printf("Invalid option!\n"); 
1966     return TCL_ERROR;
1967 }
1968
1969 /*
1970  * Remove all or n'th function call in the input function
1971  */
1972 int removeCommand(ClientData, Tcl_Interp *, int argc, char *argv[])
1973 {
1974     if (argc != 2) {
1975         printf("Usage: removecall <function>[:n]\n");
1976         return TCL_ERROR;
1977     }
1978
1979     if (!haveApp()) return TCL_ERROR;
1980
1981     int n = -1;
1982     char *ptr = strchr(argv[1],':');
1983     if (ptr) {
1984         *ptr = '\0';
1985         n = atoi(ptr+1) - 1;
1986         if (n == -1) {
1987                 printf("Invalid number is entered!\n");
1988                 return TCL_ERROR;
1989         }
1990     }
1991
1992     BPatch_Vector<BPatch_point *> *points = appImage->findProcedurePoint(argv[1], 
1993                                                                         BPatch_subroutine);
1994     if (points == NULL) {
1995         printf("Could not locate function %s\n", argv[1]);
1996         return TCL_ERROR;
1997     }
1998
1999     if (points->size() == 0) {
2000         printf("Function %s has no calls!\n", argv[1]);
2001         return TCL_ERROR;
2002     }
2003
2004     if (n > points->size()) {
2005         printf("Function %s does not have %d calls!\n", argv[1], n);
2006         return TCL_ERROR;
2007     }
2008
2009     if (n == -1) {
2010         //Remove all function calls
2011         for(int i=0; i<points->size(); ++i) {
2012                 if (!appThread->removeFunctionCall(*((*points)[i])) ) {
2013                         printf("Unable to remove call %d !\n", i);
2014                         return TCL_ERROR;
2015                 }
2016         }
2017         return TCL_OK;
2018     }
2019
2020     //Remove n'th function call
2021     if (!appThread->removeFunctionCall(*((*points)[n])) ) {
2022         printf("Unable to remove call %d !\n", n);
2023         return TCL_ERROR;
2024     }
2025
2026     return TCL_OK;
2027 }
2028
2029 /*
2030  * Write the in-memory version of the program to the specified file
2031  */
2032 int dumpCommand(ClientData, Tcl_Interp *, int argc, char *argv[])
2033 {
2034     if (argc != 2) {
2035         printf("Usage: dump <file name>\n");
2036         return TCL_ERROR;
2037     }
2038
2039     if (!haveApp()) return TCL_ERROR;
2040
2041     appThread->dumpImage(argv[1]);
2042
2043     return TCL_OK;
2044 }
2045
2046 /*
2047  * remove all the code inserted into target program
2048  */
2049 int detachCommand(ClientData, Tcl_Interp *, int argc, char **)
2050 {
2051     if (argc != 1) {
2052         printf("Usage: detach\n");
2053         return TCL_ERROR;
2054     }
2055
2056     if (!haveApp()) return TCL_ERROR;
2057
2058     appThread->detach(true);
2059
2060     return TCL_OK;
2061 }
2062
2063 //
2064 //
2065 int Tcl_AppInit(Tcl_Interp *interp)
2066 {
2067     if (Tcl_Init(interp) == TCL_ERROR) {
2068         return TCL_ERROR;
2069     }
2070     
2071     //Create BPatch library
2072     bpatch = new BPatch;
2073     if (!bpatch)
2074         return TCL_ERROR;
2075
2076     Tcl_CreateCommand(interp, "at", instStatement, NULL, NULL);
2077     Tcl_CreateCommand(interp, "attach", attachPid, NULL, NULL);
2078     Tcl_CreateCommand(interp, "break", condBreak, NULL, NULL);
2079     Tcl_CreateCommand(interp, "declare", newVar, NULL, NULL);
2080     Tcl_CreateCommand(interp, "listbreak", listBreak, NULL, NULL);
2081     Tcl_CreateCommand(interp, "deletebreak", deleteBreak, NULL, NULL);
2082     Tcl_CreateCommand(interp, "help", help, NULL, NULL);
2083     Tcl_CreateCommand(interp, "kill", killApp, NULL, NULL);
2084     Tcl_CreateCommand(interp, "load", loadCommand, NULL, NULL);
2085     Tcl_CreateCommand(interp, "run", runApp, NULL, NULL);
2086     Tcl_CreateCommand(interp, "print", printVar, NULL, NULL);
2087     Tcl_CreateCommand(interp, "whatis", whatisVar, NULL, NULL);
2088     Tcl_CreateCommand(interp, "show", showCommand, NULL, NULL);
2089     Tcl_CreateCommand(interp, "count", countCommand, NULL, NULL);
2090     Tcl_CreateCommand(interp, "replace", replaceCommand, NULL, NULL);
2091     Tcl_CreateCommand(interp, "trace", traceCommand, NULL, NULL);
2092     Tcl_CreateCommand(interp, "untrace", untraceCommand, NULL, NULL);
2093     Tcl_CreateCommand(interp, "mutations", mutationsCommand, NULL, NULL);
2094     Tcl_CreateCommand(interp, "removecall", removeCommand, NULL, NULL);
2095     //Tcl_CreateCommand(interp, "dump", dumpCommand, NULL, NULL);
2096     Tcl_CreateCommand(interp, "detach", detachCommand, NULL, NULL);
2097
2098     bpatch->registerErrorCallback(errorFunc);
2099     bpatch->setTypeChecking(false);
2100     bpatch->registerExitCallback(&exitCallback);
2101
2102     return TCL_OK;
2103 }
2104
2105 int main(int argc, char *argv[])
2106 {
2107     if (argc >= 2 && !strcmp(argv[1], "-debug")) {
2108         printf("parser debug enabled\n");
2109         dynerdebug = 1;
2110     }
2111
2112     Tcl_Main(argc, argv, Tcl_AppInit);
2113     return 0;
2114 }