source: rtems-testing/rtems-coverage/ObjdumpProcessor.cc @ dc795fa

4.11
Last change on this file since dc795fa was dc795fa, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 29, 2009 at 7:05:48 PM

2009-09-29 Joel Sherrill <joel.sherrill@…>

  • ObjdumpProcessor?.cc, do_coverage, run_coverage: Add initial powerpc/qemuppc support.
  • Property mode set to 100644
File size: 7.3 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 "ObjdumpProcessor.h"
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <ctype.h>
18#include "app_common.h"
19#include <assert.h>
20
21namespace Coverage {
22
23  class ObjdumpLine {
24 
25  public:
26     ObjdumpLine()
27     {
28       isInstruction = false;
29       isNop         = false;
30       nopSize       = 0;
31       address       = 0xffffffff;
32     } 
33
34     ~ObjdumpLine()
35     {
36     } 
37
38     std::string line;
39     bool        isInstruction;
40     bool        isNop;
41     int         nopSize;
42     uint32_t    address;
43  };
44
45  /*
46   * ObjdumpProcessor Class
47   */
48  ObjdumpProcessor::ObjdumpProcessor()
49  {
50  }
51
52  ObjdumpProcessor::~ObjdumpProcessor()
53  {
54  }
55
56  bool ObjdumpProcessor::isInstruction(
57    const char *line
58  )
59  {
60    int i; 
61    bool allBlank = true;
62   
63    for ( i=0 ; i<8 ; i++ ) {
64      if ( isxdigit( line[i] ) ) {
65        allBlank = false;
66        continue;
67      }
68      if ( isspace( line[i] ) ) {
69        continue;
70      }
71      return false;
72    }
73
74    if ( allBlank )
75      return false;
76
77    if ( line[8] != ':' )
78      return false;
79
80    return true;
81  }
82
83  bool ObjdumpProcessor::isNop(
84    const char *line,
85    int        &size
86  )
87  {
88    bool        isNop = false;
89    const char *target = Tools->getTarget();
90
91    if ( !isInstruction(line) ) {
92      size = 0;
93      return false;
94    }
95
96    size = 0;
97
98    // common patterns
99    if ( !strcmp( &line[strlen(line)-3], "nop") )
100      isNop = true;
101
102   
103    // now check target specific patterns and return proper size if "nop"
104
105    // Check ARM nops
106    if ( !strncmp( target, "arm", 3 ) ) {
107      if ( isNop ) {
108        size = 4; 
109        return true;
110      }
111   
112      // On ARM, there are literal tables at the end of methods.
113      // We need to avoid them.
114      if ( !strncmp( &line[strlen(line)-10], ".byte", 5) ) {
115        size = 1;
116        return true;
117      }
118      if ( !strncmp( &line[strlen(line)-13], ".short", 6) ) {
119        size = 2;
120        return true;
121      }
122      if ( !strncmp( &line[strlen(line)-16], ".word", 5) ) {
123        size = 4;
124        return true;
125      }
126
127      return false;
128    }
129
130    // Check i386 nops
131    if ( !strncmp( target, "i386", 4 ) ) {
132      if ( isNop ) {
133        size = 1; 
134        return true;
135      }
136      // i386 has some two and three byte nops
137      if ( !strncmp( &line[strlen(line)-14], "xchg   %ax,%ax", 14) ) {
138        size = 2;
139        return true;
140      }
141      if ( !strncmp( &line[strlen(line)-16], "xor    %eax,%eax", 16) ) {
142        size = 2;
143        return true;
144      }
145      if ( !strncmp( &line[strlen(line)-16], "xor    %ebx,%ebx", 16) ) {
146        size = 2;
147        return true;
148      }
149      if ( !strncmp( &line[strlen(line)-21], "lea    0x0(%esi),%esi", 21) ) {
150        size = 3;
151        return true;
152      }
153
154      return false;
155    }
156
157    // Check M68K/Coldfire nops
158    if ( !strncmp( target, "m68k", 4 ) ) {
159      if ( isNop ) {
160        size = 2; 
161        return true;
162      }
163
164      #define GNU_LD_FILLS_ALIGNMENT_WITH_RTS
165      #if defined(GNU_LD_FILLS_ALIGNMENT_WITH_RTS)
166        // Until binutils 2.20, binutils would fill with rts not nop
167        if ( !strcmp( &line[strlen(line)-3], "rts") ) {
168          size = 4; 
169          return true;
170        } 
171      #endif
172
173      return false;
174    }
175
176    // Check i386 nops
177    if ( !strncmp( target, "powerpc", 7 ) ) {
178      if ( isNop ) {
179        size = 4; 
180        return true;
181      }
182
183      return false;
184    }
185
186    // Check SPARC nops
187    if ( !strncmp( target, "sparc", 5 ) ) {
188      if ( isNop ) {
189        size = 4; 
190        return true;
191      }
192
193      if ( !strcmp( &line[strlen(line)-7], "unknown") ) {
194        size = 4; 
195        return true;
196      } 
197
198      return false;
199    }
200
201    fprintf( stderr, "ERROR!!! %s is not a known architecture!!!\n", target );
202    fprintf( stderr, "HOW LARGE IS NOP ON THIS ARCHITECTURE? -- fix me\n" );
203    assert(0);
204    // ASSUME: ARM dump uses nop instruction. Really "mov r0,r0"
205    return false;
206  }
207
208  bool ObjdumpProcessor::initialize(
209    const char      *executable,
210    CoverageMapBase *coverage
211  )
212  {
213    FILE *objdumpFile;
214    char *cStatus;
215    char  buffer[512];
216    int   i;
217
218    /*
219     * Generate the objdump
220     */
221    sprintf( buffer, "%s -da --source %s | sed -e \'s/ *$//\' >objdump.tmp",
222      Tools->getObjdump(), executable );
223
224    if ( system( buffer ) ) {
225      fprintf( stderr, "objdump command (%s) failed\n", buffer );
226      exit( -1 );
227    }
228
229    /*
230     *  read the file and update the coverage map passed in
231     */
232
233    objdumpFile = fopen( "objdump.tmp", "r" );
234    if ( !objdumpFile ) {
235      fprintf(
236        stderr,
237        "ObjdumpProcessor::ProcessFile - unable to open %s\n",
238        "objdump.tmp"
239      );
240      exit(-1);
241    }
242
243    /*
244     *  How many bytes is a nop?
245     */
246
247    while ( 1 ) {
248      ObjdumpLine contents;
249      cStatus = fgets( buffer, 512, objdumpFile );
250      if ( cStatus == NULL ) {
251        break;
252      }
253
254      buffer[ strlen(buffer) - 1] = '\0';
255
256      contents.line          = buffer;
257      contents.isInstruction = false;
258      contents.isNop         = false;
259      contents.address       = 0xffffffff;
260
261      // fprintf( stderr, "%08x : ", baseAddress );
262      contents.isInstruction = isInstruction( buffer );
263
264      if ( contents.isInstruction ) {
265        unsigned long l;
266        uint32_t baseAddress;
267        sscanf( buffer, "%lx:", &l );
268        baseAddress = l;
269        contents.address = baseAddress;
270
271        contents.isNop = isNop( buffer, contents.nopSize );
272        if ( contents.isNop ) {
273          // check the byte immediately before and after the nop
274          // if either was executed, then mark NOP as executed. Otherwise,
275          // we do not want to split the unexecuted range.
276          if ( coverage->wasExecuted( baseAddress - 1 ) ||
277               coverage->wasExecuted( baseAddress + contents.nopSize ) ) {
278            for ( i=0 ; i < contents.nopSize ; i++ )
279              coverage->setWasExecuted( baseAddress + i );
280          }
281        }
282      }
283
284      Contents.push_back( contents );
285    }
286    fclose( objdumpFile );
287
288    // Remove temporary file
289    (void) system( "rm -f objdump.tmp" );
290    return true;
291  }
292
293  bool ObjdumpProcessor::writeAnnotated(
294    CoverageMapBase *coverage,
295    uint32_t         low,
296    uint32_t         high,
297    const char      *annotated
298  )
299  {
300    FILE *annotatedFile;
301    std::list<ObjdumpLine>::iterator it;
302
303    if ( !annotated )
304      return false;
305
306    annotatedFile = fopen( annotated, "w" );
307    if ( !annotatedFile ) {
308      fprintf(
309        stderr,
310        "ObjdumpProcessor::writeAnnotated - unable to open %s\n",
311        annotated
312      );
313      exit(-1);
314    }
315
316    for (it =  Contents.begin() ;
317         it != Contents.end() ;
318         it++ ) {
319      bool executed = true;  // assume we do not mark it
320
321      if ( it->isInstruction &&
322           it->address >= low && it->address <= high &&
323           !coverage->wasExecuted( it->address ) )
324        executed = false;
325
326      if ( executed )
327        fprintf(annotatedFile, "%s\n", it->line.c_str() );
328      else
329        fprintf(annotatedFile, "%-76s\t<== NOT EXECUTED\n", it->line.c_str() );
330     // bool        isNop;
331     // uint32_t    address;
332    }
333    return true;
334  }
335}
Note: See TracBrowser for help on using the repository browser.