github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/liblink/list6.c (about)

     1  // Inferno utils/6c/list.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6c/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  #include <u.h>
    32  #include <libc.h>
    33  #include <bio.h>
    34  #include <link.h>
    35  #include "../cmd/6l/6.out.h"
    36  
    37  //
    38  // Format conversions
    39  //	%A int		Opcodes (instruction mnemonics)
    40  //
    41  //	%D Addr*	Addresses (instruction operands)
    42  //		Flags: "%lD": seperate the high and low words of a constant by "-"
    43  //
    44  //	%P Prog*	Instructions
    45  //
    46  //	%R int		Registers
    47  //
    48  //	%$ char*	String constant addresses (for internal use only)
    49  
    50  static int	Aconv(Fmt *fp);
    51  static int	Dconv(Fmt *fp);
    52  static int	Pconv(Fmt *fp);
    53  static int	Rconv(Fmt *fp);
    54  static int	DSconv(Fmt *fp);
    55  
    56  enum
    57  {
    58  	STRINGSZ = 1000
    59  };
    60  
    61  #pragma	varargck	type	"$"	char*
    62  
    63  void
    64  listinit6(void)
    65  {
    66  	fmtinstall('A', Aconv);
    67  	fmtinstall('D', Dconv);
    68  	fmtinstall('P', Pconv);
    69  	fmtinstall('R', Rconv);
    70  
    71  	// for internal use
    72  	fmtinstall('$', DSconv);
    73  }
    74  
    75  static	Prog*	bigP;
    76  
    77  static int
    78  Pconv(Fmt *fp)
    79  {
    80  	char str[STRINGSZ];
    81  	Prog *p;
    82  
    83  	p = va_arg(fp->args, Prog*);
    84  	bigP = p;
    85  
    86  	switch(p->as) {
    87  	case ADATA:
    88  		sprint(str, "%.5lld (%L)	%A	%D/%d,%D",
    89  			p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
    90  		break;
    91  
    92  	case ATEXT:
    93  		if(p->from.scale) {
    94  			sprint(str, "%.5lld (%L)	%A	%D,%d,%lD",
    95  				p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
    96  			break;
    97  		}
    98  		sprint(str, "%.5lld (%L)	%A	%D,%lD",
    99  			p->pc, p->lineno, p->as, &p->from, &p->to);
   100  		break;
   101  
   102  	default:
   103  		sprint(str, "%.5lld (%L)	%A	%D,%D",
   104  			p->pc, p->lineno, p->as, &p->from, &p->to);
   105  		break;
   106  	}
   107  	bigP = nil;
   108  	return fmtstrcpy(fp, str);
   109  }
   110  
   111  static int
   112  Aconv(Fmt *fp)
   113  {
   114  	int i;
   115  
   116  	i = va_arg(fp->args, int);
   117  	return fmtstrcpy(fp, anames6[i]);
   118  }
   119  
   120  static int
   121  Dconv(Fmt *fp)
   122  {
   123  	char str[STRINGSZ], s[STRINGSZ];
   124  	Addr *a;
   125  	int i;
   126  
   127  	a = va_arg(fp->args, Addr*);
   128  	i = a->type;
   129  
   130  	if(fp->flags & FmtLong) {
   131  		if(i == D_CONST)
   132  			sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32);
   133  		else {
   134  			// ATEXT dst is not constant
   135  			sprint(str, "!!%D", a);
   136  		}
   137  		goto brk;
   138  	}
   139  
   140  	if(i >= D_INDIR) {
   141  		if(a->offset)
   142  			sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
   143  		else
   144  			sprint(str, "(%R)", i-D_INDIR);
   145  		goto brk;
   146  	}
   147  	switch(i) {
   148  	default:
   149  		if(a->offset)
   150  			sprint(str, "$%lld,%R", a->offset, i);
   151  		else
   152  			sprint(str, "%R", i);
   153  		break;
   154  
   155  	case D_NONE:
   156  		str[0] = 0;
   157  		break;
   158  
   159  	case D_BRANCH:
   160  		if(a->sym != nil)
   161  			sprint(str, "%s(SB)", a->sym->name);
   162  		else if(bigP != nil && bigP->pcond != nil)
   163  			sprint(str, "%lld", bigP->pcond->pc);
   164  		else if(a->u.branch != nil)
   165  			sprint(str, "%lld", a->u.branch->pc);
   166  		else
   167  			sprint(str, "%lld(PC)", a->offset);
   168  		break;
   169  
   170  	case D_EXTERN:
   171  		sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
   172  		break;
   173  
   174  	case D_STATIC:
   175  		sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
   176  		break;
   177  
   178  	case D_AUTO:
   179  		if(a->sym)
   180  			sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
   181  		else
   182  			sprint(str, "%lld(SP)", a->offset);
   183  		break;
   184  
   185  	case D_PARAM:
   186  		if(a->sym)
   187  			sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
   188  		else
   189  			sprint(str, "%lld(FP)", a->offset);
   190  		break;
   191  
   192  	case D_CONST:
   193  		sprint(str, "$%lld", a->offset);
   194  		break;
   195  
   196  	case D_FCONST:
   197  		sprint(str, "$(%.17g)", a->u.dval);
   198  		break;
   199  
   200  	case D_SCONST:
   201  		sprint(str, "$\"%$\"", a->u.sval);
   202  		break;
   203  
   204  	case D_ADDR:
   205  		a->type = a->index;
   206  		a->index = D_NONE;
   207  		sprint(str, "$%D", a);
   208  		a->index = a->type;
   209  		a->type = D_ADDR;
   210  		goto conv;
   211  	}
   212  brk:
   213  	if(a->index != D_NONE) {
   214  		sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
   215  		strcat(str, s);
   216  	}
   217  conv:
   218  	return fmtstrcpy(fp, str);
   219  }
   220  
   221  static char*	regstr[] =
   222  {
   223  	"AL",	/* [D_AL] */
   224  	"CL",
   225  	"DL",
   226  	"BL",
   227  	"SPB",
   228  	"BPB",
   229  	"SIB",
   230  	"DIB",
   231  	"R8B",
   232  	"R9B",
   233  	"R10B",
   234  	"R11B",
   235  	"R12B",
   236  	"R13B",
   237  	"R14B",
   238  	"R15B",
   239  
   240  	"AX",	/* [D_AX] */
   241  	"CX",
   242  	"DX",
   243  	"BX",
   244  	"SP",
   245  	"BP",
   246  	"SI",
   247  	"DI",
   248  	"R8",
   249  	"R9",
   250  	"R10",
   251  	"R11",
   252  	"R12",
   253  	"R13",
   254  	"R14",
   255  	"R15",
   256  
   257  	"AH",
   258  	"CH",
   259  	"DH",
   260  	"BH",
   261  
   262  	"F0",	/* [D_F0] */
   263  	"F1",
   264  	"F2",
   265  	"F3",
   266  	"F4",
   267  	"F5",
   268  	"F6",
   269  	"F7",
   270  
   271  	"M0",
   272  	"M1",
   273  	"M2",
   274  	"M3",
   275  	"M4",
   276  	"M5",
   277  	"M6",
   278  	"M7",
   279  
   280  	"X0",
   281  	"X1",
   282  	"X2",
   283  	"X3",
   284  	"X4",
   285  	"X5",
   286  	"X6",
   287  	"X7",
   288  	"X8",
   289  	"X9",
   290  	"X10",
   291  	"X11",
   292  	"X12",
   293  	"X13",
   294  	"X14",
   295  	"X15",
   296  
   297  	"CS",	/* [D_CS] */
   298  	"SS",
   299  	"DS",
   300  	"ES",
   301  	"FS",
   302  	"GS",
   303  
   304  	"GDTR",	/* [D_GDTR] */
   305  	"IDTR",	/* [D_IDTR] */
   306  	"LDTR",	/* [D_LDTR] */
   307  	"MSW",	/* [D_MSW] */
   308  	"TASK",	/* [D_TASK] */
   309  
   310  	"CR0",	/* [D_CR] */
   311  	"CR1",
   312  	"CR2",
   313  	"CR3",
   314  	"CR4",
   315  	"CR5",
   316  	"CR6",
   317  	"CR7",
   318  	"CR8",
   319  	"CR9",
   320  	"CR10",
   321  	"CR11",
   322  	"CR12",
   323  	"CR13",
   324  	"CR14",
   325  	"CR15",
   326  
   327  	"DR0",	/* [D_DR] */
   328  	"DR1",
   329  	"DR2",
   330  	"DR3",
   331  	"DR4",
   332  	"DR5",
   333  	"DR6",
   334  	"DR7",
   335  
   336  	"TR0",	/* [D_TR] */
   337  	"TR1",
   338  	"TR2",
   339  	"TR3",
   340  	"TR4",
   341  	"TR5",
   342  	"TR6",
   343  	"TR7",
   344  
   345  	"TLS",	/* [D_TLS] */
   346  	"NONE",	/* [D_NONE] */
   347  };
   348  
   349  static int
   350  Rconv(Fmt *fp)
   351  {
   352  	char str[STRINGSZ];
   353  	int r;
   354  
   355  	r = va_arg(fp->args, int);
   356  	if(r >= D_AL && r <= D_NONE)
   357  		sprint(str, "%s", regstr[r-D_AL]);
   358  	else
   359  		sprint(str, "gok(%d)", r);
   360  
   361  	return fmtstrcpy(fp, str);
   362  }
   363  
   364  static int
   365  DSconv(Fmt *fp)
   366  {
   367  	int i, c;
   368  	char str[STRINGSZ], *p, *a;
   369  
   370  	a = va_arg(fp->args, char*);
   371  	p = str;
   372  	for(i=0; i<sizeof(double); i++) {
   373  		c = a[i] & 0xff;
   374  		if(c >= 'a' && c <= 'z' ||
   375  		   c >= 'A' && c <= 'Z' ||
   376  		   c >= '0' && c <= '9') {
   377  			*p++ = c;
   378  			continue;
   379  		}
   380  		*p++ = '\\';
   381  		switch(c) {
   382  		default:
   383  			if(c < 040 || c >= 0177)
   384  				break;	/* not portable */
   385  			p[-1] = c;
   386  			continue;
   387  		case 0:
   388  			*p++ = 'z';
   389  			continue;
   390  		case '\\':
   391  		case '"':
   392  			*p++ = c;
   393  			continue;
   394  		case '\n':
   395  			*p++ = 'n';
   396  			continue;
   397  		case '\t':
   398  			*p++ = 't';
   399  			continue;
   400  		}
   401  		*p++ = (c>>6) + '0';
   402  		*p++ = ((c>>3) & 7) + '0';
   403  		*p++ = (c & 7) + '0';
   404  	}
   405  	*p = 0;
   406  	return fmtstrcpy(fp, str);
   407  }