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

5
Last change on this file since cb018bc was cb018bc, checked in by Hermann Felbinger <hermann19829@…>, on 08/26/17 at 08:15:53

covoar: Add information to improve diagnostics.

  • Property mode set to 100644
File size: 12.5 KB
Line 
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
6 *  coverage map.
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
24namespace Coverage {
25
26  void finalizeSymbol(
27    ExecutableInfo* const            executableInfo,
28    std::string&                     symbolName,
29    uint32_t                         lowAddress,
30    uint32_t                         highAddress,
31    ObjdumpProcessor::objdumpLines_t instructions
32  ) {
33
34    CoverageMapBase*                                   aCoverageMap = NULL;
35    uint32_t                                           endAddress = highAddress;
36    ObjdumpProcessor::objdumpLines_t::iterator         itr, fnop, lnop;
37    ObjdumpProcessor::objdumpLines_t::reverse_iterator ritr;
38    SymbolInformation*                                 symbolInfo = NULL;
39    SymbolTable*                                       theSymbolTable;
40
41    //
42    // Remove trailing nop instructions.
43    //
44
45    // First find the last instruction.
46    for (ritr = instructions.rbegin();
47         ritr != instructions.rend();
48         ritr++) {
49      if (ritr->isInstruction)
50        break;
51    }
52
53    // If an instruction was found and it is a nop, ...
54    if ((ritr != instructions.rend()) && (ritr->isNop)) {
55
56      // save it as the last nop.  Note that we must account for
57      // the difference between a forward and a reverse iterator.
58      lnop = ritr.base();
59      lnop--;
60      endAddress -= lnop->nopSize;
61
62      // Now look for the first nop in the sequence of trailing nops.
63      fnop = lnop;
64      ritr++;
65      for (; ritr != instructions.rend(); ritr++) {
66        if (ritr->isNop) {
67          fnop = ritr.base();
68          fnop--;
69          endAddress -= fnop->nopSize;
70        }
71        else
72          break;
73      }
74
75      // Erase trailing nops.  The erase operation wants the first
76      // parameter to point to the first item to erase and the second
77      // parameter to point to the item beyond the last item to erase.
78      if ( fnop == lnop )
79        instructions.erase( fnop );
80      else
81        instructions.erase( fnop, ++lnop );
82    }
83
84    // If there are NOT already saved instructions, save them.
85    symbolInfo = SymbolsToAnalyze->find( symbolName );
86    if (symbolInfo->instructions.empty()) {
87      symbolInfo->sourceFile = executableInfo;
88      symbolInfo->baseAddress = lowAddress;
89      symbolInfo->instructions = instructions;
90    }
91
92    // Add the symbol to this executable's symbol table.
93    theSymbolTable = executableInfo->getSymbolTable();
94    theSymbolTable->addSymbol(
95      symbolName, lowAddress, endAddress - lowAddress + 1
96    );
97
98    // Create a coverage map for the symbol.
99    aCoverageMap = executableInfo->createCoverageMap(
100      executableInfo->getFileName().c_str(), symbolName, lowAddress, endAddress
101    );
102
103    if (aCoverageMap) {
104
105      // Mark the start of each instruction in the coverage map.
106      for (itr = instructions.begin();
107           itr != instructions.end();
108           itr++ ) {
109
110        aCoverageMap->setIsStartOfInstruction( itr->address );
111      }
112
113      // Create a unified coverage map for the symbol.
114      SymbolsToAnalyze->createCoverageMap(
115        executableInfo->getFileName().c_str(), symbolName,
116        endAddress - lowAddress + 1
117      );
118    }
119  }
120
121  ObjdumpProcessor::ObjdumpProcessor()
122  {
123  }
124
125  ObjdumpProcessor::~ObjdumpProcessor()
126  {
127  }
128
129  uint32_t ObjdumpProcessor::determineLoadAddress(
130    ExecutableInfo* theExecutable
131  )
132  {
133    #define METHOD "ERROR: ObjdumpProcessor::determineLoadAddress - "
134    FILE*        loadAddressFile = NULL;
135    char*        cStatus;
136    uint32_t     offset;
137
138    // This method should only be call for a dynamic library.
139    if (!theExecutable->hasDynamicLibrary())
140      return 0;
141
142    std::string dlinfoName = theExecutable->getFileName();
143    uint32_t address;
144    char inLibName[128];
145    std::string Library = theExecutable->getLibraryName();
146
147    dlinfoName += ".dlinfo";
148    // Read load address.
149    loadAddressFile = fopen( dlinfoName.c_str(), "r" );
150    if (!loadAddressFile) {
151      fprintf( stderr, METHOD "unable to open %s\n", dlinfoName.c_str() );
152      exit( -1 );
153    }
154
155    // Process the dlinfo file.
156    while ( 1 ) {
157
158      // Get a line.
159      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, loadAddressFile );
160      if (cStatus == NULL) {
161        fprintf(
162          stderr,
163          METHOD "library %s not found in %s\n",
164          Library.c_str(),
165          dlinfoName.c_str()
166        );
167        fclose( loadAddressFile );
168        exit( -1 );
169      }
170      sscanf( inputBuffer, "%s %x", inLibName, &offset );
171      std::string tmp = inLibName;
172      if ( tmp.find( Library ) != tmp.npos ) {
173        // fprintf( stderr, "%s - 0x%08x\n", inLibName, offset );
174        address = offset;
175        break;
176      }
177    }
178
179    fclose( loadAddressFile );
180    return address;
181
182    #undef METHOD
183  }
184
185  bool ObjdumpProcessor::IsBranch(
186    const char *instruction
187  )
188  {
189    if ( !TargetInfo ) {
190      fprintf(
191        stderr,
192        "ERROR: ObjdumpProcessor::IsBranch - unknown architecture\n"
193      );
194      assert(0);
195      return false;
196    }
197
198    return TargetInfo->isBranch( instruction );
199  }
200
201  bool ObjdumpProcessor::isBranchLine(
202    const char* const line
203  )
204  {
205    if ( !TargetInfo ) {
206      fprintf(
207        stderr,
208        "ERROR: ObjdumpProcessor::isBranchLine - unknown architecture\n"
209      );
210      assert(0);
211      return false;
212    }
213
214    return  TargetInfo->isBranchLine( line );
215  }
216
217  bool ObjdumpProcessor::isNop(
218    const char* const line,
219    int&              size
220  )
221  {
222    if ( !TargetInfo ){
223      fprintf(
224        stderr,
225        "ERROR: ObjdumpProcessor::isNop - unknown architecture\n"
226      );
227      assert(0);
228      return false;
229    }
230
231    return TargetInfo->isNopLine( line, size );
232  }
233
234  FILE* ObjdumpProcessor::getFile( std::string fileName )
235  {
236    char               dumpFile[128];
237    FILE*              objdumpFile;
238    char               buffer[ 512 ];
239    int                status;
240
241    sprintf( dumpFile, "%s.dmp", fileName.c_str() );
242
243    // Generate the objdump.
244    if (FileIsNewer( fileName.c_str(), dumpFile )) {
245      sprintf(
246        buffer,
247        "%s -Cda --section=.text --source %s | sed -e \'s/ *$//\' >%s",
248        TargetInfo->getObjdump(),
249        fileName.c_str(),
250        dumpFile
251      );
252
253      status = system( buffer );
254      if (status) {
255        fprintf(
256          stderr,
257          "ERROR: ObjdumpProcessor::getFile - command (%s) failed with %d\n",
258          buffer,
259          status
260        );
261        exit( -1 );
262      }
263    }
264
265    // Open the objdump file.
266    objdumpFile = fopen( dumpFile, "r" );
267    if (!objdumpFile) {
268      fprintf(
269        stderr,
270        "ERROR: ObjdumpProcessor::getFile - unable to open %s\n",
271        dumpFile
272      );
273      exit(-1);
274    }
275
276    return objdumpFile;
277  }
278
279  uint32_t ObjdumpProcessor::getAddressAfter( uint32_t address )
280  {
281    objdumpFile_t::iterator itr;
282
283    itr = find ( objdumpList.begin(), objdumpList.end(), address );
284    if (itr == objdumpList.end()) {
285      return 0;
286    }
287
288    itr++;
289    if (itr == objdumpList.end()) {
290      return 0;
291    }
292
293    return (*itr);
294
295  }
296
297  void ObjdumpProcessor::loadAddressTable (
298    ExecutableInfo* const executableInformation
299  )
300  {
301    char*              cStatus;
302    int                items;
303    FILE*              objdumpFile;
304    uint32_t           offset;
305    char               terminator;
306
307    // Obtain the objdump file.
308    if (!executableInformation->hasDynamicLibrary())
309      objdumpFile = getFile( executableInformation->getFileName() );
310    else
311      objdumpFile = getFile( executableInformation->getLibraryName() );
312
313    // Process all lines from the objdump file.
314    while ( 1 ) {
315
316      // Get the line.
317      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, objdumpFile );
318      if (cStatus == NULL) {
319        break;
320      }
321      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
322
323      // See if it is the dump of an instruction.
324      items = sscanf(
325        inputBuffer,
326        "%x%c",
327        &offset, &terminator
328      );
329
330      // If it looks like an instruction ...
331      if ((items == 2) && (terminator == ':')){
332        objdumpList.push_back(
333          executableInformation->getLoadAddress() + offset
334        );
335      }
336    }
337  }
338
339  void ObjdumpProcessor::load(
340    ExecutableInfo* const executableInformation
341  )
342  {
343    char*              cStatus;
344    std::string        currentSymbol = "";
345    uint32_t           endAddress;
346    uint32_t           instructionOffset;
347    int                items;
348    objdumpLine_t      lineInfo;
349    FILE*              objdumpFile;
350    uint32_t           offset;
351    bool               processSymbol = false;
352    uint32_t           startAddress = 0;
353    char               symbol[ MAX_LINE_LENGTH ];
354    char               terminator1;
355    char               terminator2;
356    objdumpLines_t     theInstructions;
357
358    // Obtain the objdump file.
359    if (!executableInformation->hasDynamicLibrary())
360      objdumpFile = getFile( executableInformation->getFileName() );
361    else
362      objdumpFile = getFile( executableInformation->getLibraryName() );
363
364    // Process all lines from the objdump file.
365    while ( 1 ) {
366
367      // Get the line.
368      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, objdumpFile );
369      if (cStatus == NULL) {
370
371        // If we are currently processing a symbol, finalize it.
372        if (processSymbol) {
373          finalizeSymbol(
374            executableInformation,
375            currentSymbol,
376            startAddress,
377            executableInformation->getLoadAddress() + offset,
378            theInstructions
379          );
380          fprintf(
381            stderr,
382            "WARNING: ObjdumpProcessor::load - analysis of symbol %s \n"
383            "         may be incorrect.  It was the last symbol in %s\n"
384            "         and the length of its last instruction is assumed "
385            "         to be one.\n",
386            currentSymbol.c_str(),
387            executableInformation->getFileName().c_str()
388          );
389        }
390        break;
391      }
392
393      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
394
395      lineInfo.line          = inputBuffer;
396      lineInfo.address       = 0xffffffff;
397      lineInfo.isInstruction = false;
398      lineInfo.isNop         = false;
399      lineInfo.nopSize       = 0;
400      lineInfo.isBranch      = false;
401
402      // Look for the start of a symbol's objdump and extract
403      // offset and symbol (i.e. offset <symbolname>:).
404      items = sscanf(
405        inputBuffer,
406        "%x <%[^>]>%c",
407        &offset, symbol, &terminator1
408      );
409
410      // If all items found, we are at the beginning of a symbol's objdump.
411      if ((items == 3) && (terminator1 == ':')) {
412
413        endAddress = executableInformation->getLoadAddress() + offset - 1;
414
415        // If we are currently processing a symbol, finalize it.
416        if (processSymbol) {
417          finalizeSymbol(
418            executableInformation,
419            currentSymbol,
420            startAddress,
421            endAddress,
422            theInstructions
423          );
424        }
425
426        // Start processing of a new symbol.
427        startAddress = 0;
428        currentSymbol = "";
429        processSymbol = false;
430        theInstructions.clear();
431
432        // See if the new symbol is one that we care about.
433        if (SymbolsToAnalyze->isDesired( symbol )) {
434          startAddress = executableInformation->getLoadAddress() + offset;
435          currentSymbol = symbol;
436          processSymbol = true;
437          theInstructions.push_back( lineInfo );
438        }
439      }
440
441      else if (processSymbol) {
442
443        // See if it is the dump of an instruction.
444        items = sscanf(
445          inputBuffer,
446          "%x%c\t%*[^\t]%c",
447          &instructionOffset, &terminator1, &terminator2
448        );
449
450        // If it looks like an instruction ...
451        if ((items == 3) && (terminator1 == ':') && (terminator2 == '\t')) {
452
453          // update the line's information, save it and ...
454          lineInfo.address =
455           executableInformation->getLoadAddress() + instructionOffset;
456          lineInfo.isInstruction = true;
457          lineInfo.isNop         = isNop( inputBuffer, lineInfo.nopSize );
458          lineInfo.isBranch      = isBranchLine( inputBuffer );
459        }
460
461        // Always save the line.
462        theInstructions.push_back( lineInfo );
463      }
464    }
465  }
466}
Note: See TracBrowser for help on using the repository browser.