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

5
Last change on this file since dd3d0cc was dd3d0cc, checked in by Jiri Gaisler <jiri@…>, on 01/25/19 at 15:36:24

covoar: debug print-out of addresses should be in hex

  • 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                          << std::hex
300                          << " (0x" << s.second.baseAddress + la
301                          << " - 0x" << s.second.baseAddress + ha
302                          << ")"
303                          << std::dec
304                          << std::endl;
305            }
306            a = ha + 1;
307          }
308          else
309            a++;
310        }
311      }
312    }
313  }
314
315
316  void DesiredSymbols::createCoverageMap(
317    const std::string& exefileName,
318    const std::string& symbolName,
319    uint32_t           size
320  )
321  {
322    CoverageMapBase* aCoverageMap;
323    uint32_t         highAddress;
324
325    // Ensure that the symbol is a desired symbol.
326    symbolSet_t::iterator itr = set.find( symbolName );
327
328    if (itr == set.end()) {
329      std::ostringstream what;
330      what << "Unable to create unified coverage map for "
331           << symbolName
332           << " because it is NOT a desired symbol";
333      throw rld::error( what, "DesiredSymbols::createCoverageMap" );
334    }
335
336    // If we have already created a coverage map, ...
337    if (itr->second.unifiedCoverageMap) {
338
339      // ensure that the specified size matches the existing size.
340      if (itr->second.stats.sizeInBytes != size) {
341
342        // Changed ERROR to INFO because size mismatch is not treated as
343        // error anymore.
344        // Set smallest size as size and continue.
345        // Update value for longer byte size.
346        // 2015-07-22
347        std::cerr << "INFO: DesiredSymbols::createCoverageMap - Attempt to create "
348                  << "unified coverage maps for "
349                  << symbolName
350                  << " with different sizes ("
351                  << rld::path::basename(exefileName) << '/' << itr->second.stats.sizeInBytes
352                  << " != "
353                  << rld::path::basename(itr->second.sourceFile->getFileName())
354                  << '/' << size << ')'
355                  << std::endl;
356
357        if ( itr->second.stats.sizeInBytes < size )
358          itr->second.stats.sizeInBytes = size;
359        else
360          size = itr->second.stats.sizeInBytes;
361      }
362    }
363
364    // If we don't already have a coverage map, create one.
365    else {
366
367      highAddress = size - 1;
368
369      aCoverageMap = new CoverageMap( exefileName, 0, highAddress );
370
371      if ( Verbose )
372        fprintf(
373          stderr,
374          "Created unified coverage map for %s (0x%x - 0x%x)\n",
375          symbolName.c_str(), 0, highAddress
376        );
377      itr->second.unifiedCoverageMap = aCoverageMap;
378      itr->second.stats.sizeInBytes = size;
379    }
380  }
381
382  void DesiredSymbols::determineSourceLines(
383    CoverageRanges* const theRanges,
384    ExecutableInfo* const theExecutable
385
386  )
387  {
388    for (auto& r : theRanges->set) {
389      std::string location;
390      theExecutable->getSourceAndLine(r.lowAddress, location);
391      r.lowSourceLine = rld::path::basename (location);
392      theExecutable->getSourceAndLine(r.highAddress, location);
393      r.highSourceLine = rld::path::basename (location);
394    }
395  }
396
397  SymbolInformation* DesiredSymbols::find(
398    const std::string& symbolName
399  )
400  {
401    if (set.find( symbolName ) == set.end())
402      return NULL;
403    else
404      return &set[ symbolName ];
405  }
406
407  void DesiredSymbols::findSourceForUncovered( void )
408  {
409    // Process uncovered ranges and/or branches for each symbol.
410    for (auto& d : SymbolsToAnalyze->set) {
411      // First the unexecuted ranges, ...
412      CoverageRanges* theRanges = d.second.uncoveredRanges;
413      if (theRanges != nullptr) {
414        if (!theRanges->set.empty()) {
415          if (Verbose)
416            std::cerr << "Looking up source lines for uncovered ranges in "
417                      << d.first
418                      << std::endl;
419          determineSourceLines( theRanges, d.second.sourceFile );
420        }
421
422        // then the uncovered branches.
423        CoverageRanges* theBranches = d.second.uncoveredBranches;
424        if (theBranches != nullptr) {
425          if (!theBranches->set.empty()) {
426            if (Verbose)
427              std::cerr << "Looking up source lines for uncovered branches in "
428                        << d.first
429                        << std::endl;
430            determineSourceLines( theBranches, d.second.sourceFile );
431          }
432        }
433      }
434    }
435  }
436
437  uint32_t DesiredSymbols::getNumberBranchesAlwaysTaken( void ) const {
438    return stats.branchesAlwaysTaken;
439  };
440
441  uint32_t DesiredSymbols::getNumberBranchesFound( void ) const {
442    return (stats.branchesNotExecuted + stats.branchesExecuted);
443  };
444
445  uint32_t DesiredSymbols::getNumberBranchesNeverTaken( void ) const {
446    return stats.branchesNeverTaken;
447  };
448
449  uint32_t DesiredSymbols::getNumberUncoveredRanges( void ) const {
450    return stats.uncoveredRanges;
451  };
452
453  bool DesiredSymbols::isDesired (
454    const std::string& symbolName
455  ) const
456  {
457    return set.find( symbolName ) == set.end() ? false : true;
458  }
459
460  void DesiredSymbols::mergeCoverageMap(
461    const std::string&           symbolName,
462    const CoverageMapBase* const sourceCoverageMap
463  )
464  {
465    // Ensure that the symbol is a desired symbol.
466    symbolSet_t::iterator itr = set.find( symbolName );
467
468    if (itr == set.end()) {
469      std::ostringstream what;
470      what << "Unable to merge coverage map for "
471           << symbolName
472           << " because it is NOT a desired symbol";
473      throw rld::error( what, "DesiredSymbols::mergeCoverageMap" );
474    }
475
476    SymbolInformation& sinfo = itr->second;
477
478    // Ensure that the source and destination coverage maps
479    // are the same size.
480    // Changed from ERROR msg to INFO, because size mismatch is not
481    // treated as error anymore. 2015-07-20
482    uint32_t dMapSize = sinfo.stats.sizeInBytes;
483    uint32_t sBaseAddress = sourceCoverageMap->getFirstLowAddress();
484    uint32_t sMapSize = sourceCoverageMap->getSize();
485    if (dMapSize != 0 && dMapSize != sMapSize) {
486      std::cerr << "INFO: DesiredSymbols::mergeCoverageMap - Unable to merge "
487                << "coverage map for " << symbolName
488                << " because the sizes are different ("
489                << "size: " << dMapSize << ", source: " << sMapSize << ')'
490                << std::endl;
491      return;
492    }
493
494    // Merge the data for each address.
495    CoverageMapBase* destinationCoverageMap = sinfo.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.