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