First Commit of this utility to let altinel start working on it.
[dyninst.git] / dyner / src / dyner.C
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <tcl.h>
7 #include <list>
8
9 #include "BPatch.h"
10 #include "BPatch_Vector.h"
11 #include "BPatch_thread.h"
12 #include "BPatch_snippet.h"
13 #include "BPatch_type.h"
14 #include "breakpoint.h"
15
16 extern "C" int sleep(unsigned);
17 extern "C" int usleep(unsigned);
18
19 extern "C" {
20 int sleep(unsigned);
21 void set_lex_input(char *s);
22 int yyparse();
23 extern int yydebug;
24 }
25
26 int debugPrint = 0;
27 BPatch_point *targetPoint;
28 BPatch_function *targetFunc;
29 bool errorLoggingOff = false;
30
31 // control debug printf statements
32 #define dprintf if (debugPrint) printf
33
34 class ListElem {
35 public:
36     int                      number;
37     char                     *function;
38     BPatch_procedureLocation where;
39     BPatch_callWhen          when;
40     BPatchSnippetHandle      *handle;
41 };
42
43 class BPListElem: public ListElem {
44 public:
45     char                     *condition;
46
47     BPListElem(int _number, char *_function, BPatch_procedureLocation _where,
48                BPatch_callWhen _when, char *_condition,
49                BPatchSnippetHandle *_handle);
50     ~BPListElem();
51 };
52
53 class runtimeVar {
54 public:
55     runtimeVar(BPatch_variableExpr *v, char *n) { var = v, name = strdup(n); }
56     BPatch_variableExpr *var;
57     char *name;
58 };
59
60 class IPListElem: public ListElem {
61 public:
62     char                     *statement;
63
64     IPListElem(int _number, char *_function, BPatch_procedureLocation _where,
65                BPatch_callWhen _when, char *_condition,
66                BPatchSnippetHandle *_handle);
67     ~IPListElem();
68 };
69
70 BPatch bpatch;
71 BPatch_thread *appThread = NULL;
72 BPatch_image *appImage = NULL;
73 static BPatch_variableExpr *bpNumber = NULL;
74 static int bpCtr = 1;
75 static int ipCtr = 1;
76 static list<ListElem *> bplist;
77 static list<ListElem *> iplist;
78 static list<runtimeVar *> varList;
79
80
81 BPListElem::BPListElem(int _number, char *_function,
82     BPatch_procedureLocation _where, BPatch_callWhen _when, char *_condition,
83     BPatchSnippetHandle *_handle)
84 {
85     number = _number;
86     function = strdup(_function);
87     where = _where;
88     when = _when;
89     condition = strdup(_condition);
90     handle = _handle;
91 }
92
93 BPListElem::~BPListElem()
94 {
95     free(function);
96     free(condition);
97 }
98
99 IPListElem::IPListElem(int _number, char *_function,
100     BPatch_procedureLocation _where, BPatch_callWhen _when, char *_condition,
101     BPatchSnippetHandle *_handle)
102 {
103     number = _number;
104     function = strdup(_function);
105     where = _where;
106     when = _when;
107     statement = strdup(_condition);
108     handle = _handle;
109 }
110
111 IPListElem::~IPListElem()
112 {
113     free(function);
114     free(statement);
115     if (handle) delete handle;
116 }
117
118 list<ListElem *>::iterator findBP(int n)
119 {
120     list<ListElem *>::iterator i;
121
122     for (i = bplist.begin(); i != bplist.end(); i++) {
123         if ((*i)->number == n) break;
124     }
125
126     return i;
127 }
128
129 int help(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
130 {
131
132     printf("at <function> [entry|exit|preCall|postCall] <statement> - instert statement\n");
133     printf("declare <variable> <type> - create a new variable of type <type>\n");
134     printf("deletebreak <breakpoint number ...> - delete breakpoint(s)\n");
135     printf("cbreak <function> [entry|exit|preCall|postCall] <condition> - set a conditional\n");
136     printf("  break point\n");
137     printf("listbreak - list break points\n");
138     printf("load <program> [arguments] [< filename] [> filename] - load a program\n");
139     printf("run - run or continue the loaded program\n");
140     return TCL_OK;
141 }
142
143 bool haveApp()
144 {
145     if (appThread == NULL) {
146         fprintf(stderr, "No application loaded.\n");
147         return false;
148     }
149
150     if (appThread->isTerminated()) {
151         fprintf(stderr, "The application has exited.\n");
152         return false;
153     }
154
155     return true;
156 }
157
158 bool name2loc(char *s, BPatch_procedureLocation &where,
159               BPatch_callWhen &when)
160 {
161     if (!strcmp(s, "entry")) {
162         where = BPatch_entry;
163         when = BPatch_callBefore;
164     } else if (!strcmp(s, "exit")) {
165         where = BPatch_exit;
166         when = BPatch_callBefore;
167     } else if (!strcmp(s, "preCall")) {
168         where = BPatch_subroutine;
169         when = BPatch_callBefore;
170     } else if (!strcmp(s, "postCall")) {
171         where = BPatch_subroutine;
172         when = BPatch_callAfter;
173     } else {
174         return false;
175     }
176     return true;
177 }
178
179 char *loc2name(BPatch_procedureLocation where, BPatch_callWhen when)
180 {
181     switch (where) {
182       case BPatch_entry:
183         return "entry";
184       case BPatch_exit:
185         return "exit";
186       case BPatch_subroutine:
187         if (when == BPatch_callBefore) return "preCall";
188         else return "postCall";
189       default:
190         return "<error>";
191     };
192 }
193
194 int loadApp(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
195 {
196     char *pathname = argv[1];
197
198     if (argc < 2) {
199         printf("Usage load <program> [<arguments>]\n");
200         return TCL_ERROR;
201     }
202     
203     printf("Loading \"%s\"\n", pathname);
204
205     if (appThread != NULL) delete appThread;
206     bplist.erase(bplist.begin(), bplist.end());
207     appThread = bpatch.createProcess(pathname, &argv[1]);
208     bpNumber = NULL;
209
210     if (!appThread || appThread->isTerminated()) {
211         fprintf(stderr, "Unable to run test program.\n");
212         appThread = NULL;
213         return TCL_ERROR;
214     }
215
216     // Read the program's image and get an associated image object
217     appImage = appThread->getImage();
218
219     if (appImage) return TCL_OK;
220
221     return TCL_ERROR;
222
223 }
224
225
226 int listBreak(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
227 {
228     if (!haveApp()) return TCL_ERROR;
229
230     BPListElem *curr;
231     list<ListElem *>::iterator i;
232
233     for (i = bplist.begin(); i != bplist.end(); i++) {
234         curr = (BPListElem *) *i;
235         printf("%2d: in %s (%s), condition %s\n",
236                 curr->number, curr->function,
237                 loc2name(curr->where, curr->when),
238                 curr->condition);
239     }
240 }
241
242 int deleteBreak(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
243 {
244     if (!haveApp()) return TCL_ERROR;
245
246     if (argc < 2) {
247         fprintf(stderr, "Specify breakpoint(s) to delete.\n");
248         return TCL_ERROR;
249     }
250
251     int ret = TCL_OK;
252     for (int j = 1; j < argc; j++) {
253         int n = atoi(argv[j]);
254
255         list<ListElem *>::iterator i = findBP(n);
256         if (i == bplist.end()) {
257             printf("No such breakpoint: %d\n", n);
258             ret = TCL_ERROR;
259         } else {
260             appThread->deleteSnippet((*i)->handle);
261             delete *i;
262             bplist.erase(i);
263             printf("Breakpoint %d deleted.\n", n);
264         }
265     }
266
267     return ret;
268 }
269
270 int runApp(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
271 {
272     hrtime_t start_time, end_time;
273
274     start_time = gethrtime();
275
276     if (!haveApp()) return TCL_ERROR;
277
278     if (bpNumber) {
279         int inval = -1;
280         bpNumber->writeValue(&inval);
281     }
282
283     // Start of code to continue the process.
284     dprintf("starting program execution.\n");
285     appThread->continueExecution();
286
287     while (!appThread->isStopped() && !appThread->isTerminated())
288         usleep(250);
289
290     int bp = -1;
291     if (bpNumber) bpNumber->readValue(&bp);
292
293     if (appThread->isTerminated()) {
294         printf("\nApplication exited.\n");
295     } else if (appThread->isStopped() && bp > 0) {
296         printf("\nStopped at break point %d.\n", bp);
297         list<ListElem *>::iterator i = findBP(bp);
298         if (i != bplist.end()) {
299             BPListElem *curr = (BPListElem *) *i;
300             printf("%s (%s); %s\n",
301                     curr->function,
302                     loc2name(curr->where, curr->when),
303                     curr->condition);
304         }
305     } else {
306         printf("\nStopped.\n");
307     }
308
309     end_time = gethrtime();
310
311     printf("Running time (nanoseconds): %lld\n", end_time - start_time);
312
313     return TCL_OK;
314 }
315
316 int killApp(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
317 {
318     if (!haveApp()) return TCL_ERROR;
319
320     appThread->terminateExecution();
321
322     return TCL_OK;
323 }
324
325 extern BPatch_snippet *parse_result;
326 int condBreak(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
327 {
328     if (!haveApp()) return TCL_ERROR;
329
330     if (bpNumber == NULL) {
331         bpNumber = appThread->malloc(*appImage->findType("int"));
332         if (bpNumber == NULL) {
333             fprintf(stderr, "Unable to allocate memory in the inferior process.\n");
334             exit(1);
335         }
336     }
337
338     if (argc < 3) {
339         printf("Wrong number of paramters.\n");
340         return TCL_ERROR;
341     }
342
343     int expr_start = 2;
344     BPatch_procedureLocation where;
345     BPatch_callWhen when;
346     if (name2loc(argv[2], where, when)) {
347         expr_start = 3;
348     } else {
349         where = BPatch_entry;
350         when = BPatch_callBefore;
351     }
352
353     BPatch_Vector<BPatch_point *> *points =
354         appImage->findProcedurePoint(argv[1], where);
355     if (points == NULL) {
356         fprintf(stderr, "Unable to locate function: %s\n", argv[1]);
357         return TCL_ERROR;
358     }
359
360     // Count up how large a buffer we need for the whole line
361     int line_len = 0;
362     for (int i = expr_start; i < argc; i++)
363         line_len += strlen(argv[i]) + 1;
364     line_len++;
365     // Make the buffer and copy the line into it
366     char *line_buf = new char[line_len];
367     *line_buf = '\0';
368     for (int i = expr_start; i < argc; i++) {
369         strcat(line_buf, argv[i]);
370         if (i != argc-1) strcat(line_buf, " ");
371     }
372
373     set_lex_input(line_buf);
374     if (yyparse() != 0) {
375         fprintf(stderr, "Breakpoint not set due to error.\n");
376         delete line_buf;
377         return TCL_ERROR;
378     }
379
380     if (parse_type != parsed_bool) {
381         fprintf(stderr, "Breakpoint not set due error, expression not boolean.\n");
382         delete line_buf;
383         delete parse_result;
384         return TCL_ERROR;
385     }
386
387     // Make a snippet to tell us which breakpoint it is
388     BPatch_arithExpr storeBPNum(BPatch_assign,
389                                 *bpNumber, BPatch_constExpr(bpCtr));
390
391     // Make a snippet to break at the breakpoint
392     BPatch_function *breakFunc = appImage->findFunction("DYNINSTbreakPoint");
393     if (breakFunc == NULL) {
394         fprintf(stderr, "Unable to find function DYNINSTbreakPoint (required for setting break points)\n");
395         delete parse_result;
396         delete line_buf;
397         return TCL_ERROR;
398     }
399
400     BPatch_Vector<BPatch_snippet *> nullArgs;
401     BPatch_funcCallExpr callBreak(*breakFunc, nullArgs);
402
403     // store the break point number, then  break
404     BPatch_arithExpr doBreak(BPatch_seq, storeBPNum, callBreak);
405     
406
407     // Call the break snippet conditionally
408     BPatch_ifExpr condBreak(*(BPatch_boolExpr *)parse_result, doBreak); 
409
410     delete parse_result;
411
412     BPatchSnippetHandle *handle =
413         appThread->insertSnippet(condBreak, *points, when,BPatch_lastSnippet);
414     if (handle == 0) {
415         fprintf(stderr, "Error inserting snippet.\n");
416         delete line_buf;
417         return TCL_ERROR;
418     }
419
420     BPListElem *bpl =
421         new BPListElem(bpCtr, argv[1], where, when, line_buf, handle);
422     delete line_buf;
423
424     bplist.push_back(bpl);
425
426     printf("Breakpoint %d set.\n", bpCtr);
427     bpCtr++;
428
429     return TCL_OK;
430 }
431 /*
432  * void printPtr( )
433  *
434  * This function recursively goes through the BPatch_type pointers until
435  * it gets to the base type and prints that name.  The base type can be
436  * a builtin type or an enum, struct, or union.  The default case handles
437  * unknown pointer types.  -- jdd 5/27/99
438  */
439 void printPtr( BPatch_type * type )
440 {
441   if( type->type() == BPatch_pointer ){
442     printPtr( type->getConstituentType() );
443     printf("*");
444   }
445   else if((type->type() == BPatch_scalar)||(type->type() == BPatchSymTypeRange)){
446     printf("        %s ", type->getName());
447   }
448   else{
449     switch( type->type() ){
450     case BPatch_enumerated:
451       printf("        enum %s", type->getName());
452       break;
453     case BPatch_structure:
454       printf("        struct %s", type->getName());
455       break;
456     case BPatch_union:
457       printf("        union %s", type->getName());
458       break;
459     default:
460       printf("Undefined POINTER: %s", type->getName());
461       break;
462     }
463   }
464   
465 }
466 /*
467  * printArray()
468  *
469  * This function prints arrays of various dimension, 1D to 3D. It first
470  * checks how many dimensions the array is and then prints it out.
471  * The default case handles the unknown. --jdd 5/27/99
472  */
473  
474 void printArray(BPatch_type * type )
475 {
476   int j = 0;
477   if(type->getConstituentType()){
478     j++;
479     if(type->getConstituentType()->getConstituentType()){
480       j++;
481       if(type->getConstituentType()->getConstituentType()->getConstituentType()){
482         j++;
483       }
484     }
485   }
486   switch(j){
487   case 3:
488     
489     //3D array
490     printf("    %s is an array [%s..%s][%s..%s][%s..%s] of %s\n",
491            type->getName(), type->getLow(), type->getHigh(),
492            type->getConstituentType()->getLow(),
493            type->getConstituentType()->getHigh(),
494            type->getConstituentType()->getConstituentType()->getLow(),
495            type->getConstituentType()->getConstituentType()->getHigh(),
496            type->getConstituentType()->getConstituentType()->getConstituentType()->getName());
497     break;
498   case 2:
499         
500     //2D array
501     printf("    %s is an array [%s..%s][%s..%s] of %s\n", type->getName(), 
502            type->getLow(), type->getHigh(),
503            type->getConstituentType()->getLow(),
504            type->getConstituentType()->getHigh(),
505            type->getConstituentType()->getConstituentType()->getName());
506     break;
507   case 1:
508     printf("    %s is an array [%s..%s] of %s\n", type->getName(),
509            type->getLow(), type->getHigh(), 
510            type->getConstituentType()->getName());
511     break;
512   default:
513     printf("Unable to process array %s\n", type->getName());
514     break;
515   }
516 }
517
518 int instStatement(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
519 {
520     if (!haveApp()) return TCL_ERROR;
521
522     if (argc < 3) {
523         printf("Wrong number of paramters.\n");
524         return TCL_ERROR;
525     }
526
527     int expr_start = 2;
528     BPatch_procedureLocation where;
529     BPatch_callWhen when;
530     if (name2loc(argv[2], where, when)) {
531         expr_start = 3;
532     } else {
533         where = BPatch_entry;
534         when = BPatch_callBefore;
535     }
536
537     BPatch_Vector<BPatch_point *> *points =
538         appImage->findProcedurePoint(argv[1], where);
539     if (points == NULL) {
540         fprintf(stderr, "Unable to locate function: %s\n", argv[1]);
541         return TCL_ERROR;
542     }
543     if (points->size() != 1) {
544         fprintf(stderr, "function %s is not unique (due to overloading?)\n", 
545             argv[1]);
546         return TCL_ERROR;
547     }
548
549     targetPoint = (*points)[0];
550     assert(targetPoint);
551
552     // Count up how large a buffer we need for the whole line
553     int line_len = 0;
554     for (int i = expr_start; i < argc; i++)
555         line_len += strlen(argv[i]) + 1;
556     line_len += 2;
557     // Make the buffer and copy the line into it
558     char *line_buf = new char[line_len];
559     *line_buf = '\0';
560     for (int i = expr_start; i < argc; i++) {
561         strcat(line_buf, argv[i]);
562         if (i != argc-1) strcat(line_buf, " ");
563     }
564     strcat(line_buf, "\n");
565
566     printf("calling parse of %s\n", line_buf);
567     set_lex_input(line_buf);
568     if (yyparse() != 0) {
569         fprintf(stderr, "Instrumentation not set due to error.\n");
570         delete line_buf;
571         targetPoint = NULL;
572         return TCL_ERROR;
573     }
574
575     targetPoint = NULL;
576
577     if (parse_type != parsed_statement) {
578         fprintf(stderr, "code not inserted, expression is not a statement.\n");
579         delete line_buf;
580         delete parse_result;
581         return TCL_ERROR;
582     }
583
584     BPatchSnippetHandle *handle =
585         appThread->insertSnippet(*parse_result, *points, when,BPatch_lastSnippet);
586     if (handle == 0) {
587         fprintf(stderr, "Error inserting snippet.\n");
588         delete line_buf;
589         return TCL_ERROR;
590     }
591
592     IPListElem *snl =
593         new IPListElem(ipCtr, argv[1], where, when, line_buf, handle);
594     delete line_buf;
595
596     iplist.push_back(snl);
597
598     printf("Inst point %d set.\n", ipCtr);
599     ipCtr++;
600
601     return TCL_OK;
602 }
603
604 printVarRecursive(BPatch_variableExpr *var, int level)
605 {
606     int iVal;
607     int pVal;
608     float fVal;
609
610     BPatch_dataClass dc;
611     BPatch_type *type = var->getType();
612
613     dc = type->type();
614     if (!strcmp(type->getName(), "int")) {
615         /* print out the integer */
616         var->readValue((void *) &iVal);
617         printf("%d\n", iVal);
618     } else if (!strcmp(type->getName(), "float")) {
619         /* print out the float */
620         var->readValue((void *) &fVal);
621         printf("%f\n", fVal);
622     } else if (dc == BPatch_pointer) {
623         /* print out the float */
624         var->readValue((void *) &pVal);
625         printf("0x%x\n", pVal);
626     } else if (dc == BPatch_structure) {
627         printf("struct {\n");
628         level++;
629         BPatch_Vector<BPatch_variableExpr *> *fields = var->getComponents();
630         for (int i=0; i < fields->size(); i++) {
631              BPatch_variableExpr *fieldVar = (*fields)[i];
632              for (int i=0;i < level; i++) printf("    ");
633              printf("%s = ", fieldVar->getName());
634              printVarRecursive(fieldVar, level);
635         }
636         level--;
637         printf("}\n");
638     } else if (dc == BPatch_array) {
639         printf("<arrays not yet implemented>\n");
640     } else {
641         printf("<unknown type>\n");
642     }
643 }
644
645 int printVar(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
646 {
647     if (!haveApp()) return TCL_ERROR;
648
649     BPatch_variableExpr *var = findVariable(argv[1]);
650     if (!var) {
651         printf("%s is not defined\n", argv[1]);
652         return TCL_ERROR;
653     }
654
655     printf("    %s = ", argv[1]);
656     printVarRecursive(var, 1);
657
658     return TCL_OK;
659 }
660
661 /*
662  * declare <variable name> <type>
663  */
664 int newVar(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
665 {
666     if (!haveApp()) return TCL_ERROR;
667
668     BPatch_type *type = appImage->findType(argv[2]);
669     if (!type) {
670         printf("type %s is not defined\n", argv[1]);
671         return TCL_ERROR;
672     }
673
674     BPatch_variableExpr *newVar = appThread->malloc(*type);
675     if (!newVar) {
676         printf("unable to create variable.\n");
677         return TCL_ERROR;
678     }
679
680     varList.push_back(new runtimeVar(newVar, argv[1]));
681 }
682
683 BPatch_variableExpr *findVariable(char *name)
684 {
685     BPatch_variableExpr *var;
686     list<runtimeVar *>::iterator i;
687
688     // first check the function locals
689     if (targetPoint) {
690         var = appImage->findVariable(*targetPoint, name);
691         if (var) return var;
692     }
693
694     errorLoggingOff = true;
695     var = appImage->findVariable(name);
696     errorLoggingOff = false;
697
698     if (var) return var;
699
700     // now look for runtime created variables
701     for (i = varList.begin(); i != varList.end(); i++) {
702         if (!strcmp(name, (*i)->name)) {
703             var = new BPatch_variableExpr(*((*i)->var));
704             return (var);
705         }
706     }
707
708     printf("unable to locate variable %s\n", name);
709     return NULL;
710 }
711
712 /* 
713  * int whatisParam()
714  *
715  * This function is an extension to the "whatis" command.  This function
716  * processes the command: whatis -scope <function> <variable>. If the
717  * <function> is undefined then TCL_ERROR is returned.  Otherwise, the
718  * local variable collection is searched first; followed by the parameter
719  * collection; and finally the Global collection is searched last. If the
720  * <variable> is not found, then "<variable> is not defined" is reported
721  * to the user. --jdd 5/27/98
722  */
723 int whatisParam(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
724 {
725   if (!haveApp()) return TCL_ERROR;
726   BPatch_function * func = appImage->findBPFunction(argv[2]);
727   printf("func is %x\n", func);
728   if(!func){
729     printf("%s is not defined\n", argv[3]);
730     return TCL_ERROR;
731   }
732   
733   
734   BPatch_localVar * lvar = func->findLocalVar(argv[3]);
735   if(lvar){
736     BPatch_type *type = lvar->getType();
737     if( type ){
738       switch (type->type()) {
739       case BPatch_array:
740         printArray( type );
741         break;
742         
743       case BPatch_pointer:
744         printPtr( type );
745         printf("\t %s\n", argv[3]);
746         break;
747         
748       default:
749         printf("    %s is of type %s \n", argv[3], type->getName());
750         break;
751       }
752     }
753     //print local variable info
754     printf("        %s is a local variable in function %s\n", lvar->getName(),
755            argv[2]);
756     printf("        Declared on line %d and has a Frame offset of %d\n",
757            lvar->getLineNum(), lvar->getFrameOffset());
758   }
759   else{
760     lvar = func->findLocalParam(argv[3]);
761     
762     if (!lvar) {
763       BPatch_variableExpr *var = findVariable(argv[3]);
764       if(!var){
765         // do something else ??
766         //int ret = whatisType(cd, interp, argc, argv);
767         return TCL_OK;
768       }
769       BPatch_type *type = var->getType();
770       switch (type->type()) {
771       case BPatch_array:
772         printArray( type );
773         break;
774         
775       case BPatch_pointer:
776         printPtr( type );
777         printf("\t %s\n", argv[3]);
778         break;
779         
780       default:
781         printf("    %s is of type %s \n", argv[3], type->getName());
782         break;
783       }
784      printf("      %s is a Global variable\n", argv[3]);
785     }
786     else{
787       const BPatch_type *lType = lvar->getType();
788       if (lType){
789         switch (lType->type()) {
790         case BPatch_array:
791           printArray( lType );
792           break;
793           
794         case BPatch_pointer:
795           printPtr( lType );
796           printf("\t %s\n", argv[3]);
797           break;
798           
799         default:
800           printf("    %s is of type %s \n", argv[3], lType->getName());
801           break;
802         }
803         printf("       %s is a parameter of the function %s\n",lvar->getName(),
804            argv[2]);
805         printf("       Declared on line %d and has a Frame offset of %d\n",
806            lvar->getLineNum(), lvar->getFrameOffset());
807       }
808       else{
809         printf("   unknown type %s\n", lvar->getName());
810       }
811     }   
812   }
813   return TCL_OK;
814 }
815
816 /*
817  * int whatisFunc()
818  *
819  * This function is an extension to the "whatis" command.  This function
820  * searches all of the modules to find the BPatch_function with the name
821  * given be argv[1]. If no such function is found, then TCL_ERROR is returned.
822  * This is the last function in the chain of "whatis" command functions to
823  * be executed in the search for argv[1]. --jdd 5/27/99
824  */
825  
826 int whatisFunc(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
827 {
828     if (!haveApp()) return TCL_ERROR;
829     // If the function is found it returns the BPatch_function.
830     // findFunction() creates a new BPatch_function so it is not
831     // used here. --jdd 5/27/99
832     BPatch_function * func = appImage->findBPFunction(argv[1]);
833     
834     if(!func){
835       printf("%s is not defined\n", argv[1]);
836       return TCL_ERROR;
837     }
838     printf("    Function %s ", argv[1]);
839     BPatch_type * retType = func->getReturnType();
840     if(retType)
841       switch(retType->type()){
842       case BPatch_scalar:
843       case BPatchSymTypeRange:
844         printf("  with return type %s\n",retType->getName() );
845         break;
846       case BPatch_array:
847         printf("  with return type ");
848         printArray( retType );
849         printf("\n");
850         break;
851           
852       case BPatch_pointer:
853         printf("  with return type ");
854         printPtr( retType );
855         printf("\n");
856         break;
857         
858       default:
859         printf("    %s has unknown return type %s %d\n",argv[1],
860                retType->getName(), retType->getID());
861         break;
862       }
863     else
864       printf("   unknown return type for %s\n", argv[1]);
865     BPatch_Vector<BPatch_localVar *> *params = func->getParams();
866     if( params->size())
867       printf("        Parameters: \n");
868     for (int i=0; i < params->size(); i++) {
869       BPatch_localVar *localVar = (*params)[i];
870       const BPatch_type *lType = localVar->getType();
871       if (lType){
872         if( (lType->type())  == BPatch_pointer){
873           printPtr(lType);
874           printf(" \t %s\n", localVar->getName());
875         }
876         else if( (lType->type()) == BPatch_array){
877           printArray( lType );
878         }
879         else
880           printf("        %s %s\n",lType->getName(), localVar->getName());
881         
882       }
883       else{
884         printf("   unknown type %s\n", localVar->getName());
885       }
886     }    
887     return TCL_OK;
888 }
889
890 /*
891  * int whatisType()
892  *
893  * This function is an extension to the "whatis" command.  This function
894  * searches for the type collection of the all the modules looking for
895  * the type specified by argv[1]. If it is not found, then whatisFunc()
896  * is called. This is function is called by whatisVar if a variable is
897  * not found. -- jdd 5/27/99
898  */
899  
900 int whatisType(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
901 {
902     if (!haveApp()) return TCL_ERROR;
903     
904     BPatch_type *type = appImage->findType(argv[1]);
905     if (!type) {
906       int ret = whatisFunc(cd, interp, argc, argv);
907       return ret;
908     }
909
910     BPatch_dataClass dc = type->type();
911     switch (dc) {
912     case BPatch_structure: {
913       printf("    struct %s {\n", argv[1]);
914       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
915       for (int i=0; i < fields->size(); i++) {
916         BPatch_field *field = (*fields)[i];
917         const BPatch_type *fType = field->getType();
918         if (fType){
919           switch (fType->type()) {
920           case BPatch_array:
921             printArray( fType );
922             printf("  %s\n", field->getName());
923             break;
924         
925           case BPatch_pointer:
926             printPtr( fType );
927             printf("  %s\n", field->getName());
928             break;
929         
930           default:
931             printf("        %s %s\n", fType->getName(), field->getName());
932             break;
933           }
934         }
935         else{
936           printf("   unknown type %s\n", field->getName());
937         }
938       }
939       printf("    }\n");
940       break;
941     }
942     case BPatch_union: {
943       printf("    union %s {\n", argv[1]);
944       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
945       for (int i=0; i < fields->size(); i++) {
946         BPatch_field *field = (*fields)[i];
947         const BPatch_type *fType = field->getType();
948         if (fType){
949           switch (fType->type()) {
950           case BPatch_array:
951             printArray( fType );
952             printf("  %s\n", field->getName());
953             break;
954         
955           case BPatch_pointer:
956             printPtr( fType );
957             printf("  %s\n", field->getName());
958             break;
959             
960           default:
961             printf("        %s %s\n", fType->getName(), field->getName());
962             break;
963           }
964         }
965         else{
966           printf("        unknown type %s\n", field->getName());
967         }
968       }
969       printf("    }\n");
970       break;
971     }
972     case BPatch_enumerated: {
973       printf("    enum %s {\n", argv[1]);
974       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
975       for (int i=0; i < fields->size(); i++) {
976         BPatch_field *field = (*fields)[i];
977         printf("        %s    \t%d\n", field->getName(),
978                field->getValue());
979       }
980       printf("    }\n");
981       break;
982     }
983     case BPatch_array:
984       printArray( type );
985       break;
986       
987     case BPatch_scalar:
988       printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
989       break;
990       
991     case BPatch_pointer:
992       printPtr( type );
993       printf("\t %s\n", argv[1]);
994       /*
995       printf("    %s is pointer to type %s\n", argv[1], 
996              type->getConstituentType()->getName());*/
997       break;
998     case BPatchSymTypeRange:
999       if(type->getConstituentType())
1000         printf("    %s is a %s of size %d\n",argv[1],
1001                (type->getConstituentType())->getName(),type->getSize());
1002       else
1003         printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1004       if( type->getLow() ){
1005          printf("        with range %s to %s\n", type->getLow(),
1006                 type->getHigh());
1007       }
1008       break;
1009     default:
1010       printf("%s is of an unknown data class %d\n", argv[1],
1011              dc);
1012       break;
1013     }
1014     
1015     return TCL_OK;
1016 }
1017
1018 /*
1019  * int whatisVar()
1020  *
1021  * This function is an extension to the "whatis" command.  This function
1022  * searches the process for the variable named by argv[1] and then searches
1023  * all the Global variables for all the modules to find the variable
1024  * specified by argv[1].  If nothing is found, then whatisType() is called. If
1025  * whatisType() finds nothing, whatisFunc() is called.  If the command is
1026  * of the form "whatis -scope <function> <variable>", then whatisParam() is
1027  * called skipping all other attempts to find the variable. -- jdd 5/27/99
1028  */
1029
1030 int whatisVar(ClientData cd, Tcl_Interp *interp, int argc, char *argv[])
1031 {
1032     if (!haveApp()) return TCL_ERROR;
1033     
1034     if (argc == 4){ //looking for a local variable
1035       if(!(strcmp(argv[1], "-scope"))){
1036         int ret = whatisParam(cd, interp, argc, argv );
1037         return ret;
1038       } else {
1039         printf("inavlid argument %s\n", argv[1]);
1040         return TCL_ERROR;
1041       }
1042     }
1043
1044     BPatch_variableExpr *var = findVariable(argv[1]);
1045     if (!var) {
1046         int ret = whatisType(cd, interp, argc, argv);
1047         return ret;
1048     }
1049
1050     BPatch_type *type = var->getType();
1051     switch (type->type()) {
1052     case BPatch_structure: {
1053       printf("    struct %s {\n", argv[1]);
1054       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1055       for (int i=0; i < fields->size(); i++) {
1056         BPatch_field *field = (BPatch_field *) (*fields)[i];
1057         const BPatch_type *fType = field->getType();
1058         if (fType){
1059           printf("        %s %s\n", fType->getName(), field->getName());
1060         }
1061         else{
1062           printf("   unknown type %s\n", field->getName());
1063         }
1064       }
1065       printf("    }\n");
1066       break;
1067     }
1068     case BPatch_union: {
1069       printf("    union %s {\n", argv[1]);
1070       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1071       for (int i=0; i < fields->size(); i++) {
1072         BPatch_field *field = (*fields)[i];
1073         const BPatch_type *fType = field->getType();
1074         if (fType){
1075           printf("        %s %s\n", fType->getName(), field->getName());
1076         }
1077         else{
1078           printf("        unknown type %s\n", field->getName());
1079         }
1080       }
1081       printf("    }\n");
1082       break;
1083     }
1084     case BPatch_enumerated: {
1085       printf("    enum %s {\n", argv[1]);
1086       BPatch_Vector<BPatch_field *> *fields = type->getComponents();
1087       for (int i=0; i < fields->size(); i++) {
1088         BPatch_field *field = (*fields)[i];
1089         printf("        %s    \t%d\n", field->getName(),
1090                field->getValue());
1091       }
1092       printf("    }\n");
1093       break;
1094     }
1095     case BPatch_array:
1096       printArray(type);
1097       break;
1098    
1099     case BPatch_pointer:
1100       printPtr( type );
1101       printf("\t %s\n", argv[1]);
1102       /*
1103       printf("    %s is pointer to type %s\n", argv[1], 
1104              type->getConstituentType()->getName());*/
1105       break;
1106     case BPatchSymTypeRange:
1107       if(type->getConstituentType())
1108         printf("    %s is a %s of size %d\n",argv[1],
1109                (type->getConstituentType())->getName(),type->getSize());
1110       else
1111         printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1112       if( type->getLow() ){
1113         printf("        with range %s to %s\n", type->getLow(),
1114                type->getHigh());
1115       }
1116       break;
1117     case BPatch_scalar:
1118       printf("    %s is a scalar of size %d\n",argv[1],type->getSize());
1119       break;
1120       
1121     default:
1122       printf("    %s is of type %s \n", argv[1], type->getName());
1123       //int ret = whatisType(cd, interp, argc, argv);
1124       break;
1125     }
1126     
1127     return TCL_OK;
1128 }
1129
1130 const int DYNINST_NO_ERROR = -1;
1131
1132 void errorFunc(BPatchErrorLevel level, int num, const char **params)
1133 {
1134     char line[256];
1135
1136     if (errorLoggingOff) return;
1137
1138     if ((num == 0) && ((level == BPatchWarning) || (level == BPatchInfo))) {
1139          // these are old warnings/status info from paradyn
1140          return;
1141     }
1142
1143     const char *msg = bpatch.getEnglishErrorString(num);
1144     bpatch.formatErrorString(line, sizeof(line), msg, params);
1145
1146     if (num != DYNINST_NO_ERROR) {
1147         printf("Error #%d (level %d): %s\n", num, level, line);
1148
1149         // We consider some errors fatal.
1150         if (num == 101) {
1151             exit(-1);
1152         }
1153     }
1154 }
1155
1156 //
1157 // Tcl AppInit defines the new commands for dyninst
1158 //
1159 int Tcl_AppInit(Tcl_Interp *interp)
1160 {
1161     if (Tcl_Init(interp) == TCL_ERROR) {
1162         return TCL_ERROR;
1163     }
1164     
1165     Tcl_CreateCommand(interp, "at", instStatement, NULL, NULL);
1166     Tcl_CreateCommand(interp, "cbreak", condBreak, NULL, NULL);
1167     Tcl_CreateCommand(interp, "declare", newVar, NULL, NULL);
1168     Tcl_CreateCommand(interp, "listbreak", listBreak, NULL, NULL);
1169     Tcl_CreateCommand(interp, "deletebreak", deleteBreak, NULL, NULL);
1170     Tcl_CreateCommand(interp, "help", help, NULL, NULL);
1171     Tcl_CreateCommand(interp, "kill", killApp, NULL, NULL);
1172     Tcl_CreateCommand(interp, "load", loadApp, NULL, NULL);
1173     Tcl_CreateCommand(interp, "run", runApp, NULL, NULL);
1174     Tcl_CreateCommand(interp, "print", printVar, NULL, NULL);
1175     Tcl_CreateCommand(interp, "whatis", whatisVar, NULL, NULL);
1176     
1177     bpatch.registerErrorCallback(errorFunc);
1178     bpatch.setTypeChecking(false);
1179
1180     return TCL_OK;
1181 }
1182
1183 int main(int argc, char *argv[])
1184 {
1185     if (argc >= 2 && !strcmp(argv[1], "-debug")) {
1186         printf("parser debug enabled\n");
1187         yydebug = 1;
1188     }
1189
1190     Tcl_Main(argc, argv, Tcl_AppInit);
1191     return 0;
1192 }