github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/libmach/machdata.c (about)

     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+%#ux", 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, "%ux", 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(%.8ux%.8ux)", 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(%.8ux%.8ux)", h&((1<<20)-1), 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(%.8ux)", 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  }