1 // Inferno libmach/machdata.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/libmach/machdata.c
3 //
4 // Copyright © 1994-1999 Lucent Technologies Inc.
5 // Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
6 // Portions Copyright © 1997-1999 Vita Nuova Limited.
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
8 // Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
9 // Portions Copyright © 2009 The Go Authors. All rights reserved.
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28
29 /*
30 * Debugger utilities shared by at least two architectures
31 */
32
33 #include <u.h>
34 #include <libc.h>
35 #include <bio.h>
36 #include <mach.h>
37
38 #define STARTSYM "_main"
39 #define PROFSYM "_mainp"
40 #define FRAMENAME ".frame"
41
42 extern Machdata mipsmach;
43
44 int asstype = AMIPS; /* disassembler type */
45 Machdata *machdata; /* machine-dependent functions */
46
47 int
48 localaddr(Map *map, char *fn, char *var, uvlong *r, Rgetter rget)
49 {
50 Symbol s;
51 uvlong fp, pc, sp, link;
52
53 if (!lookup(fn, 0, &s)) {
54 werrstr("function not found");
55 return -1;
56 }
57 pc = rget(map, mach->pc);
58 sp = rget(map, mach->sp);
59 if(mach->link)
60 link = rget(map, mach->link);
61 else
62 link = 0;
63 fp = machdata->findframe(map, s.value, pc, sp, link);
64 if (fp == 0) {
65 werrstr("stack frame not found");
66 return -1;
67 }
68
69 if (!var || !var[0]) {
70 *r = fp;
71 return 1;
72 }
73
74 if (findlocal(&s, var, &s) == 0) {
75 werrstr("local variable not found");
76 return -1;
77 }
78
79 switch (s.class) {
80 case CAUTO:
81 *r = fp - s.value;
82 break;
83 case CPARAM: /* assume address size is stack width */
84 *r = fp + s.value + mach->szaddr;
85 break;
86 default:
87 werrstr("local variable not found: %d", s.class);
88 return -1;
89 }
90 return 1;
91 }
92
93 /*
94 * Print value v as s.name[+offset] if possible, or just v.
95 */
96 int
97 symoff(char *buf, int n, uvlong v, int space)
98 {
99 Symbol s;
100 int r;
101 int32 delta;
102
103 r = delta = 0; /* to shut compiler up */
104 if (v) {
105 r = findsym(v, space, &s);
106 if (r)
107 delta = v-s.value;
108 if (delta < 0)
109 delta = -delta;
110 }
111 if (v == 0 || r == 0)
112 return snprint(buf, n, "%llux", v);
113 if (s.type != 't' && s.type != 'T' && delta >= 4096)
114 return snprint(buf, n, "%llux", v);
115 else if (delta)
116 return snprint(buf, n, "%s+%#lux", s.name, delta);
117 else
118 return snprint(buf, n, "%s", s.name);
119 }
120
121 /*
122 * Format floating point registers
123 *
124 * Register codes in format field:
125 * 'X' - print as 32-bit hexadecimal value
126 * 'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
127 * 'f' - 32-bit ieee float
128 * '8' - big endian 80-bit ieee extended float
129 * '3' - little endian 80-bit ieee extended float with hole in bytes 8&9
130 */
131 int
132 fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
133 {
134 char reg[12];
135 uint32 r;
136
137 switch(rp->rformat)
138 {
139 case 'X':
140 if (get4(map, rp->roffs, &r) < 0)
141 return -1;
142 snprint(buf, n, "%lux", r);
143 break;
144 case 'F': /* first reg of double reg pair */
145 if (modif == 'F')
146 if ((rp->rformat=='F') || (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f')) {
147 if (get1(map, rp->roffs, (uchar *)reg, 8) < 0)
148 return -1;
149 machdata->dftos(buf, n, reg);
150 if (rp->rformat == 'F')
151 return 1;
152 return 2;
153 }
154 /* treat it like 'f' */
155 if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
156 return -1;
157 machdata->sftos(buf, n, reg);
158 break;
159 case 'f': /* 32 bit float */
160 if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
161 return -1;
162 machdata->sftos(buf, n, reg);
163 break;
164 case '3': /* little endian ieee 80 with hole in bytes 8&9 */
165 if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
166 return -1;
167 memmove(reg+10, reg+8, 2); /* open hole */
168 memset(reg+8, 0, 2); /* fill it */
169 leieee80ftos(buf, n, reg);
170 break;
171 case '8': /* big-endian ieee 80 */
172 if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
173 return -1;
174 beieee80ftos(buf, n, reg);
175 break;
176 default: /* unknown */
177 break;
178 }
179 return 1;
180 }
181
182 char *
183 _hexify(char *buf, uint32 p, int zeros)
184 {
185 uint32 d;
186
187 d = p/16;
188 if(d)
189 buf = _hexify(buf, d, zeros-1);
190 else
191 while(zeros--)
192 *buf++ = '0';
193 *buf++ = "0123456789abcdef"[p&0x0f];
194 return buf;
195 }
196
197 /*
198 * These routines assume that if the number is representable
199 * in IEEE floating point, it will be representable in the native
200 * double format. Naive but workable, probably.
201 */
202 int
203 ieeedftos(char *buf, int n, uint32 h, uint32 l)
204 {
205 double fr;
206 int exp;
207
208 if (n <= 0)
209 return 0;
210
211
212 if(h & (1L<<31)){
213 *buf++ = '-';
214 h &= ~(1L<<31);
215 }else
216 *buf++ = ' ';
217 n--;
218 if(l == 0 && h == 0)
219 return snprint(buf, n, "0.");
220 exp = (h>>20) & ((1L<<11)-1L);
221 if(exp == 0)
222 return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
223 if(exp == ((1L<<11)-1L)){
224 if(l==0 && (h&((1L<<20)-1L)) == 0)
225 return snprint(buf, n, "Inf");
226 else
227 return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
228 }
229 exp -= (1L<<10) - 2L;
230 fr = l & ((1L<<16)-1L);
231 fr /= 1L<<16;
232 fr += (l>>16) & ((1L<<16)-1L);
233 fr /= 1L<<16;
234 fr += (h & (1L<<20)-1L) | (1L<<20);
235 fr /= 1L<<21;
236 fr = ldexp(fr, exp);
237 return snprint(buf, n, "%.18g", fr);
238 }
239
240 int
241 ieeesftos(char *buf, int n, uint32 h)
242 {
243 double fr;
244 int exp;
245
246 if (n <= 0)
247 return 0;
248
249 if(h & (1L<<31)){
250 *buf++ = '-';
251 h &= ~(1L<<31);
252 }else
253 *buf++ = ' ';
254 n--;
255 if(h == 0)
256 return snprint(buf, n, "0.");
257 exp = (h>>23) & ((1L<<8)-1L);
258 if(exp == 0)
259 return snprint(buf, n, "DeN(%.8lux)", h);
260 if(exp == ((1L<<8)-1L)){
261 if((h&((1L<<23)-1L)) == 0)
262 return snprint(buf, n, "Inf");
263 else
264 return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
265 }
266 exp -= (1L<<7) - 2L;
267 fr = (h & ((1L<<23)-1L)) | (1L<<23);
268 fr /= 1L<<24;
269 fr = ldexp(fr, exp);
270 return snprint(buf, n, "%.9g", fr);
271 }
272
273 int
274 beieeesftos(char *buf, int n, void *s)
275 {
276 return ieeesftos(buf, n, beswal(*(uint32*)s));
277 }
278
279 int
280 beieeedftos(char *buf, int n, void *s)
281 {
282 return ieeedftos(buf, n, beswal(*(uint32*)s), beswal(((uint32*)(s))[1]));
283 }
284
285 int
286 leieeesftos(char *buf, int n, void *s)
287 {
288 return ieeesftos(buf, n, leswal(*(uint32*)s));
289 }
290
291 int
292 leieeedftos(char *buf, int n, void *s)
293 {
294 return ieeedftos(buf, n, leswal(((uint32*)(s))[1]), leswal(*(uint32*)s));
295 }
296
297 /* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
298 int
299 beieee80ftos(char *buf, int n, void *s)
300 {
301 uchar *reg = (uchar*)s;
302 int i;
303 uint32 x;
304 uchar ieee[8+8]; /* room for slop */
305 uchar *p, *q;
306
307 memset(ieee, 0, sizeof(ieee));
308 /* sign */
309 if(reg[0] & 0x80)
310 ieee[0] |= 0x80;
311
312 /* exponent */
313 x = ((reg[0]&0x7F)<<8) | reg[1];
314 if(x == 0) /* number is ±0 */
315 goto done;
316 if(x == 0x7FFF){
317 if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
318 x = 2047;
319 }else{ /* NaN */
320 x = 2047;
321 ieee[7] = 0x1; /* make sure */
322 }
323 ieee[0] |= x>>4;
324 ieee[1] |= (x&0xF)<<4;
325 goto done;
326 }
327 x -= 0x3FFF; /* exponent bias */
328 x += 1023;
329 if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
330 return snprint(buf, n, "not in range");
331 ieee[0] |= x>>4;
332 ieee[1] |= (x&0xF)<<4;
333
334 /* mantissa */
335 p = reg+4;
336 q = ieee+1;
337 for(i=0; i<56; i+=8, p++, q++){ /* move one byte */
338 x = (p[0]&0x7F) << 1;
339 if(p[1] & 0x80)
340 x |= 1;
341 q[0] |= x>>4;
342 q[1] |= (x&0xF)<<4;
343 }
344 done:
345 return beieeedftos(buf, n, (void*)ieee);
346 }
347
348 int
349 leieee80ftos(char *buf, int n, void *s)
350 {
351 int i;
352 char *cp;
353 char b[12];
354
355 cp = (char*) s;
356 for(i=0; i<12; i++)
357 b[11-i] = *cp++;
358 return beieee80ftos(buf, n, b);
359 }
360
361 int
362 cisctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
363 {
364 Symbol s;
365 int found, i;
366 uvlong opc, moved;
367
368 USED(link);
369 i = 0;
370 opc = 0;
371 while(pc && opc != pc) {
372 moved = pc2sp(pc);
373 if (moved == ~0)
374 break;
375 found = findsym(pc, CTEXT, &s);
376 if (!found)
377 break;
378 if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
379 break;
380
381 sp += moved;
382 opc = pc;
383 if (geta(map, sp, &pc) < 0)
384 break;
385 (*trace)(map, pc, sp, &s);
386 sp += mach->szaddr; /*assumes address size = stack width*/
387 if(++i > 40)
388 break;
389 }
390 return i;
391 }
392
393 int
394 risctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
395 {
396 int i;
397 Symbol s, f;
398 uvlong oldpc;
399
400 i = 0;
401 while(findsym(pc, CTEXT, &s)) {
402 if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
403 break;
404
405 if(pc == s.value) /* at first instruction */
406 f.value = 0;
407 else if(findlocal(&s, FRAMENAME, &f) == 0)
408 break;
409
410 oldpc = pc;
411 if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant)
412 pc = link;
413 else
414 if (geta(map, sp, &pc) < 0)
415 break;
416
417 if(pc == 0 || (pc == oldpc && f.value == 0))
418 break;
419
420 sp += f.value;
421 (*trace)(map, pc-8, sp, &s);
422
423 if(++i > 40)
424 break;
425 }
426 return i;
427 }
428
429 uvlong
430 ciscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
431 {
432 Symbol s;
433 uvlong moved;
434
435 USED(link);
436 for(;;) {
437 moved = pc2sp(pc);
438 if (moved == ~0)
439 break;
440 sp += moved;
441 findsym(pc, CTEXT, &s);
442 if (addr == s.value)
443 return sp;
444 if (geta(map, sp, &pc) < 0)
445 break;
446 sp += mach->szaddr; /*assumes sizeof(addr) = stack width*/
447 }
448 return 0;
449 }
450
451 uvlong
452 riscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
453 {
454 Symbol s, f;
455
456 while (findsym(pc, CTEXT, &s)) {
457 if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
458 break;
459
460 if(pc == s.value) /* at first instruction */
461 f.value = 0;
462 else
463 if(findlocal(&s, FRAMENAME, &f) == 0)
464 break;
465
466 sp += f.value;
467 if (s.value == addr)
468 return sp;
469
470 if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2)
471 pc = link;
472 else
473 if (geta(map, sp-f.value, &pc) < 0)
474 break;
475 }
476 return 0;
477 }