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

Last change on this file since fb987e8 was fb987e8, checked in by Chris Johns <chrisj@…>, on May 8, 2018 at 5:09:39 AM

covoar: Use DWARF to map addresses to source files and lines.

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