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