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

5
Last change on this file since e04699b was e04699b, checked in by Chris Johns <chrisj@…>, on 05/24/18 at 21:25:38

tester/covoar: Do not load an executable's local symbols.

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