Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/libmach/5db.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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