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

     1  // Inferno libmach/5db.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/libmach/5db.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  #include <u.h>
    30  #include <libc.h>
    31  #include <bio.h>
    32  #include "ureg_arm.h"
    33  #include <mach.h>
    34  
    35  static int debug = 0;
    36  
    37  #define	BITS(a, b)	((1<<(b+1))-(1<<a))
    38  
    39  #define LSR(v, s)	((ulong)(v) >> (s))
    40  #define ASR(v, s)	((long)(v) >> (s))
    41  #define ROR(v, s)	(LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
    42  
    43  
    44  
    45  typedef struct	Instr	Instr;
    46  struct	Instr
    47  {
    48  	Map	*map;
    49  	ulong	w;
    50  	ulong	addr;
    51  	uchar	op;			/* super opcode */
    52  
    53  	uchar	cond;			/* bits 28-31 */
    54  	uchar	store;			/* bit 20 */
    55  
    56  	uchar	rd;			/* bits 12-15 */
    57  	uchar	rn;			/* bits 16-19 */
    58  	uchar	rs;			/* bits 0-11 (shifter operand) */
    59  
    60  	long	imm;			/* rotated imm */
    61  	char*	curr;			/* fill point in buffer */
    62  	char*	end;			/* end of buffer */
    63  	char*	err;			/* error message */
    64  };
    65  
    66  typedef struct Opcode Opcode;
    67  struct Opcode
    68  {
    69  	char*	o;
    70  	void	(*fmt)(Opcode*, Instr*);
    71  	ulong	(*foll)(Map*, Rgetter, Instr*, ulong);
    72  	char*	a;
    73  };
    74  
    75  static	void	format(char*, Instr*, char*);
    76  static	char	FRAMENAME[] = ".frame";
    77  
    78  /*
    79   * Arm-specific debugger interface
    80   */
    81  
    82  extern	char	*armexcep(Map*, Rgetter);
    83  static	int	armfoll(Map*, uvlong, Rgetter, uvlong*);
    84  static	int	arminst(Map*, uvlong, char, char*, int);
    85  static	int	armdas(Map*, uvlong, char*, int);
    86  static	int	arminstlen(Map*, uvlong);
    87  
    88  /*
    89   *	Debugger interface
    90   */
    91  Machdata armmach =
    92  {
    93  	{0, 0, 0, 0xD},		/* break point */
    94  	4,			/* break point size */
    95  
    96  	leswab,			/* short to local byte order */
    97  	leswal,			/* long to local byte order */
    98  	leswav,			/* long to local byte order */
    99  	risctrace,		/* C traceback */
   100  	riscframe,		/* Frame finder */
   101  	armexcep,			/* print exception */
   102  	0,			/* breakpoint fixup */
   103  	0,			/* single precision float printer */
   104  	0,			/* double precision float printer */
   105  	armfoll,		/* following addresses */
   106  	arminst,		/* print instruction */
   107  	armdas,			/* dissembler */
   108  	arminstlen,		/* instruction size */
   109  };
   110  
   111  char*
   112  armexcep(Map *map, Rgetter rget)
   113  {
   114  	long c;
   115  
   116  	c = (*rget)(map, "TYPE");
   117  	switch (c&0x1f) {
   118  	case 0x11:
   119  		return "Fiq interrupt";
   120  	case 0x12:
   121  		return "Mirq interrupt";
   122  	case 0x13:
   123  		return "SVC/SWI Exception";
   124  	case 0x17:
   125  		return "Prefetch Abort/Data Abort";
   126  	case 0x18:
   127  		return "Data Abort";
   128  	case 0x1b:
   129  		return "Undefined instruction/Breakpoint";
   130  	case 0x1f:
   131  		return "Sys trap";
   132  	default:
   133  		return "Undefined trap";
   134  	}
   135  }
   136  
   137  static
   138  char*	cond[16] =
   139  {
   140  	"EQ",	"NE",	"CS",	"CC",
   141  	"MI",	"PL",	"VS",	"VC",
   142  	"HI",	"LS",	"GE",	"LT",
   143  	"GT",	"LE",	0,	"NV"
   144  };
   145  
   146  static
   147  char*	shtype[4] =
   148  {
   149  	"<<",	">>",	"->",	"@>"
   150  };
   151  
   152  static
   153  char *hb[4] =
   154  {
   155  	"???",	"HU", "B", "H"
   156  };
   157  
   158  static
   159  char*	addsub[2] =
   160  {
   161  	"-",	"+",
   162  };
   163  
   164  int
   165  armclass(long w)
   166  {
   167  	int op;
   168  
   169  	op = (w >> 25) & 0x7;
   170  	switch(op) {
   171  	case 0:	/* data processing r,r,r */
   172  		op = ((w >> 4) & 0xf);
   173  		if(op == 0x9) {
   174  			op = 48+16;		/* mul */
   175  			if(w & (1<<24)) {
   176  				op += 2;
   177  				if(w & (1<<22))
   178  					op++;	/* swap */
   179  				break;
   180  			}
   181  			if(w & (1<<21))
   182  				op++;		/* mla */
   183  			break;
   184  		}
   185  		if ((op & 0x9) == 0x9)		/* ld/st byte/half s/u */
   186  		{
   187  			op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
   188  			break;
   189  		}
   190  		op = (w >> 21) & 0xf;
   191  		if(w & (1<<4))
   192  			op += 32;
   193  		else
   194  		if(w & (31<<7))
   195  			op += 16;
   196  		break;
   197  	case 1:	/* data processing i,r,r */
   198  		op = (48) + ((w >> 21) & 0xf);
   199  		break;
   200  	case 2:	/* load/store byte/word i(r) */
   201  		op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
   202  		break;
   203  	case 3:	/* load/store byte/word (r)(r) */
   204  		op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
   205  		break;
   206  	case 4:	/* block data transfer (r)(r) */
   207  		op = (48+24+4+4) + ((w >> 20) & 0x1);
   208  		break;
   209  	case 5:	/* branch / branch link */
   210  		op = (48+24+4+4+2) + ((w >> 24) & 0x1);
   211  		break;
   212  	case 7:	/* coprocessor crap */
   213  		op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
   214  		break;
   215  	default:
   216  		op = (48+24+4+4+2+2+4);
   217  		break;
   218  	}
   219  	return op;
   220  }
   221  
   222  static int
   223  decode(Map *map, ulong pc, Instr *i)
   224  {
   225  	uint32 w;
   226  
   227  	if(get4(map, pc, &w) < 0) {
   228  		werrstr("can't read instruction: %r");
   229  		return -1;
   230  	}
   231  	i->w = w;
   232  	i->addr = pc;
   233  	i->cond = (w >> 28) & 0xF;
   234  	i->op = armclass(w);
   235  	i->map = map;
   236  	return 1;
   237  }
   238  
   239  static void
   240  bprint(Instr *i, char *fmt, ...)
   241  {
   242  	va_list arg;
   243  
   244  	va_start(arg, fmt);
   245  	i->curr = vseprint(i->curr, i->end, fmt, arg);
   246  	va_end(arg);
   247  }
   248  
   249  static int
   250  plocal(Instr *i)
   251  {
   252  	char *reg;
   253  	Symbol s;
   254  	char *fn;
   255  	int class;
   256  	int offset;
   257  
   258  	if(!findsym(i->addr, CTEXT, &s)) {
   259  		if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr);
   260  		return 0;
   261  	}
   262  	fn = s.name;
   263  	if (!findlocal(&s, FRAMENAME, &s)) {
   264  		if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
   265  			return 0;
   266  	}
   267  	if(s.value > i->imm) {
   268  		class = CAUTO;
   269  		offset = s.value-i->imm;
   270  		reg = "(SP)";
   271  	} else {
   272  		class = CPARAM;
   273  		offset = i->imm-s.value-4;
   274  		reg = "(FP)";
   275  	}
   276  	if(!getauto(&s, offset, class, &s)) {
   277  		if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
   278  			class == CAUTO ? " auto" : "param", offset);
   279  		return 0;
   280  	}
   281  	bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
   282  	return 1;
   283  }
   284  
   285  /*
   286   * Print value v as name[+offset]
   287   */
   288  int
   289  gsymoff(char *buf, int n, long v, int space)
   290  {
   291  	Symbol s;
   292  	int r;
   293  	long delta;
   294  
   295  	r = delta = 0;		/* to shut compiler up */
   296  	if (v) {
   297  		r = findsym(v, space, &s);
   298  		if (r)
   299  			delta = v-s.value;
   300  		if (delta < 0)
   301  			delta = -delta;
   302  	}
   303  	if (v == 0 || r == 0 || delta >= 4096)
   304  		return snprint(buf, n, "#%lux", v);
   305  	if (strcmp(s.name, ".string") == 0)
   306  		return snprint(buf, n, "#%lux", v);
   307  	if (!delta)
   308  		return snprint(buf, n, "%s", s.name);
   309  	if (s.type != 't' && s.type != 'T')
   310  		return snprint(buf, n, "%s+%llux", s.name, v-s.value);
   311  	else
   312  		return snprint(buf, n, "#%lux", v);
   313  }
   314  
   315  static void
   316  armdps(Opcode *o, Instr *i)
   317  {
   318  	i->store = (i->w >> 20) & 1;
   319  	i->rn = (i->w >> 16) & 0xf;
   320  	i->rd = (i->w >> 12) & 0xf;
   321  	i->rs = (i->w >> 0) & 0xf;
   322  	if(i->rn == 15 && i->rs == 0) {
   323  		if(i->op == 8) {
   324  			format("MOVW", i,"CPSR, R%d");
   325  			return;
   326  		} else
   327  		if(i->op == 10) {
   328  			format("MOVW", i,"SPSR, R%d");
   329  			return;
   330  		}
   331  	} else
   332  	if(i->rn == 9 && i->rd == 15) {
   333  		if(i->op == 9) {
   334  			format("MOVW", i, "R%s, CPSR");
   335  			return;
   336  		} else
   337  		if(i->op == 11) {
   338  			format("MOVW", i, "R%s, SPSR");
   339  			return;
   340  		}
   341  	}
   342  	format(o->o, i, o->a);
   343  }
   344  
   345  static void
   346  armdpi(Opcode *o, Instr *i)
   347  {
   348  	ulong v;
   349  	int c;
   350  
   351  	v = (i->w >> 0) & 0xff;
   352  	c = (i->w >> 8) & 0xf;
   353  	while(c) {
   354  		v = (v<<30) | (v>>2);
   355  		c--;
   356  	}
   357  	i->imm = v;
   358  	i->store = (i->w >> 20) & 1;
   359  	i->rn = (i->w >> 16) & 0xf;
   360  	i->rd = (i->w >> 12) & 0xf;
   361  	i->rs = i->w&0x0f;
   362  
   363  		/* RET is encoded as ADD #0,R14,R15 */
   364  	if((i->w & 0x0fffffff) == 0x028ef000){
   365  		format("RET%C", i, "");
   366  		return;
   367  	}
   368  	if((i->w & 0x0ff0ffff) == 0x0280f000){
   369  		format("B%C", i, "0(R%n)");
   370  		return;
   371  	}
   372  	format(o->o, i, o->a);
   373  }
   374  
   375  static void
   376  armsdti(Opcode *o, Instr *i)
   377  {
   378  	ulong v;
   379  
   380  	v = i->w & 0xfff;
   381  	if(!(i->w & (1<<23)))
   382  		v = -v;
   383  	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
   384  	i->imm = v;
   385  	i->rn = (i->w >> 16) & 0xf;
   386  	i->rd = (i->w >> 12) & 0xf;
   387  		/* RET is encoded as LW.P x,R13,R15 */
   388  	if ((i->w & 0x0ffff000) == 0x049df000)
   389  	{
   390  		format("RET%C%p", i, "%I");
   391  		return;
   392  	}
   393  	format(o->o, i, o->a);
   394  }
   395  
   396  /* arm V4 ld/st halfword, signed byte */
   397  static void
   398  armhwby(Opcode *o, Instr *i)
   399  {
   400  	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
   401  	i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
   402  	if (!(i->w & (1 << 23)))
   403  		i->imm = - i->imm;
   404  	i->rn = (i->w >> 16) & 0xf;
   405  	i->rd = (i->w >> 12) & 0xf;
   406  	i->rs = (i->w >> 0) & 0xf;
   407  	format(o->o, i, o->a);
   408  }
   409  
   410  static void
   411  armsdts(Opcode *o, Instr *i)
   412  {
   413  	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
   414  	i->rs = (i->w >> 0) & 0xf;
   415  	i->rn = (i->w >> 16) & 0xf;
   416  	i->rd = (i->w >> 12) & 0xf;
   417  	format(o->o, i, o->a);
   418  }
   419  
   420  static void
   421  armbdt(Opcode *o, Instr *i)
   422  {
   423  	i->store = (i->w >> 21) & 0x3;		/* S & W bits */
   424  	i->rn = (i->w >> 16) & 0xf;
   425  	i->imm = i->w & 0xffff;
   426  	if(i->w == 0xe8fd8000)
   427  		format("RFE", i, "");
   428  	else
   429  		format(o->o, i, o->a);
   430  }
   431  
   432  /*
   433  static void
   434  armund(Opcode *o, Instr *i)
   435  {
   436  	format(o->o, i, o->a);
   437  }
   438  
   439  static void
   440  armcdt(Opcode *o, Instr *i)
   441  {
   442  	format(o->o, i, o->a);
   443  }
   444  */
   445  
   446  static void
   447  armunk(Opcode *o, Instr *i)
   448  {
   449  	format(o->o, i, o->a);
   450  }
   451  
   452  static void
   453  armb(Opcode *o, Instr *i)
   454  {
   455  	ulong v;
   456  
   457  	v = i->w & 0xffffff;
   458  	if(v & 0x800000)
   459  		v |= ~0xffffff;
   460  	i->imm = (v<<2) + i->addr + 8;
   461  	format(o->o, i, o->a);
   462  }
   463  
   464  static void
   465  armco(Opcode *o, Instr *i)		/* coprocessor instructions */
   466  {
   467  	int op, p, cp;
   468  
   469  	char buf[1024];
   470  
   471  	i->rn = (i->w >> 16) & 0xf;
   472  	i->rd = (i->w >> 12) & 0xf;
   473  	i->rs = i->w&0xf;
   474  	cp = (i->w >> 8) & 0xf;
   475  	p = (i->w >> 5) & 0x7;
   476  	if(i->w&(1<<4)) {
   477  		op = (i->w >> 21) & 0x07;
   478  		snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
   479  	} else {
   480  		op = (i->w >> 20) & 0x0f;
   481  		snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
   482  	}
   483  	format(o->o, i, buf);
   484  }
   485  
   486  static int
   487  armcondpass(Map *map, Rgetter rget, uchar cond)
   488  {
   489  	ulong psr;
   490  	uchar n;
   491  	uchar z;
   492  	uchar c;
   493  	uchar v;
   494  
   495  	psr = rget(map, "PSR");
   496  	n = (psr >> 31) & 1;
   497  	z = (psr >> 30) & 1;
   498  	c = (psr >> 29) & 1;
   499  	v = (psr >> 28) & 1;
   500  
   501  	switch(cond) {
   502  		case 0:		return z;
   503  		case 1:		return !z;
   504  		case 2:		return c;
   505  		case 3:		return !c;
   506  		case 4:		return n;
   507  		case 5:		return !n;
   508  		case 6:		return v;
   509  		case 7:		return !v;
   510  		case 8:		return c && !z;
   511  		case 9:		return !c || z;
   512  		case 10:	return n == v;
   513  		case 11:	return n != v;
   514  		case 12:	return !z && (n == v);
   515  		case 13:	return z && (n != v);
   516  		case 14:	return 1;
   517  		case 15:	return 0;
   518  	}
   519  	return 0;
   520  }
   521  
   522  static ulong
   523  armshiftval(Map *map, Rgetter rget, Instr *i)
   524  {
   525  	if(i->w & (1 << 25)) {				/* immediate */
   526  		ulong imm = i->w & BITS(0, 7);
   527  		ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
   528  		return ROR(imm, s);
   529  	} else {
   530  		char buf[8];
   531  		ulong v;
   532  		ulong s = (i->w & BITS(7,11)) >> 7;
   533  
   534  		sprint(buf, "R%ld", i->w & 0xf);
   535  		v = rget(map, buf);
   536  
   537  		switch((i->w & BITS(4, 6)) >> 4) {
   538  		case 0:					/* LSLIMM */
   539  			return v << s;
   540  		case 1:					/* LSLREG */
   541  			sprint(buf, "R%lud", s >> 1);
   542  			s = rget(map, buf) & 0xFF;
   543  			if(s >= 32) return 0;
   544  			return v << s;
   545  		case 2:					/* LSRIMM */
   546  			return LSR(v, s);
   547  		case 3:					/* LSRREG */
   548  			sprint(buf, "R%ld", s >> 1);
   549  			s = rget(map, buf) & 0xFF;
   550  			if(s >= 32) return 0;
   551  			return LSR(v, s);
   552  		case 4:					/* ASRIMM */
   553  			if(s == 0) {
   554  				if((v & (1U<<31)) == 0)
   555  					return 0;
   556  				return 0xFFFFFFFF;
   557  			}
   558  			return ASR(v, s);
   559  		case 5:					/* ASRREG */
   560  			sprint(buf, "R%ld", s >> 1);
   561  			s = rget(map, buf) & 0xFF;
   562  			if(s >= 32) {
   563  				if((v & (1U<<31)) == 0)
   564  					return 0;
   565  				return 0xFFFFFFFF;
   566  			}
   567  			return ASR(v, s);
   568  		case 6:					/* RORIMM */
   569  			if(s == 0) {
   570  				ulong c = (rget(map, "PSR") >> 29) & 1;
   571  
   572  				return (c << 31) | LSR(v, 1);
   573  			}
   574  			return ROR(v, s);
   575  		case 7:					/* RORREG */
   576  			sprint(buf, "R%ld", (s>>1)&0xF);
   577  			s = rget(map, buf);
   578  			if(s == 0 || (s & 0xF) == 0)
   579  				return v;
   580  			return ROR(v, s & 0xF);
   581  		}
   582  	}
   583  	return 0;
   584  }
   585  
   586  static int
   587  nbits(ulong v)
   588  {
   589  	int n = 0;
   590  	int i;
   591  
   592  	for(i=0; i < 32 ; i++) {
   593  		if(v & 1) ++n;
   594  		v >>= 1;
   595  	}
   596  
   597  	return n;
   598  }
   599  
   600  static ulong
   601  armmaddr(Map *map, Rgetter rget, Instr *i)
   602  {
   603  	ulong v;
   604  	ulong nb;
   605  	char buf[8];
   606  	ulong rn;
   607  
   608  	rn = (i->w >> 16) & 0xf;
   609  	sprint(buf,"R%ld", rn);
   610  
   611  	v = rget(map, buf);
   612  	nb = nbits(i->w & ((1 << 15) - 1));
   613  
   614  	switch((i->w >> 23) & 3) {
   615  		case 0: return (v - (nb*4)) + 4;
   616  		case 1: return v;
   617  		case 2: return v - (nb*4);
   618  		case 3: return v + 4;
   619  	}
   620  	return 0;
   621  }
   622  
   623  static ulong
   624  armaddr(Map *map, Rgetter rget, Instr *i)
   625  {
   626  	char buf[8];
   627  	ulong rn;
   628  
   629  	sprint(buf, "R%ld", (i->w >> 16) & 0xf);
   630  	rn = rget(map, buf);
   631  
   632  	if((i->w & (1<<24)) == 0) {			/* POSTIDX */
   633  		sprint(buf, "R%ld", rn);
   634  		return rget(map, buf);
   635  	}
   636  
   637  	if((i->w & (1<<25)) == 0) {			/* OFFSET */
   638  		sprint(buf, "R%ld", rn);
   639  		if(i->w & (1U<<23))
   640  			return rget(map, buf) + (i->w & BITS(0,11));
   641  		return rget(map, buf) - (i->w & BITS(0,11));
   642  	} else {					/* REGOFF */
   643  		ulong index = 0;
   644  		uchar c;
   645  		uchar rm;
   646  
   647  		sprint(buf, "R%ld", i->w & 0xf);
   648  		rm = rget(map, buf);
   649  
   650  		switch((i->w & BITS(5,6)) >> 5) {
   651  		case 0: index = rm << ((i->w & BITS(7,11)) >> 7);	break;
   652  		case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7));	break;
   653  		case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7));	break;
   654  		case 3:
   655  			if((i->w & BITS(7,11)) == 0) {
   656  				c = (rget(map, "PSR") >> 29) & 1;
   657  				index = c << 31 | LSR(rm, 1);
   658  			} else {
   659  				index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
   660  			}
   661  			break;
   662  		}
   663  		if(i->w & (1<<23))
   664  			return rn + index;
   665  		return rn - index;
   666  	}
   667  }
   668  
   669  static ulong
   670  armfadd(Map *map, Rgetter rget, Instr *i, ulong pc)
   671  {
   672  	char buf[8];
   673  	int r;
   674  
   675  	r = (i->w >> 12) & 0xf;
   676  	if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
   677  		return pc+4;
   678  
   679  	r = (i->w >> 16) & 0xf;
   680  	sprint(buf, "R%d", r);
   681  
   682  	return rget(map, buf) + armshiftval(map, rget, i);
   683  }
   684  
   685  static ulong
   686  armfmovm(Map *map, Rgetter rget, Instr *i, ulong pc)
   687  {
   688  	uint32 v;
   689  	ulong addr;
   690  
   691  	v = i->w & 1<<15;
   692  	if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
   693  		return pc+4;
   694  
   695  	addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
   696  	if(get4(map, addr, &v) < 0) {
   697  		werrstr("can't read addr: %r");
   698  		return -1;
   699  	}
   700  	return v;
   701  }
   702  
   703  static ulong
   704  armfbranch(Map *map, Rgetter rget, Instr *i, ulong pc)
   705  {
   706  	if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
   707  		return pc+4;
   708  
   709  	return pc + (((signed long)i->w << 8) >> 6) + 8;
   710  }
   711  
   712  static ulong
   713  armfmov(Map *map, Rgetter rget, Instr *i, ulong pc)
   714  {
   715  	ulong rd;
   716  	uint32 v;
   717  
   718  	rd = (i->w >> 12) & 0xf;
   719  	if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
   720  		return pc+4;
   721  
   722  	 /* LDR */
   723  	/* BUG: Needs LDH/B, too */
   724  	if(((i->w>>26)&0x3) == 1) {
   725  		if(get4(map, armaddr(map, rget, i), &v) < 0) {
   726  			werrstr("can't read instruction: %r");
   727  			return pc+4;
   728  		}
   729  		return v;
   730  	}
   731  
   732  	 /* MOV */
   733  	return armshiftval(map, rget, i);
   734  }
   735  
   736  static Opcode opcodes[] =
   737  {
   738  	"AND%C%S",	armdps, 0,	"R%s,R%n,R%d",
   739  	"EOR%C%S",	armdps, 0,	"R%s,R%n,R%d",
   740  	"SUB%C%S",	armdps, 0,	"R%s,R%n,R%d",
   741  	"RSB%C%S",	armdps, 0,	"R%s,R%n,R%d",
   742  	"ADD%C%S",	armdps, armfadd,	"R%s,R%n,R%d",
   743  	"ADC%C%S",	armdps, 0,	"R%s,R%n,R%d",
   744  	"SBC%C%S",	armdps, 0,	"R%s,R%n,R%d",
   745  	"RSC%C%S",	armdps, 0,	"R%s,R%n,R%d",
   746  	"TST%C%S",	armdps, 0,	"R%s,R%n",
   747  	"TEQ%C%S",	armdps, 0,	"R%s,R%n",
   748  	"CMP%C%S",	armdps, 0,	"R%s,R%n",
   749  	"CMN%C%S",	armdps, 0,	"R%s,R%n",
   750  	"ORR%C%S",	armdps, 0,	"R%s,R%n,R%d",
   751  	"MOVW%C%S",	armdps, armfmov,	"R%s,R%d",
   752  	"BIC%C%S",	armdps, 0,	"R%s,R%n,R%d",
   753  	"MVN%C%S",	armdps, 0,	"R%s,R%d",
   754  
   755  /* 16 */
   756  	"AND%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   757  	"EOR%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   758  	"SUB%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   759  	"RSB%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   760  	"ADD%C%S",	armdps, armfadd,	"(R%s%h%m),R%n,R%d",
   761  	"ADC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   762  	"SBC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   763  	"RSC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   764  	"TST%C%S",	armdps, 0,	"(R%s%h%m),R%n",
   765  	"TEQ%C%S",	armdps, 0,	"(R%s%h%m),R%n",
   766  	"CMP%C%S",	armdps, 0,	"(R%s%h%m),R%n",
   767  	"CMN%C%S",	armdps, 0,	"(R%s%h%m),R%n",
   768  	"ORR%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   769  	"MOVW%C%S",	armdps, armfmov,	"(R%s%h%m),R%d",
   770  	"BIC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
   771  	"MVN%C%S",	armdps, 0,	"(R%s%h%m),R%d",
   772  
   773  /* 32 */
   774  	"AND%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   775  	"EOR%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   776  	"SUB%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   777  	"RSB%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   778  	"ADD%C%S",	armdps, armfadd,	"(R%s%hR%M),R%n,R%d",
   779  	"ADC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   780  	"SBC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   781  	"RSC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   782  	"TST%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
   783  	"TEQ%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
   784  	"CMP%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
   785  	"CMN%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
   786  	"ORR%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   787  	"MOVW%C%S",	armdps, armfmov,	"(R%s%hR%M),R%d",
   788  	"BIC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
   789  	"MVN%C%S",	armdps, 0,	"(R%s%hR%M),R%d",
   790  
   791  /* 48 */
   792  	"AND%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   793  	"EOR%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   794  	"SUB%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   795  	"RSB%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   796  	"ADD%C%S",	armdpi, armfadd,	"$#%i,R%n,R%d",
   797  	"ADC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   798  	"SBC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   799  	"RSC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   800  	"TST%C%S",	armdpi, 0,	"$#%i,R%n",
   801  	"TEQ%C%S",	armdpi, 0,	"$#%i,R%n",
   802  	"CMP%C%S",	armdpi, 0,	"$#%i,R%n",
   803  	"CMN%C%S",	armdpi, 0,	"$#%i,R%n",
   804  	"ORR%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   805  	"MOVW%C%S",	armdpi, armfmov,	"$#%i,R%d",
   806  	"BIC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
   807  	"MVN%C%S",	armdpi, 0,	"$#%i,R%d",
   808  
   809  /* 48+16 */
   810  	"MUL%C%S",	armdpi, 0,	"R%s,R%M,R%n",
   811  	"MULA%C%S",	armdpi, 0,	"R%s,R%M,R%n,R%d",
   812  	"SWPW",		armdpi, 0,	"R%s,(R%n),R%d",
   813  	"SWPB",		armdpi, 0,	"R%s,(R%n),R%d",
   814  
   815  /* 48+16+4 */
   816  	"MOV%u%C%p",	armhwby, 0,	"R%d,(R%n%UR%M)",
   817  	"MOV%u%C%p",	armhwby, 0,	"R%d,%I",
   818  	"MOV%u%C%p",	armhwby, armfmov,	"(R%n%UR%M),R%d",
   819  	"MOV%u%C%p",	armhwby, armfmov,	"%I,R%d",
   820  
   821  /* 48+24 */
   822  	"MOVW%C%p",	armsdti, 0,	"R%d,%I",
   823  	"MOVB%C%p",	armsdti, 0,	"R%d,%I",
   824  	"MOVW%C%p",	armsdti, armfmov,	"%I,R%d",
   825  	"MOVBU%C%p",	armsdti, armfmov,	"%I,R%d",
   826  
   827  	"MOVW%C%p",	armsdts, 0,	"R%d,(R%s%h%m)(R%n)",
   828  	"MOVB%C%p",	armsdts, 0,	"R%d,(R%s%h%m)(R%n)",
   829  	"MOVW%C%p",	armsdts, armfmov,	"(R%s%h%m)(R%n),R%d",
   830  	"MOVBU%C%p",	armsdts, armfmov,	"(R%s%h%m)(R%n),R%d",
   831  
   832  	"MOVM%C%P%a",	armbdt, armfmovm,		"[%r],(R%n)",
   833  	"MOVM%C%P%a",	armbdt, armfmovm,		"(R%n),[%r]",
   834  
   835  	"B%C",		armb, armfbranch,		"%b",
   836  	"BL%C",		armb, armfbranch,		"%b",
   837  
   838  	"CDP%C",	armco, 0,		"",
   839  	"CDP%C",	armco, 0,		"",
   840  	"MCR%C",	armco, 0,		"",
   841  	"MRC%C",	armco, 0,		"",
   842  
   843  	"UNK",		armunk, 0,	"",
   844  };
   845  
   846  static void
   847  gaddr(Instr *i)
   848  {
   849  	*i->curr++ = '$';
   850  	i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
   851  }
   852  
   853  static	char *mode[] = { 0, "IA", "DB", "IB" };
   854  static	char *pw[] = { "P", "PW", 0, "W" };
   855  static	char *sw[] = { 0, "W", "S", "SW" };
   856  
   857  static void
   858  format(char *mnemonic, Instr *i, char *f)
   859  {
   860  	int j, k, m, n;
   861  	int g;
   862  	char *fmt;
   863  
   864  	if(mnemonic)
   865  		format(0, i, mnemonic);
   866  	if(f == 0)
   867  		return;
   868  	if(mnemonic)
   869  		if(i->curr < i->end)
   870  			*i->curr++ = '\t';
   871  	for ( ; *f && i->curr < i->end; f++) {
   872  		if(*f != '%') {
   873  			*i->curr++ = *f;
   874  			continue;
   875  		}
   876  		switch (*++f) {
   877  
   878  		case 'C':	/* .CONDITION */
   879  			if(cond[i->cond])
   880  				bprint(i, ".%s", cond[i->cond]);
   881  			break;
   882  
   883  		case 'S':	/* .STORE */
   884  			if(i->store)
   885  				bprint(i, ".S");
   886  			break;
   887  
   888  		case 'P':	/* P & U bits for block move */
   889  			n = (i->w >>23) & 0x3;
   890  			if (mode[n])
   891  				bprint(i, ".%s", mode[n]);
   892  			break;
   893  
   894  		case 'p':	/* P & W bits for single data xfer*/
   895  			if (pw[i->store])
   896  				bprint(i, ".%s", pw[i->store]);
   897  			break;
   898  
   899  		case 'a':	/* S & W bits for single data xfer*/
   900  			if (sw[i->store])
   901  				bprint(i, ".%s", sw[i->store]);
   902  			break;
   903  
   904  		case 's':
   905  			bprint(i, "%d", i->rs & 0xf);
   906  			break;
   907  
   908  		case 'M':
   909  			bprint(i, "%d", (i->w>>8) & 0xf);
   910  			break;
   911  
   912  		case 'm':
   913  			bprint(i, "%d", (i->w>>7) & 0x1f);
   914  			break;
   915  
   916  		case 'h':
   917  			bprint(i, shtype[(i->w>>5) & 0x3]);
   918  			break;
   919  
   920  		case 'u':		/* Signed/unsigned Byte/Halfword */
   921  			bprint(i, hb[(i->w>>5) & 0x3]);
   922  			break;
   923  
   924  		case 'I':
   925  			if (i->rn == 13) {
   926  				if (plocal(i))
   927  					break;
   928  			}
   929  			g = 0;
   930  			fmt = "#%lx(R%d)";
   931  			if (i->rn == 15) {
   932  				/* convert load of offset(PC) to a load immediate */
   933  				uint32 x;
   934  				if (get4(i->map, i->addr+i->imm+8, &x) > 0)
   935  				{
   936  					i->imm = (int32)x;
   937  					g = 1;
   938  					fmt = "";
   939  				}
   940  			}
   941  			if (mach->sb)
   942  			{
   943  				if (i->rd == 11) {
   944  					uint32 nxti;
   945  
   946  					if (get4(i->map, i->addr+4, &nxti) > 0) {
   947  						if ((nxti & 0x0e0f0fff) == 0x060c000b) {
   948  							i->imm += mach->sb;
   949  							g = 1;
   950  							fmt = "-SB";
   951  						}
   952  					}
   953  				}
   954  				if (i->rn == 12)
   955  				{
   956  					i->imm += mach->sb;
   957  					g = 1;
   958  					fmt = "-SB(SB)";
   959  				}
   960  			}
   961  			if (g)
   962  			{
   963  				gaddr(i);
   964  				bprint(i, fmt, i->rn);
   965  			}
   966  			else
   967  				bprint(i, fmt, i->imm, i->rn);
   968  			break;
   969  		case 'U':		/* Add/subtract from base */
   970  			bprint(i, addsub[(i->w >> 23) & 1]);
   971  			break;
   972  
   973  		case 'n':
   974  			bprint(i, "%d", i->rn);
   975  			break;
   976  
   977  		case 'd':
   978  			bprint(i, "%d", i->rd);
   979  			break;
   980  
   981  		case 'i':
   982  			bprint(i, "%lux", i->imm);
   983  			break;
   984  
   985  		case 'b':
   986  			i->curr += symoff(i->curr, i->end-i->curr,
   987  				i->imm, CTEXT);
   988  			break;
   989  
   990  		case 'g':
   991  			i->curr += gsymoff(i->curr, i->end-i->curr,
   992  				i->imm, CANY);
   993  			break;
   994  
   995  		case 'r':
   996  			n = i->imm&0xffff;
   997  			j = 0;
   998  			k = 0;
   999  			while(n) {
  1000  				m = j;
  1001  				while(n&0x1) {
  1002  					j++;
  1003  					n >>= 1;
  1004  				}
  1005  				if(j != m) {
  1006  					if(k)
  1007  						bprint(i, ",");
  1008  					if(j == m+1)
  1009  						bprint(i, "R%d", m);
  1010  					else
  1011  						bprint(i, "R%d-R%d", m, j-1);
  1012  					k = 1;
  1013  				}
  1014  				j++;
  1015  				n >>= 1;
  1016  			}
  1017  			break;
  1018  
  1019  		case '\0':
  1020  			*i->curr++ = '%';
  1021  			return;
  1022  
  1023  		default:
  1024  			bprint(i, "%%%c", *f);
  1025  			break;
  1026  		}
  1027  	}
  1028  	*i->curr = 0;
  1029  }
  1030  
  1031  static int
  1032  printins(Map *map, ulong pc, char *buf, int n)
  1033  {
  1034  	Instr i;
  1035  
  1036  	i.curr = buf;
  1037  	i.end = buf+n-1;
  1038  	if(decode(map, pc, &i) < 0)
  1039  		return -1;
  1040  
  1041  	(*opcodes[i.op].fmt)(&opcodes[i.op], &i);
  1042  	return 4;
  1043  }
  1044  
  1045  static int
  1046  arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
  1047  {
  1048  	USED(modifier);
  1049  	return printins(map, pc, buf, n);
  1050  }
  1051  
  1052  static int
  1053  armdas(Map *map, uvlong pc, char *buf, int n)
  1054  {
  1055  	Instr i;
  1056  
  1057  	i.curr = buf;
  1058  	i.end = buf+n;
  1059  	if(decode(map, pc, &i) < 0)
  1060  		return -1;
  1061  	if(i.end-i.curr > 8)
  1062  		i.curr = _hexify(buf, i.w, 7);
  1063  	*i.curr = 0;
  1064  	return 4;
  1065  }
  1066  
  1067  static int
  1068  arminstlen(Map *map, uvlong pc)
  1069  {
  1070  	Instr i;
  1071  
  1072  	if(decode(map, pc, &i) < 0)
  1073  		return -1;
  1074  	return 4;
  1075  }
  1076  
  1077  static int
  1078  armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
  1079  {
  1080  	ulong d;
  1081  	Instr i;
  1082  
  1083  	if(decode(map, pc, &i) < 0)
  1084  		return -1;
  1085  
  1086  	if(opcodes[i.op].foll) {
  1087  		d = (*opcodes[i.op].foll)(map, rget, &i, pc);
  1088  		if(d == -1)
  1089  			return -1;
  1090  	} else
  1091  		d = pc+4;
  1092  
  1093  	foll[0] = d;
  1094  	return 1;
  1095  }