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