Commit | Line | Data |
---|---|---|
e0001a05 | 1 | /* xtensa-dis.c. Disassembly functions for Xtensa. |
43cd72b9 | 2 | Copyright 2003, 2004 Free Software Foundation, Inc. |
e0001a05 NC |
3 | Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com) |
4 | ||
5 | This file is part of GDB, GAS, and the GNU binutils. | |
6 | ||
7 | GDB, GAS, and the GNU binutils are free software; you can redistribute | |
8 | them and/or modify them under the terms of the GNU General Public | |
9 | License as published by the Free Software Foundation; either version 2, | |
10 | or (at your option) any later version. | |
11 | ||
12 | GDB, GAS, and the GNU binutils are distributed in the hope that they | |
13 | will be useful, but WITHOUT ANY WARRANTY; without even the implied | |
14 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
15 | the GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License along | |
18 | with this file; see the file COPYING. If not, write to the Free | |
19 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
20 | USA. */ | |
21 | ||
22 | #include <stdlib.h> | |
23 | #include <stdio.h> | |
24 | #include <sys/types.h> | |
25 | #include <string.h> | |
26 | #include "xtensa-isa.h" | |
27 | #include "ansidecl.h" | |
43cd72b9 | 28 | #include "libiberty.h" |
e0001a05 NC |
29 | #include "sysdep.h" |
30 | #include "dis-asm.h" | |
31 | ||
32 | #include <setjmp.h> | |
33 | ||
43cd72b9 BW |
34 | extern xtensa_isa xtensa_default_isa; |
35 | ||
e0001a05 NC |
36 | #ifndef MAX |
37 | #define MAX(a,b) (a > b ? a : b) | |
38 | #endif | |
39 | ||
e0001a05 NC |
40 | int show_raw_fields; |
41 | ||
42 | static int fetch_data | |
43cd72b9 | 43 | PARAMS ((struct disassemble_info *, bfd_vma)); |
e0001a05 | 44 | static void print_xtensa_operand |
43cd72b9 | 45 | PARAMS ((bfd_vma, struct disassemble_info *, xtensa_opcode, int, unsigned)); |
e0001a05 | 46 | |
43cd72b9 BW |
47 | struct dis_private |
48 | { | |
e0001a05 NC |
49 | bfd_byte *byte_buf; |
50 | jmp_buf bailout; | |
51 | }; | |
52 | ||
43cd72b9 | 53 | |
e0001a05 | 54 | static int |
118fecd3 | 55 | fetch_data (info, memaddr) |
e0001a05 NC |
56 | struct disassemble_info *info; |
57 | bfd_vma memaddr; | |
e0001a05 NC |
58 | { |
59 | int length, status = 0; | |
60 | struct dis_private *priv = (struct dis_private *) info->private_data; | |
43cd72b9 | 61 | int insn_size = xtensa_isa_maxlength (xtensa_default_isa); |
e0001a05 NC |
62 | |
63 | /* Read the maximum instruction size, padding with zeros if we go past | |
64 | the end of the text section. This code will automatically adjust | |
65 | length when we hit the end of the buffer. */ | |
66 | ||
67 | memset (priv->byte_buf, 0, insn_size); | |
68 | for (length = insn_size; length > 0; length--) | |
69 | { | |
70 | status = (*info->read_memory_func) (memaddr, priv->byte_buf, length, | |
71 | info); | |
72 | if (status == 0) | |
73 | return length; | |
74 | } | |
75 | (*info->memory_error_func) (status, memaddr, info); | |
76 | longjmp (priv->bailout, 1); | |
77 | /*NOTREACHED*/ | |
78 | } | |
79 | ||
80 | ||
81 | static void | |
43cd72b9 | 82 | print_xtensa_operand (memaddr, info, opc, opnd, operand_val) |
e0001a05 NC |
83 | bfd_vma memaddr; |
84 | struct disassemble_info *info; | |
43cd72b9 BW |
85 | xtensa_opcode opc; |
86 | int opnd; | |
e0001a05 | 87 | unsigned operand_val; |
e0001a05 | 88 | { |
43cd72b9 | 89 | xtensa_isa isa = xtensa_default_isa; |
e0001a05 NC |
90 | int signed_operand_val; |
91 | ||
92 | if (show_raw_fields) | |
93 | { | |
94 | if (operand_val < 0xa) | |
95 | (*info->fprintf_func) (info->stream, "%u", operand_val); | |
96 | else | |
97 | (*info->fprintf_func) (info->stream, "0x%x", operand_val); | |
98 | return; | |
99 | } | |
100 | ||
43cd72b9 | 101 | (void) xtensa_operand_decode (isa, opc, opnd, &operand_val); |
e0001a05 NC |
102 | signed_operand_val = (int) operand_val; |
103 | ||
43cd72b9 | 104 | if (xtensa_operand_is_register (isa, opc, opnd) == 0) |
e0001a05 | 105 | { |
43cd72b9 BW |
106 | if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1) |
107 | { | |
108 | (void) xtensa_operand_undo_reloc (isa, opc, opnd, | |
109 | &operand_val, memaddr); | |
110 | info->target = operand_val; | |
111 | (*info->print_address_func) (info->target, info); | |
112 | } | |
e0001a05 | 113 | else |
43cd72b9 BW |
114 | { |
115 | if ((signed_operand_val > -256) && (signed_operand_val < 256)) | |
116 | (*info->fprintf_func) (info->stream, "%d", signed_operand_val); | |
117 | else | |
118 | (*info->fprintf_func) (info->stream, "0x%x", signed_operand_val); | |
119 | } | |
e0001a05 NC |
120 | } |
121 | else | |
43cd72b9 BW |
122 | { |
123 | int i = 1; | |
124 | xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd); | |
125 | (*info->fprintf_func) (info->stream, "%s%u", | |
126 | xtensa_regfile_shortname (isa, opnd_rf), | |
127 | operand_val); | |
128 | while (i < xtensa_operand_num_regs (isa, opc, opnd)) | |
129 | { | |
130 | operand_val++; | |
131 | (*info->fprintf_func) (info->stream, ":%s%u", | |
132 | xtensa_regfile_shortname (isa, opnd_rf), | |
133 | operand_val); | |
134 | i++; | |
135 | } | |
136 | } | |
e0001a05 NC |
137 | } |
138 | ||
139 | ||
140 | /* Print the Xtensa instruction at address MEMADDR on info->stream. | |
141 | Returns length of the instruction in bytes. */ | |
142 | ||
143 | int | |
144 | print_insn_xtensa (memaddr, info) | |
145 | bfd_vma memaddr; | |
146 | struct disassemble_info *info; | |
147 | { | |
148 | unsigned operand_val; | |
43cd72b9 | 149 | int bytes_fetched, size, maxsize, i, n, noperands, nslots; |
e0001a05 NC |
150 | xtensa_isa isa; |
151 | xtensa_opcode opc; | |
43cd72b9 | 152 | xtensa_format fmt; |
e0001a05 NC |
153 | struct dis_private priv; |
154 | static bfd_byte *byte_buf = NULL; | |
155 | static xtensa_insnbuf insn_buffer = NULL; | |
43cd72b9 BW |
156 | static xtensa_insnbuf slot_buffer = NULL; |
157 | int first, first_slot, valid_insn; | |
e0001a05 NC |
158 | |
159 | if (!xtensa_default_isa) | |
43cd72b9 | 160 | xtensa_default_isa = xtensa_isa_init (0, 0); |
e0001a05 NC |
161 | |
162 | info->target = 0; | |
43cd72b9 | 163 | maxsize = xtensa_isa_maxlength (xtensa_default_isa); |
e0001a05 NC |
164 | |
165 | /* Set bytes_per_line to control the amount of whitespace between the hex | |
166 | values and the opcode. For Xtensa, we always print one "chunk" and we | |
167 | vary bytes_per_chunk to determine how many bytes to print. (objdump | |
168 | would apparently prefer that we set bytes_per_chunk to 1 and vary | |
169 | bytes_per_line but that makes it hard to fit 64-bit instructions on | |
170 | an 80-column screen.) The value of bytes_per_line here is not exactly | |
171 | right, because objdump adds an extra space for each chunk so that the | |
172 | amount of whitespace depends on the chunk size. Oh well, it's good | |
173 | enough.... Note that we set the minimum size to 4 to accomodate | |
174 | literal pools. */ | |
175 | info->bytes_per_line = MAX (maxsize, 4); | |
176 | ||
177 | /* Allocate buffers the first time through. */ | |
178 | if (!insn_buffer) | |
43cd72b9 BW |
179 | { |
180 | insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); | |
181 | slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); | |
182 | byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4)); | |
183 | } | |
e0001a05 NC |
184 | |
185 | priv.byte_buf = byte_buf; | |
186 | ||
187 | info->private_data = (PTR) &priv; | |
188 | if (setjmp (priv.bailout) != 0) | |
189 | /* Error return. */ | |
190 | return -1; | |
191 | ||
192 | /* Don't set "isa" before the setjmp to keep the compiler from griping. */ | |
193 | isa = xtensa_default_isa; | |
43cd72b9 BW |
194 | size = 0; |
195 | nslots = 0; | |
e0001a05 NC |
196 | |
197 | /* Fetch the maximum size instruction. */ | |
118fecd3 | 198 | bytes_fetched = fetch_data (info, memaddr); |
e0001a05 NC |
199 | |
200 | /* Copy the bytes into the decode buffer. */ | |
201 | memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) * | |
202 | sizeof (xtensa_insnbuf_word))); | |
43cd72b9 BW |
203 | xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf, bytes_fetched); |
204 | ||
205 | fmt = xtensa_format_decode (isa, insn_buffer); | |
206 | if (fmt == XTENSA_UNDEFINED | |
207 | || ((size = xtensa_format_length (isa, fmt)) > bytes_fetched)) | |
208 | valid_insn = 0; | |
209 | else | |
210 | { | |
211 | /* Make sure all the opcodes are valid. */ | |
212 | valid_insn = 1; | |
213 | nslots = xtensa_format_num_slots (isa, fmt); | |
214 | for (n = 0; n < nslots; n++) | |
215 | { | |
216 | xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); | |
217 | if (xtensa_opcode_decode (isa, fmt, n, slot_buffer) | |
218 | == XTENSA_UNDEFINED) | |
219 | { | |
220 | valid_insn = 0; | |
221 | break; | |
222 | } | |
223 | } | |
224 | } | |
e0001a05 | 225 | |
43cd72b9 | 226 | if (!valid_insn) |
e0001a05 NC |
227 | { |
228 | (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]); | |
229 | return 1; | |
230 | } | |
231 | ||
43cd72b9 BW |
232 | if (nslots > 1) |
233 | (*info->fprintf_func) (info->stream, "{ "); | |
e0001a05 | 234 | |
43cd72b9 BW |
235 | first_slot = 1; |
236 | for (n = 0; n < nslots; n++) | |
e0001a05 | 237 | { |
43cd72b9 BW |
238 | if (first_slot) |
239 | first_slot = 0; | |
240 | else | |
241 | (*info->fprintf_func) (info->stream, "; "); | |
242 | ||
243 | xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); | |
244 | opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer); | |
245 | (*info->fprintf_func) (info->stream, "%s", | |
246 | xtensa_opcode_name (isa, opc)); | |
e0001a05 | 247 | |
43cd72b9 BW |
248 | /* Print the operands (if any). */ |
249 | noperands = xtensa_opcode_num_operands (isa, opc); | |
250 | first = 1; | |
e0001a05 NC |
251 | for (i = 0; i < noperands; i++) |
252 | { | |
43cd72b9 BW |
253 | if (xtensa_operand_is_visible (isa, opc, i) == 0) |
254 | continue; | |
e0001a05 | 255 | if (first) |
43cd72b9 BW |
256 | { |
257 | (*info->fprintf_func) (info->stream, "\t"); | |
258 | first = 0; | |
259 | } | |
e0001a05 NC |
260 | else |
261 | (*info->fprintf_func) (info->stream, ", "); | |
43cd72b9 BW |
262 | (void) xtensa_operand_get_field (isa, opc, i, fmt, n, |
263 | slot_buffer, &operand_val); | |
264 | ||
265 | print_xtensa_operand (memaddr, info, opc, i, operand_val); | |
266 | } | |
e0001a05 NC |
267 | } |
268 | ||
43cd72b9 BW |
269 | if (nslots > 1) |
270 | (*info->fprintf_func) (info->stream, " }"); | |
271 | ||
e0001a05 NC |
272 | info->bytes_per_chunk = size; |
273 | info->display_endian = info->endian; | |
274 | ||
275 | return size; | |
276 | } | |
277 |