]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libmach/vcodas.c
ssh: loop keyboard-interactive on failure
[plan9front.git] / sys / src / libmach / vcodas.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5
6         /* mips native disassembler */
7
8 typedef struct {
9         uvlong addr;                    /* pc of instr */
10         uchar op;                       /* bits 31-26 */
11         uchar rs;                       /* bits 25-21 */
12         uchar rt;                       /* bits 20-16 */
13         uchar rd;                       /* bits 15-11 */
14         uchar sa;                       /* bits 10-6 */
15         uchar function;                 /* bits 5-0 */
16         long immediate;                 /* bits 15-0 */
17         ulong cofun;                    /* bits 24-0 */
18         ulong target;                   /* bits 25-0 */
19         long w0;
20         char *curr;                     /* current fill point */
21         char *end;                      /* end of buffer */
22         char *err;
23 } Instr;
24
25 typedef struct {
26         char *mnemonic;
27         char *mipsco;
28 } Opcode;
29
30 static char mipscoload[] = "r%t,%l";
31 static char mipscoalui[] = "r%t,r%s,%i";
32 static char mipscoalu3op[] = "r%d,r%s,r%t";
33 static char mipscoboc[] = "r%s,r%t,%b";
34 static char mipscoboc0[] = "r%s,%b";
35 static char mipscorsrt[] = "r%s,r%t";
36 static char mipscorsi[] = "r%s,%i";
37 static char mipscoxxx[] = "%w";
38 static char mipscofp3[] = "f%a,f%d,f%t";        /* fd,fs,ft */
39 static char mipscofp2[] = "f%a,f%d";            /* fd,fs */
40 static char mipscofpc[] = "f%d,f%t";            /* fs,ft */
41
42 static Opcode opcodes[64] = {
43         0,              0,
44         0,              0,
45         "j",            "%j",
46         "jal",          "%j",
47         "beq",          mipscoboc,
48         "bne",          mipscoboc,
49         "blez",         mipscoboc0,
50         "bgtz",         mipscoboc0,
51         "addi",         mipscoalui,
52         "addiu",        mipscoalui,
53         "slti",         mipscoalui,
54         "sltiu",        mipscoalui,
55         "andi",         mipscoalui,
56         "ori",          mipscoalui,
57         "xori",         mipscoalui,
58         "lui",          "r%t,%u",
59         "cop0",         0,
60         "cop1",         0,
61         "cop2",         0,
62         "cop3",         0,
63         "beql",         mipscoboc,
64         "bnel",         mipscoboc,
65         "blezl",        mipscoboc0,
66         "bgtzl",        mipscoboc0,
67         "instr18",      mipscoxxx,
68         "instr19",      mipscoxxx,
69         "instr1A",      mipscoxxx,
70         "instr1B",      mipscoxxx,
71         "instr1C",      mipscoxxx,
72         "instr1D",      mipscoxxx,
73         "instr1E",      mipscoxxx,
74         "instr1F",      mipscoxxx,
75         "lb",           mipscoload,
76         "lh",           mipscoload,
77         "lwl",          mipscoload,
78         "lw",           mipscoload,
79         "lbu",          mipscoload,
80         "lhu",          mipscoload,
81         "lwr",          mipscoload,
82         "instr27",      mipscoxxx,
83         "sb",           mipscoload,
84         "sh",           mipscoload,
85         "swl",          mipscoload,
86         "sw",           mipscoload,
87         "instr2C",      mipscoxxx,
88         "instr2D",      mipscoxxx,
89         "swr",          mipscoload,
90         "cache",        "",
91         "ll",           mipscoload,
92         "lwc1",         mipscoload,
93         "lwc2",         mipscoload,
94         "lwc3",         mipscoload,
95         "instr34",      mipscoxxx,
96         "ld",           mipscoload,
97         "ld",           mipscoload,
98         "ld",           mipscoload,
99         "sc",           mipscoload,
100         "swc1",         mipscoload,
101         "swc2",         mipscoload,
102         "swc3",         mipscoload,
103         "instr3C",      mipscoxxx,
104         "sd",           mipscoload,
105         "sd",           mipscoload,
106         "sd",           mipscoload,
107 };
108
109 static Opcode sopcodes[64] = {
110         "sll",          "r%d,r%t,$%a",
111         "special01",    mipscoxxx,
112         "srl",          "r%d,r%t,$%a",
113         "sra",          "r%d,r%t,$%a",
114         "sllv",         "r%d,r%t,R%s",
115         "special05",    mipscoxxx,
116         "srlv",         "r%d,r%t,r%s",
117         "srav",         "r%d,r%t,r%s",
118         "jr",           "r%s",
119         "jalr",         "r%d,r%s",
120         "special0A",    mipscoxxx,
121         "special0B",    mipscoxxx,
122         "syscall",      "",
123         "break",        "",
124         "special0E",    mipscoxxx,
125         "sync",         "",
126         "mfhi",         "r%d",
127         "mthi",         "r%s",
128         "mflo",         "r%d",
129         "mtlo",         "r%s",
130         "special14",    mipscoxxx,
131         "special15",    mipscoxxx,
132         "special16",    mipscoxxx,
133         "special17",    mipscoxxx,
134         "mult",         mipscorsrt,
135         "multu",        mipscorsrt,
136         "div",          mipscorsrt,
137         "divu",         mipscorsrt,
138         "special1C",    mipscoxxx,
139         "special1D",    mipscoxxx,
140         "special1E",    mipscoxxx,
141         "special1F",    mipscoxxx,
142         "add",          mipscoalu3op,
143         "addu",         mipscoalu3op,
144         "sub",          mipscoalu3op,
145         "subu",         mipscoalu3op,
146         "and",          mipscoalu3op,
147         "or",           mipscoalu3op,
148         "xor",          mipscoalu3op,
149         "nor",          mipscoalu3op,
150         "special28",    mipscoxxx,
151         "special29",    mipscoxxx,
152         "slt",          mipscoalu3op,
153         "sltu",         mipscoalu3op,
154         "special2C",    mipscoxxx,
155         "special2D",    mipscoxxx,
156         "special2E",    mipscoxxx,
157         "special2F",    mipscoxxx,
158         "tge",          mipscorsrt,
159         "tgeu",         mipscorsrt,
160         "tlt",          mipscorsrt,
161         "tltu",         mipscorsrt,
162         "teq",          mipscorsrt,
163         "special35",    mipscoxxx,
164         "tne",          mipscorsrt,
165         "special37",    mipscoxxx,
166         "special38",    mipscoxxx,
167         "special39",    mipscoxxx,
168         "special3A",    mipscoxxx,
169         "special3B",    mipscoxxx,
170         "special3C",    mipscoxxx,
171         "special3D",    mipscoxxx,
172         "special3E",    mipscoxxx,
173         "special3F",    mipscoxxx,
174 };
175
176 static Opcode ropcodes[32] = {
177         "bltz",         mipscoboc0,
178         "bgez",         mipscoboc0,
179         "bltzl",        mipscoboc0,
180         "bgezl",        mipscoboc0,
181         "regimm04",     mipscoxxx,
182         "regimm05",     mipscoxxx,
183         "regimm06",     mipscoxxx,
184         "regimm07",     mipscoxxx,
185         "tgei",         mipscorsi,
186         "tgeiu",        mipscorsi,
187         "tlti",         mipscorsi,
188         "tltiu",        mipscorsi,
189         "teqi",         mipscorsi,
190         "regimm0D",     mipscoxxx,
191         "tnei",         mipscorsi,
192         "regimm0F",     mipscoxxx,
193         "bltzal",       mipscoboc0,
194         "bgezal",       mipscoboc0,
195         "bltzall",      mipscoboc0,
196         "bgezall",      mipscoboc0,
197         "regimm14",     mipscoxxx,
198         "regimm15",     mipscoxxx,
199         "regimm16",     mipscoxxx,
200         "regimm17",     mipscoxxx,
201         "regimm18",     mipscoxxx,
202         "regimm19",     mipscoxxx,
203         "regimm1A",     mipscoxxx,
204         "regimm1B",     mipscoxxx,
205         "regimm1C",     mipscoxxx,
206         "regimm1D",     mipscoxxx,
207         "regimm1E",     mipscoxxx,
208         "regimm1F",     mipscoxxx,
209 };
210
211 static Opcode fopcodes[64] = {
212         "add.%f",       mipscofp3,
213         "sub.%f",       mipscofp3,
214         "mul.%f",       mipscofp3,
215         "div.%f",       mipscofp3,
216         "sqrt.%f",      mipscofp2,
217         "abs.%f",       mipscofp2,
218         "mov.%f",       mipscofp2,
219         "neg.%f",       mipscofp2,
220         "finstr08",     mipscoxxx,
221         "finstr09",     mipscoxxx,
222         "finstr0A",     mipscoxxx,
223         "finstr0B",     mipscoxxx,
224         "round.w.%f",   mipscofp2,
225         "trunc.w%f",    mipscofp2,
226         "ceil.w%f",     mipscofp2,
227         "floor.w%f",    mipscofp2,
228         "finstr10",     mipscoxxx,
229         "finstr11",     mipscoxxx,
230         "finstr12",     mipscoxxx,
231         "finstr13",     mipscoxxx,
232         "finstr14",     mipscoxxx,
233         "finstr15",     mipscoxxx,
234         "finstr16",     mipscoxxx,
235         "finstr17",     mipscoxxx,
236         "finstr18",     mipscoxxx,
237         "finstr19",     mipscoxxx,
238         "finstr1A",     mipscoxxx,
239         "finstr1B",     mipscoxxx,
240         "finstr1C",     mipscoxxx,
241         "finstr1D",     mipscoxxx,
242         "finstr1E",     mipscoxxx,
243         "finstr1F",     mipscoxxx,
244         "cvt.s.%f",     mipscofp2,
245         "cvt.d.%f",     mipscofp2,
246         "cvt.e.%f",     mipscofp2,
247         "cvt.q.%f",     mipscofp2,
248         "cvt.w.%f",     mipscofp2,
249         "finstr25",     mipscoxxx,
250         "finstr26",     mipscoxxx,
251         "finstr27",     mipscoxxx,
252         "finstr28",     mipscoxxx,
253         "finstr29",     mipscoxxx,
254         "finstr2A",     mipscoxxx,
255         "finstr2B",     mipscoxxx,
256         "finstr2C",     mipscoxxx,
257         "finstr2D",     mipscoxxx,
258         "finstr2E",     mipscoxxx,
259         "finstr2F",     mipscoxxx,
260         "c.f.%f",       mipscofpc,
261         "c.un.%f",      mipscofpc,
262         "c.eq.%f",      mipscofpc,
263         "c.ueq.%f",     mipscofpc,
264         "c.olt.%f",     mipscofpc,
265         "c.ult.%f",     mipscofpc,
266         "c.ole.%f",     mipscofpc,
267         "c.ule.%f",     mipscofpc,
268         "c.sf.%f",      mipscofpc,
269         "c.ngle.%f",    mipscofpc,
270         "c.seq.%f",     mipscofpc,
271         "c.ngl.%f",     mipscofpc,
272         "c.lt.%f",      mipscofpc,
273         "c.nge.%f",     mipscofpc,
274         "c.le.%f",      mipscofpc,
275         "c.ngt.%f",     mipscofpc,
276 };
277
278 static char fsub[16] = {
279         's', 'd', 'e', 'q', 'w', '?', '?', '?',
280         '?', '?', '?', '?', '?', '?', '?', '?'
281 };
282
283
284 static int
285 mkinstr(Instr *i, Map *map, uvlong pc)
286 {
287         ulong w;
288
289         if (get4(map, pc, &w) < 0) {
290                 werrstr("can't read instruction: %r");
291                 return -1;
292         }
293         i->addr = pc;
294         i->op = (w >> 26) & 0x3F;
295         i->rs = (w >> 21) & 0x1F;
296         i->rt = (w >> 16) & 0x1F;
297         i->rd = (w >> 11) & 0x1F;
298         i->sa = (w >> 6) & 0x1F;
299         i->function = w & 0x3F;
300         i->immediate = w & 0x0000FFFF;
301         if (i->immediate & 0x8000)
302                 i->immediate |= ~0x0000FFFF;
303         i->cofun = w & 0x01FFFFFF;
304         i->target = w & 0x03FFFFFF;
305         i->w0 = w;
306         return 1;
307 }
308
309 #pragma varargck        argpos  bprint          2
310
311 static void
312 bprint(Instr *i, char *fmt, ...)
313 {
314         va_list arg;
315
316         va_start(arg, fmt);
317         i->curr = vseprint(i->curr, i->end, fmt, arg);
318         va_end(arg);
319 }
320
321 static void
322 format(char *mnemonic, Instr *i, char *f)
323 {
324         if (mnemonic)
325                 format(0, i, mnemonic);
326         if (f == 0)
327                 return;
328         if (i->curr < i->end)
329                 *i->curr++ = '\t';
330         for ( ; *f && i->curr < i->end; f++) {
331                 if (*f != '%') {
332                         *i->curr++ = *f;
333                         continue;
334                 }
335                 switch (*++f) {
336
337                 case 's':
338                         bprint(i, "%d", i->rs);
339                         break;
340
341                 case 't':
342                         bprint(i, "%d", i->rt);
343                         break;
344
345                 case 'd':
346                         bprint(i, "%d", i->rd);
347                         break;
348
349                 case 'a':
350                         bprint(i, "%d", i->sa);
351                         break;
352
353                 case 'l':
354                         if (i->rs == 30) {
355                                 i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
356                                 bprint(i, "(SB)");
357                         } else 
358                                 bprint(i, "%lx(r%d)", i->immediate, i->rs);
359                         break;
360
361                 case 'i':
362                         bprint(i, "$%lx", i->immediate);
363                         break;
364
365                 case 'u':
366                         *i->curr++ = '$';
367                         i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
368                         bprint(i, "(SB)");
369                         break;
370
371                 case 'j':
372                         i->curr += symoff(i->curr, i->end-i->curr,
373                                 (i->target<<2)|(i->addr & 0xF0000000), CANY);
374                         bprint(i, "(SB)");
375                         break;
376
377                 case 'b':
378                         i->curr += symoff(i->curr, i->end-i->curr,
379                                 (i->immediate<<2)+i->addr+4, CANY);
380                         break;
381
382                 case 'c':
383                         bprint(i, "%lux", i->cofun);
384                         break;
385
386                 case 'w':
387                         bprint(i, "[%lux]", i->w0);
388                         break;
389
390                 case 'f':
391                         *i->curr++ = fsub[i->rs & 0x0F];
392                         break;
393
394                 case '\0':
395                         *i->curr++ = '%';
396                         return;
397
398                 default:
399                         bprint(i, "%%%c", *f);
400                         break;
401                 }
402         }
403 }
404
405 static void
406 copz(int cop, Instr *i)
407 {
408         char *f, *m, buf[16];
409
410         m = buf;
411         f = "%t,%d";
412         switch (i->rs) {
413
414         case 0:
415                 sprint(buf, "mfc%d", cop);
416                 break;
417
418         case 2:
419                 sprint(buf, "cfc%d", cop);
420                 break;
421
422         case 4:
423                 sprint(buf, "mtc%d", cop);
424                 break;
425
426         case 6:
427                 sprint(buf, "ctc%d", cop);
428                 break;
429
430         case 8:
431                 f = "%b";
432                 switch (i->rt) {
433
434                 case 0:
435                         sprint(buf, "bc%df", cop);
436                         break;
437
438                 case 1:
439                         sprint(buf, "bc%dt", cop);
440                         break;
441
442                 case 2:
443                         sprint(buf, "bc%dfl", cop);
444                         break;
445
446                 case 3:
447                         sprint(buf, "bc%dtl", cop);
448                         break;
449
450                 default:
451                         sprint(buf, "cop%d", cop);
452                         f = mipscoxxx;
453                         break;
454                 }
455                 break;
456
457         default:
458                 sprint(buf, "cop%d", cop);
459                 if (i->rs & 0x10)
460                         f = "function %c";
461                 else
462                         f = mipscoxxx;
463                 break;
464         }
465         format(m, i, f);
466 }
467
468 static void
469 cop0(Instr *i)
470 {
471         char *m = 0;
472
473         if (i->rs >= 0x10) {
474                 switch (i->cofun) {
475         
476                 case 1:
477                         m = "tlbr";
478                         break;
479         
480                 case 2:
481                         m = "tlbwi";
482                         break;
483         
484                 case 6:
485                         m = "tlbwr";
486                         break;
487         
488                 case 8:
489                         m = "tlbp";
490                         break;
491         
492                 case 16:
493                         m = "rfe";
494                         break;
495
496                 case 24:
497                         m = "eret";
498                         break;  
499
500                 case 32:
501                         m = "wait";
502                         break;
503                 }
504                 if (m) {
505                         format(m, i, 0);
506                         if (i->curr < i->end)
507                                 *i->curr++ = 0;
508                         return;
509                 }
510         }
511         copz(0, i);
512 }
513
514 int
515 _mipscoinst(Map *map, uvlong pc, char *buf, int n)
516 {
517         Instr i;
518         Opcode *o;
519         uchar op;
520
521         i.curr = buf;
522         i.end = buf+n-1;
523         if (mkinstr(&i, map, pc) < 0)
524                 return -1;
525         switch (i.op) {
526
527         case 0x00:                                      /* SPECIAL */
528                 o = sopcodes;
529                 op = i.function;
530                 break;
531
532         case 0x01:                                      /* REGIMM */
533                 o = ropcodes;
534                 op = i.rt;
535                 break;
536
537         case 0x10:                                      /* COP0 */
538                 cop0(&i);
539                 return 4;
540
541         case 0x11:                                      /* COP1 */
542                 if (i.rs & 0x10) {
543                         o = fopcodes;
544                         op = i.function;
545                         break;
546                 }
547                 /*FALLTHROUGH*/
548         case 0x12:                                      /* COP2 */
549         case 0x13:                                      /* COP3 */
550                 copz(i.op-0x10, &i);
551                 return 4;
552
553         default:
554                 o = opcodes;
555                 op = i.op;
556                 break;
557         }
558         format(o[op].mnemonic, &i, o[op].mipsco);
559         return 4;
560 }