~angelsl/ubuntu/wily/binutils/mips-cross

« back to all changes in this revision

Viewing changes to gprof/vax.c

  • Committer: angelsl
  • Date: 2015-11-03 15:54:40 UTC
  • Revision ID: angelsl-20151103155440-gbh6qo1olzlvaiqs
Import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1983, 1993, 2001
 
3
 *      The Regents of the University of California.  All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 * 3. Neither the name of the University nor the names of its contributors
 
14
 *    may be used to endorse or promote products derived from this software
 
15
 *    without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
27
 * SUCH DAMAGE.
 
28
 */
 
29
#include "gprof.h"
 
30
#include "search_list.h"
 
31
#include "source.h"
 
32
#include "symtab.h"
 
33
#include "cg_arcs.h"
 
34
#include "corefile.h"
 
35
#include "hist.h"
 
36
 
 
37
    /*
 
38
     *        opcode of the `calls' instruction
 
39
     */
 
40
#define CALLS   0xfb
 
41
 
 
42
    /*
 
43
     *        register for pc relative addressing
 
44
     */
 
45
#define PC      0xf
 
46
 
 
47
enum opermodes
 
48
  {
 
49
    literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
 
50
    bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
 
51
    immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
 
52
    longrel, longreldef
 
53
  };
 
54
typedef enum opermodes operandenum;
 
55
 
 
56
/* *INDENT-OFF* */
 
57
/* Here to document only.  We can't use this when cross compiling as
 
58
   the bitfield layout might not be the same as native.
 
59
 
 
60
   struct modebyte
 
61
     {
 
62
       unsigned int regfield:4;
 
63
       unsigned int modefield:4;
 
64
     };
 
65
*/
 
66
/* *INDENT-ON* */
 
67
 
 
68
/*
 
69
 * A symbol to be the child of indirect calls:
 
70
 */
 
71
static Sym indirectchild;
 
72
 
 
73
static operandenum vax_operandmode (unsigned char *);
 
74
static char *vax_operandname (operandenum);
 
75
static long vax_operandlength (unsigned char *);
 
76
static bfd_signed_vma vax_offset (unsigned char *);
 
77
void vax_find_call (Sym *, bfd_vma, bfd_vma);
 
78
 
 
79
static operandenum
 
80
vax_operandmode (unsigned char *modep)
 
81
{
 
82
  int usesreg = *modep & 0xf;
 
83
 
 
84
  switch ((*modep >> 4) & 0xf)
 
85
    {
 
86
    case 0:
 
87
    case 1:
 
88
    case 2:
 
89
    case 3:
 
90
      return literal;
 
91
    case 4:
 
92
      return indexed;
 
93
    case 5:
 
94
      return reg;
 
95
    case 6:
 
96
      return regdef;
 
97
    case 7:
 
98
      return autodec;
 
99
    case 8:
 
100
      return usesreg != PC ? autoinc : immediate;
 
101
    case 9:
 
102
      return usesreg != PC ? autoincdef : absolute;
 
103
    case 10:
 
104
      return usesreg != PC ? bytedisp : byterel;
 
105
    case 11:
 
106
      return usesreg != PC ? bytedispdef : bytereldef;
 
107
    case 12:
 
108
      return usesreg != PC ? worddisp : wordrel;
 
109
    case 13:
 
110
      return usesreg != PC ? worddispdef : wordreldef;
 
111
    case 14:
 
112
      return usesreg != PC ? longdisp : longrel;
 
113
    case 15:
 
114
      return usesreg != PC ? longdispdef : longreldef;
 
115
    }
 
116
  /* NOTREACHED */
 
117
  abort ();
 
118
}
 
119
 
 
120
static char *
 
121
vax_operandname (operandenum mode)
 
122
{
 
123
 
 
124
  switch (mode)
 
125
    {
 
126
    case literal:
 
127
      return "literal";
 
128
    case indexed:
 
129
      return "indexed";
 
130
    case reg:
 
131
      return "register";
 
132
    case regdef:
 
133
      return "register deferred";
 
134
    case autodec:
 
135
      return "autodecrement";
 
136
    case autoinc:
 
137
      return "autoincrement";
 
138
    case autoincdef:
 
139
      return "autoincrement deferred";
 
140
    case bytedisp:
 
141
      return "byte displacement";
 
142
    case bytedispdef:
 
143
      return "byte displacement deferred";
 
144
    case byterel:
 
145
      return "byte relative";
 
146
    case bytereldef:
 
147
      return "byte relative deferred";
 
148
    case worddisp:
 
149
      return "word displacement";
 
150
    case worddispdef:
 
151
      return "word displacement deferred";
 
152
    case wordrel:
 
153
      return "word relative";
 
154
    case wordreldef:
 
155
      return "word relative deferred";
 
156
    case immediate:
 
157
      return "immediate";
 
158
    case absolute:
 
159
      return "absolute";
 
160
    case longdisp:
 
161
      return "long displacement";
 
162
    case longdispdef:
 
163
      return "long displacement deferred";
 
164
    case longrel:
 
165
      return "long relative";
 
166
    case longreldef:
 
167
      return "long relative deferred";
 
168
    }
 
169
  /* NOTREACHED */
 
170
  abort ();
 
171
}
 
172
 
 
173
static long
 
174
vax_operandlength (unsigned char *modep)
 
