source: rtems-testing/covoar/ObjdumpProcessor.cc @ e7bb58a

4.11
Last change on this file since e7bb58a was e7bb58a, checked in by Jennifer Averett <Jennifer.Averett@…>, on May 25, 2010 at 7:14:48 PM

2010-05-25 Jennifer Averett <Jennifer.Averett@…>

  • DesiredSymbols?.cc, Explanations.cc, ObjdumpProcessor?.cc, TraceReaderLogQEMU.cc, app_common.cc, app_common.h: Added a inputBuffer to app_common and modified all fgets calls to use this buffer. This will allow for a size increase if necessary.
  • Property mode set to 100644
File size: 12.4 KB
Line 
1/*
2 *  $Id$
3 */
4
5/*! @file ObjdumpProcessor.cc
6 *  @brief ObjdumpProcessor Implementation
7 *
8 *  This file contains the implementation of the functions supporting
9 *  the reading of an objdump output file and adding nops to a
10 *  coverage map.
11 */
12
13#include <assert.h>
14#include <ctype.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <algorithm>
19#include <string>
20
21#include "app_common.h"
22#include "ObjdumpProcessor.h"
23#include "CoverageMap.h"
24#include "ExecutableInfo.h"
25#include "SymbolTable.h"
26#include "TargetFactory.h"
27
28namespace Coverage {
29
30  void finalizeSymbol(
31    ExecutableInfo* const            executableInfo,
32    std::string&                     symbolName,
33    uint32_t                         lowAddress,
34    uint32_t                         highAddress,
35    ObjdumpProcessor::objdumpLines_t instructions
36  ) {
37
38    CoverageMapBase*                                   aCoverageMap = NULL;
39    uint32_t                                           endAddress = highAddress;
40    ObjdumpProcessor::objdumpLines_t::iterator         itr, fnop, lnop;
41    ObjdumpProcessor::objdumpLines_t::reverse_iterator ritr;
42    SymbolInformation*                                 symbolInfo = NULL;
43    SymbolTable*                                       theSymbolTable;
44
45    //
46    // Remove trailing nop instructions.
47    //
48
49    // First find the last instruction.
50    for (ritr = instructions.rbegin();
51         ritr != instructions.rend();
52         ritr++) {
53      if (ritr->isInstruction)
54        break;
55    }
56
57    // If an instruction was found and it is a nop, ...
58    if ((ritr != instructions.rend()) && (ritr->isNop)) {
59
60      // save it as the last nop.  Note that we must account for
61      // the difference between a forward and a reverse iterator.
62      lnop = ritr.base();
63      lnop--;
64      endAddress -= lnop->nopSize;
65
66      // Now look for the first nop in the sequence of trailing nops.
67      fnop = lnop;
68      ritr++;
69      for (; ritr != instructions.rend(); ritr++) {
70        if (ritr->isNop) {
71          fnop = ritr.base();
72          fnop--;
73          endAddress -= fnop->nopSize;
74        }
75        else
76          break;
77      }
78
79      // Erase trailing nops.  The erase operation wants the first
80      // parameter to point to the first item to erase and the second
81      // parameter to point to the item beyond the last item to erase.
82      instructions.erase( fnop, ++lnop );
83    }
84
85    // If there are NOT already saved instructions, save them.
86    symbolInfo = SymbolsToAnalyze->find( symbolName );
87    if (symbolInfo->instructions.empty()) {
88      symbolInfo->sourceFile = executableInfo;
89      symbolInfo->baseAddress = lowAddress;
90      symbolInfo->instructions = instructions;
91    }
92
93    // Add the symbol to this executable's symbol table.
94    theSymbolTable = executableInfo->getSymbolTable();
95    theSymbolTable->addSymbol(
96      symbolName, lowAddress, endAddress - lowAddress + 1
97    );
98
99    // Create a coverage map for the symbol.
100    aCoverageMap = executableInfo->createCoverageMap(
101      symbolName, lowAddress, endAddress
102    );
103
104    if (aCoverageMap) {
105
106      // Mark the start of each instruction in the coverage map.
107      for (itr = instructions.begin();
108           itr != instructions.end();
109           itr++ ) {
110
111        aCoverageMap->setIsStartOfInstruction( itr->address );
112      }
113
114      // Create a unified coverage map for the symbol.
115      SymbolsToAnalyze->createCoverageMap(
116        symbolName, 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[ 100 ];
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.