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

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

covoar: Refactor DesiredSymbols?.cc to C++11.

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