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