diff mbox series

linux-user: Add strace support for printing arguments for ioctls used for terminals and serial lines

Message ID 20200714200439.11328-1-Filip.Bozuta@syrmia.com (mailing list archive)
State New, archived
Headers show
Series linux-user: Add strace support for printing arguments for ioctls used for terminals and serial lines | expand

Commit Message

Filip Bozuta July 14, 2020, 8:04 p.m. UTC
Functions "print_ioctl()" and "print_syscall_ret_ioctl()" are used
to print arguments of "ioctl()" with "-strace". These functions
use "thunk_print()", which is defined in "thunk.c", to print the
contents of ioctl's third arguments that are not basic types.
However, this function doesn't handle ioctls of group ioctl_tty which
are used for terminals and serial lines. These ioctls use a type
"struct termios" which thunk type is defined in a non standard
way using "STRUCT_SPECIAL()". This means that this type is not decoded
regularly using "thunk_convert()" and uses special converting functions
"target_to_host_termios()" and "host_to_target_termios()", which are defined
in "syscall.c" to decode it's values. For simillar reasons, this type is
also not printed regularly using "thunk_print()". That is the reason
why a separate printing function "print_termios()" is defined in
file "strace.c". This function decodes and prints flag values of the
"termios" structure.

Implementation notes:

    Function "print_termios()" was implemented in "strace.c" using
    an existing function "print_flags()" to print flag values of
    "struct termios" fields. These flag values were defined
    using an existing macro "FLAG_TARGET()" that generates aproppriate
    target flag values and string representations of these flags.
    This function was declared in "qemu.h" so that it can be accessed
    in "syscall.c". Type "StructEntry" defined in "exec/user/thunk.h"
    contains information that is used to decode structure values.
    Field "void print(void *arg)" was added in this structure as a
    special print function. Also, function "thunk_print()" was changed
    a little so that it uses this special print function in case
    it is defined. This printing function was instantiated with the
    defined "print_termios()" in "syscall.c" in "struct_termios_def".

Signed-off-by: Filip Bozuta <Filip.Bozuta@syrmia.com>
---
 include/exec/user/thunk.h |   1 +
 linux-user/qemu.h         |   2 +
 linux-user/strace.c       | 193 ++++++++++++++++++++++++++++++++++++++
 linux-user/syscall.c      |   1 +
 thunk.c                   |  23 +++--
 5 files changed, 211 insertions(+), 9 deletions(-)

Comments

no-reply@patchew.org July 14, 2020, 8:54 p.m. UTC | #1
Patchew URL: https://patchew.org/QEMU/20200714200439.11328-1-Filip.Bozuta@syrmia.com/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20200714200439.11328-1-Filip.Bozuta@syrmia.com
Subject: [PATCH] linux-user: Add strace support for printing arguments for ioctls used for terminals and serial lines

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

From https://github.com/patchew-project/qemu
   d2628b1..8bfa25a  master     -> master
Switched to a new branch 'test'
ae9f19a linux-user: Add strace support for printing arguments for ioctls used for terminals and serial lines

