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

Last change on this file since 881824f was 881824f, checked in by Chris Johns <chrisj@…>, on May 11, 2018 at 2:24:11 AM

tester/covoar: Remove all exit() calls and throw an rld::error exception.

Add a suitable catch to covoar's main.

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