175
{
 
176
 
 
177
  switch (vax_operandmode (modep))
 
178
    {
 
179
    case literal:
 
180
    case reg:
 
181
    case regdef:
 
182
    case autodec:
 
183
    case autoinc:
 
184
    case autoincdef:
 
185
      return 1;
 
186
    case bytedisp:
 
187
    case bytedispdef:
 
188
    case byterel:
 
189
    case bytereldef:
 
190
      return 2;
 
191
    case worddisp:
 
192
    case worddispdef:
 
193
    case wordrel:
 
194
    case wordreldef:
 
195
      return 3;
 
196
    case immediate:
 
197
    case absolute:
 
198
    case longdisp:
 
199
    case longdispdef:
 
200
    case longrel:
 
201
    case longreldef:
 
202
      return 5;
 
203
    case indexed:
 
204
      return 1 + vax_operandlength (modep + 1);
 
205
    }
 
206
  /* NOTREACHED */
 
207
  abort ();
 
208
}
 
209
 
 
210
static bfd_signed_vma
 
211
vax_offset (unsigned char *modep)
 
212
{
 
213
  operandenum mode = vax_operandmode (modep);
 
214
 
 
215
  ++modep;                              /* skip over the mode */
 
216
  switch (mode)
 
217
    {
 
218
    default:
 
219
      fprintf (stderr, "[reladdr] not relative address\n");
 
220
      return 0;
 
221
    case byterel:
 
222
      return 1 + bfd_get_signed_8 (core_bfd, modep);
 
223
    case wordrel:
 
224
      return 2 + bfd_get_signed_16 (core_bfd, modep);
 
225
    case longrel:
 
226
      return 4 + bfd_get_signed_32 (core_bfd, modep);
 
227
    }
 
228
}
 
229
 
 
230
 
 
231
void
 
232
vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
 
233
{
 
234
  unsigned char *instructp;
 
235
  long length;
 
236
  Sym *child;
 
237
  operandenum mode;
 
238
  operandenum firstmode;
 
239
  bfd_vma pc, destpc;
 
240
  static bfd_boolean inited = FALSE;
 
241
 
 
242
  if (!inited)
 
243
    {
 
244
      inited = TRUE;
 
245
      sym_init (&indirectchild);
 
246
      indirectchild.cg.prop.fract = 1.0;
 
247
      indirectchild.cg.cyc.head = &indirectchild;
 
248
    }
 
249
 
 
250
  DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
 
251
                          parent->name, (unsigned long) p_lowpc,
 
252
                          (unsigned long) p_highpc));
 
253
  for (pc = p_lowpc; pc < p_highpc; pc += length)
 
254
    {
 
255
      length = 1;
 
256
      instructp = ((unsigned char *) core_text_space
 
257
                   + pc - core_text_sect->vma);
 
258
      if ((*instructp & 0xff) == CALLS)
 
259
        {
 
260
          /*
 
261
           *    maybe a calls, better check it out.
 
262
           *      skip the count of the number of arguments.
 
263
           */
 
264
          DBG (CALLDEBUG,
 
265
               printf ("[findcall]\t0x%lx:calls", (unsigned long) pc));
 
266
          firstmode = vax_operandmode (instructp + length);
 
267
          switch (firstmode)
 
268
            {
 
269
            case literal:
 
270
            case immediate:
 
271
              break;
 
272
            default:
 
273
              goto botched;
 
274
            }
 
275
          length += vax_operandlength (instructp + length);
 
276
          mode = vax_operandmode (instructp + length);
 
277
          DBG (CALLDEBUG,
 
278
               printf ("\tfirst operand is %s", vax_operandname (firstmode));
 
279
               printf ("\tsecond operand is %s\n", vax_operandname (mode)));
 
280
          switch (mode)
 
281
            {
 
282
            case regdef:
 
283
            case bytedispdef:
 
284
            case worddispdef:
 
285
            case longdispdef:
 
286
            case bytereldef:
 
287
            case wordreldef:
 
288
            case longreldef:
 
289
              /*
 
290
               *    indirect call: call through pointer
 
291
               *      either  *d(r)   as a parameter or local
 
292
               *              (r)     as a return value
 
293
               *              *f      as a global pointer
 
294
               *      [are there others that we miss?,
 
295
               *       e.g. arrays of pointers to functions???]
 
296
               */
 
297
              arc_add (parent, &indirectchild, (unsigned long) 0);
 
298
              length += vax_operandlength (instructp + length);
 
299
              continue;
 
300
            case byterel:
 
301
            case wordrel:
 
302
            case longrel:
 
303
              /*
 
304
               *    regular pc relative addressing
 
305
               *      check that this is the address of
 
306
               *      a function.
 
307
               */
 
308
              destpc = pc + vax_offset (instructp + length);
 
309
              if (hist_check_address (destpc))
 
310
                {
 
311
                  child = sym_lookup (&symtab, destpc);
 
312
                  if (child)
 
313
                    {
 
314
                      DBG (CALLDEBUG,
 
315
                           printf ("[findcall]\tdestpc 0x%lx",
 
316
                                   (unsigned long) destpc);
 
317
                           printf (" child->name %s", child->name);
 
318
                           printf (" child->addr 0x%lx\n",
 
319
                                   (unsigned long) child->addr);
 
320
                        );
 
321
                      if (child->addr == destpc)
 
322
                        {
 
323
                          /*
 
324
                           *    a hit
 
325
                           */
 
326
                          arc_add (parent, child, (unsigned long) 0);
 
327
                          length += vax_operandlength (instructp + length);
 
328
                          continue;
 
329
                        }
 
330
                    }
 
331
                  goto botched;
 
332
                }
 
333
              /*
 
334
               *    else:
 
335
               *      it looked like a calls,
 
336
               *      but it wasn't to anywhere.
 
337
               */
 
338
              goto botched;
 
339
            default:
 
340
            botched:
 
341
              /*
 
342
               *    something funny going on.
 
343
               */
 
344
              DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
 
345
              length = 1;
 
346
              continue;
 
347
            }
 
348
        }
 
349
    }
 
350
}