1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate #include "gprof.h"
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gate /*
32*0Sstevel@tonic-gate * a namelist entry to be the child of indirect calls
33*0Sstevel@tonic-gate */
34*0Sstevel@tonic-gate nltype indirectchild = {
35*0Sstevel@tonic-gate "(*)", /* the name */
36*0Sstevel@tonic-gate &modules, /* module [-c only for prog txtspace] */
37*0Sstevel@tonic-gate (pctype)0, /* the pc entry point */
38*0Sstevel@tonic-gate (pctype)0, /* aligned entry point */
39*0Sstevel@tonic-gate (unsigned long)0, /* function size */
40*0Sstevel@tonic-gate (unsigned char)0, /* symbol information */
41*0Sstevel@tonic-gate (size_t)0, /* ticks in this routine */
42*0Sstevel@tonic-gate (double)0.0, /* ticks in this routine (as double) */
43*0Sstevel@tonic-gate (double)0.0, /* cumulative ticks in children */
44*0Sstevel@tonic-gate (long)0, /* how many times called */
45*0Sstevel@tonic-gate (long)0, /* how many calls to self */
46*0Sstevel@tonic-gate (double)1.0, /* propagation fraction */
47*0Sstevel@tonic-gate (double)0.0, /* self propagation time */
48*0Sstevel@tonic-gate (double)0.0, /* child propagation time */
49*0Sstevel@tonic-gate (bool)0, /* print flag */
50*0Sstevel@tonic-gate (int)0, /* index in the graph list */
51*0Sstevel@tonic-gate (int)0, /* graph call chain top-sort order */
52*0Sstevel@tonic-gate (int)0, /* internal number of cycle on */
53*0Sstevel@tonic-gate (struct nl *)&indirectchild, /* pointer to head of cycle */
54*0Sstevel@tonic-gate (struct nl *)0, /* pointer to next member of cycle */
55*0Sstevel@tonic-gate (arctype *)0, /* list of caller arcs */
56*0Sstevel@tonic-gate (arctype *)0, /* list of callee arcs */
57*0Sstevel@tonic-gate (unsigned long)0 /* number of callers */
58*0Sstevel@tonic-gate };
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate void
findcalls(nltype * parentp,pctype p_lowpc,pctype p_highpc)61*0Sstevel@tonic-gate findcalls(nltype *parentp, pctype p_lowpc, pctype p_highpc)
62*0Sstevel@tonic-gate {
63*0Sstevel@tonic-gate unsigned long instructp;
64*0Sstevel@tonic-gate sztype length;
65*0Sstevel@tonic-gate nltype *childp;
66*0Sstevel@tonic-gate pctype destpc;
67*0Sstevel@tonic-gate
68*0Sstevel@tonic-gate if (textspace == 0) {
69*0Sstevel@tonic-gate return;
70*0Sstevel@tonic-gate }
71*0Sstevel@tonic-gate if (p_lowpc > s_highpc)
72*0Sstevel@tonic-gate return;
73*0Sstevel@tonic-gate if (p_highpc < s_lowpc)
74*0Sstevel@tonic-gate return;
75*0Sstevel@tonic-gate if (p_lowpc < s_lowpc)
76*0Sstevel@tonic-gate p_lowpc = s_lowpc;
77*0Sstevel@tonic-gate if (p_highpc > s_highpc)
78*0Sstevel@tonic-gate p_highpc = s_highpc;
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gate #ifdef DEBUG
81*0Sstevel@tonic-gate if (debug & CALLSDEBUG) {
82*0Sstevel@tonic-gate printf("[findcalls] %s: 0x%llx to 0x%llx\n",
83*0Sstevel@tonic-gate parentp->name, p_lowpc, p_highpc);
84*0Sstevel@tonic-gate }
85*0Sstevel@tonic-gate #endif /* DEBUG */
86*0Sstevel@tonic-gate
87*0Sstevel@tonic-gate length = 4;
88*0Sstevel@tonic-gate for (instructp = (uintptr_t)textspace + p_lowpc - TORIGIN;
89*0Sstevel@tonic-gate instructp < (uintptr_t)textspace + p_highpc - TORIGIN;
90*0Sstevel@tonic-gate instructp += length) {
91*0Sstevel@tonic-gate
92*0Sstevel@tonic-gate switch (OP(instructp)) {
93*0Sstevel@tonic-gate case CALL:
94*0Sstevel@tonic-gate /*
95*0Sstevel@tonic-gate * May be a call, better check it out.
96*0Sstevel@tonic-gate */
97*0Sstevel@tonic-gate #ifdef DEBUG
98*0Sstevel@tonic-gate if (debug & CALLSDEBUG) {
99*0Sstevel@tonic-gate printf("[findcalls]\t0x%x:call\n",
100*0Sstevel@tonic-gate PC_VAL(instructp));
101*0Sstevel@tonic-gate }
102*0Sstevel@tonic-gate #endif /* DEBUG */
103*0Sstevel@tonic-gate destpc = (DISP30(instructp) << 2) + PC_VAL(instructp);
104*0Sstevel@tonic-gate break;
105*0Sstevel@tonic-gate
106*0Sstevel@tonic-gate case FMT3_0x10:
107*0Sstevel@tonic-gate if (OP3(instructp) != JMPL)
108*0Sstevel@tonic-gate continue;
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate #ifdef DEBUG
111*0Sstevel@tonic-gate if (debug & CALLSDEBUG)
112*0Sstevel@tonic-gate printf("[findcalls]\t0x%x:jmpl",
113*0Sstevel@tonic-gate PC_VAL(instructp));
114*0Sstevel@tonic-gate #endif /* DEBUG */
115*0Sstevel@tonic-gate if (RD(instructp) == R_G0) {
116*0Sstevel@tonic-gate #ifdef DEBUG
117*0Sstevel@tonic-gate if (debug & CALLSDEBUG) {
118*0Sstevel@tonic-gate switch (RS1(instructp)) {
119*0Sstevel@tonic-gate case R_O7:
120*0Sstevel@tonic-gate printf("\tprobably a RETL\n");
121*0Sstevel@tonic-gate break;
122*0Sstevel@tonic-gate case R_I7:
123*0Sstevel@tonic-gate printf("\tprobably a RET\n");
124*0Sstevel@tonic-gate break;
125*0Sstevel@tonic-gate default:
126*0Sstevel@tonic-gate printf(", but not a call: "
127*0Sstevel@tonic-gate "linked to g0\n");
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate #endif /* DEBUG */
131*0Sstevel@tonic-gate continue;
132*0Sstevel@tonic-gate }
133*0Sstevel@tonic-gate #ifdef DEBUG
134*0Sstevel@tonic-gate if (debug & CALLSDEBUG) {
135*0Sstevel@tonic-gate printf("\toperands are DST = R%d,\tSRC = R%d",
136*0Sstevel@tonic-gate RD(instructp), RS1(instructp));
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate #endif /* DEBUG */
139*0Sstevel@tonic-gate if (IMMED(instructp)) {
140*0Sstevel@tonic-gate #ifdef DEBUG
141*0Sstevel@tonic-gate if (debug & CALLSDEBUG) {
142*0Sstevel@tonic-gate if (SIMM13(instructp) < 0) {
143*0Sstevel@tonic-gate printf(" - 0x%x\n",
144*0Sstevel@tonic-gate -(SIMM13(instructp)));
145*0Sstevel@tonic-gate } else {
146*0Sstevel@tonic-gate printf(" + 0x%x\n",
147*0Sstevel@tonic-gate SIMM13(instructp));
148*0Sstevel@tonic-gate }
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate #endif /* DEBUG */
151*0Sstevel@tonic-gate switch (RS1(instructp)) {
152*0Sstevel@tonic-gate case R_G0:
153*0Sstevel@tonic-gate /*
154*0Sstevel@tonic-gate * absolute address, simm 13
155*0Sstevel@tonic-gate */
156*0Sstevel@tonic-gate destpc = SIMM13(instructp);
157*0Sstevel@tonic-gate break;
158*0Sstevel@tonic-gate default:
159*0Sstevel@tonic-gate /*
160*0Sstevel@tonic-gate * indirect call
161*0Sstevel@tonic-gate */
162*0Sstevel@tonic-gate addarc(parentp, &indirectchild, 0);
163*0Sstevel@tonic-gate continue;
164*0Sstevel@tonic-gate }
165*0Sstevel@tonic-gate } else {
166*0Sstevel@tonic-gate /*
167*0Sstevel@tonic-gate * two register sources, all cases are indirect
168*0Sstevel@tonic-gate */
169*0Sstevel@tonic-gate #ifdef DEBUG
170*0Sstevel@tonic-gate if (debug & CALLSDEBUG) {
171*0Sstevel@tonic-gate printf(" + R%d\n", RS2(instructp));
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate #endif /* DEBUG */
174*0Sstevel@tonic-gate addarc(parentp, &indirectchild, 0);
175*0Sstevel@tonic-gate continue;
176*0Sstevel@tonic-gate }
177*0Sstevel@tonic-gate break;
178*0Sstevel@tonic-gate default:
179*0Sstevel@tonic-gate continue;
180*0Sstevel@tonic-gate }
181*0Sstevel@tonic-gate
182*0Sstevel@tonic-gate /*
183*0Sstevel@tonic-gate * Check that the destination is the address of
184*0Sstevel@tonic-gate * a function; this allows us to differentiate
185*0Sstevel@tonic-gate * real calls from someone trying to get the PC,
186*0Sstevel@tonic-gate * e.g. position independent switches.
187*0Sstevel@tonic-gate */
188*0Sstevel@tonic-gate if (destpc >= s_lowpc && destpc <= s_highpc) {
189*0Sstevel@tonic-gate
190*0Sstevel@tonic-gate childp = nllookup(&modules, destpc, NULL);
191*0Sstevel@tonic-gate #ifdef DEBUG
192*0Sstevel@tonic-gate if (debug & CALLSDEBUG) {
193*0Sstevel@tonic-gate printf("[findcalls]\tdestpc 0x%llx", destpc);
194*0Sstevel@tonic-gate printf(" childp->name %s", childp->name);
195*0Sstevel@tonic-gate printf(" childp->value 0x%llx\n",
196*0Sstevel@tonic-gate childp->value);
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate #endif /* DEBUG */
199*0Sstevel@tonic-gate if (childp->value == destpc) {
200*0Sstevel@tonic-gate /*
201*0Sstevel@tonic-gate * a hit
202*0Sstevel@tonic-gate */
203*0Sstevel@tonic-gate addarc(parentp, childp, 0);
204*0Sstevel@tonic-gate continue;
205*0Sstevel@tonic-gate }
206*0Sstevel@tonic-gate }
207*0Sstevel@tonic-gate /*
208*0Sstevel@tonic-gate * else:
209*0Sstevel@tonic-gate * it looked like a call,
210*0Sstevel@tonic-gate * but it wasn't to anywhere.
211*0Sstevel@tonic-gate */
212*0Sstevel@tonic-gate #ifdef DEBUG
213*0Sstevel@tonic-gate if (debug & CALLSDEBUG) {
214*0Sstevel@tonic-gate printf("[findcalls]\tbut it's a switch or a botch\n");
215*0Sstevel@tonic-gate }
216*0Sstevel@tonic-gate #endif /* DEBUG */
217*0Sstevel@tonic-gate continue;
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate }
220