github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/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  	if(fp->flags & FmtSharp) {
    87  		char *s = str;
    88  		s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, p->as);
    89  		if(p->from.type != D_NONE)
    90  			s += sprint(s, " from={%#D}", &p->from);
    91  		if(p->reg)
    92  			s += sprint(s, " reg=%d", p->reg);
    93  		if(p->to.type != D_NONE)
    94  			sprint(s, " to={%#D}", &p->to);
    95  		return fmtstrcpy(fp, str);
    96  	}
    97  
    98  	switch(p->as) {
    99  	case ADATA:
   100  		sprint(str, "%.5lld (%L)	%A	%D/%d,%D",
   101  			p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
   102  		break;
   103  
   104  	case ATEXT:
   105  		if(p->from.scale) {
   106  			sprint(str, "%.5lld (%L)	%A	%D,%d,%lD",
   107  				p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
   108  			break;
   109  		}
   110  		sprint(str, "%.5lld (%L)	%A	%D,%lD",
   111  			p->pc, p->lineno, p->as, &p->from, &p->to);
   112  		break;
   113  
   114  	default:
   115  		sprint(str, "%.5lld (%L)	%A	%D,%D",
   116  			p->pc, p->lineno, p->as, &p->from, &p->to);
   117  		break;
   118  	}
   119  	bigP = nil;
   120  	return fmtstrcpy(fp, str);
   121  }
   122  
   123  static int
   124  Aconv(Fmt *fp)
   125  {
   126  	int i;
   127  
   128  	i = va_arg(fp->args, int);
   129  	return fmtstrcpy(fp, anames6[i]);
   130  }
   131  
   132  static int
   133  Dconv(Fmt *fp)
   134  {
   135  	char str[STRINGSZ], s[STRINGSZ];
   136  	Addr *a;
   137  	int i;
   138  
   139  	a = va_arg(fp->args, Addr*);
   140  	i = a->type;
   141  
   142  	if(fp->flags & FmtSharp) {
   143  		char *s = str;
   144  		s += sprint(s, "type=");
   145  		if(i == D_NONE) {
   146  			sprint(s, "NONE");
   147  			goto brk;
   148  		}
   149  		if(i >= D_INDIR) {
   150  			i -= D_INDIR;
   151  			s += sprint(s, "INDIR+");
   152  		}
   153  		if(i >= 0 && i < D_LAST && dnames6[i] != nil)
   154  			s += sprint(s, "%s ", dnames6[i]);
   155  		else
   156  			s += sprint(s, "%d ", i);
   157  		s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width);
   158  		if(a->class != 0)
   159  			s += sprint(s, " class=%s", cnames9[(int)a->class]);
   160  		if(a->sym != nil)
   161  			s += sprint(s, " sym=%s", a->sym->name);
   162  		if(a->type == D_BRANCH && a->u.branch != nil)
   163  			sprint(s, " branch=%.5lld", a->u.branch->pc);
   164  		goto brk;
   165  	}
   166  
   167  	if(fp->flags & FmtLong) {
   168  		if(i == D_CONST)
   169  			sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32);
   170  		else {
   171  			// ATEXT dst is not constant
   172  			sprint(str, "!!%D", a);
   173  		}
   174  		goto brk;
   175  	}
   176  
   177  	if(i >= D_INDIR) {
   178  		if(a->offset)
   179  			sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
   180  		else
   181  			sprint(str, "(%R)", i-D_INDIR);
   182  		goto brk;
   183  	}
   184  	switch(i) {
   185  	default:
   186  		if(a->offset)
   187  			sprint(str, "$%lld,%R", a->offset, i);
   188  		else
   189  			sprint(str, "%R", i);
   190  		break;
   191  
   192  	case D_NONE:
   193  		str[0] = 0;
   194  		break;
   195  
   196  	case D_BRANCH:
   197  		if(a->sym != nil)
   198  			sprint(str, "%s(SB)", a->sym->name);
   199  		else if(bigP != nil && bigP->pcond != nil)
   200  			sprint(str, "%lld", bigP->pcond->pc);
   201  		else if(a->u.branch != nil)
   202  			sprint(str, "%lld", a->u.branch->pc);
   203  		else
   204  			sprint(str, "%lld(PC)", a->offset);
   205  		break;
   206  
   207  	case D_EXTERN:
   208  		sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
   209  		break;
   210  
   211  	case D_STATIC:
   212  		sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
   213  		break;
   214  
   215  	case D_AUTO:
   216  		if(a->sym)
   217  			sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
   218  		else
   219  			sprint(str, "%lld(SP)", a->offset);
   220  		break;
   221  
   222  	case D_PARAM:
   223  		if(a->sym)
   224  			sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
   225  		else
   226  			sprint(str, "%lld(FP)", a->offset);
   227  		break;
   228  
   229  	case D_CONST:
   230  		sprint(str, "$%lld", a->offset);
   231  		break;
   232  
   233  	case D_FCONST:
   234  		sprint(str, "$(%.17g)", a->u.dval);
   235  		break;
   236  
   237  	case D_SCONST:
   238  		sprint(str, "$\"%$\"", a->u.sval);
   239  		break;
   240  
   241  	case D_ADDR:
   242  		a->type = a->index;
   243  		a->index = D_NONE;
   244  		sprint(str, "$%D", a);
   245  		a->index = a->type;
   246  		a->type = D_ADDR;
   247  		goto conv;
   248  	}
   249  brk:
   250  	if(a->index != D_NONE) {
   251  		sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
   252  		strcat(str, s);
   253  	}
   254  conv:
   255  	return fmtstrcpy(fp, str);
   256  }
   257  
   258  static char*	regstr[] =
   259  {
   260  	"AL",	/* [D_AL] */
   261  	"CL",
   262  	"DL",
   263  	"BL",
   264  	"SPB",
   265  	"BPB",
   266  	"SIB",
   267  	"DIB",
   268  	"R8B",
   269  	"R9B",
   270  	"R10B",
   271  	"R11B",
   272  	"R12B",
   273  	"R13B",
   274  	"R14B",
   275  	"R15B",
   276  
   277  	"AX",	/* [D_AX] */
   278  	"CX",
   279  	"DX",
   280  	"BX",
   281  	"SP",
   282  	"BP",
   283  	"SI",
   284  	"DI",
   285  	"R8",
   286  	"R9",
   287  	"R10",
   288  	"R11",
   289  	"R12",
   290  	"R13",
   291  	"R14",
   292  	"R15",
   293  
   294  	"AH",
   295  	"CH",
   296  	"DH",
   297  	"BH",
   298  
   299  	"F0",	/* [D_F0] */
   300  	"F1",
   301  	"F2",
   302  	"F3",
   303  	"F4",
   304  	"F5",
   305  	"F6",
   306  	"F7",
   307  
   308  	"M0",
   309  	"M1",
   310  	"M2",
   311  	"M3",
   312  	"M4",
   313  	"M5",
   314  	"M6",
   315  	"M7",
   316  
   317  	"X0",
   318  	"X1",
   319  	"X2",
   320  	"X3",
   321  	"X4",
   322  	"X5",
   323  	"X6",
   324  	"X7",
   325  	"X8",
   326  	"X9",
   327  	"X10",
   328  	"X11",
   329  	"X12",
   330  	"X13",
   331  	"X14",
   332  	"X15",
   333  
   334  	"CS",	/* [D_CS] */
   335  	"SS",
   336  	"DS",
   337  	"ES",
   338  	"FS",
   339  	"GS",
   340  
   341  	"GDTR",	/* [D_GDTR] */
   342  	"IDTR",	/* [D_IDTR] */
   343  	"LDTR",	/* [D_LDTR] */
   344  	"MSW",	/* [D_MSW] */
   345  	"TASK",	/* [D_TASK] */
   346  
   347  	"CR0",	/* [D_CR] */
   348  	"CR1",
   349  	"CR2",
   350  	"CR3",
   351  	"CR4",
   352  	"CR5",
   353  	"CR6",
   354  	"CR7",
   355  	"CR8",
   356  	"CR9",
   357  	"CR10",
   358  	"CR11",
   359  	"CR12",
   360  	"CR13",
   361  	"CR14",
   362  	"CR15",
   363  
   364  	"DR0",	/* [D_DR] */
   365  	"DR1",
   366  	"DR2",
   367  	"DR3",
   368  	"DR4",
   369  	"DR5",
   370  	"DR6",
   371  	"DR7",
   372  
   373  	"TR0",	/* [D_TR] */
   374  	"TR1",
   375  	"TR2",
   376  	"TR3",
   377  	"TR4",
   378  	"TR5",
   379  	"TR6",
   380  	"TR7",
   381  
   382  	"TLS",	/* [D_TLS] */
   383  	"NONE",	/* [D_NONE] */
   384  };
   385  
   386  static int
   387  Rconv(Fmt *fp)
   388  {
   389  	char str[STRINGSZ];
   390  	int r;
   391  
   392  	r = va_arg(fp->args, int);
   393  	if(r >= D_AL && r <= D_NONE)
   394  		sprint(str, "%s", regstr[r-D_AL]);
   395  	else
   396  		sprint(str, "gok(%d)", r);
   397  
   398  	return fmtstrcpy(fp, str);
   399  }
   400  
   401  static int
   402  DSconv(Fmt *fp)
   403  {
   404  	int i, c;
   405  	char str[STRINGSZ], *p, *a;
   406  
   407  	a = va_arg(fp->args, char*);
   408  	p = str;
   409  	for(i=0; i<sizeof(double); i++) {
   410  		c = a[i] & 0xff;
   411  		if(c >= 'a' && c <= 'z' ||
   412  		   c >= 'A' && c <= 'Z' ||
   413  		   c >= '0' && c <= '9') {
   414  			*p++ = c;
   415  			continue;
   416  		}
   417  		*p++ = '\\';
   418  		switch(c) {
   419  		default:
   420  			if(c < 040 || c >= 0177)
   421  				break;	/* not portable */
   422  			p[-1] = c;
   423  			continue;
   424  		case 0:
   425  			*p++ = 'z';
   426  			continue;
   427  		case '\\':
   428  		case '"':
   429  			*p++ = c;
   430  			continue;
   431  		case '\n':
   432  			*p++ = 'n';
   433  			continue;
   434  		case '\t':
   435  			*p++ = 't';
   436  			continue;
   437  		}
   438  		*p++ = (c>>6) + '0';
   439  		*p++ = ((c>>3) & 7) + '0';
   440  		*p++ = (c & 7) + '0';
   441  	}
   442  	*p = 0;
   443  	return fmtstrcpy(fp, str);
   444  }