]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/v850-dis.c
Fix potential array overruns when disassembling corrupt v850 binaries.
[thirdparty/binutils-gdb.git] / opcodes / v850-dis.c
1 /* Disassemble V850 instructions.
2 Copyright (C) 1996-2019 Free Software Foundation, Inc.
3
4 This file is part of the GNU opcodes library.
5
6 This library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 It is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21
22 #include "sysdep.h"
23 #include <stdio.h>
24 #include <string.h>
25 #include "opcode/v850.h"
26 #include "disassemble.h"
27 #include "opintl.h"
28 #include "libiberty.h"
29
30 static const int v850_cacheop_codes[] =
31 {
32 0x00, 0x20, 0x40, 0x60, 0x61, 0x04, 0x06,
33 0x07, 0x24, 0x26, 0x27, 0x44, 0x64, 0x65, -1
34 };
35
36 static const int v850_prefop_codes[] =
37 { 0x00, 0x04, -1};
38
39 static void
40 print_value (int flags,
41 bfd_vma memaddr,
42 struct disassemble_info *info,
43 long value)
44 {
45 if (flags & V850_PCREL)
46 {
47 bfd_vma addr = value + memaddr;
48
49 if (flags & V850_INVERSE_PCREL)
50 addr = memaddr - value;
51 info->print_address_func (addr, info);
52 }
53 else if (flags & V850_OPERAND_DISP)
54 {
55 if (flags & V850_OPERAND_SIGNED)
56 {
57 info->fprintf_func (info->stream, "%ld", value);
58 }
59 else
60 {
61 info->fprintf_func (info->stream, "%lu", value);
62 }
63 }
64 else if ((flags & V850E_IMMEDIATE32)
65 || (flags & V850E_IMMEDIATE16HI))
66 {
67 info->fprintf_func (info->stream, "0x%lx", value);
68 }
69 else
70 {
71 if (flags & V850_OPERAND_SIGNED)
72 {
73 info->fprintf_func (info->stream, "%ld", value);
74 }
75 else
76 {
77 info->fprintf_func (info->stream, "%lu", value);
78 }
79 }
80 }
81
82 static long
83 get_operand_value (const struct v850_operand *operand,
84 unsigned long insn,
85 int bytes_read,
86 bfd_vma memaddr,
87 struct disassemble_info * info,
88 bfd_boolean noerror,
89 int *invalid)
90 {
91 long value;
92 bfd_byte buffer[4];
93
94 if ((operand->flags & V850E_IMMEDIATE16)
95 || (operand->flags & V850E_IMMEDIATE16HI))
96 {
97 int status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
98
99 if (status == 0)
100 {
101 value = bfd_getl16 (buffer);
102
103 if (operand->flags & V850E_IMMEDIATE16HI)
104 value <<= 16;
105 else if (value & 0x8000)
106 value |= (-1UL << 16);
107
108 return value;
109 }
110
111 if (!noerror)
112 info->memory_error_func (status, memaddr + bytes_read, info);
113
114 return 0;
115 }
116
117 if (operand->flags & V850E_IMMEDIATE23)
118 {
119 int status = info->read_memory_func (memaddr + 2, buffer, 4, info);
120
121 if (status == 0)
122 {
123 value = bfd_getl32 (buffer);
124
125 value = (operand->extract) (value, invalid);
126
127 return value;
128 }
129
130 if (!noerror)
131 info->memory_error_func (status, memaddr + bytes_read, info);
132
133 return 0;
134 }
135
136 if (operand->flags & V850E_IMMEDIATE32)
137 {
138 int status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
139
140 if (status == 0)
141 {
142 bytes_read += 4;
143 value = bfd_getl32 (buffer);
144
145 return value;
146 }
147
148 if (!noerror)
149 info->memory_error_func (status, memaddr + bytes_read, info);
150
151 return 0;
152 }
153
154 if (operand->extract)
155 value = (operand->extract) (insn, invalid);
156 else
157 {
158 if (operand->bits == -1)
159 value = (insn & operand->shift);
160 else
161 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
162
163 if (operand->flags & V850_OPERAND_SIGNED)
164 value = ((long)(value << (sizeof (long)*8 - operand->bits))
165 >> (sizeof (long)*8 - operand->bits));
166 }
167
168 return value;
169 }
170
171 static const char *
172 get_v850_sreg_name (unsigned int reg)
173 {
174 static const char *const v850_sreg_names[] =
175 {
176 "eipc/vip/mpm", "eipsw/mpc", "fepc/tid", "fepsw/ppa", "ecr/vmecr", "psw/vmtid",
177 "sr6/fpsr/vmadr/dcc", "sr7/fpepc/dc0",
178 "sr8/fpst/vpecr/dcv1", "sr9/fpcc/vptid", "sr10/fpcfg/vpadr/spal", "sr11/spau",
179 "sr12/vdecr/ipa0l", "eiic/vdtid/ipa0u", "feic/ipa1l", "dbic/ipa1u",
180 "ctpc/ipa2l", "ctpsw/ipa2u", "dbpc/ipa3l", "dbpsw/ipa3u", "ctbp/dpa0l",
181 "dir/dpa0u", "bpc/dpa0u", "asid/dpa1l",
182 "bpav/dpa1u", "bpam/dpa2l", "bpdv/dpa2u", "bpdm/dpa3l", "eiwr/dpa3u",
183 "fewr", "dbwr", "bsel"
184 };
185
186 if (reg < ARRAY_SIZE (v850_sreg_names))
187 return v850_sreg_names[reg];
188 return _("<invalid s-reg number>");
189 }
190
191 static const char *
192 get_v850_reg_name (unsigned int reg)
193 {
194 static const char *const v850_reg_names[] =
195 {
196 "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
197 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
198 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
199 "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp"
200 };
201
202 if (reg < ARRAY_SIZE (v850_reg_names))
203 return v850_reg_names[reg];
204 return _("<invalid reg number>");
205 }
206
207 static const char *
208 get_v850_vreg_name (unsigned int reg)
209 {
210 static const char *const v850_vreg_names[] =
211 {
212 "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", "vr8", "vr9",
213 "vr10", "vr11", "vr12", "vr13", "vr14", "vr15", "vr16", "vr17", "vr18",
214 "vr19", "vr20", "vr21", "vr22", "vr23", "vr24", "vr25", "vr26", "vr27",
215 "vr28", "vr29", "vr30", "vr31"
216 };
217
218 if (reg < ARRAY_SIZE (v850_vreg_names))
219 return v850_vreg_names[reg];
220 return _("<invalid v-reg number>");
221 }
222
223 static const char *
224 get_v850_cc_name (unsigned int reg)
225 {
226 static const char *const v850_cc_names[] =
227 {
228 "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
229 "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt"
230 };
231
232 if (reg < ARRAY_SIZE (v850_cc_names))
233 return v850_cc_names[reg];
234 return _("<invalid CC-reg number>");
235 }
236
237 static const char *
238 get_v850_float_cc_name (unsigned int reg)
239 {
240 static const char *const v850_float_cc_names[] =
241 {
242 "f/t", "un/or", "eq/neq", "ueq/ogl", "olt/uge", "ult/oge", "ole/ugt", "ule/ogt",
243 "sf/st", "ngle/gle", "seq/sne", "ngl/gl", "lt/nlt", "nge/ge", "le/nle", "ngt/gt"
244 };
245
246 if (reg < ARRAY_SIZE (v850_float_cc_names))
247 return v850_float_cc_names[reg];
248 return _("<invalid float-CC-reg number>");
249 }
250
251 static const char *
252 get_v850_cacheop_name (unsigned int reg)
253 {
254 static const char *const v850_cacheop_names[] =
255 {
256 "chbii", "cibii", "cfali", "cisti", "cildi", "chbid", "chbiwbd",
257 "chbwbd", "cibid", "cibiwbd", "cibwbd", "cfald", "cistd", "cildd"
258 };
259
260 if (reg < ARRAY_SIZE (v850_cacheop_names))
261 return v850_cacheop_names[reg];
262 return _("<invalid cacheop number>");
263 }
264
265 static const char *
266 get_v850_prefop_name (unsigned int reg)
267 {
268 static const char *const v850_prefop_names[] =
269 { "prefi", "prefd" };
270
271 if (reg < ARRAY_SIZE (v850_prefop_names))
272 return v850_prefop_names[reg];
273 return _("<invalid prefop number>");
274 }
275
276 static int
277 disassemble (bfd_vma memaddr,
278 struct disassemble_info *info,
279 int bytes_read,
280 unsigned long insn)
281 {
282 struct v850_opcode *op = (struct v850_opcode *) v850_opcodes;
283 const struct v850_operand *operand;
284 int match = 0;
285 int target_processor;
286
287 switch (info->mach)
288 {
289 case 0:
290 default:
291 target_processor = PROCESSOR_V850;
292 break;
293
294 case bfd_mach_v850e:
295 target_processor = PROCESSOR_V850E;
296 break;
297
298 case bfd_mach_v850e1:
299 target_processor = PROCESSOR_V850E;
300 break;
301
302 case bfd_mach_v850e2:
303 target_processor = PROCESSOR_V850E2;
304 break;
305
306 case bfd_mach_v850e2v3:
307 target_processor = PROCESSOR_V850E2V3;
308 break;
309
310 case bfd_mach_v850e3v5:
311 target_processor = PROCESSOR_V850E3V5;
312 break;
313 }
314
315 /* If this is a two byte insn, then mask off the high bits. */
316 if (bytes_read == 2)
317 insn &= 0xffff;
318
319 /* Find the opcode. */
320 while (op->name)
321 {
322 if ((op->mask & insn) == op->opcode
323 && (op->processors & target_processor)
324 && !(op->processors & PROCESSOR_OPTION_ALIAS))
325 {
326 /* Code check start. */
327 const unsigned char *opindex_ptr;
328 unsigned int opnum;
329 unsigned int memop;
330
331 for (opindex_ptr = op->operands, opnum = 1;
332 *opindex_ptr != 0;
333 opindex_ptr++, opnum++)
334 {
335 int invalid = 0;
336 long value;
337
338 operand = &v850_operands[*opindex_ptr];
339
340 value = get_operand_value (operand, insn, bytes_read, memaddr,
341 info, 1, &invalid);
342
343 if (invalid)
344 goto next_opcode;
345
346 if ((operand->flags & V850_NOT_R0) && value == 0 && (op->memop) <=2)
347 goto next_opcode;
348
349 if ((operand->flags & V850_NOT_SA) && value == 0xd)
350 goto next_opcode;
351
352 if ((operand->flags & V850_NOT_IMM0) && value == 0)
353 goto next_opcode;
354 }
355
356 /* Code check end. */
357
358 match = 1;
359 (*info->fprintf_func) (info->stream, "%s\t", op->name);
360 #if 0
361 fprintf (stderr, "match: insn: %lx, mask: %lx, opcode: %lx, name: %s\n",
362 insn, op->mask, op->opcode, op->name );
363 #endif
364
365 memop = op->memop;
366 /* Now print the operands.
367
368 MEMOP is the operand number at which a memory
369 address specification starts, or zero if this
370 instruction has no memory addresses.
371
372 A memory address is always two arguments.
373
374 This information allows us to determine when to
375 insert commas into the output stream as well as
376 when to insert disp[reg] expressions onto the
377 output stream. */
378
379 for (opindex_ptr = op->operands, opnum = 1;
380 *opindex_ptr != 0;
381 opindex_ptr++, opnum++)
382 {
383 bfd_boolean square = FALSE;
384 long value;
385 int flag;
386 char *prefix;
387
388 operand = &v850_operands[*opindex_ptr];
389
390 value = get_operand_value (operand, insn, bytes_read, memaddr,
391 info, 0, 0);
392
393 /* The first operand is always output without any
394 special handling.
395
396 For the following arguments:
397
398 If memop && opnum == memop + 1, then we need '[' since
399 we're about to output the register used in a memory
400 reference.
401
402 If memop && opnum == memop + 2, then we need ']' since
403 we just finished the register in a memory reference. We
404 also need a ',' before this operand.
405
406 Else we just need a comma.
407
408 We may need to output a trailing ']' if the last operand
409 in an instruction is the register for a memory address.
410
411 The exception (and there's always an exception) are the
412 "jmp" insn which needs square brackets around it's only
413 register argument, and the clr1/not1/set1/tst1 insns
414 which [...] around their second register argument. */
415
416 prefix = "";
417 if (operand->flags & V850_OPERAND_BANG)
418 {
419 prefix = "!";
420 }
421 else if (operand->flags & V850_OPERAND_PERCENT)
422 {
423 prefix = "%";
424 }
425
426 if (opnum == 1 && opnum == memop)
427 {
428 info->fprintf_func (info->stream, "%s[", prefix);
429 square = TRUE;
430 }
431 else if ( (strcmp ("stc.w", op->name) == 0
432 || strcmp ("cache", op->name) == 0
433 || strcmp ("pref", op->name) == 0)
434 && opnum == 2 && opnum == memop)
435 {
436 info->fprintf_func (info->stream, ", [");
437 square = TRUE;
438 }
439 else if ( (strcmp (op->name, "pushsp") == 0
440 || strcmp (op->name, "popsp") == 0
441 || strcmp (op->name, "dbpush" ) == 0)
442 && opnum == 2)
443 {
444 info->fprintf_func (info->stream, "-");
445 }
446 else if (opnum > 1
447 && (v850_operands[*(opindex_ptr - 1)].flags
448 & V850_OPERAND_DISP) != 0
449 && opnum == memop)
450 {
451 info->fprintf_func (info->stream, "%s[", prefix);
452 square = TRUE;
453 }
454 else if (opnum == 2
455 && ( op->opcode == 0x00e407e0 /* clr1 */
456 || op->opcode == 0x00e207e0 /* not1 */
457 || op->opcode == 0x00e007e0 /* set1 */
458 || op->opcode == 0x00e607e0 /* tst1 */
459 ))
460 {
461 info->fprintf_func (info->stream, ", %s[", prefix);
462 square = TRUE;
463 }
464 else if (opnum > 1)
465 info->fprintf_func (info->stream, ", %s", prefix);
466
467 /* Extract the flags, ignoring ones which do not
468 effect disassembly output. */
469 flag = operand->flags & (V850_OPERAND_REG
470 | V850_REG_EVEN
471 | V850_OPERAND_EP
472 | V850_OPERAND_SRG
473 | V850E_OPERAND_REG_LIST
474 | V850_OPERAND_CC
475 | V850_OPERAND_VREG
476 | V850_OPERAND_CACHEOP
477 | V850_OPERAND_PREFOP
478 | V850_OPERAND_FLOAT_CC);
479
480 switch (flag)
481 {
482 case V850_OPERAND_REG:
483 info->fprintf_func (info->stream, "%s", get_v850_reg_name (value));
484 break;
485 case (V850_OPERAND_REG|V850_REG_EVEN):
486 info->fprintf_func (info->stream, "%s", get_v850_reg_name (value * 2));
487 break;
488 case V850_OPERAND_EP:
489 info->fprintf_func (info->stream, "ep");
490 break;
491 case V850_OPERAND_SRG:
492 info->fprintf_func (info->stream, "%s", get_v850_sreg_name (value));
493 break;
494 case V850E_OPERAND_REG_LIST:
495 {
496 static int list12_regs[32] = { 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
497 0, 0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
498 int *regs;
499 int i;
500 unsigned long int mask = 0;
501 int pc = 0;
502
503 switch (operand->shift)
504 {
505 case 0xffe00001: regs = list12_regs; break;
506 default:
507 /* xgettext:c-format */
508 opcodes_error_handler (_("unknown operand shift: %x"),
509 operand->shift);
510 abort ();
511 }
512
513 for (i = 0; i < 32; i++)
514 {
515 if (value & (1 << i))
516 {
517 switch (regs[ i ])
518 {
519 default:
520 mask |= (1 << regs[ i ]);
521 break;
522 case 0:
523 /* xgettext:c-format */
524 opcodes_error_handler (_("unknown reg: %d"), i);
525 abort ();
526 break;
527 case -1:
528 pc = 1;
529 break;
530 }
531 }
532 }
533
534 info->fprintf_func (info->stream, "{");
535
536 if (mask || pc)
537 {
538 if (mask)
539 {
540 unsigned int bit;
541 int shown_one = 0;
542
543 for (bit = 0; bit < 32; bit++)
544 if (mask & (1 << bit))
545 {
546 unsigned long int first = bit;
547 unsigned long int last;
548
549 if (shown_one)
550 info->fprintf_func (info->stream, ", ");
551 else
552 shown_one = 1;
553
554 info->fprintf_func (info->stream, "%s", get_v850_reg_name (first));
555
556 for (bit++; bit < 32; bit++)
557 if ((mask & (1 << bit)) == 0)
558 break;
559
560 last = bit;
561
562 if (last > first + 1)
563 {
564 info->fprintf_func (info->stream, " - %s", get_v850_reg_name (last - 1));
565 }
566 }
567 }
568
569 if (pc)
570 info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
571 }
572
573 info->fprintf_func (info->stream, "}");
574 }
575 break;
576
577 case V850_OPERAND_CC:
578 info->fprintf_func (info->stream, "%s", get_v850_cc_name (value));
579 break;
580
581 case V850_OPERAND_FLOAT_CC:
582 info->fprintf_func (info->stream, "%s", get_v850_float_cc_name (value));
583 break;
584
585 case V850_OPERAND_CACHEOP:
586 {
587 int idx;
588
589 for (idx = 0; v850_cacheop_codes[idx] != -1; idx++)
590 {
591 if (value == v850_cacheop_codes[idx])
592 {
593 info->fprintf_func (info->stream, "%s",
594 get_v850_cacheop_name (idx));
595 goto MATCH_CACHEOP_CODE;
596 }
597 }
598 info->fprintf_func (info->stream, "%d", (int) value);
599 }
600 MATCH_CACHEOP_CODE:
601 break;
602
603 case V850_OPERAND_PREFOP:
604 {
605 int idx;
606
607 for (idx = 0; v850_prefop_codes[idx] != -1; idx++)
608 {
609 if (value == v850_prefop_codes[idx])
610 {
611 info->fprintf_func (info->stream, "%s",
612 get_v850_prefop_name (idx));
613 goto MATCH_PREFOP_CODE;
614 }
615 }
616 info->fprintf_func (info->stream, "%d", (int) value);
617 }
618 MATCH_PREFOP_CODE:
619 break;
620
621 case V850_OPERAND_VREG:
622 info->fprintf_func (info->stream, "%s", get_v850_vreg_name (value));
623 break;
624
625 default:
626 print_value (operand->flags, memaddr, info, value);
627 break;
628 }
629
630 if (square)
631 (*info->fprintf_func) (info->stream, "]");
632 }
633
634 /* All done. */
635 break;
636 }
637 next_opcode:
638 op++;
639 }
640
641 return match;
642 }
643
644 int
645 print_insn_v850 (bfd_vma memaddr, struct disassemble_info * info)
646 {
647 int status, status2, match;
648 bfd_byte buffer[8];
649 int length = 0, code_length = 0;
650 unsigned long insn = 0, insn2 = 0;
651 int target_processor;
652
653 switch (info->mach)
654 {
655 case 0:
656 default:
657 target_processor = PROCESSOR_V850;
658 break;
659
660 case bfd_mach_v850e:
661 target_processor = PROCESSOR_V850E;
662 break;
663
664 case bfd_mach_v850e1:
665 target_processor = PROCESSOR_V850E;
666 break;
667
668 case bfd_mach_v850e2:
669 target_processor = PROCESSOR_V850E2;
670 break;
671
672 case bfd_mach_v850e2v3:
673 target_processor = PROCESSOR_V850E2V3;
674 break;
675
676 case bfd_mach_v850e3v5:
677 target_processor = PROCESSOR_V850E3V5;
678 break;
679 }
680
681 status = info->read_memory_func (memaddr, buffer, 2, info);
682
683 if (status)
684 {
685 info->memory_error_func (status, memaddr, info);
686 return -1;
687 }
688
689 insn = bfd_getl16 (buffer);
690
691 status2 = info->read_memory_func (memaddr+2, buffer, 2 , info);
692
693 if (!status2)
694 {
695 insn2 = bfd_getl16 (buffer);
696 /* fprintf (stderr, "insn2 0x%08lx\n", insn2); */
697 }
698
699 /* Special case. */
700 if (length == 0
701 && ((target_processor & PROCESSOR_V850E2_UP) != 0))
702 {
703 if ((insn & 0xffff) == 0x02e0 /* jr 32bit */
704 && !status2 && (insn2 & 0x1) == 0)
705 {
706 length = 2;
707 code_length = 6;
708 }
709 else if ((insn & 0xffe0) == 0x02e0 /* jarl 32bit */
710 && !status2 && (insn2 & 0x1) == 0)
711 {
712 length = 2;
713 code_length = 6;
714 }
715 else if ((insn & 0xffe0) == 0x06e0 /* jmp 32bit */
716 && !status2 && (insn2 & 0x1) == 0)
717 {
718 length = 2;
719 code_length = 6;
720 }
721 }
722
723 if (length == 0
724 && ((target_processor & PROCESSOR_V850E3V5_UP) != 0))
725 {
726 if ( ((insn & 0xffe0) == 0x07a0 /* ld.dw 23bit (v850e3v5) */
727 && !status2 && (insn2 & 0x000f) == 0x0009)
728 || ((insn & 0xffe0) == 0x07a0 /* st.dw 23bit (v850e3v5) */
729 && !status2 && (insn2 & 0x000f) == 0x000f))
730 {
731 length = 4;
732 code_length = 6;
733 }
734 }
735
736 if (length == 0
737 && ((target_processor & PROCESSOR_V850E2V3_UP) != 0))
738 {
739 if (((insn & 0xffe0) == 0x0780 /* ld.b 23bit */
740 && !status2 && (insn2 & 0x000f) == 0x0005)
741 || ((insn & 0xffe0) == 0x07a0 /* ld.bu 23bit */
742 && !status2 && (insn2 & 0x000f) == 0x0005)
743 || ((insn & 0xffe0) == 0x0780 /* ld.h 23bit */
744 && !status2 && (insn2 & 0x000f) == 0x0007)
745 || ((insn & 0xffe0) == 0x07a0 /* ld.hu 23bit */
746 && !status2 && (insn2 & 0x000f) == 0x0007)
747 || ((insn & 0xffe0) == 0x0780 /* ld.w 23bit */
748 && !status2 && (insn2 & 0x000f) == 0x0009))
749 {
750 length = 4;
751 code_length = 6;
752 }
753 else if (((insn & 0xffe0) == 0x0780 /* st.b 23bit */
754 && !status2 && (insn2 & 0x000f) == 0x000d)
755 || ((insn & 0xffe0) == 0x07a0 /* st.h 23bit */
756 && !status2 && (insn2 & 0x000f) == 0x000d)
757 || ((insn & 0xffe0) == 0x0780 /* st.w 23bit */
758 && !status2 && (insn2 & 0x000f) == 0x000f))
759 {
760 length = 4;
761 code_length = 6;
762 }
763 }
764
765 if (length == 0
766 && target_processor != PROCESSOR_V850)
767 {
768 if ((insn & 0xffe0) == 0x0620) /* 32 bit MOV */
769 {
770 length = 2;
771 code_length = 6;
772 }
773 else if ((insn & 0xffc0) == 0x0780 /* prepare {list}, imm5, imm16<<16 */
774 && !status2 && (insn2 & 0x001f) == 0x0013)
775 {
776 length = 4;
777 code_length = 6;
778 }
779 else if ((insn & 0xffc0) == 0x0780 /* prepare {list}, imm5, imm16 */
780 && !status2 && (insn2 & 0x001f) == 0x000b)
781 {
782 length = 4;
783 code_length = 6;
784 }
785 else if ((insn & 0xffc0) == 0x0780 /* prepare {list}, imm5, imm32 */
786 && !status2 && (insn2 & 0x001f) == 0x001b)
787 {
788 length = 4;
789 code_length = 8;
790 }
791 }
792
793 if (length == 4
794 || (length == 0
795 && (insn & 0x0600) == 0x0600))
796 {
797 /* This is a 4 byte insn. */
798 status = info->read_memory_func (memaddr, buffer, 4, info);
799 if (!status)
800 {
801 insn = bfd_getl32 (buffer);
802
803 if (!length)
804 length = code_length = 4;
805 }
806 }
807
808 if (code_length > length)
809 {
810 status = info->read_memory_func (memaddr + length, buffer, code_length - length, info);
811 if (status)
812 length = 0;
813 }
814
815 if (length == 0 && !status)
816 length = code_length = 2;
817
818 if (length == 2)
819 insn &= 0xffff;
820
821 /* when the last 2 bytes of section is 0xffff, length will be 0 and cause infinitive loop */
822 if (length == 0)
823 return -1;
824
825 match = disassemble (memaddr, info, length, insn);
826
827 if (!match)
828 {
829 int l = 0;
830
831 status = info->read_memory_func (memaddr, buffer, code_length, info);
832
833 while (l < code_length)
834 {
835 if (code_length - l == 2)
836 {
837 insn = bfd_getl16 (buffer + l) & 0xffff;
838 info->fprintf_func (info->stream, ".short\t0x%04lx", insn);
839 l += 2;
840 }
841 else
842 {
843 insn = bfd_getl32 (buffer + l);
844 info->fprintf_func (info->stream, ".long\t0x%08lx", insn);
845 l += 4;
846 }
847 }
848 }
849
850 return code_length;
851 }