• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /* -*- mode: C; c-basic-offset: 3; -*- */
2  
3  /*---------------------------------------------------------------*/
4  /*--- begin                                     s390_disasm.c ---*/
5  /*---------------------------------------------------------------*/
6  
7  /*
8     This file is part of Valgrind, a dynamic binary instrumentation
9     framework.
10  
11     Copyright IBM Corp. 2010-2015
12  
13     This program is free software; you can redistribute it and/or
14     modify it under the terms of the GNU General Public License as
15     published by the Free Software Foundation; either version 2 of the
16     License, or (at your option) any later version.
17  
18     This program is distributed in the hope that it will be useful, but
19     WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21     General Public License for more details.
22  
23     You should have received a copy of the GNU General Public License
24     along with this program; if not, write to the Free Software
25     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26     02110-1301, USA.
27  
28     The GNU General Public License is contained in the file COPYING.
29  */
30  
31  /* Contributed by Florian Krohm */
32  
33  #include <stdarg.h>
34  #include "libvex_basictypes.h"
35  #include "main_util.h"        // vassert
36  #include "main_globals.h"     // vex_traceflags
37  #include "s390_defs.h"        // S390_MAX_MNEMONIC_LEN
38  #include "s390_disasm.h"
39  
40  
41  /* Return the mnemonic padded with blanks to its right */
42  static const HChar *
mnemonic(const HChar * mnm)43  mnemonic(const HChar *mnm)
44  {
45     vassert(vex_strlen(mnm) <= S390_MAX_MNEMONIC_LEN);
46  
47     static HChar buf[S390_MAX_MNEMONIC_LEN + 1];
48  
49     vex_sprintf(buf, "%-*s", S390_MAX_MNEMONIC_LEN, mnm);
50  
51     return buf;
52  }
53  
54  
55  /* Return the name of a general purpose register for dis-assembly purposes. */
56  static const HChar *
gpr_operand(UInt archreg)57  gpr_operand(UInt archreg)
58  {
59     static const HChar names[16][5] = {
60        "%r0", "%r1", "%r2", "%r3",
61        "%r4", "%r5", "%r6", "%r7",
62        "%r8", "%r9", "%r10", "%r11",
63        "%r12", "%r13", "%r14", "%r15",
64     };
65  
66     vassert(archreg < 16);
67  
68     return names[archreg];
69  }
70  
71  
72  /* Return the name of a floating point register for dis-assembly purposes. */
73  static const HChar *
fpr_operand(UInt archreg)74  fpr_operand(UInt archreg)
75  {
76     static const HChar names[16][5] = {
77        "%f0", "%f1", "%f2", "%f3",
78        "%f4", "%f5", "%f6", "%f7",
79        "%f8", "%f9", "%f10", "%f11",
80        "%f12", "%f13", "%f14", "%f15",
81     };
82  
83     vassert(archreg < 16);
84  
85     return names[archreg];
86  }
87  
88  
89  /* Return the name of an access register for dis-assembly purposes. */
90  static const HChar *
ar_operand(UInt archreg)91  ar_operand(UInt archreg)
92  {
93     static const HChar names[16][5] = {
94        "%a0", "%a1", "%a2", "%a3",
95        "%a4", "%a5", "%a6", "%a7",
96        "%a8", "%a9", "%a10", "%a11",
97        "%a12", "%a13", "%a14", "%a15",
98     };
99  
100     vassert(archreg < 16);
101  
102     return names[archreg];
103  }
104  
105  
106  /* Build and return the extended mnemonic for the compare and branch
107     opcodes as introduced by z10. See also the opcodes in file
108     opcodes/s390-opc.txt (from binutils) that have a '$' in their name. */
109  static const HChar *
cab_operand(const HChar * base,UInt mask)110  cab_operand(const HChar *base, UInt mask)
111  {
112     HChar *to;
113     const HChar *from;
114  
115     static HChar buf[S390_MAX_MNEMONIC_LEN + 1];
116  
117     static const HChar suffix[8][3] = {
118        "", "h", "l", "ne", "e", "nl", "nh", ""
119     };
120  
121     /* Guard against buffer overflow */
122     vassert(vex_strlen(base) + sizeof suffix[0] <= sizeof buf);
123  
124     /* strcpy(buf, from); */
125     for (from = base, to = buf; *from; ++from, ++to) {
126        *to = *from;
127     }
128     /* strcat(buf, suffix); */
129     for (from = suffix[mask >> 1]; *from; ++from, ++to) {
130        *to = *from;
131     }
132     *to = '\0';
133  
134     return buf;
135  }
136  
137  
138  /* Common function used to construct a mnemonic based on a condition code
139     mask. */
140  static const HChar *
construct_mnemonic(const HChar * prefix,const HChar * suffix,UInt mask)141  construct_mnemonic(const HChar *prefix, const HChar *suffix, UInt mask)
142  {
143     HChar *to;
144     const HChar *from;
145  
146     static HChar buf[S390_MAX_MNEMONIC_LEN + 1];
147  
148     static HChar mask_id[16][4] = {
149        "", /* 0 -> unused */
150        "o", "h", "nle", "l", "nhe", "lh", "ne",
151        "e", "nlh", "he", "nl", "le", "nh", "no",
152        ""  /* 15 -> unused */
153     };
154  
155     /* Guard against buffer overflow */
156     vassert(vex_strlen(prefix) + vex_strlen(suffix) +
157             sizeof mask_id[0] <= sizeof buf);
158  
159     /* strcpy(buf, prefix); */
160     for (from = prefix, to = buf; *from; ++from, ++to) {
161        *to = *from;
162     }
163     /* strcat(buf, mask_id); */
164     for (from = mask_id[mask]; *from; ++from, ++to) {
165        *to = *from;
166     }
167     /* strcat(buf, suffix); */
168     for (from = suffix; *from; ++from, ++to) {
169        *to = *from;
170     }
171     *to = '\0';
172  
173     return buf;
174  }
175  
176  
177  /* Return the special mnemonic for the BCR opcode */
178  static const HChar *
bcr_operand(UInt m1)179  bcr_operand(UInt m1)
180  {
181     if (m1 ==  0) return "nopr";
182     if (m1 == 15) return "br";
183  
184     return construct_mnemonic("b", "r", m1);
185  }
186  
187  
188  /* Return the special mnemonic for the BC opcode */
189  static const HChar *
bc_operand(UInt m1)190  bc_operand(UInt m1)
191  {
192     if (m1 ==  0) return "nop";
193     if (m1 == 15) return "b";
194  
195     return construct_mnemonic("b", "", m1);
196  }
197  
198  
199  /* Return the special mnemonic for the BRC opcode */
200  static const HChar *
brc_operand(UInt m1)201  brc_operand(UInt m1)
202  {
203     if (m1 == 0)  return "brc";
204     if (m1 == 15) return "j";
205  
206     return construct_mnemonic("j", "", m1);
207  }
208  
209  
210  /* Return the special mnemonic for the BRCL opcode */
211  static const HChar *
brcl_operand(UInt m1)212  brcl_operand(UInt m1)
213  {
214     if (m1 == 0)  return "brcl";
215     if (m1 == 15) return "jg";
216  
217     return construct_mnemonic("jg", "", m1);
218  }
219  
220  
221  /* Return the special mnemonic for a conditional load/store  opcode */
222  static const HChar *
cls_operand(Int kind,UInt mask)223  cls_operand(Int kind, UInt mask)
224  {
225     const HChar *prefix;
226  
227     switch (kind) {
228     case S390_XMNM_LOCR:   prefix = "locr";  break;
229     case S390_XMNM_LOCGR:  prefix = "locgr"; break;
230     case S390_XMNM_LOC:    prefix = "loc";   break;
231     case S390_XMNM_LOCG:   prefix = "locg";  break;
232     case S390_XMNM_STOC:   prefix = "stoc";  break;
233     case S390_XMNM_STOCG:  prefix = "stocg"; break;
234     default:
235        vpanic("cls_operand");
236     }
237  
238     return construct_mnemonic(prefix, "", mask);
239  }
240  
241  
242  /* An operand with a base register, an index register, and a displacement.
243     If the displacement is signed, the rightmost 20 bit of D need to be
244     sign extended */
245  static HChar *
dxb_operand(HChar * p,UInt d,UInt x,UInt b,Bool displacement_is_signed)246  dxb_operand(HChar *p, UInt d, UInt x, UInt b, Bool displacement_is_signed)
247  {
248     if (displacement_is_signed) {
249        Int displ = (Int)(d << 12) >> 12;  /* sign extend */
250  
251        p += vex_sprintf(p, "%d", displ);
252     } else {
253        p += vex_sprintf(p, "%u", d);
254     }
255     if (x != 0) {
256        p += vex_sprintf(p, "(%s", gpr_operand(x));
257        if (b != 0) {
258           p += vex_sprintf(p, ",%s", gpr_operand(b));
259        }
260        p += vex_sprintf(p, ")");
261     } else {
262        if (b != 0) {
263           p += vex_sprintf(p, "(%s)", gpr_operand(b));
264        }
265     }
266  
267     return p;
268  }
269  
270  
271  /* An operand with base register, unsigned length, and a 12-bit
272     unsigned displacement */
273  static HChar *
udlb_operand(HChar * p,UInt d,UInt length,UInt b)274  udlb_operand(HChar *p, UInt d, UInt length, UInt b)
275  {
276     p += vex_sprintf(p, "%u", d);
277     p += vex_sprintf(p, "(%u", length + 1);  // actual length is +1
278     if (b != 0) {
279        p += vex_sprintf(p, ",%s", gpr_operand(b));
280     }
281     p += vex_sprintf(p, ")");
282  
283     return p;
284  }
285  
286  
287  /* The first argument is the command that says how to write the disassembled
288     insn. It is understood that the mnemonic comes first and that arguments
289     are separated by a ','. The command holds the arguments. Each argument is
290     encoded using a 4-bit S390_ARG_xyz value. The first argument is placed
291     in the least significant bits of the command and so on. There are at most
292     5 arguments in an insn and a sentinel (S390_ARG_DONE) is needed to identify
293     the end of the argument list. 6 * 4 = 24 bits are required for the
294     command. */
295  void
s390_disasm(UInt command,...)296  s390_disasm(UInt command, ...)
297  {
298     va_list  args;
299     UInt argkind;
300     HChar buf[128];  /* holds the disassembled insn */
301     HChar *p;
302     HChar separator;
303     Int mask_suffix = -1;
304  
305     va_start(args, command);
306  
307     p = buf;
308     separator = 0;
309  
310     while (42) {
311        argkind = command & 0xF;
312        command >>= 4;
313  
314        if (argkind == S390_ARG_DONE) goto done;
315  
316        if (argkind == S390_ARG_CABM) separator = 0;  /* optional */
317  
318        /* Write out the separator */
319        if (separator) *p++ = separator;
320  
321        /* argument */
322        switch (argkind) {
323        case S390_ARG_MNM:
324           p += vex_sprintf(p, "%s", mnemonic(va_arg(args, HChar *)));
325           separator = ' ';
326           continue;
327  
328        case S390_ARG_XMNM: {
329           UInt mask, kind;
330           const HChar *mnm;
331  
332           kind = va_arg(args, UInt);
333  
334           separator = ' ';
335           switch (kind) {
336           case S390_XMNM_BC:
337           case S390_XMNM_BCR:
338              mask = va_arg(args, UInt);
339              mnm = kind == S390_XMNM_BCR ? bcr_operand(mask) : bc_operand(mask);
340              p  += vex_sprintf(p, "%s", mnemonic(mnm));
341              /* mask == 0 is a NOP and has no argument */
342              if (mask == 0) goto done;
343              break;
344  
345           case S390_XMNM_BRC:
346           case S390_XMNM_BRCL:
347              mask = va_arg(args, UInt);
348              mnm = kind == S390_XMNM_BRC ? brc_operand(mask) : brcl_operand(mask);
349              p  += vex_sprintf(p, "%s", mnemonic(mnm));
350  
351              /* mask == 0 has no special mnemonic */
352              if (mask == 0) {
353                 p += vex_sprintf(p, " 0");
354                 separator = ',';
355              }
356              break;
357  
358           case S390_XMNM_CAB:
359              mnm  = va_arg(args, HChar *);
360              mask = va_arg(args, UInt);
361              p  += vex_sprintf(p, "%s", mnemonic(cab_operand(mnm, mask)));
362              break;
363  
364           case S390_XMNM_LOCR:
365           case S390_XMNM_LOCGR:
366           case S390_XMNM_LOC:
367           case S390_XMNM_LOCG:
368           case S390_XMNM_STOC:
369           case S390_XMNM_STOCG:
370              mask = va_arg(args, UInt);
371              mnm = cls_operand(kind, mask);
372              p  += vex_sprintf(p, "%s", mnemonic(mnm));
373              /* There are no special opcodes when mask == 0 or 15. In that case
374                 the integer mask is appended as the final operand */
375              if (mask == 0 || mask == 15) mask_suffix = mask;
376              break;
377           }
378        }
379        continue;
380  
381        case S390_ARG_GPR:
382           p += vex_sprintf(p, "%s", gpr_operand(va_arg(args, UInt)));
383           break;
384  
385        case S390_ARG_FPR:
386           p += vex_sprintf(p, "%s", fpr_operand(va_arg(args, UInt)));
387           break;
388  
389        case S390_ARG_AR:
390           p += vex_sprintf(p, "%s", ar_operand(va_arg(args, UInt)));
391           break;
392  
393        case S390_ARG_UINT:
394           p += vex_sprintf(p, "%u", va_arg(args, UInt));
395           break;
396  
397        case S390_ARG_INT:
398           p += vex_sprintf(p, "%d", (Int)(va_arg(args, UInt)));
399           break;
400  
401        case S390_ARG_PCREL: {
402           Long offset = va_arg(args, Int);
403  
404           /* Convert # halfwords to # bytes */
405           offset <<= 1;
406  
407           if (offset < 0) {
408              p += vex_sprintf(p, ".%lld", offset);
409           } else {
410              p += vex_sprintf(p, ".+%lld", offset);
411           }
412           break;
413        }
414  
415        case S390_ARG_SDXB: {
416           UInt dh, dl, x, b;
417  
418           dh = va_arg(args, UInt);
419           dl = va_arg(args, UInt);
420           x  = va_arg(args, UInt);
421           b  = va_arg(args, UInt);
422  
423           p = dxb_operand(p, (dh << 12) | dl, x, b, 1 /* signed_displacement */);
424           break;
425        }
426  
427        case S390_ARG_UDXB: {
428           UInt d, x, b;
429  
430           d = va_arg(args, UInt);
431           x = va_arg(args, UInt);
432           b = va_arg(args, UInt);
433  
434           p = dxb_operand(p, d, x, b, 0 /* signed_displacement */);
435           break;
436        }
437  
438        case S390_ARG_UDLB: {
439           UInt d, l, b;
440  
441           d = va_arg(args, UInt);
442           l = va_arg(args, UInt);
443           b = va_arg(args, UInt);
444  
445           p = udlb_operand(p, d, l, b);
446           break;
447        }
448  
449        case S390_ARG_CABM: {
450           UInt mask;
451  
452           mask = va_arg(args, UInt) & 0xE;
453           if (mask == 0 || mask == 14) {
454              p += vex_sprintf(p, ",%u", mask);
455           }
456           break;
457        }
458        }
459  
460        separator = ',';
461     }
462  
463   done:
464     va_end(args);
465  
466     if (mask_suffix != -1)
467        p += vex_sprintf(p, ",%d", mask_suffix);
468     *p = '\0';
469  
470     vassert(p < buf + sizeof buf);  /* detect buffer overwrite */
471  
472     /* Finally, write out the disassembled insn */
473     vex_printf("%s\n", buf);
474  }
475  
476  /*---------------------------------------------------------------*/
477  /*--- end                                       s390_disasm.c ---*/
478  /*---------------------------------------------------------------*/
479