source: rtems-tools/tester/covoar/ObjdumpProcessor.cc @ 61410db

5
Last change on this file since 61410db was 61410db, checked in by Chris Johns <chrisj@…>, on 11/28/18 at 21:03:29

tester/coverage: Remove warnings in covoar on Windows.

  • Property mode set to 100644
File size: 11.3 KB
RevLine 
[100f517]1/*! @file ObjdumpProcessor.cc
2 *  @brief ObjdumpProcessor Implementation
3 *
4 *  This file contains the implementation of the functions supporting
5 *  the reading of an objdump output file and adding nops to a
[cb018bc]6 *  coverage map.
[100f517]7 */
8
9#include <assert.h>
10#include <ctype.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <algorithm>
15#include <string>
16
17#include "app_common.h"
18#include "ObjdumpProcessor.h"
19#include "CoverageMap.h"
20#include "ExecutableInfo.h"
21#include "SymbolTable.h"
22#include "TargetFactory.h"
23
[6a4859e]24#include "rld.h"
25#include "rld-process.h"
26
[100f517]27namespace Coverage {
28
29  void finalizeSymbol(
30    ExecutableInfo* const            executableInfo,
31    std::string&                     symbolName,
32    ObjdumpProcessor::objdumpLines_t instructions
33  ) {
[99c90b3]34    // Find the symbol's coverage map.
35    CoverageMapBase& coverageMap = executableInfo->findCoverageMap( symbolName );
[100f517]36
[99c90b3]37    uint32_t lowAddress = coverageMap.getFirstLowAddress();
38    uint32_t size = coverageMap.getSize();
39    uint32_t highAddress = lowAddress + size;
[100f517]40
41    // If there are NOT already saved instructions, save them.
[99c90b3]42    SymbolInformation* symbolInfo = SymbolsToAnalyze->find( symbolName );
[100f517]43    if (symbolInfo->instructions.empty()) {
44      symbolInfo->sourceFile = executableInfo;
45      symbolInfo->baseAddress = lowAddress;
46      symbolInfo->instructions = instructions;
47    }
48
49    // Add the symbol to this executable's symbol table.
[99c90b3]50    SymbolTable* theSymbolTable = executableInfo->getSymbolTable();
[100f517]51    theSymbolTable->addSymbol(
[99c90b3]52      symbolName, lowAddress, highAddress - lowAddress + 1
[100f517]53    );
54
[99c90b3]55    // Mark the start of each instruction in the coverage map.
56    for (auto& instruction : instructions) {
57      coverageMap.setIsStartOfInstruction( instruction.address );
[100f517]58    }
[99c90b3]59
60    // Create a unified coverage map for the symbol.
61    SymbolsToAnalyze->createCoverageMap(
62      executableInfo->getFileName().c_str(), symbolName, size
63    );
[100f517]64  }
65
66  ObjdumpProcessor::ObjdumpProcessor()
67  {
68  }
69
70  ObjdumpProcessor::~ObjdumpProcessor()
71  {
72  }
73
74  uint32_t ObjdumpProcessor::determineLoadAddress(
75    ExecutableInfo* theExecutable
76  )
77  {
78    #define METHOD "ERROR: ObjdumpProcessor::determineLoadAddress - "
79    FILE*        loadAddressFile = NULL;
80    char*        cStatus;
81    uint32_t     offset;
82
83    // This method should only be call for a dynamic library.
84    if (!theExecutable->hasDynamicLibrary())
85      return 0;
86
87    std::string dlinfoName = theExecutable->getFileName();
88    uint32_t address;
89    char inLibName[128];
90    std::string Library = theExecutable->getLibraryName();
91
92    dlinfoName += ".dlinfo";
93    // Read load address.
[881824f]94    loadAddressFile = ::fopen( dlinfoName.c_str(), "r" );
[100f517]95    if (!loadAddressFile) {
[881824f]96      std::ostringstream what;
97      what << "Unable to open " << dlinfoName;
98      throw rld::error( what, METHOD );
[100f517]99    }
100
101    // Process the dlinfo file.
102    while ( 1 ) {
103
104      // Get a line.
[881824f]105      cStatus = ::fgets( inputBuffer, MAX_LINE_LENGTH, loadAddressFile );
[100f517]106      if (cStatus == NULL) {
[881824f]107        ::fclose( loadAddressFile );
108        std::ostringstream what;
109        what << "library " << Library << " not found in " << dlinfoName;
110        throw rld::error( what, METHOD );
[100f517]111      }
112      sscanf( inputBuffer, "%s %x", inLibName, &offset );
113      std::string tmp = inLibName;
114      if ( tmp.find( Library ) != tmp.npos ) {
115        // fprintf( stderr, "%s - 0x%08x\n", inLibName, offset );
[cb018bc]116        address = offset;
[100f517]117        break;
118      }
119    }
120
[881824f]121    ::fclose( loadAddressFile );
[100f517]122    return address;
123
124    #undef METHOD
125  }
126
127  bool ObjdumpProcessor::IsBranch(
[cb018bc]128    const char *instruction
[100f517]129  )
[cb018bc]130  {
[100f517]131    if ( !TargetInfo ) {
132      fprintf(
133        stderr,
134        "ERROR: ObjdumpProcessor::IsBranch - unknown architecture\n"
135      );
136      assert(0);
137      return false;
138    }
139
140    return TargetInfo->isBranch( instruction );
141  }
142
143  bool ObjdumpProcessor::isBranchLine(
144    const char* const line
145  )
146  {
147    if ( !TargetInfo ) {
148      fprintf(
149        stderr,
150        "ERROR: ObjdumpProcessor::isBranchLine - unknown architecture\n"
151      );
152      assert(0);
153      return false;
154    }
155
156    return  TargetInfo->isBranchLine( line );
157  }
158
159  bool ObjdumpProcessor::isNop(
160    const char* const line,
161    int&              size
162  )
163  {
164    if ( !TargetInfo ){
165      fprintf(
166        stderr,
167        "ERROR: ObjdumpProcessor::isNop - unknown architecture\n"
168      );
169      assert(0);
170      return false;
171    }
172
173    return TargetInfo->isNopLine( line, size );
174  }
175
[6a4859e]176  void ObjdumpProcessor::getFile(
177    std::string fileName,
178    rld::process::tempfile& objdumpFile,
179    rld::process::tempfile& err
180    )
[100f517]181  {
[6a4859e]182    rld::process::status        status;
183    rld::process::arg_container args = { TargetInfo->getObjdump(),
184                                         "-Cda", "--section=.text", "--source",
185                                         fileName };
186    try
187    {
188      status = rld::process::execute( TargetInfo->getObjdump(),
[3e187ba]189                                      args, objdumpFile.name(), err.name() );
[6a4859e]190      if ( (status.type != rld::process::status::normal)
191           || (status.code != 0) ) {
192        throw rld::error( "Objdump error", "generating objdump" );
193      }
194    } catch( rld::error& err )
195      {
[3e187ba]196        std::cout << "Error while running " << TargetInfo->getObjdump()
197                  << " on " << fileName << std::endl;
[6a4859e]198        std::cout << err.what << " in " << err.where << std::endl;
199        return;
[100f517]200      }
201
[6a4859e]202    objdumpFile.open( true );
[100f517]203  }
204
205  uint32_t ObjdumpProcessor::getAddressAfter( uint32_t address )
206  {
207    objdumpFile_t::iterator itr;
208
209    itr = find ( objdumpList.begin(), objdumpList.end(), address );
210    if (itr == objdumpList.end()) {
211      return 0;
212    }
[cb018bc]213
[100f517]214    itr++;
215    if (itr == objdumpList.end()) {
216      return 0;
217    }
218
219    return (*itr);
220
221  }
222
223  void ObjdumpProcessor::loadAddressTable (
[6a4859e]224    ExecutableInfo* const    executableInformation,
225    rld::process::tempfile&  objdumpFile,
226    rld::process::tempfile&  err
[100f517]227  )
228  {
[6a4859e]229    int          items;
230    uint32_t     offset;
231    char         terminator;
232    std::string  line;
[100f517]233
234    // Obtain the objdump file.
[6a4859e]235    if ( !executableInformation->hasDynamicLibrary() )
236      getFile( executableInformation->getFileName(), objdumpFile, err );
[100f517]237    else
[6a4859e]238      getFile( executableInformation->getLibraryName(), objdumpFile, err );
[100f517]239
240    // Process all lines from the objdump file.
[6a4859e]241    while ( true ) {
[100f517]242
243      // Get the line.
[6a4859e]244      objdumpFile.read_line( line );
245      if ( line.empty() ) {
[100f517]246        break;
247      }
248
249      // See if it is the dump of an instruction.
250      items = sscanf(
[6a4859e]251        line.c_str(),
[100f517]252        "%x%c",
253        &offset, &terminator
254      );
255
256      // If it looks like an instruction ...
[6a4859e]257      if ((items == 2) && (terminator == ':')) {
[100f517]258        objdumpList.push_back(
259          executableInformation->getLoadAddress() + offset
260        );
261      }
262    }
263  }
264
265  void ObjdumpProcessor::load(
[6a4859e]266    ExecutableInfo* const    executableInformation,
267    rld::process::tempfile&  objdumpFile,
268    rld::process::tempfile&  err
[100f517]269  )
270  {
[6a4859e]271    std::string     currentSymbol = "";
272    uint32_t        instructionOffset;
273    int             items;
274    int             found;
275    objdumpLine_t   lineInfo;
276    uint32_t        offset;
277    bool            processSymbol = false;
278    char            symbol[ MAX_LINE_LENGTH ];
279    char            terminator1;
280    char            terminatorOne;
281    char            terminator2;
282    objdumpLines_t  theInstructions;
283    char            instruction[ MAX_LINE_LENGTH ];
284    char            ID[ MAX_LINE_LENGTH ];
285    std::string     call = "";
286    std::string     jumpTableID = "";
287    std::string     line = "";
[100f517]288
289    // Obtain the objdump file.
[6a4859e]290    if ( !executableInformation->hasDynamicLibrary() )
291      getFile( executableInformation->getFileName(), objdumpFile, err );
[100f517]292    else
[6a4859e]293      getFile( executableInformation->getLibraryName(), objdumpFile, err );
[100f517]294
[6a4859e]295    while ( true ) {
[100f517]296      // Get the line.
[6a4859e]297      objdumpFile.read_line( line );
298      if ( line.empty() ) {
[100f517]299        // If we are currently processing a symbol, finalize it.
300        if (processSymbol) {
301          finalizeSymbol(
302            executableInformation,
303            currentSymbol,
304            theInstructions
305          );
306          fprintf(
307            stderr,
308            "WARNING: ObjdumpProcessor::load - analysis of symbol %s \n"
309            "         may be incorrect.  It was the last symbol in %s\n"
310            "         and the length of its last instruction is assumed "
311            "         to be one.\n",
312            currentSymbol.c_str(),
313            executableInformation->getFileName().c_str()
314          );
315        }
[6a4859e]316        objdumpFile.close();
[100f517]317        break;
318      }
319
[6a4859e]320      lineInfo.line          = line;
[100f517]321      lineInfo.address       = 0xffffffff;
322      lineInfo.isInstruction = false;
323      lineInfo.isNop         = false;
324      lineInfo.nopSize       = 0;
325      lineInfo.isBranch      = false;
326
[99c90b3]327      instruction[0] = '\0';
328      ID[0] = '\0';
329
[100f517]330      // Look for the start of a symbol's objdump and extract
331      // offset and symbol (i.e. offset <symbolname>:).
332      items = sscanf(
[6a4859e]333        line.c_str(),
[100f517]334        "%x <%[^>]>%c",
335        &offset, symbol, &terminator1
336      );
337
[9534157]338      // See if it is a jump table.
339      found = sscanf(
[6a4859e]340        line.c_str(),
[9534157]341        "%x%c\t%*[^\t]%c%s %*x %*[^+]%s",
342        &instructionOffset, &terminatorOne, &terminator2, instruction, ID
343      );
344      call = instruction;
345      jumpTableID = ID;
346
[100f517]347      // If all items found, we are at the beginning of a symbol's objdump.
348      if ((items == 3) && (terminator1 == ':')) {
349        // If we are currently processing a symbol, finalize it.
350        if (processSymbol) {
351          finalizeSymbol(
352            executableInformation,
353            currentSymbol,
354            theInstructions
355          );
356        }
357
358        // Start processing of a new symbol.
359        currentSymbol = "";
360        processSymbol = false;
361        theInstructions.clear();
362
363        // See if the new symbol is one that we care about.
364        if (SymbolsToAnalyze->isDesired( symbol )) {
365          currentSymbol = symbol;
366          processSymbol = true;
367          theInstructions.push_back( lineInfo );
368        }
369      }
[9534157]370      // If it looks like a jump table, finalize the symbol.
371      else if ( (found == 5) && (terminatorOne == ':') && (terminator2 == '\t')
372               && (call.find( "call" ) != std::string::npos)
373               && (jumpTableID.find( "+0x" ) != std::string::npos)
374               && processSymbol )
375      {
[99c90b3]376        // If we are currently processing a symbol, finalize it.
377        if ( processSymbol ) {
378          finalizeSymbol(
379            executableInformation,
380            currentSymbol,
381            theInstructions
[9534157]382            );
[99c90b3]383        }
384        processSymbol = false;
[9534157]385      }
[100f517]386      else if (processSymbol) {
387
388        // See if it is the dump of an instruction.
389        items = sscanf(
[6a4859e]390          line.c_str(),
[100f517]391          "%x%c\t%*[^\t]%c",
392          &instructionOffset, &terminator1, &terminator2
393        );
394
395        // If it looks like an instruction ...
396        if ((items == 3) && (terminator1 == ':') && (terminator2 == '\t')) {
397          // update the line's information, save it and ...
398          lineInfo.address =
399           executableInformation->getLoadAddress() + instructionOffset;
400          lineInfo.isInstruction = true;
[6a4859e]401          lineInfo.isNop         = isNop( line.c_str(), lineInfo.nopSize );
402          lineInfo.isBranch      = isBranchLine( line.c_str() );
[100f517]403        }
404
405        // Always save the line.
406        theInstructions.push_back( lineInfo );
407      }
408    }
409  }
410}
Note: See TracBrowser for help on using the repository browser.