* configure.ac (AC_CHECK_FUNCS): Add iconv_open.
(AC_CHECK_HEADERS): Add iconv.h.
* tests/s390_sthyi-v.c: New file.
* tests/s390_sthyi.c: Likewise.
* tests/.gitignore: Add s390_sthyi, s390_sthyi-v.
* tests/pure_executables.list: Likewise.
* tests/gen_tests.in (s390_sthyi, s390_sthyi): New tests.
---
 configure.ac                |   2 +
 tests/.gitignore            |   2 +
 tests/gen_tests.in          |   2 +
 tests/pure_executables.list |   2 +
 tests/s390_sthyi-v.c        |   2 +
 tests/s390_sthyi.c          | 786 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 796 insertions(+)
 create mode 100644 tests/s390_sthyi-v.c
 create mode 100644 tests/s390_sthyi.c

diff --git a/configure.ac b/configure.ac
index a1391c7..63595ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -287,6 +287,7 @@ AC_CHECK_FUNCS(m4_normalize([
        fstatat
        ftruncate
        futimens
+       iconv_open
        if_indextoname
        open64
        prctl
@@ -394,6 +395,7 @@ AC_CHECK_HEADERS(m4_normalize([
        asm/sysmips.h
        bluetooth/bluetooth.h
        elf.h
+       iconv.h
        inttypes.h
        linux/bsg.h
        linux/cryptouser.h
diff --git a/tests/.gitignore b/tests/.gitignore
index 4c54589..19aa493 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -357,6 +357,8 @@ rt_sigsuspend
 rt_sigtimedwait
 rt_tgsigqueueinfo
 run_expect_termsig
+s390_sthyi
+s390_sthyi-v
 sched_get_priority_mxx
 sched_rr_get_interval
 sched_xetaffinity
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index 93b1687..968f6e4 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -303,6 +303,8 @@ rt_sigreturn        -esignal='!USR1'
 rt_sigsuspend  -a20 -esignal=none
 rt_sigtimedwait        -a38
 rt_tgsigqueueinfo      -esignal=none
+s390_sthyi     -a47
+s390_sthyi-v   -e trace=s390_sthyi -a47
 sched  test_trace_expr times -e/sched
 sched_get_priority_mxx -a33 -e 
trace=sched_get_priority_min,sched_get_priority_max
 sched_rr_get_interval  -a31
diff --git a/tests/pure_executables.list b/tests/pure_executables.list
index 8f5ff31..d8b997d 100755
--- a/tests/pure_executables.list
+++ b/tests/pure_executables.list
@@ -296,6 +296,8 @@ rt_sigreturn
 rt_sigsuspend
 rt_sigtimedwait
 rt_tgsigqueueinfo
+s390_sthyi
+s390_sthyi-v
 sched_get_priority_mxx
 sched_rr_get_interval
 sched_xetaffinity
diff --git a/tests/s390_sthyi-v.c b/tests/s390_sthyi-v.c
new file mode 100644
index 0000000..8605520
--- /dev/null
+++ b/tests/s390_sthyi-v.c
@@ -0,0 +1,2 @@
+#define VERBOSE 1
+#include "s390_sthyi.c"
diff --git a/tests/s390_sthyi.c b/tests/s390_sthyi.c
new file mode 100644
index 0000000..1554daf
--- /dev/null
+++ b/tests/s390_sthyi.c
@@ -0,0 +1,786 @@
+/*
+ * Check decoding of s390_sthyi syscall.
+ *
+ * Copyright (c) 2018 The strace developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests.h"
+#include <asm/unistd.h>
+
+#if defined HAVE_ICONV_H && defined HAVE_ICONV_OPEN && defined __NR_s390_sthyi
+
+# include <errno.h>
+# include <iconv.h>
+# include <inttypes.h>
+# include <stdbool.h>
+# include <stdint.h>
+# include <stdio.h>
+# include <unistd.h>
+
+# include <sys/user.h>
+
+# define EBCDIC_MAX_LEN 16
+
+# ifndef VERBOSE
+#  define VERBOSE 0
+# endif
+
+static bool
+print_0x8(const char *prefix, unsigned char *buf, unsigned int offs, bool zero)
+{
+       if (!zero && !buf[offs])
+               return false;
+
+       printf("%s=%#02hhx", prefix, buf[offs]);
+
+       return true;
+}
+
+static bool
+print_u8(const char *prefix, unsigned char *buf, unsigned int offs, bool zero)
+{
+       if (!zero && !buf[offs])
+               return false;
+
+       printf("%s=%hhu", prefix, buf[offs]);
+
+       return true;
+}
+
+static bool
+print_u16(const char *prefix, unsigned char *buf, unsigned int offs, bool zero)
+{
+       uint16_t val = *(uint16_t *) (buf + offs);
+
+       if (!zero && !val)
+               return false;
+
+       printf("%s=%" PRIu16, prefix, val);
+
+       return true;
+}
+
+static bool
+print_x32(const char *prefix, unsigned char *buf, unsigned int offs, bool zero)
+{
+       uint32_t val = *(uint32_t *) (buf + offs);
+
+       if (!zero && !val)
+               return false;
+
+       printf("%s=%#" PRIx32, prefix, val);
+
+       return true;
+}
+
+static bool
+print_weight(const char *prefix, unsigned char *buf, unsigned int offs,
+            bool zero)
+{
+       uint32_t val = *(uint32_t *) (buf + offs);
+
+       if (print_x32(prefix, buf, offs, zero)) {
+               if (val)
+                       printf(" /* %u %u/65536 cores */",
+                              val >> 16, val & 0xFFFF);
+               else
+                       printf(" /* unlimited */");
+
+               return true;
+       }
+
+       return false;
+}
+
+static char *
+ebcdic2ascii(unsigned char *ebcdic, size_t size)
+{
+       static char ascii_buf[EBCDIC_MAX_LEN];
+
+       char *ebcdic_pos = (char *) ebcdic;
+       char *ascii_pos = ascii_buf;
+       size_t ebcdic_left = size;
+       size_t ascii_left = size;
+       size_t ret;
+
+       iconv_t cd = iconv_open("ASCII", "EBCDICUS");
+
+       if (size > sizeof(ascii_buf))
+               error_msg_and_fail("ebcdic2ascii: EBCDIC string is too big: "
+                                  "%zu (maximum is %zu)",
+                                  size, sizeof(ascii_buf));
+       if (cd == (iconv_t) -1)
+               perror_msg_and_fail("ebcdic2ascii: unable to allocate a "
+                                   "conversion descriptior for converting "
+                                   "EBCDIC to ASCII");
+
+       while ((ret = iconv(cd, &ebcdic_pos, &ebcdic_left,
+           &ascii_pos, &ascii_left)) == (size_t) -1) {
+               switch (errno) {
+               case EILSEQ:
+               case EINVAL: /* That one is quite unexpected, actually */
+                       if (!ebcdic_left || !ascii_left)
+                               goto ebcdic2ascii_end;
+
+                       *ascii_pos++ = ' ';
+                       ebcdic_pos++;
+                       ebcdic_left--;
+
+                       break;
+
+               case E2BIG:
+                       perror_msg_and_fail("ebcdic2ascii: ran out of "
+                                           "ASCII buffer unexpectedly");
+               default:
+                       perror_msg_and_fail("ebcdic2ascii: unexpected error");
+               }
+       }
+
+ebcdic2ascii_end:
+       iconv_close(cd);
+
+       if (ebcdic_left != ascii_left)
+               error_msg_and_fail("ebcdic2ascii: ASCII string differs in size "
+                                  "from EBCDIC");
+
+       return ascii_buf;
+}
+
+# if VERBOSE
+static bool
+is_empty(unsigned char *ptr, size_t size)
+{
+       size_t i;
+
+       for (i = 0; !*ptr && i < size; ptr++, i++)
+               ;
+
+       return i == size;
+}
+# endif /* !VERBOSE */
+
+static bool
+print_ebcdic(const char *prefix, unsigned char *addr, unsigned int offs,
+            size_t size, bool zero, bool blank)
+{
+       const char *ascii = ebcdic2ascii(addr + offs, size);
+
+       if (!zero) {
+               size_t i;
+
+               for (i = 0; (addr[offs + i] == (blank ? 64 : 0)) && (i < size);
+                   i++)
+                       ;
+
+               if (i == size)
+                       return false;
+       }
+
+       printf("%s=", prefix);
+       print_quoted_hex((char *) (addr + offs), size);
+       printf(" /* ");
+       print_quoted_memory(ascii, size);
+       printf(" */");
+
+       return true;
+}
+
+static void
+print_hypervisor_header(unsigned char *buf, int level, unsigned int offs_pos,
+                       unsigned int len_pos, bool mt)
+{
+       uint16_t offs = *(uint16_t *) (buf + offs_pos);
+       uint16_t hdr_size = *(uint16_t *) (buf + len_pos);
+       unsigned char *cur;
+
+       if (!offs)
+               return;
+       if (hdr_size < 32)
+               error_msg_and_fail("sthyi: hypervisor %d section is too small "
+                                  "(got %hu, 32 expected)", level, hdr_size);
+
+       cur = buf + offs;
+
+       printf(", /* hypervisor %d */ {infyflg1", level);
+       print_0x8("", cur, 0, true);
+# if VERBOSE
+       if (cur[0]) {
+               bool printed = false;
+
+               printf(" /* ");
+               if (cur[0] & 0x80) {
+                       printf("0x80 - guest CPU usage had limiting is using "
+                              "the consumption method");
+                       printed = true;
+               }
+               if (cur[0] & 0x40) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x40 - LIMITHARD caps use prorated core time "
+                              "for capping");
+                       printed = true;
+               }
+               if (cur[0] & 0x3F) {
+                       if (printed)
+                               printf(", ");
+                       printf("%#hhx - ???", cur[0] & 0x3F);
+               }
+               printf(" */");
+       }
+
+       print_0x8(", infyflg2", cur, 1, false);
+       print_0x8(", infyval1", cur, 2, false);
+       print_0x8(", infyval2", cur, 3, false);
+
+       print_u8(", infytype", cur, 4, true);
+       if (cur[4] == 1)
+               printf(" /* z/VM is the hypervisor */");
+       else
+               printf(" /* unknown hypervisor type */");
+
+       if (cur[5])
+               printf(", reserved_1__=\"\\x%#02hhx\"", cur[5]);
+# endif /* !VERBOSE */
+
+       print_u8(", infycpt",  cur, 6, VERBOSE && mt);
+       print_u8(", infyiflt", cur, 7, VERBOSE && mt);
+
+       print_ebcdic(", infysyid", cur, 8,  8, VERBOSE, true);
+       print_ebcdic(", infyclnm", cur, 16, 8, VERBOSE, true);
+
+       print_u16(", infyscps", cur, 24, VERBOSE);
+       print_u16(", infydcps", cur, 26, VERBOSE);
+       print_u16(", infysifl", cur, 28, VERBOSE);
+       print_u16(", infydifl", cur, 30, VERBOSE);
+
+# if VERBOSE
+       if (hdr_size > 32 && !is_empty(cur + 32, hdr_size - 32)) {
+               printf(", ");
+               print_quoted_hex((char *) (cur + 32), hdr_size - 32);
+       }
+# else /* !VERBOSE */
+       printf(", ...");
+# endif /* !VERBOSE */
+
+       printf("}");
+}
+
+static void
+print_guest_header(unsigned char *buf, int level, unsigned int offs_pos,
+                  unsigned int len_pos)
+{
+       uint16_t offs = *(uint16_t *) (buf + offs_pos);
+       uint16_t hdr_size = *(uint16_t *) (buf + len_pos);
+       unsigned char *cur;
+
+       if (!offs)
+               return;
+       if (hdr_size < 56)
+               error_msg_and_fail("sthyi: guest %d section is too small "
+                                  "(got %hu, 56 expected)", level, hdr_size);
+
+       cur = buf + offs;
+
+       printf(", /* guest %d */ {infgflg1", level);
+       print_0x8("", cur, 0, true);
+# if VERBOSE
+       if (cur[0]) {
+               bool printed = false;
+
+               printf(" /* ");
+               if (cur[0] & 0x80) {
+                       printf("0x80 - guest is mobility enabled");
+                       printed = true;
+               }
+               if (cur[0] & 0x40) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x40 - guest has multiple virtual CPU types");
+                       printed = true;
+               }
+               if (cur[0] & 0x20) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x20 - guest CP dispatch type has LIMITHARD "
+                              "cap");
+                       printed = true;
+               }
+               if (cur[0] & 0x10) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x10 - guest IFL dispatch type has LIMITHARD "
+                              "cap");
+                       printed = true;
+               }
+               if (cur[0] & 0x08) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x08 - virtual CPs are thread dispatched");
+                       printed = true;
+               }
+               if (cur[0] & 0x04) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x04 - virtual IFLs are thread dispatched");
+                       printed = true;
+               }
+               if (cur[0] & 0x3) {
+                       if (printed)
+                               printf(", ");
+                       printf("%#hhx - ???", cur[0] & 0x3);
+               }
+               printf(" */");
+       }
+
+       print_0x8(", infgflg2", cur, 1, false);
+       print_0x8(", infgval1", cur, 2, false);
+       print_0x8(", infgval2", cur, 3, false);
+# endif /* !VERBOSE */
+
+       print_ebcdic(", infgusid", cur, 4, 8, true, false);
+
+       print_u16(", infgscps", cur, 12, VERBOSE);
+       print_u16(", infgdcps", cur, 14, VERBOSE);
+
+# if VERBOSE
+       print_u8(", infgcpdt", cur, 16, true);
+       if (cur[16] == 0)
+               printf(" /* General Purpose (CP) */");
+       else
+               printf(" /* unknown */");
+
+       if (cur[17] || cur[18] || cur[19])
+               printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"",
+                      cur[17], cur[18], cur[19]);
+# endif /* !VERBOSE */
+
+       print_weight(", infgcpcc", cur, 20, VERBOSE);
+
+       print_u16(", infgsifl", cur, 24, VERBOSE);
+       print_u16(", infgdifl", cur, 26, VERBOSE);
+
+# if VERBOSE
+       print_u8(", infgifdt", cur, 28, true);
+       if (cur[28] == 0)
+               printf(" /* General Purpose (CP) */");
+       else if (cur[28] == 3)
+               printf(" /* Integrated Facility for Linux (IFL) */");
+       else
+               printf(" /* unknown */");
+
+       if (cur[29] || cur[30] || cur[31])
+               printf(", reserved_2__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"",
+                      cur[29], cur[30], cur[31]);
+# endif /* !VERBOSE */
+
+       print_weight(", infgifcc", cur, 32, VERBOSE);
+
+       print_0x8(", infgpflg", cur, 36, true);
+# if VERBOSE
+       if (cur[36]) {
+               bool printed = false;
+
+               printf(" /* ");
+               if (cur[36] & 0x80) {
+                       printf("0x80 - CPU pool's CP virtual type has "
+                              "LIMITHARD cap");
+                       printed = true;
+               }
+               if (cur[36] & 0x40) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x40 - CPU pool's CP virtual type has "
+                              "CAPACITY cap");
+                       printed = true;
+               }
+               if (cur[36] & 0x20) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x20 - CPU pool's IFL virtual type has "
+                              "LIMITHARD cap");
+                       printed = true;
+               }
+               if (cur[36] & 0x10) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x10 - CPU pool's IFL virtual type has "
+                              "CAPACITY cap");
+                       printed = true;
+               }
+               if (cur[36] & 0x08) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x08 - CPU pool uses prorated core time");
+                       printed = true;
+               }
+               if (cur[36] & 0x7) {
+                       if (printed)
+                               printf(", ");
+                       printf("%#hhx - ???", cur[36] & 0x7);
+               }
+               printf(" */");
+       }
+
+       if (cur[37] || cur[38] || cur[39])
+               printf(", reserved_3__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"",
+                      cur[37], cur[38], cur[39]);
+
+       print_ebcdic(", infgpnam", cur, 40, 8, false, true);
+
+       print_weight(", infgpccc", cur, 48, true);
+       print_weight(", infgpicc", cur, 52, true);
+
+       if (hdr_size > 56 && !is_empty(cur + 56, hdr_size - 56)) {
+               printf(", ");
+               print_quoted_hex((char *) (cur + 56), hdr_size - 56);
+       }
+# else /* !VERBOSE */
+       printf(", ...");
+# endif /* !VERBOSE */
+
+       printf("}");
+}
+
+static void
+print_sthyi(unsigned char *buf)
+{
+       unsigned char *cur;
+       uint16_t hdr_size;
+       uint16_t offs;
+       bool mt = false;
+
+       hdr_size = *(uint16_t *) (buf + 10);
+       if (hdr_size < 44)
+               error_msg_and_fail("sthyi: header section is too small "
+                                  "(got %hu, 44 expected)", hdr_size);
+
+       /* INFHFLG1 */
+       print_0x8("{/* header */ {infhflg1", buf, 0, true);
+# if VERBOSE
+       if (buf[0]) {
+               bool printed = false;
+
+               printf(" /* ");
+               if (buf[0] & 0x80) {
+                       printf("0x80 - Global Performance Data unavailable");
+                       printed = true;
+               }
+               if (buf[0] & 0x40) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x40 - One or more hypervisor levels below "
+                              "this level does not support the STHYI "
+                              "instruction");
+                       printed = true;
+               }
+               if (buf[0] & 0x20) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x20 - Virtualization stack is incomplete");
+                       printed = true;
+               }
+               if (buf[0] & 0x10) {
+                       if (printed)
+                               printf(", ");
+                       printf("0x10 - Execution environment is not within a "
+                              "logical partition");
+                       printed = true;
+               }
+               if (buf[0] & 0xF) {
+                       if (printed)
+                               printf(", ");
+                       printf("%#hhx - ???", buf[0] & 0xF);
+               }
+               printf(" */");
+       }
+
+       print_0x8(", infhflg2", buf, 1, false);
+       print_0x8(", infhval1", buf, 2, false);
+       print_0x8(", infhval2", buf, 3, false);
+
+       /* Reserved */
+       if (buf[4] || buf[5] || buf[6])
+               printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\\x%#02hhx\"",
+                      buf[4], buf[5], buf[6]);
+
+       print_u8(", infhygct", buf, 7, true);
+       print_u16(", infhtotl", buf, 8, true);
+       print_u16(", infhdln", buf, 10, true);
+       print_u16(", infmoff", buf, 12, true);
+       print_u16(", infmlen", buf, 14, true);
+       print_u16(", infpoff", buf, 16, true);
+       print_u16(", infplen", buf, 18, true);
+       print_u16(", infhoff1", buf, 20, true);
+       print_u16(", infhlen1", buf, 22, true);
+       print_u16(", infgoff1", buf, 24, true);
+       print_u16(", infglen1", buf, 26, true);
+       print_u16(", infhoff2", buf, 28, true);
+       print_u16(", infhlen2", buf, 30, true);
+       print_u16(", infgoff2", buf, 32, true);
+       print_u16(", infglen2", buf, 34, true);
+       print_u16(", infhoff3", buf, 36, true);
+       print_u16(", infhlen3", buf, 38, true);
+       print_u16(", infgoff3", buf, 40, true);
+       print_u16(", infglen3", buf, 42, true);
+
+       if (hdr_size > 44 && !is_empty(buf + 44, hdr_size - 44)) {
+               printf(", ");
+               print_quoted_hex((char *) (buf + 44), hdr_size - 44);
+       }
+# else /* !VERBOSE */
+       printf(", ...");
+# endif /* !VERBOSE */
+
+       printf("}");
+
+       /* Machine header */
+       offs = *(uint16_t *) (buf + 12);
+       if (!offs)
+               goto partition_hdr;
+
+       hdr_size = *(uint16_t *) (buf + 14);
+       if (hdr_size < 60)
+               error_msg_and_fail("sthyi: machine section is too small "
+                                  "(got %hu, 60 expected)", hdr_size);
+
+       cur = buf + offs;
+
+       printf(", /* machine */ {");
+
+# if VERBOSE
+       print_0x8("infmflg1", cur, 0, false);
+       if (cur[0])
+               printf(", ");
+       print_0x8("infmflg2", cur, 1, false);
+       if (cur[1])
+               printf(", ");
+# endif /* !VERBOSE */
+       print_0x8("infmval1", cur, 2, true);
+
+       bool cnt_valid = cur[2] & 0x80;
+# if VERBOSE
+       bool id_valid = cur[2] & 0x40;
+       bool name_valid = cur[2] & 0x20;
+
+       printf(" /* processor count validity: %d, machine ID validity: %d, "
+              "machine name validity: %d",
+              !!cnt_valid, !!id_valid, !!name_valid);
+       if (cur[2] & 0x1F)
+               printf(", %#hhx - ???", cur[2] & 0x1F);
+       printf(" */");
+       print_0x8(", infmval2", cur, 3, false);
+# endif /* !VERBOSE */
+
+       print_u16(", infmscps", cur, 4,  cnt_valid);
+       print_u16(", infmdcps", cur, 6,  cnt_valid);
+       print_u16(", infmsifl", cur, 8,  cnt_valid);
+       print_u16(", infmdifl", cur, 10, cnt_valid);
+
+# if VERBOSE
+       print_ebcdic(", infmname", cur, 12, 8, name_valid, false);
+
+       print_ebcdic(", infmtype", cur, 20, 4,  id_valid, false);
+       print_ebcdic(", infmmanu", cur, 24, 16, id_valid, false);
+       print_ebcdic(", infmseq",  cur, 40, 16, id_valid, false);
+       print_ebcdic(", infmpman", cur, 56, 4,  id_valid, false);
+
+       if (hdr_size > 60 && !is_empty(cur + 60, hdr_size - 60)) {
+               printf(", ");
+               print_quoted_hex((char *) (cur + 60), hdr_size - 60);
+       }
+# else /* !VERBOSE */
+       printf(", ...");
+# endif /* !VERBOSE */
+
+       printf("}");
+
+partition_hdr:
+       /* Partition header */
+       offs = *(uint16_t *) (buf + 16);
+       if (!offs)
+               goto hv_hdr;
+
+       hdr_size = *(uint16_t *) (buf + 18);
+       if (hdr_size < 56)
+               error_msg_and_fail("sthyi: partition section is too small "
+                                  "(got %hu, 56 expected)", hdr_size);
+
+       cur = buf + offs;
+
+       print_0x8(", /* partition */ {infpflg1", cur, 0, true);
+       mt = !!(cur[0] & 0x80);
+# if VERBOSE
+       if (cur[0]) {
+               bool printed = false;
+
+               printf(" /* ");
+               if (cur[0] & 0x80) {
+                       printf("0x80 - multithreading is enabled");
+                       printed = true;
+               }
+               if (cur[0] & 0x7F) {
+                       if (printed)
+                               printf(", ");
+                       printf("%#hhx - ???", cur[0] & 0x7F);
+               }
+               printf(" */");
+       }
+       print_0x8(", infpflg2", cur, 1, false);
+# endif /* !VERBOSE */
+       print_0x8(", infpval1", cur, 2, true);
+
+       bool pcnt_valid  = cur[2] & 0x80;
+       bool pid_valid   = cur[2] & 0x10;
+# if VERBOSE
+       bool pwcap_valid = cur[2] & 0x40;
+       bool pacap_valid = cur[2] & 0x20;
+       bool lpar_valid  = cur[2] & 0x08;
+# endif /* !VERBOSE */
+
+# if VERBOSE
+       printf(" /* processor count validity: %d, partition weight-based "
+              "capacity validity: %d, partition absolute capacity validity: "
+              "%d, partition ID validity: %d, LPAR group absolute capacity "
+              "capping information validity: %d",
+              !!pcnt_valid, !!pwcap_valid, !!pacap_valid, !!pid_valid,
+              !!lpar_valid);
+       if (cur[2] & 0x7)
+               printf(", %#hhx - ???", cur[2] & 0x7);
+       printf(" */");
+
+       print_0x8(", infpval2", cur, 3, false);
+# endif /* !VERBOSE */
+
+       print_u16(", infppnum", cur, 4, pid_valid);
+
+       print_u16(", infpscps", cur, 6,  pcnt_valid);
+       print_u16(", infpdcps", cur, 8,  pcnt_valid);
+       print_u16(", infpsifl", cur, 10, pcnt_valid);
+       print_u16(", infpdifl", cur, 12, pcnt_valid);
+
+# if VERBOSE
+       if (cur[14] || cur[15])
+               printf(", reserved_1__=\"\\x%#02hhx\\x%#02hhx\"",
+                      cur[14], cur[15]);
+# endif /* !VERBOSE */
+
+       print_ebcdic(", infppnam", cur, 16, 8, pid_valid, false);
+
+# if VERBOSE
+       print_weight(", infpwbcp", cur, 24, pwcap_valid);
+       print_weight(", infpabcp", cur, 28, pacap_valid);
+       print_weight(", infpwbif", cur, 32, pwcap_valid);
+       print_weight(", infpabif", cur, 36, pacap_valid);
+
+       if (print_ebcdic(", infplgnm", cur, 40, 8, false, false)) {
+
+               print_weight(", infplgcp", cur, 48, false);
+               print_weight(", infplgif", cur, 52, false);
+       } else {
+               if (lpar_valid) {
+                       printf(", infplgnm=");
+                       print_quoted_hex((char *) (cur + 40), 8);
+               }
+
+               print_x32(", infplgcp", cur, 48, false);
+               print_x32(", infplgif", cur, 52, false);
+       }
+
+       if (hdr_size > 56 && !is_empty(cur + 56, hdr_size - 56)) {
+               printf(", ");
+               print_quoted_hex((char *) (cur + 56), hdr_size - 56);
+       }
+# else /* !VERBOSE */
+       printf(", ...");
+# endif /* !VERBOSE */
+
+       printf("}");
+
+hv_hdr:
+       /* Hypervisor/guest headers */
+       print_hypervisor_header(buf, 1, 20, 22, mt);
+       print_guest_header(buf, 1, 24, 26);
+       print_hypervisor_header(buf, 2, 28, 30, mt);
+       print_guest_header(buf, 2, 32, 34);
+       print_hypervisor_header(buf, 3, 36, 38, mt);
+       print_guest_header(buf, 3, 40, 42);
+
+       printf("}");
+}
+
+int
+main(void)
+{
+       static const kernel_ulong_t bogus_func =
+               (kernel_ulong_t) 0xdeafbeefdeadc0deULL;
+       static const kernel_ulong_t bogus_resp_buf =
+               (kernel_ulong_t) 0xfacefeedac0ffeedULL;
+       static const kernel_ulong_t bogus_ret_code =
+               (kernel_ulong_t) 0xf00dfa57decaffedULL;
+       static const kernel_ulong_t bogus_flags =
+               (kernel_ulong_t) 0xfee1deadfa57beefULL;
+
+       unsigned char *buf = tail_alloc(PAGE_SIZE);
+       uint64_t *ret = tail_alloc(sizeof(*ret));
+
+       long rc;
+
+       rc = syscall(__NR_s390_sthyi, 0, 0, 0, 0);
+       printf("s390_sthyi(STHYI_FC_CP_IFL_CAP, NULL, NULL, 0) = %s\n",
+              sprintrc(rc));
+
+       rc = syscall(__NR_s390_sthyi, bogus_func, bogus_resp_buf,
+                    bogus_ret_code, bogus_flags);
+       printf("s390_sthyi(%#llx /* STHYI_FC_??? */, %#llx, %#llx, %#llx) = "
+              "%s\n",
+              (unsigned long long) bogus_func,
+              (unsigned long long) bogus_resp_buf,
+              (unsigned long long) bogus_ret_code,
+              (unsigned long long) bogus_flags,
+              sprintrc(rc));
+
+       rc = syscall(__NR_s390_sthyi, bogus_func, buf, ret, 0);
+       printf("s390_sthyi(%#llx /* STHYI_FC_??? */, %p, %p, 0) = %s\n",
+              (unsigned long long) bogus_func, buf, ret, sprintrc(rc));
+
+       rc = syscall(__NR_s390_sthyi, 0, buf, ret, 0);
+       if (rc)
+               error_msg_and_fail("syscall(__NR_s390_sthyi, 0, buf, ret, 0) "
+                                  "returned unexpected value of %ld", rc);
+
+       printf("s390_sthyi(STHYI_FC_CP_IFL_CAP, ");
+       print_sthyi(buf);
+       printf(", [0], 0) = 0\n");
+
+       puts("+++ exited with 0 +++");
+       return 0;
+}
+
+#else
+
+SKIP_MAIN_UNDEFINED("HAVE_ICONV_H && HAVE_ICONV_OPEN && __NR_s390_sthyi")
+
+#endif
-- 
2.1.4


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to