changes in the interface manipulation of code coverage
[dyninst.git] / codeCoverage / src / main.C
1 #include <stdio.h>
2 #include <iostream.h>
3 #include <stdlib.h>
4
5 #ifdef sparc_sun_solaris2_4
6
7 #include <string.h>
8 #include <fstream.h>
9 #include <limits.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <tcl.h>
14 #include <tk.h>
15 #include <pthread.h>
16
17 #endif
18
19 #ifdef sparc_sun_solaris2_4
20
21 #include <CCcommon.h>
22 #include <FunctionCoverage.h>
23 #include <CCPreInstrument.h>
24 #include <CCOnDemandInstrument.h>
25
26 #endif
27
28 #ifdef sparc_sun_solaris2_4
29
30 typedef struct {
31         Tcl_Interp* interp;
32         CodeCoverage* codeCoverage;
33 }ARGS;
34
35 Tk_Window mainWindow = NULL;
36 Tk_Window textMessage = NULL;
37 Tk_Window fileDisplay = NULL;
38 Tk_Window fileList = NULL;
39 Tk_Window funcList = NULL;
40 Tk_Window startButton = NULL;
41 Tk_Window refreshButton = NULL;
42 Tk_Window statusMessage = NULL;
43
44 bool executionStarted = false;
45 bool isRunning = false;
46
47 void* codeCoverageThread(void* arg){
48
49         CodeCoverage* codeCoverage = ((ARGS*)arg)->codeCoverage;
50         Tcl_Interp* interp = ((ARGS*)arg)->interp;
51
52         int errorCode = Error_OK;
53
54         /** insert the initial instrumentation code for the functions
55           * that are selected to be instrumented for code coverage
56           */
57         errorCode = codeCoverage->instrumentInitial();
58         if(errorCode < Error_OK){
59                 codeCoverage->terminate();
60                 return NULL;
61         }
62
63         if(interp)
64                 Tcl_Eval(interp,"set alreadyStarted 1");
65
66         isRunning = true;
67
68         /** runs the mutatee after the instrumentation */
69         errorCode = codeCoverage->run();
70         if(errorCode < Error_OK){
71                 codeCoverage->terminate();
72                 return NULL;
73         }
74
75         if(interp)
76                 Tcl_Eval(interp,"set isTerminated 1");
77
78         return arg;
79 }
80
81 void exitCodeCoverage(ClientData clientData){
82         CodeCoverage* codeCoverage = ((ARGS*)clientData)->codeCoverage;
83         codeCoverage->terminate();
84         delete codeCoverage;
85         cerr << "information: terminating code coverage execution ..." << endl;
86 }
87
88 void startButtonHandler(ClientData clientData,XEvent* eventPtr){
89         sigset_t sigs_to_block;
90         if(!eventPtr)
91                 return;
92
93         CodeCoverage* codeCoverage = ((ARGS*)clientData)->codeCoverage;
94         if(!executionStarted){
95                 pthread_attr_t attr;
96                 pthread_t newThreadId;
97                 pthread_attr_init(&attr);
98                 if(pthread_create(&newThreadId,&attr,
99                                   codeCoverageThread,(void*)clientData)){
100                         codeCoverage->terminate();
101                         cerr << "ERROR : Can not create graphical"
102                              << "  interface pthread..." << endl;
103                         exit(-1);
104                 }
105                 executionStarted = true;
106                 sigemptyset(&sigs_to_block);
107                 sigaddset(&sigs_to_block,SIGALRM);
108                 pthread_sigmask(SIG_BLOCK,&sigs_to_block,NULL);
109         }
110 }
111
112 void refreshButtonHandler(ClientData clientData,XEvent* eventPtr){
113         if(!eventPtr)
114                 return;
115
116         CodeCoverage* codeCoverage = ((ARGS*)clientData)->codeCoverage;
117         Tcl_Interp* interp = ((ARGS*)clientData)->interp;
118         
119         if(!isRunning){
120                 Tcl_Eval(interp,".fileFrame.status configure -text \
121                          \"To refresh, please wait untill mutatee starts...\"");
122                 return;
123         }
124
125         char tclFileName[124];
126         sprintf(tclFileName,"./.updateExecuted.tcl.%d",(int)getpid());
127         ofstream tclFile;
128         tclFile.open(tclFileName,ios::out);
129         codeCoverage->getTclTkExecutedLines(tclFile);
130
131         if(Tcl_EvalFile(interp,tclFileName) != TCL_OK){
132                 codeCoverage->terminate();
133                 cerr << "ERROR: Update execution string is not valid..."
134                      << endl;
135                 exit(-1);
136         }
137
138         tclFile.close();
139         unlink(tclFileName);
140 }
141
142 void prepareTclTkGlobalDataStucture(ARGS* passedArguments) {
143
144         CodeCoverage* codeCoverage = passedArguments->codeCoverage;
145         Tcl_Interp* interp = passedArguments->interp;
146
147         char tclFileName[124];
148         sprintf(tclFileName,"./.contructDS.tcl.%d",(int)getpid());
149         ofstream tclFile;
150         tclFile.open(tclFileName,ios::out);
151         codeCoverage->getTclTkMenuListCreation(tclFile);
152
153         if(Tcl_EvalFile(interp,tclFileName) != TCL_OK){
154                 codeCoverage->terminate();
155                 cerr << "ERROR: Menu list preparation string is not valid..."
156                      << endl;
157                 exit(-1);
158         }
159         tclFile.close();
160         unlink(tclFileName);
161 }
162
163 int Tcl_AppInit(Tcl_Interp* interp){
164         return (interp ? TCL_OK : TCL_OK);
165 }
166
167 Tcl_Interp* initTclTk(CodeCoverage* codeCoverage,int interval){
168
169         Tcl_Interp* interp = Tcl_CreateInterp();
170         if(!interp)
171                 return NULL;
172
173         if(Tcl_Init(interp) == TCL_ERROR)
174                 return NULL;
175         if(Tk_Init(interp) == TCL_ERROR)
176                 return NULL;
177
178         char buffer[124];
179         sprintf(buffer,"set deletionInterval %d",interval);
180         Tcl_Eval(interp,buffer);
181
182         char tcktkFilePath[1024];
183         char* p = getenv("DYNINST_ROOT");
184         if(!p){
185                 codeCoverage->terminate();
186                 cerr << "ERROR: DYNINST_ROOT environment variable is not set..."
187                      << endl;
188                 exit(-1);
189         }
190         sprintf(tcktkFilePath,"%s/core/codeCoverage/src/interface.tcl",p);
191
192         if(Tcl_EvalFile(interp,tcktkFilePath) != TCL_OK){
193                 codeCoverage->terminate();
194                 cerr << "ERROR: Interface preparation script can not "
195                      << "be run correctly (" << tcktkFilePath << ")..."
196                      << endl;
197                 exit(-1);
198         }
199
200         mainWindow = Tk_MainWindow(interp);
201         textMessage = Tk_NameToWindow(interp,
202                                 ".fileFrame.message",mainWindow);
203         fileDisplay = Tk_NameToWindow(interp,
204                                 ".fileFrame.displayPanel.text",mainWindow);
205         fileList = Tk_NameToWindow(interp,
206                                 ".menuFrame.listFrame.fileListFrame.list",mainWindow);
207         funcList = Tk_NameToWindow(interp,
208                                 ".menuFrame.listFrame.funcListFrame",mainWindow);
209         startButton = Tk_NameToWindow(interp,
210                                 ".menuFrame.buttonFrame.start",mainWindow);
211         refreshButton = Tk_NameToWindow(interp,
212                                 ".menuFrame.buttonFrame.refresh",mainWindow);
213         statusMessage = Tk_NameToWindow(interp,
214                                 ".menuFrame.buttonFrame.quit",mainWindow);
215
216         if(!mainWindow || !textMessage || !fileDisplay || !fileList ||
217            !funcList || !startButton || !refreshButton || !statusMessage){
218                 codeCoverage->terminate();
219                 cerr << "ERROR: Some of the interface widgets can not be accessed..."
220                      << endl;
221                 exit(-1);
222         }
223
224         codeCoverage->setTclTkSupport(interp,".fileFrame.status");
225
226         return interp;
227 }
228
229 Tcl_Interp* initTclTkForView(){
230
231         Tcl_Interp* interp = Tcl_CreateInterp();
232         if(!interp)
233                 return NULL;
234
235         if(Tcl_Init(interp) == TCL_ERROR)
236                 return NULL;
237         if(Tk_Init(interp) == TCL_ERROR)
238                 return NULL;
239
240         Tcl_Eval(interp,"set deletionInterval 0");
241
242         char tcktkFilePath[1024];
243         char* p = getenv("DYNINST_ROOT");
244         if(!p){
245                 cerr << "ERROR: DYNINST_ROOT environment variable is not set..."
246                      << endl;
247                 exit(-1);
248         }
249         sprintf(tcktkFilePath,"%s/core/codeCoverage/src/interface.tcl",p);
250
251         if(Tcl_EvalFile(interp,tcktkFilePath) != TCL_OK){
252                 cerr << "ERROR: Interface preparation script can not "
253                      << "be run correctly (" << tcktkFilePath << ")..."
254                      << endl;
255                 exit(-1);
256         }
257         if((Tcl_Eval(interp,"destroy .menuFrame.buttonFrame.start") != TCL_OK) ||
258            (Tcl_Eval(interp,"destroy .menuFrame.buttonFrame.refresh") != TCL_OK) ||
259            (Tcl_Eval(interp,"destroy .fileFrame.status") != TCL_OK))
260         {
261                 cerr << "ERROR: Destroying some widgets do not work poperly..." << endl;
262                 exit(-1);
263         }
264
265         return interp;
266 }
267
268 #endif
269
270 /** function to show the usage of code coverage tool 
271   * one usage is to run and produce the coverage results
272   * in a binary file and the other is to view the coverage results
273   */
274 void printUsage(char* s,bool d=false){
275         cerr << "Usage_1 : " << s << " [--interface] [--deletion <interval>] [--dominator] \\" << endl
276              << "                 [--ondemand] [--suffix <outfile suffix>] \\" << endl
277              << "                 --run <executable> <arguments>" << endl;
278         cerr << "Usage_2 : " << s << " --view <fileName>" << endl;
279         cerr << "Usage_3 : " << s << " --xview <fileName>" << endl;
280
281         if(d)
282           cerr 
283              << endl
284              << "Information : " << endl
285              << endl
286              << "--deletion     : Interval to delete instrumentation code in seconds." << endl
287              << "                 Default value is 0, that is no deletion of " << endl
288              << "                 instrumentation code." << endl
289              << "--dominator    : Flag to make this tool use dominator information." << endl
290              << "                 All basic blocks is used by default." << endl
291              << "--suffix       : The suffix of the output file, generated by appending" << endl
292              << "                 to the name of executable.Output file contains " << endl
293              << "                 coverage information" << endl
294              << "--ondemand     : Flag to instrument functions when called first time." << endl
295              << "                 By default, the functions with source line information" << endl
296              << "                 is pre-instrumented." << endl
297              << "--run          : The executable and its arguments to run is given after" << endl
298              << "                 this flag. This flag HAS to come after all other flags" << endl
299              << "--view         : To view the output file generated from coverage data" << endl
300              << "                 in text format. The output file is generated if it is" << endl
301              << "                 executed in Usage_1 format." << endl
302              << "--xview         : To view the output file generated from coverage data" << endl
303              << "                 using graphical interface." << endl
304              << "--interface    : To run the code coverage with its Tcl/Tk" << endl
305              << "                 based grahical user interface." << endl
306              << endl << endl;
307
308         exit(0);
309 }
310
311 /** main function */
312 int main(int argc,char* argv[]){
313 #ifdef sparc_sun_solaris2_4
314
315         bool useInterface = false;
316         bool useDominator = false;
317         bool useOnDemand = false;
318         char* suffix = ".dyncov";
319         int interval = 0;
320         int execIndex = 0;
321         char* p = NULL;
322         int errorCode = Error_OK;
323         Tcl_Interp* interp = NULL;
324
325
326         if(argc < 3)
327                 printUsage(argv[0],true);
328
329         if((argc == 3) && !strncmp("--view",argv[1],6)){
330                 return CodeCoverage::viewCodeCoverageInfo(argv[2]);
331         }
332         else if((argc == 3) && !strncmp("--xview",argv[1],7)){
333                 interp = initTclTkForView(); 
334                 if(!interp){
335                         cerr << "ERROR : The Tcl/Tk interpreter"
336                              << " can not be created..." << endl; 
337                         exit(-1);
338                 }
339
340                 char tclFileName[124];
341                 sprintf(tclFileName,"./.view.tcl.%d",(int)getpid());
342                 ofstream tclFile;
343                 tclFile.open(tclFileName,ios::out);
344
345                 errorCode = CodeCoverage::getTclTkMenuListForView(argv[2],tclFile);
346
347                 if(errorCode != Error_OK){
348                         cerr << "ERROR: Coverage file can not be parsed properly..."
349                              << endl;
350                         exit(-1);
351                 }
352
353                 if(Tcl_EvalFile(interp,tclFileName) != TCL_OK){
354                         cerr << "ERROR: Menu list preparation string is not valid..."
355                              << endl;
356                         exit(-1);
357                 }
358
359                 tclFile.close();
360                 unlink(tclFileName);
361
362                 Tk_Main(argc,argv,Tcl_AppInit);
363                 Tcl_DeleteInterp(interp);
364
365                 return errorCode;
366         }
367
368         for(int i=1;i<argc;i++){
369                 if(!strncmp("--del",argv[i],5)){
370                         i++;
371                         if(!strncmp("--",argv[i],2))
372                                 printUsage(argv[0]);
373                         interval = strtol(argv[i],&p,10);
374                         if(argv[i] == p)
375                                 printUsage(argv[0]);
376                 }
377                 else if(!strncmp("--dom",argv[i],5))
378                         useDominator = true;
379                 else if(!strncmp("--ond",argv[i],5))
380                         useOnDemand = true;
381                 else if(!strncmp("--run",argv[i],5)){
382                         execIndex = i+1;
383                         break;
384                 }
385                 else if(!strncmp("--suf",argv[i],5)){
386                         i++;
387                         if(!strncmp("--",argv[i],2))
388                                 printUsage(argv[0]);
389                         suffix = argv[i];
390                 }
391                 else if(!strncmp("--int",argv[i],5)){
392                         useInterface = true;
393                 }
394                 else
395                         printUsage(argv[0]);
396         }
397
398         if(!execIndex || (execIndex == argc))
399                  printUsage(argv[0]);
400
401         struct stat statBuffer;
402         if(stat(argv[execIndex],&statBuffer) < 0){
403                 cerr << "ERROR : Executable " << argv[execIndex] 
404                      << " does not exist" << endl;
405                 exit(-100);
406         }
407
408         CodeCoverage* codeCoverage = NULL;
409
410         /** create the corresponding code coverage object */
411         if(useOnDemand)
412                 codeCoverage = new CCOnDemandInstrument;
413         else
414                 codeCoverage = new CCPreInstrument;
415
416         errorCode = Error_OK;
417
418         /** initialize the necessary BPatch obejcts */
419         errorCode = codeCoverage->initialize(argv+execIndex,interval,
420                                              useDominator,suffix);
421         if(errorCode < Error_OK){
422                 codeCoverage->terminate();
423                 exit(errorCode);
424         }
425
426         if(useInterface){
427                 interp = initTclTk(codeCoverage,interval); 
428                 if(!interp){
429                         codeCoverage->terminate();
430                         cerr << "ERROR : The Tcl/Tk interpreter"
431                              << " can not be created..." << endl; 
432                         exit(-1);
433                 }
434         }
435
436         ARGS* passedArguments = new ARGS;
437         passedArguments->interp = interp;
438         passedArguments->codeCoverage = codeCoverage;
439
440         if(useInterface){
441                 Tcl_CreateExitHandler(exitCodeCoverage,
442                                      (ClientData)passedArguments);
443
444                 Tk_CreateEventHandler(startButton,ButtonReleaseMask,
445                                       startButtonHandler,
446                                       (ClientData)passedArguments);
447
448                 Tk_CreateEventHandler(refreshButton,ButtonPressMask,
449                                       refreshButtonHandler,
450                                       (ClientData)passedArguments);
451         }
452
453         /** instrument a breakpoint to the beginning of the exit handle
454           * to catch the termination of the mutatee 
455           */
456         errorCode = codeCoverage->instrumentExitHandle();
457         if(errorCode < Error_OK){
458                 codeCoverage->terminate();
459                 Tcl_DeleteInterp(interp);
460                 exit(errorCode);
461         }
462
463         /** select functions whose source code line information
464           * is available in the executable 
465           */
466         errorCode = codeCoverage->selectFunctions();
467         if(errorCode < Error_OK){
468                 codeCoverage->terminate();
469                 Tcl_DeleteInterp(interp);
470                 exit(errorCode);
471         }
472
473         if(useInterface) {
474                 prepareTclTkGlobalDataStucture(passedArguments);
475                 Tk_Main(argc,argv,Tcl_AppInit);
476                 Tcl_DeleteInterp(interp);
477         }
478         else 
479                 codeCoverageThread((void*)passedArguments);
480
481         delete passedArguments;
482
483         return Error_OK;
484 #else
485         cerr << endl
486              << "IMPORTANT Information : " << endl
487              << "\tCodeCoverage Tool is not implemented for" << endl
488              << "\tthis platform...." << endl << endl << endl;
489
490         printUsage(argv[0],true);
491
492         return 0;
493 #endif
494 }