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

Last change on this file since 09f4dbe was 99c90b3, checked in by Chris Johns <chrisj@…>, on Aug 5, 2018 at 11:41:08 PM

tester/covoar: Integrate DWARF function data.

Use DAWRF function data to create the executable coverage
maps. Integrate the existing objdump processing with this
data.

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