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