source: rtems-testing/covoar/DesiredSymbols.cc @ e7bb58a

4.11
Last change on this file since e7bb58a was e7bb58a, checked in by Jennifer Averett <Jennifer.Averett@…>, on May 25, 2010 at 7:14:48 PM

2010-05-25 Jennifer Averett <Jennifer.Averett@…>

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