1ed0d50c3Schristos /* pj-dis.c -- Disassemble picoJava instructions.
2*b88e3e88Schristos    Copyright (C) 1999-2020 Free Software Foundation, Inc.
3ed0d50c3Schristos    Contributed by Steve Chamberlain, of Transmeta (sac@pobox.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 program; if not, write to the Free Software
19ed0d50c3Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20ed0d50c3Schristos    MA 02110-1301, USA.  */
21ed0d50c3Schristos 
22ed0d50c3Schristos #include "sysdep.h"
23ed0d50c3Schristos #include <stdio.h>
24ed0d50c3Schristos #include "opcode/pj.h"
2506324dcfSchristos #include "disassemble.h"
26ed0d50c3Schristos 
27ed0d50c3Schristos extern const pj_opc_info_t pj_opc_info[512];
28ed0d50c3Schristos 
29ed0d50c3Schristos static int
get_int(bfd_vma memaddr,int * iptr,struct disassemble_info * info)30ed0d50c3Schristos get_int (bfd_vma memaddr, int *iptr, struct disassemble_info *info)
31ed0d50c3Schristos {
32ed0d50c3Schristos   unsigned char ival[4];
33ed0d50c3Schristos   int status = info->read_memory_func (memaddr, ival, 4, info);
34ed0d50c3Schristos 
35*b88e3e88Schristos   *iptr = (((unsigned) ival[0] << 24)
36ed0d50c3Schristos 	   | (ival[1] << 16)
37ed0d50c3Schristos 	   | (ival[2] << 8)
38*b88e3e88Schristos 	   | (ival[3] << 0));
39ed0d50c3Schristos 
40ed0d50c3Schristos   return status;
41ed0d50c3Schristos }
42ed0d50c3Schristos 
43ed0d50c3Schristos int
print_insn_pj(bfd_vma addr,struct disassemble_info * info)44ed0d50c3Schristos print_insn_pj (bfd_vma addr, struct disassemble_info *info)
45ed0d50c3Schristos {
46ed0d50c3Schristos   fprintf_ftype fprintf_fn = info->fprintf_func;
47ed0d50c3Schristos   void *stream = info->stream;
48ed0d50c3Schristos   unsigned char opcode;
49ed0d50c3Schristos   int status;
50ed0d50c3Schristos 
51ed0d50c3Schristos   if ((status = info->read_memory_func (addr, &opcode, 1, info)))
52ed0d50c3Schristos     goto fail;
53ed0d50c3Schristos 
54ed0d50c3Schristos   if (opcode == 0xff)
55ed0d50c3Schristos     {
56ed0d50c3Schristos       unsigned char byte_2;
57ed0d50c3Schristos 
58ed0d50c3Schristos       if ((status = info->read_memory_func (addr + 1, &byte_2, 1, info)))
59ed0d50c3Schristos 	goto fail;
60ed0d50c3Schristos       fprintf_fn (stream, "%s\t", pj_opc_info[opcode + byte_2].u.name);
61ed0d50c3Schristos       return 2;
62ed0d50c3Schristos     }
63ed0d50c3Schristos   else
64ed0d50c3Schristos     {
65ed0d50c3Schristos       char *sep = "\t";
66ed0d50c3Schristos       int insn_start = addr;
67ed0d50c3Schristos       const pj_opc_info_t *op = &pj_opc_info[opcode];
68ed0d50c3Schristos       int a;
69ed0d50c3Schristos 
70ed0d50c3Schristos       addr++;
71ed0d50c3Schristos       fprintf_fn (stream, "%s", op->u.name);
72ed0d50c3Schristos 
73ed0d50c3Schristos       /* The tableswitch instruction is followed by the default
74ed0d50c3Schristos 	 address, low value, high value and the destinations.  */
75ed0d50c3Schristos 
76ed0d50c3Schristos       if (strcmp (op->u.name, "tableswitch") == 0)
77ed0d50c3Schristos 	{
78ed0d50c3Schristos 	  int lowval;
79ed0d50c3Schristos 	  int highval;
80ed0d50c3Schristos 	  int val;
81ed0d50c3Schristos 
82ed0d50c3Schristos 	  addr = (addr + 3) & ~3;
83ed0d50c3Schristos 	  if ((status = get_int (addr, &val, info)))
84ed0d50c3Schristos 	    goto fail;
85ed0d50c3Schristos 
86ed0d50c3Schristos 	  fprintf_fn (stream, " default: ");
87ed0d50c3Schristos 	  (*info->print_address_func) (val + insn_start, info);
88ed0d50c3Schristos 	  addr += 4;
89ed0d50c3Schristos 
90ed0d50c3Schristos 	  if ((status = get_int (addr, &lowval, info)))
91ed0d50c3Schristos 	    goto fail;
92ed0d50c3Schristos 	  addr += 4;
93ed0d50c3Schristos 
94ed0d50c3Schristos 	  if ((status = get_int (addr, &highval, info)))
95ed0d50c3Schristos 	    goto fail;
96ed0d50c3Schristos 	  addr += 4;
97ed0d50c3Schristos 
98ed0d50c3Schristos 	  while (lowval <= highval)
99ed0d50c3Schristos 	    {
100ed0d50c3Schristos 	      if ((status = get_int (addr, &val, info)))
101ed0d50c3Schristos 		goto fail;
102ed0d50c3Schristos 	      fprintf_fn (stream, " %d:[", lowval);
103ed0d50c3Schristos 	      (*info->print_address_func) (val + insn_start, info);
104ed0d50c3Schristos 	      fprintf_fn (stream, " ]");
105ed0d50c3Schristos 	      addr += 4;
106ed0d50c3Schristos 	      lowval++;
107ed0d50c3Schristos 	    }
108ed0d50c3Schristos 	  return addr - insn_start;
109ed0d50c3Schristos 	}
110ed0d50c3Schristos 
111ed0d50c3Schristos       /* The lookupswitch instruction is followed by the default
112ed0d50c3Schristos 	 address, element count and pairs of values and
113ed0d50c3Schristos 	 addresses.  */
114ed0d50c3Schristos       if (strcmp (op->u.name, "lookupswitch") == 0)
115ed0d50c3Schristos 	{
116ed0d50c3Schristos 	  int count;
117ed0d50c3Schristos 	  int val;
118ed0d50c3Schristos 
119ed0d50c3Schristos 	  addr = (addr + 3) & ~3;
120ed0d50c3Schristos 	  if ((status = get_int (addr, &val, info)))
121ed0d50c3Schristos 	    goto fail;
122ed0d50c3Schristos 	  addr += 4;
123ed0d50c3Schristos 
124ed0d50c3Schristos 	  fprintf_fn (stream, " default: ");
125ed0d50c3Schristos 	  (*info->print_address_func) (val + insn_start, info);
126ed0d50c3Schristos 
127ed0d50c3Schristos 	  if ((status = get_int (addr, &count, info)))
128ed0d50c3Schristos 	    goto fail;
129ed0d50c3Schristos 	  addr += 4;
130ed0d50c3Schristos 
131ed0d50c3Schristos 	  while (count--)
132ed0d50c3Schristos 	    {
133ed0d50c3Schristos 	      if ((status = get_int (addr, &val, info)))
134ed0d50c3Schristos 		goto fail;
135ed0d50c3Schristos 	      addr += 4;
136ed0d50c3Schristos 	      fprintf_fn (stream, " %d:[", val);
137ed0d50c3Schristos 
138ed0d50c3Schristos 	      if ((status = get_int (addr, &val, info)))
139ed0d50c3Schristos 		goto fail;
140ed0d50c3Schristos 	      addr += 4;
141ed0d50c3Schristos 
142ed0d50c3Schristos 	      (*info->print_address_func) (val + insn_start, info);
143ed0d50c3Schristos 	      fprintf_fn (stream, " ]");
144ed0d50c3Schristos 	    }
145ed0d50c3Schristos 	  return addr - insn_start;
146ed0d50c3Schristos 	}
147ed0d50c3Schristos 
148ed0d50c3Schristos       for (a = 0; op->arg[a]; a++)
149ed0d50c3Schristos 	{
150ed0d50c3Schristos 	  unsigned char data[4];
151ed0d50c3Schristos 	  int val = 0;
152ed0d50c3Schristos 	  int i;
153ed0d50c3Schristos 	  int size = ASIZE (op->arg[a]);
154ed0d50c3Schristos 
155ed0d50c3Schristos 	  if ((status = info->read_memory_func (addr, data, size, info)))
156ed0d50c3Schristos 	    goto fail;
157ed0d50c3Schristos 
158ed0d50c3Schristos 	  val = (UNS (op->arg[0]) || ((data[0] & 0x80) == 0)) ? 0 : -1;
159ed0d50c3Schristos 
160ed0d50c3Schristos 	  for (i = 0; i < size; i++)
161ed0d50c3Schristos 	    val = (val << 8) | (data[i] & 0xff);
162ed0d50c3Schristos 
163ed0d50c3Schristos 	  if (PCREL (op->arg[a]))
164ed0d50c3Schristos 	    (*info->print_address_func) (val + insn_start, info);
165ed0d50c3Schristos 	  else
166ed0d50c3Schristos 	    fprintf_fn (stream, "%s%d", sep, val);
167ed0d50c3Schristos 
168ed0d50c3Schristos 	  sep = ",";
169ed0d50c3Schristos 	  addr += size;
170ed0d50c3Schristos 	}
171ed0d50c3Schristos       return op->len;
172ed0d50c3Schristos     }
173ed0d50c3Schristos 
174ed0d50c3Schristos  fail:
175ed0d50c3Schristos   info->memory_error_func (status, addr, info);
176ed0d50c3Schristos   return -1;
177ed0d50c3Schristos }
178