Lots of changes from David Mosberger-Tang; see ChangeLog and NOTES for details:
[platform/upstream/binutils.git] / gprof / alpha.c
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that: (1) source distributions retain this entire copyright
7  * notice and comment, and (2) distributions including binaries display
8  * the following acknowledgement:  ``This product includes software
9  * developed by the University of California, Berkeley and its contributors''
10  * in the documentation or other materials provided with the distribution
11  * and in all advertising materials mentioning features or use of this
12  * software. Neither the name of the University nor the names of its
13  * contributors may be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 #include "gprof.h"
20 #include "cg_arcs.h"
21 #include "core.h"
22 #include "hist.h"
23 #include "symtab.h"
24
25 /*
26  * Opcodes of the call instructions:
27  */
28 #define OP_Jxx  0x1a
29 #define OP_BSR  0x34
30
31 #define Jxx_FUNC_JMP            0
32 #define Jxx_FUNC_JSR            1
33 #define Jxx_FUNC_RET            2
34 #define Jxx_FUNC_JSR_COROUTINE  3
35
36 typedef union {
37     struct {
38         unsigned other   : 26;
39         unsigned op_code :  6;
40     } a;                                /* any format */
41     struct {
42         signed   disp    : 21;
43         unsigned ra      :  5;
44         unsigned op_code :  6;
45     } b;                                /* branch format */
46     struct {
47         signed   hint    : 14;
48         unsigned func    :  2;
49         unsigned rb      :  5;
50         unsigned ra      :  5;
51         unsigned op_code :  6;
52     } j;                                /* jump format */
53 } Instruction;
54
55 static Sym indirect_child;
56
57
58 /*
59  * On the Alpha we can only detect PC relative calls, which are
60  * usually generated for calls to functions within the same
61  * object file only.  This is still better than nothing, however.
62  * (In particular it should be possible to find functions that
63  *  potentially call integer division routines, for example.)
64  */
65 void
66 find_call(parent, p_lowpc, p_highpc)
67      Sym *parent;
68      bfd_vma p_lowpc;
69      bfd_vma p_highpc;
70 {
71     static bfd_vma delta = 0;
72     bfd_vma dest_pc;
73     Instruction *pc;
74     Sym *child;
75     
76     if (!delta) {
77         delta = (bfd_vma) core_text_space - core_text_sect->vma;
78
79         sym_init(&indirect_child);
80         indirect_child.name = "<indirect child>";
81         indirect_child.cg.prop.fract = 1.0;
82         indirect_child.cg.cyc.head = &indirect_child;
83     } /* if */
84     
85     if (!core_text_space) {
86         return;
87     } /* if */
88     if (p_lowpc < s_lowpc) {
89         p_lowpc = s_lowpc;
90     } /* if */
91     if (p_highpc > s_highpc) {
92         p_highpc = s_highpc;
93     } /* if */
94     DBG(CALLDEBUG, printf("[find_call] %s: 0x%lx to 0x%lx\n",
95                           parent->name, p_lowpc, p_highpc));
96     for (pc = (Instruction*)(p_lowpc + delta);
97          pc < (Instruction*)(p_highpc + delta);
98          ++pc)
99     {
100         switch (pc->a.op_code) {
101           case OP_Jxx:
102             /*
103              * There is no simple and reliable way to determine the
104              * target of a jsr (the hint bits help, but there aren't
105              * enough bits to get a satisfactory hit rate).  Instead,
106              * for any indirect jump we simply add an arc from PARENT
107              * to INDIRECT_CHILD---that way the user it at least able
108              * to see that there are other calls as well.
109              */
110             if (pc->j.func == Jxx_FUNC_JSR
111                 || pc->j.func == Jxx_FUNC_JSR_COROUTINE)
112             {
113                 DBG(CALLDEBUG,
114                     printf("[find_call] 0x%lx: jsr%s <indirect_child>\n",
115                            (bfd_vma) pc - delta,
116                            pc->j.func == Jxx_FUNC_JSR ? "" : "_coroutine"));
117                 arc_add(parent, &indirect_child, 0);
118             } /* if */
119             break;
120
121           case OP_BSR:
122             DBG(CALLDEBUG,
123                 printf("[find_call] 0x%lx: bsr", (bfd_vma) pc - delta));
124             /*
125              * Regular PC relative addressing.  Check that this is the
126              * address of a function.  The linker sometimes redirects
127              * the entry point by 8 bytes to skip loading the global
128              * pointer, so we all for either address:
129              */
130             dest_pc = ((bfd_vma) (pc + 1 + pc->b.disp)) - delta;
131             if (dest_pc >= s_lowpc && dest_pc <= s_highpc) {
132                 child = sym_lookup(&symtab, dest_pc);
133                 DBG(CALLDEBUG,
134                     printf(" 0x%lx\t; name=%s, addr=0x%lx",
135                            dest_pc, child->name, child->addr));
136                 if (child->addr == dest_pc || child->addr == dest_pc - 8) {
137                     DBG(CALLDEBUG, printf("\n"));
138                     /* a hit:  */
139                     arc_add(parent, child, 0);
140                     continue;
141                 } /* if */
142             } /* if */
143             /*
144              * Something funny going on.
145              */
146             DBG(CALLDEBUG, printf("\tbut it's a botch\n"));
147             break;
148
149           default:
150             break;
151         } /* switch */
152     } /* for */
153 } /* find_call */
154                         /*** end of alpha.c ***/