xref: /plan9/sys/src/libmach/machdata.c (revision 4de34a7edde43207e841ec91ecd12e6cf5f5ebe7)
1 /*
2  * Debugger utilities shared by at least two architectures
3  */
4 
5 #include <u.h>
6 #include <libc.h>
7 #include <bio.h>
8 #include <mach.h>
9 
10 #define STARTSYM	"_main"
11 #define PROFSYM		"_mainp"
12 #define	FRAMENAME	".frame"
13 
14 extern	Machdata	mipsmach;
15 
16 int	asstype = AMIPS;		/* disassembler type */
17 Machdata *machdata;		/* machine-dependent functions */
18 
19 int
localaddr(Map * map,char * fn,char * var,uvlong * r,Rgetter rget)20 localaddr(Map *map, char *fn, char *var, uvlong *r, Rgetter rget)
21 {
22 	Symbol s;
23 	uvlong fp, pc, sp, link;
24 
25 	if (!lookup(fn, 0, &s)) {
26 		werrstr("function not found");
27 		return -1;
28 	}
29 	pc = rget(map, mach->pc);
30 	sp = rget(map, mach->sp);
31 	if(mach->link)
32 		link = rget(map, mach->link);
33 	else
34 		link = 0;
35 	fp = machdata->findframe(map, s.value, pc, sp, link);
36 	if (fp == 0) {
37 		werrstr("stack frame not found");
38 		return -1;
39 	}
40 
41 	if (!var || !var[0]) {
42 		*r = fp;
43 		return 1;
44 	}
45 
46 	if (findlocal(&s, var, &s) == 0) {
47 		werrstr("local variable not found");
48 		return -1;
49 	}
50 
51 	switch (s.class) {
52 	case CAUTO:
53 		*r = fp - s.value;
54 		break;
55 	case CPARAM:		/* assume address size is stack width */
56 		*r = fp + s.value + mach->szaddr;
57 		break;
58 	default:
59 		werrstr("local variable not found: %d", s.class);
60 		return -1;
61 	}
62 	return 1;
63 }
64 
65 /*
66  * Print value v as s.name[+offset] if possible, or just v.
67  */
68 int
symoff(char * buf,int n,uvlong v,int space)69 symoff(char *buf, int n, uvlong v, int space)
70 {
71 	Symbol s;
72 	int r;
73 	long delta;
74 
75 	r = delta = 0;		/* to shut compiler up */
76 	if (v) {
77 		r = findsym(v, space, &s);
78 		if (r)
79 			delta = v-s.value;
80 		if (delta < 0)
81 			delta = -delta;
82 	}
83 	if (v == 0 || r == 0)
84 		return snprint(buf, n, "%llux", v);
85 	if (s.type != 't' && s.type != 'T' && delta >= 4096)
86 		return snprint(buf, n, "%llux", v);
87 	else if (delta)
88 		return snprint(buf, n, "%s+%lux", s.name, delta);
89 	else
90 		return snprint(buf, n, "%s", s.name);
91 }
92 
93 /*
94  *	Format floating point registers
95  *
96  *	Register codes in format field:
97  *	'X' - print as 32-bit hexadecimal value
98  *	'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
99  *	'f' - 32-bit ieee float
100  *	'8' - big endian 80-bit ieee extended float
101  *	'3' - little endian 80-bit ieee extended float with hole in bytes 8&9
102  */
103 int
fpformat(Map * map,Reglist * rp,char * buf,int n,int modif)104 fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
105 {
106 	char reg[12];
107 	ulong r;
108 
109 	switch(rp->rformat)
110 	{
111 	case 'X':
112 		if (get4(map, rp->roffs, &r) < 0)
113 			return -1;
114 		snprint(buf, n, "%lux", r);
115 		break;
116 	case 'F':	/* first reg of double reg pair */
117 		if (modif == 'F')
118 		if ((rp->rformat=='F') || (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f')) {
119 			if (get1(map, rp->roffs, (uchar *)reg, 8) < 0)
120 				return -1;
121 			machdata->dftos(buf, n, reg);
122 			if (rp->rformat == 'F')
123 				return 1;
124 			return 2;
125 		}
126 			/* treat it like 'f' */
127 		if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
128 			return -1;
129 		machdata->sftos(buf, n, reg);
130 		break;
131 	case 'f':	/* 32 bit float */
132 		if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
133 			return -1;
134 		machdata->sftos(buf, n, reg);
135 		break;
136 	case '3':	/* little endian ieee 80 with hole in bytes 8&9 */
137 		if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
138 			return -1;
139 		memmove(reg+10, reg+8, 2);	/* open hole */
140 		memset(reg+8, 0, 2);		/* fill it */
141 		leieee80ftos(buf, n, reg);
142 		break;
143 	case '8':	/* big-endian ieee 80 */
144 		if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
145 			return -1;
146 		beieee80ftos(buf, n, reg);
147 		break;
148 	default:	/* unknown */
149 		break;
150 	}
151 	return 1;
152 }
153 
154 char *
_hexify(char * buf,ulong p,int zeros)155 _hexify(char *buf, ulong p, int zeros)
156 {
157 	ulong d;
158 
159 	d = p/16;
160 	if(d)
161 		buf = _hexify(buf, d, zeros-1);
162 	else
163 		while(zeros--)
164 			*buf++ = '0';
165 	*buf++ = "0123456789abcdef"[p&0x0f];
166 	return buf;
167 }
168 
169 /*
170  * These routines assume that if the number is representable
171  * in IEEE floating point, it will be representable in the native
172  * double format.  Naive but workable, probably.
173  */
174 int
ieeedftos(char * buf,int n,ulong h,ulong l)175 ieeedftos(char *buf, int n, ulong h, ulong l)
176 {
177 	double fr;
178 	int exp;
179 
180 	if (n <= 0)
181 		return 0;
182 
183 
184 	if(h & (1L<<31)){
185 		*buf++ = '-';
186 		h &= ~(1L<<31);
187 	}else
188 		*buf++ = ' ';
189 	n--;
190 	if(l == 0 && h == 0)
191 		return snprint(buf, n, "0.");
192 	exp = (h>>20) & ((1L<<11)-1L);
193 	if(exp == 0)
194 		return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
195 	if(exp == ((1L<<11)-1L)){
196 		if(l==0 && (h&((1L<<20)-1L)) == 0)
197 			return snprint(buf, n, "Inf");
198 		else
199 			return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
200 	}
201 	exp -= (1L<<10) - 2L;
202 	fr = l & ((1L<<16)-1L);
203 	fr /= 1L<<16;
204 	fr += (l>>16) & ((1L<<16)-1L);
205 	fr /= 1L<<16;
206 	fr += (h & (1L<<20)-1L) | (1L<<20);
207 	fr /= 1L<<21;
208 	fr = ldexp(fr, exp);
209 	return snprint(buf, n, "%.18g", fr);
210 }
211 
212 int
ieeesftos(char * buf,int n,ulong h)213 ieeesftos(char *buf, int n, ulong h)
214 {
215 	double fr;
216 	int exp;
217 
218 	if (n <= 0)
219 		return 0;
220 
221 	if(h & (1L<<31)){
222 		*buf++ = '-';
223 		h &= ~(1L<<31);
224 	}else
225 		*buf++ = ' ';
226 	n--;
227 	if(h == 0)
228 		return snprint(buf, n, "0.");
229 	exp = (h>>23) & ((1L<<8)-1L);
230 	if(exp == 0)
231 		return snprint(buf, n, "DeN(%.8lux)", h);
232 	if(exp == ((1L<<8)-1L)){
233 		if((h&((1L<<23)-1L)) == 0)
234 			return snprint(buf, n, "Inf");
235 		else
236 			return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
237 	}
238 	exp -= (1L<<7) - 2L;
239 	fr = (h & ((1L<<23)-1L)) | (1L<<23);
240 	fr /= 1L<<24;
241 	fr = ldexp(fr, exp);
242 	return snprint(buf, n, "%.9g", fr);
243 }
244 
245 int
beieeesftos(char * buf,int n,void * s)246 beieeesftos(char *buf, int n, void *s)
247 {
248 	return ieeesftos(buf, n, beswal(*(ulong*)s));
249 }
250 
251 int
beieeedftos(char * buf,int n,void * s)252 beieeedftos(char *buf, int n, void *s)
253 {
254 	return ieeedftos(buf, n, beswal(*(ulong*)s), beswal(((ulong*)(s))[1]));
255 }
256 
257 int
leieeesftos(char * buf,int n,void * s)258 leieeesftos(char *buf, int n, void *s)
259 {
260 	return ieeesftos(buf, n, leswal(*(ulong*)s));
261 }
262 
263 int
leieeedftos(char * buf,int n,void * s)264 leieeedftos(char *buf, int n, void *s)
265 {
266 	return ieeedftos(buf, n, leswal(((ulong*)(s))[1]), leswal(*(ulong*)s));
267 }
268 
269 /* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
270 int
beieee80ftos(char * buf,int n,void * s)271 beieee80ftos(char *buf, int n, void *s)
272 {
273 	uchar *reg = (uchar*)s;
274 	int i;
275 	ulong x;
276 	uchar ieee[8+8];	/* room for slop */
277 	uchar *p, *q;
278 
279 	memset(ieee, 0, sizeof(ieee));
280 	/* sign */
281 	if(reg[0] & 0x80)
282 		ieee[0] |= 0x80;
283 
284 	/* exponent */
285 	x = ((reg[0]&0x7F)<<8) | reg[1];
286 	if(x == 0)		/* number is ±0 */
287 		goto done;
288 	if(x == 0x7FFF){
289 		if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
290 			x = 2047;
291 		}else{				/* NaN */
292 			x = 2047;
293 			ieee[7] = 0x1;		/* make sure */
294 		}
295 		ieee[0] |= x>>4;
296 		ieee[1] |= (x&0xF)<<4;
297 		goto done;
298 	}
299 	x -= 0x3FFF;		/* exponent bias */
300 	x += 1023;
301 	if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
302 		return snprint(buf, n, "not in range");
303 	ieee[0] |= x>>4;
304 	ieee[1] |= (x&0xF)<<4;
305 
306 	/* mantissa */
307 	p = reg+4;
308 	q = ieee+1;
309 	for(i=0; i<56; i+=8, p++, q++){	/* move one byte */
310 		x = (p[0]&0x7F) << 1;
311 		if(p[1] & 0x80)
312 			x |= 1;
313 		q[0] |= x>>4;
314 		q[1] |= (x&0xF)<<4;
315 	}
316     done:
317 	return beieeedftos(buf, n, (void*)ieee);
318 }
319 
320 int
leieee80ftos(char * buf,int n,void * s)321 leieee80ftos(char *buf, int n, void *s)
322 {
323 	int i;
324 	char *cp;
325 	char b[12];
326 
327 	cp = (char*) s;
328 	for(i=0; i<12; i++)
329 		b[11-i] = *cp++;
330 	return beieee80ftos(buf, n, b);
331 }
332 
333 int
cisctrace(Map * map,uvlong pc,uvlong sp,uvlong link,Tracer trace)334 cisctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
335 {
336 	Symbol s;
337 	int found, i;
338 	uvlong opc, moved;
339 
340 	USED(link);
341 	i = 0;
342 	opc = 0;
343 	while(pc && opc != pc) {
344 		moved = pc2sp(pc);
345 		if (moved == ~0)
346 			break;
347 		found = findsym(pc, CTEXT, &s);
348 		if (!found)
349 			break;
350 		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
351 			break;
352 
353 		sp += moved;
354 		opc = pc;
355 		if (geta(map, sp, &pc) < 0)
356 			break;
357 		(*trace)(map, pc, sp, &s);
358 		sp += mach->szaddr;	/*assumes address size = stack width*/
359 		if(++i > 40)
360 			break;
361 	}
362 	return i;
363 }
364 
365 int
risctrace(Map * map,uvlong pc,uvlong sp,uvlong link,Tracer trace)366 risctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
367 {
368 	int i;
369 	Symbol s, f;
370 	uvlong oldpc;
371 
372 	i = 0;
373 	while(findsym(pc, CTEXT, &s)) {
374 		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
375 			break;
376 
377 		if(pc == s.value)	/* at first instruction */
378 			f.value = 0;
379 		else if(findlocal(&s, FRAMENAME, &f) == 0)
380 			break;
381 
382 		oldpc = pc;
383 		if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant)
384 			pc = link;
385 		else
386 			if (geta(map, sp, &pc) < 0)
387 				break;
388 
389 		if(pc == 0 || (pc == oldpc && f.value == 0))
390 			break;
391 
392 		sp += f.value;
393 		(*trace)(map, pc-8, sp, &s);
394 
395 		if(++i > 40)
396 			break;
397 	}
398 	return i;
399 }
400 
401 uvlong
ciscframe(Map * map,uvlong addr,uvlong pc,uvlong sp,uvlong link)402 ciscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
403 {
404 	Symbol s;
405 	uvlong moved;
406 
407 	USED(link);
408 	for(;;) {
409 		moved = pc2sp(pc);
410 		if (moved  == ~0)
411 			break;
412 		sp += moved;
413 		findsym(pc, CTEXT, &s);
414 		if (addr == s.value)
415 			return sp;
416 		if (geta(map, sp, &pc) < 0)
417 			break;
418 		sp += mach->szaddr;	/*assumes sizeof(addr) = stack width*/
419 	}
420 	return 0;
421 }
422 
423 uvlong
riscframe(Map * map,uvlong addr,uvlong pc,uvlong sp,uvlong link)424 riscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
425 {
426 	Symbol s, f;
427 
428 	while (findsym(pc, CTEXT, &s)) {
429 		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
430 			break;
431 
432 		if(pc == s.value)	/* at first instruction */
433 			f.value = 0;
434 		else
435 		if(findlocal(&s, FRAMENAME, &f) == 0)
436 			break;
437 
438 		sp += f.value;
439 		if (s.value == addr)
440 			return sp;
441 
442 		if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2)
443 			pc = link;
444 		else
445 		if (geta(map, sp-f.value, &pc) < 0)
446 			break;
447 	}
448 	return 0;
449 }
450