Several enhancements to dyner. Development is still in progres....
[dyninst.git] / dyner / src / dyner.C
1 #include <stdio.h>
2 #include <stdlib.h>
3 #if defined(sparc_sun_solaris2_4)
4         #include <sys/time.h>
5 #else
6         #include <sys/timeb.h>
7
8         extern "C" int ftime(struct timeb *);
9 #endif
10
11 #include "tcl.h"
12 #include "dynerList.h"
13 #include "BPatch.h"
14 #include "BPatch_type.h"
15 #include "BPatch_collections.h"
16 #include "BPatch_Vector.h"
17 #include "BPatch_thread.h"
18 #include "BPatch_snippet.h"
19 #include "breakpoint.h"
20
21 extern "C" {
22         int usleep(useconds_t);
23
24         void set_lex_input(char *s);
25         int dynerparse();
26 }
27
28 extern "C" int dynerdebug;
29
30 int debugPrint = 0;
31 BPatch_point *targetPoint;
32 bool errorLoggingOff = false;
33
34 // control debug printf statements
35 #define dprintf if (debugPrint) printf
36
37 class ListElem {
38 public:
39     int                      number;
40     char                     *function;
41     BPatch_procedureLocation where;
42     BPatch_callWhen          when;
43     BPatchSnippetHandle      *handle;
44 };
45
46 class BPListElem: public ListElem {
47 public:
48     char                     *condition;
49
50     BPListElem(int _number, char *_function, BPatch_procedureLocation _where,
51                BPatch_callWhen _when, char *_condition,
52                BPatchSnippetHandle *_handle);
53     ~BPListElem();
54 };
55
56 class runtimeVar {
57 public:
58     runtimeVar(BPatch_variableExpr *v, char *n) { var = v, name = strdup(n); }
59     BPatch_variableExpr *var;
60     char *name;
61     bool readValue(void *buf) { return var->readValue(buf); }
62 };
63
64 class IPListElem: public ListElem {
65 public:
66     char                     *statement;
67
68     IPListElem(int _number, char *_function, BPatch_procedureLocation _where,
69                BPatch_callWhen _when, char *_condition,
70                BPatchSnippetHandle *_handle);
71     ~IPListElem();
72 };
73
74 BPatch bpatch;
75 BPatch_thread *appThread = NULL;
76 BPatch_image *appImage = NULL;
77 static BPatch_variableExpr *bpNumber = NULL;
78 static int bpCtr = 1;
79 static int ipCtr = 1;
80 static DynerList<ListElem *> bplist;
81 static DynerList<ListElem *> iplist;
82 static DynerList<runtimeVar *> varList;
83
84
85 BPListElem::BPListElem(int _number, char *_function,
86     BPatch_procedureLocation _where, BPatch_callWhen _when, char *_condition,
87     BPatchSnippetHandle *_handle)
88 {
89     number = _number;
90     function = strdup(_function);
91     where = _where;
92     when = _when;
93     condition = strdup(_condition);
94     handle = _handle;
95 }
96
97 BPListElem::~BPListElem()
98 {
99     free(function);
100     free(condition);
101 }
102
103 IPListElem::IPListElem(int _number, char *_function,
104     BPatch_procedureLocation _where, BPatch_callWhen _when, char *_condition,
105     BPatchSnippetHandle *_handle)
106 {
107     number = _number;
108     function = strdup(_function);
109     where = _where;
110     when = _when;
111     statement = strdup(_condition);
112     handle = _handle;
113 }
114
115 IPListElem::~IPListElem()
116 {
117     free(function);
118     free(statement);
119     if (handle) delete handle;
120 }
121
122 ListElem *findBP(int n)
123 {
124     DynerList<ListElem *>::iterator i;
125
126     for (i = bplist.begin(); i != bplist.end(); i++) {
127         if ((*i)->number == n) return (*i);
128     }
129
130     return NULL;
131 }
132
133 int help(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
134 {
135
136     printf("at <function> [entry|exit|preCall|postCall] <statement> - instert statement\n");
137     printf("declare <variable> <type> - create a new variable of type <type>\n");
138     printf("deletebreak <breakpoint number ...> - delete breakpoint(s)\n");
139     printf("cbreak <function> [entry|exit|preCall|postCall] <condition> - set a conditional\n");
140     printf("  break point\n");
141     printf("listbreak - list break points\n");
142     printf("load <program> [arguments] [< filename] [> filename] - load a program\n");
143     printf("run - run or continue the loaded program\n");
144     return TCL_OK;
145 }
146
147 bool haveApp()
148 {
149     if (appThread == NULL) {
150         fprintf(stderr, "No application loaded.\n");
151         return false;
152     }
153
154     if (appThread->isTerminated()) {
155         fprintf(stderr, "The application has exited.\n");
156         return false;
157     }
158     return true;
159 }
160
161 bool name2loc(char *s, BPatch_procedureLocation &where,
162               BPatch_callWhen &when)
163 {
164     if (!strcmp(s, "entry")) {
165         where = BPatch_entry;
166         when = BPatch_callBefore;
167     } else if (!strcmp(s, "exit")) {
168         where = BPatch_exit;
169         /* This is not supported anymore!
170         when = BPatch_callBefore;
171         */
172         when = BPatch_callAfter;
173     } else if (!strcmp(s, "preCall")) {
174         where = BPatch_subroutine;
175         when = BPatch_callBefore;
176     } else if (!strcmp(s, "postCall")) {
177         where = BPatch_subroutine;
178         when = BPatch_callAfter;
179     } else {
180         return false;
181     }
182     return true;
183 }
184
185 char *loc2name(BPatch_procedureLocation where, BPatch_callWhen when)
186 {
187     switch (where) {
188       case BPatch_entry:
189         return "entry";
190       case BPatch_exit:
191         return "exit";
192       case BPatch_subroutine:
193         if (when == BPatch_callBefore) return "preCall";
194         else return "postCall";
195       default:
196         return "<error>";
197     };
198 }
199
200 int loadApp(char *pathname, char **args)
201 {
202     printf("Loading \"%s\"\n", pathname);
203
204     if (appThread != NULL) delete appThread;
205     bplist.clear();
206     iplist.clear();
207     varList.clear();
208     appThread = bpatch.createProcess(pathname, args);
209     bpNumber = NULL;
210
211     if (!appThread || appThread->isTerminated()) {
212         fprintf(stderr, "Unable to run test program.\n");
213         appThread = NULL;
214         return TCL_ERROR;
215     }
216
217     // Read the program's image and get an associated image object
218     appImage = appThread->getImage();
219
220     if (!appImage) return TCL_ERROR;
221
222     //Create type info
223     appImage->getModules();
224
225     return TCL_OK;
226
227 }
228
229
230 int loadLib(char *libName) {
231     if (!haveApp()) return TCL_ERROR;
232
233     if (appThread->loadLibrary(libName))
234         return TCL_OK;
235
236     return TCL_ERROR;
237 }
238
239 int loadCommand(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
240 {
241     if ( (argc == 3) && (!strcmp(argv[1], "library")) )
242         return loadLib(argv[2]);
243
244     if (argc < 2) {
245         printf("Usage load <program> [<arguments>]\n");
246         return TCL_ERROR;
247     }
248
249     return loadApp(argv[1], &argv[1]);
250 }
251
252 int listBreak(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
253 {
254     if (!haveApp()) return TCL_ERROR;
255
256     BPListElem *curr;
257     DynerList<ListElem *>::iterator i;
258
259     for (i = bplist.begin(); i != bplist.end(); i++) {
260         curr = (BPListElem *) *i;
261         printf("%2d: in %s (%s), condition %s\n",
262                 curr->number, curr->function,
263                 loc2name(curr->where, curr->when),
264                 curr->condition);
265     }
266 }
267
268 int deleteBreak(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
269 {
270     if (!haveApp()) return TCL_ERROR;
271
272     if (argc < 2) {
273         fprintf(stderr, "Specify breakpoint(s) to delete.\n");
274         return TCL_ERROR;
275     }
276
277     int ret = TCL_OK;
278     for (int j = 1; j < argc; j++) {
279         int n = atoi(argv[j]);
280
281         ListElem *i = findBP(n);
282         if (i == NULL) {
283             printf("No such breakpoint: %d\n", n);
284             ret = TCL_ERROR;
285         } else {
286             appThread->deleteSnippet(i->handle);
287             bplist.erase(i);
288             delete i;
289             printf("Breakpoint %d deleted.\n", n);
290         }
291     }
292
293     return ret;
294 }
295
296 int runApp(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
297 {
298 #if defined(sparc_sun_solaris2_4) 
299     hrtime_t start_time, end_time;
300
301     start_time = gethrtime();
302 #else
303     struct timeb start_time, end_time;
304
305     ftime(&start_time);
306 #endif
307
308     if (!haveApp()) return TCL_ERROR;
309
310     if (bpNumber) {
311         int inval = -1;
312         bpNumber->writeValue(&inval);
313     }
314
315     // Start of code to continue the process.
316     dprintf("starting program execution.\n");
317     appThread->continueExecution();
318
319     while (!appThread->isStopped() && !appThread->isTerminated())
320         usleep(250);
321
322     int bp = -1;
323     if (bpNumber) bpNumber->readValue(&bp);
324
325     if (appThread->isTerminated()) {
326         printf("\nApplication exited.\n");
327     } else if (appThread->isStopped() && bp > 0) {
328         printf("\nStopped at break point %d.\n", bp);
329         ListElem *i = findBP(bp);
330         if (i != NULL) {
331             BPListElem *curr = (BPListElem *) i;
332             printf("%s (%s); %s\n",
333                     curr->function,
334                     loc2name(curr->where, curr->when),
335                     curr->condition);
336         }
337     } else {
338         printf("\nStopped.\n");
339     }
340
341 #if defined(sparc_sun_solaris2_4)
342     end_time = gethrtime();
343     printf("Running time (nanoseconds): %lld\n", end_time - start_time);
344 #else
345     ftime(&end_time);
346     printf("Running time (miliseconds): %d\n", (end_time.time - start_time.time) * 1000 + 
347                                                         end_time.millitm - start_time.millitm);
348 #endif
349
350     return TCL_OK;
351 }
352
353 int killApp(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
354 {
355     if (!haveApp()) return TCL_ERROR;
356
357     appThread->terminateExecution();
358
359     return TCL_OK;
360 }
361
362 extern BPatch_snippet *parse_result;
363 int condBreak(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
364 {
365     if (!haveApp()) return TCL_ERROR;
366
367     if (bpNumber == NULL) {
368         bpNumber = appThread->malloc(*appImage->findType("int"));
369         if (bpNumber == NULL) {
370             fprintf(stderr, "Unable to allocate memory in the inferior process.\n");
371             exit(1);
372         }
373     }
374
375     if (argc < 3) {
376         printf("Wrong number of paramters.\n");
377         return TCL_ERROR;
378     }
379
380     int expr_start = 2;
381     BPatch_procedureLocation where;
382     BPatch_callWhen when;
383     if (name2loc(argv[2], where, when)) {
384         expr_start = 3;
385     } else {
386         where = BPatch_entry;
387         when = BPatch_callBefore;
388     }
389
390     BPatch_Vector<BPatch_point *> *points =
391         appImage->findProcedurePoint(argv[1], where);
392     if (points == NULL) {
393         fprintf(stderr, "Unable to locate function: %s\n", argv[1]);
394         return TCL_ERROR;
395     }
396
397     // Count up how large a buffer we need for the whole line
398     int line_len = 0;
399     for (int i = expr_start; i < argc; i++)
400         line_len += strlen(argv[i]) + 1;
401     line_len++;
402     // Make the buffer and copy the line into it
403     char *line_buf = new char[line_len];
404     *line_buf = '\0';
405     for (int i = expr_start; i < argc; i++) {
406         strcat(line_buf, argv[i]);
407         if (i != argc-1) strcat(line_buf, " ");
408     }
409
410     set_lex_input(line_buf);
411     if (dynerparse() != 0) {
412         fprintf(stderr, "Breakpoint not set due to error.\n");
413         delete line_buf;
414         return TCL_ERROR;
415     }
416
417     if (parse_type != parsed_bool) {
418         fprintf(stderr, "Breakpoint not set due error, expression not boolean.\n");
419         delete line_buf;
420         delete parse_result;
421         return TCL_ERROR;
422     }
423
424     // Make a snippet to tell us which breakpoint it is
425     BPatch_arithExpr storeBPNum(BPatch_assign,
426                                 *bpNumber, BPatch_constExpr(bpCtr));
427
428     // Make a snippet to break at the breakpoint
429     BPatch_function *breakFunc = appImage->findFunction("DYNINSTbreakPoint");
430     if (breakFunc == NULL) {
431         fprintf(stderr, "Unable to find function DYNINSTbreakPoint (required for setting break points)\n");
432         delete parse_result;
433         delete line_buf;
434         return TCL_ERROR;
435     }
436
437     BPatch_Vector<BPatch_snippet *> nullArgs;
438     BPatch_funcCallExpr callBreak(*breakFunc, nullArgs);
439
440     // store the break point number, then  break
441     BPatch_arithExpr doBreak(BPatch_seq, storeBPNum, callBreak);
442     
443
444     // Call the break snippet conditionally
445     BPatch_ifExpr condBreak(*(BPatch_boolExpr *)parse_result, doBreak); 
446
447     delete parse_result;
448
449     BPatchSnippetHandle *handle =
450         appThread->insertSnippet(condBreak, *points, when,BPatch_lastSnippet);
451     if (handle == 0) {
452         fprintf(stderr, "Error inserting snippet.\n");
453         delete line_buf;
454         return TCL_ERROR;
455     }
456
457     BPListElem *bpl =
458         new BPListElem(bpCtr, argv[1], where, when, line_buf, handle);
459     delete line_buf;
460
461     bplist.push_back(bpl);
462
463     printf("Breakpoint %d set.\n", bpCtr);
464     bpCtr++;
465
466     return TCL_OK;
467 }
468 /*
469  * void printPtr( )
470  *
471  * This function recursively goes through the BPatch_type pointers until
472  * it gets to the base type and prints that name.  The base type can be
473  * a builtin type or an enum, struct, or union.  The default case handles
474  * unknown pointer types.  -- jdd 5/27/99
475  */
476 void printPtr( BPatch_type * type )
477 {
478   if( type->getDataClass() == BPatch_pointer ){
479     printPtr( type->getConstituentType() );
480     printf("*");
481   }
482   else if((type->getDataClass() == BPatch_scalar)||(type->getDataClass() == BPatch_built_inType)||
483         (type->getDataClass() == BPatchSymTypeRange)){
484     printf("%s ", type->getName());
485   }
486   else{
487     switch( type->getDataClass() ){
488     case BPatch_enumerated:
489       printf("enum %s ", type->getName());
490       break;
491     case BPatch_structure:
492       printf("struct %s ", type->getName());
493       break;
494     case BPatch_union:
495       printf("union %s ", type->getName());
496       break;
497     default:
498       printf("Undefined POINTER: %s", type->getName());
499       break;
500     }
501   }
502   
503 }
504 /*
505  * printArray()
506  *
507  * This function prints arrays of various dimension, 1D to 3D. It first
508  * checks how many dimensions the array is and then prints it out.
509  * The default case handles the unknown. --jdd 5/27/99
510  */
511  
512 void printArray(BPatch_type * type )
513 {
514   int j = 0;
515   if(type->getConstituentType()){
516     j++;
517     if(type->getConstituentType()->getConstituentType()){
518       j++;
519       if(type->getConstituentType()->getConstituentType()->getConstituentType()){
520         j++;
521       }
522     }
523   }
524   switch(j){
525   case 3:
526     
527     //3D array
528     printf("    %s is an array [%s..%s][%s..%s][%s..%s] of %s\n",
529            type->getName(), type->getLow(), type->getHigh(),
530            type->getConstituentType()->getLow(),
531            type->getConstituentType()->getHigh(),
532            type->getConstituentType()->getConstituentType()->getLow(),
533            type->getConstituentType()->getConstituentType()->getHigh(),
534            type->getConstituentType()->getConstituentType()->getConstituentType()->getName());
535     break;
536   case 2:
537         
538     //2D array
539     printf("    %s is an array [%s..%s][%s..%s] of %s\n", type->getName(), 
540            type->getLow(), type->getHigh(),
541            type->getConstituentType()->getLow(),
542            type->getConstituentType()->getHigh(),
543            type->getConstituentType()->getConstituentType()->getName());
544     break;
545   case 1:
546     printf("    %s is an array [%s..%s] of %s\n", type->getName(),
547            type->getLow(), type->getHigh(), 
548            type->getConstituentType()->getName());
549     break;
550   default:
551     printf("Unable to process array %s\n", type->getName());
552     break;
553   }
554 }
555
556 int instStatement(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
557 {
558     if (!haveApp()) return TCL_ERROR;
559
560     if (argc < 3) {
561         printf("Wrong number of paramters.\n");
562         return TCL_ERROR;
563     }
564
565     int expr_start = 2;
566     BPatch_procedureLocation where;
567     BPatch_callWhen when;
568     if (name2loc(argv[2], where, when)) {
569         expr_start = 3;
570     } else {
571         where = BPatch_entry;
572         when = BPatch_callBefore;
573     }
574
575     BPatch_function *func = appImage->findFunction(argv[1]);
576     if (func == NULL) {
577         fprintf(stderr, "Unable to locate function: %s\n", argv[1]);
578         return TCL_ERROR;
579     }
580
581
582     BPatch_Vector<BPatch_point *> *points = func->findPoint(where);
583                                 // appImage->findProcedurePoint(argv[1], where);
584
585     if (points == NULL) {
586         fprintf(stderr, "Unable to locate function: %s\n", argv[1]);
587         return TCL_ERROR;
588     }
589
590     //Assign targetPoint using function entry point
591     targetPoint = (*(func->findPoint(BPatch_entry)))[0];
592
593     // Count up how large a buffer we need for the whole line
594     int line_len = 0;
595     for (int i = expr_start; i < argc; i++)
596         line_len += strlen(argv[i]) + 1;
597     line_len += 2;
598     // Make the buffer and copy the line into it
599     char *line_buf = new char[line_len];
600     *line_buf = '\0';
601     for (int i = expr_start; i < argc; i++) {
602         strcat(line_buf, argv[i]);
603         if (i != argc-1) strcat(line_buf, " ");
604     }
605     strcat(line_buf, "\n");
606
607     // printf("calling parse of %s\n", line_buf);
608     set_lex_input(line_buf);
609     if (dynerparse() != 0) {
610         fprintf(stderr, "Instrumentation not set due to error.\n");
611         delete line_buf;
612         targetPoint = NULL;
613         return TCL_ERROR;
614     }
615
616     targetPoint = NULL;
617
618     if (parse_type != parsed_statement) {
619         fprintf(stderr, "code not inserted, expression is not a statement.\n");
620         delete line_buf;
621         delete parse_result;
622         return TCL_ERROR;
623     }
624
625     BPatchSnippetHandle *handle =
626         appThread->insertSnippet(*parse_result, *points, when,BPatch_lastSnippet);
627     if (handle == 0) {
628         fprintf(stderr, "Error inserting snippet.\n");
629         delete line_buf;
630         return TCL_ERROR;
631     }
632
633     IPListElem *snl =
634         new IPListElem(ipCtr, argv[1], where, when, line_buf, handle);
635     delete line_buf;
636
637     iplist.push_back(snl);
638
639     // printf("Inst point %d set.\n", ipCtr);
640     ipCtr++;
641
642     return TCL_OK;
643 }
644
645 void printVarRecursive(BPatch_variableExpr *var, int level)
646 {
647     int iVal;
648     int pVal;
649     float fVal;
650
651     BPatch_dataClass dc;
652     BPatch_type *type = (BPatch_type *) var->getType();
653
654     dc = type->getDataClass();
655     if (!strcmp(type->getName(), "int")) {
656         /* print out the integer */
657         var->readValue((void *) &iVal);
658         printf("%d\n", iVal);
659     } else if (!strcmp(type->getName(), "float")) {
660         /* print out the float */
661         var->readValue((void *) &fVal);
662         printf("%f\n", fVal);
663     } else if (dc == BPatch_pointer) {
664         /* print out the float */
665         var->readValue((void *) &pVal);
666         printf("0x%x\n", pVal);
667     } else if (dc == BPatch_structure) {
668         printf("struct {\n");
669         level++;
670         BPatch_Vector<BPatch_variableExpr *> *fields = var->getComponents();
671         for (int i=0; i < fields->size(); i++) {
672              BPatch_variableExpr *fieldVar = (*fields)[i];
673              for (int i=0;i < level; i++) printf("    ");
674              printf("%s = ", fieldVar->getName());
675              printVarRecursive(fieldVar, level);
676         }
677         level--;
678         printf("}\n");
679     } else if (dc == BPatch_array) {
680         printf("<arrays not yet implemented>\n");
681     } else {
682         printf("<unknown type>\n");
683     }
684 }
685
686 int printVar(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
687 {
688     //if (!haveApp()) return TCL_ERROR;
689
690     BPatch_variableExpr *var = findVariable(argv[1]);
691     if (!var) {
692         printf("%s is not defined\n", argv[1]);
693         return TCL_ERROR;
694     }
695
696     printf("    %s = ", argv[1]);
697     printVarRecursive(var, 1);
698
699     return TCL_OK;
700 }
701
702 /*
703  * declare <type> <variable name>
704  */
705 int newVar(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
706 {
707     if (!haveApp()) return TCL_ERROR;
708
709     BPatch_type *type = appImage->findType(argv[1]);
710     if (!type) {
711         printf("type %s is not defined\n", argv[1]);
712         return TCL_ERROR;
713     }
714
715     BPatch_variableExpr *newVar = appThread->malloc(*type);
716     if (!newVar) {
717         printf("unable to create variable.\n");
718         return TCL_ERROR;
719     }
720
721     varList.push_back(new runtimeVar(newVar, argv[2]));
722 }
723
724 BPatch_variableExpr *findVariable(char *name)
725 {
726     BPatch_variableExpr *var;
727     DynerList<runtimeVar *>::iterator i;
728
729     // First look for runtime created variables
730     for (i = varList.begin(); i != varList.end(); i++) {
731         if (!strcmp(name, (*i)->name)) {
732             var = new BPatch_variableExpr(*((*i)->var));
733             return (var);
734         }
735     }
736
737     // Now check the function locals
738     if (targetPoint) {
739         var = appImage->findVariable(*targetPoint, name);
740         if (var) return var;
741     }
742
743     // Check global vars in the mutatee
744     errorLoggingOff = true;
745     var = appImage->findVariable(name);
746     errorLoggingOff = false;
747
748     if (var) return var;
749
750     printf("Unable to locate variable %s\n", name);
751     return NULL;
752 }
753
754 /* 
755  * int whatisParam()
756  *
757  * This function is an extension to the "whatis" command.  This function
758  * processes the command: whatis -scope <function> <variable>. If the
759  * <function> is undefined then TCL_ERROR is returned.  Otherwise, the
760  * local variable collection is searched first; followed by the parameter
761  * collection; and finally the Global collection is searched last. If the
762  * <variable> is not found, then "<variable> is not defined" is reported
763  * to the user. --jdd 5/27/98
764  */
765 int whatisParam(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
766 {
767   if (!haveApp()) return TCL_ERROR;
768   BPatch_function * func = appImage->findBPFunction(argv[2]);
769   printf("func is %x\n", func);
770   if(!func){
771     printf("%s is not defined\n", argv[3]);
772     return TCL_ERROR;
773   }
774   
775   
776   BPatch_localVar * lvar = func->findLocalVar(argv[3]);
777   if(lvar){
778     BPatch_type *type = lvar->getType();
779     if( type ){
780       switch (type->getDataClass()) {
781       case BPatch_array:
782         printArray( type );
783         break;
784         
785       case BPatch_pointer:
786         printPtr( type );
787         printf("\t %s\n", argv[3]);
788         break;
789         
790       default:
791         printf("    %s is of type %s \n", argv[3], type->getName());
792         break;
793       }
794     }
795     //print local variable info
796     printf("        %s is a local variable in function %s\n", lvar->getName(),
797            argv[2]);
798     printf("        Declared on line %d and has a Frame offset of %d\n",
799            lvar->getLineNum(), lvar->getFrameOffset());
800   }
801   else{
802     lvar = func->findLocalParam(argv[3]);
803     
804     if (!lvar) {
805       BPatch_variableExpr *var = findVariable(argv[3]);
806       if(!var){
807         // do something else ??
808         //int ret = whatisType(cd, interp, argc, argv);
809         return TCL_OK;
810       }
811       BPatch_type *type = (BPatch_type *) var->getType();
812       switch (type->getDataClass()) {
813       case BPatch_array:
814         printArray( type );
815         break;
816         
817       case BPatch_pointer:
818         printPtr( type );
819         printf("\t %s\n", argv[3]);
820         break;
821         
822       default:
823         printf("    %s is of type %s \n", argv[3], type->getName());
824         break;
825       }
826      printf("      %s is a Global variable\n", argv[3]);
827     }
828     else{
829       BPatch_type *lType = (BPatch_type *) lvar->getType();
830       if (lType){
831         switch (lType->getDataClass()) {
832         case BPatch_array:
833           printArray( lType );
834           break;
835           
836         case BPatch_pointer:
837           printPtr( lType );
838           printf("\t %s\n", argv[3]);
839           break;
840           
841         default:
842           printf("    %s is of type %s \n", argv[3], lType->getName());
843           break;
844         }
845         printf("       %s is a parameter of the function %s\n",lvar->getName(),
846            argv[2]);
847         printf("       Declared on line %d and has a Frame offset of %d\n",
848            lvar->getLineNum(), lvar->getFrameOffset());
849       }
850       else{
851         printf("   unknown type %s\n", lvar->getName());
852       }
853     }   
854   }
855   return TCL_OK;
856 }
857
858 /*
859  * int whatisFunc()
860  *
861  * This function is an extension to the "whatis" command.  This function
862  * searches all of the modules to find the BPatch_function with the name
863  * given be argv[1]. If no such function is found, then TCL_ERROR is returned.
864  * This is the last function in the chain of "whatis" command functions to
865  * be executed in the search for argv[1]. --jdd 5/27/99
866  */
867  
868 int whatisFunc(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
869 {
870     if (!haveApp()) return TCL_ERROR;
871     // If the function is found it returns the BPatch_function.
872     // findFunction() creates a new BPatch_function so it is not
873     // used here. --jdd 5/27/99
874     BPatch_function * func = appImage->findBPFunction(argv[1]);
875     
876     if(!func){
877       printf("%s is not defined\n", argv[1]);
878       return TCL_ERROR;
879     }
880     printf("    Function %s ", argv[1]);
881     BPatch_type * retType = func->getReturnType();
882     if(retType)
883       switch(retType->getDataClass()){
884       case BPatch_scalar:
885       case BPatch_built_inType:
886       case BPatchSymTypeRange:
887         printf("  with return type %s\n",retType->getName() );
888         break;
889       case BPatch_array:
890         printf("  with return type ");
891         printArray( retType );
892         printf("\n");
893         break;
894           
895       case BPatch_pointer:
896         printf("  with return type ");
897         printPtr( retType );
898         printf("\n");
899         break;
900         
901       default:
902         printf("    %s has unknown return type %s %d\n",argv[1],
903                retType->getName(), retType->getID());
904         break;
905       }
906     else
907       printf("   unknown return type for %s\n", argv[1]);
908     BPatch_Vector<BPatch_localVar *> *params = func->getParams();
909     if( params->size())
910       printf("        Parameters: \n");
911     for (int i=0; i < params->size(); i++) {
912       BPatch_localVar *localVar = (*params)[i];
913       BPatch_type *lType = (BPatch_type *) localVar->getType();
914       if (lType){
915         if( (lType->getDataClass())  == BPatch_pointer){
916           printPtr(lType);
917           printf(" \t %s\n", localVar->getName());
918         }
919         else if( (lType->getDataClass()) == BPatch_array){
920           printArray( lType );
921         }
922         else
923           printf("        %s %s\n",lType->getName(), localVar->getName());
924         
925       }
926       else{
927         printf("   unknown type %s\n", localVar->getName());
928       }
929     }    
930     return TCL_OK;
931 }
932
933 /*
934  * int whatisType()
935  *
936  * This function is an extension to the "whatis" command.  This function
937  * searches for the type collection of the all the modules looking for
938  * the type specified by argv[1]. If it is not found, then whatisFunc()
939  * is called. This is function is called by whatisVar if a variable is
940  * not found. -- jdd 5/27/99
941  */
942  
943 int whatisType(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
944 {
945     if (!haveApp()) return TCL_ERROR;
946     
947     BPatch_type *type = appImage->findType(argv[1]);
948     if (!type) {
949       int ret = whatisFunc(cd, interp, argc, argv);
950       return ret;
951     }
952
953     BPatch_dataClass dc = type->getDataClass();
954     switch (dc) {
955     case BPatch_structure: {
956       printf("    struct %s {\n", argv[1]);
957       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
958       for (int i=0; i < fields->size(); i++) {
959         BPatch_field *field = (*fields)[i];
960         BPatch_type *fType = (BPatch_type *) field->getType();
961         if (fType){
962           switch (fType->getDataClass()) {
963           case BPatch_array:
964             printArray( fType );
965             printf("  %s\n", field->getName());
966             break;
967         
968           case BPatch_pointer:
969             printPtr( fType );
970             printf("  %s\n", field->getName());
971             break;
972         
973           default:
974             printf("        %s %s\n", fType->getName(), field->getName());
975             break;
976           }
977         }
978         else{
979           printf("   unknown type %s\n", field->getName());
980         }
981       }
982       printf("    }\n");
983       break;
984     }
985     case BPatch_union: {
986       printf("    union %s {\n", argv[1]);
987       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
988       for (int i=0; i < fields->size(); i++) {
989         BPatch_field *field = (*fields)[i];
990         BPatch_type *fType = (BPatch_type *) field->getType();
991         if (fType){
992           switch (fType->getDataClass()) {
993           case BPatch_array:
994             printArray( fType );
995             printf("  %s\n", field->getName());
996             break;
997         
998           case BPatch_pointer:
999             printPtr( fType );
1000             printf("  %s\n", field->getName());
1001             break;
1002             
1003           default:
1004             printf("        %s %s\n", fType->getName(), field->getName());
1005             break;
1006           }
1007         }
1008         else{
1009           printf("        unknown type %s\n", field->getName());
1010         }
1011       }
1012       printf("    }\n");
1013       break;
1014     }
1015     case BPatch_enumerated: {
1016       printf("    enum %s {\n", argv[1]);
1017       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1018       for (int i=0; i < fields->size(); i++) {
1019         BPatch_field *field = (*fields)[i];
1020         printf("        %s    \t%d\n", field->getName(),
1021                field->getValue());
1022       }
1023       printf("    }\n");
1024       break;
1025     }
1026     case BPatch_array:
1027       printArray( type );
1028       break;
1029       
1030     case BPatch_scalar:
1031     case BPatch_built_inType:
1032       printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1033       break;
1034       
1035     case BPatch_pointer:
1036       printPtr( type );
1037       printf("\t %s\n", argv[1]);
1038       /*
1039       printf("    %s is pointer to type %s\n", argv[1], 
1040              type->getConstituentType()->getName());*/
1041       break;
1042     case BPatchSymTypeRange:
1043       if(type->getConstituentType())
1044         printf("    %s is a %s of size %d\n",argv[1],
1045                (type->getConstituentType())->getName(),type->getSize());
1046       else
1047         printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1048       if( type->getLow() ){
1049          printf("        with range %s to %s\n", type->getLow(),
1050                 type->getHigh());
1051       }
1052       break;
1053     default:
1054       printf("%s is of an unknown data class %d\n", argv[1],
1055              dc);
1056       break;
1057     }
1058     
1059     return TCL_OK;
1060 }
1061
1062 /*
1063  * int whatisVar()
1064  *
1065  * This function is an extension to the "whatis" command.  This function
1066  * searches the process for the variable named by argv[1] and then searches
1067  * all the Global variables for all the modules to find the variable
1068  * specified by argv[1].  If nothing is found, then whatisType() is called. If
1069  * whatisType() finds nothing, whatisFunc() is called.  If the command is
1070  * of the form "whatis -scope <function> <variable>", then whatisParam() is
1071  * called skipping all other attempts to find the variable. -- jdd 5/27/99
1072  */
1073
1074 int whatisVar(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
1075 {
1076     if (!haveApp()) return TCL_ERROR;
1077     
1078     if (argc == 4){ //looking for a local variable
1079       if(!(strcmp(argv[1], "-scope"))){
1080         int ret = whatisParam(cd, interp, argc, argv );
1081         return ret;
1082       } else {
1083         printf("inavlid argument %s\n", argv[1]);
1084         return TCL_ERROR;
1085       }
1086     }
1087
1088     BPatch_variableExpr *var = findVariable(argv[1]);
1089     if (!var) {
1090         int ret = whatisType(cd, interp, argc, argv);
1091         return ret;
1092     }
1093
1094     BPatch_type *type = (BPatch_type *) var->getType();
1095     switch (type->getDataClass()) {
1096     case BPatch_structure: {
1097       printf("    struct %s {\n", argv[1]);
1098       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1099       for (int i=0; i < fields->size(); i++) {
1100         BPatch_field *field = (BPatch_field *) (*fields)[i];
1101         BPatch_type *fType = (BPatch_type *) field->getType();
1102         if (fType){
1103           printf("        %s %s\n", fType->getName(), field->getName());
1104         }
1105         else{
1106           printf("   unknown type %s\n", field->getName());
1107         }
1108       }
1109       printf("    }\n");
1110       break;
1111     }
1112     case BPatch_union: {
1113       printf("    union %s {\n", argv[1]);
1114       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1115       for (int i=0; i < fields->size(); i++) {
1116         BPatch_field *field = (*fields)[i];
1117         BPatch_type *fType = (BPatch_type *) field->getType();
1118         if (fType){
1119           printf("        %s %s\n", fType->getName(), field->getName());
1120         }
1121         else{
1122           printf("        unknown type %s\n", field->getName());
1123         }
1124       }
1125       printf("    }\n");
1126       break;
1127     }
1128     case BPatch_enumerated: {
1129       printf("    enum %s {\n", argv[1]);
1130       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1131       for (int i=0; i < fields->size(); i++) {
1132         BPatch_field *field = (*fields)[i];
1133         printf("        %s    \t%d\n", field->getName(),
1134                field->getValue());
1135       }
1136       printf("    }\n");
1137       break;
1138     }
1139     case BPatch_array:
1140       printArray(type);
1141       break;
1142    
1143     case BPatch_pointer:
1144       printPtr( type );
1145       printf("\t %s\n", argv[1]);
1146       /*
1147       printf("    %s is pointer to type %s\n", argv[1], 
1148              type->getConstituentType()->getName());*/
1149       break;
1150     case BPatchSymTypeRange:
1151       if(type->getConstituentType())
1152         printf("    %s is a %s of size %d\n",argv[1],
1153                (type->getConstituentType())->getName(),type->getSize());
1154       else
1155         printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1156       if( type->getLow() ){
1157         printf("        with range %s to %s\n", type->getLow(),
1158                type->getHigh());
1159       }
1160       break;
1161     case BPatch_scalar:
1162     case BPatch_built_inType:
1163       printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1164       break;
1165       
1166     default:
1167       printf("    %s is of type %s \n", argv[1], type->getName());
1168       //int ret = whatisType(cd, interp, argc, argv);
1169       break;
1170     }
1171     
1172     return TCL_OK;
1173 }
1174
1175 const int DYNINST_NO_ERROR = -1;
1176
1177 void errorFunc(BPatchErrorLevel level, int num, const char **params)
1178 {
1179     char line[256];
1180
1181     if (errorLoggingOff) return;
1182
1183     if ((num == 0) && ((level == BPatchWarning) || (level == BPatchInfo))) {
1184          // these are old warnings/status info from paradyn
1185          return;
1186     }
1187
1188     const char *msg = bpatch.getEnglishErrorString(num);
1189     bpatch.formatErrorString(line, sizeof(line), msg, params);
1190
1191     if (num != DYNINST_NO_ERROR) {
1192         printf("Error #%d (level %d): %s\n", num, level, line);
1193
1194         // We consider some errors fatal.
1195         if (num == 101) {
1196             exit(-1);
1197         }
1198     }
1199 }
1200
1201 /* This function prints type information. */
1202 void PrintTypeInfo(char *var, BPatch_type *type) {
1203       if (!type) {
1204         printf("NO RETURN TYPE INFO for %s\n", var);
1205         return;
1206       }
1207
1208       switch(type->getDataClass()){
1209       case BPatch_array:
1210         printArray( type );
1211         printf(" %s\n", var);
1212         break;
1213           
1214       case BPatch_pointer:
1215         printPtr( type );
1216         printf(" %s\n", var);
1217         break;
1218         
1219       default:
1220         printf("%s %s\n", type->getName(), var);
1221         break;
1222       }
1223 }
1224
1225 /* This function displays all the functions in the executable or the functions in a module
1226  * if a module name is provided.
1227  */
1228 int ShowFunctions(int argc, char *argv[]) {
1229     BPatch_Vector<BPatch_function *> *functions = NULL;
1230
1231     if (argc == 2) 
1232         functions = appImage->getProcedures();
1233     else if ( (argc == 4) && (!strcmp(argv[2], "in")) ) {
1234         //First locate the module using module name given in argv[3]
1235         BPatch_Vector<BPatch_module *> *modules = appImage->getModules();
1236
1237         if (!modules) {
1238                 printf("Can not get module info !\n");
1239                 return TCL_ERROR;
1240         }
1241
1242         char modName[1024];
1243         BPatch_module *module = NULL;
1244
1245         for(int i=0; i<modules->size(); ++i) {
1246                 (*modules)[i]->getName(modName, 1024);
1247
1248                 if (!strcmp(modName, argv[3])) {
1249                         module = (*modules)[i];
1250                         break;
1251                 }
1252         }
1253
1254         if (!module) {
1255                 printf("Module %s is not found !\n", argv[3]);
1256                 return TCL_ERROR;
1257         }
1258
1259         //Get the module functions
1260         functions = module->getProcedures();
1261     }
1262     else {
1263         printf("Syntax error !\n");
1264         return TCL_ERROR;
1265     }
1266
1267     if (!functions) {
1268         printf("Can not get function list!\n");
1269         return TCL_ERROR;
1270     }
1271
1272     //Now print all the functions in the module
1273     char funcName[1024];
1274     for(int i=0; i<functions->size(); ++i) {
1275         (*functions)[i]->getName(funcName, 1024);
1276         PrintTypeInfo(funcName, (*functions)[i]->getReturnType());
1277     }
1278
1279     return TCL_OK;
1280 }
1281
1282 /* Finds all the modules in the executable and displays the module names */
1283 int ShowModules()
1284 {
1285     char modName[1024];
1286     BPatch_Vector<BPatch_module *> *modules = appImage->getModules();
1287
1288     if (!modules) {
1289         printf("Can not get module info !\n");
1290         return TCL_ERROR;
1291     }
1292
1293     for(int i=0; i<modules->size(); ++i) {
1294         (*modules)[i]->getName(modName, 1024);
1295         printf("%s\n", modName);
1296     }
1297
1298     return TCL_OK;
1299 }
1300
1301 /*
1302  * This function finds and prints all the parameters
1303  * of a function whose name is given as input.
1304  */
1305 int ShowParameters(int argc, char *argv[]) {
1306     if ( (argc != 4) || (strcmp(argv[2], "in")) ) {
1307         printf("Syntax error!\n");
1308         return TCL_ERROR;
1309     }
1310
1311     BPatch_function *fp = appImage->findFunction(argv[3]);
1312
1313     if (!fp) {
1314         printf("Invalid function name: %s\n", argv[3]);
1315         return TCL_ERROR;
1316     }
1317
1318     BPatch_Vector<BPatch_localVar *> *params = fp->getParams();
1319     for(int i=0; i<params->size(); ++i) {
1320         PrintTypeInfo((char *) (*params)[i]->getName(), (*params)[i]->getType());
1321     }
1322
1323     return TCL_OK;
1324 }
1325
1326 /*
1327  * This function finds and prints all the local variables
1328  * of a function whose name is given as input.
1329  */
1330 int ShowLocalVars(char *funcName) {
1331     BPatch_function *fp = appImage->findFunction(funcName);
1332
1333     if (!fp) {
1334         printf("Invalid function name: %s\n", funcName);
1335         return TCL_ERROR;
1336     }
1337
1338     BPatch_Vector<BPatch_localVar *> *vars = fp->localVariables->getAllVars();
1339     for(int i=0; i<vars->size(); ++i) {
1340         PrintTypeInfo((char *) (*vars)[i]->getName(), (*vars)[i]->getType());
1341     }
1342
1343     delete vars;
1344
1345     return TCL_OK;
1346 }
1347
1348 /* Finds all the global vars in the executable and prints their names. */
1349 int ShowGlobalVars() {
1350     BPatch_Vector<BPatch_variableExpr *> *vars = appImage->getGlobalVariables();
1351
1352     if (!vars) {
1353         printf("Can not get global variable info !\n");
1354         return TCL_ERROR;
1355     }
1356
1357     for(int i=0; i<vars->size(); ++i) {
1358         PrintTypeInfo((*vars)[i]->getName(), (BPatch_type *) (*vars)[i]->getType());
1359     }
1360
1361     return TCL_OK;
1362 }
1363
1364 /* Finds all global variables or local variables in the function */
1365 int ShowVariables(int argc, char *argv[])
1366 {
1367     if (argc == 2)
1368         return ShowGlobalVars();
1369
1370     if ( (argc == 4) && (!strcmp(argv[2], "in")) )
1371         return ShowLocalVars(argv[3]);
1372
1373     //Should not reach here!
1374     return TCL_ERROR;
1375 }
1376
1377 /* Displays either modules or functions in a specific module in the executable */
1378
1379 int showCommand(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
1380 {
1381     if (!haveApp()) return TCL_ERROR;
1382
1383     if (argc == 1)
1384         return TCL_ERROR;
1385
1386     if (!strcmp(argv[1], "modules"))
1387         return ShowModules();
1388
1389     if (!strcmp(argv[1], "functions"))
1390         return ShowFunctions(argc, argv);
1391
1392     if (!strcmp(argv[1], "variables"))
1393         return ShowVariables(argc, argv);
1394
1395     if (!strcmp(argv[1], "parameters"))
1396         return ShowParameters(argc, argv);
1397
1398     printf("Syntax error!\n");
1399     return TCL_ERROR;
1400 }
1401
1402 /* Displays how many times input fcn is called */
1403 int countCommand(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
1404 {
1405     if (!haveApp()) return TCL_ERROR;
1406
1407     if (argc != 2) {
1408         printf("Invalid number of arguments for count command!\n");
1409         return TCL_ERROR;
1410     }
1411
1412     BPatch_function *fp = appImage->findFunction(argv[1]);
1413
1414     if (!fp) {
1415         printf("Invalid function name: %s\n", argv[1]);
1416         return TCL_ERROR;
1417     }
1418
1419     char *fcnName = argv[1];
1420     char cmdBuf[1024];
1421
1422     sprintf(cmdBuf, "declare int _%s_cnt", fcnName);
1423     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1424         return TCL_ERROR;
1425
1426     sprintf(cmdBuf, "at main entry { _%s_cnt = 0; }", fcnName);
1427     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1428         return TCL_ERROR;
1429
1430     sprintf(cmdBuf, "at %s entry { _%s_cnt++; }", fcnName, fcnName);
1431     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1432         return TCL_ERROR;
1433
1434     sprintf(cmdBuf, "at main exit { printf(\"%s called %%d times\\n\", _%s_cnt); }", 
1435                                                                         fcnName, fcnName);
1436     if (Tcl_Eval(interp, cmdBuf) == TCL_ERROR)
1437         return TCL_ERROR;
1438
1439     return TCL_OK;
1440 }
1441
1442 /*
1443  * Replace all calls to fcn1 with calls fcn2
1444  */
1445 int repFunc(char *name1, char *name2) {
1446
1447     BPatch_function *func1 = appImage->findFunction(name1);
1448     if (!func1) {
1449         printf("Invalid function name: %s\n", name1);
1450         return TCL_ERROR;
1451     }
1452
1453     BPatch_function *func2 = appImage->findFunction(name2);
1454     if (!func2) {
1455         printf("Invalid function name: %s\n", name2);
1456         return TCL_ERROR;
1457     }
1458
1459     if (appThread->replaceFunction(*func1, *func2))
1460         return TCL_OK;
1461
1462     return TCL_ERROR;
1463 }
1464
1465 /*
1466  * Replaces functions or function calls with input function
1467  */
1468 int replaceCommand(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
1469 {
1470     if (!haveApp()) return TCL_ERROR;
1471
1472     if ( (argc != 5) || (strcmp(argv[1], "function")) || 
1473                         (strcmp(argv[3], "with")) ) 
1474     {
1475         printf("Invalid number of arguments to replace command!\n");
1476         return TCL_ERROR;
1477     }
1478
1479     if (!strcmp(argv[1], "function"))
1480         return repFunc(argv[2], argv[4]);
1481
1482     // Replace function calls
1483     // Not implemented yet!
1484  
1485     return TCL_OK;
1486 }
1487
1488 //
1489 // Tcl AppInit defines the new commands for dyninst
1490 //
1491 int Tcl_AppInit(Tcl_Interp *interp)
1492 {
1493     if (Tcl_Init(interp) == TCL_ERROR) {
1494         return TCL_ERROR;
1495     }
1496     
1497     Tcl_CreateCommand(interp, "at", instStatement, NULL, NULL);
1498     Tcl_CreateCommand(interp, "cbreak", condBreak, NULL, NULL);
1499     Tcl_CreateCommand(interp, "declare", newVar, NULL, NULL);
1500     Tcl_CreateCommand(interp, "listbreak", listBreak, NULL, NULL);
1501     Tcl_CreateCommand(interp, "deletebreak", deleteBreak, NULL, NULL);
1502     Tcl_CreateCommand(interp, "help", help, NULL, NULL);
1503     Tcl_CreateCommand(interp, "kill", killApp, NULL, NULL);
1504     Tcl_CreateCommand(interp, "load", loadCommand, NULL, NULL);
1505     Tcl_CreateCommand(interp, "run", runApp, NULL, NULL);
1506     Tcl_CreateCommand(interp, "print", printVar, NULL, NULL);
1507     Tcl_CreateCommand(interp, "whatis", whatisVar, NULL, NULL);
1508     Tcl_CreateCommand(interp, "show", showCommand, NULL, NULL);
1509     Tcl_CreateCommand(interp, "count", countCommand, NULL, NULL);
1510     Tcl_CreateCommand(interp, "replace", replaceCommand, NULL, NULL);
1511     
1512     bpatch.registerErrorCallback(errorFunc);
1513     bpatch.setTypeChecking(false);
1514
1515     return TCL_OK;
1516 }
1517
1518 int main(int argc, char *argv[])
1519 {
1520     if (argc >= 2 && !strcmp(argv[1], "-debug")) {
1521         printf("parser debug enabled\n");
1522         dynerdebug = 1;
1523     }
1524
1525     Tcl_Main(argc, argv, Tcl_AppInit);
1526     return 0;
1527 }