f833f8b2cb01ec96f076840001f5eb8dab098fae
[b43-tools.git] / disassembler / main.c
1 /*
2  *   Copyright (C) 2006-2010  Michael Buesch <mb@bu3sch.de>
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License version 2
6  *   as published by the Free Software Foundation.
7  *
8  *   This program is distributed in the hope that it will be useful,
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *   GNU General Public License for more details.
12  */
13
14 #include "main.h"
15 #include "list.h"
16 #include "util.h"
17 #include "args.h"
18
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24
25 struct bin_instruction {
26         unsigned int opcode;
27         unsigned int operands[3];
28 };
29
30 struct statement {
31         enum {
32                 STMT_INSN,
33                 STMT_LABEL,
34         } type;
35
36         union {
37                 struct {
38                         struct bin_instruction *bin;
39                         const char *name;
40                         const char *operands[5];
41
42                         int is_labelref;
43                         unsigned int labeladdr;
44                         struct statement *labelref;
45                 } insn;
46                 struct {
47                         char *name;
48                 } label;
49         } u;
50
51         struct list_head list;
52 };
53
54 struct disassembler_context {
55         /* The architecture of the input file. */
56         unsigned int arch;
57
58         struct bin_instruction *code;
59         size_t nr_insns;
60
61         struct list_head stmt_list;
62 };
63
64
65 FILE *infile;
66 FILE *outfile;
67 const char *infile_name;
68 const char *outfile_name;
69
70
71 static const char * gen_raw_code(unsigned int operand)
72 {
73         char *ret;
74
75         ret = xmalloc(6);
76         snprintf(ret, 6, "@%X", operand);
77
78         return ret;
79 }
80
81 static const char * disasm_mem_operand(unsigned int operand)
82 {
83         char *ret;
84
85         ret = xmalloc(9);
86         snprintf(ret, 9, "[0x%X]", operand);
87
88         return ret;
89 }
90
91 static const char * disasm_indirect_mem_operand(unsigned int operand)
92 {
93         char *ret;
94         unsigned int offset, reg;
95
96         switch (cmdargs.arch) {
97         case 5:
98                 offset = (operand & 0x3F);
99                 reg = ((operand >> 6) & 0x7);
100                 break;
101         case 15:
102                 offset = (operand & 0x7F);
103                 reg = ((operand >> 7) & 0x7);
104                 break;
105         default:
106                 fprintf(stderr, "Internal error: disasm_indirect_mem_operand invalid arch\n");
107                 exit(1);
108         }
109         ret = xmalloc(12);
110         snprintf(ret, 12, "[0x%02X,off%u]", offset, reg);
111
112         return ret;
113 }
114
115 static const char * disasm_imm_operand(unsigned int operand)
116 {
117         char *ret;
118         unsigned int signmask;
119         unsigned int mask;
120
121         switch (cmdargs.arch) {
122         case 5:
123                 signmask = (1 << 9);
124                 mask = 0x3FF;
125                 break;
126         case 15:
127                 signmask = (1 << 10);
128                 mask = 0x7FF;
129                 break;
130         default:
131                 fprintf(stderr, "Internal error: disasm_imm_operand invalid arch\n");
132                 exit(1);
133         }
134
135         operand &= mask;
136
137         ret = xmalloc(7);
138         if (operand & signmask)
139                 operand = (operand | (~mask & 0xFFFF));
140         snprintf(ret, 7, "0x%X", operand);
141
142         return ret;
143 }
144
145 static const char * disasm_spr_operand(unsigned int operand)
146 {
147         char *ret;
148         unsigned int mask;
149
150         switch (cmdargs.arch) {
151         case 5:
152                 mask = 0x1FF;
153                 break;
154         case 15:
155                 mask = 0x7FF;
156                 break;
157         default:
158                 fprintf(stderr, "Internal error: disasm_spr_operand invalid arch\n");
159                 exit(1);
160         }
161
162         ret = xmalloc(8);
163         snprintf(ret, 8, "spr%X", (operand & mask));
164
165         return ret;
166 }
167
168 static const char * disasm_gpr_operand(unsigned int operand)
169 {
170         char *ret;
171         unsigned int mask;
172
173         switch (cmdargs.arch) {
174         case 5:
175                 mask = 0x3F;
176                 break;
177         case 15:
178                 mask = 0x7F;
179                 break;
180         default:
181                 fprintf(stderr, "Internal error: disasm_gpr_operand invalid arch\n");
182                 exit(1);
183         }
184
185         ret = xmalloc(5);
186         snprintf(ret, 5, "r%u", (operand & mask));
187
188         return ret;
189 }
190
191 static void disasm_std_operand(struct statement *stmt,
192                                int oper_idx,
193                                int out_idx,
194                                int forceraw)
195 {
196         unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
197
198         if (forceraw)
199                 goto raw;
200
201         switch (cmdargs.arch) {
202         case 5:
203                 if (!(operand & 0x800)) {
204                         stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
205                         return;
206                 } else if ((operand & 0xC00) == 0xC00) { 
207                         stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
208                         return;
209                 } else if ((operand & 0xFC0) == 0xBC0) {
210                         stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
211                         return;
212                 } else if ((operand & 0xE00) == 0x800) {
213                         stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
214                         return;
215                 } else if ((operand & 0xE00) == 0xA00) {
216                         stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
217                         return;
218                 }
219                 break;
220         case 15:
221                 if (!(operand & 0x1000)) {
222                         stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
223                         return;
224                 } else if ((operand & 0x1800) == 0x1800) { 
225                         stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
226                         return;
227                 } else if ((operand & 0x1F80) == 0x1780) {
228                         stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
229                         return;
230                 } else if ((operand & 0x1C00) == 0x1000) {
231                         stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
232                         return;
233                 } else if ((operand & 0x1C00) == 0x1400) {
234                         stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
235                         return;
236                 }
237                 break;
238         default:
239                 fprintf(stderr, "Internal error: disasm_std_operand invalid arch\n");
240                 exit(1);
241         }
242 raw:
243         stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
244 }
245
246 static void disasm_opcode_raw(struct disassembler_context *ctx,
247                               struct statement *stmt)
248 {
249         stmt->u.insn.name = gen_raw_code(stmt->u.insn.bin->opcode);
250         disasm_std_operand(stmt, 0, 0, 1);
251         disasm_std_operand(stmt, 1, 1, 1);
252         disasm_std_operand(stmt, 2, 2, 1);
253 }
254
255 static void disasm_constant_opcodes(struct disassembler_context *ctx,
256                                     struct statement *stmt)
257 {
258         struct bin_instruction *bin = stmt->u.insn.bin;
259
260         switch (bin->opcode) {
261         case 0x1C0:
262                 stmt->u.insn.name = "add";
263                 disasm_std_operand(stmt, 0, 0, 0);
264                 disasm_std_operand(stmt, 1, 1, 0);
265                 disasm_std_operand(stmt, 2, 2, 0);
266                 break;
267         case 0x1C2:
268                 stmt->u.insn.name = "add.";
269                 disasm_std_operand(stmt, 0, 0, 0);
270                 disasm_std_operand(stmt, 1, 1, 0);
271                 disasm_std_operand(stmt, 2, 2, 0);
272                 break;
273         case 0x1C1:
274                 stmt->u.insn.name = "addc";
275                 disasm_std_operand(stmt, 0, 0, 0);
276                 disasm_std_operand(stmt, 1, 1, 0);
277                 disasm_std_operand(stmt, 2, 2, 0);
278                 break;
279         case 0x1C3:
280                 stmt->u.insn.name = "addc.";
281                 disasm_std_operand(stmt, 0, 0, 0);
282                 disasm_std_operand(stmt, 1, 1, 0);
283                 disasm_std_operand(stmt, 2, 2, 0);
284                 break;
285         case 0x1D0:
286                 stmt->u.insn.name = "sub";
287                 disasm_std_operand(stmt, 0, 0, 0);
288                 disasm_std_operand(stmt, 1, 1, 0);
289                 disasm_std_operand(stmt, 2, 2, 0);
290                 break;
291         case 0x1D2:
292                 stmt->u.insn.name = "sub.";
293                 disasm_std_operand(stmt, 0, 0, 0);
294                 disasm_std_operand(stmt, 1, 1, 0);
295                 disasm_std_operand(stmt, 2, 2, 0);
296                 break;
297         case 0x1D1:
298                 stmt->u.insn.name = "subc";
299                 disasm_std_operand(stmt, 0, 0, 0);
300                 disasm_std_operand(stmt, 1, 1, 0);
301                 disasm_std_operand(stmt, 2, 2, 0);
302                 break;
303         case 0x1D3:
304                 stmt->u.insn.name = "subc.";
305                 disasm_std_operand(stmt, 0, 0, 0);
306                 disasm_std_operand(stmt, 1, 1, 0);
307                 disasm_std_operand(stmt, 2, 2, 0);
308                 break;
309         case 0x130:
310                 stmt->u.insn.name = "sra";
311                 disasm_std_operand(stmt, 0, 0, 0);
312                 disasm_std_operand(stmt, 1, 1, 0);
313                 disasm_std_operand(stmt, 2, 2, 0);
314                 break;
315         case 0x160:
316                 stmt->u.insn.name = "or";
317                 disasm_std_operand(stmt, 0, 0, 0);
318                 disasm_std_operand(stmt, 1, 1, 0);
319                 disasm_std_operand(stmt, 2, 2, 0);
320                 break;
321         case 0x140:
322                 stmt->u.insn.name = "and";
323                 disasm_std_operand(stmt, 0, 0, 0);
324                 disasm_std_operand(stmt, 1, 1, 0);
325                 disasm_std_operand(stmt, 2, 2, 0);
326                 break;
327         case 0x170:
328                 stmt->u.insn.name = "xor";
329                 disasm_std_operand(stmt, 0, 0, 0);
330                 disasm_std_operand(stmt, 1, 1, 0);
331                 disasm_std_operand(stmt, 2, 2, 0);
332                 break;
333         case 0x120:
334                 stmt->u.insn.name = "sr";
335                 disasm_std_operand(stmt, 0, 0, 0);
336                 disasm_std_operand(stmt, 1, 1, 0);
337                 disasm_std_operand(stmt, 2, 2, 0);
338                 break;
339         case 0x110:
340                 stmt->u.insn.name = "sl";
341                 disasm_std_operand(stmt, 0, 0, 0);
342                 disasm_std_operand(stmt, 1, 1, 0);
343                 disasm_std_operand(stmt, 2, 2, 0);
344                 break;
345         case 0x1A0:
346                 stmt->u.insn.name = "rl";
347                 disasm_std_operand(stmt, 0, 0, 0);
348                 disasm_std_operand(stmt, 1, 1, 0);
349                 disasm_std_operand(stmt, 2, 2, 0);
350                 break;
351         case 0x1B0:
352                 stmt->u.insn.name = "rr";
353                 disasm_std_operand(stmt, 0, 0, 0);
354                 disasm_std_operand(stmt, 1, 1, 0);
355                 disasm_std_operand(stmt, 2, 2, 0);
356                 break;
357         case 0x150:
358                 stmt->u.insn.name = "nand";
359                 disasm_std_operand(stmt, 0, 0, 0);
360                 disasm_std_operand(stmt, 1, 1, 0);
361                 disasm_std_operand(stmt, 2, 2, 0);
362                 break;
363         case 0x040:
364                 stmt->u.insn.name = "jand";
365                 stmt->u.insn.is_labelref = 2;
366                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
367                 disasm_std_operand(stmt, 0, 0, 0);
368                 disasm_std_operand(stmt, 1, 1, 0);
369                 break;
370         case (0x040 | 0x1):
371                 stmt->u.insn.name = "jnand";
372                 stmt->u.insn.is_labelref = 2;
373                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
374                 disasm_std_operand(stmt, 0, 0, 0);
375                 disasm_std_operand(stmt, 1, 1, 0);
376                 break;
377         case 0x050:
378                 stmt->u.insn.name = "js";
379                 stmt->u.insn.is_labelref = 2;
380                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
381                 disasm_std_operand(stmt, 0, 0, 0);
382                 disasm_std_operand(stmt, 1, 1, 0);
383                 break;
384         case (0x050 | 0x1):
385                 stmt->u.insn.name = "jns";
386                 stmt->u.insn.is_labelref = 2;
387                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
388                 disasm_std_operand(stmt, 0, 0, 0);
389                 disasm_std_operand(stmt, 1, 1, 0);
390                 break;
391         case 0x0D0:
392                 stmt->u.insn.name = "je";
393                 stmt->u.insn.is_labelref = 2;
394                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
395                 disasm_std_operand(stmt, 0, 0, 0);
396                 disasm_std_operand(stmt, 1, 1, 0);
397                 break;
398         case (0x0D0 | 0x1):
399                 stmt->u.insn.name = "jne";
400                 stmt->u.insn.is_labelref = 2;
401                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
402                 disasm_std_operand(stmt, 0, 0, 0);
403                 disasm_std_operand(stmt, 1, 1, 0);
404                 break;
405         case 0x0D2:
406                 stmt->u.insn.name = "jls";
407                 stmt->u.insn.is_labelref = 2;
408                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
409                 disasm_std_operand(stmt, 0, 0, 0);
410                 disasm_std_operand(stmt, 1, 1, 0);
411                 break;
412         case (0x0D2 | 0x1):
413                 stmt->u.insn.name = "jges";
414                 stmt->u.insn.is_labelref = 2;
415                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
416                 disasm_std_operand(stmt, 0, 0, 0);
417                 disasm_std_operand(stmt, 1, 1, 0);
418                 break;
419         case 0x0D4:
420                 stmt->u.insn.name = "jgs";
421                 stmt->u.insn.is_labelref = 2;
422                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
423                 disasm_std_operand(stmt, 0, 0, 0);
424                 disasm_std_operand(stmt, 1, 1, 0);
425                 break;
426         case (0x0D4 | 0x1):
427                 stmt->u.insn.name = "jles";
428                 stmt->u.insn.is_labelref = 2;
429                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
430                 disasm_std_operand(stmt, 0, 0, 0);
431                 disasm_std_operand(stmt, 1, 1, 0);
432                 break;
433         case 0x0DA:
434                 stmt->u.insn.name = "jl";
435                 stmt->u.insn.is_labelref = 2;
436                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
437                 disasm_std_operand(stmt, 0, 0, 0);
438                 disasm_std_operand(stmt, 1, 1, 0);
439                 break;
440         case (0x0DA | 0x1):
441                 stmt->u.insn.name = "jge";
442                 stmt->u.insn.is_labelref = 2;
443                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
444                 disasm_std_operand(stmt, 0, 0, 0);
445                 disasm_std_operand(stmt, 1, 1, 0);
446                 break;
447         case 0x0DC:
448                 stmt->u.insn.name = "jg";
449                 stmt->u.insn.is_labelref = 2;
450                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
451                 disasm_std_operand(stmt, 0, 0, 0);
452                 disasm_std_operand(stmt, 1, 1, 0);
453                 break;
454         case (0x0DC | 0x1):
455                 stmt->u.insn.name = "jle";
456                 stmt->u.insn.is_labelref = 2;
457                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
458                 disasm_std_operand(stmt, 0, 0, 0);
459                 disasm_std_operand(stmt, 1, 1, 0);
460                 break;
461         case 0x002: {
462                 char *str;
463
464                 switch (cmdargs.arch) {
465                 case 5:
466                         stmt->u.insn.name = "call";
467                         stmt->u.insn.is_labelref = 1;
468                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
469                         str = xmalloc(4);
470                         snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
471                         stmt->u.insn.operands[0] = str;
472                         break;
473                 case 15:
474                         //FIXME: This opcode is different on r15. Decode raw for now.
475                         disasm_opcode_raw(ctx, stmt);
476                         break;
477                 }
478                 break;
479         }
480         case 0x003: {
481                 char *str;
482
483                 stmt->u.insn.name = "ret";
484                 str = xmalloc(4);
485                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
486                 stmt->u.insn.operands[0] = str;
487                 str = xmalloc(4);
488                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
489                 stmt->u.insn.operands[2] = str;
490                 break;
491         }
492 //TODO also implement it in the assembler
493 #if 0
494         case 0x004: {
495                 if (cmdargs.arch != 15) {
496                         fprintf(stderr, "Error: arch 15 call instruction found in arch %d binary\n",
497                                 cmdargs.arch);
498                         exit(1);
499                 }
500                 stmt->u.insn.name = "call";
501                 stmt->u.insn.is_labelref = 0;
502                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
503                 if (stmt->u.insn.bin->operands[0] != 0x1780 ||
504                     stmt->u.insn.bin->operands[1] != 0x1780) {
505                         fprintf(stderr, "r15 call: Invalid first or second argument\n");
506                 }
507                 break;
508         }
509         case 0x005: {
510                 if (cmdargs.arch != 15) {
511                         fprintf(stderr, "Error: arch 15 ret instruction found in arch %d binary\n",
512                                 cmdargs.arch);
513                         exit(1);
514                 }
515                 stmt->u.insn.name = "ret";
516                 break;
517         }
518 #endif
519         case 0x1E0: {
520                 unsigned int flags, mask;
521
522                 switch (cmdargs.arch) {
523                 case 5:
524                         mask = 0x3FF;
525                         break;
526                 case 15:
527                         mask = 0x7FF;
528                         break;
529                 default:
530                         fprintf(stderr, "Internal error: TKIP invalid arch\n");
531                         exit(1);
532                 }
533
534                 flags = stmt->u.insn.bin->operands[1];
535                 switch (flags & mask) {
536                 case 0x1:
537                         stmt->u.insn.name = "tkiph";
538                         break;
539                 case (0x1 | 0x2):
540                         stmt->u.insn.name = "tkiphs";
541                         break;
542                 case 0x0:
543                         stmt->u.insn.name = "tkipl";
544                         break;
545                 case (0x0 | 0x2):
546                         stmt->u.insn.name = "tkipls";
547                         break;
548                 default:
549                         fprintf(stderr, "Invalid TKIP flags %X\n",
550                                 flags);
551                         exit(1);
552                 }
553                 disasm_std_operand(stmt, 0, 0, 0);
554                 disasm_std_operand(stmt, 2, 2, 0);
555                 break;
556         }
557         case 0x001: {
558                 unsigned int mask;
559
560                 stmt->u.insn.name = "nap";
561                 switch (cmdargs.arch) {
562                 case 5:
563                         mask = 0xBC0;
564                         break;
565                 case 15:
566                         mask = 0x1780;
567                         break;
568                 default:
569                         fprintf(stderr, "Internal error: NAP invalid arch\n");
570                         exit(1);
571                 }
572                 if (stmt->u.insn.bin->operands[0] != mask) {
573                         fprintf(stderr, "NAP: invalid first argument 0x%04X\n",
574                                 stmt->u.insn.bin->operands[0]);
575                 }
576                 if (stmt->u.insn.bin->operands[1] != mask) {
577                         fprintf(stderr, "NAP: invalid second argument 0x%04X\n",
578                                 stmt->u.insn.bin->operands[1]);
579                 }
580                 if (stmt->u.insn.bin->operands[2] != 0) {
581                         fprintf(stderr, "NAP: invalid third argument 0x%04X\n",
582                                 stmt->u.insn.bin->operands[2]);
583                 }
584                 break;
585         }
586         default:
587                 disasm_opcode_raw(ctx, stmt);
588                 break;
589         }
590 }
591
592 static void disasm_opcodes(struct disassembler_context *ctx)
593 {
594         struct bin_instruction *bin;
595         size_t i;
596         struct statement *stmt;
597         char *str;
598
599         for (i = 0; i < ctx->nr_insns; i++) {
600                 bin = &(ctx->code[i]);
601
602                 stmt = xmalloc(sizeof(struct statement));
603                 stmt->type = STMT_INSN;
604                 INIT_LIST_HEAD(&stmt->list);
605                 stmt->u.insn.bin = bin;
606                 stmt->u.insn.is_labelref = -1;
607
608                 switch (bin->opcode & 0xF00) {
609                 case 0x200:
610                         stmt->u.insn.name = "srx";
611
612                         str = xmalloc(3);
613                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
614                         stmt->u.insn.operands[0] = str;
615                         str = xmalloc(3);
616                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
617                         stmt->u.insn.operands[1] = str;
618
619                         disasm_std_operand(stmt, 0, 2, 0);
620                         disasm_std_operand(stmt, 1, 3, 0);
621                         disasm_std_operand(stmt, 2, 4, 0);
622                         break;
623                 case 0x300:
624                         stmt->u.insn.name = "orx";
625
626                         str = xmalloc(3);
627                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
628                         stmt->u.insn.operands[0] = str;
629                         str = xmalloc(3);
630                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
631                         stmt->u.insn.operands[1] = str;
632
633                         disasm_std_operand(stmt, 0, 2, 0);
634                         disasm_std_operand(stmt, 1, 3, 0);
635                         disasm_std_operand(stmt, 2, 4, 0);
636                         break;
637                 case 0x400:
638                         stmt->u.insn.name = "jzx";
639
640                         str = xmalloc(3);
641                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
642                         stmt->u.insn.operands[0] = str;
643                         str = xmalloc(3);
644                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
645                         stmt->u.insn.operands[1] = str;
646
647                         disasm_std_operand(stmt, 0, 2, 0);
648                         disasm_std_operand(stmt, 1, 3, 0);
649                         stmt->u.insn.is_labelref = 4;
650                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
651                         break;
652                 case 0x500:
653                         stmt->u.insn.name = "jnzx";
654
655                         str = xmalloc(3);
656                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
657                         stmt->u.insn.operands[0] = str;
658                         str = xmalloc(3);
659                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
660                         stmt->u.insn.operands[1] = str;
661
662                         disasm_std_operand(stmt, 0, 2, 0);
663                         disasm_std_operand(stmt, 1, 3, 0);
664                         stmt->u.insn.is_labelref = 4;
665                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
666                         break;
667                 case 0x600:
668                         stmt->u.insn.name = "jnext";
669
670                         str = xmalloc(5);
671                         snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
672                         stmt->u.insn.operands[0] = str;
673
674                         /* We don't disassemble the first and second operand, as
675                          * that always is a dummy r0 operand.
676                          * disasm_std_operand(stmt, 0, 1, 0);
677                          * disasm_std_operand(stmt, 1, 2, 0);
678                          * stmt->u.insn.is_labelref = 3;
679                          */
680                         stmt->u.insn.is_labelref = 1;
681                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
682                         break;
683                 case 0x700:
684                         stmt->u.insn.name = "jext";
685
686                         str = xmalloc(5);
687                         snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
688                         stmt->u.insn.operands[0] = str;
689
690                         /* We don't disassemble the first and second operand, as
691                          * that always is a dummy r0 operand.
692                          * disasm_std_operand(stmt, 0, 1, 0);
693                          * disasm_std_operand(stmt, 1, 2, 0);
694                          * stmt->u.insn.is_labelref = 3;
695                          */
696                         stmt->u.insn.is_labelref = 1;
697                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
698                         break;
699                 default:
700                         disasm_constant_opcodes(ctx, stmt);
701                         break;
702                 }
703
704                 list_add_tail(&stmt->list, &ctx->stmt_list);
705         }
706 }
707
708 static struct statement * get_label_at(struct disassembler_context *ctx,
709                                        unsigned int addr)
710 {
711         unsigned int addrcnt = 0;
712         struct statement *stmt, *ret, *prev;
713
714         list_for_each_entry(stmt, &ctx->stmt_list, list) {
715                 if (stmt->type != STMT_INSN)
716                         continue;
717                 if (addrcnt == addr) {
718                         prev = list_entry(stmt->list.prev, struct statement, list);
719                         if (prev->type == STMT_LABEL)
720                                 return prev;
721                         ret = xmalloc(sizeof(struct statement));
722                         INIT_LIST_HEAD(&ret->list);
723                         ret->type = STMT_LABEL;
724                         list_add(&ret->list, &prev->list);
725
726                         return ret;
727                 }
728                 addrcnt++;
729         }
730
731         return NULL;
732 }
733
734 static void resolve_labels(struct disassembler_context *ctx)
735 {
736         struct statement *stmt;
737         struct statement *label;
738         struct statement *n;
739         unsigned int labeladdr;
740         unsigned int namecnt = 0;
741
742         /* Resolve label references */
743         list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
744                 if (stmt->type != STMT_INSN)
745                         continue;
746                 if (stmt->u.insn.is_labelref == -1)
747                         continue;
748                 labeladdr = stmt->u.insn.labeladdr;
749                 label = get_label_at(ctx, labeladdr);
750                 if (!label) {
751                         fprintf(stderr, "Labeladdress %X out of bounds\n",
752                                 labeladdr);
753                         exit(1);
754                 }
755                 stmt->u.insn.labelref = label;
756         }
757
758         /* Name the labels */
759         list_for_each_entry(stmt, &ctx->stmt_list, list) {
760                 if (stmt->type != STMT_LABEL)
761                         continue;
762                 stmt->u.label.name = xmalloc(20);
763                 snprintf(stmt->u.label.name, 20, "L%u", namecnt);
764                 namecnt++;
765         }
766 }
767
768 static void emit_asm(struct disassembler_context *ctx)
769 {
770         struct statement *stmt;
771         int first, i;
772         int err;
773         unsigned int addr = 0;
774
775         err = open_output_file();
776         if (err)
777                 exit(1);
778
779         fprintf(outfile, "%%arch %u\n", ctx->arch);
780         fprintf(outfile, "%%start entry\n\n");
781         fprintf(outfile, "entry:\n");
782         list_for_each_entry(stmt, &ctx->stmt_list, list) {
783                 switch (stmt->type) {
784                 case STMT_INSN:
785                         if (cmdargs.print_addresses)
786                                 fprintf(outfile, "/* %03X */", addr);
787                         fprintf(outfile, "\t%s", stmt->u.insn.name);
788                         first = 1;
789                         for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
790                                 if (!stmt->u.insn.operands[i] &&
791                                     stmt->u.insn.is_labelref != i)
792                                         continue;
793                                 if (first)
794                                         fprintf(outfile, "\t");
795                                 if (!first)
796                                         fprintf(outfile, ", ");
797                                 first = 0;
798                                 if (stmt->u.insn.is_labelref == i) {
799                                         fprintf(outfile, "%s",
800                                                 stmt->u.insn.labelref->u.label.name);
801                                 } else {
802                                         fprintf(outfile, "%s",
803                                                 stmt->u.insn.operands[i]);
804                                 }
805                         }
806                         fprintf(outfile, "\n");
807                         addr++;
808                         break;
809                 case STMT_LABEL:
810                         fprintf(outfile, "%s:\n", stmt->u.label.name);
811                         break;
812                 }
813         }
814
815         close_output_file();
816 }
817
818 static int read_input(struct disassembler_context *ctx)
819 {
820         size_t size = 0, pos = 0;
821         size_t ret;
822         struct bin_instruction *code = NULL;
823         unsigned char tmp[sizeof(uint64_t)];
824         uint64_t codeword;
825         struct fw_header hdr;
826         int err;
827
828         err = open_input_file();
829         if (err)
830                 goto error;
831
832         switch (cmdargs.informat) {
833         case FMT_RAW_LE32:
834         case FMT_RAW_BE32:
835                 /* Nothing */
836                 break;
837         case FMT_B43:
838                 ret = fread(&hdr, 1, sizeof(hdr), infile);
839                 if (ret != sizeof(hdr)) {
840                         fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
841                         goto err_close;
842                 }
843                 if (hdr.type != FW_TYPE_UCODE) {
844                         fprintf(stderr, "Corrupt input file. Not a microcode image.\n");
845                         goto err_close;
846                 }
847                 if (hdr.ver != FW_HDR_VER) {
848                         fprintf(stderr, "Invalid input file header version.\n");
849                         goto err_close;
850                 }
851                 break;
852         }
853
854         while (1) {
855                 if (pos >= size) {
856                         size += 512;
857                         code = xrealloc(code, size * sizeof(struct bin_instruction));
858                 }
859                 ret = fread(tmp, 1, sizeof(uint64_t), infile);
860                 if (!ret)
861                         break;
862                 if (ret != sizeof(uint64_t)) {
863                         fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
864                         goto err_free_code;
865                 }
866
867                 switch (cmdargs.informat) {
868                 case FMT_B43:
869                 case FMT_RAW_BE32:
870                         codeword = 0;
871                         codeword |= ((uint64_t)tmp[0]) << 56;
872                         codeword |= ((uint64_t)tmp[1]) << 48;
873                         codeword |= ((uint64_t)tmp[2]) << 40;
874                         codeword |= ((uint64_t)tmp[3]) << 32;
875                         codeword |= ((uint64_t)tmp[4]) << 24;
876                         codeword |= ((uint64_t)tmp[5]) << 16;
877                         codeword |= ((uint64_t)tmp[6]) << 8;
878                         codeword |= ((uint64_t)tmp[7]);
879                         codeword = ((codeword & (uint64_t)0xFFFFFFFF00000000ULL) >> 32) |
880                                    ((codeword & (uint64_t)0x00000000FFFFFFFFULL) << 32);
881                         break;
882                 case FMT_RAW_LE32:
883                         codeword = 0;
884                         codeword |= ((uint64_t)tmp[7]) << 56;
885                         codeword |= ((uint64_t)tmp[6]) << 48;
886                         codeword |= ((uint64_t)tmp[5]) << 40;
887                         codeword |= ((uint64_t)tmp[4]) << 32;
888                         codeword |= ((uint64_t)tmp[3]) << 24;
889                         codeword |= ((uint64_t)tmp[2]) << 16;
890                         codeword |= ((uint64_t)tmp[1]) << 8;
891                         codeword |= ((uint64_t)tmp[0]);
892                         break;
893                 }
894
895                 switch (cmdargs.arch) {
896                 case 5:
897                         if (codeword >> 48) {
898                                 fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
899                                         "Wrong input format or architecture?\n", (unsigned int)pos);
900                                 goto err_free_code;
901                         }
902                         code[pos].opcode = (codeword >> 36) & 0xFFF;
903                         code[pos].operands[2] = codeword & 0xFFF;
904                         code[pos].operands[1] = (codeword >> 12) & 0xFFF;
905                         code[pos].operands[0] = (codeword >> 24) & 0xFFF;
906                         break;
907                 case 15:
908                         if (codeword >> 51) {
909                                 fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
910                                         "Wrong input format or architecture?\n", (unsigned int)pos);
911                                 goto err_free_code;
912                         }
913                         code[pos].opcode = (codeword >> 39) & 0xFFF;
914                         code[pos].operands[2] = codeword & 0x1FFF;
915                         code[pos].operands[1] = (codeword >> 13) & 0x1FFF;
916                         code[pos].operands[0] = (codeword >> 26) & 0x1FFF;
917                         break;
918                 default:
919                         fprintf(stderr, "Internal error: read_input unknown arch %u\n",
920                                 cmdargs.arch);
921                         goto err_free_code;
922                 }
923
924                 pos++;
925         }
926
927         ctx->code = code;
928         ctx->nr_insns = pos;
929
930         close_input_file();
931
932         return 0;
933
934 err_free_code:
935         free(code);
936 err_close:
937         close_input_file();
938 error:
939         return -1;
940 }
941
942 static void disassemble(void)
943 {
944         struct disassembler_context ctx;
945         int err;
946
947         memset(&ctx, 0, sizeof(ctx));
948         INIT_LIST_HEAD(&ctx.stmt_list);
949         ctx.arch = cmdargs.arch;
950
951         err = read_input(&ctx);
952         if (err)
953                 exit(1);
954         disasm_opcodes(&ctx);
955         resolve_labels(&ctx);
956         emit_asm(&ctx);
957 }
958
959 int main(int argc, char **argv)
960 {
961         int err, res = 1;
962
963         err = parse_args(argc, argv);
964         if (err < 0)
965                 goto out;
966         if (err > 0) {
967                 res = 0;
968                 goto out;
969         }
970         disassemble();
971         res = 0;
972 out:
973         /* Lazyman simply leaks all allocated memory. */
974         return res;
975 }