source: rtems-testing/covoar/ObjdumpProcessor.cc @ 2b85270

4.11
Last change on this file since 2b85270 was 2b85270, checked in by Jennifer Averett <Jennifer.Averett@…>, on May 25, 2010 at 6:16:48 PM

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

  • Property mode set to 100644
File size: 15.1 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         buffer[ 512 ];
136    char*        cStatus;
137    uint32_t     offset;
138
139    // This method should only be call for a dynamic library.
140    if (!theExecutable->hasDynamicLibrary())
141      return 0;
142
143#if 0
144    static FILE* gdbCommands = NULL;
145    int          items;
146    uint32_t     loadAddress;
147    FILE*        objdumpFile = NULL;
148    int          status;
149    char         terminator;
150
151
152    //
153    // Invoke gdb to determine the physical load address
154    // of the .text section.
155    //
156
157    // Create a gdb input commands file.
158    if (!gdbCommands) {
159
160      gdbCommands = fopen( "gdbCommands", "w" );
161      if (!gdbCommands) {
162        fprintf(
163          stderr,
164          "ERROR: ObjdumpProcessor::determineLoadAddress - "
165          "unable to create gdbCommands\n"
166        );
167        exit( -1 );
168      }
169
170      fprintf(
171        gdbCommands,
172        "set pagination off\n"
173        "b main\n"
174        "r\n"
175        "info sharedlibrary\n"
176        "quit\n"
177      );
178
179      fclose( gdbCommands );
180    }
181
182    // Invoke gdb.
183    sprintf(
184      buffer,
185      "gdb -x gdbCommands %s | grep %s | cut -d ' ' -f1 > %s",
186      (theExecutable->getFileName()).c_str(),
187      (theExecutable->getLibraryName()).c_str(),
188      "library_addr.tmp"
189    );
190
191    status = system( buffer );
192    if (status) {
193      fprintf(
194        stderr,
195        "ERROR: ObjdumpProcessor::determineLoadAddress - "
196        "command (%s) failed with %d\n",
197        buffer,
198        status
199      );
200      exit( -1 );
201    }
202
203    // Read load address.
204    loadAddressFile = fopen( "library_addr.tmp", "r" );
205    if (!loadAddressFile) {
206      fprintf(
207        stderr,
208        "ERROR: ObjdumpProcessor::determineLoadAddress - "
209        "unable to open library_addr.tmp\n"
210      );
211      exit( -1 );
212    }
213
214    cStatus = fgets( buffer, 512, loadAddressFile );
215    items = sscanf(
216      buffer, "%x", &loadAddress
217    );
218
219    fclose( loadAddressFile );
220    unlink( "library_addr.tmp" );
221
222    //
223    // Partially process an objdump of the library to determine the first
224    // symbol's offset from the physical load address of the library.
225    //
226
227    // Obtain the objdump file.
228    objdumpFile = getFile( theExecutable->getLibraryName() );
229
230    // Process the objdump file.
231    while ( 1 ) {
232
233      // Get a line.
234      cStatus = fgets( buffer, 512, objdumpFile );
235      if (cStatus == NULL) {
236        fprintf(
237          stderr,
238          "ERROR: ObjdumpProcessor::determineLoadAddress - "
239          "no symbol found in objdump file\n"
240        );
241        exit( -1 );
242      }
243
244      // Look for the start of a symbol's objdump and extract
245      // address and symbol (i.e. address <symbolname>:).
246      items = sscanf(
247        buffer,
248        "%x <%*[^>]>%c",
249        &offset, &terminator
250      );
251
252      // If all items found, we have found the first symbol's objdump.
253      if ((items == 2) && (terminator == ':')) {
254        break;
255      }
256    }
257
258    return (loadAddress - offset);
259# endif
260#if 1
261    std::string dlinfoName = theExecutable->getFileName();
262    uint32_t address;
263    char inLibName[128];
264    std::string Library = theExecutable->getLibraryName();
265
266    dlinfoName += ".dlinfo";
267    // Read load address.
268    loadAddressFile = fopen( dlinfoName.c_str(), "r" );
269    if (!loadAddressFile) {
270      fprintf( stderr, METHOD "unable to open %s\n", dlinfoName.c_str() );
271      exit( -1 );
272    }
273
274    // Process the dlinfo file.
275    while ( 1 ) {
276
277      // Get a line.
278      cStatus = fgets( buffer, 512, loadAddressFile );
279      if (cStatus == NULL) {
280        fprintf(
281          stderr,
282          METHOD "library %s not found in %s\n",
283          Library.c_str(),
284          dlinfoName.c_str()
285        );
286        fclose( loadAddressFile );
287        exit( -1 );
288      }
289      sscanf( buffer, "%s %x", inLibName, &offset );
290      std::string tmp = inLibName;
291      if ( tmp.find( Library ) != tmp.npos ) {
292        // fprintf( stderr, "%s - 0x%08x\n", inLibName, offset );
293        address = offset;
294        break;
295      }
296    }
297
298    fclose( loadAddressFile );
299    return address;
300#endif
301    #undef METHOD
302  }
303
304  bool ObjdumpProcessor::IsBranch(
305    const char *instruction
306  )
307  {
308    if ( !TargetInfo ) {
309      fprintf(
310        stderr,
311        "ERROR: ObjdumpProcessor::IsBranch - unknown architecture\n"
312      );
313      assert(0);
314      return false;
315    }
316
317    return TargetInfo->isBranch( instruction );
318  }
319
320  bool ObjdumpProcessor::isBranchLine(
321    const char* const line
322  )
323  {
324    if ( !TargetInfo ) {
325      fprintf(
326        stderr,
327        "ERROR: ObjdumpProcessor::isBranchLine - unknown architecture\n"
328      );
329      assert(0);
330      return false;
331    }
332
333    return  TargetInfo->isBranchLine( line );
334  }
335
336  bool ObjdumpProcessor::isNop(
337    const char* const line,
338    int&              size
339  )
340  {
341    if ( !TargetInfo ){
342      fprintf(
343        stderr,
344        "ERROR: ObjdumpProcessor::isNop - unknown architecture\n"
345      );
346      assert(0);
347      return false;
348    }
349
350    return TargetInfo->isNopLine( line, size );
351  }
352
353  FILE* ObjdumpProcessor::getFile( std::string fileName )
354  {
355    char               dumpFile[128];
356    FILE*              objdumpFile;
357    char               buffer[ 512 ];
358    int                status;
359
360    sprintf( dumpFile, "%s.dmp", fileName.c_str() );
361     
362    // Generate the objdump.
363    if (FileIsNewer( fileName.c_str(), dumpFile )) {
364      sprintf(
365        buffer,
366        "%s -Cda --section=.text --source %s | sed -e \'s/ *$//\' >%s",
367        TargetInfo->getObjdump(),
368        fileName.c_str(),
369        dumpFile
370      );
371
372      status = system( buffer );
373      if (status) {
374        fprintf(
375          stderr,
376          "ERROR: ObjdumpProcessor::getFile - command (%s) failed with %d\n",
377          buffer,
378          status
379        );
380        exit( -1 );
381      }
382    }
383
384    // Open the objdump file.
385    objdumpFile = fopen( dumpFile, "r" );
386    if (!objdumpFile) {
387      fprintf(
388        stderr,
389        "ERROR: ObjdumpProcessor::getFile - unable to open %s\n",
390        dumpFile
391      );
392      exit(-1);
393    }
394
395    return objdumpFile;
396  }
397
398  uint32_t ObjdumpProcessor::getAddressAfter( uint32_t address )
399  {
400    objdumpFile_t::iterator itr;
401
402    itr = find ( objdumpList.begin(), objdumpList.end(), address );
403    if (itr == objdumpList.end()) {
404      return 0;
405    }
406   
407    itr++;
408    if (itr == objdumpList.end()) {
409      return 0;
410    }
411
412    return (*itr);
413
414  }
415
416  void ObjdumpProcessor::loadAddressTable (
417    ExecutableInfo* const executableInformation
418  )
419  {
420    char               buffer[ 512 ];
421    char*              cStatus;
422    int                items;
423    FILE*              objdumpFile;
424    uint32_t           offset;
425    char               terminator;
426
427    // Obtain the objdump file.
428    if (!executableInformation->hasDynamicLibrary())
429      objdumpFile = getFile( executableInformation->getFileName() );
430    else
431      objdumpFile = getFile( executableInformation->getLibraryName() );
432
433    // Process all lines from the objdump file.
434    while ( 1 ) {
435
436      // Get the line.
437      cStatus = fgets( buffer, 512, objdumpFile );
438      if (cStatus == NULL) {
439        break;
440      }
441      buffer[ strlen(buffer) - 1] = '\0';
442
443      // See if it is the dump of an instruction.
444      items = sscanf(
445        buffer,
446        "%x%c",
447        &offset, &terminator
448      );
449
450      // If it looks like an instruction ...
451      if ((items == 2) && (terminator == ':')){
452        objdumpList.push_back(
453          executableInformation->getLoadAddress() + offset
454        );
455      }
456    }
457  }
458
459  void ObjdumpProcessor::load(
460    ExecutableInfo* const executableInformation
461  )
462  {
463    char               buffer[ 512 ];
464    char*              cStatus;
465    std::string        currentSymbol = "";
466    uint32_t           endAddress;
467    uint32_t           instructionOffset;
468    int                items;
469    objdumpLine_t      lineInfo;
470    FILE*              objdumpFile;
471    uint32_t           offset;
472    bool               processSymbol = false;
473    uint32_t           startAddress = 0;
474    char               symbol[ 100 ];
475    char               terminator1;
476    char               terminator2;
477    objdumpLines_t     theInstructions;
478
479    // Obtain the objdump file.
480    if (!executableInformation->hasDynamicLibrary())
481      objdumpFile = getFile( executableInformation->getFileName() );
482    else
483      objdumpFile = getFile( executableInformation->getLibraryName() );
484
485    // Process all lines from the objdump file.
486    while ( 1 ) {
487
488      // Get the line.
489      cStatus = fgets( buffer, 512, objdumpFile );
490      if (cStatus == NULL) {
491
492        // If we are currently processing a symbol, finalize it.
493        if (processSymbol) {
494          finalizeSymbol(
495            executableInformation,
496            currentSymbol,
497            startAddress,
498            executableInformation->getLoadAddress() + offset,
499            theInstructions
500          );
501          fprintf(
502            stderr,
503            "WARNING: ObjdumpProcessor::load - analysis of symbol %s \n"
504            "         may be incorrect.  It was the last symbol in %s\n"
505            "         and the length of its last instruction is assumed "
506            "         to be one.\n",
507            currentSymbol.c_str(),
508            executableInformation->getFileName().c_str()
509          );
510        }
511        break;
512      }
513
514      buffer[ strlen(buffer) - 1] = '\0';
515
516      lineInfo.line          = buffer;
517      lineInfo.address       = 0xffffffff;
518      lineInfo.isInstruction = false;
519      lineInfo.isNop         = false;
520      lineInfo.nopSize       = 0;
521      lineInfo.isBranch      = false;
522
523      // Look for the start of a symbol's objdump and extract
524      // offset and symbol (i.e. offset <symbolname>:).
525      items = sscanf(
526        buffer,
527        "%x <%[^>]>%c",
528        &offset, symbol, &terminator1
529      );
530
531      // If all items found, we are at the beginning of a symbol's objdump.
532      if ((items == 3) && (terminator1 == ':')) {
533
534        endAddress = executableInformation->getLoadAddress() + offset - 1;
535
536        // If we are currently processing a symbol, finalize it.
537        if (processSymbol) {
538          finalizeSymbol(
539            executableInformation,
540            currentSymbol,
541            startAddress,
542            endAddress,
543            theInstructions
544          );
545        }
546
547        // Start processing of a new symbol.
548        startAddress = 0;
549        currentSymbol = "";
550        processSymbol = false;
551        theInstructions.clear();
552
553        // See if the new symbol is one that we care about.
554        if (SymbolsToAnalyze->isDesired( symbol )) {
555          startAddress = executableInformation->getLoadAddress() + offset;
556          currentSymbol = symbol;
557          processSymbol = true;
558          theInstructions.push_back( lineInfo );
559        }
560      }
561
562      else if (processSymbol) {
563
564        // See if it is the dump of an instruction.
565        items = sscanf(
566          buffer,
567          "%x%c\t%*[^\t]%c",
568          &instructionOffset, &terminator1, &terminator2
569        );
570
571        // If it looks like an instruction ...
572        if ((items == 3) && (terminator1 == ':') && (terminator2 == '\t')) {
573
574          // update the line's information, save it and ...
575          lineInfo.address =
576           executableInformation->getLoadAddress() + instructionOffset;
577          lineInfo.isInstruction = true;
578          lineInfo.isNop         = isNop( buffer, lineInfo.nopSize );
579          lineInfo.isBranch      = isBranchLine( buffer );
580        }
581
582        // Always save the line.
583        theInstructions.push_back( lineInfo );
584      }
585    }
586  }
587}
Note: See TracBrowser for help on using the repository browser.