alpha-dis.c revision 1.1.1.1.2.1 1 1.1 christos /* alpha-dis.c -- Disassemble Alpha AXP instructions
2 1.1.1.1.2.1 pgoyette Copyright (C) 1996-2015 Free Software Foundation, Inc.
3 1.1 christos Contributed by Richard Henderson <rth (at) tamu.edu>,
4 1.1 christos patterned after the PPC opcode handling written by Ian Lance Taylor.
5 1.1 christos
6 1.1 christos This file is part of libopcodes.
7 1.1 christos
8 1.1 christos This library is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3, or (at your option)
11 1.1 christos any later version.
12 1.1 christos
13 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT
14 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 1.1 christos License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this file; see the file COPYING. If not, write to the Free
20 1.1 christos Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21 1.1 christos 02110-1301, USA. */
22 1.1 christos
23 1.1 christos #include "sysdep.h"
24 1.1 christos #include <stdio.h>
25 1.1 christos #include "dis-asm.h"
26 1.1 christos #include "opcode/alpha.h"
27 1.1 christos
28 1.1 christos /* OSF register names. */
29 1.1 christos
30 1.1 christos static const char * const osf_regnames[64] = {
31 1.1 christos "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
32 1.1 christos "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
33 1.1 christos "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
34 1.1 christos "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
35 1.1 christos "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
36 1.1 christos "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
37 1.1 christos "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
38 1.1 christos "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
39 1.1 christos };
40 1.1 christos
41 1.1 christos /* VMS register names. */
42 1.1 christos
43 1.1 christos static const char * const vms_regnames[64] = {
44 1.1 christos "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
45 1.1 christos "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
46 1.1 christos "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
47 1.1 christos "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
48 1.1 christos "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
49 1.1 christos "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
50 1.1 christos "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
51 1.1 christos "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
52 1.1 christos };
53 1.1 christos
54 1.1 christos /* Disassemble Alpha instructions. */
55 1.1 christos
56 1.1 christos int
57 1.1 christos print_insn_alpha (memaddr, info)
58 1.1 christos bfd_vma memaddr;
59 1.1 christos struct disassemble_info *info;
60 1.1 christos {
61 1.1 christos static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
62 1.1 christos const char * const * regnames;
63 1.1 christos const struct alpha_opcode *opcode, *opcode_end;
64 1.1 christos const unsigned char *opindex;
65 1.1 christos unsigned insn, op, isa_mask;
66 1.1 christos int need_comma;
67 1.1 christos
68 1.1 christos /* Initialize the majorop table the first time through */
69 1.1 christos if (!opcode_index[0])
70 1.1 christos {
71 1.1 christos opcode = alpha_opcodes;
72 1.1 christos opcode_end = opcode + alpha_num_opcodes;
73 1.1 christos
74 1.1 christos for (op = 0; op < AXP_NOPS; ++op)
75 1.1 christos {
76 1.1 christos opcode_index[op] = opcode;
77 1.1 christos while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
78 1.1 christos ++opcode;
79 1.1 christos }
80 1.1 christos opcode_index[op] = opcode;
81 1.1 christos }
82 1.1 christos
83 1.1 christos if (info->flavour == bfd_target_evax_flavour)
84 1.1 christos regnames = vms_regnames;
85 1.1 christos else
86 1.1 christos regnames = osf_regnames;
87 1.1 christos
88 1.1 christos isa_mask = AXP_OPCODE_NOPAL;
89 1.1 christos switch (info->mach)
90 1.1 christos {
91 1.1 christos case bfd_mach_alpha_ev4:
92 1.1 christos isa_mask |= AXP_OPCODE_EV4;
93 1.1 christos break;
94 1.1 christos case bfd_mach_alpha_ev5:
95 1.1 christos isa_mask |= AXP_OPCODE_EV5;
96 1.1 christos break;
97 1.1 christos case bfd_mach_alpha_ev6:
98 1.1 christos isa_mask |= AXP_OPCODE_EV6;
99 1.1 christos break;
100 1.1 christos }
101 1.1 christos
102 1.1 christos /* Read the insn into a host word */
103 1.1 christos {
104 1.1 christos bfd_byte buffer[4];
105 1.1 christos int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
106 1.1 christos if (status != 0)
107 1.1 christos {
108 1.1 christos (*info->memory_error_func) (status, memaddr, info);
109 1.1 christos return -1;
110 1.1 christos }
111 1.1 christos insn = bfd_getl32 (buffer);
112 1.1 christos }
113 1.1 christos
114 1.1 christos /* Get the major opcode of the instruction. */
115 1.1 christos op = AXP_OP (insn);
116 1.1 christos
117 1.1 christos /* Find the first match in the opcode table. */
118 1.1 christos opcode_end = opcode_index[op + 1];
119 1.1 christos for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
120 1.1 christos {
121 1.1 christos if ((insn ^ opcode->opcode) & opcode->mask)
122 1.1 christos continue;
123 1.1 christos
124 1.1 christos if (!(opcode->flags & isa_mask))
125 1.1 christos continue;
126 1.1 christos
127 1.1 christos /* Make two passes over the operands. First see if any of them
128 1.1 christos have extraction functions, and, if they do, make sure the
129 1.1 christos instruction is valid. */
130 1.1 christos {
131 1.1 christos int invalid = 0;
132 1.1 christos for (opindex = opcode->operands; *opindex != 0; opindex++)
133 1.1 christos {
134 1.1 christos const struct alpha_operand *operand = alpha_operands + *opindex;
135 1.1 christos if (operand->extract)
136 1.1 christos (*operand->extract) (insn, &invalid);
137 1.1 christos }
138 1.1 christos if (invalid)
139 1.1 christos continue;
140 1.1 christos }
141 1.1 christos
142 1.1 christos /* The instruction is valid. */
143 1.1 christos goto found;
144 1.1 christos }
145 1.1 christos
146 1.1 christos /* No instruction found */
147 1.1 christos (*info->fprintf_func) (info->stream, ".long %#08x", insn);
148 1.1 christos
149 1.1 christos return 4;
150 1.1 christos
151 1.1 christos found:
152 1.1 christos (*info->fprintf_func) (info->stream, "%s", opcode->name);
153 1.1 christos if (opcode->operands[0] != 0)
154 1.1 christos (*info->fprintf_func) (info->stream, "\t");
155 1.1 christos
156 1.1 christos /* Now extract and print the operands. */
157 1.1 christos need_comma = 0;
158 1.1 christos for (opindex = opcode->operands; *opindex != 0; opindex++)
159 1.1 christos {
160 1.1 christos const struct alpha_operand *operand = alpha_operands + *opindex;
161 1.1 christos int value;
162 1.1 christos
163 1.1 christos /* Operands that are marked FAKE are simply ignored. We
164 1.1 christos already made sure that the extract function considered
165 1.1 christos the instruction to be valid. */
166 1.1 christos if ((operand->flags & AXP_OPERAND_FAKE) != 0)
167 1.1 christos continue;
168 1.1 christos
169 1.1 christos /* Extract the value from the instruction. */
170 1.1 christos if (operand->extract)
171 1.1 christos value = (*operand->extract) (insn, (int *) NULL);
172 1.1 christos else
173 1.1 christos {
174 1.1 christos value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
175 1.1 christos if (operand->flags & AXP_OPERAND_SIGNED)
176 1.1 christos {
177 1.1 christos int signbit = 1 << (operand->bits - 1);
178 1.1 christos value = (value ^ signbit) - signbit;
179 1.1 christos }
180 1.1 christos }
181 1.1 christos
182 1.1 christos if (need_comma &&
183 1.1 christos ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA))
184 1.1 christos != AXP_OPERAND_PARENS))
185 1.1 christos {
186 1.1 christos (*info->fprintf_func) (info->stream, ",");
187 1.1 christos }
188 1.1 christos if (operand->flags & AXP_OPERAND_PARENS)
189 1.1 christos (*info->fprintf_func) (info->stream, "(");
190 1.1 christos
191 1.1 christos /* Print the operand as directed by the flags. */
192 1.1 christos if (operand->flags & AXP_OPERAND_IR)
193 1.1 christos (*info->fprintf_func) (info->stream, "%s", regnames[value]);
194 1.1 christos else if (operand->flags & AXP_OPERAND_FPR)
195 1.1 christos (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]);
196 1.1 christos else if (operand->flags & AXP_OPERAND_RELATIVE)
197 1.1 christos (*info->print_address_func) (memaddr + 4 + value, info);
198 1.1 christos else if (operand->flags & AXP_OPERAND_SIGNED)
199 1.1 christos (*info->fprintf_func) (info->stream, "%d", value);
200 1.1 christos else
201 1.1 christos (*info->fprintf_func) (info->stream, "%#x", value);
202 1.1 christos
203 1.1 christos if (operand->flags & AXP_OPERAND_PARENS)
204 1.1 christos (*info->fprintf_func) (info->stream, ")");
205 1.1 christos need_comma = 1;
206 1.1 christos }
207 1.1 christos
208 1.1 christos return 4;
209 1.1 christos }
210