=== OUTPUT BEGIN ===
ERROR: storage class should be at the beginning of the declaration
#75: FILE: linux-user/strace.c:1196:
+UNUSED static struct flags termios_iflags[] = {

ERROR: storage class should be at the beginning of the declaration
#93: FILE: linux-user/strace.c:1214:
+UNUSED static struct flags termios_oflags[] = {

ERROR: storage class should be at the beginning of the declaration
#105: FILE: linux-user/strace.c:1226:
+UNUSED static struct flags termios_oflags_NLDLY[] = {

ERROR: storage class should be at the beginning of the declaration
#111: FILE: linux-user/strace.c:1232:
+UNUSED static struct flags termios_oflags_CRDLY[] = {

ERROR: storage class should be at the beginning of the declaration
#119: FILE: linux-user/strace.c:1240:
+UNUSED static struct flags termios_oflags_TABDLY[] = {

ERROR: storage class should be at the beginning of the declaration
#127: FILE: linux-user/strace.c:1248:
+UNUSED static struct flags termios_oflags_VTDLY[] = {

ERROR: storage class should be at the beginning of the declaration
#133: FILE: linux-user/strace.c:1254:
+UNUSED static struct flags termios_oflags_FFDLY[] = {

ERROR: storage class should be at the beginning of the declaration
#139: FILE: linux-user/strace.c:1260:
+UNUSED static struct flags termios_oflags_BSDLY[] = {

ERROR: storage class should be at the beginning of the declaration
#145: FILE: linux-user/strace.c:1266:
+UNUSED static struct flags termios_cflags_CBAUD[] = {

ERROR: storage class should be at the beginning of the declaration
#169: FILE: linux-user/strace.c:1290:
+UNUSED static struct flags termios_cflags_CSIZE[] = {

ERROR: storage class should be at the beginning of the declaration
#177: FILE: linux-user/strace.c:1298:
+UNUSED static struct flags termios_cflags[] = {

ERROR: storage class should be at the beginning of the declaration
#188: FILE: linux-user/strace.c:1309:
+UNUSED static struct flags termios_lflags[] = {

total: 12 errors, 0 warnings, 260 lines checked

Commit ae9f19a165a6 (linux-user: Add strace support for printing arguments for ioctls used for terminals and serial lines) has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20200714200439.11328-1-Filip.Bozuta@syrmia.com/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com
Laurent Vivier July 17, 2020, 2:47 p.m. UTC | #2
Le 14/07/2020 à 22:04, Filip Bozuta a écrit :
> Functions "print_ioctl()" and "print_syscall_ret_ioctl()" are used
> to print arguments of "ioctl()" with "-strace". These functions
> use "thunk_print()", which is defined in "thunk.c", to print the
> contents of ioctl's third arguments that are not basic types.
> However, this function doesn't handle ioctls of group ioctl_tty which
> are used for terminals and serial lines. These ioctls use a type
> "struct termios" which thunk type is defined in a non standard
> way using "STRUCT_SPECIAL()". This means that this type is not decoded
> regularly using "thunk_convert()" and uses special converting functions
> "target_to_host_termios()" and "host_to_target_termios()", which are defined
> in "syscall.c" to decode it's values. For simillar reasons, this type is
> also not printed regularly using "thunk_print()". That is the reason
> why a separate printing function "print_termios()" is defined in
> file "strace.c". This function decodes and prints flag values of the
> "termios" structure.
> 
> Implementation notes:
> 
>     Function "print_termios()" was implemented in "strace.c" using
>     an existing function "print_flags()" to print flag values of
>     "struct termios" fields. These flag values were defined
>     using an existing macro "FLAG_TARGET()" that generates aproppriate
>     target flag values and string representations of these flags.
>     This function was declared in "qemu.h" so that it can be accessed
>     in "syscall.c". Type "StructEntry" defined in "exec/user/thunk.h"
>     contains information that is used to decode structure values.
>     Field "void print(void *arg)" was added in this structure as a
>     special print function. Also, function "thunk_print()" was changed
>     a little so that it uses this special print function in case
>     it is defined. This printing function was instantiated with the
>     defined "print_termios()" in "syscall.c" in "struct_termios_def".
> 
> Signed-off-by: Filip Bozuta <Filip.Bozuta@syrmia.com>
> ---
>  include/exec/user/thunk.h |   1 +
>  linux-user/qemu.h         |   2 +
>  linux-user/strace.c       | 193 ++++++++++++++++++++++++++++++++++++++
>  linux-user/syscall.c      |   1 +
>  thunk.c                   |  23 +++--
>  5 files changed, 211 insertions(+), 9 deletions(-)
> 
> diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h
> index 7992475c9f..a5bbb2c733 100644
> --- a/include/exec/user/thunk.h
> +++ b/include/exec/user/thunk.h
> @@ -55,6 +55,7 @@ typedef struct {
>      int *field_offsets[2];
>      /* special handling */
>      void (*convert[2])(void *dst, const void *src);
> +    void (*print)(void *arg);
>      int size[2];
>      int align[2];
>      const char *name;
> diff --git a/linux-user/qemu.h b/linux-user/qemu.h
> index 5c964389c1..e51a0ededb 100644
> --- a/linux-user/qemu.h
> +++ b/linux-user/qemu.h
> @@ -706,6 +706,8 @@ static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
>  }
>  #endif /* TARGET_ABI_BITS != 32 */
>  
> +extern void print_termios(void *arg);
> +
>  /**
>   * preexit_cleanup: housekeeping before the guest exits
>   *
> diff --git a/linux-user/strace.c b/linux-user/strace.c
> index 5235b2260c..7b5408cf4a 100644
> --- a/linux-user/strace.c
> +++ b/linux-user/strace.c
> @@ -1193,6 +1193,138 @@ UNUSED static struct flags falloc_flags[] = {
>  #endif
>  };
>  
> +UNUSED static struct flags termios_iflags[] = {
> +    FLAG_TARGET(IGNBRK),
> +    FLAG_TARGET(BRKINT),
> +    FLAG_TARGET(IGNPAR),
> +    FLAG_TARGET(PARMRK),
> +    FLAG_TARGET(INPCK),
> +    FLAG_TARGET(ISTRIP),
> +    FLAG_TARGET(INLCR),
> +    FLAG_TARGET(IGNCR),
> +    FLAG_TARGET(ICRNL),
> +    FLAG_TARGET(IUCLC),
> +    FLAG_TARGET(IXON),
> +    FLAG_TARGET(IXANY),
> +    FLAG_TARGET(IXOFF),
> +    FLAG_TARGET(IMAXBEL),

IUTF8 is missing

> +    FLAG_END,
> +};
> +
> +UNUSED static struct flags termios_oflags[] = {
> +    FLAG_TARGET(OPOST),
> +    FLAG_TARGET(OLCUC),
> +    FLAG_TARGET(ONLCR),
> +    FLAG_TARGET(OCRNL),
> +    FLAG_TARGET(ONOCR),
> +    FLAG_TARGET(ONLRET),
> +    FLAG_TARGET(OFILL),
> +    FLAG_TARGET(OFDEL),
> +    FLAG_END,
> +};
> +

the following entries are not flags: flags are bits, while we have
enumerated values in these cases.

NL0, NL1 = 0,1

> +UNUSED static struct flags termios_oflags_NLDLY[] = {
> +    FLAG_TARGET(NL0),
> +    FLAG_TARGET(NL1),
> +    FLAG_END,
> +};

CR0, CR1, CR2, CR3 = 0, 1, 2, 3

> +UNUSED static struct flags termios_oflags_CRDLY[] = {
> +    FLAG_TARGET(CR0),
> +    FLAG_TARGET(CR1),
> +    FLAG_TARGET(CR2),
> +    FLAG_TARGET(CR3),
> +    FLAG_END,
> +};
>

TAB0 is 0 so it cannot be detected

> +UNUSED static struct flags termios_oflags_TABDLY[] = {
> +    FLAG_TARGET(TAB0),
> +    FLAG_TARGET(TAB1),
> +    FLAG_TARGET(TAB2),
> +    FLAG_TARGET(TAB3),
> +    FLAG_END,
> +};

VT0 is 0

> +UNUSED static struct flags termios_oflags_VTDLY[] = {
> +    FLAG_TARGET(VT0),
> +    FLAG_TARGET(VT1),
> +    FLAG_END,
> +};

FF0 is 0

> +UNUSED static struct flags termios_oflags_FFDLY[] = {
> +    FLAG_TARGET(FF0),
> +    FLAG_TARGET(FF1),
> +    FLAG_END,
> +};

BS0 is 0

> +UNUSED static struct flags termios_oflags_BSDLY[] = {
> +    FLAG_TARGET(BS0),
> +    FLAG_TARGET(BS1),
> +    FLAG_END,
> +};

ditto: these are not bits but enumerated values (B0 is 0).

> +UNUSED static struct flags termios_cflags_CBAUD[] = {
> +    FLAG_TARGET(B0),
> +    FLAG_TARGET(B50),
> +    FLAG_TARGET(B75),
> +    FLAG_TARGET(B110),
> +    FLAG_TARGET(B134),
> +    FLAG_TARGET(B150),
> +    FLAG_TARGET(B200),
> +    FLAG_TARGET(B300),
> +    FLAG_TARGET(B600),
> +    FLAG_TARGET(B1200),
> +    FLAG_TARGET(B1800),
> +    FLAG_TARGET(B2400),
> +    FLAG_TARGET(B4800),
> +    FLAG_TARGET(B9600),
> +    FLAG_TARGET(B19200),
> +    FLAG_TARGET(B38400),
> +    FLAG_TARGET(B57600),
> +    FLAG_TARGET(B115200),
> +    FLAG_TARGET(B230400),
> +    FLAG_TARGET(B460800),
> +    FLAG_END,
> +};

CS5 is 0

> +UNUSED static struct flags termios_cflags_CSIZE[] = {
> +    FLAG_TARGET(CS5),
> +    FLAG_TARGET(CS6),
> +    FLAG_TARGET(CS7),
> +    FLAG_TARGET(CS8),
> +    FLAG_END,
> +};

These ones are ok:

> +UNUSED static struct flags termios_cflags[] = {
> +    FLAG_TARGET(CSTOPB),
> +    FLAG_TARGET(CREAD),
> +    FLAG_TARGET(PARENB),
> +    FLAG_TARGET(PARODD),
> +    FLAG_TARGET(HUPCL),
> +    FLAG_TARGET(CLOCAL),
> +    FLAG_TARGET(CRTSCTS),
> +    FLAG_END,
> +};

These ones too:

> +UNUSED static struct flags termios_lflags[] = {
> +    FLAG_TARGET(ISIG),
> +    FLAG_TARGET(ICANON),
> +    FLAG_TARGET(XCASE),
> +    FLAG_TARGET(ECHO),
> +    FLAG_TARGET(ECHOE),
> +    FLAG_TARGET(ECHOK),
> +    FLAG_TARGET(ECHONL),
> +    FLAG_TARGET(NOFLSH),
> +    FLAG_TARGET(TOSTOP),
> +    FLAG_TARGET(ECHOCTL),
> +    FLAG_TARGET(ECHOPRT),
> +    FLAG_TARGET(ECHOKE),
> +    FLAG_TARGET(FLUSHO),
> +    FLAG_TARGET(PENDIN),
> +    FLAG_TARGET(IEXTEN),

missing EXTPROC

> +    FLAG_END,
> +};
> +
>  /*
>   * print_xxx utility functions.  These are used to print syscall
>   * parameters in certain format.  All of these have parameter
> @@ -1420,6 +1552,67 @@ print_timezone(abi_ulong tz_addr, int last)
>      }
>  }
>  
> +void
> +print_termios(void *arg)
> +{
> +    const struct target_termios *target = arg;
> +
> +    abi_long iflags = tswap32(target->c_iflag);
> +    abi_long oflags = tswap32(target->c_oflag);
> +    abi_long cflags = tswap32(target->c_cflag);
> +    abi_long lflags = tswap32(target->c_lflag);

You should use target_tcflag_t here, rather than abi_long.
To be able to do that we need some cleanup before:
- define target_tcflag_t, target_cc_t, target_speed_t in a new file
  linux-user/generic/termbits.h
- update all the existing target_termios to use them

> +
> +    qemu_log("{");
> +
> +    qemu_log("c_iflag = ");
> +    print_flags(termios_iflags, iflags, 0);
> +
> +    qemu_log("c_oflag = ");
> +    abi_long oflags_clean =  oflags & ~(TARGET_NLDLY) & ~(TARGET_CRDLY) &
> +                                      ~(TARGET_TABDLY) & ~(TARGET_BSDLY) &
> +                                      ~(TARGET_VTDLY) & ~(TARGET_FFDLY);

I think would simpler to write:

oflags & ~(TARGET_NLDLY | TARGET_CRDLY | TARGET_TABDLY | TARGET_BSDLY |
TARGET_VTDLY | TARGET_FFDLY)

> +    print_flags(termios_oflags, oflags_clean, 0);
> +    if (oflags & TARGET_NLDLY) {

NL0 is 0 so you never display it.

> +        print_flags(termios_oflags_NLDLY, oflags & TARGET_NLDLY, 0);
> +    }
> +    if (oflags & TARGET_CRDLY) {

CR0 is 0, same comment for the following ones.

> +        print_flags(termios_oflags_CRDLY, oflags & TARGET_CRDLY, 0);
> +    }
> +    if (oflags & TARGET_TABDLY) {
> +        print_flags(termios_oflags_TABDLY, oflags & TARGET_TABDLY, 0);
> +    }
> +    if (oflags & TARGET_BSDLY) {
> +        print_flags(termios_oflags_BSDLY, oflags & TARGET_BSDLY, 0);
> +    }
> +    if (oflags & TARGET_VTDLY) {
> +        print_flags(termios_oflags_VTDLY, oflags & TARGET_VTDLY, 0);
> +    }
> +    if (oflags & TARGET_FFDLY) {
> +        print_flags(termios_oflags_FFDLY, oflags & TARGET_FFDLY, 0);
> +    }
> +
> +    qemu_log("c_cflag = ");
> +    if (cflags & TARGET_CBAUD) {
> +        print_flags(termios_cflags_CBAUD, cflags & TARGET_CBAUD, 0);
> +    }
> +    if (cflags & TARGET_CSIZE) {
> +        print_flags(termios_cflags_CSIZE, cflags & TARGET_CSIZE, 0);
> +    }
> +    abi_long cflags_clean = cflags & ~(TARGET_CBAUD) & ~(TARGET_CSIZE);
> +    print_flags(termios_cflags, cflags_clean, 0);
> +
> +    qemu_log("c_lflag = ");
> +    print_flags(termios_lflags, lflags, 0);
> +
> +    qemu_log("c_cc = ");
> +    qemu_log("\"%s\",", target->c_cc);
> +
> +    qemu_log("c_line = ");
> +    print_raw_param("\'%c\'", target->c_line, 1);
> +
> +    qemu_log("}");
> +}
> +
>  #undef UNUSED
>  
>  #ifdef TARGET_NR_accept

Thanks,
Laurent
diff mbox series

Patch

diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h
index 7992475c9f..a5bbb2c733 100644
--- a/include/exec/user/thunk.h
+++ b/include/exec/user/thunk.h
@@ -55,6 +55,7 @@  typedef struct {
     int *field_offsets[2];
     /* special handling */
     void (*convert[2])(void *dst, const void *src);
+    void (*print)(void *arg);
     int size[2];
     int align[2];
     const char *name;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 5c964389c1..e51a0ededb 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -706,6 +706,8 @@  static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
 }
 #endif /* TARGET_ABI_BITS != 32 */
 
+extern void print_termios(void *arg);
+
 /**
  * preexit_cleanup: housekeeping before the guest exits
  *
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 5235b2260c..7b5408cf4a 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1193,6 +1193,138 @@  UNUSED static struct flags falloc_flags[] = {
 #endif
 };
 
+UNUSED static struct flags termios_iflags[] = {
+    FLAG_TARGET(IGNBRK),
+    FLAG_TARGET(BRKINT),
+    FLAG_TARGET(IGNPAR),
+    FLAG_TARGET(PARMRK),
+    FLAG_TARGET(INPCK),
+    FLAG_TARGET(ISTRIP),
+    FLAG_TARGET(INLCR),
+    FLAG_TARGET(IGNCR),
+    FLAG_TARGET(ICRNL),
+    FLAG_TARGET(IUCLC),
+    FLAG_TARGET(IXON),
+    FLAG_TARGET(IXANY),
+    FLAG_TARGET(IXOFF),
+    FLAG_TARGET(IMAXBEL),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_oflags[] = {
+    FLAG_TARGET(OPOST),
+    FLAG_TARGET(OLCUC),
+    FLAG_TARGET(ONLCR),
+    FLAG_TARGET(OCRNL),
+    FLAG_TARGET(ONOCR),
+    FLAG_TARGET(ONLRET),
+    FLAG_TARGET(OFILL),
+    FLAG_TARGET(OFDEL),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_oflags_NLDLY[] = {
+    FLAG_TARGET(NL0),
+    FLAG_TARGET(NL1),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_oflags_CRDLY[] = {
+    FLAG_TARGET(CR0),
+    FLAG_TARGET(CR1),
+    FLAG_TARGET(CR2),
+    FLAG_TARGET(CR3),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_oflags_TABDLY[] = {
+    FLAG_TARGET(TAB0),
+    FLAG_TARGET(TAB1),
+    FLAG_TARGET(TAB2),
+    FLAG_TARGET(TAB3),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_oflags_VTDLY[] = {
+    FLAG_TARGET(VT0),
+    FLAG_TARGET(VT1),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_oflags_FFDLY[] = {
+    FLAG_TARGET(FF0),
+    FLAG_TARGET(FF1),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_oflags_BSDLY[] = {
+    FLAG_TARGET(BS0),
+    FLAG_TARGET(BS1),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_cflags_CBAUD[] = {
+    FLAG_TARGET(B0),
+    FLAG_TARGET(B50),
+    FLAG_TARGET(B75),
+    FLAG_TARGET(B110),
+    FLAG_TARGET(B134),
+    FLAG_TARGET(B150),
+    FLAG_TARGET(B200),
+    FLAG_TARGET(B300),
+    FLAG_TARGET(B600),
+    FLAG_TARGET(B1200),
+    FLAG_TARGET(B1800),
+    FLAG_TARGET(B2400),
+    FLAG_TARGET(B4800),
+    FLAG_TARGET(B9600),
+    FLAG_TARGET(B19200),
+    FLAG_TARGET(B38400),
+    FLAG_TARGET(B57600),
+    FLAG_TARGET(B115200),
+    FLAG_TARGET(B230400),
+    FLAG_TARGET(B460800),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_cflags_CSIZE[] = {
+    FLAG_TARGET(CS5),
+    FLAG_TARGET(CS6),
+    FLAG_TARGET(CS7),
+    FLAG_TARGET(CS8),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_cflags[] = {
+    FLAG_TARGET(CSTOPB),
+    FLAG_TARGET(CREAD),
+    FLAG_TARGET(PARENB),
+    FLAG_TARGET(PARODD),
+    FLAG_TARGET(HUPCL),
+    FLAG_TARGET(CLOCAL),
+    FLAG_TARGET(CRTSCTS),
+    FLAG_END,
+};
+
+UNUSED static struct flags termios_lflags[] = {
+    FLAG_TARGET(ISIG),
+    FLAG_TARGET(ICANON),
+    FLAG_TARGET(XCASE),
+    FLAG_TARGET(ECHO),
+    FLAG_TARGET(ECHOE),
+    FLAG_TARGET(ECHOK),
+    FLAG_TARGET(ECHONL),
+    FLAG_TARGET(NOFLSH),
+    FLAG_TARGET(TOSTOP),
+    FLAG_TARGET(ECHOCTL),
+    FLAG_TARGET(ECHOPRT),
+    FLAG_TARGET(ECHOKE),
+    FLAG_TARGET(FLUSHO),
+    FLAG_TARGET(PENDIN),
+    FLAG_TARGET(IEXTEN),
+    FLAG_END,
+};
+
 /*
  * print_xxx utility functions.  These are used to print syscall
  * parameters in certain format.  All of these have parameter
@@ -1420,6 +1552,67 @@  print_timezone(abi_ulong tz_addr, int last)
     }
 }
 
+void
+print_termios(void *arg)
+{
+    const struct target_termios *target = arg;
+
+    abi_long iflags = tswap32(target->c_iflag);
+    abi_long oflags = tswap32(target->c_oflag);
+    abi_long cflags = tswap32(target->c_cflag);
+    abi_long lflags = tswap32(target->c_lflag);
+
+    qemu_log("{");
+
+    qemu_log("c_iflag = ");
+    print_flags(termios_iflags, iflags, 0);
+
+    qemu_log("c_oflag = ");
+    abi_long oflags_clean =  oflags & ~(TARGET_NLDLY) & ~(TARGET_CRDLY) &
+                                      ~(TARGET_TABDLY) & ~(TARGET_BSDLY) &
+                                      ~(TARGET_VTDLY) & ~(TARGET_FFDLY);
+    print_flags(termios_oflags, oflags_clean, 0);
+    if (oflags & TARGET_NLDLY) {
+        print_flags(termios_oflags_NLDLY, oflags & TARGET_NLDLY, 0);
+    }
+    if (oflags & TARGET_CRDLY) {
+        print_flags(termios_oflags_CRDLY, oflags & TARGET_CRDLY, 0);
+    }
+    if (oflags & TARGET_TABDLY) {
+        print_flags(termios_oflags_TABDLY, oflags & TARGET_TABDLY, 0);
+    }
+    if (oflags & TARGET_BSDLY) {
+        print_flags(termios_oflags_BSDLY, oflags & TARGET_BSDLY, 0);
+    }
+    if (oflags & TARGET_VTDLY) {
+        print_flags(termios_oflags_VTDLY, oflags & TARGET_VTDLY, 0);
+    }
+    if (oflags & TARGET_FFDLY) {
+        print_flags(termios_oflags_FFDLY, oflags & TARGET_FFDLY, 0);
+    }
+
+    qemu_log("c_cflag = ");
+    if (cflags & TARGET_CBAUD) {
+        print_flags(termios_cflags_CBAUD, cflags & TARGET_CBAUD, 0);
+    }
+    if (cflags & TARGET_CSIZE) {
+        print_flags(termios_cflags_CSIZE, cflags & TARGET_CSIZE, 0);
+    }
+    abi_long cflags_clean = cflags & ~(TARGET_CBAUD) & ~(TARGET_CSIZE);
+    print_flags(termios_cflags, cflags_clean, 0);
+
+    qemu_log("c_lflag = ");
+    print_flags(termios_lflags, lflags, 0);
+
+    qemu_log("c_cc = ");
+    qemu_log("\"%s\",", target->c_cc);
+
+    qemu_log("c_line = ");
+    print_raw_param("\'%c\'", target->c_line, 1);
+
+    qemu_log("}");
+}
+
 #undef UNUSED
 
 #ifdef TARGET_NR_accept
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 82afadcea0..0c79011727 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5633,6 +5633,7 @@  static const StructEntry struct_termios_def = {
     .convert = { host_to_target_termios, target_to_host_termios },
     .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
     .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
+    .print = print_termios,
 };
 
 static bitmask_transtbl mmap_flags_tbl[] = {
diff --git a/thunk.c b/thunk.c
index c5d9719747..0718325d86 100644
--- a/thunk.c
+++ b/thunk.c
@@ -404,19 +404,24 @@  const argtype *thunk_print(void *arg, const argtype *type_ptr)
             const int *arg_offsets;
 
             se = struct_entries + *type_ptr++;
-            a = arg;
 
-            field_types = se->field_types;
-            arg_offsets = se->field_offsets[0];
+            if (se->print != NULL) {
+                se->print(arg);
+            } else {
+                a = arg;
 
-            qemu_log("{");
-            for (i = 0; i < se->nb_fields; i++) {
-                if (i > 0) {
-                    qemu_log(",");
+                field_types = se->field_types;
+                arg_offsets = se->field_offsets[0];
+
+                qemu_log("{");
+                for (i = 0; i < se->nb_fields; i++) {
+                    if (i > 0) {
+                        qemu_log(",");
+                    }
+                    field_types = thunk_print(a + arg_offsets[i], field_types);
                 }
-                field_types = thunk_print(a + arg_offsets[i], field_types);
+                qemu_log("}");
             }
-            qemu_log("}");
         }
         break;
     default: