The Go Programming Language

Text file src/libmach/machdata.c

     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	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.