source: rtems-tools/tester/covoar/DesiredSymbols.cc @ 100f517

4.104.11
Last change on this file since 100f517 was 100f517, checked in by Chris Johns <chrisj@…>, on May 9, 2014 at 11:50:37 AM

covoar: Merger the covoar source from rtems-testing.git.

Use waf to build covoar.

  • Property mode set to 100644
File size: 18.9 KB
Line 
1/*! @file DesiredSymbols.cc
2 *  @brief DesiredSymbols Implementation
3 *
4 *  This file contains the implementation of the functions
5 *  which provide the functionality of the DesiredSymbols.
6 */
7
8#include <libgen.h>
9#include <limits.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "DesiredSymbols.h"
16#include "app_common.h"
17#include "CoverageMap.h"
18#include "ObjdumpProcessor.h"
19
20namespace Coverage {
21
22  DesiredSymbols::DesiredSymbols()
23  {
24  }
25
26  DesiredSymbols::~DesiredSymbols()
27  {
28  }
29
30  void DesiredSymbols::load(
31    const char* const symbolsFile
32  )
33  {
34    int                     cStatus;
35    bool                    done = false;
36    FILE*                   sFile;
37    SymbolInformation*      symInfo;
38    int                     line = 1;
39    std::string             symbol;
40
41    // Ensure that symbols file name is given.
42    if ( !symbolsFile ) {
43      fprintf(
44        stderr,
45        "ERROR: DesiredSymbols::load - no symbols file specified\n"
46      );
47      exit(-1);
48    }
49
50    // Open symbols file.
51    sFile = fopen( symbolsFile, "r" );
52    if ( !sFile ) {
53      fprintf(
54        stderr,
55        "ERROR: DesiredSymbols::load - unable to open symbols file %s\n",
56        symbolsFile
57      );
58      exit(-1);
59    }
60
61    // Process symbols file.
62    while ( !done ) {
63
64      symInfo = new SymbolInformation;
65
66      // Skip blank lines between symbols
67      do { 
68        inputBuffer[0] = '\0';
69        inputBuffer2[0] = '\0';
70        cStatus = fscanf( sFile, "%s %s", inputBuffer, inputBuffer2 );
71        if ( cStatus == EOF ) {
72          done = true;
73        }
74        else {
75          //inputBuffer[ strlen(inputBuffer) - 1] = '\0';
76          line++;
77        }
78      } while ( !done && (inputBuffer[0] == '\0') );
79
80      // Have we already seen this one?
81      if ( !done ) {
82        if (set.find( inputBuffer ) != set.end()) {
83          fprintf(
84            stderr,
85            "File: %s, Line %d: Duplicate symbol: %s\n",
86            symbolsFile,
87            line,
88            inputBuffer
89          );
90
91          delete symInfo;
92        }
93
94        // Add this to the set of symbols.
95        else 
96          set[ inputBuffer ] = *symInfo;
97      }
98    }
99  }
100
101  void DesiredSymbols::preprocess( void )
102  {
103    ObjdumpProcessor::objdumpLines_t::iterator fitr;
104    ObjdumpProcessor::objdumpLines_t::iterator n, p;
105    DesiredSymbols::symbolSet_t::iterator      sitr;
106    CoverageMapBase*                           theCoverageMap;
107
108    // Look at each symbol.
109    for (sitr = SymbolsToAnalyze->set.begin();
110         sitr != SymbolsToAnalyze->set.end();
111         sitr++) {
112
113      // If the unified coverage map does not exist, the symbol was
114      // never referenced by any executable.  Just skip it.
115      theCoverageMap = sitr->second.unifiedCoverageMap;
116      if (!theCoverageMap)
117        continue;
118
119      // Mark any branch and NOP instructions.
120      for (fitr = sitr->second.instructions.begin();
121           fitr != sitr->second.instructions.end();
122           fitr++) {
123        if (fitr->isBranch) {
124           theCoverageMap->setIsBranch(
125             fitr->address - sitr->second.baseAddress
126           );
127        }
128        if (fitr->isNop) {
129           theCoverageMap->setIsNop(
130             fitr->address - sitr->second.baseAddress
131           );
132        }
133      }
134
135    }
136  }
137
138  void DesiredSymbols::calculateStatistics( void )
139  {
140    uint32_t                              a;
141    uint32_t                              endAddress;
142    DesiredSymbols::symbolSet_t::iterator sitr;
143    CoverageMapBase*                      theCoverageMap;
144
145    // Look at each symbol.
146    for (sitr = SymbolsToAnalyze->set.begin();
147         sitr != SymbolsToAnalyze->set.end();
148         sitr++) {
149
150      // If the unified coverage map does not exist, the symbol was
151      // never referenced by any executable.  Just skip it.
152      theCoverageMap = sitr->second.unifiedCoverageMap;
153      if (!theCoverageMap)
154        continue;
155
156      // Increment the total sizeInBytes byt the bytes in the symbol
157      stats.sizeInBytes += sitr->second.stats.sizeInBytes;
158
159      // Now scan through the coverage map of this symbol.
160      endAddress = sitr->second.stats.sizeInBytes - 1;
161      a = 0;
162      while (a <= endAddress) {
163
164        // If we are at the start of instruction increment
165        // instruction type counters as needed.
166        if ( theCoverageMap->isStartOfInstruction( a ) ) {
167
168          stats.sizeInInstructions++;
169          sitr->second.stats.sizeInInstructions++;
170
171          if (!theCoverageMap->wasExecuted( a ) ) {
172            stats.uncoveredInstructions++;
173            sitr->second.stats.uncoveredInstructions++;
174
175            if ( theCoverageMap->isBranch( a )) {
176              stats.branchesNotExecuted++;
177              sitr->second.stats.branchesNotExecuted++;
178             }
179          } else if (theCoverageMap->isBranch( a )) {
180            stats.branchesExecuted++;
181            sitr->second.stats.branchesExecuted++;
182          }
183 
184        }
185 
186        if (!theCoverageMap->wasExecuted( a )) {
187          stats.uncoveredBytes++;
188          sitr->second.stats.uncoveredBytes++;
189        }       
190        a++;
191
192      }
193    }
194  }
195
196
197  void DesiredSymbols::computeUncovered( void )
198  {
199    uint32_t                              a, la, ha;
200    uint32_t                              endAddress;
201    uint32_t                              count;
202    DesiredSymbols::symbolSet_t::iterator sitr;
203    CoverageRanges*                       theBranches;
204    CoverageMapBase*                      theCoverageMap;
205    CoverageRanges*                       theRanges;
206
207    // Look at each symbol.
208    for (sitr = SymbolsToAnalyze->set.begin();
209         sitr != SymbolsToAnalyze->set.end();
210         sitr++) {
211
212      // If the unified coverage map does not exist, the symbol was
213      // never referenced by any executable.  Just skip it.
214      theCoverageMap = sitr->second.unifiedCoverageMap;
215      if (!theCoverageMap)
216        continue;
217
218      // Create containers for the symbol's uncovered ranges and branches.
219      theRanges = new CoverageRanges();
220      sitr->second.uncoveredRanges = theRanges;
221      theBranches = new CoverageRanges();
222      sitr->second.uncoveredBranches = theBranches;
223
224      // Mark NOPs as executed
225      endAddress = sitr->second.stats.sizeInBytes - 1;
226      a = 0;
227      while (a < endAddress) {
228        if (!theCoverageMap->wasExecuted( a )) {
229          a++;
230          continue;
231        }
232
233        for (ha=a+1;
234             ha<=endAddress && !theCoverageMap->isStartOfInstruction( ha );
235             ha++)
236          ;
237        if ( ha >= endAddress )
238          break;
239
240        if (theCoverageMap->isNop( ha ))
241          do {
242            theCoverageMap->setWasExecuted( ha );
243            ha++;
244            if ( ha >= endAddress )
245              break;
246          } while ( !theCoverageMap->isStartOfInstruction( ha ) );
247        a = ha;
248      }
249
250      // Now scan through the coverage map of this symbol.
251      endAddress = sitr->second.stats.sizeInBytes - 1;
252      a = 0;
253      while (a <= endAddress) {
254       
255        // If an address was NOT executed, find consecutive unexecuted
256        // addresses and add them to the uncovered ranges.
257        if (!theCoverageMap->wasExecuted( a )) {
258
259          la = a;
260          count = 1;
261          for (ha=a+1;
262               ha<=endAddress && !theCoverageMap->wasExecuted( ha );
263               ha++)
264          {
265            if ( theCoverageMap->isStartOfInstruction( ha ) )
266              count++;
267          }
268          ha--;
269
270          stats.uncoveredRanges++;
271          sitr->second.stats.uncoveredRanges++;
272          theRanges->add(
273            sitr->second.baseAddress + la,
274            sitr->second.baseAddress + ha,
275            CoverageRanges::UNCOVERED_REASON_NOT_EXECUTED,
276            count
277          );
278          a = ha + 1;
279        }
280
281        // If an address is a branch instruction, add any uncovered branches
282        // to the uncoverd branches.
283        else if (theCoverageMap->isBranch( a )) {
284          la = a;
285          for (ha=a+1;
286               ha<=endAddress && !theCoverageMap->isStartOfInstruction( ha );
287               ha++)
288            ;
289          ha--;
290
291          if (theCoverageMap->wasAlwaysTaken( la )) {
292            stats.branchesAlwaysTaken++;
293            sitr->second.stats.branchesAlwaysTaken++;
294            theBranches->add(
295              sitr->second.baseAddress + la,
296              sitr->second.baseAddress + ha,
297              CoverageRanges::UNCOVERED_REASON_BRANCH_ALWAYS_TAKEN,
298              1
299            );
300            if (Verbose)
301              fprintf(
302                stderr,
303                "Branch always taken found in %s (0x%x - 0x%x)\n",
304                (sitr->first).c_str(),
305                sitr->second.baseAddress + la,
306                sitr->second.baseAddress + ha
307              );
308          }
309
310          else if (theCoverageMap->wasNeverTaken( la )) {
311            stats.branchesNeverTaken++;
312            sitr->second.stats.branchesNeverTaken++;
313            theBranches->add(
314              sitr->second.baseAddress + la,
315              sitr->second.baseAddress + ha,
316              CoverageRanges::UNCOVERED_REASON_BRANCH_NEVER_TAKEN,
317              1
318            );
319            if (Verbose)
320              fprintf(
321                stderr,
322                "Branch never taken found in %s (0x%x - 0x%x)\n",
323                (sitr->first).c_str(),
324                sitr->second.baseAddress + la,
325                sitr->second.baseAddress + ha
326              );
327          }
328          a = ha + 1;
329        }
330        else
331          a++;
332      }
333    }
334  }
335
336
337  void DesiredSymbols::createCoverageMap(
338    const std::string& symbolName,
339    uint32_t           size
340  )
341  {
342    CoverageMapBase*      aCoverageMap;
343    uint32_t              highAddress;
344    symbolSet_t::iterator itr;
345
346    // Ensure that the symbol is a desired symbol.
347    itr = set.find( symbolName );
348
349    if (itr == set.end()) {
350
351      fprintf(
352        stderr,
353        "ERROR: DesiredSymbols::createCoverageMap - Unable to create "
354        "unified coverage map for %s because it is NOT a desired symbol\n",
355        symbolName.c_str()
356      );
357      exit( -1 );
358    }
359
360    // If we have already created a coverage map, ...
361    if (itr->second.unifiedCoverageMap) {
362
363      // ensure that the specified size matches the existing size.
364      if (itr->second.stats.sizeInBytes != size) {
365
366        fprintf(
367          stderr,
368          "ERROR: DesiredSymbols::createCoverageMap - Attempt to create "
369          "unified coverage maps for %s with different sizes (%d != %d)\n",
370          symbolName.c_str(),
371          itr->second.stats.sizeInBytes,
372          size
373        );
374        if ( itr->second.stats.sizeInBytes < size )
375          itr->second.stats.sizeInBytes = size;
376        else
377          size = itr->second.stats.sizeInBytes;
378        // exit( -1 );
379      }
380    }
381
382    // If we don't already have a coverage map, create one.
383    else {
384
385      highAddress = size - 1;
386
387      aCoverageMap = new CoverageMap( 0, highAddress );
388      if (!aCoverageMap) {
389
390        fprintf(
391          stderr,
392          "ERROR: DesiredSymbols::createCoverageMap - Unable to allocate "
393          "coverage map for %s\n",
394          symbolName.c_str()
395        );
396        exit( -1 );
397      }
398
399      if ( Verbose )
400        fprintf(
401          stderr,
402          "Created unified coverage map for %s (0x%x - 0x%x)\n",
403          symbolName.c_str(), 0, highAddress
404        );
405      itr->second.unifiedCoverageMap = aCoverageMap;
406      itr->second.stats.sizeInBytes = size;
407    }
408  }
409
410  void DesiredSymbols::determineSourceLines(
411    CoverageRanges* const theRanges,
412    ExecutableInfo* const theExecutable
413
414  )
415  {
416    char*                              base;
417    char*                              cStatus;
418    char                               command[512];
419    std::string                        fileName;
420    CoverageRanges::ranges_t::iterator ritr;
421    char                               rpath[PATH_MAX];
422    FILE*                              tmpfile;
423
424    // Open a temporary file for the uncovered ranges.
425    tmpfile = fopen( "ranges1.tmp", "w" );
426    if ( !tmpfile ) {
427      fprintf(
428        stderr,
429        "ERROR: DesiredSymbols::determineSourceLines - "
430        "unable to open %s\n",
431        "ranges1.tmp"
432      );
433      exit(-1);
434    }
435
436    // Write the range addresses to the temporary file.
437    for (ritr =  theRanges->set.begin();
438         ritr != theRanges->set.end();
439         ritr++ ) {
440      fprintf(
441        tmpfile,
442        "0x%08x\n0x%08x\n",
443        ritr->lowAddress - theExecutable->getLoadAddress(),
444        ritr->highAddress - theExecutable->getLoadAddress()
445      );
446    }
447
448    fclose( tmpfile );
449
450    // Invoke addr2line to generate the source lines for each address.
451    if (theExecutable->hasDynamicLibrary())
452      fileName = theExecutable->getLibraryName();
453    else
454      fileName = theExecutable->getFileName();
455
456    sprintf(
457      command,
458      "%s -Ce %s <%s | dos2unix >%s",
459      TargetInfo->getAddr2line(),
460      fileName.c_str(),
461      "ranges1.tmp",
462      "ranges2.tmp"
463    );
464
465    if (system( command )) {
466      fprintf(
467        stderr,
468        "ERROR: DesiredSymbols::determineSourceLines - "
469        "command (%s) failed\n",
470        command
471      );
472      exit( -1 );
473    }
474
475    // Open the addr2line output file.
476    tmpfile = fopen( "ranges2.tmp", "r" );
477    if ( !tmpfile ) {
478      fprintf(
479        stderr,
480        "ERROR: DesiredSymbols::determineSourceLines - "
481        "unable to open %s\n",
482        "ranges2.tmp"
483      );
484      exit(-1);
485    }
486
487    // Process the addr2line output.
488    for (ritr =  theRanges->set.begin();
489         ritr != theRanges->set.end();
490         ritr++ ) {
491
492      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, tmpfile );
493      if ( cStatus == NULL ) {
494        fprintf(
495          stderr,
496          "ERROR: DesiredSymbols::determineSourceLines - "
497          "Out of sync in addr2line output\n"
498        );
499        exit( -1 );
500      }
501      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
502
503      // Use only the base filename without directory path.
504      realpath( inputBuffer, rpath );
505      base = basename( rpath );
506
507      ritr->lowSourceLine = std::string( base );
508
509      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, tmpfile );
510      if ( cStatus == NULL ) {
511        fprintf(
512          stderr,
513          "ERROR: DesiredSymbols::determineSourceLines - "
514          "Out of sync in addr2line output\n"
515        );
516        exit( -1 );
517      }
518      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
519
520      // Use only the base filename without directory path.
521      realpath( inputBuffer, rpath );
522      base = basename( rpath );
523
524      ritr->highSourceLine = std::string( base );
525    }
526
527    fclose( tmpfile );
528    unlink( "ranges1.tmp" );
529    unlink( "ranges2.tmp" );
530  }
531
532  SymbolInformation* DesiredSymbols::find(
533    const std::string& symbolName
534  )
535  {
536    if (set.find( symbolName ) == set.end())
537      return NULL;
538    else
539      return &set[ symbolName ];
540  }
541
542  void DesiredSymbols::findSourceForUncovered( void )
543  {
544    DesiredSymbols::symbolSet_t::iterator ditr;
545    CoverageRanges*                       theBranches;
546    CoverageRanges*                       theRanges;
547
548    // Process uncovered ranges and/or branches for each symbol.
549    for (ditr = SymbolsToAnalyze->set.begin();
550         ditr != SymbolsToAnalyze->set.end();
551         ditr++) {
552
553      // First the unexecuted ranges, ...
554      theRanges = ditr->second.uncoveredRanges;
555      if (theRanges == NULL)
556        continue;
557
558      if (!theRanges->set.empty()) {
559        if (Verbose)
560          fprintf(
561            stderr,
562            "Looking up source lines for uncovered ranges in %s\n",
563            (ditr->first).c_str()
564          );
565        determineSourceLines(
566          theRanges,
567          ditr->second.sourceFile
568        );
569      }
570
571      // then the uncovered branches.
572      theBranches = ditr->second.uncoveredBranches;
573      if (theBranches == NULL)
574        continue;
575
576      if (!theBranches->set.empty()) {
577        if (Verbose)
578          fprintf(
579            stderr,
580            "Looking up source lines for uncovered branches in %s\n",
581            (ditr->first).c_str()
582          );
583        determineSourceLines(
584          theBranches,
585          ditr->second.sourceFile
586        );
587      }
588    }
589  }
590
591  uint32_t DesiredSymbols::getNumberBranchesAlwaysTaken( void ) const {
592    return stats.branchesAlwaysTaken;
593  };
594
595  uint32_t DesiredSymbols::getNumberBranchesFound( void ) const {
596    return (stats.branchesNotExecuted + stats.branchesExecuted);
597  };
598
599  uint32_t DesiredSymbols::getNumberBranchesNeverTaken( void ) const {
600    return stats.branchesNeverTaken;
601  };
602
603  uint32_t DesiredSymbols::getNumberUncoveredRanges( void ) const {
604    return stats.uncoveredRanges;
605  };
606
607  bool DesiredSymbols::isDesired (
608    const std::string& symbolName
609  ) const
610  {
611    if (set.find( symbolName ) == set.end()) {
612      #if 0
613        fprintf( stderr,
614          "Warning: Unable to find symbol %s\n",
615          symbolName.c_str()
616        );
617      #endif
618      return false;
619    }
620    return true;
621  }
622
623  void DesiredSymbols::mergeCoverageMap(
624    const std::string&           symbolName,
625    const CoverageMapBase* const sourceCoverageMap
626  )
627  {
628    uint32_t              dAddress;
629    CoverageMapBase*      destinationCoverageMap;
630    uint32_t              dMapSize;
631    symbolSet_t::iterator itr;
632    uint32_t              sAddress;
633    uint32_t              sBaseAddress;
634    uint32_t              sMapSize;
635    uint32_t              executionCount;
636   
637    // Ensure that the symbol is a desired symbol.
638    itr = set.find( symbolName );
639
640    if (itr == set.end()) {
641
642      fprintf(
643        stderr,
644        "ERROR: DesiredSymbols::mergeCoverageMap - Unable to merge "
645        "coverage map for %s because it is NOT a desired symbol\n",
646        symbolName.c_str()
647      );
648      exit( -1 );
649    }
650
651    // Ensure that the source and destination coverage maps
652    // are the same size.
653    dMapSize = itr->second.stats.sizeInBytes;
654    sBaseAddress = sourceCoverageMap->getFirstLowAddress();
655    sMapSize = sourceCoverageMap->getSize();
656    if (dMapSize != sMapSize) {
657
658      fprintf(
659        stderr,
660        "ERROR: DesiredSymbols::mergeCoverageMap - Unable to merge "
661        "coverage map for %s because the sizes are different\n",
662        symbolName.c_str()
663      );
664      return;
665      // exit( -1 );
666    }
667
668    // Merge the data for each address.
669    destinationCoverageMap = itr->second.unifiedCoverageMap;
670
671    for (dAddress = 0; dAddress < dMapSize; dAddress++) {
672
673      sAddress = dAddress + sBaseAddress;
674
675      // Merge start of instruction indication.
676      if (sourceCoverageMap->isStartOfInstruction( sAddress ))
677        destinationCoverageMap->setIsStartOfInstruction( dAddress );
678
679      // Merge the execution data.
680      executionCount = sourceCoverageMap->getWasExecuted( sAddress );
681      destinationCoverageMap->sumWasExecuted( dAddress, executionCount );
682
683      // Merge the branch data.
684      executionCount = sourceCoverageMap->getWasTaken( sAddress );
685      destinationCoverageMap->sumWasTaken( dAddress, executionCount );
686
687      executionCount = sourceCoverageMap->getWasNotTaken( sAddress );
688      destinationCoverageMap->sumWasNotTaken( dAddress, executionCount );
689    }
690  }
691
692}
Note: See TracBrowser for help on using the repository browser.