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

4.104.11
Last change on this file since f381f26 was f381f26, checked in by Chris Johns <chrisj@…>, on Jan 19, 2015 at 9:56:14 PM

Fix covoar so it builds for Windows.

  • 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#if WIN32
505      #define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
506#endif
507      realpath( inputBuffer, rpath );
508      base = basename( rpath );
509
510      ritr->lowSourceLine = std::string( base );
511
512      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, tmpfile );
513      if ( cStatus == NULL ) {
514        fprintf(
515          stderr,
516          "ERROR: DesiredSymbols::determineSourceLines - "
517          "Out of sync in addr2line output\n"
518        );
519        exit( -1 );
520      }
521      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
522
523      // Use only the base filename without directory path.
524      realpath( inputBuffer, rpath );
525      base = basename( rpath );
526
527      ritr->highSourceLine = std::string( base );
528    }
529
530    fclose( tmpfile );
531    unlink( "ranges1.tmp" );
532    unlink( "ranges2.tmp" );
533  }
534
535  SymbolInformation* DesiredSymbols::find(
536    const std::string& symbolName
537  )
538  {
539    if (set.find( symbolName ) == set.end())
540      return NULL;
541    else
542      return &set[ symbolName ];
543  }
544
545  void DesiredSymbols::findSourceForUncovered( void )
546  {
547    DesiredSymbols::symbolSet_t::iterator ditr;
548    CoverageRanges*                       theBranches;
549    CoverageRanges*                       theRanges;
550
551    // Process uncovered ranges and/or branches for each symbol.
552    for (ditr = SymbolsToAnalyze->set.begin();
553         ditr != SymbolsToAnalyze->set.end();
554         ditr++) {
555
556      // First the unexecuted ranges, ...
557      theRanges = ditr->second.uncoveredRanges;
558      if (theRanges == NULL)
559        continue;
560
561      if (!theRanges->set.empty()) {
562        if (Verbose)
563          fprintf(
564            stderr,
565            "Looking up source lines for uncovered ranges in %s\n",
566            (ditr->first).c_str()
567          );
568        determineSourceLines(
569          theRanges,
570          ditr->second.sourceFile
571        );
572      }
573
574      // then the uncovered branches.
575      theBranches = ditr->second.uncoveredBranches;
576      if (theBranches == NULL)
577        continue;
578
579      if (!theBranches->set.empty()) {
580        if (Verbose)
581          fprintf(
582            stderr,
583            "Looking up source lines for uncovered branches in %s\n",
584            (ditr->first).c_str()
585          );
586        determineSourceLines(
587          theBranches,
588          ditr->second.sourceFile
589        );
590      }
591    }
592  }
593
594  uint32_t DesiredSymbols::getNumberBranchesAlwaysTaken( void ) const {
595    return stats.branchesAlwaysTaken;
596  };
597
598  uint32_t DesiredSymbols::getNumberBranchesFound( void ) const {
599    return (stats.branchesNotExecuted + stats.branchesExecuted);
600  };
601
602  uint32_t DesiredSymbols::getNumberBranchesNeverTaken( void ) const {
603    return stats.branchesNeverTaken;
604  };
605
606  uint32_t DesiredSymbols::getNumberUncoveredRanges( void ) const {
607    return stats.uncoveredRanges;
608  };
609
610  bool DesiredSymbols::isDesired (
611    const std::string& symbolName
612  ) const
613  {
614    if (set.find( symbolName ) == set.end()) {
615      #if 0
616        fprintf( stderr,
617          "Warning: Unable to find symbol %s\n",
618          symbolName.c_str()
619        );
620      #endif
621      return false;
622    }
623    return true;
624  }
625
626  void DesiredSymbols::mergeCoverageMap(
627    const std::string&           symbolName,
628    const CoverageMapBase* const sourceCoverageMap
629  )
630  {
631    uint32_t              dAddress;
632    CoverageMapBase*      destinationCoverageMap;
633    uint32_t              dMapSize;
634    symbolSet_t::iterator itr;
635    uint32_t              sAddress;
636    uint32_t              sBaseAddress;
637    uint32_t              sMapSize;
638    uint32_t              executionCount;
639
640    // Ensure that the symbol is a desired symbol.
641    itr = set.find( symbolName );
642
643    if (itr == set.end()) {
644
645      fprintf(
646        stderr,
647        "ERROR: DesiredSymbols::mergeCoverageMap - Unable to merge "
648        "coverage map for %s because it is NOT a desired symbol\n",
649        symbolName.c_str()
650      );
651      exit( -1 );
652    }
653
654    // Ensure that the source and destination coverage maps
655    // are the same size.
656    dMapSize = itr->second.stats.sizeInBytes;
657    sBaseAddress = sourceCoverageMap->getFirstLowAddress();
658    sMapSize = sourceCoverageMap->getSize();
659    if (dMapSize != sMapSize) {
660
661      fprintf(
662        stderr,
663        "ERROR: DesiredSymbols::mergeCoverageMap - Unable to merge "
664        "coverage map for %s because the sizes are different\n",
665        symbolName.c_str()
666      );
667      return;
668      // exit( -1 );
669    }
670
671    // Merge the data for each address.
672    destinationCoverageMap = itr->second.unifiedCoverageMap;
673
674    for (dAddress = 0; dAddress < dMapSize; dAddress++) {
675
676      sAddress = dAddress + sBaseAddress;
677
678      // Merge start of instruction indication.
679      if (sourceCoverageMap->isStartOfInstruction( sAddress ))
680        destinationCoverageMap->setIsStartOfInstruction( dAddress );
681
682      // Merge the execution data.
683      executionCount = sourceCoverageMap->getWasExecuted( sAddress );
684      destinationCoverageMap->sumWasExecuted( dAddress, executionCount );
685
686      // Merge the branch data.
687      executionCount = sourceCoverageMap->getWasTaken( sAddress );
688      destinationCoverageMap->sumWasTaken( dAddress, executionCount );
689
690      executionCount = sourceCoverageMap->getWasNotTaken( sAddress );
691      destinationCoverageMap->sumWasNotTaken( dAddress, executionCount );
692    }
693  }
694
695}
Note: See TracBrowser for help on using the repository browser.