github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/5l/list.c (about)

     1  // Inferno utils/5l/list.h
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5l/list.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 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  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  // Printing.
    32  
    33  #include "l.h"
    34  #include "../ld/lib.h"
    35  
    36  void
    37  listinit(void)
    38  {
    39  
    40  	fmtinstall('A', Aconv);
    41  	fmtinstall('C', Cconv);
    42  	fmtinstall('D', Dconv);
    43  	fmtinstall('P', Pconv);
    44  	fmtinstall('S', Sconv);
    45  	fmtinstall('N', Nconv);
    46  	fmtinstall('O', Oconv);		// C_type constants
    47  	fmtinstall('I', Iconv);
    48  }
    49  
    50  void
    51  prasm(Prog *p)
    52  {
    53  	print("%P\n", p);
    54  }
    55  
    56  int
    57  Pconv(Fmt *fp)
    58  {
    59  	Prog *p;
    60  	int a;
    61  
    62  	p = va_arg(fp->args, Prog*);
    63  	curp = p;
    64  	a = p->as;
    65  	switch(a) {
    66  	default:
    67  		fmtprint(fp, "(%d)", p->line);
    68  		if(p->reg == NREG && p->as != AGLOBL)
    69  			fmtprint(fp, "	%A%C	%D,%D",
    70  				a, p->scond, &p->from, &p->to);
    71  		else
    72  		if(p->from.type != D_FREG)
    73  			fmtprint(fp, "	%A%C	%D,R%d,%D",
    74  				a, p->scond, &p->from, p->reg, &p->to);
    75  		else
    76  			fmtprint(fp, "	%A%C	%D,F%d,%D",
    77  				a, p->scond, &p->from, p->reg, &p->to);
    78  		break;
    79  
    80  	case ASWPW:
    81  	case ASWPBU:
    82  		fmtprint(fp, "(%d)	%A%C	R%d,%D,%D",
    83  			p->line, a, p->scond, p->reg, &p->from, &p->to);
    84  		break;
    85  
    86  	case ADATA:
    87  	case AINIT_:
    88  	case ADYNT_:
    89  		fmtprint(fp, "(%d)	%A%C	%D/%d,%D",
    90  			p->line, a, p->scond, &p->from, p->reg, &p->to);
    91  		break;
    92  
    93  	case AWORD:
    94  		fmtprint(fp, "(%d)	WORD	%D", p->line, &p->to);
    95  		break;
    96  
    97  	case ADWORD:
    98  		fmtprint(fp, "(%d)	DWORD	%D %D", p->line, &p->from, &p->to);
    99  		break;
   100  	}
   101  	
   102  	if(p->spadj)
   103  		fmtprint(fp, "  (spadj%+d)", p->spadj);
   104  
   105  	return 0;
   106  }
   107  
   108  int
   109  Aconv(Fmt *fp)
   110  {
   111  	char *s;
   112  	int a;
   113  
   114  	a = va_arg(fp->args, int);
   115  	s = "???";
   116  	if(a >= AXXX && a < ALAST)
   117  		s = anames[a];
   118  	return fmtstrcpy(fp, s);
   119  }
   120  
   121  char*	strcond[16] =
   122  {
   123  	".EQ",
   124  	".NE",
   125  	".HS",
   126  	".LO",
   127  	".MI",
   128  	".PL",
   129  	".VS",
   130  	".VC",
   131  	".HI",
   132  	".LS",
   133  	".GE",
   134  	".LT",
   135  	".GT",
   136  	".LE",
   137  	"",
   138  	".NV"
   139  };
   140  
   141  int
   142  Cconv(Fmt *fp)
   143  {
   144  	char s[20];
   145  	int c;
   146  
   147  	c = va_arg(fp->args, int);
   148  	strcpy(s, strcond[c & C_SCOND]);
   149  	if(c & C_SBIT)
   150  		strcat(s, ".S");
   151  	if(c & C_PBIT)
   152  		strcat(s, ".P");
   153  	if(c & C_WBIT)
   154  		strcat(s, ".W");
   155  	if(c & C_UBIT)		/* ambiguous with FBIT */
   156  		strcat(s, ".U");
   157  	return fmtstrcpy(fp, s);
   158  }
   159  
   160  int
   161  Dconv(Fmt *fp)
   162  {
   163  	char str[STRINGSZ];
   164  	const char *op;
   165  	Adr *a;
   166  	int32 v;
   167  
   168  	a = va_arg(fp->args, Adr*);
   169  	switch(a->type) {
   170  
   171  	default:
   172  		snprint(str, sizeof str, "GOK-type(%d)", a->type);
   173  		break;
   174  
   175  	case D_NONE:
   176  		str[0] = 0;
   177  		if(a->name != D_NONE || a->reg != NREG || a->sym != S)
   178  			snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
   179  		break;
   180  
   181  	case D_CONST:
   182  		if(a->reg == NREG)
   183  			snprint(str, sizeof str, "$%N", a);
   184  		else
   185  			snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
   186  		break;
   187  
   188  	case D_CONST2:
   189  		snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
   190  		break;
   191  
   192  	case D_SHIFT:
   193  		v = a->offset;
   194  		op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
   195  		if(v & (1<<4))
   196  			snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
   197  		else
   198  			snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
   199  		if(a->reg != NREG)
   200  			seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg);
   201  		break;
   202  
   203  	case D_OCONST:
   204  		snprint(str, sizeof str, "$*$%N", a);
   205  		if(a->reg != NREG)
   206  			snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg);
   207  		break;
   208  
   209  	case D_OREG:
   210  		if(a->reg != NREG)
   211  			snprint(str, sizeof str, "%N(R%d)", a, a->reg);
   212  		else
   213  			snprint(str, sizeof str, "%N", a);
   214  		break;
   215  
   216  	case D_REG:
   217  		snprint(str, sizeof str, "R%d", a->reg);
   218  		if(a->name != D_NONE || a->sym != S)
   219  			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
   220  		break;
   221  
   222  	case D_REGREG:
   223  		snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset);
   224  		if(a->name != D_NONE || a->sym != S)
   225  			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
   226  		break;
   227  
   228  	case D_REGREG2:
   229  		snprint(str, sizeof str, "R%d,R%d", a->reg, (int)a->offset);
   230  		if(a->name != D_NONE || a->sym != S)
   231  			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
   232  		break;
   233  
   234  	case D_FREG:
   235  		snprint(str, sizeof str, "F%d", a->reg);
   236  		if(a->name != D_NONE || a->sym != S)
   237  			snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
   238  		break;
   239  
   240  	case D_PSR:
   241  		switch(a->reg) {
   242  		case 0:
   243  			snprint(str, sizeof str, "CPSR");
   244  			break;
   245  		case 1:
   246  			snprint(str, sizeof str, "SPSR");
   247  			break;
   248  		default:
   249  			snprint(str, sizeof str, "PSR%d", a->reg);
   250  			break;
   251  		}
   252  		if(a->name != D_NONE || a->sym != S)
   253  			snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg);
   254  		break;
   255  
   256  	case D_FPCR:
   257  		switch(a->reg){
   258  		case 0:
   259  			snprint(str, sizeof str, "FPSR");
   260  			break;
   261  		case 1:
   262  			snprint(str, sizeof str, "FPCR");
   263  			break;
   264  		default:
   265  			snprint(str, sizeof str, "FCR%d", a->reg);
   266  			break;
   267  		}
   268  		if(a->name != D_NONE || a->sym != S)
   269  			snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg);
   270  
   271  		break;
   272  
   273  	case D_BRANCH:	/* botch */
   274  		if(curp->cond != P) {
   275  			v = curp->cond->pc;
   276  			if(a->sym != S)
   277  				snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
   278  			else
   279  				snprint(str, sizeof str, "%.5ux(BRANCH)", v);
   280  		} else
   281  			if(a->sym != S)
   282  				snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset);
   283  			else
   284  				snprint(str, sizeof str, "%d(APC)", a->offset);
   285  		break;
   286  
   287  	case D_FCONST:
   288  		snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
   289  		break;
   290  
   291  	case D_SCONST:
   292  		snprint(str, sizeof str, "$\"%S\"", a->sval);
   293  		break;
   294  	}
   295  	return fmtstrcpy(fp, str);
   296  }
   297  
   298  int
   299  Nconv(Fmt *fp)
   300  {
   301  	char str[STRINGSZ];
   302  	Adr *a;
   303  	Sym *s;
   304  
   305  	a = va_arg(fp->args, Adr*);
   306  	s = a->sym;
   307  	switch(a->name) {
   308  	default:
   309  		sprint(str, "GOK-name(%d)", a->name);
   310  		break;
   311  
   312  	case D_NONE:
   313  		sprint(str, "%d", a->offset);
   314  		break;
   315  
   316  	case D_EXTERN:
   317  		if(s == S)
   318  			sprint(str, "%d(SB)", a->offset);
   319  		else
   320  			sprint(str, "%s+%d(SB)", s->name, a->offset);
   321  		break;
   322  
   323  	case D_STATIC:
   324  		if(s == S)
   325  			sprint(str, "<>+%d(SB)", a->offset);
   326  		else
   327  			sprint(str, "%s<>+%d(SB)", s->name, a->offset);
   328  		break;
   329  
   330  	case D_AUTO:
   331  		if(s == S)
   332  			sprint(str, "%d(SP)", a->offset);
   333  		else
   334  			sprint(str, "%s-%d(SP)", s->name, -a->offset);
   335  		break;
   336  
   337  	case D_PARAM:
   338  		if(s == S)
   339  			sprint(str, "%d(FP)", a->offset);
   340  		else
   341  			sprint(str, "%s+%d(FP)", s->name, a->offset);
   342  		break;
   343  	}
   344  	return fmtstrcpy(fp, str);
   345  }
   346  
   347  int
   348  Sconv(Fmt *fp)
   349  {
   350  	int i, c;
   351  	char str[STRINGSZ], *p, *a;
   352  
   353  	a = va_arg(fp->args, char*);
   354  	p = str;
   355  	for(i=0; i<sizeof(int32); i++) {
   356  		c = a[i] & 0xff;
   357  		if(c >= 'a' && c <= 'z' ||
   358  		   c >= 'A' && c <= 'Z' ||
   359  		   c >= '0' && c <= '9' ||
   360  		   c == ' ' || c == '%') {
   361  			*p++ = c;
   362  			continue;
   363  		}
   364  		*p++ = '\\';
   365  		switch(c) {
   366  		case 0:
   367  			*p++ = 'z';
   368  			continue;
   369  		case '\\':
   370  		case '"':
   371  			*p++ = c;
   372  			continue;
   373  		case '\n':
   374  			*p++ = 'n';
   375  			continue;
   376  		case '\t':
   377  			*p++ = 't';
   378  			continue;
   379  		}
   380  		*p++ = (c>>6) + '0';
   381  		*p++ = ((c>>3) & 7) + '0';
   382  		*p++ = (c & 7) + '0';
   383  	}
   384  	*p = 0;
   385  	return fmtstrcpy(fp, str);
   386  }
   387  
   388  int
   389  Iconv(Fmt *fp)
   390  {
   391  	int i, n;
   392  	uint32 *p;
   393  	char *s;
   394  	Fmt fmt;
   395  	
   396  	n = fp->prec;
   397  	fp->prec = 0;
   398  	if(!(fp->flags&FmtPrec) || n < 0)
   399  		return fmtstrcpy(fp, "%I");
   400  	fp->flags &= ~FmtPrec;
   401  	p = va_arg(fp->args, uint32*);
   402  
   403  	// format into temporary buffer and
   404  	// call fmtstrcpy to handle padding.
   405  	fmtstrinit(&fmt);
   406  	for(i=0; i<n/4; i++) {
   407  		if(i > 0)
   408  			fmtprint(&fmt, " ");
   409  		fmtprint(&fmt, "%.8ux", *p++);
   410  	}
   411  	s = fmtstrflush(&fmt);
   412  	fmtstrcpy(fp, s);
   413  	free(s);
   414  	return 0;
   415  }
   416  
   417  static char*
   418  cnames[] =
   419  {
   420  	[C_ADDR]	= "C_ADDR",
   421  	[C_FAUTO]	= "C_FAUTO",
   422  	[C_ZFCON]	= "C_SFCON",
   423  	[C_SFCON]	= "C_SFCON",
   424  	[C_LFCON]	= "C_LFCON",
   425  	[C_FCR]		= "C_FCR",
   426  	[C_FOREG]	= "C_FOREG",
   427  	[C_FREG]	= "C_FREG",
   428  	[C_GOK]		= "C_GOK",
   429  	[C_HAUTO]	= "C_HAUTO",
   430  	[C_HFAUTO]	= "C_HFAUTO",
   431  	[C_HFOREG]	= "C_HFOREG",
   432  	[C_HOREG]	= "C_HOREG",
   433  	[C_HREG]	= "C_HREG",
   434  	[C_LACON]	= "C_LACON",
   435  	[C_LAUTO]	= "C_LAUTO",
   436  	[C_LBRA]	= "C_LBRA",
   437  	[C_LCON]	= "C_LCON",
   438  	[C_LCONADDR]	= "C_LCONADDR",
   439  	[C_LOREG]	= "C_LOREG",
   440  	[C_NCON]	= "C_NCON",
   441  	[C_NONE]	= "C_NONE",
   442  	[C_PC]		= "C_PC",
   443  	[C_PSR]		= "C_PSR",
   444  	[C_RACON]	= "C_RACON",
   445  	[C_RCON]	= "C_RCON",
   446  	[C_REG]		= "C_REG",
   447  	[C_REGREG]	= "C_REGREG",
   448  	[C_REGREG2]	= "C_REGREG2",
   449  	[C_ROREG]	= "C_ROREG",
   450  	[C_SAUTO]	= "C_SAUTO",
   451  	[C_SBRA]	= "C_SBRA",
   452  	[C_SCON]	= "C_SCON",
   453  	[C_SHIFT]	= "C_SHIFT",
   454  	[C_SOREG]	= "C_SOREG",
   455  	[C_SP]		= "C_SP",
   456  	[C_SROREG]	= "C_SROREG"
   457  };
   458  
   459  int
   460  Oconv(Fmt *fp)
   461  {
   462  	char buf[500];
   463  	int o;
   464  
   465  	o = va_arg(fp->args, int);
   466  	if(o < 0 || o >= nelem(cnames) || cnames[o] == nil) {
   467  		snprint(buf, sizeof(buf), "C_%d", o);
   468  		return fmtstrcpy(fp, buf);
   469  	}
   470  	return fmtstrcpy(fp, cnames[o]);
   471  }
   472  
   473  void
   474  diag(char *fmt, ...)
   475  {
   476  	char buf[STRINGSZ], *tn, *sep;
   477  	va_list arg;
   478  
   479  	tn = "";
   480  	sep = "";
   481  	if(cursym != S) {
   482  		tn = cursym->name;
   483  		sep = ": ";
   484  	}
   485  	va_start(arg, fmt);
   486  	vseprint(buf, buf+sizeof(buf), fmt, arg);
   487  	va_end(arg);
   488  	print("%s%s%s\n", tn, sep, buf);
   489  
   490  	nerrors++;
   491  	if(nerrors > 20) {
   492  		print("too many errors\n");
   493  		errorexit();
   494  	}
   495  }