fwcutter/make: Avoid _DEFAULT_SOURCE warning
[b43-tools.git] / disassembler / main.c
1 /*
2  *   Copyright (C) 2006-2010  Michael Buesch <m@bues.ch>
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 labelref_operand;
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_raw_operand(struct statement *stmt,
207                                int oper_idx,
208                                int out_idx)
209 {
210         unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
211
212         stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
213 }
214
215 static void disasm_std_operand(struct statement *stmt,
216                                int oper_idx,
217                                int out_idx)
218 {
219         unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
220
221         switch (cmdargs.arch) {
222         case 5:
223                 if (!(operand & 0x800)) {
224                         stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
225                         return;
226                 } else if ((operand & 0xC00) == 0xC00) { 
227                         stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
228                         return;
229                 } else if ((operand & 0xFC0) == 0xBC0) {
230                         stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
231                         return;
232                 } else if ((operand & 0xE00) == 0x800) {
233                         stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
234                         return;
235                 } else if ((operand & 0xE00) == 0xA00) {
236                         stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
237                         return;
238                 }
239                 break;
240         case 15:
241                 if (!(operand & 0x1000)) {
242                         stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
243                         return;
244                 } else if ((operand & 0x1800) == 0x1800) { 
245                         stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
246                         return;
247                 } else if ((operand & 0x1F80) == 0x1780) {
248                         stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
249                         return;
250                 } else if ((operand & 0x1C00) == 0x1000) {
251                         stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
252                         return;
253                 } else if ((operand & 0x1C00) == 0x1400) {
254                         stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
255                         return;
256                 }
257                 break;
258         default:
259                 dasm_int_error("disasm_std_operand invalid arch");
260         }
261         /* No luck. Disassemble to raw operand. */
262         disasm_raw_operand(stmt, oper_idx, out_idx);
263 }
264
265 static void disasm_opcode_raw(struct disassembler_context *ctx,
266                               struct statement *stmt,
267                               int raw_operands)
268 {
269         stmt->u.insn.name = gen_raw_code(stmt->u.insn.bin->opcode);
270         if (raw_operands) {
271                 disasm_raw_operand(stmt, 0, 0);
272                 disasm_raw_operand(stmt, 1, 1);
273                 disasm_raw_operand(stmt, 2, 2);
274         } else {
275                 disasm_std_operand(stmt, 0, 0);
276                 disasm_std_operand(stmt, 1, 1);
277                 disasm_std_operand(stmt, 2, 2);
278         }
279 }
280
281 static void disasm_constant_opcodes(struct disassembler_context *ctx,
282                                     struct statement *stmt)
283 {
284         struct bin_instruction *bin = stmt->u.insn.bin;
285
286         switch (bin->opcode) {
287         case 0x101:
288                 stmt->u.insn.name = "mul";
289                 disasm_std_operand(stmt, 0, 0);
290                 disasm_std_operand(stmt, 1, 1);
291                 disasm_std_operand(stmt, 2, 2);
292                 break;
293         case 0x1C0:
294                 stmt->u.insn.name = "add";
295                 disasm_std_operand(stmt, 0, 0);
296                 disasm_std_operand(stmt, 1, 1);
297                 disasm_std_operand(stmt, 2, 2);
298                 break;
299         case 0x1C2:
300                 stmt->u.insn.name = "add.";
301                 disasm_std_operand(stmt, 0, 0);
302                 disasm_std_operand(stmt, 1, 1);
303                 disasm_std_operand(stmt, 2, 2);
304                 break;
305         case 0x1C1:
306                 stmt->u.insn.name = "addc";
307                 disasm_std_operand(stmt, 0, 0);
308                 disasm_std_operand(stmt, 1, 1);
309                 disasm_std_operand(stmt, 2, 2);
310                 break;
311         case 0x1C3:
312                 stmt->u.insn.name = "addc.";
313                 disasm_std_operand(stmt, 0, 0);
314                 disasm_std_operand(stmt, 1, 1);
315                 disasm_std_operand(stmt, 2, 2);
316                 break;
317         case 0x1D0:
318                 stmt->u.insn.name = "sub";
319                 disasm_std_operand(stmt, 0, 0);
320                 disasm_std_operand(stmt, 1, 1);
321                 disasm_std_operand(stmt, 2, 2);
322                 break;
323         case 0x1D2:
324                 stmt->u.insn.name = "sub.";
325                 disasm_std_operand(stmt, 0, 0);
326                 disasm_std_operand(stmt, 1, 1);
327                 disasm_std_operand(stmt, 2, 2);
328                 break;
329         case 0x1D1:
330                 stmt->u.insn.name = "subc";
331                 disasm_std_operand(stmt, 0, 0);
332                 disasm_std_operand(stmt, 1, 1);
333                 disasm_std_operand(stmt, 2, 2);
334                 break;
335         case 0x1D3:
336                 stmt->u.insn.name = "subc.";
337                 disasm_std_operand(stmt, 0, 0);
338                 disasm_std_operand(stmt, 1, 1);
339                 disasm_std_operand(stmt, 2, 2);
340                 break;
341         case 0x130:
342                 stmt->u.insn.name = "sra";
343                 disasm_std_operand(stmt, 0, 0);
344                 disasm_std_operand(stmt, 1, 1);
345                 disasm_std_operand(stmt, 2, 2);
346                 break;
347         case 0x160:
348                 stmt->u.insn.name = "or";
349                 disasm_std_operand(stmt, 0, 0);
350                 disasm_std_operand(stmt, 1, 1);
351                 disasm_std_operand(stmt, 2, 2);
352                 break;
353         case 0x140:
354                 stmt->u.insn.name = "and";
355                 disasm_std_operand(stmt, 0, 0);
356                 disasm_std_operand(stmt, 1, 1);
357                 disasm_std_operand(stmt, 2, 2);
358                 break;
359         case 0x170:
360                 stmt->u.insn.name = "xor";
361                 disasm_std_operand(stmt, 0, 0);
362                 disasm_std_operand(stmt, 1, 1);
363                 disasm_std_operand(stmt, 2, 2);
364                 break;
365         case 0x120:
366                 stmt->u.insn.name = "sr";
367                 disasm_std_operand(stmt, 0, 0);
368                 disasm_std_operand(stmt, 1, 1);
369                 disasm_std_operand(stmt, 2, 2);
370                 break;
371         case 0x110:
372                 stmt->u.insn.name = "sl";
373                 disasm_std_operand(stmt, 0, 0);
374                 disasm_std_operand(stmt, 1, 1);
375                 disasm_std_operand(stmt, 2, 2);
376                 break;
377         case 0x1A0:
378                 stmt->u.insn.name = "rl";
379                 disasm_std_operand(stmt, 0, 0);
380                 disasm_std_operand(stmt, 1, 1);
381                 disasm_std_operand(stmt, 2, 2);
382                 break;
383         case 0x1B0:
384                 stmt->u.insn.name = "rr";
385                 disasm_std_operand(stmt, 0, 0);
386                 disasm_std_operand(stmt, 1, 1);
387                 disasm_std_operand(stmt, 2, 2);
388                 break;
389         case 0x150:
390                 stmt->u.insn.name = "nand";
391                 disasm_std_operand(stmt, 0, 0);
392                 disasm_std_operand(stmt, 1, 1);
393                 disasm_std_operand(stmt, 2, 2);
394                 break;
395         case 0x040:
396                 stmt->u.insn.name = "jand";
397                 stmt->u.insn.labelref_operand = 2;
398                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
399                 disasm_std_operand(stmt, 0, 0);
400                 disasm_std_operand(stmt, 1, 1);
401                 break;
402         case (0x040 | 0x1):
403                 stmt->u.insn.name = "jnand";
404                 stmt->u.insn.labelref_operand = 2;
405                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
406                 disasm_std_operand(stmt, 0, 0);
407                 disasm_std_operand(stmt, 1, 1);
408                 break;
409         case 0x050:
410                 stmt->u.insn.name = "js";
411                 stmt->u.insn.labelref_operand = 2;
412                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
413                 disasm_std_operand(stmt, 0, 0);
414                 disasm_std_operand(stmt, 1, 1);
415                 break;
416         case (0x050 | 0x1):
417                 stmt->u.insn.name = "jns";
418                 stmt->u.insn.labelref_operand = 2;
419                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
420                 disasm_std_operand(stmt, 0, 0);
421                 disasm_std_operand(stmt, 1, 1);
422                 break;
423         case 0x0D0:
424                 stmt->u.insn.name = "je";
425                 stmt->u.insn.labelref_operand = 2;
426                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
427                 disasm_std_operand(stmt, 0, 0);
428                 disasm_std_operand(stmt, 1, 1);
429                 break;
430         case (0x0D0 | 0x1):
431                 stmt->u.insn.name = "jne";
432                 stmt->u.insn.labelref_operand = 2;
433                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
434                 disasm_std_operand(stmt, 0, 0);
435                 disasm_std_operand(stmt, 1, 1);
436                 break;
437         case 0x0D2:
438                 stmt->u.insn.name = "jls";
439                 stmt->u.insn.labelref_operand = 2;
440                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
441                 disasm_std_operand(stmt, 0, 0);
442                 disasm_std_operand(stmt, 1, 1);
443                 break;
444         case (0x0D2 | 0x1):
445                 stmt->u.insn.name = "jges";
446                 stmt->u.insn.labelref_operand = 2;
447                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
448                 disasm_std_operand(stmt, 0, 0);
449                 disasm_std_operand(stmt, 1, 1);
450                 break;
451         case 0x0D4:
452                 stmt->u.insn.name = "jgs";
453                 stmt->u.insn.labelref_operand = 2;
454                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
455                 disasm_std_operand(stmt, 0, 0);
456                 disasm_std_operand(stmt, 1, 1);
457                 break;
458         case (0x0D4 | 0x1):
459                 stmt->u.insn.name = "jles";
460                 stmt->u.insn.labelref_operand = 2;
461                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
462                 disasm_std_operand(stmt, 0, 0);
463                 disasm_std_operand(stmt, 1, 1);
464                 break;
465         case 0x0D6:
466                 stmt->u.insn.name = "jdn";
467                 stmt->u.insn.labelref_operand = 2;
468                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
469                 disasm_std_operand(stmt, 0, 0);
470                 disasm_std_operand(stmt, 1, 1);
471                 break;
472         case (0x0D6 | 0x1):
473                 stmt->u.insn.name = "jdpz";
474                 stmt->u.insn.labelref_operand = 2;
475                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
476                 disasm_std_operand(stmt, 0, 0);
477                 disasm_std_operand(stmt, 1, 1);
478                 break;
479         case 0x0D8:
480                 stmt->u.insn.name = "jdp";
481                 stmt->u.insn.labelref_operand = 2;
482                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
483                 disasm_std_operand(stmt, 0, 0);
484                 disasm_std_operand(stmt, 1, 1);
485                 break;
486         case (0x0D8 | 0x1):
487                 stmt->u.insn.name = "jdnz";
488                 stmt->u.insn.labelref_operand = 2;
489                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
490                 disasm_std_operand(stmt, 0, 0);
491                 disasm_std_operand(stmt, 1, 1);
492                 break;
493         case 0x0DA:
494                 stmt->u.insn.name = "jl";
495                 stmt->u.insn.labelref_operand = 2;
496                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
497                 disasm_std_operand(stmt, 0, 0);
498                 disasm_std_operand(stmt, 1, 1);
499                 break;
500         case (0x0DA | 0x1):
501                 stmt->u.insn.name = "jge";
502                 stmt->u.insn.labelref_operand = 2;
503                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
504                 disasm_std_operand(stmt, 0, 0);
505                 disasm_std_operand(stmt, 1, 1);
506                 break;
507         case 0x0DC:
508                 stmt->u.insn.name = "jg";
509                 stmt->u.insn.labelref_operand = 2;
510                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
511                 disasm_std_operand(stmt, 0, 0);
512                 disasm_std_operand(stmt, 1, 1);
513                 break;
514         case (0x0DC | 0x1):
515                 stmt->u.insn.name = "jle";
516                 stmt->u.insn.labelref_operand = 2;
517                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
518                 disasm_std_operand(stmt, 0, 0);
519                 disasm_std_operand(stmt, 1, 1);
520                 break;
521         case 0x002: {
522                 char *str;
523
524                 switch (cmdargs.arch) {
525                 case 5:
526                         stmt->u.insn.name = "call";
527                         stmt->u.insn.labelref_operand = 1;
528                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
529                         str = xmalloc(4);
530                         snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
531                         stmt->u.insn.operands[0] = str;
532                         break;
533                 case 15:
534                         //FIXME: This opcode is different on r15. Decode raw for now.
535                         disasm_opcode_raw(ctx, stmt, 1);
536                         break;
537                 }
538                 break;
539         }
540         case 0x003: {
541                 char *str;
542
543                 stmt->u.insn.name = "ret";
544                 str = xmalloc(4);
545                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
546                 stmt->u.insn.operands[0] = str;
547                 str = xmalloc(4);
548                 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
549                 stmt->u.insn.operands[2] = str;
550                 break;
551         }
552         case 0x004: {
553                 if (cmdargs.arch != 15) {
554                         dasm_error("arch 15 'calls' instruction found in arch %d binary",
555                                    cmdargs.arch);
556                 }
557                 stmt->u.insn.name = "calls";
558                 stmt->u.insn.labelref_operand = 0;
559                 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
560                 if (stmt->u.insn.bin->operands[0] != 0x1780 ||
561                     stmt->u.insn.bin->operands[1] != 0x1780)
562                         dasm_warn("r15 calls: Invalid first or second argument");
563                 break;
564         }
565         case 0x005: {
566                 if (cmdargs.arch != 15) {
567                         dasm_error("arch 15 'rets' instruction found in arch %d binary",
568                                    cmdargs.arch);
569                 }
570                 stmt->u.insn.name = "rets";
571                 if (stmt->u.insn.bin->operands[0] != 0x1780 ||
572                     stmt->u.insn.bin->operands[1] != 0x1780 ||
573                     stmt->u.insn.bin->operands[2] != 0)
574                         dasm_warn("r15 rets: Invalid argument(s)");
575                 break;
576         }
577         case 0x1E0: {
578                 unsigned int flags, mask;
579
580                 switch (cmdargs.arch) {
581                 case 5:
582                         mask = 0x3FF;
583                         break;
584                 case 15:
585                         mask = 0x7FF;
586                         break;
587                 default:
588                         dasm_int_error("TKIP invalid arch");
589                 }
590
591                 flags = stmt->u.insn.bin->operands[1];
592                 switch (flags & mask) {
593                 case 0x1:
594                         stmt->u.insn.name = "tkiph";
595                         break;
596                 case (0x1 | 0x2):
597                         stmt->u.insn.name = "tkiphs";
598                         break;
599                 case 0x0:
600                         stmt->u.insn.name = "tkipl";
601                         break;
602                 case (0x0 | 0x2):
603                         stmt->u.insn.name = "tkipls";
604                         break;
605                 default:
606                         dasm_error("Invalid TKIP flags %X", flags);
607                 }
608                 disasm_std_operand(stmt, 0, 0);
609                 disasm_std_operand(stmt, 2, 2);
610                 break;
611         }
612         case 0x001: {
613                 unsigned int mask;
614
615                 stmt->u.insn.name = "nap";
616                 switch (cmdargs.arch) {
617                 case 5:
618                         mask = 0xBC0;
619                         break;
620                 case 15:
621                         mask = 0x1780;
622                         break;
623                 default:
624                         dasm_int_error("NAP invalid arch");
625                 }
626                 if (stmt->u.insn.bin->operands[0] != mask) {
627                         dasm_warn("NAP: invalid first argument 0x%04X\n",
628                                   stmt->u.insn.bin->operands[0]);
629                 }
630                 if (stmt->u.insn.bin->operands[1] != mask) {
631                         dasm_warn("NAP: invalid second argument 0x%04X\n",
632                                   stmt->u.insn.bin->operands[1]);
633                 }
634                 if (stmt->u.insn.bin->operands[2] != 0) {
635                         dasm_warn("NAP: invalid third argument 0x%04X\n",
636                                   stmt->u.insn.bin->operands[2]);
637                 }
638                 break;
639         }
640         case 0x000:
641                 disasm_opcode_raw(ctx, stmt, 1);
642                 break;
643         default:
644                 disasm_opcode_raw(ctx, stmt, (cmdargs.unknown_decode == 0));
645                 break;
646         }
647 }
648
649 static void disasm_opcodes(struct disassembler_context *ctx)
650 {
651         struct bin_instruction *bin;
652         size_t i;
653         struct statement *stmt;
654         char *str;
655
656         for (i = 0; i < ctx->nr_insns; i++) {
657                 bin = &(ctx->code[i]);
658
659                 stmt = xmalloc(sizeof(struct statement));
660                 stmt->type = STMT_INSN;
661                 INIT_LIST_HEAD(&stmt->list);
662                 stmt->u.insn.bin = bin;
663                 stmt->u.insn.labelref_operand = -1; /* none */
664
665                 switch (bin->opcode & 0xF00) {
666                 case 0x200:
667                         stmt->u.insn.name = "srx";
668
669                         str = xmalloc(3);
670                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
671                         stmt->u.insn.operands[0] = str;
672                         str = xmalloc(3);
673                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
674                         stmt->u.insn.operands[1] = str;
675
676                         disasm_std_operand(stmt, 0, 2);
677                         disasm_std_operand(stmt, 1, 3);
678                         disasm_std_operand(stmt, 2, 4);
679                         break;
680                 case 0x300:
681                         stmt->u.insn.name = "orx";
682
683                         str = xmalloc(3);
684                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
685                         stmt->u.insn.operands[0] = str;
686                         str = xmalloc(3);
687                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
688                         stmt->u.insn.operands[1] = str;
689
690                         disasm_std_operand(stmt, 0, 2);
691                         disasm_std_operand(stmt, 1, 3);
692                         disasm_std_operand(stmt, 2, 4);
693                         break;
694                 case 0x400:
695                         stmt->u.insn.name = "jzx";
696
697                         str = xmalloc(3);
698                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
699                         stmt->u.insn.operands[0] = str;
700                         str = xmalloc(3);
701                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
702                         stmt->u.insn.operands[1] = str;
703
704                         disasm_std_operand(stmt, 0, 2);
705                         disasm_std_operand(stmt, 1, 3);
706                         stmt->u.insn.labelref_operand = 4;
707                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
708                         break;
709                 case 0x500:
710                         stmt->u.insn.name = "jnzx";
711
712                         str = xmalloc(3);
713                         snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
714                         stmt->u.insn.operands[0] = str;
715                         str = xmalloc(3);
716                         snprintf(str, 3, "%d", (bin->opcode & 0x00F));
717                         stmt->u.insn.operands[1] = str;
718
719                         disasm_std_operand(stmt, 0, 2);
720                         disasm_std_operand(stmt, 1, 3);
721                         stmt->u.insn.labelref_operand = 4;
722                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
723                         break;
724                 case 0x600:
725                         stmt->u.insn.name = "jnext";
726
727                         str = xmalloc(5);
728                         snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
729                         stmt->u.insn.operands[0] = str;
730
731                         /* We don't disassemble the first and second operand, as
732                          * that always is a dummy r0 operand.
733                          * disasm_std_operand(stmt, 0, 1);
734                          * disasm_std_operand(stmt, 1, 2);
735                          * stmt->u.insn.labelref_operand = 3;
736                          */
737                         stmt->u.insn.labelref_operand = 1;
738                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
739                         break;
740                 case 0x700:
741                         stmt->u.insn.name = "jext";
742
743                         str = xmalloc(5);
744                         snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
745                         stmt->u.insn.operands[0] = str;
746
747                         /* We don't disassemble the first and second operand, as
748                          * that always is a dummy r0 operand.
749                          * disasm_std_operand(stmt, 0, 1);
750                          * disasm_std_operand(stmt, 1, 2);
751                          * stmt->u.insn.labelref_operand = 3;
752                          */
753                         stmt->u.insn.labelref_operand = 1;
754                         stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
755                         break;
756                 default:
757                         disasm_constant_opcodes(ctx, stmt);
758                         break;
759                 }
760
761                 list_add_tail(&stmt->list, &ctx->stmt_list);
762         }
763 }
764
765 static struct statement * get_label_at(struct disassembler_context *ctx,
766                                        unsigned int addr)
767 {
768         unsigned int addrcnt = 0;
769         struct statement *stmt, *ret, *prev;
770
771         list_for_each_entry(stmt, &ctx->stmt_list, list) {
772                 if (stmt->type != STMT_INSN)
773                         continue;
774                 if (addrcnt == addr) {
775                         prev = list_entry(stmt->list.prev, struct statement, list);
776                         if (prev->type == STMT_LABEL)
777                                 return prev;
778                         ret = xmalloc(sizeof(struct statement));
779                         INIT_LIST_HEAD(&ret->list);
780                         ret->type = STMT_LABEL;
781                         list_add(&ret->list, &prev->list);
782
783                         return ret;
784                 }
785                 addrcnt++;
786         }
787
788         return NULL;
789 }
790
791 static void resolve_labels(struct disassembler_context *ctx)
792 {
793         struct statement *stmt;
794         struct statement *label;
795         struct statement *n;
796         unsigned int labeladdr;
797         unsigned int namecnt = 0;
798
799         /* Resolve label references */
800         list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
801                 if (stmt->type != STMT_INSN)
802                         continue;
803                 if (stmt->u.insn.labelref_operand < 0)
804                         continue; /* Doesn't have label reference operand. */
805                 labeladdr = stmt->u.insn.labeladdr;
806                 label = get_label_at(ctx, labeladdr);
807                 if (!label)
808                         dasm_error("Labeladdress %X out of bounds", labeladdr);
809                 stmt->u.insn.labelref = label;
810         }
811
812         /* Name the labels */
813         list_for_each_entry(stmt, &ctx->stmt_list, list) {
814                 if (stmt->type != STMT_LABEL)
815                         continue;
816                 stmt->u.label.name = xmalloc(20);
817                 snprintf(stmt->u.label.name, 20, "L%u", namecnt);
818                 namecnt++;
819         }
820 }
821
822 static void emit_asm(struct disassembler_context *ctx)
823 {
824         struct statement *stmt;
825         int first;
826         int err;
827         unsigned int i, addr = 0;
828
829         err = open_output_file();
830         if (err)
831                 exit(1);
832
833         fprintf(outfile, "%%arch %u\n", ctx->arch);
834         fprintf(outfile, "%%start entry\n\n");
835         fprintf(outfile, "entry:\n");
836         list_for_each_entry(stmt, &ctx->stmt_list, list) {
837                 switch (stmt->type) {
838                 case STMT_INSN:
839                         if (cmdargs.print_addresses)
840                                 fprintf(outfile, "/* %04X */", addr);
841                         fprintf(outfile, "\t%s", stmt->u.insn.name);
842                         first = 1;
843                         for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
844                                 if (!stmt->u.insn.operands[i] &&
845                                     (stmt->u.insn.labelref_operand < 0 ||
846                                      (unsigned int)stmt->u.insn.labelref_operand != i))
847                                         continue;
848                                 if (first)
849                                         fprintf(outfile, "\t");
850                                 if (!first)
851                                         fprintf(outfile, ", ");
852                                 first = 0;
853                                 if (stmt->u.insn.labelref_operand >= 0 &&
854                                     (unsigned int)stmt->u.insn.labelref_operand == i) {
855                                         fprintf(outfile, "%s",
856                                                 stmt->u.insn.labelref->u.label.name);
857                                 } else {
858                                         fprintf(outfile, "%s",
859                                                 stmt->u.insn.operands[i]);
860                                 }
861                         }
862                         fprintf(outfile, "\n");
863                         addr++;
864                         break;
865                 case STMT_LABEL:
866                         fprintf(outfile, "%s:\n", stmt->u.label.name);
867                         break;
868                 }
869         }
870
871         close_output_file();
872 }
873
874 static int read_input(struct disassembler_context *ctx)
875 {
876         size_t size = 0, pos = 0;
877         size_t ret;
878         struct bin_instruction *code = NULL;
879         unsigned char tmp[sizeof(uint64_t)];
880         uint64_t codeword = 0;
881         struct fw_header hdr;
882         int err;
883
884         err = open_input_file();
885         if (err)
886                 goto error;
887
888         switch (cmdargs.informat) {
889         case FMT_RAW_LE32:
890         case FMT_RAW_BE32:
891                 /* Nothing */
892                 break;
893         case FMT_B43:
894                 ret = fread(&hdr, 1, sizeof(hdr), infile);
895                 if (ret != sizeof(hdr)) {
896                         fprintf(stderr, "Corrupt input file (no b43 header found)\n");
897                         goto err_close;
898                 }
899                 if (hdr.type != FW_TYPE_UCODE) {
900                         fprintf(stderr, "Corrupt input file. Not a b43 microcode image.\n");
901                         goto err_close;
902                 }
903                 if (hdr.ver != FW_HDR_VER) {
904                         fprintf(stderr, "Invalid input file header version.\n");
905                         goto err_close;
906                 }
907                 break;
908         }
909
910         while (1) {
911                 if (pos >= size) {
912                         size += 512;
913                         code = xrealloc(code, size * sizeof(struct bin_instruction));
914                 }
915                 ret = fread(tmp, 1, sizeof(uint64_t), infile);
916                 if (!ret)
917                         break;
918                 if (ret != sizeof(uint64_t)) {
919                         fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
920                         goto err_free_code;
921                 }
922
923                 switch (cmdargs.informat) {
924                 case FMT_B43:
925                 case FMT_RAW_BE32:
926                         codeword = 0;
927                         codeword |= ((uint64_t)tmp[0]) << 56;
928                         codeword |= ((uint64_t)tmp[1]) << 48;
929                         codeword |= ((uint64_t)tmp[2]) << 40;
930                         codeword |= ((uint64_t)tmp[3]) << 32;
931                         codeword |= ((uint64_t)tmp[4]) << 24;
932                         codeword |= ((uint64_t)tmp[5]) << 16;
933                         codeword |= ((uint64_t)tmp[6]) << 8;
934                         codeword |= ((uint64_t)tmp[7]);
935                         codeword = ((codeword & (uint64_t)0xFFFFFFFF00000000ULL) >> 32) |
936                                    ((codeword & (uint64_t)0x00000000FFFFFFFFULL) << 32);
937                         break;
938                 case FMT_RAW_LE32:
939                         codeword = 0;
940                         codeword |= ((uint64_t)tmp[7]) << 56;
941                         codeword |= ((uint64_t)tmp[6]) << 48;
942                         codeword |= ((uint64_t)tmp[5]) << 40;
943                         codeword |= ((uint64_t)tmp[4]) << 32;
944                         codeword |= ((uint64_t)tmp[3]) << 24;
945                         codeword |= ((uint64_t)tmp[2]) << 16;
946                         codeword |= ((uint64_t)tmp[1]) << 8;
947                         codeword |= ((uint64_t)tmp[0]);
948                         break;
949                 }
950
951                 switch (cmdargs.arch) {
952                 case 5:
953                         if (codeword >> 48) {
954                                 fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
955                                         "Wrong input format or architecture?\n", (unsigned int)pos);
956                                 goto err_free_code;
957                         }
958                         code[pos].opcode = (codeword >> 36) & 0xFFF;
959                         code[pos].operands[2] = codeword & 0xFFF;
960                         code[pos].operands[1] = (codeword >> 12) & 0xFFF;
961                         code[pos].operands[0] = (codeword >> 24) & 0xFFF;
962                         break;
963                 case 15:
964                         if (codeword >> 51) {
965                                 fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
966                                         "Wrong input format or architecture?\n", (unsigned int)pos);
967                                 goto err_free_code;
968                         }
969                         code[pos].opcode = (codeword >> 39) & 0xFFF;
970                         code[pos].operands[2] = codeword & 0x1FFF;
971                         code[pos].operands[1] = (codeword >> 13) & 0x1FFF;
972                         code[pos].operands[0] = (codeword >> 26) & 0x1FFF;
973                         break;
974                 default:
975                         fprintf(stderr, "Internal error: read_input unknown arch %u\n",
976                                 cmdargs.arch);
977                         goto err_free_code;
978                 }
979
980                 pos++;
981         }
982
983         ctx->code = code;
984         ctx->nr_insns = pos;
985
986         close_input_file();
987
988         return 0;
989
990 err_free_code:
991         free(code);
992 err_close:
993         close_input_file();
994 error:
995         return -1;
996 }
997
998 static void disassemble(void)
999 {
1000         struct disassembler_context ctx;
1001         int err;
1002
1003         memset(&ctx, 0, sizeof(ctx));
1004         INIT_LIST_HEAD(&ctx.stmt_list);
1005         ctx.arch = cmdargs.arch;
1006
1007         err = read_input(&ctx);
1008         if (err)
1009                 exit(1);
1010         disasm_opcodes(&ctx);
1011         resolve_labels(&ctx);
1012         emit_asm(&ctx);
1013 }
1014
1015 int main(int argc, char **argv)
1016 {
1017         int err, res = 1;
1018
1019         err = parse_args(argc, argv);
1020         if (err < 0)
1021                 goto out;
1022         if (err > 0) {
1023                 res = 0;
1024                 goto out;
1025         }
1026         disassemble();
1027         res = 0;
1028 out:
1029         /* Lazyman simply leaks all allocated memory. */
1030         return res;
1031 }