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