The Go Programming Language

Text file src/libmach/5db.c

     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+%lux", 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	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.