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