s390-dis.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /* s390-dis.c -- Disassemble S390 instructions
  2. Copyright (C) 2000-2015 Free Software Foundation, Inc.
  3. Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
  4. This file is part of the GNU opcodes library.
  5. This library is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3, or (at your option)
  8. any later version.
  9. It is distributed in the hope that it will be useful, but WITHOUT
  10. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  12. License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this file; see the file COPYING. If not, write to the
  15. Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
  16. MA 02110-1301, USA. */
  17. #include "sysdep.h"
  18. #include <stdio.h>
  19. #include "ansidecl.h"
  20. #include "dis-asm.h"
  21. #include "opintl.h"
  22. #include "opcode/s390.h"
  23. static int init_flag = 0;
  24. static int opc_index[256];
  25. static int current_arch_mask = 0;
  26. /* Set up index table for first opcode byte. */
  27. static void
  28. init_disasm (struct disassemble_info *info)
  29. {
  30. int i;
  31. const char *p;
  32. memset (opc_index, 0, sizeof (opc_index));
  33. /* Reverse order, such that each opc_index ends up pointing to the
  34. first matching entry instead of the last. */
  35. for (i = s390_num_opcodes; i--; )
  36. opc_index[s390_opcodes[i].opcode[0]] = i;
  37. for (p = info->disassembler_options; p != NULL; )
  38. {
  39. if (CONST_STRNEQ (p, "esa"))
  40. current_arch_mask = 1 << S390_OPCODE_ESA;
  41. else if (CONST_STRNEQ (p, "zarch"))
  42. current_arch_mask = 1 << S390_OPCODE_ZARCH;
  43. else
  44. fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
  45. p = strchr (p, ',');
  46. if (p != NULL)
  47. p++;
  48. }
  49. if (!current_arch_mask)
  50. current_arch_mask = 1 << S390_OPCODE_ZARCH;
  51. init_flag = 1;
  52. }
  53. /* Derive the length of an instruction from its first byte. */
  54. static inline int
  55. s390_insn_length (const bfd_byte *buffer)
  56. {
  57. /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */
  58. return ((buffer[0] >> 6) + 3) & ~1U;
  59. }
  60. /* Match the instruction in BUFFER against the given OPCODE, excluding
  61. the first byte. */
  62. static inline int
  63. s390_insn_matches_opcode (const bfd_byte *buffer,
  64. const struct s390_opcode *opcode)
  65. {
  66. return (buffer[1] & opcode->mask[1]) == opcode->opcode[1]
  67. && (buffer[2] & opcode->mask[2]) == opcode->opcode[2]
  68. && (buffer[3] & opcode->mask[3]) == opcode->opcode[3]
  69. && (buffer[4] & opcode->mask[4]) == opcode->opcode[4]
  70. && (buffer[5] & opcode->mask[5]) == opcode->opcode[5];
  71. }
  72. union operand_value
  73. {
  74. int i;
  75. unsigned int u;
  76. };
  77. /* Extracts an operand value from an instruction. */
  78. /* We do not perform the shift operation for larl-type address
  79. operands here since that would lead to an overflow of the 32 bit
  80. integer value. Instead the shift operation is done when printing
  81. the operand. */
  82. static inline union operand_value
  83. s390_extract_operand (const bfd_byte *insn,
  84. const struct s390_operand *operand)
  85. {
  86. union operand_value ret;
  87. unsigned int val;
  88. int bits;
  89. const bfd_byte *orig_insn = insn;
  90. /* Extract fragments of the operand byte for byte. */
  91. insn += operand->shift / 8;
  92. bits = (operand->shift & 7) + operand->bits;
  93. val = 0;
  94. do
  95. {
  96. val <<= 8;
  97. val |= (unsigned int) *insn++;
  98. bits -= 8;
  99. }
  100. while (bits > 0);
  101. val >>= -bits;
  102. val &= ((1U << (operand->bits - 1)) << 1) - 1;
  103. /* Check for special long displacement case. */
  104. if (operand->bits == 20 && operand->shift == 20)
  105. val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
  106. /* Sign extend value if the operand is signed or pc relative. Avoid
  107. integer overflows. */
  108. if (operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
  109. {
  110. unsigned int m = 1U << (operand->bits - 1);
  111. if (val >= m)
  112. ret.i = (int) (val - m) - 1 - (int) (m - 1U);
  113. else
  114. ret.i = (int) val;
  115. }
  116. else if (operand->flags & S390_OPERAND_LENGTH)
  117. /* Length x in an instruction has real length x + 1. */
  118. ret.u = val + 1;
  119. else if (operand->flags & S390_OPERAND_VR)
  120. {
  121. /* Extract the extra bits for a vector register operand stored
  122. in the RXB field. */
  123. unsigned vr = operand->shift == 32 ? 3
  124. : (unsigned) operand->shift / 4 - 2;
  125. ret.u = val | ((orig_insn[4] & (1 << (3 - vr))) << (vr + 1));
  126. }
  127. else
  128. ret.u = val;
  129. return ret;
  130. }
  131. /* Print the S390 instruction in BUFFER, assuming that it matches the
  132. given OPCODE. */
  133. static void
  134. s390_print_insn_with_opcode (bfd_vma memaddr,
  135. struct disassemble_info *info,
  136. const bfd_byte *buffer,
  137. const struct s390_opcode *opcode)
  138. {
  139. const unsigned char *opindex;
  140. char separator;
  141. /* Mnemonic. */
  142. info->fprintf_func (info->stream, "%s", opcode->name);
  143. /* Operands. */
  144. separator = '\t';
  145. for (opindex = opcode->operands; *opindex != 0; opindex++)
  146. {
  147. const struct s390_operand *operand = s390_operands + *opindex;
  148. union operand_value val = s390_extract_operand (buffer, operand);
  149. unsigned long flags = operand->flags;
  150. if ((flags & S390_OPERAND_INDEX) && val.u == 0)
  151. continue;
  152. if ((flags & S390_OPERAND_BASE) &&
  153. val.u == 0 && separator == '(')
  154. {
  155. separator = ',';
  156. continue;
  157. }
  158. /* For instructions with a last optional operand don't print it
  159. if zero. */
  160. if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
  161. && val.u == 0
  162. && opindex[1] == 0)
  163. break;
  164. if (flags & S390_OPERAND_GPR)
  165. info->fprintf_func (info->stream, "%c%%r%u", separator, val.u);
  166. else if (flags & S390_OPERAND_FPR)
  167. info->fprintf_func (info->stream, "%c%%f%u", separator, val.u);
  168. else if (flags & S390_OPERAND_VR)
  169. info->fprintf_func (info->stream, "%c%%v%i", separator, val.u);
  170. else if (flags & S390_OPERAND_AR)
  171. info->fprintf_func (info->stream, "%c%%a%u", separator, val.u);
  172. else if (flags & S390_OPERAND_CR)
  173. info->fprintf_func (info->stream, "%c%%c%u", separator, val.u);
  174. else if (flags & S390_OPERAND_PCREL)
  175. {
  176. info->fprintf_func (info->stream, "%c", separator);
  177. info->print_address_func (memaddr + val.i + val.i, info);
  178. }
  179. else if (flags & S390_OPERAND_SIGNED)
  180. info->fprintf_func (info->stream, "%c%i", separator, val.i);
  181. else
  182. {
  183. if (flags & S390_OPERAND_OR1)
  184. val.u &= ~1;
  185. if (flags & S390_OPERAND_OR2)
  186. val.u &= ~2;
  187. if (flags & S390_OPERAND_OR8)
  188. val.u &= ~8;
  189. if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
  190. && val.u == 0
  191. && opindex[1] == 0)
  192. break;
  193. info->fprintf_func (info->stream, "%c%u", separator, val.u);
  194. }
  195. if (flags & S390_OPERAND_DISP)
  196. separator = '(';
  197. else if (flags & S390_OPERAND_BASE)
  198. {
  199. info->fprintf_func (info->stream, ")");
  200. separator = ',';
  201. }
  202. else
  203. separator = ',';
  204. }
  205. }
  206. /* Check whether opcode A's mask is more specific than that of B. */
  207. static int
  208. opcode_mask_more_specific (const struct s390_opcode *a,
  209. const struct s390_opcode *b)
  210. {
  211. return (((int) a->mask[0] + a->mask[1] + a->mask[2]
  212. + a->mask[3] + a->mask[4] + a->mask[5])
  213. > ((int) b->mask[0] + b->mask[1] + b->mask[2]
  214. + b->mask[3] + b->mask[4] + b->mask[5]));
  215. }
  216. /* Print a S390 instruction. */
  217. int
  218. print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
  219. {
  220. bfd_byte buffer[6];
  221. const struct s390_opcode *opcode = NULL;
  222. unsigned int value;
  223. int status, opsize, bufsize;
  224. if (init_flag == 0)
  225. init_disasm (info);
  226. /* The output looks better if we put 6 bytes on a line. */
  227. info->bytes_per_line = 6;
  228. /* Every S390 instruction is max 6 bytes long. */
  229. memset (buffer, 0, 6);
  230. status = info->read_memory_func (memaddr, buffer, 6, info);
  231. if (status != 0)
  232. {
  233. for (bufsize = 0; bufsize < 6; bufsize++)
  234. if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
  235. break;
  236. if (bufsize <= 0)
  237. {
  238. info->memory_error_func (status, memaddr, info);
  239. return -1;
  240. }
  241. opsize = s390_insn_length (buffer);
  242. status = opsize > bufsize;
  243. }
  244. else
  245. {
  246. bufsize = 6;
  247. opsize = s390_insn_length (buffer);
  248. }
  249. if (status == 0)
  250. {
  251. const struct s390_opcode *op;
  252. /* Find the "best match" in the opcode table. */
  253. for (op = s390_opcodes + opc_index[buffer[0]];
  254. op != s390_opcodes + s390_num_opcodes
  255. && op->opcode[0] == buffer[0];
  256. op++)
  257. {
  258. if ((op->modes & current_arch_mask)
  259. && s390_insn_matches_opcode (buffer, op)
  260. && (opcode == NULL
  261. || opcode_mask_more_specific (op, opcode)))
  262. opcode = op;
  263. }
  264. }
  265. if (opcode != NULL)
  266. {
  267. /* The instruction is valid. Print it and return its size. */
  268. s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
  269. return opsize;
  270. }
  271. /* Fall back to hex print. */
  272. if (bufsize >= 4)
  273. {
  274. value = (unsigned int) buffer[0];
  275. value = (value << 8) + (unsigned int) buffer[1];
  276. value = (value << 8) + (unsigned int) buffer[2];
  277. value = (value << 8) + (unsigned int) buffer[3];
  278. info->fprintf_func (info->stream, ".long\t0x%08x", value);
  279. return 4;
  280. }
  281. else if (bufsize >= 2)
  282. {
  283. value = (unsigned int) buffer[0];
  284. value = (value << 8) + (unsigned int) buffer[1];
  285. info->fprintf_func (info->stream, ".short\t0x%04x", value);
  286. return 2;
  287. }
  288. else
  289. {
  290. value = (unsigned int) buffer[0];
  291. info->fprintf_func (info->stream, ".byte\t0x%02x", value);
  292. return 1;
  293. }
  294. }
  295. void
  296. print_s390_disassembler_options (FILE *stream)
  297. {
  298. fprintf (stream, _("\n\
  299. The following S/390 specific disassembler options are supported for use\n\
  300. with the -M switch (multiple options should be separated by commas):\n"));
  301. fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
  302. fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));
  303. }