]>
Commit | Line | Data |
---|---|---|
3d6c6501 SEF |
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 | */ | |
5489fcc3 KR |
19 | #include "gprof.h" |
20 | #include "time_host.h" | |
3d6c6501 | 21 | |
5489fcc3 KR |
22 | /* |
23 | * A symbol to be the child of indirect callf: | |
24 | */ | |
25 | Sym indirectchild; | |
3d6c6501 | 26 | |
3d6c6501 SEF |
27 | |
28 | operandenum | |
5489fcc3 | 29 | operandmode(modep) |
3d6c6501 SEF |
30 | unsigned char *modep; |
31 | { | |
5489fcc3 | 32 | long usesreg = ((long)*modep) & 0xf; |
3d6c6501 | 33 | |
5489fcc3 | 34 | switch (((long)*modep) >> 4) { |
3d6c6501 SEF |
35 | case 0: |
36 | case 1: | |
37 | case 2: | |
38 | case 3: | |
39 | return literal; | |
40 | case 4: | |
41 | return indexed; | |
42 | case 5: | |
43 | return reg; | |
44 | case 6: | |
45 | return regdef; | |
46 | case 7: | |
47 | return autodec; | |
48 | case 8: | |
5489fcc3 | 49 | return usesreg != 0xe ? autoinc : immediate; |
3d6c6501 | 50 | case 9: |
5489fcc3 | 51 | return usesreg != PC ? autoincdef : absolute; |
3d6c6501 | 52 | case 10: |
5489fcc3 | 53 | return usesreg != PC ? bytedisp : byterel; |
3d6c6501 | 54 | case 11: |
5489fcc3 | 55 | return usesreg != PC ? bytedispdef : bytereldef; |
3d6c6501 | 56 | case 12: |
5489fcc3 | 57 | return usesreg != PC ? worddisp : wordrel; |
3d6c6501 | 58 | case 13: |
5489fcc3 | 59 | return usesreg != PC ? worddispdef : wordreldef; |
3d6c6501 | 60 | case 14: |
5489fcc3 | 61 | return usesreg != PC ? longdisp : longrel; |
3d6c6501 | 62 | case 15: |
5489fcc3 | 63 | return usesreg != PC ? longdispdef : longreldef; |
3d6c6501 SEF |
64 | } |
65 | /* NOTREACHED */ | |
66 | } | |
67 | ||
68 | char * | |
5489fcc3 | 69 | operandname(mode) |
3d6c6501 SEF |
70 | operandenum mode; |
71 | { | |
72 | ||
5489fcc3 | 73 | switch (mode) { |
3d6c6501 SEF |
74 | case literal: |
75 | return "literal"; | |
76 | case indexed: | |
77 | return "indexed"; | |
78 | case reg: | |
79 | return "register"; | |
80 | case regdef: | |
81 | return "register deferred"; | |
82 | case autodec: | |
83 | return "autodecrement"; | |
84 | case autoinc: | |
85 | return "autoincrement"; | |
86 | case autoincdef: | |
87 | return "autoincrement deferred"; | |
88 | case bytedisp: | |
89 | return "byte displacement"; | |
90 | case bytedispdef: | |
91 | return "byte displacement deferred"; | |
92 | case byterel: | |
93 | return "byte relative"; | |
94 | case bytereldef: | |
95 | return "byte relative deferred"; | |
96 | case worddisp: | |
97 | return "word displacement"; | |
98 | case worddispdef: | |
99 | return "word displacement deferred"; | |
100 | case wordrel: | |
101 | return "word relative"; | |
102 | case wordreldef: | |
103 | return "word relative deferred"; | |
104 | case immediate: | |
105 | return "immediate"; | |
106 | case absolute: | |
107 | return "absolute"; | |
108 | case longdisp: | |
109 | return "long displacement"; | |
110 | case longdispdef: | |
111 | return "long displacement deferred"; | |
112 | case longrel: | |
113 | return "long relative"; | |
114 | case longreldef: | |
115 | return "long relative deferred"; | |
116 | } | |
117 | /* NOTREACHED */ | |
118 | } | |
119 | ||
120 | long | |
5489fcc3 | 121 | operandlength(modep) |
3d6c6501 SEF |
122 | unsigned char *modep; |
123 | { | |
124 | ||
5489fcc3 | 125 | switch (operandmode(modep)) { |
3d6c6501 SEF |
126 | case literal: |
127 | case reg: | |
128 | case regdef: | |
129 | case autodec: | |
130 | case autoinc: | |
131 | case autoincdef: | |
132 | return 1; | |
133 | case bytedisp: | |
134 | case bytedispdef: | |
135 | case byterel: | |
136 | case bytereldef: | |
137 | return 2; | |
138 | case worddisp: | |
139 | case worddispdef: | |
140 | case wordrel: | |
141 | case wordreldef: | |
142 | return 3; | |
143 | case immediate: | |
144 | case absolute: | |
145 | case longdisp: | |
146 | case longdispdef: | |
147 | case longrel: | |
148 | case longreldef: | |
149 | return 5; | |
150 | case indexed: | |
5489fcc3 | 151 | return 1+operandlength(modep + 1); |
3d6c6501 SEF |
152 | } |
153 | /* NOTREACHED */ | |
154 | } | |
155 | ||
5489fcc3 KR |
156 | bfd_vma |
157 | reladdr(modep) | |
3d6c6501 SEF |
158 | char *modep; |
159 | { | |
5489fcc3 | 160 | operandenum mode = operandmode(modep); |
3d6c6501 SEF |
161 | char *cp; |
162 | short *sp; | |
163 | long *lp; | |
164 | int i; | |
165 | long value = 0; | |
166 | ||
167 | cp = modep; | |
5489fcc3 KR |
168 | ++cp; /* skip over the mode */ |
169 | switch (mode) { | |
3d6c6501 | 170 | default: |
5489fcc3 KR |
171 | fprintf(stderr, "[reladdr] not relative address\n"); |
172 | return (bfd_vma) modep; | |
3d6c6501 | 173 | case byterel: |
5489fcc3 | 174 | return (bfd_vma) (cp + sizeof *cp + *cp); |
3d6c6501 SEF |
175 | case wordrel: |
176 | for (i = 0; i < sizeof *sp; i++) | |
177 | value = (value << 8) + (cp[i] & 0xff); | |
5489fcc3 | 178 | return (bfd_vma) (cp + sizeof *sp + value); |
3d6c6501 SEF |
179 | case longrel: |
180 | for (i = 0; i < sizeof *lp; i++) | |
181 | value = (value << 8) + (cp[i] & 0xff); | |
5489fcc3 | 182 | return (bfd_vma) (cp + sizeof *lp + value); |
3d6c6501 SEF |
183 | } |
184 | } | |
185 | ||
5489fcc3 KR |
186 | find_call(parent, p_lowpc, p_highpc) |
187 | Sym *parent; | |
188 | bfd_vma p_lowpc; | |
189 | bfd_vma p_highpc; | |
3d6c6501 | 190 | { |
5489fcc3 KR |
191 | unsigned char *instructp; |
192 | long length; | |
193 | Sym *child; | |
194 | operandenum mode; | |
195 | operandenum firstmode; | |
196 | bfd_vma destpc; | |
197 | static bool inited = FALSE; | |
3d6c6501 | 198 | |
5489fcc3 KR |
199 | if (!inited) { |
200 | inited = TRUE; | |
201 | sym_init(&indirectchild); | |
202 | indirectchild.cg.prop.fract = 1.0; | |
203 | indirectchild.cg.cyc.head = &indirectchild; | |
204 | } /* if */ | |
205 | ||
206 | if (textspace == 0) { | |
3d6c6501 SEF |
207 | return; |
208 | } | |
5489fcc3 | 209 | if (p_lowpc < s_lowpc) { |
3d6c6501 SEF |
210 | p_lowpc = s_lowpc; |
211 | } | |
5489fcc3 | 212 | if (p_highpc > s_highpc) { |
3d6c6501 SEF |
213 | p_highpc = s_highpc; |
214 | } | |
5489fcc3 KR |
215 | DBG(CALLDEBUG, printf("[findcall] %s: 0x%x to 0x%x\n", |
216 | parent -> name, p_lowpc, p_highpc)); | |
217 | for ( instructp = textspace + p_lowpc ; | |
3d6c6501 | 218 | instructp < textspace + p_highpc ; |
5489fcc3 | 219 | instructp += length) { |
3d6c6501 | 220 | length = 1; |
5489fcc3 | 221 | if (*instructp == CALLF) { |
3d6c6501 SEF |
222 | /* |
223 | * maybe a callf, better check it out. | |
224 | * skip the count of the number of arguments. | |
225 | */ | |
5489fcc3 KR |
226 | DBG(CALLDEBUG, printf("[findcall]\t0x%x:callf", |
227 | instructp - textspace)); | |
228 | firstmode = operandmode(instructp+length); | |
229 | switch (firstmode) { | |
3d6c6501 SEF |
230 | case literal: |
231 | case immediate: | |
232 | break; | |
233 | default: | |
234 | goto botched; | |
235 | } | |
5489fcc3 KR |
236 | length += operandlength(instructp+length); |
237 | mode = operandmode(instructp + length); | |
238 | DBG(CALLDEBUG, | |
239 | printf("\tfirst operand is %s", operandname(firstmode)); | |
240 | printf("\tsecond operand is %s\n", operandname(mode)); | |
241 | ); | |
242 | switch (mode) { | |
3d6c6501 SEF |
243 | case regdef: |
244 | case bytedispdef: | |
245 | case worddispdef: | |
246 | case longdispdef: | |
247 | case bytereldef: | |
248 | case wordreldef: | |
249 | case longreldef: | |
250 | /* | |
251 | * indirect call: call through pointer | |
252 | * either *d(r) as a parameter or local | |
253 | * (r) as a return value | |
254 | * *f as a global pointer | |
255 | * [are there others that we miss?, | |
256 | * e.g. arrays of pointers to functions???] | |
257 | */ | |
5489fcc3 KR |
258 | arc_add(parent, &indirectchild, (long) 0); |
259 | length += operandlength(instructp + length); | |
3d6c6501 SEF |
260 | continue; |
261 | case byterel: | |
262 | case wordrel: | |
263 | case longrel: | |
264 | /* | |
265 | * regular pc relative addressing | |
266 | * check that this is the address of | |
267 | * a function. | |
268 | */ | |
5489fcc3 KR |
269 | destpc = reladdr(instructp+length) |
270 | - (bfd_vma) textspace; | |
271 | if (destpc >= s_lowpc && destpc <= s_highpc) { | |
272 | child = sym_lookup(destpc); | |
273 | DBG(CALLDEBUG, | |
274 | printf("[findcall]\tdestpc 0x%x", destpc); | |
275 | printf(" child->name %s", child -> name); | |
276 | printf(" child->addr 0x%x\n", child -> addr); | |
277 | ); | |
278 | if (child -> addr == destpc) { | |
3d6c6501 SEF |
279 | /* |
280 | * a hit | |
281 | */ | |
5489fcc3 KR |
282 | arc_add(parent, child, (long) 0); |
283 | length += operandlength(instructp + length); | |
3d6c6501 SEF |
284 | continue; |
285 | } | |
286 | goto botched; | |
287 | } | |
288 | /* | |
289 | * else: | |
290 | * it looked like a callf, | |
291 | * but it wasn't to anywhere. | |
292 | */ | |
293 | goto botched; | |
294 | default: | |
295 | botched: | |
296 | /* | |
297 | * something funny going on. | |
298 | */ | |
5489fcc3 | 299 | DBG(CALLDEBUG, printf("[findcall]\tbut it's a botch\n")); |
3d6c6501 SEF |
300 | length = 1; |
301 | continue; | |
302 | } | |
303 | } | |
304 | } | |
305 | } |