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