1ed0d50c3Schristos /* xtensa-dis.c. Disassembly functions for Xtensa.
2*b88e3e88Schristos Copyright (C) 2003-2020 Free Software Foundation, Inc.
3ed0d50c3Schristos Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com)
4ed0d50c3Schristos
5ed0d50c3Schristos This file is part of the GNU opcodes library.
6ed0d50c3Schristos
7ed0d50c3Schristos This library is free software; you can redistribute it and/or modify
8ed0d50c3Schristos it under the terms of the GNU General Public License as published by
9ed0d50c3Schristos the Free Software Foundation; either version 3, or (at your option)
10ed0d50c3Schristos any later version.
11ed0d50c3Schristos
12ed0d50c3Schristos It is distributed in the hope that it will be useful, but WITHOUT
13ed0d50c3Schristos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14ed0d50c3Schristos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15ed0d50c3Schristos License for more details.
16ed0d50c3Schristos
17ed0d50c3Schristos You should have received a copy of the GNU General Public License
18ed0d50c3Schristos along with this file; see the file COPYING. If not, write to the
19ed0d50c3Schristos Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20ed0d50c3Schristos MA 02110-1301, USA. */
21ed0d50c3Schristos
22ed0d50c3Schristos #include "sysdep.h"
23ed0d50c3Schristos #include <stdlib.h>
24ed0d50c3Schristos #include <stdio.h>
25ed0d50c3Schristos #include <sys/types.h>
26ed0d50c3Schristos #include <string.h>
27ed0d50c3Schristos #include "xtensa-isa.h"
28ed0d50c3Schristos #include "ansidecl.h"
29ed0d50c3Schristos #include "libiberty.h"
3006324dcfSchristos #include "bfd.h"
3106324dcfSchristos #include "elf/xtensa.h"
3206324dcfSchristos #include "disassemble.h"
33ed0d50c3Schristos
34ed0d50c3Schristos #include <setjmp.h>
35ed0d50c3Schristos
36ed0d50c3Schristos extern xtensa_isa xtensa_default_isa;
37ed0d50c3Schristos
38ed0d50c3Schristos #ifndef MAX
39ed0d50c3Schristos #define MAX(a,b) (a > b ? a : b)
40ed0d50c3Schristos #endif
41ed0d50c3Schristos
42ed0d50c3Schristos int show_raw_fields;
43ed0d50c3Schristos
44ed0d50c3Schristos struct dis_private
45ed0d50c3Schristos {
46ed0d50c3Schristos bfd_byte *byte_buf;
47ed0d50c3Schristos OPCODES_SIGJMP_BUF bailout;
4806324dcfSchristos /* Persistent fields, valid for last_section only. */
4906324dcfSchristos asection *last_section;
5006324dcfSchristos property_table_entry *insn_table_entries;
5106324dcfSchristos int insn_table_entry_count;
5206324dcfSchristos /* Cached property table search position. */
5306324dcfSchristos bfd_vma insn_table_cur_addr;
5406324dcfSchristos int insn_table_cur_idx;
55ed0d50c3Schristos };
56ed0d50c3Schristos
5706324dcfSchristos static void
xtensa_coalesce_insn_tables(struct dis_private * priv)5806324dcfSchristos xtensa_coalesce_insn_tables (struct dis_private *priv)
5906324dcfSchristos {
6006324dcfSchristos const int mask = ~(XTENSA_PROP_DATA | XTENSA_PROP_NO_TRANSFORM);
6106324dcfSchristos int count = priv->insn_table_entry_count;
6206324dcfSchristos int i, j;
6306324dcfSchristos
6406324dcfSchristos /* Loop over all entries, combining adjacent ones that differ only in
6506324dcfSchristos the flag bits XTENSA_PROP_DATA and XTENSA_PROP_NO_TRANSFORM. */
6606324dcfSchristos
6706324dcfSchristos for (i = j = 0; j < count; ++i)
6806324dcfSchristos {
6906324dcfSchristos property_table_entry *entry = priv->insn_table_entries + i;
7006324dcfSchristos
7106324dcfSchristos *entry = priv->insn_table_entries[j];
7206324dcfSchristos
7306324dcfSchristos for (++j; j < count; ++j)
7406324dcfSchristos {
7506324dcfSchristos property_table_entry *next = priv->insn_table_entries + j;
7606324dcfSchristos int fill = xtensa_compute_fill_extra_space (entry);
7706324dcfSchristos int size = entry->size + fill;
7806324dcfSchristos
7906324dcfSchristos if (entry->address + size == next->address)
8006324dcfSchristos {
8106324dcfSchristos int entry_flags = entry->flags & mask;
8206324dcfSchristos int next_flags = next->flags & mask;
8306324dcfSchristos
8406324dcfSchristos if (next_flags == entry_flags)
8506324dcfSchristos entry->size = next->address - entry->address + next->size;
8606324dcfSchristos else
8706324dcfSchristos break;
8806324dcfSchristos }
8906324dcfSchristos else
9006324dcfSchristos {
9106324dcfSchristos break;
9206324dcfSchristos }
9306324dcfSchristos }
9406324dcfSchristos }
9506324dcfSchristos priv->insn_table_entry_count = i;
9606324dcfSchristos }
9706324dcfSchristos
9806324dcfSchristos static property_table_entry *
xtensa_find_table_entry(bfd_vma memaddr,struct disassemble_info * info)9906324dcfSchristos xtensa_find_table_entry (bfd_vma memaddr, struct disassemble_info *info)
10006324dcfSchristos {
10106324dcfSchristos struct dis_private *priv = (struct dis_private *) info->private_data;
10206324dcfSchristos int i;
10306324dcfSchristos
10406324dcfSchristos if (priv->insn_table_entries == NULL
10506324dcfSchristos || priv->insn_table_entry_count < 0)
10606324dcfSchristos return NULL;
10706324dcfSchristos
10806324dcfSchristos if (memaddr < priv->insn_table_cur_addr)
10906324dcfSchristos priv->insn_table_cur_idx = 0;
11006324dcfSchristos
11106324dcfSchristos for (i = priv->insn_table_cur_idx; i < priv->insn_table_entry_count; ++i)
11206324dcfSchristos {
11306324dcfSchristos property_table_entry *block = priv->insn_table_entries + i;
11406324dcfSchristos
11506324dcfSchristos if (block->size != 0)
11606324dcfSchristos {
11706324dcfSchristos if ((memaddr >= block->address
11806324dcfSchristos && memaddr < block->address + block->size)
11906324dcfSchristos || memaddr < block->address)
12006324dcfSchristos {
12106324dcfSchristos priv->insn_table_cur_addr = memaddr;
12206324dcfSchristos priv->insn_table_cur_idx = i;
12306324dcfSchristos return block;
12406324dcfSchristos }
12506324dcfSchristos }
12606324dcfSchristos }
12706324dcfSchristos return NULL;
12806324dcfSchristos }
12906324dcfSchristos
13006324dcfSchristos /* Check whether an instruction crosses an instruction block boundary
13106324dcfSchristos (according to property tables).
13206324dcfSchristos If it does, return 0 (doesn't fit), else return 1. */
13306324dcfSchristos
13406324dcfSchristos static int
xtensa_instruction_fits(bfd_vma memaddr,int size,property_table_entry * insn_block)13506324dcfSchristos xtensa_instruction_fits (bfd_vma memaddr, int size,
13606324dcfSchristos property_table_entry *insn_block)
13706324dcfSchristos {
13806324dcfSchristos unsigned max_size;
13906324dcfSchristos
14006324dcfSchristos /* If no property table info, assume it fits. */
14106324dcfSchristos if (insn_block == NULL || size <= 0)
14206324dcfSchristos return 1;
14306324dcfSchristos
14406324dcfSchristos /* If too high, limit nextstop by the next insn address. */
14506324dcfSchristos if (insn_block->address > memaddr)
14606324dcfSchristos {
14706324dcfSchristos /* memaddr is not in an instruction block, but is followed by one. */
14806324dcfSchristos max_size = insn_block->address - memaddr;
14906324dcfSchristos }
15006324dcfSchristos else
15106324dcfSchristos {
15206324dcfSchristos /* memaddr is in an instruction block, go no further than the end. */
15306324dcfSchristos max_size = insn_block->address + insn_block->size - memaddr;
15406324dcfSchristos }
15506324dcfSchristos
15606324dcfSchristos /* Crossing a boundary, doesn't "fit". */
15706324dcfSchristos if ((unsigned)size > max_size)
15806324dcfSchristos return 0;
15906324dcfSchristos return 1;
16006324dcfSchristos }
161ed0d50c3Schristos
162ed0d50c3Schristos static int
fetch_data(struct disassemble_info * info,bfd_vma memaddr)163ed0d50c3Schristos fetch_data (struct disassemble_info *info, bfd_vma memaddr)
164ed0d50c3Schristos {
165ed0d50c3Schristos int length, status = 0;
166ed0d50c3Schristos struct dis_private *priv = (struct dis_private *) info->private_data;
167ed0d50c3Schristos int insn_size = xtensa_isa_maxlength (xtensa_default_isa);
168ed0d50c3Schristos
16906324dcfSchristos insn_size = MAX (insn_size, 4);
17006324dcfSchristos
171ed0d50c3Schristos /* Read the maximum instruction size, padding with zeros if we go past
172ed0d50c3Schristos the end of the text section. This code will automatically adjust
173ed0d50c3Schristos length when we hit the end of the buffer. */
174ed0d50c3Schristos
175ed0d50c3Schristos memset (priv->byte_buf, 0, insn_size);
176ed0d50c3Schristos for (length = insn_size; length > 0; length--)
177ed0d50c3Schristos {
178ed0d50c3Schristos status = (*info->read_memory_func) (memaddr, priv->byte_buf, length,
179ed0d50c3Schristos info);
180ed0d50c3Schristos if (status == 0)
181ed0d50c3Schristos return length;
182ed0d50c3Schristos }
183ed0d50c3Schristos (*info->memory_error_func) (status, memaddr, info);
184ed0d50c3Schristos OPCODES_SIGLONGJMP (priv->bailout, 1);
185ed0d50c3Schristos /*NOTREACHED*/
186ed0d50c3Schristos }
187ed0d50c3Schristos
188ed0d50c3Schristos
189ed0d50c3Schristos static void
print_xtensa_operand(bfd_vma memaddr,struct disassemble_info * info,xtensa_opcode opc,int opnd,unsigned operand_val)190ed0d50c3Schristos print_xtensa_operand (bfd_vma memaddr,
191ed0d50c3Schristos struct disassemble_info *info,
192ed0d50c3Schristos xtensa_opcode opc,
193ed0d50c3Schristos int opnd,
194ed0d50c3Schristos unsigned operand_val)
195ed0d50c3Schristos {
196ed0d50c3Schristos xtensa_isa isa = xtensa_default_isa;
197ed0d50c3Schristos int signed_operand_val;
198ed0d50c3Schristos
199ed0d50c3Schristos if (show_raw_fields)
200ed0d50c3Schristos {
201ed0d50c3Schristos if (operand_val < 0xa)
202ed0d50c3Schristos (*info->fprintf_func) (info->stream, "%u", operand_val);
203ed0d50c3Schristos else
204ed0d50c3Schristos (*info->fprintf_func) (info->stream, "0x%x", operand_val);
205ed0d50c3Schristos return;
206ed0d50c3Schristos }
207ed0d50c3Schristos
208ed0d50c3Schristos (void) xtensa_operand_decode (isa, opc, opnd, &operand_val);
209ed0d50c3Schristos signed_operand_val = (int) operand_val;
210ed0d50c3Schristos
211ed0d50c3Schristos if (xtensa_operand_is_register (isa, opc, opnd) == 0)
212ed0d50c3Schristos {
213ed0d50c3Schristos if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
214ed0d50c3Schristos {
215ed0d50c3Schristos (void) xtensa_operand_undo_reloc (isa, opc, opnd,
216ed0d50c3Schristos &operand_val, memaddr);
217ed0d50c3Schristos info->target = operand_val;
218ed0d50c3Schristos (*info->print_address_func) (info->target, info);
219ed0d50c3Schristos }
220ed0d50c3Schristos else
221ed0d50c3Schristos {
222ed0d50c3Schristos if ((signed_operand_val > -256) && (signed_operand_val < 256))
223ed0d50c3Schristos (*info->fprintf_func) (info->stream, "%d", signed_operand_val);
224ed0d50c3Schristos else
225ed0d50c3Schristos (*info->fprintf_func) (info->stream, "0x%x", signed_operand_val);
226ed0d50c3Schristos }
227ed0d50c3Schristos }
228ed0d50c3Schristos else
229ed0d50c3Schristos {
230ed0d50c3Schristos int i = 1;
231ed0d50c3Schristos xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd);
232ed0d50c3Schristos (*info->fprintf_func) (info->stream, "%s%u",
233ed0d50c3Schristos xtensa_regfile_shortname (isa, opnd_rf),
234ed0d50c3Schristos operand_val);
235ed0d50c3Schristos while (i < xtensa_operand_num_regs (isa, opc, opnd))
236ed0d50c3Schristos {
237ed0d50c3Schristos operand_val++;
238ed0d50c3Schristos (*info->fprintf_func) (info->stream, ":%s%u",
239ed0d50c3Schristos xtensa_regfile_shortname (isa, opnd_rf),
240ed0d50c3Schristos operand_val);
241ed0d50c3Schristos i++;
242ed0d50c3Schristos }
243ed0d50c3Schristos }
244ed0d50c3Schristos }
245ed0d50c3Schristos
246ed0d50c3Schristos
247ed0d50c3Schristos /* Print the Xtensa instruction at address MEMADDR on info->stream.
248ed0d50c3Schristos Returns length of the instruction in bytes. */
249ed0d50c3Schristos
250ed0d50c3Schristos int
print_insn_xtensa(bfd_vma memaddr,struct disassemble_info * info)251ed0d50c3Schristos print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info)
252ed0d50c3Schristos {
253ed0d50c3Schristos unsigned operand_val;
254ed0d50c3Schristos int bytes_fetched, size, maxsize, i, n, noperands, nslots;
255ed0d50c3Schristos xtensa_isa isa;
256ed0d50c3Schristos xtensa_opcode opc;
257ed0d50c3Schristos xtensa_format fmt;
25806324dcfSchristos static struct dis_private priv;
259ed0d50c3Schristos static bfd_byte *byte_buf = NULL;
260ed0d50c3Schristos static xtensa_insnbuf insn_buffer = NULL;
261ed0d50c3Schristos static xtensa_insnbuf slot_buffer = NULL;
262ed0d50c3Schristos int first, first_slot, valid_insn;
26306324dcfSchristos property_table_entry *insn_block;
264ed0d50c3Schristos
265ed0d50c3Schristos if (!xtensa_default_isa)
266ed0d50c3Schristos xtensa_default_isa = xtensa_isa_init (0, 0);
267ed0d50c3Schristos
268ed0d50c3Schristos info->target = 0;
269ed0d50c3Schristos maxsize = xtensa_isa_maxlength (xtensa_default_isa);
270ed0d50c3Schristos
271ed0d50c3Schristos /* Set bytes_per_line to control the amount of whitespace between the hex
272ed0d50c3Schristos values and the opcode. For Xtensa, we always print one "chunk" and we
273ed0d50c3Schristos vary bytes_per_chunk to determine how many bytes to print. (objdump
274ed0d50c3Schristos would apparently prefer that we set bytes_per_chunk to 1 and vary
275ed0d50c3Schristos bytes_per_line but that makes it hard to fit 64-bit instructions on
276ed0d50c3Schristos an 80-column screen.) The value of bytes_per_line here is not exactly
277ed0d50c3Schristos right, because objdump adds an extra space for each chunk so that the
278ed0d50c3Schristos amount of whitespace depends on the chunk size. Oh well, it's good
279ed0d50c3Schristos enough.... Note that we set the minimum size to 4 to accomodate
280ed0d50c3Schristos literal pools. */
281ed0d50c3Schristos info->bytes_per_line = MAX (maxsize, 4);
282ed0d50c3Schristos
283ed0d50c3Schristos /* Allocate buffers the first time through. */
284ed0d50c3Schristos if (!insn_buffer)
285ed0d50c3Schristos {
286ed0d50c3Schristos insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
287ed0d50c3Schristos slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
288ed0d50c3Schristos byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4));
289ed0d50c3Schristos }
290ed0d50c3Schristos
291ed0d50c3Schristos priv.byte_buf = byte_buf;
292ed0d50c3Schristos
293ed0d50c3Schristos info->private_data = (void *) &priv;
29406324dcfSchristos
29506324dcfSchristos /* Prepare instruction tables. */
29606324dcfSchristos
29706324dcfSchristos if (info->section != NULL)
29806324dcfSchristos {
29906324dcfSchristos asection *section = info->section;
30006324dcfSchristos
30106324dcfSchristos if (priv.last_section != section)
30206324dcfSchristos {
30306324dcfSchristos bfd *abfd = section->owner;
30406324dcfSchristos
30506324dcfSchristos if (priv.last_section != NULL)
30606324dcfSchristos {
30706324dcfSchristos /* Reset insn_table_entries. */
30806324dcfSchristos priv.insn_table_entry_count = 0;
30906324dcfSchristos if (priv.insn_table_entries)
31006324dcfSchristos free (priv.insn_table_entries);
31106324dcfSchristos priv.insn_table_entries = NULL;
31206324dcfSchristos }
31306324dcfSchristos priv.last_section = section;
31406324dcfSchristos
31506324dcfSchristos /* Read insn_table_entries. */
31606324dcfSchristos priv.insn_table_entry_count =
31706324dcfSchristos xtensa_read_table_entries (abfd, section,
31806324dcfSchristos &priv.insn_table_entries,
31906324dcfSchristos XTENSA_PROP_SEC_NAME, FALSE);
32006324dcfSchristos if (priv.insn_table_entry_count == 0)
32106324dcfSchristos {
32206324dcfSchristos if (priv.insn_table_entries)
32306324dcfSchristos free (priv.insn_table_entries);
32406324dcfSchristos priv.insn_table_entries = NULL;
32506324dcfSchristos /* Backwards compatibility support. */
32606324dcfSchristos priv.insn_table_entry_count =
32706324dcfSchristos xtensa_read_table_entries (abfd, section,
32806324dcfSchristos &priv.insn_table_entries,
32906324dcfSchristos XTENSA_INSN_SEC_NAME, FALSE);
33006324dcfSchristos }
33106324dcfSchristos priv.insn_table_cur_idx = 0;
33206324dcfSchristos xtensa_coalesce_insn_tables (&priv);
33306324dcfSchristos }
33406324dcfSchristos /* Else nothing to do, same section as last time. */
33506324dcfSchristos }
33606324dcfSchristos
337ed0d50c3Schristos if (OPCODES_SIGSETJMP (priv.bailout) != 0)
338ed0d50c3Schristos /* Error return. */
339ed0d50c3Schristos return -1;
340ed0d50c3Schristos
34106324dcfSchristos /* Fetch the maximum size instruction. */
34206324dcfSchristos bytes_fetched = fetch_data (info, memaddr);
34306324dcfSchristos
34406324dcfSchristos insn_block = xtensa_find_table_entry (memaddr, info);
34506324dcfSchristos
346ed0d50c3Schristos /* Don't set "isa" before the setjmp to keep the compiler from griping. */
347ed0d50c3Schristos isa = xtensa_default_isa;
348ed0d50c3Schristos size = 0;
349ed0d50c3Schristos nslots = 0;
35006324dcfSchristos valid_insn = 0;
35106324dcfSchristos fmt = 0;
35206324dcfSchristos if (!insn_block || (insn_block->flags & XTENSA_PROP_INSN))
35306324dcfSchristos {
354ed0d50c3Schristos /* Copy the bytes into the decode buffer. */
355ed0d50c3Schristos memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) *
356ed0d50c3Schristos sizeof (xtensa_insnbuf_word)));
35706324dcfSchristos xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf,
35806324dcfSchristos bytes_fetched);
359ed0d50c3Schristos
360ed0d50c3Schristos fmt = xtensa_format_decode (isa, insn_buffer);
36106324dcfSchristos if (fmt != XTENSA_UNDEFINED
36206324dcfSchristos && ((size = xtensa_format_length (isa, fmt)) <= bytes_fetched)
36306324dcfSchristos && xtensa_instruction_fits (memaddr, size, insn_block))
364ed0d50c3Schristos {
365ed0d50c3Schristos /* Make sure all the opcodes are valid. */
366ed0d50c3Schristos valid_insn = 1;
367ed0d50c3Schristos nslots = xtensa_format_num_slots (isa, fmt);
368ed0d50c3Schristos for (n = 0; n < nslots; n++)
369ed0d50c3Schristos {
370ed0d50c3Schristos xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
371ed0d50c3Schristos if (xtensa_opcode_decode (isa, fmt, n, slot_buffer)
372ed0d50c3Schristos == XTENSA_UNDEFINED)
373ed0d50c3Schristos {
374ed0d50c3Schristos valid_insn = 0;
375ed0d50c3Schristos break;
376ed0d50c3Schristos }
377ed0d50c3Schristos }
378ed0d50c3Schristos }
37906324dcfSchristos }
380ed0d50c3Schristos
381ed0d50c3Schristos if (!valid_insn)
382ed0d50c3Schristos {
38306324dcfSchristos if (insn_block && (insn_block->flags & XTENSA_PROP_LITERAL)
38406324dcfSchristos && (memaddr & 3) == 0 && bytes_fetched >= 4)
38506324dcfSchristos {
38606324dcfSchristos return 4;
38706324dcfSchristos }
38806324dcfSchristos else
38906324dcfSchristos {
390ed0d50c3Schristos (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]);
391ed0d50c3Schristos return 1;
392ed0d50c3Schristos }
39306324dcfSchristos }
394ed0d50c3Schristos
395ed0d50c3Schristos if (nslots > 1)
396ed0d50c3Schristos (*info->fprintf_func) (info->stream, "{ ");
397ed0d50c3Schristos
398ed0d50c3Schristos first_slot = 1;
399ed0d50c3Schristos for (n = 0; n < nslots; n++)
400ed0d50c3Schristos {
401ed0d50c3Schristos if (first_slot)
402ed0d50c3Schristos first_slot = 0;
403ed0d50c3Schristos else
404ed0d50c3Schristos (*info->fprintf_func) (info->stream, "; ");
405ed0d50c3Schristos
406ed0d50c3Schristos xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
407ed0d50c3Schristos opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer);
408ed0d50c3Schristos (*info->fprintf_func) (info->stream, "%s",
409ed0d50c3Schristos xtensa_opcode_name (isa, opc));
410ed0d50c3Schristos
411ed0d50c3Schristos /* Print the operands (if any). */
412ed0d50c3Schristos noperands = xtensa_opcode_num_operands (isa, opc);
413ed0d50c3Schristos first = 1;
414ed0d50c3Schristos for (i = 0; i < noperands; i++)
415ed0d50c3Schristos {
416ed0d50c3Schristos if (xtensa_operand_is_visible (isa, opc, i) == 0)
417ed0d50c3Schristos continue;
418ed0d50c3Schristos if (first)
419ed0d50c3Schristos {
420ed0d50c3Schristos (*info->fprintf_func) (info->stream, "\t");
421ed0d50c3Schristos first = 0;
422ed0d50c3Schristos }
423ed0d50c3Schristos else
424ed0d50c3Schristos (*info->fprintf_func) (info->stream, ", ");
425ed0d50c3Schristos (void) xtensa_operand_get_field (isa, opc, i, fmt, n,
426ed0d50c3Schristos slot_buffer, &operand_val);
427ed0d50c3Schristos
428ed0d50c3Schristos print_xtensa_operand (memaddr, info, opc, i, operand_val);
429ed0d50c3Schristos }
430ed0d50c3Schristos }
431ed0d50c3Schristos
432ed0d50c3Schristos if (nslots > 1)
433ed0d50c3Schristos (*info->fprintf_func) (info->stream, " }");
434ed0d50c3Schristos
435ed0d50c3Schristos info->bytes_per_chunk = size;
436ed0d50c3Schristos info->display_endian = info->endian;
437ed0d50c3Schristos
438ed0d50c3Schristos return size;
439ed0d50c3Schristos }
440ed0d50c3Schristos
441