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

4.104.115
Last change on this file since 100f517 was 100f517, checked in by Chris Johns <chrisj@…>, on 05/09/14 at 11:50:37

covoar: Merger the covoar source from rtems-testing.git.

Use waf to build covoar.

  • Property mode set to 100644
File size: 12.4 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      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        symbolName, endAddress - lowAddress + 1
116      );
117    }
118  }
119
120  ObjdumpProcessor::ObjdumpProcessor()
121  {
122  }
123
124  ObjdumpProcessor::~ObjdumpProcessor()
125  {
126  }
127
128  uint32_t ObjdumpProcessor::determineLoadAddress(
129    ExecutableInfo* theExecutable
130  )
131  {
132    #define METHOD "ERROR: ObjdumpProcessor::determineLoadAddress - "
133    FILE*        loadAddressFile = NULL;
134    char*        cStatus;
135    uint32_t     offset;
136
137    // This method should only be call for a dynamic library.
138    if (!theExecutable->hasDynamicLibrary())
139      return 0;
140
141    std::string dlinfoName = theExecutable->getFileName();
142    uint32_t address;
143    char inLibName[128];
144    std::string Library = theExecutable->getLibraryName();
145
146    dlinfoName += ".dlinfo";
147    // Read load address.
148    loadAddressFile = fopen( dlinfoName.c_str(), "r" );
149    if (!loadAddressFile) {
150      fprintf( stderr, METHOD "unable to open %s\n", dlinfoName.c_str() );
151      exit( -1 );
152    }
153
154    // Process the dlinfo file.
155    while ( 1 ) {
156
157      // Get a line.
158      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, loadAddressFile );
159      if (cStatus == NULL) {
160        fprintf(
161          stderr,
162          METHOD "library %s not found in %s\n",
163          Library.c_str(),
164          dlinfoName.c_str()
165        );
166        fclose( loadAddressFile );
167        exit( -1 );
168      }
169      sscanf( inputBuffer, "%s %x", inLibName, &offset );
170      std::string tmp = inLibName;
171      if ( tmp.find( Library ) != tmp.npos ) {
172        // fprintf( stderr, "%s - 0x%08x\n", inLibName, offset );
173        address = offset;
174        break;
175      }
176    }
177
178    fclose( loadAddressFile );
179    return address;
180
181    #undef METHOD
182  }
183
184  bool ObjdumpProcessor::IsBranch(
185    const char *instruction
186  )
187  {
188    if ( !TargetInfo ) {
189      fprintf(
190        stderr,
191        "ERROR: ObjdumpProcessor::IsBranch - unknown architecture\n"
192      );
193      assert(0);
194      return false;
195    }
196
197    return TargetInfo->isBranch( instruction );
198  }
199
200  bool ObjdumpProcessor::isBranchLine(
201    const char* const line
202  )
203  {
204    if ( !TargetInfo ) {
205      fprintf(
206        stderr,
207        "ERROR: ObjdumpProcessor::isBranchLine - unknown architecture\n"
208      );
209      assert(0);
210      return false;
211    }
212
213    return  TargetInfo->isBranchLine( line );
214  }
215
216  bool ObjdumpProcessor::isNop(
217    const char* const line,
218    int&              size
219  )
220  {
221    if ( !TargetInfo ){
222      fprintf(
223        stderr,
224        "ERROR: ObjdumpProcessor::isNop - unknown architecture\n"
225      );
226      assert(0);
227      return false;
228    }
229
230    return TargetInfo->isNopLine( line, size );
231  }
232
233  FILE* ObjdumpProcessor::getFile( std::string fileName )
234  {
235    char               dumpFile[128];
236    FILE*              objdumpFile;
237    char               buffer[ 512 ];
238    int                status;
239
240    sprintf( dumpFile, "%s.dmp", fileName.c_str() );
241     
242    // Generate the objdump.
243    if (FileIsNewer( fileName.c_str(), dumpFile )) {
244      sprintf(
245        buffer,
246        "%s -Cda --section=.text --source %s | sed -e \'s/ *$//\' >%s",
247        TargetInfo->getObjdump(),
248        fileName.c_str(),
249        dumpFile
250      );
251
252      status = system( buffer );
253      if (status) {
254        fprintf(
255          stderr,
256          "ERROR: ObjdumpProcessor::getFile - command (%s) failed with %d\n",
257          buffer,
258          status
259        );
260        exit( -1 );
261      }
262    }
263
264    // Open the objdump file.
265    objdumpFile = fopen( dumpFile, "r" );
266    if (!objdumpFile) {
267      fprintf(
268        stderr,
269        "ERROR: ObjdumpProcessor::getFile - unable to open %s\n",
270        dumpFile
271      );
272      exit(-1);
273    }
274
275    return objdumpFile;
276  }
277
278  uint32_t ObjdumpProcessor::getAddressAfter( uint32_t address )
279  {
280    objdumpFile_t::iterator itr;
281
282    itr = find ( objdumpList.begin(), objdumpList.end(), address );
283    if (itr == objdumpList.end()) {
284      return 0;
285    }
286   
287    itr++;
288    if (itr == objdumpList.end()) {
289      return 0;
290    }
291
292    return (*itr);
293
294  }
295
296  void ObjdumpProcessor::loadAddressTable (
297    ExecutableInfo* const executableInformation
298  )
299  {
300    char*              cStatus;
301    int                items;
302    FILE*              objdumpFile;
303    uint32_t           offset;
304    char               terminator;
305
306    // Obtain the objdump file.
307    if (!executableInformation->hasDynamicLibrary())
308      objdumpFile = getFile( executableInformation->getFileName() );
309    else
310      objdumpFile = getFile( executableInformation->getLibraryName() );
311
312    // Process all lines from the objdump file.
313    while ( 1 ) {
314
315      // Get the line.
316      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, objdumpFile );
317      if (cStatus == NULL) {
318        break;
319      }
320      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
321
322      // See if it is the dump of an instruction.
323      items = sscanf(
324        inputBuffer,
325        "%x%c",
326        &offset, &terminator
327      );
328
329      // If it looks like an instruction ...
330      if ((items == 2) && (terminator == ':')){
331        objdumpList.push_back(
332          executableInformation->getLoadAddress() + offset
333        );
334      }
335    }
336  }
337
338  void ObjdumpProcessor::load(
339    ExecutableInfo* const executableInformation
340  )
341  {
342    char*              cStatus;
343    std::string        currentSymbol = "";
344    uint32_t           endAddress;
345    uint32_t           instructionOffset;
346    int                items;
347    objdumpLine_t      lineInfo;
348    FILE*              objdumpFile;
349    uint32_t           offset;
350    bool               processSymbol = false;
351    uint32_t           startAddress = 0;
352    char               symbol[ MAX_LINE_LENGTH ];
353    char               terminator1;
354    char               terminator2;
355    objdumpLines_t     theInstructions;
356
357    // Obtain the objdump file.
358    if (!executableInformation->hasDynamicLibrary())
359      objdumpFile = getFile( executableInformation->getFileName() );
360    else
361      objdumpFile = getFile( executableInformation->getLibraryName() );
362
363    // Process all lines from the objdump file.
364    while ( 1 ) {
365
366      // Get the line.
367      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, objdumpFile );
368      if (cStatus == NULL) {
369
370        // If we are currently processing a symbol, finalize it.
371        if (processSymbol) {
372          finalizeSymbol(
373            executableInformation,
374            currentSymbol,
375            startAddress,
376            executableInformation->getLoadAddress() + offset,
377            theInstructions
378          );
379          fprintf(
380            stderr,
381            "WARNING: ObjdumpProcessor::load - analysis of symbol %s \n"
382            "         may be incorrect.  It was the last symbol in %s\n"
383            "         and the length of its last instruction is assumed "
384            "         to be one.\n",
385            currentSymbol.c_str(),
386            executableInformation->getFileName().c_str()
387          );
388        }
389        break;
390      }
391
392      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
393
394      lineInfo.line          = inputBuffer;
395      lineInfo.address       = 0xffffffff;
396      lineInfo.isInstruction = false;
397      lineInfo.isNop         = false;
398      lineInfo.nopSize       = 0;
399      lineInfo.isBranch      = false;
400
401      // Look for the start of a symbol's objdump and extract
402      // offset and symbol (i.e. offset <symbolname>:).
403      items = sscanf(
404        inputBuffer,
405        "%x <%[^>]>%c",
406        &offset, symbol, &terminator1
407      );
408
409      // If all items found, we are at the beginning of a symbol's objdump.
410      if ((items == 3) && (terminator1 == ':')) {
411
412        endAddress = executableInformation->getLoadAddress() + offset - 1;
413
414        // If we are currently processing a symbol, finalize it.
415        if (processSymbol) {
416          finalizeSymbol(
417            executableInformation,
418            currentSymbol,
419            startAddress,
420            endAddress,
421            theInstructions
422          );
423        }
424
425        // Start processing of a new symbol.
426        startAddress = 0;
427        currentSymbol = "";
428        processSymbol = false;
429        theInstructions.clear();
430
431        // See if the new symbol is one that we care about.
432        if (SymbolsToAnalyze->isDesired( symbol )) {
433          startAddress = executableInformation->getLoadAddress() + offset;
434          currentSymbol = symbol;
435          processSymbol = true;
436          theInstructions.push_back( lineInfo );
437        }
438      }
439
440      else if (processSymbol) {
441
442        // See if it is the dump of an instruction.
443        items = sscanf(
444          inputBuffer,
445          "%x%c\t%*[^\t]%c",
446          &instructionOffset, &terminator1, &terminator2
447        );
448
449        // If it looks like an instruction ...
450        if ((items == 3) && (terminator1 == ':') && (terminator2 == '\t')) {
451
452          // update the line's information, save it and ...
453          lineInfo.address =
454           executableInformation->getLoadAddress() + instructionOffset;
455          lineInfo.isInstruction = true;
456          lineInfo.isNop         = isNop( inputBuffer, lineInfo.nopSize );
457          lineInfo.isBranch      = isBranchLine( inputBuffer );
458        }
459
460        // Always save the line.
461        theInstructions.push_back( lineInfo );
462      }
463    }
464  }
465}
Note: See TracBrowser for help on using the repository browser.