Merge changes since Dyninst 5.2 beta 3 into trunk
[dyninst.git] / codeCoverage / src / main.C
1 /*
2  * Copyright (c) 1996-2004 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #include <stdio.h>
43 #include <iostream>
44 #include <stdlib.h>
45
46 #ifdef sparc_sun_solaris2_4
47
48 #include <string.h>
49 #include <fstream.h>
50 #include <limits.h>
51 #include <unistd.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <tcl.h>
55 #include <tk.h>
56 #include <pthread.h>
57
58 #endif
59
60 using namespace std;
61
62 #ifdef sparc_sun_solaris2_4
63
64 #include <CCcommon.h>
65 #include <FunctionCoverage.h>
66 #include <CCPreInstrument.h>
67 #include <CCOnDemandInstrument.h>
68
69 #endif
70
71 #ifdef sparc_sun_solaris2_4
72
73 typedef struct {
74         Tcl_Interp* interp;
75         CodeCoverage* codeCoverage;
76 }ARGS;
77
78 Tk_Window mainWindow = NULL;
79 Tk_Window textMessage = NULL;
80 Tk_Window fileDisplay = NULL;
81 Tk_Window fileList = NULL;
82 Tk_Window funcList = NULL;
83 Tk_Window startButton = NULL;
84 Tk_Window refreshButton = NULL;
85 Tk_Window statusMessage = NULL;
86
87 bool executionStarted = false;
88 bool isRunning = false;
89
90 void statusUpdateProcedure(ClientData clientData){
91         char buffer[1024];
92         CodeCoverage* codeCoverage = ((ARGS*)clientData)->codeCoverage;
93         Tcl_Interp* interp = ((ARGS*)clientData)->interp;
94         
95         if(codeCoverage->getTclStatusUpdateString(buffer,1024))
96                 Tcl_Eval(interp,buffer);
97
98         Tcl_CreateTimerHandler(2000,statusUpdateProcedure,clientData);
99 }
100
101 void* codeCoverageThread(void* arg){
102
103         CodeCoverage* codeCoverage = ((ARGS*)arg)->codeCoverage;
104         Tcl_Interp* interp = ((ARGS*)arg)->interp;
105
106         int errorCode = Error_OK;
107
108         /** insert the initial instrumentation code for the functions
109           * that are selected to be instrumented for code coverage
110           */
111         errorCode = codeCoverage->instrumentInitial();
112         if(errorCode < Error_OK){
113                 codeCoverage->terminate();
114                 return NULL;
115         }
116
117         if(interp)
118                 Tcl_Eval(interp,"set alreadyStarted 1");
119
120         isRunning = true;
121
122         /** runs the mutatee after the instrumentation */
123         errorCode = codeCoverage->run();
124         if(errorCode < Error_OK){
125                 codeCoverage->terminate();
126                 return NULL;
127         }
128
129         if(interp)
130                 Tcl_Eval(interp,"set isTerminated 1");
131
132         return arg;
133 }
134
135 void exitCodeCoverage(ClientData clientData){
136         CodeCoverage* codeCoverage = ((ARGS*)clientData)->codeCoverage;
137         codeCoverage->terminate();
138         //delete codeCoverage;
139         cerr << "information: terminating code coverage execution ..." << endl;
140 }
141
142 void startButtonHandler(ClientData clientData,XEvent* eventPtr){
143         if(!eventPtr)
144                 return;
145
146         CodeCoverage* codeCoverage = ((ARGS*)clientData)->codeCoverage;
147         if(!executionStarted){
148                 pthread_attr_t attr;
149                 pthread_t newThreadId;
150                 pthread_attr_init(&attr);
151                 if(pthread_create(&newThreadId,&attr,
152                                   codeCoverageThread,(void*)clientData)){
153                         codeCoverage->terminate();
154                         cerr << "ERROR : Can not create graphical"
155                              << "  interface pthread..." << endl;
156                         exit(-1);
157                 }
158                 executionStarted = true;
159         }
160 }
161
162 void refreshButtonHandler(ClientData clientData,XEvent* eventPtr);
163
164 void graphUpdateProcedure(ClientData clientData){
165
166         char buffer[1024];
167         //CodeCoverage* codeCoverage = ((ARGS*)clientData)->codeCoverage;
168         Tcl_Interp* interp = ((ARGS*)clientData)->interp;
169         
170         refreshButtonHandler(clientData,NULL);
171         
172         strcpy(buffer,"UpdateAfterRefresh .fileFrame.displayPanel.text \
173                 .fileFrame.message \
174                 .fileFrame.status \
175                 .menuFrame.listFrame.fileListFrame \
176                 .menuFrame.listFrame.funcListFrame \
177                 .menuFrame.listFrame.graphPanel \
178                 globalDataStructure \
179                 globalExecutionMap \
180                 globalFrequencyMap");
181  
182         Tcl_Eval(interp,buffer);
183
184         Tcl_CreateTimerHandler(5000,graphUpdateProcedure,clientData);
185 }
186
187 void refreshButtonHandler(ClientData clientData,XEvent* /* eventPtr */){
188         /*
189         if(!eventPtr)
190                 return;
191         */
192
193         CodeCoverage* codeCoverage = ((ARGS*)clientData)->codeCoverage;
194         Tcl_Interp* interp = ((ARGS*)clientData)->interp;
195         
196         if(!isRunning){
197                 /*
198                 Tcl_Eval(interp,".fileFrame.status configure -text \
199                          \"To refresh, please wait untill mutatee starts...\"");
200                 */
201                 return;
202         }
203
204         char tclFileName[124];
205         sprintf(tclFileName,"./.updateExecuted.tcl.%d",(int)getpid());
206         ofstream tclFile;
207         tclFile.open(tclFileName,std::ios::out);
208         codeCoverage->getTclTkExecutedLines(tclFile);
209
210         if(Tcl_EvalFile(interp,tclFileName) != TCL_OK){
211                 codeCoverage->terminate();
212                 cerr << "ERROR: Update execution string is not valid..."
213                      << endl;
214                 exit(-1);
215         }
216
217         tclFile.close();
218         unlink(tclFileName);
219 }
220
221 void prepareTclTkGlobalDataStucture(ARGS* passedArguments) {
222
223         CodeCoverage* codeCoverage = passedArguments->codeCoverage;
224         Tcl_Interp* interp = passedArguments->interp;
225
226         char tclFileName[124];
227         sprintf(tclFileName,"./.contructDS.tcl.%d",(int)getpid());
228         ofstream tclFile;
229         tclFile.open(tclFileName,std::ios::out);
230         codeCoverage->getTclTkMenuListCreation(tclFile);
231
232         if(Tcl_EvalFile(interp,tclFileName) != TCL_OK){
233                 codeCoverage->terminate();
234                 cerr << "ERROR: Menu list preparation string is not valid..."
235                      << endl;
236                 exit(-1);
237         }
238         tclFile.close();
239         unlink(tclFileName);
240 }
241
242 int Tcl_AppInit(Tcl_Interp* interp){
243         return (interp ? TCL_OK : TCL_OK);
244 }
245
246 Tcl_Interp* initTclTk(CodeCoverage* codeCoverage,int interval){
247
248         Tcl_Interp* interp = Tcl_CreateInterp();
249         if(!interp) 
250                 return NULL;
251
252         if(Tcl_Init(interp) == TCL_ERROR)
253                 return NULL;
254
255         Tcl_Channel channel = Tcl_GetStdChannel(TCL_STDIN);
256         if(channel){
257                 if(Tcl_Close(interp,channel) != TCL_OK)
258                         cerr << "warning : Tcl_Channel for TCL_STDIN  can not be closed" << endl;
259         }
260         else
261                 cerr << "warning : Tcl_Channel for TCL_STDIN is not valid" << endl;
262
263         if(Tk_Init(interp) == TCL_ERROR)
264                 return NULL;
265
266         char buffer[124];
267         sprintf(buffer,"set deletionInterval %d",interval);
268         Tcl_Eval(interp,buffer);
269
270         char tcktkFilePath[1024];
271         char* p = getenv("DYNINST_ROOT");
272         if(!p){
273                 codeCoverage->terminate();
274                 cerr << "ERROR: DYNINST_ROOT environment variable is not set..."
275                      << endl;
276                 exit(-1);
277         }
278         sprintf(tcktkFilePath,"%s/core/codeCoverage/src/interface.tcl",p);
279
280         if(Tcl_EvalFile(interp,tcktkFilePath) != TCL_OK){
281                 codeCoverage->terminate();
282                 cerr << "ERROR: Interface preparation script can not "
283                      << "be run correctly (" << tcktkFilePath << ")..."
284                      << endl;
285                 exit(-1);
286         }
287
288         mainWindow = Tk_MainWindow(interp);
289         textMessage = Tk_NameToWindow(interp,
290                                 ".fileFrame.message",mainWindow);
291         fileDisplay = Tk_NameToWindow(interp,
292                                 ".fileFrame.displayPanel.text",mainWindow);
293         fileList = Tk_NameToWindow(interp,
294                                 ".menuFrame.listFrame.fileListFrame.list",mainWindow);
295         funcList = Tk_NameToWindow(interp,
296                                 ".menuFrame.listFrame.funcListFrame",mainWindow);
297         startButton = Tk_NameToWindow(interp,
298                                 ".menuFrame.buttonFrame.start",mainWindow);
299         refreshButton = Tk_NameToWindow(interp,
300                                 ".menuFrame.buttonFrame.refresh",mainWindow);
301         statusMessage = Tk_NameToWindow(interp,
302                                 ".menuFrame.buttonFrame.quit",mainWindow);
303
304         if(!mainWindow || !textMessage || !fileDisplay || !fileList ||
305            !funcList || !startButton || !refreshButton || !statusMessage){
306                 codeCoverage->terminate();
307                 cerr << "ERROR: Some of the interface widgets can not be accessed..."
308                      << endl;
309                 exit(-1);
310         }
311
312         codeCoverage->setTclTkSupport(interp,".fileFrame.status");
313
314         return interp;
315 }
316
317 Tcl_Interp* initTclTkForView(){
318
319         Tcl_Interp* interp = Tcl_CreateInterp();
320         if(!interp)
321                 return NULL;
322
323         if(Tcl_Init(interp) == TCL_ERROR)
324                 return NULL;
325         if(Tk_Init(interp) == TCL_ERROR)
326                 return NULL;
327
328         Tcl_Eval(interp,"set deletionInterval 0");
329
330         char tcktkFilePath[1024];
331         char* p = getenv("DYNINST_ROOT");
332         if(!p){
333                 cerr << "ERROR: DYNINST_ROOT environment variable is not set..."
334                      << endl;
335                 exit(-1);
336         }
337         sprintf(tcktkFilePath,"%s/core/codeCoverage/src/interface.tcl",p);
338
339         if(Tcl_EvalFile(interp,tcktkFilePath) != TCL_OK){
340                 cerr << "ERROR: Interface preparation script can not "
341                      << "be run correctly (" << tcktkFilePath << ")..."
342                      << endl;
343                 exit(-1);
344         }
345         if((Tcl_Eval(interp,"destroy .menuFrame.buttonFrame.start") != TCL_OK) ||
346            (Tcl_Eval(interp,"destroy .menuFrame.buttonFrame.refresh") != TCL_OK) ||
347            (Tcl_Eval(interp,"destroy .fileFrame.status") != TCL_OK))
348         {
349                 cerr << "ERROR: Destroying some widgets do not work poperly..." << endl;
350                 exit(-1);
351         }
352
353         return interp;
354 }
355
356 #endif
357
358 /** function to show the usage of code coverage tool 
359   * one usage is to run and produce the coverage results
360   * in a binary file and the other is to view the coverage results
361   */
362 void printUsage(char* s,bool d=false){
363         cerr << "Usage_1 : " << s << " [--interface] [--deletion <interval>] [--dominator] \\" << endl
364              << "                 [--ondemand] [--suffix <outfile suffix>] \\" << endl
365              << "                 --run <executable> <arguments>" << endl;
366         cerr << "Usage_2 : " << s << " --view <fileName>" << endl;
367         cerr << "Usage_3 : " << s << " --xview <fileName>" << endl;
368
369         if(d)
370           cerr 
371              << endl
372              << "Information : " << endl
373              << endl
374              << "--deletion     : Interval to delete instrumentation code in seconds." << endl
375              << "                 Default value is 0, that is no deletion of " << endl
376              << "                 instrumentation code." << endl
377              << "--dominator    : Flag to make this tool use dominator information." << endl
378              << "                 All basic blocks is used by default." << endl
379              << "--suffix       : The suffix of the output file, generated by appending" << endl
380              << "                 to the name of executable.Output file contains " << endl
381              << "                 coverage information" << endl
382              << "--ondemand     : Flag to instrument functions when called first time." << endl
383              << "                 By default, the functions with source line information" << endl
384              << "                 is pre-instrumented." << endl
385              << "--run          : The executable and its arguments to run is given after" << endl
386              << "                 this flag. This flag HAS to come after all other flags" << endl
387              << "--view         : To view the output file generated from coverage data" << endl
388              << "                 in text format. The output file is generated if it is" << endl
389              << "                 executed in Usage_1 format." << endl
390              << "--xview         : To view the output file generated from coverage data" << endl
391              << "                 using graphical interface." << endl
392              << "--interface    : To run the code coverage with its Tcl/Tk" << endl
393              << "                 based grahical user interface." << endl
394              << endl << endl;
395
396         exit(0);
397 }
398
399 /** main function */
400 #ifdef sparc_sun_solaris2_4
401 int main(int argc,char* argv[]){
402
403         bool useInterface = false;
404         bool useDominator = false;
405         bool useOnDemand = false;
406         const char* suffix = ".dyncov";
407         int interval = 0;
408         int execIndex = 0;
409         char* p = NULL;
410         int errorCode = Error_OK;
411         Tcl_Interp* interp = NULL;
412
413
414         if(argc < 3)
415                 printUsage(argv[0],true);
416
417         if((argc == 3) && !strncmp("--view",argv[1],6)){
418                 return CodeCoverage::viewCodeCoverageInfo(argv[2]);
419         }
420         else if((argc == 3) && !strncmp("--xview",argv[1],7)){
421                 interp = initTclTkForView(); 
422                 if(!interp){
423                         cerr << "ERROR : The Tcl/Tk interpreter"
424                              << " can not be created..." << endl; 
425                         exit(-1);
426                 }
427
428                 char tclFileName[124];
429                 sprintf(tclFileName,"./.view.tcl.%d",(int)getpid());
430                 ofstream tclFile;
431                 tclFile.open(tclFileName,std::ios::out);
432
433                 errorCode = CodeCoverage::getTclTkMenuListForView(argv[2],tclFile);
434
435                 if(errorCode != Error_OK){
436                         cerr << "ERROR: Coverage file can not be parsed properly..."
437                              << endl;
438                         exit(-1);
439                 }
440
441                 if(Tcl_EvalFile(interp,tclFileName) != TCL_OK){
442                         cerr << "ERROR: Menu list preparation string is not valid..."
443                              << endl;
444                         exit(-1);
445                 }
446
447                 tclFile.close();
448                 unlink(tclFileName);
449
450                 Tk_Main(argc,argv,Tcl_AppInit);
451                 Tcl_DeleteInterp(interp);
452
453                 return errorCode;
454         }
455
456         for(int i=1;i<argc;i++){
457                 if(!strncmp("--del",argv[i],5)){
458                         i++;
459                         if(!strncmp("--",argv[i],2))
460                                 printUsage(argv[0]);
461                         interval = strtol(argv[i],&p,10);
462                         if(argv[i] == p)
463                                 printUsage(argv[0]);
464                 }
465                 else if(!strncmp("--dom",argv[i],5))
466                         useDominator = true;
467                 else if(!strncmp("--ond",argv[i],5))
468                         useOnDemand = true;
469                 else if(!strncmp("--run",argv[i],5)){
470                         execIndex = i+1;
471                         break;
472                 }
473                 else if(!strncmp("--suf",argv[i],5)){
474                         i++;
475                         if(!strncmp("--",argv[i],2))
476                                 printUsage(argv[0]);
477                         suffix = argv[i];
478                 }
479                 else if(!strncmp("--int",argv[i],5)){
480                         useInterface = true;
481                 }
482                 else
483                         printUsage(argv[0]);
484         }
485
486         if(!execIndex || (execIndex == argc))
487                  printUsage(argv[0]);
488
489         struct stat statBuffer;
490         if(stat(argv[execIndex],&statBuffer) < 0){
491                 cerr << "ERROR : Executable " << argv[execIndex] 
492                      << " does not exist" << endl;
493                 exit(-100);
494         }
495
496         CodeCoverage* codeCoverage = NULL;
497
498         /** create the corresponding code coverage object */
499         if(useOnDemand)
500                 codeCoverage = new CCOnDemandInstrument;
501         else
502                 codeCoverage = new CCPreInstrument;
503
504         errorCode = Error_OK;
505
506         /** initialize the necessary BPatch obejcts */
507         errorCode = codeCoverage->initialize((const char **)argv+execIndex,interval,
508                                              useDominator,suffix);
509         if(errorCode < Error_OK){
510                 codeCoverage->terminate();
511                 exit(errorCode);
512         }
513
514         if(useInterface){
515                 interp = initTclTk(codeCoverage,interval); 
516                 if(!interp){
517                         codeCoverage->terminate();
518                         cerr << "ERROR : The Tcl/Tk interpreter"
519                              << " can not be created..." << endl; 
520                         exit(-1);
521                 }
522         }
523
524         ARGS* passedArguments = new ARGS;
525         passedArguments->interp = interp;
526         passedArguments->codeCoverage = codeCoverage;
527
528         if(useInterface){
529                 Tcl_CreateExitHandler(exitCodeCoverage,
530                                      (ClientData)passedArguments);
531
532                 Tk_CreateEventHandler(startButton,ButtonReleaseMask,
533                                       startButtonHandler,
534                                       (ClientData)passedArguments);
535
536                 Tk_CreateEventHandler(refreshButton,ButtonPressMask,
537                                       refreshButtonHandler,
538                                       (ClientData)passedArguments);
539
540                 Tcl_CreateTimerHandler(1000,statusUpdateProcedure,
541                                        (ClientData)passedArguments);
542
543                 Tcl_CreateTimerHandler(5000,graphUpdateProcedure,
544                                        (ClientData)passedArguments);
545         }
546
547         /** instrument a breakpoint to the beginning of the exit handle
548           * to catch the termination of the mutatee 
549           */
550         errorCode = codeCoverage->instrumentExitHandle();
551         if(errorCode < Error_OK){
552                 codeCoverage->terminate();
553                 Tcl_DeleteInterp(interp);
554                 exit(errorCode);
555         }
556
557         /** select functions whose source code line information
558           * is available in the executable 
559           */
560         errorCode = codeCoverage->selectFunctions();
561         if(errorCode < Error_OK){
562                 codeCoverage->terminate();
563                 Tcl_DeleteInterp(interp);
564                 exit(errorCode);
565         }
566
567         if(useInterface) {
568                 prepareTclTkGlobalDataStucture(passedArguments);
569                 Tk_Main(argc,argv,Tcl_AppInit);
570                 Tcl_DeleteInterp(interp);
571         }
572         else 
573                 codeCoverageThread((void*)passedArguments);
574
575         delete passedArguments;
576
577         return Error_OK;
578 #else
579 int main(int /* argc */,char* argv[]){
580         cerr << endl
581              << "IMPORTANT Information : " << endl
582              << "\tCodeCoverage Tool is not implemented for" << endl
583              << "\tthis platform...." << endl << endl << endl;
584
585         printUsage(argv[0],true);
586
587         return 0;
588 #endif
589 }