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