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 | |
f4321104 | 19 | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, |
e0001a05 NC |
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 | ||
43cd72b9 BW |
42 | struct dis_private |
43 | { | |
e0001a05 NC |
44 | bfd_byte *byte_buf; |
45 | jmp_buf bailout; | |
46 | }; | |
47 | ||
43cd72b9 | 48 | |
e0001a05 | 49 | static int |
7fa3d080 | 50 | fetch_data (struct disassemble_info *info, bfd_vma memaddr) |
e0001a05 NC |
51 | { |
52 | int length, status = 0; | |
53 | struct dis_private *priv = (struct dis_private *) info->private_data; | |
43cd72b9 | 54 | int insn_size = xtensa_isa_maxlength (xtensa_default_isa); |
e0001a05 NC |
55 | |
56 | /* Read the maximum instruction size, padding with zeros if we go past | |
57 | the end of the text section. This code will automatically adjust | |
58 | length when we hit the end of the buffer. */ | |
59 | ||
60 | memset (priv->byte_buf, 0, insn_size); | |
61 | for (length = insn_size; length > 0; length--) | |
62 | { | |
63 | status = (*info->read_memory_func) (memaddr, priv->byte_buf, length, | |
64 | info); | |
65 | if (status == 0) | |
66 | return length; | |
67 | } | |
68 | (*info->memory_error_func) (status, memaddr, info); | |
69 | longjmp (priv->bailout, 1); | |
70 | /*NOTREACHED*/ | |
71 | } | |
72 | ||
73 | ||
74 | static void | |
7fa3d080 BW |
75 | print_xtensa_operand (bfd_vma memaddr, |
76 | struct disassemble_info *info, | |
77 | xtensa_opcode opc, | |
78 | int opnd, | |
79 | unsigned operand_val) | |
e0001a05 | 80 | { |
43cd72b9 | 81 | xtensa_isa isa = xtensa_default_isa; |
e0001a05 NC |
82 | int signed_operand_val; |
83 | ||
84 | if (show_raw_fields) | |
85 | { | |
86 | if (operand_val < 0xa) | |
87 | (*info->fprintf_func) (info->stream, "%u", operand_val); | |
88 | else | |
89 | (*info->fprintf_func) (info->stream, "0x%x", operand_val); | |
90 | return; | |
91 | } | |
92 | ||
43cd72b9 | 93 | (void) xtensa_operand_decode (isa, opc, opnd, &operand_val); |
e0001a05 NC |
94 | signed_operand_val = (int) operand_val; |
95 | ||
43cd72b9 | 96 | if (xtensa_operand_is_register (isa, opc, opnd) == 0) |
e0001a05 | 97 | { |
43cd72b9 BW |
98 | if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1) |
99 | { | |
100 | (void) xtensa_operand_undo_reloc (isa, opc, opnd, | |
101 | &operand_val, memaddr); | |
102 | info->target = operand_val; | |
103 | (*info->print_address_func) (info->target, info); | |
104 | } | |
e0001a05 | 105 | else |
43cd72b9 BW |
106 | { |
107 | if ((signed_operand_val > -256) && (signed_operand_val < 256)) | |
108 | (*info->fprintf_func) (info->stream, "%d", signed_operand_val); | |
109 | else | |
110 | (*info->fprintf_func) (info->stream, "0x%x", signed_operand_val); | |
111 | } | |
e0001a05 NC |
112 | } |
113 | else | |
43cd72b9 BW |
114 | { |
115 | int i = 1; | |
116 | xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd); | |
117 | (*info->fprintf_func) (info->stream, "%s%u", | |
118 | xtensa_regfile_shortname (isa, opnd_rf), | |
119 | operand_val); | |
120 | while (i < xtensa_operand_num_regs (isa, opc, opnd)) | |
121 | { | |
122 | operand_val++; | |
123 | (*info->fprintf_func) (info->stream, ":%s%u", | |
124 | xtensa_regfile_shortname (isa, opnd_rf), | |
125 | operand_val); | |
126 | i++; | |
127 | } | |
128 | } | |
e0001a05 NC |
129 | } |
130 | ||
131 | ||
132 | /* Print the Xtensa instruction at address MEMADDR on info->stream. | |
133 | Returns length of the instruction in bytes. */ | |
134 | ||
135 | int | |
7fa3d080 | 136 | print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info) |
e0001a05 NC |
137 | { |
138 | unsigned operand_val; | |
43cd72b9 | 139 | int bytes_fetched, size, maxsize, i, n, noperands, nslots; |
e0001a05 NC |
140 | xtensa_isa isa; |
141 | xtensa_opcode opc; | |
43cd72b9 | 142 | xtensa_format fmt; |
e0001a05 NC |
143 | struct dis_private priv; |
144 | static bfd_byte *byte_buf = NULL; | |
145 | static xtensa_insnbuf insn_buffer = NULL; | |
43cd72b9 BW |
146 | static xtensa_insnbuf slot_buffer = NULL; |
147 | int first, first_slot, valid_insn; | |
e0001a05 NC |
148 | |
149 | if (!xtensa_default_isa) | |
43cd72b9 | 150 | xtensa_default_isa = xtensa_isa_init (0, 0); |
e0001a05 NC |
151 | |
152 | info->target = 0; | |
43cd72b9 | 153 | maxsize = xtensa_isa_maxlength (xtensa_default_isa); |
e0001a05 NC |
154 | |
155 | /* Set bytes_per_line to control the amount of whitespace between the hex | |
156 | values and the opcode. For Xtensa, we always print one "chunk" and we | |
157 | vary bytes_per_chunk to determine how many bytes to print. (objdump | |
158 | would apparently prefer that we set bytes_per_chunk to 1 and vary | |
159 | bytes_per_line but that makes it hard to fit 64-bit instructions on | |
160 | an 80-column screen.) The value of bytes_per_line here is not exactly | |
161 | right, because objdump adds an extra space for each chunk so that the | |
162 | amount of whitespace depends on the chunk size. Oh well, it's good | |
163 | enough.... Note that we set the minimum size to 4 to accomodate | |
164 | literal pools. */ | |
165 | info->bytes_per_line = MAX (maxsize, 4); | |
166 | ||
167 | /* Allocate buffers the first time through. */ | |
168 | if (!insn_buffer) | |
43cd72b9 BW |
169 | { |
170 | insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); | |
171 | slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); | |
172 | byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4)); | |
173 | } | |
e0001a05 NC |
174 | |
175 | priv.byte_buf = byte_buf; | |
176 | ||
7fa3d080 | 177 | info->private_data = (void *) &priv; |
e0001a05 NC |
178 | if (setjmp (priv.bailout) != 0) |
179 | /* Error return. */ | |
180 | return -1; | |
181 | ||
182 | /* Don't set "isa" before the setjmp to keep the compiler from griping. */ | |
183 | isa = xtensa_default_isa; | |
43cd72b9 BW |
184 | size = 0; |
185 | nslots = 0; | |
e0001a05 NC |
186 | |
187 | /* Fetch the maximum size instruction. */ | |
118fecd3 | 188 | bytes_fetched = fetch_data (info, memaddr); |
e0001a05 NC |
189 | |
190 | /* Copy the bytes into the decode buffer. */ | |
191 | memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) * | |
192 | sizeof (xtensa_insnbuf_word))); | |
43cd72b9 BW |
193 | xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf, bytes_fetched); |
194 | ||
195 | fmt = xtensa_format_decode (isa, insn_buffer); | |
196 | if (fmt == XTENSA_UNDEFINED | |
197 | || ((size = xtensa_format_length (isa, fmt)) > bytes_fetched)) | |
198 | valid_insn = 0; | |
199 | else | |
200 | { | |
201 | /* Make sure all the opcodes are valid. */ | |
202 | valid_insn = 1; | |
203 | nslots = xtensa_format_num_slots (isa, fmt); | |
204 | for (n = 0; n < nslots; n++) | |
205 | { | |
206 | xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); | |
207 | if (xtensa_opcode_decode (isa, fmt, n, slot_buffer) | |
208 | == XTENSA_UNDEFINED) | |
209 | { | |
210 | valid_insn = 0; | |
211 | break; | |
212 | } | |
213 | } | |
214 | } | |
e0001a05 | 215 | |
43cd72b9 | 216 | if (!valid_insn) |
e0001a05 NC |
217 | { |
218 | (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]); | |
219 | return 1; | |
220 | } | |
221 | ||
43cd72b9 BW |
222 | if (nslots > 1) |
223 | (*info->fprintf_func) (info->stream, "{ "); | |
e0001a05 | 224 | |
43cd72b9 BW |
225 | first_slot = 1; |
226 | for (n = 0; n < nslots; n++) | |
e0001a05 | 227 | { |
43cd72b9 BW |
228 | if (first_slot) |
229 | first_slot = 0; | |
230 | else | |
231 | (*info->fprintf_func) (info->stream, "; "); | |
232 | ||
233 | xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer); | |
234 | opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer); | |
235 | (*info->fprintf_func) (info->stream, "%s", | |
236 | xtensa_opcode_name (isa, opc)); | |
e0001a05 | 237 | |
43cd72b9 BW |
238 | /* Print the operands (if any). */ |
239 | noperands = xtensa_opcode_num_operands (isa, opc); | |
240 | first = 1; | |
e0001a05 NC |
241 | for (i = 0; i < noperands; i++) |
242 | { | |
43cd72b9 BW |
243 | if (xtensa_operand_is_visible (isa, opc, i) == 0) |
244 | continue; | |
e0001a05 | 245 | if (first) |
43cd72b9 BW |
246 | { |
247 | (*info->fprintf_func) (info->stream, "\t"); | |
248 | first = 0; | |
249 | } | |
e0001a05 NC |
250 | else |
251 | (*info->fprintf_func) (info->stream, ", "); | |
43cd72b9 BW |
252 | (void) xtensa_operand_get_field (isa, opc, i, fmt, n, |
253 | slot_buffer, &operand_val); | |
254 | ||
255 | print_xtensa_operand (memaddr, info, opc, i, operand_val); | |
256 | } | |
e0001a05 NC |
257 | } |
258 | ||
43cd72b9 BW |
259 | if (nslots > 1) |
260 | (*info->fprintf_func) (info->stream, " }"); | |
261 | ||
e0001a05 NC |
262 | info->bytes_per_chunk = size; |
263 | info->display_endian = info->endian; | |
264 | ||
265 | return size; | |
266 | } | |
267 |