source: rtems-tools/tester/covoar/ExecutableInfo.cc @ 0c4884a

Last change on this file since 0c4884a was 917469b, checked in by Alex White <alex.white@…>, on 02/26/21 at 23:11:06

covoar: Fix overflow of high PC address

This fixes an integer overflow that would occur if a function's high PC
address were zero in the DWARF info.

  • Property mode set to 100644
File size: 5.6 KB
Line 
1/*! @file ExecutableInfo.cc
2 *  @brief ExecutableInfo Implementation
3 *
4 *  This file contains the implementation of the functionality
5 *  of the ExecutableInfo class.
6 */
7
8#include <stdio.h>
9
10#include <rld.h>
11
12#include "ExecutableInfo.h"
13#include "app_common.h"
14#include "CoverageMap.h"
15#include "DesiredSymbols.h"
16#include "SymbolTable.h"
17
18namespace Coverage {
19
20  ExecutableInfo::ExecutableInfo(
21    const char* const theExecutableName,
22    const char* const theLibraryName,
23    bool              verbose
24    ) : executable(theExecutableName),
25        loadAddress(0)
26  {
27    if (theLibraryName != nullptr)
28      libraryName = theLibraryName;
29
30    if (verbose) {
31      std::cerr << "Loading executable " << theExecutableName;
32      if (theLibraryName != nullptr)
33        std::cerr << " (" << theLibraryName << ')';
34      std::cerr << std::endl;
35    }
36
37    executable.open();
38    executable.begin();
39    executable.load_symbols(symbols);
40
41    debug.begin(executable.elf());
42    debug.load_debug();
43    debug.load_functions();
44
45    try {
46      for (auto& cu : debug.get_cus()) {
47        for (auto& func : cu.get_functions()) {
48          if (!func.has_machine_code()) {
49            continue;
50          }
51
52          if (!SymbolsToAnalyze->isDesired(func.name())) {
53            continue;
54          }
55
56          if (func.is_inlined()) {
57            if (func.is_external()) {
58              // Flag it
59              std::cerr << "Function is both external and inlined: "
60                        << func.name() << std::endl;
61            }
62
63            if (func.has_entry_pc()) {
64              continue;
65            }
66
67            // If the low PC address is zero, the symbol does not appear in
68            // this executable.
69            if (func.pc_low() == 0) {
70              continue;
71            }
72          }
73
74          // We can't process a zero size function.
75          if (func.pc_high() == 0) {
76            continue;
77          }
78
79          createCoverageMap (cu.name(), func.name(),
80                              func.pc_low(), func.pc_high() - 1);
81        }
82      }
83    } catch (...) {
84      debug.end();
85      executable.end();
86      executable.close();
87      throw;
88    }
89
90    // Can't cleanup handles until the destructor because the information is
91    // referenced elsewhere. NOTE: This could cause problems from too many open
92    // file descriptors.
93  }
94
95  ExecutableInfo::~ExecutableInfo()
96  {
97    debug.end();
98    executable.end();
99    executable.close();
100  }
101
102  void ExecutableInfo::dumpCoverageMaps( void ) {
103    ExecutableInfo::CoverageMaps::iterator  itr;
104
105    for (auto& cm : coverageMaps) {
106      std::cerr << "Coverage Map for " << cm.first << std::endl;
107      cm.second->dump();
108    }
109  }
110
111  void ExecutableInfo::dumpExecutableInfo( void ){
112    std::cout << std::endl
113              << "== Executable info ==" << std::endl
114              << "executable = " << getFileName () << std::endl
115              << "library = " << libraryName << std::endl
116              << "loadAddress = " << loadAddress << std::endl;
117    theSymbolTable.dumpSymbolTable();
118  }
119
120  CoverageMapBase* ExecutableInfo::getCoverageMap ( uint32_t address )
121  {
122    CoverageMapBase*       aCoverageMap = NULL;
123    CoverageMaps::iterator it;
124    std::string            itsSymbol;
125
126    // Obtain the coverage map containing the specified address.
127    itsSymbol = theSymbolTable.getSymbol( address );
128    if (itsSymbol != "") {
129      aCoverageMap = &findCoverageMap(itsSymbol);
130    }
131
132    return aCoverageMap;
133  }
134
135  const std::string ExecutableInfo::getFileName ( void ) const
136  {
137    return executable.name().full();
138  }
139
140  const std::string ExecutableInfo::getLibraryName( void ) const
141  {
142    return libraryName;
143  }
144
145  uint32_t ExecutableInfo::getLoadAddress( void ) const
146  {
147    return loadAddress;
148  }
149
150  SymbolTable* ExecutableInfo::getSymbolTable ( void )
151  {
152    return &theSymbolTable;
153  }
154
155  CoverageMapBase& ExecutableInfo::findCoverageMap(
156    const std::string& symbolName
157  )
158  {
159    CoverageMaps::iterator cmi = coverageMaps.find( symbolName );
160    if ( cmi == coverageMaps.end() )
161      throw CoverageMapNotFoundError(symbolName);
162    return *(cmi->second);
163  }
164
165  void ExecutableInfo::createCoverageMap (
166    const std::string& fileName,
167    const std::string& symbolName,
168    uint32_t           lowAddress,
169    uint32_t           highAddress
170  )
171  {
172    CoverageMapBase        *theMap;
173    CoverageMaps::iterator  itr;
174
175    if ( lowAddress > highAddress ) {
176      std::ostringstream what;
177      what << "Low address is greater than high address for symbol "
178            << symbolName
179            << " (" << lowAddress
180            << " and " << highAddress
181            << ")";
182      throw rld::error( what, "ExecutableInfo::createCoverageMap" );
183    }
184
185    itr = coverageMaps.find( symbolName );
186    if ( itr == coverageMaps.end() ) {
187      theMap = new CoverageMap( fileName, lowAddress, highAddress );
188      coverageMaps[ symbolName ] = theMap;
189    } else {
190      theMap = itr->second;
191      theMap->Add( lowAddress, highAddress );
192    }
193  }
194
195  void ExecutableInfo::getSourceAndLine(
196    const unsigned int address,
197    std::string&       line
198  )
199  {
200    std::string file;
201    int         lno;
202    debug.get_source (address, file, lno);
203    std::ostringstream ss;
204    ss << file << ':' << lno;
205    line = ss.str ();
206  }
207
208  bool ExecutableInfo::hasDynamicLibrary( void )
209  {
210    return !libraryName.empty();
211  }
212
213  void ExecutableInfo::mergeCoverage( void ) {
214    for (auto& cm : coverageMaps) {
215      if (SymbolsToAnalyze->isDesired( cm.first ))
216        SymbolsToAnalyze->mergeCoverageMap( cm.first, cm.second );
217    }
218  }
219
220  void ExecutableInfo::setLoadAddress( uint32_t address )
221  {
222    loadAddress = address;
223  }
224
225}
Note: See TracBrowser for help on using the repository browser.