Update copyright to LGPL on all files
[dyninst.git] / codeCoverage / src / CodeCoverage.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 <unistd.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <iostream>
37 #include <fstream>
38 #include <limits.h>
39 #include <pthread.h>
40 #include <tcl.h>
41 #include <tk.h>
42
43 #include "common/h/Vector.h"
44 #include "common/src/Dictionary.C"
45 #include "BPatch_Set.h"
46 #include "BPatch_statement.h"
47
48 #include "common/h/Types.h"
49 #include "common/h/String.h"
50
51 #include <CCcommon.h>
52 #include <FCAllBlocks.h>
53 #include <FCUseDominator.h>
54 #include <CodeCoverage.h>
55
56 BPatch_function* exitHandle = NULL;
57 BPatch_Vector<unsigned short> frequencyCode;
58 BPatch_Vector<unsigned short> frequencyLine;
59
60 /** a linked list definition of functions to be used in hash structure */
61 class BPFunctionList {
62 public:
63         BPatch_function* f;
64         BPatch_module* m;
65         BPFunctionList* n;
66
67         BPFunctionList(BPatch_function* argf,BPatch_module* argm) :
68                 f(argf),m(argm),n(NULL){}
69         BPFunctionList(BPatch_function* argf,BPatch_module* argm,
70                        BPFunctionList* argn) : f(argf),m(argm),n(argn){}
71 };
72
73 /** mapping from function name to linked list of functions with the same name */
74 dictionary_hash<pdstring,BPFunctionList*>* allFunctionsHash = NULL;
75
76 dictionary_hash<pdstring,FunctionCoverage*>* allCoverageHash = NULL;
77
78 /** static initialization of the global code coverage object used
79   * by interval call backs
80   */
81 CodeCoverage* CodeCoverage::globalObject = NULL;
82 unsigned short CodeCoverage::fileCount = 0;
83 unsigned short* CodeCoverage::fileStartIndex = NULL;
84 unsigned short* CodeCoverage::fileLineCount = NULL;
85 FileLineCoverage** CodeCoverage::fileLineCoverage = NULL;
86
87 /** constructor */
88 CodeCoverage::CodeCoverage()
89         : appThread(NULL),appImage(NULL),coverageFileName(NULL),
90           deletionInterval(0),appModules(NULL),
91           instrumentedFunctions(NULL),instrumentedFunctionCount(0),
92           useDominator(false),globalInterp(NULL),statusBarName(NULL),
93           whichInterval(0),totalDeletions(0),totalCoveredLines(0),
94           tclStatusChanged(false)
95 {
96         pthread_mutex_init(&updateLock,NULL);
97         pthread_mutex_init(&statusUpdateLock,NULL);
98 }
99
100 /** constructor */
101 CodeCoverage::~CodeCoverage()
102 {
103         delete[] coverageFileName;
104         delete appModules;
105         for(int i=0;i<instrumentedFunctionCount;i++)
106                 delete instrumentedFunctions[i];
107         delete[] instrumentedFunctions;
108         delete FILE_EXTENSION;
109         pthread_mutex_destroy(&updateLock);
110         pthread_mutex_destroy(&statusUpdateLock);
111 }
112
113 /** error printing function that overrides dyninst default 
114   * function
115   */
116 void codeCoverageError(BPatchErrorLevel /* level */,
117                        int /* num */, const char * const * /* params */)
118 { }
119
120 /** this method initializes the necessary data structures and
121   * creates a map from string name to the linked list of function
122   * records to be used later to access function faster
123   */
124 int CodeCoverage::initialize(const char* mutatee[],unsigned short interval,
125                              bool dominatorInfo,const char* suffix)
126 {
127         deletionInterval = interval;
128         useDominator = dominatorInfo;
129         FILE_EXTENSION = new char[strlen(suffix)+1];
130         strcpy(FILE_EXTENSION,suffix);
131
132         coverageFileName = new char[strlen(mutatee[0])+strlen(FILE_EXTENSION)+1];
133         strcpy(coverageFileName,mutatee[0]);
134         strcat(coverageFileName,FILE_EXTENSION);
135
136         registerErrorCallback(codeCoverageError);
137
138         /** create the process */
139         appThread = bPatch.createProcess(mutatee[0],mutatee);
140         if(!appThread)
141                 return errorPrint(Error_ThreadCreate);
142
143         /** get the image */
144         appImage = appThread->getImage();
145         if(!appImage)
146                 return errorPrint(Error_ImageCreate);
147
148         allFunctionsHash = 
149                 new dictionary_hash<pdstring,BPFunctionList*>(pdstring::hash);
150
151         if(!allFunctionsHash)
152                 return errorPrint(Error_HashCreate);
153
154         /** get the modules in the image */
155         appModules = appImage->getModules();
156
157         if(!appModules)
158                 return errorPrint(Error_ModuleCreate);
159         
160         /** for each module in the image get the functions and
161           * insert them into the map
162           */
163         for(unsigned int i=0;i<appModules->size();i++){
164                 BPatch_module* m = (*appModules)[i];
165                 char mName[1024];
166                 m->getName(mName,1023);
167                 BPatch_Vector<BPatch_function*>* fs = m->getProcedures();
168                 for(unsigned int j=0;j<fs->size();j++){
169                         BPatch_function* f = (*fs)[j];
170                         char fName[1023];
171                         f->getMangledName(fName,1023); fName[1023] = '\0';
172                         if(allFunctionsHash->defines(pdstring(fName))){
173                                 /** if already there add to the front */
174                                 BPFunctionList* fl = (*allFunctionsHash)[fName];
175                                 (*allFunctionsHash)[pdstring(fName)] = 
176                                         new BPFunctionList(f,m,fl);
177                         }
178                         else
179                                 /** create a new linked list */
180                                 (*allFunctionsHash)[pdstring(fName)] = 
181                                         new BPFunctionList(f,m);
182                 }
183                 delete fs;
184         }
185
186         if(allFunctionsHash->defines(pdstring("_exithandle"))){
187                 BPFunctionList* fl = (*allFunctionsHash)[pdstring("_exithandle")];
188                 exitHandle = fl->f;
189         }
190                                 
191         /** set the base trampoline deletion to true to delete
192           * base trampolines when there is no more instrumentation code
193           * at the point
194           */
195         bPatch.setBaseTrampDeletion(true);
196
197         return Error_OK;
198 }
199
200 /** method that validates whether the function has source line
201   * information available. To do that, the records from the source
202   * line information stab is compared with the functions with the same
203   * name and its properties (if there are more than 1 possible functions
204   * with the same name 
205   */
206 BPatch_function* CodeCoverage::validateFunction(const char* funcN,
207                                                 unsigned long min)
208 {
209
210         BPatch_function* currFunc = NULL;
211         
212         /** get the possible functions with the same name */
213         BPFunctionList* possibleFunctions = NULL;
214         if(allFunctionsHash->defines(pdstring(funcN)))
215                 possibleFunctions = (*allFunctionsHash)[pdstring(funcN)];
216
217         if(!possibleFunctions)
218                 return NULL;
219
220         /** for each possible function compare the source code line info
221           * record with the properties of the function. If matches
222           * then terminate otherwise continue
223           */
224         for(;possibleFunctions;possibleFunctions=possibleFunctions->n){
225                 Address fb=(Address)(possibleFunctions->f->getBaseAddr());
226                 Address fe=fb + possibleFunctions->f->getSize();
227                 if((fb <= min) && (min <= fe)){
228                         currFunc = possibleFunctions->f;
229                         break;
230                 }
231         }
232
233         if(!currFunc)
234                 return NULL;
235
236         return currFunc;
237 }
238
239 /** creates a function coverage object according to the 
240   * the nature of instrumentation, tthat is whether all basic block
241   * instrumentation will be used or dominator tree information
242   * will be used 
243   */
244 FunctionCoverage* CodeCoverage::newFunctionCoverage(BPatch_function* f,
245                                  const char* funcN,FileLineCoverage* flc)
246 {
247         FunctionCoverage* ret = NULL;
248         if(useDominator)
249                 ret = new FCUseDominator(f,appThread,appImage,funcN);
250         else
251                 ret = new FCAllBlocks(f,appThread,appImage,funcN);
252
253         ret->addSourceFile(flc);
254         flc->setOwner(ret);
255
256         return ret;
257 }
258
259 void CodeCoverage::createFileStructure(){
260
261         unsigned short i = 0, j = 0;
262
263         int sourceObjectCount = 0;
264         for(i=0;i<instrumentedFunctionCount;i++){
265                 FunctionCoverage* fc = instrumentedFunctions[i];
266                 for(j=0;j<fc->sourceFileLinesCount;j++)
267                         sourceObjectCount++;
268         }
269
270         fileLineCoverage = new FileLineCoverage*[sourceObjectCount + 1];
271         fileLineCoverage[sourceObjectCount] = NULL;
272
273         sourceObjectCount = 0;
274         for(i=0;i<instrumentedFunctionCount;i++){
275                 FunctionCoverage* fc = instrumentedFunctions[i];
276                 for(j=0;j<fc->sourceFileLinesCount;j++)
277                         fileLineCoverage[sourceObjectCount++] = fc->sourceFileLines[j];
278         }
279
280         qsort((void*)fileLineCoverage,
281               sourceObjectCount,sizeof(FileLineCoverage*),
282               FLSortByFileName);
283
284         fileCount = 0;
285
286         const char* tmp = "what can it be";
287         for(i=0;i<sourceObjectCount;i++)
288                 if(strcmp(tmp,fileLineCoverage[i]->fileName)){
289                         tmp = fileLineCoverage[i]->fileName;
290                         fileCount++;
291                 }
292
293         if(!fileCount)
294                 return;
295
296         tmp = "can not be";
297         fileStartIndex = new unsigned short[fileCount];
298         fileLineCount = new unsigned short[fileCount];
299         for(i=0,j=0;i<sourceObjectCount;i++)
300                 if(strcmp(tmp,fileLineCoverage[i]->fileName)){
301                         fileStartIndex[j] = i;
302                         fileLineCount[j] = fileLineCoverage[i]->lineCount;
303                         tmp = fileLineCoverage[i]->fileName;
304                         j++;
305                 }
306                 else 
307                         fileLineCount[j-1] += fileLineCoverage[i]->lineCount;
308
309         for(i=0;i<fileCount;i++)
310                 cout << "information: file "
311                      << fileLineCoverage[fileStartIndex[i]]->fileName
312                      << " will be analyzed..." << endl;
313 }
314
315 /** method to select the functions whose source line information is available
316   * and whose data is stored in dyninst. It goes over the line information 
317   * strucute elements and for each source file and function it check whether
318   * the source line info record matches the properties of the function in dyninst
319   * If they match it is added to be instrumented. This method also creates and
320   * initializes the data structures that will be used for function coverage
321   */
322 int CodeCoverage::selectFunctions() {
323         allCoverageHash = new dictionary_hash< pdstring, FunctionCoverage * >(pdstring::hash);
324
325         for( unsigned int i = 0; i < appModules->size(); ++i ) {
326                 BPatch_module * currentModule = (* appModules)[i];
327
328                 /* Skip the synthetic modules. */
329                 char currentModuleName[1024];
330                 char currentFunctionName[1024];
331                 currentModule->getName( currentModuleName, 1023 );
332
333                 if(     strcmp( currentModuleName, "DEFAULT_MODULE" ) == 0
334                         || strcmp( currentModuleName, "DYN_MODULE" ) == 0
335                         || strcmp( currentModuleName, "LIBRARY_MODULE" ) == 0 ) {
336                         continue;
337                         }
338
339                 BPatch_Vector<BPatch_statement> statements;
340                 if (!currentModule->getStatements(statements)) {
341                     fprintf(stderr, "%s[%d]:  failed to get statements\n", __FILE__, __LINE__);
342                     continue;
343                 }
344
345                 for (unsigned int i = 0; i < statements.size(); ++i) {
346                    void *startAddress = statements[i].startAddr();
347                    int lineNumber = statements[i].lineNumber();
348                    const char *fileName = statements[i].fileName();
349                    BPatch_function *currentFunction
350                        = appThread->findFunctionByAddr(startAddress);
351
352                    if (currentFunction == NULL) {
353                        fprintf( stderr, "%s[%d]: Unable to locate function in line information at address %p\n", __FILE__, __LINE__, startAddress );
354                         continue;
355                     }
356                     currentFunction->getName( currentFunctionName, 1023 );
357                     pdstring pdCurrentFunctionName( currentFunctionName );
358                         
359                     /* Generate the flc. */
360                     FileLineCoverage * flc = new FileLineCoverage( fileName );
361
362                     /* Tikir: All line number should be changed to be unsigned ints. */
363                     BPatch_Set< unsigned short > lines;
364                     lines += (unsigned short) lineNumber;
365                     flc->initializeLines( lines );
366
367                     /* Add FLC to existing FC or create new FC with it, and register in allCoverageHash. */
368                     FunctionCoverage * fc = NULL;
369                     if ( allCoverageHash->defines( pdCurrentFunctionName ) ) {
370                        fc = allCoverageHash->get( pdCurrentFunctionName );
371                        fc->addSourceFile( flc );
372                        flc->setOwner( fc );
373                     }
374                     else {
375                        fc = newFunctionCoverage( currentFunction, currentFunctionName, flc );
376                        allCoverageHash->set( pdCurrentFunctionName, fc );
377                     }
378                 }
379 #if 0
380                 LineInformation & lineInformation = currentModule->getLineInformation();
381                 for(    LineInformation::const_iterator iter = lineInformation.begin();
382                                 iter != lineInformation.end();
383                                 ++ iter ) {
384                         BPatch_function * currentFunction = appThread->findFunctionByAddr( (void *)(iter->first.first) );
385                         if( currentFunction == NULL ) {
386                                 fprintf( stderr, "%s[%d]: Unable to locate function in line information at address 0x%lx\n", __FILE__, __LINE__, iter->first.first );
387                                 continue;
388                                 }
389                         currentFunction->getName( currentFunctionName, 1023 );
390                         pdstring pdCurrentFunctionName( currentFunctionName );
391                         
392                         /* Generate the flc. */
393                         FileLineCoverage * flc = new FileLineCoverage( iter->second.first );
394
395                         /* Tikir: All line number should be changed to be unsigned ints. */
396                         BPatch_Set< unsigned short > lines;
397                         lines += (unsigned short)(iter->second.second);
398                         flc->initializeLines( lines );
399
400                         /* Add FLC to existing FC or create new FC with it, and register in allCoverageHash. */
401                         FunctionCoverage * fc = NULL;
402                         if( allCoverageHash->defines( pdCurrentFunctionName ) ) {
403                                 fc = allCoverageHash->get( pdCurrentFunctionName );
404                                 fc->addSourceFile( flc );
405                                 flc->setOwner( fc );
406                                 }
407                         else {
408                                 fc = newFunctionCoverage( currentFunction, currentFunctionName, flc );
409                                 allCoverageHash->set( pdCurrentFunctionName, fc );
410                                 }
411
412                         } /* end iteration over line information */
413 #endif
414         } /* end iteration over modules */
415
416         if( allCoverageHash->size() == 0 ) {
417                 return errorPrint( Error_NoFunctionsToCover );
418                 }
419
420         /** creates the necessary data structures and initializes them */
421         instrumentedFunctionCount = allCoverageHash->size();
422         instrumentedFunctions = new FunctionCoverage * [ instrumentedFunctionCount ];
423         
424         dictionary_hash< pdstring, FunctionCoverage * >::const_iterator iter = allCoverageHash->begin();
425         for( int j = 0; iter != allCoverageHash->end() && j < instrumentedFunctionCount; ++iter, ++j ) {
426                 instrumentedFunctions[j] = * iter;
427                 }
428
429         cout    << "information: " << instrumentedFunctionCount
430                         << " functions are selected to be instrumented..." << endl;
431
432         /** sort the function coverage objects according to the name of the functions */
433         qsort(  (void *)instrumentedFunctions, instrumentedFunctionCount,
434                         sizeof( FunctionCoverage * ), FCSortByFileName );
435
436         createFileStructure();
437         return Error_OK;
438 } /* end CodeCoverage::selectFunctions() */
439
440 /** method to do initial instrumentation */
441 int CodeCoverage::instrumentInitial(){
442         return Error_OK;
443 }
444
445 /** method to run the mutatee */
446 int CodeCoverage::run(){
447         return Error_OK;
448 }
449
450 /** method to instrument exit handle to detect the
451   * termination of the mutatee
452   */
453 int CodeCoverage::instrumentExitHandle()
454 {
455         BPatch_breakPointExpr breakExpr;
456         BPatch_Vector<BPatch_point*>* breakPoints = NULL;
457         BPatchSnippetHandle* ret = NULL;
458
459         /** _exithandle is the exit function to be called for sparc*/
460         breakPoints = exitHandle->findPoint(BPatch_entry);
461
462         if(!breakPoints)
463                 return errorPrint(Error_ProcedurePoint,"Entry to _exithandle");
464
465         ret = appThread->insertSnippet(breakExpr,*breakPoints,
466                                        BPatch_callBefore,BPatch_lastSnippet);
467
468         if(!ret)
469                 return errorPrint(Error_InsertSnippet,"Breakpoint to _exithandle");
470
471         delete breakPoints;
472
473         return Error_OK;
474 }
475
476 /** method to print the error codes for this class */
477 int CodeCoverage::errorPrint(int code,char* text)
478 {
479         cerr << "Error(" << code << ") : ";
480
481         switch(code){
482                 case Error_FileOpen:
483                         cerr << "File can not be opened. ";
484                         break;
485                 case Error_ThreadCreate:
486                         cerr << "The bpatch thread can not be created. ";
487                         break;
488                 case Error_ImageCreate:
489                         cerr << "The bpatch image can not be created. ";
490                         break;
491                 case Error_HashCreate:
492                         cerr << "Buffer for possible intrumentable functions can not be created. ";
493                         break;
494                 case Error_ModuleCreate:
495                         cerr << "Modules in the image can not be created. ";
496                         break;
497                 case Error_NoFunctionsToCover:
498                         cerr << "There are no functions/line information to test for source coverage. ";
499                         break;
500                 case Error_DeletionInterval:
501                         cerr << "An error occurred in deletion interval. ";
502                         break;
503                 case Error_PrintResult:
504                         cerr << "Coverage results can not be printed. ";
505                         break;
506                 case Error_FileFormat:
507                         cerr << "Coverage file is not in valid format. ";
508                         break;
509                 default: cerr << "Unrecognized error!!!!";
510         }
511
512         if(text)
513                 cerr << endl << "\t[ " << text << " ]";
514
515         cerr << endl;
516
517         return code;
518 }
519
520 void CodeCoverage::terminate(){
521         if(appThread && !appThread->isTerminated())
522                 appThread->terminateExecution();
523 }
524
525 /** method to be called during the deletion intervals */
526 int CodeCoverage::deletionIntervalCallback(){
527         return Error_OK;
528 }
529
530 /** function that is used to sort the function coverage objects according
531   * to the names of the functions
532   */
533 int FLSortByFileName(const void* arg1,const void* arg2){
534         FileLineCoverage* e1 = *((FileLineCoverage* const *)arg1);
535         FileLineCoverage* e2 = *((FileLineCoverage* const *)arg2);
536
537         int check = strcmp(e1->fileName,
538                            e2->fileName);
539         if(check > 0)
540                 return 1;
541         if(check < 0)
542                 return -1;
543
544         check = strcmp(e1->owner->functionName,
545                        e2->owner->functionName);
546         if(check > 0)
547                 return 1;
548         if(check < 0)
549                 return -1;
550         return 0;
551 }
552
553 /** function that is used to sort the function coverage objects according
554   * to the names of the functions
555   */
556 int FCSortByFileName(const void* arg1,const void* arg2){
557         FunctionCoverage* e1 = *((FunctionCoverage* const *)arg1);
558         FunctionCoverage* e2 = *((FunctionCoverage* const *)arg2);
559
560         int check = strcmp(e1->sourceFileLines[0]->fileName,
561                            e2->sourceFileLines[0]->fileName);
562         if(check > 0)
563                 return 1;
564         if(check < 0)
565                 return -1;
566
567         check = strcmp(e1->functionName,
568                        e2->functionName);
569         if(check > 0)
570                 return 1;
571         if(check < 0)
572                 return -1;
573         return 0;
574 }
575
576 /** method to print the coverage results to a binary file.
577   * it iterates over the function coverage objects and prints 
578   * the results for each of them.
579   */
580 int CodeCoverage::printCoverageInformation(){
581
582         if(globalInterp && statusBarName){
583                 pthread_mutex_lock(&statusUpdateLock);
584                 tclStatusChanged = true;
585                 /*
586                 sprintf(tclStatusBuffer,"%s configure -text \
587                         \"Dumping coverage results to the binary file...\"",
588                         statusBarName);
589                 */
590                 pthread_mutex_unlock(&statusUpdateLock);
591         }
592
593         /** update the execution counts for the last time */
594         updateFCObjectInfo();
595
596         /** create the coverage results file */
597         coverageFile.open(coverageFileName,std::ios::out);
598         if(!coverageFile)
599                 return errorPrint(Error_FileOpen,coverageFileName);
600
601         /** write the unique identifier for the file format */
602         char* ccid = "Dyncov-1.0";
603         coverageFile.write(ccid,10);
604
605         /** for each function coverage print the results */
606         for(int i=0;i<instrumentedFunctionCount;i++)
607                 instrumentedFunctions[i]->printCoverageInformation(
608                                         coverageFile);
609
610         /** print the termination flag */
611         unsigned tmp_u = 0;
612         coverageFile.write((char*)&tmp_u,sizeof(unsigned));
613
614         /** close the output file */
615         coverageFile.close();
616
617         return Error_OK;
618 }
619
620 /** method that updates execution counts of each basic block 
621   * instrumented going over the function coverage objects
622   */
623 int CodeCoverage::updateFCObjectInfo(){
624
625         pthread_mutex_lock(&updateLock);
626
627         for(int i=0;i<instrumentedFunctionCount;i++)
628              if(isInstrumented(i))
629                 instrumentedFunctions[i]->updateExecutionCounts();
630
631         pthread_mutex_unlock(&updateLock);
632
633         return Error_OK;
634 }
635
636 /** method that returns whether a function is instrumented or not */
637 bool CodeCoverage::isInstrumented(int i){
638         return true || i;
639 }
640
641 /** method to register the error function for dyninst error call back */
642 BPatchErrorCallback
643 CodeCoverage::registerErrorCallback(BPatchErrorCallback f){
644         return bPatch.registerErrorCallback(f);
645 }
646
647 void CodeCoverage::addTclTkFrequency(){
648         if(deletionInterval && globalInterp && statusBarName){
649                 pthread_mutex_lock(&updateLock);
650                 frequencyCode.push_back(totalDeletions);
651                 frequencyLine.push_back(totalCoveredLines);
652                 pthread_mutex_unlock(&updateLock);
653         }
654 }
655
656 void CodeCoverage::getTclTkExecutedLines(ofstream& file){
657    if(deletionInterval || appThread->isTerminated()) {
658
659         if(globalInterp && statusBarName){
660                 pthread_mutex_lock(&statusUpdateLock);
661                 tclStatusChanged = true;
662                 sprintf(tclStatusBuffer,"%s configure -text \
663                         \"Updating executed line information...\"",
664                         statusBarName);
665                 pthread_mutex_unlock(&statusUpdateLock);
666         }
667
668         pthread_mutex_lock(&updateLock);
669
670         for(unsigned int i=0;i<fileCount;i++){
671                 file << "set globalExecutionMap(" << i << ") \\" << endl;
672                 file << "\t[list \\" << endl
673                      << "\t\t[list \\" << endl;
674
675                 unsigned short index = fileStartIndex[i];
676                 const char* fileName = fileLineCoverage[index]->fileName;
677
678                 unsigned percentage = 0;
679                 for(unsigned short j=index;fileLineCoverage[j];j++){
680
681                         FileLineCoverage* flc = fileLineCoverage[j];
682                         FunctionCoverage* fc = flc->owner;
683
684                         if(strcmp(fileName,flc->fileName))
685                                 break;
686
687                         file << "\t\t\t[list \\" << endl
688                              << "\t\t\t\t" << (int)(flc->executionPercentage) << " \\" << endl;
689
690                         pthread_mutex_lock(&(fc->updateLock));
691
692                         unsigned es = flc->executedLines.size();
693
694                         file << "\t\t\t\t" << es << " \\" << endl
695                              << "\t\t\t\t" << flc->lineCount << " \\" << endl;
696
697                         if(es){
698                                 percentage += es;
699                                 file << "\t\t\t\t[list \\" << endl;
700                                 unsigned short* elements =
701                                          new unsigned short[es];
702                                 flc->executedLines.elements(elements);
703                                 for(unsigned t=0;t<es;t++)
704                                         file << elements[t] << " ";
705                                 delete[] elements;
706                                 file << "\\" << endl;
707                                 file << "\t\t\t\t] \\" << endl;
708                         }
709                         pthread_mutex_unlock(&(fc->updateLock));
710
711                         file << "\t\t\t] \\" << endl;
712                 }
713                 file << "\t\t] \\" << endl
714                      << "\t\t" << (int)(((1.0*percentage)/fileLineCount[i])*100) << " \\" << endl
715                      << "\t\t" << percentage << " \\" << endl
716                      << "\t\t" << fileLineCount[i] << " \\" << endl
717                      << "\t]" << endl;
718         }
719         for(unsigned int i=0;i<frequencyCode.size();i++){
720                 file << "set globalFrequencyMap(" << i+1 << ") [list "
721                      << frequencyLine[i] << " " << frequencyCode[i] << " ]" << endl;
722         }
723
724         pthread_mutex_unlock(&updateLock);
725         
726    }
727    else {
728         if(globalInterp && statusBarName){
729                 pthread_mutex_lock(&statusUpdateLock);
730                 tclStatusChanged = true;
731                 sprintf(tclStatusBuffer,"%s configure -text \
732                         \"Can not update executed line information (no deletion)...\"",
733                         statusBarName);
734                 pthread_mutex_unlock(&statusUpdateLock);
735         }
736    }
737 }
738
739 void CodeCoverage::getTclTkMenuListCreation(ofstream& file){
740
741         for(int i=0;i<fileCount;i++){
742                 file << "set globalDataStructure(" << i << ") \\" << endl;
743
744                 unsigned short index = fileStartIndex[i];
745                 const char* fileName = fileLineCoverage[index]->fileName;
746
747                 file << "\t[list \\" << endl;
748                 file << "\t\t" << fileName << " \\" << endl;
749
750                 file << "\t\t[list \\" << endl;
751                 for(unsigned short j=index;fileLineCoverage[j];j++){
752                         FileLineCoverage* flc = fileLineCoverage[j];
753                         FunctionCoverage* fc = flc->owner;
754                         if(strcmp(fileName,flc->fileName))
755                                 break;
756                         file << "\t\t\t" << fc->functionName << " \\" << endl;
757                 }
758                 file << "\t\t] \\" << endl;
759                 file << "\t\t[list \\" << endl;
760                 for(unsigned short j=index;fileLineCoverage[j];j++){
761                         FileLineCoverage* flc = fileLineCoverage[j];
762                         if(strcmp(fileName,flc->fileName))
763                                 break;
764
765                         unsigned short minLine = 
766                                 (flc->unExecutedLines.size() ?
767                                         flc->unExecutedLines.minimum():
768                                         0);
769
770                         file << "\t\t\t" << minLine << " \\" << endl;
771                 }
772                 file << "\t\t]]" << endl;
773         }
774         for(int i=0;i<fileCount;i++){
775                 file << "set globalExecutionMap(" << i << ") \\" << endl;
776                 file << "\t[list \\" << endl;
777                 file << "\t\t[list \\" << endl;
778
779                 unsigned short index = fileStartIndex[i];
780                 const char* fileName = fileLineCoverage[index]->fileName;
781
782                 for(unsigned short j=index;fileLineCoverage[j];j++){
783                         FileLineCoverage* flc = fileLineCoverage[j];
784                         if(strcmp(fileName,flc->fileName))
785                                 break;
786                         file << "\t\t\t[list \\" << endl
787                              << "\t\t\t\t0 \\" << endl
788                              << "\t\t\t\t0 \\" << endl
789                              << "\t\t\t\t" << flc->lineCount << " \\" << endl
790                              << "\t\t\t] \\" << endl;
791                 }
792                 file << "\t\t] \\" << endl
793                      << "\t\t0 \\" << endl
794                      << "\t\t0 \\" << endl
795                      << "\t\t" << fileLineCount[i] << " \\" << endl
796                      << "\t]" << endl;
797         }
798         file << "InitializeInterface \\" << endl
799              << "\t.menuFrame.listFrame.fileListFrame \\" << endl
800              << "\t.fileFrame.displayPanel.text \\" << endl
801              << "\t0 \\" << endl
802              << "\tglobalDataStructure \\" << endl
803              << "\tglobalExecutionMap \\" << endl;
804
805 }
806
807 /** method to set tcl/tk related things to CodeCoverage */
808 void CodeCoverage::setTclTkSupport(Tcl_Interp* interp,const char* statusBar){
809         globalInterp = interp;
810         statusBarName = statusBar;
811 }
812
813 /** method to print the coverage results after reading
814   * from the binary file produced by code coverage tool.
815   */
816 int CodeCoverage::viewCodeCoverageInfo(char* fN){
817         unsigned tmp_u;
818         unsigned short tmp_s;
819         char buffer[1024];
820
821         ifstream inputFile;
822         inputFile.open(fN,ios::in);
823
824         if(!inputFile)
825                 return errorPrint(Error_FileOpen,fN);
826
827         char ccid[10];
828         inputFile.read(ccid,10);
829         if(strncmp(ccid,"Dyncov-1.0",10))
830                 return errorPrint(Error_FileFormat,fN);
831
832         while(true){
833
834                 inputFile.read((char*)&tmp_u,sizeof(unsigned));
835                 if(!tmp_u)
836                         break;
837
838                 cout << "# # # # # # # # # # # # # # # # # # # "
839                      << "# # # # # # # # # # # # # # # # # # #" << endl; 
840                 inputFile.read(buffer,tmp_u);buffer[tmp_u] = '\0';
841                 cout << "** Function  :  " << buffer << endl;
842
843                 inputFile.read((char*)&tmp_u,sizeof(unsigned));
844                 inputFile.read(buffer,tmp_u);buffer[tmp_u] = '\0';
845                 cout << "** File      :  " << buffer << endl;
846
847                 cout << "** Executed  : ";
848                 inputFile.read((char*)&tmp_u,sizeof(unsigned));
849                 unsigned nofe = tmp_u;
850                 for(unsigned i=1;i<=tmp_u;i++){
851                         inputFile.read((char*)&tmp_s,sizeof(unsigned short));
852                         cout << " " << tmp_s;
853                         if(!(i % 10) && (i < tmp_u))
854                                 cout << endl << "              ";
855                 }
856
857                 cout << endl << "** UnExecuted: ";
858                 inputFile.read((char*)&tmp_u,sizeof(unsigned));
859                 unsigned nofu = tmp_u;
860                 for(unsigned i=1;i<=tmp_u;i++){
861                         inputFile.read((char*)&tmp_s,sizeof(unsigned short));
862                         cout << " " << tmp_s;
863                         if(!(i % 10) && (i < tmp_u))
864                                 cout << endl << "              ";
865                 }
866
867                 cout << endl << "[ Percentage : ";
868                 if(nofe+nofu) 
869                         cout << ((float)nofe/(nofe+nofu))*100;
870                 else
871                         cout << "0.0";
872                 cout << " % ]" << endl << endl;
873         }
874
875         inputFile.close();
876
877         return Error_OK;
878 }
879
880 typedef struct {
881         char* fileName;
882         char* funcName;
883         unsigned short min;
884         unsigned total;
885         BPatch_Set<unsigned short> executed;
886 } COVINFO;
887
888 int FCSortCOVINFO(const void* arg1,const void* arg2){
889         COVINFO* e1 = *((COVINFO* const *)arg1);
890         COVINFO* e2 = *((COVINFO* const *)arg2);
891
892         int check = strcmp(e1->fileName,e2->fileName);
893         if(check > 0)
894                 return 1;
895         if(check < 0)
896                 return -1;
897
898         check = strcmp(e1->funcName,e2->funcName);
899
900         if(check > 0)
901                 return 1;
902         if(check < 0)
903                 return -1;
904
905         return 0;
906 }
907
908 int CodeCoverage::getTclTkMenuListForView(char* fN,ofstream& file){
909         
910         unsigned tmp_u;
911         unsigned short tmp_s;
912
913         unsigned allInfoSize = 0;
914         COVINFO** allInfo = NULL;
915
916         ifstream inputFile;
917         inputFile.open(fN,ios::in);
918
919         if(!inputFile)
920                 return errorPrint(Error_FileOpen,fN);
921
922         char ccid[10];
923         inputFile.read(ccid,10);
924         if(strncmp(ccid,"Dyncov-1.0",10))
925                 return errorPrint(Error_FileFormat,fN);
926
927         while(true){
928
929                 inputFile.read((char*)&tmp_u,sizeof(unsigned));
930                 if(!tmp_u)
931                         break;
932
933                 COVINFO* covInfo = new COVINFO;
934                 covInfo->funcName = new char[tmp_u+1];
935                 inputFile.read(covInfo->funcName,tmp_u);covInfo->funcName[tmp_u] = '\0';
936
937                 inputFile.read((char*)&tmp_u,sizeof(unsigned));
938                 covInfo->fileName = new char[tmp_u+1];
939                 inputFile.read(covInfo->fileName,tmp_u);covInfo->fileName[tmp_u] = '\0';
940
941                 covInfo->min = 0xffff;
942                 inputFile.read((char*)&tmp_u,sizeof(unsigned));
943                 unsigned nofe = tmp_u;
944                 for(unsigned i=1;i<=tmp_u;i++){
945                         inputFile.read((char*)&tmp_s,sizeof(unsigned short));
946                         covInfo->executed += tmp_s;
947                         if(tmp_s < covInfo->min)
948                                 covInfo->min = tmp_s;
949                                 
950                 }
951
952                 inputFile.read((char*)&tmp_u,sizeof(unsigned));
953                 unsigned nofu = tmp_u;
954                 for(unsigned i=1;i<=tmp_u;i++){
955                         inputFile.read((char*)&tmp_s,sizeof(unsigned short));
956                         if(tmp_s < covInfo->min)
957                                 covInfo->min = tmp_s;
958                 }
959
960                 covInfo->total = nofe+nofu;
961
962                 allInfo = (COVINFO**)realloc((void*)allInfo,(allInfoSize+1)*sizeof(COVINFO*));
963                 allInfo[allInfoSize++] = covInfo;
964         }
965
966         if(!allInfo){
967                 inputFile.close();
968                 return Error_OK;
969         }
970
971         qsort((void*)allInfo,allInfoSize,sizeof(COVINFO*),
972                       FCSortCOVINFO);
973
974         unsigned fileInfoSize = 0;
975         unsigned short* fileInfo = new unsigned short[allInfoSize];
976         
977         char* fileName = "no file name";
978         for(unsigned short i=0;i<allInfoSize;i++){
979                 if(strcmp(fileName,allInfo[i]->fileName)){
980                         fileName = allInfo[i]->fileName;
981                         fileInfo[fileInfoSize] = i;
982                         fileInfoSize++;
983                 }
984         }
985
986         fileName = "no file name";
987         for(unsigned i=0;i<fileInfoSize;i++){
988                 file << "set globalDataStructure(" << i << ") \\" << endl;
989                 unsigned index = fileInfo[i];
990                 fileName = allInfo[index]->fileName;
991                 /*char* p = fileName;p++;*/
992                 /*p = strchr(p,'/');*/
993                 
994                 file << "\t[list \\" << endl
995                      /*<< "\t\t/baffie" << p << " \\" << endl*/
996                      << "\t\t" << fileName  << " \\" << endl
997                      << "\t\t[list \\" << endl;
998
999                 for(unsigned j=index;j<allInfoSize;j++){
1000                         COVINFO* fc = allInfo[j];
1001                         if(strcmp(fileName,fc->fileName))
1002                                 break;
1003                         file << "\t\t\t" << fc->funcName << " \\" << endl;
1004                 }
1005                 file << "\t\t] \\" << endl
1006                      << "\t\t[list \\" << endl;
1007                 for(unsigned j=index;j<allInfoSize;j++){
1008                         COVINFO* fc = allInfo[j];
1009                         if(strcmp(fileName,fc->fileName))
1010                                 break;
1011                         file << "\t\t\t" << fc->min << " \\" << endl;
1012                 }
1013                 file << "\t\t]]" << endl;
1014         }
1015         for(unsigned i=0;i<fileInfoSize;i++){
1016                 file << "set globalExecutionMap(" << i << ") \\" << endl
1017                      << "\t[list \\" << endl
1018                      << "\t\t[list \\" << endl;
1019                 unsigned index = fileInfo[i];
1020                 fileName = allInfo[index]->fileName;
1021                 unsigned percentage = 0;
1022                 unsigned total = 0;
1023                 for(unsigned j=index;j<allInfoSize;j++){
1024                         COVINFO* fc = allInfo[j];
1025                         if(strcmp(fileName,fc->fileName))
1026                                  break;
1027
1028                         unsigned es = fc->executed.size();
1029                         file << "\t\t\t[list \\" << endl
1030                              << "\t\t\t\t" << (int)(((1.0*es)/fc->total)*100) << " \\" << endl
1031                              << "\t\t\t\t" << es << " \\" << endl
1032                              << "\t\t\t\t" << fc->total << " \\" << endl;
1033
1034                         percentage += es;
1035                         total += fc->total;
1036
1037                         if(es){
1038                                 file << "\t\t\t\t[list \\" << endl;
1039                                 unsigned short* elements =
1040                                         new unsigned short[es];
1041                                 fc->executed.elements(elements);
1042                                 for(unsigned t=0;t<es;t++)
1043                                         file << elements[t] << " ";
1044                                 delete[] elements;
1045                                 file << "\\" << endl
1046                                      << "\t\t\t\t] \\" << endl;
1047                         }
1048                         file << "\t\t\t] \\" << endl;
1049                 }
1050                 file << "\t\t] \\" << endl
1051                      << "\t\t" << (int)(((1.0*percentage)/total)*100) << " \\" << endl
1052                      << "\t\t" << percentage << " \\" << endl
1053                      << "\t\t" << total << " \\" << endl
1054                      << "\t]" << endl;
1055         }
1056
1057         file << "InitializeInterface \\" << endl
1058              << "\t.menuFrame.listFrame.fileListFrame \\" << endl
1059              << "\t.fileFrame.displayPanel.text \\" << endl
1060              << "\t0 \\" << endl
1061              << "\tglobalDataStructure \\" << endl
1062              << "\tglobalExecutionMap \\" << endl;
1063
1064         for(unsigned i=0;i<allInfoSize;i++)
1065                 delete allInfo[i];
1066         free(allInfo);
1067
1068         inputFile.close();
1069
1070         return Error_OK;
1071 }
1072
1073 bool CodeCoverage::getTclStatusUpdateString(char* buffer,int length){
1074         bool ret = false;
1075         pthread_mutex_lock(&statusUpdateLock);
1076         ret = tclStatusChanged;
1077         strncpy(buffer,tclStatusBuffer,length);
1078         tclStatusChanged = false;
1079         pthread_mutex_unlock(&statusUpdateLock);
1080         return ret;
1081 }