diff mbox series

[12/12] linux-user: Extract target errno related functions to 'target_errno.h'

Message ID 20210704183755.655002-13-f4bug@amsat.org
State New
Headers show
Series linux-user: Extract target errno related functions to 'target_errno.h' | expand

Commit Message

Philippe Mathieu-Daudé July 4, 2021, 6:37 p.m. UTC
Extract target errno related functions to a new 'target_errno.h'
header, so we can do the host <-> target errno conversion out of
the big syscall.c (which is already 13k LoC).

Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 linux-user/target_errno.h |  32 +++++++
 linux-user/syscall.c      | 162 +--------------------------------
 linux-user/target_errno.c | 183 ++++++++++++++++++++++++++++++++++++++
 linux-user/meson.build    |   1 +
 4 files changed, 217 insertions(+), 161 deletions(-)
 create mode 100644 linux-user/target_errno.h
 create mode 100644 linux-user/target_errno.c

Comments

Taylor Simpson July 5, 2021, 10:29 p.m. UTC | #1
> -----Original Message-----
> From: Philippe Mathieu-Daudé <philippe.mathieu.daude@gmail.com> On
> Behalf Of Philippe Mathieu-Daudé
> Sent: Sunday, July 4, 2021 12:38 PM
> To: qemu-devel@nongnu.org
> Cc: Richard Henderson <richard.henderson@linaro.org>; Jiaxun Yang
> <jiaxun.yang@flygoat.com>; Laurent Vivier <laurent@vivier.eu>; Aleksandar
> Rikalo <aleksandar.rikalo@syrmia.com>; Taylor Simpson
> <tsimpson@quicinc.com>; Philippe Mathieu-Daudé <f4bug@amsat.org>;
> Aurelien Jarno <aurelien@aurel32.net>; Helge Deller <deller@gmx.de>
> Subject: [PATCH 12/12] linux-user: Extract target errno related functions to
> 'target_errno.h'
> 
> diff --git a/linux-user/target_errno.h b/linux-user/target_errno.h new file
> mode 100644 index 00000000000..4e5e9d384c9
> --- /dev/null
> +++ b/linux-user/target_errno.h
> @@ -0,0 +1,32 @@
> +
> +void target_to_host_errno_table_init(void);

This is added as static in linux-user/syscall.c in patch 10/12.  But then, removed from syscall.c in this patch and added to linux-user/target_errno.c in this patch.

Is this so that each patch in the series will build?

> diff --git a/linux-user/target_errno.c b/linux-user/target_errno.c new file
> mode 100644 index 00000000000..2a7320d240f
> --- /dev/null
> +++ b/linux-user/target_errno.c
> @@ -0,0 +1,183 @@
> +/*
> + *  Linux syscalls

Copy/paste error?

Could you add a more descriptive comment to this file for posterity?
- How does the default behavior get inherited by targets?
- How does a target override the default behavior?
- A pointer to a target that is overriding the default behavior?


Thanks,
Taylor
Richard Henderson July 7, 2021, 2:08 a.m. UTC | #2
On 7/4/21 11:37 AM, Philippe Mathieu-Daudé wrote:
> Extract target errno related functions to a new 'target_errno.h'
> header, so we can do the host <-> target errno conversion out of
> the big syscall.c (which is already 13k LoC).
> 
> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>   linux-user/target_errno.h |  32 +++++++
>   linux-user/syscall.c      | 162 +--------------------------------
>   linux-user/target_errno.c | 183 ++++++++++++++++++++++++++++++++++++++
>   linux-user/meson.build    |   1 +
>   4 files changed, 217 insertions(+), 161 deletions(-)
>   create mode 100644 linux-user/target_errno.h
>   create mode 100644 linux-user/target_errno.c

I guess this is just data movement, so it's ok.

But...

> +/*
> + * target_to_host_errno_table[] is initialized from
> + * host_to_target_errno_table[] in target_to_host_errno_table_init().
> + */
> +static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
> +};
> +
> +/*
> + * This list is the union of errno values overridden in asm-<arch>/errno.h
> + * minus the errnos that are not actually generic to all archs.
> + */
> +static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
> +    [EAGAIN]            = TARGET_EAGAIN,
> +    [EIDRM]             = TARGET_EIDRM,
> +    [ECHRNG]            = TARGET_ECHRNG,

... there's enough pattern here to make it easy to initialize both of these at 
compile-time.  We just need to move the list out to a .c.inc file.

--%<

E(EAGAIN)
E(EIDRM)
...
#ifdef EFOO
E(EFOO)
#endif

--%<

static const uint16_t target_to_host_errno_table[] = {
#define E(X)  [TARGET_##X] = X,
#include "errnos.c.inc"
#undef E
};

static const uint16_t host_to_target_errno_table[] = {
#define E(X)  [X] = TARGET_##X,
#include "errnos.c.inc"
#undef E
};

> +int host_to_target_errno(int err)
> +{
> +    if (err >= 0 && err < ERRNO_TABLE_SIZE &&
> +        host_to_target_errno_table[err]) {
> +        return host_to_target_errno_table[err];
> +    }
> +    return err;
> +}

Here and

> +int target_to_host_errno(int err)
> +{
> +    if (err >= 0 && err < ERRNO_TABLE_SIZE &&
> +        target_to_host_errno_table[err]) {
> +        return target_to_host_errno_table[err];
> +    }
> +    return err;
> +}

here, we might as well use ARRAY_SIZE(foo) instead of ERRNO_TABLE_SIZE.

Or even convert directly to switches, with no array, and let the compiler decide what it 
thinks is best.  Which might turn out to compile away to the identity function when host 
and guest are both asm-generic.


r~
diff mbox series

Patch

diff --git a/linux-user/target_errno.h b/linux-user/target_errno.h
new file mode 100644
index 00000000000..4e5e9d384c9
--- /dev/null
+++ b/linux-user/target_errno.h
@@ -0,0 +1,32 @@ 
+/*
+ *  Linux syscalls
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef LINUX_USER_TARGET_ERRNO_H
+#define LINUX_USER_TARGET_ERRNO_H
+
+#define ERRNO_TABLE_SIZE 1200
+
+int target_to_host_errno(int err);
+
+void target_to_host_errno_table_init(void);
+
+int host_to_target_errno(int err);
+
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 3761d3b2d64..06c4358b813 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -131,6 +131,7 @@ 
 #include "qemu/selfmap.h"
 #include "user/syscall-trace.h"
 #include "qapi/error.h"
+#include "target_errno.h"
 #include "fd-trans.h"
 #include "tcg/tcg.h"
 
@@ -507,167 +508,6 @@  static inline int next_free_host_timer(void)
 }
 #endif
 
-#define ERRNO_TABLE_SIZE 1200
-
-/*
- * target_to_host_errno_table[] is initialized from
- * host_to_target_errno_table[] in target_to_host_errno_table_init().
- */
-static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
-};
-
-/*
- * This list is the union of errno values overridden in asm-<arch>/errno.h
- * minus the errnos that are not actually generic to all archs.
- */
-static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
-    [EAGAIN]            = TARGET_EAGAIN,
-    [EIDRM]             = TARGET_EIDRM,
-    [ECHRNG]            = TARGET_ECHRNG,
-    [EL2NSYNC]          = TARGET_EL2NSYNC,
-    [EL3HLT]            = TARGET_EL3HLT,
-    [EL3RST]            = TARGET_EL3RST,
-    [ELNRNG]            = TARGET_ELNRNG,
-    [EUNATCH]           = TARGET_EUNATCH,
-    [ENOCSI]            = TARGET_ENOCSI,
-    [EL2HLT]            = TARGET_EL2HLT,
-    [EDEADLK]           = TARGET_EDEADLK,
-    [ENOLCK]            = TARGET_ENOLCK,
-    [EBADE]             = TARGET_EBADE,
-    [EBADR]             = TARGET_EBADR,
-    [EXFULL]            = TARGET_EXFULL,
-    [ENOANO]            = TARGET_ENOANO,
-    [EBADRQC]           = TARGET_EBADRQC,
-    [EBADSLT]           = TARGET_EBADSLT,
-    [EBFONT]            = TARGET_EBFONT,
-    [ENOSTR]            = TARGET_ENOSTR,
-    [ENODATA]           = TARGET_ENODATA,
-    [ETIME]             = TARGET_ETIME,
-    [ENOSR]             = TARGET_ENOSR,
-    [ENONET]            = TARGET_ENONET,
-    [ENOPKG]            = TARGET_ENOPKG,
-    [EREMOTE]           = TARGET_EREMOTE,
-    [ENOLINK]           = TARGET_ENOLINK,
-    [EADV]              = TARGET_EADV,
-    [ESRMNT]            = TARGET_ESRMNT,
-    [ECOMM]             = TARGET_ECOMM,
-    [EPROTO]            = TARGET_EPROTO,
-    [EDOTDOT]           = TARGET_EDOTDOT,
-    [EMULTIHOP]         = TARGET_EMULTIHOP,
-    [EBADMSG]           = TARGET_EBADMSG,
-    [ENAMETOOLONG]      = TARGET_ENAMETOOLONG,
-    [EOVERFLOW]         = TARGET_EOVERFLOW,
-    [ENOTUNIQ]          = TARGET_ENOTUNIQ,
-    [EBADFD]            = TARGET_EBADFD,
-    [EREMCHG]           = TARGET_EREMCHG,
-    [ELIBACC]           = TARGET_ELIBACC,
-    [ELIBBAD]           = TARGET_ELIBBAD,
-    [ELIBSCN]           = TARGET_ELIBSCN,
-    [ELIBMAX]           = TARGET_ELIBMAX,
-    [ELIBEXEC]          = TARGET_ELIBEXEC,
-    [EILSEQ]            = TARGET_EILSEQ,
-    [ENOSYS]            = TARGET_ENOSYS,
-    [ELOOP]             = TARGET_ELOOP,
-    [ERESTART]          = TARGET_ERESTART,
-    [ESTRPIPE]          = TARGET_ESTRPIPE,
-    [ENOTEMPTY]         = TARGET_ENOTEMPTY,
-    [EUSERS]            = TARGET_EUSERS,
-    [ENOTSOCK]          = TARGET_ENOTSOCK,
-    [EDESTADDRREQ]      = TARGET_EDESTADDRREQ,
-    [EMSGSIZE]          = TARGET_EMSGSIZE,
-    [EPROTOTYPE]        = TARGET_EPROTOTYPE,
-    [ENOPROTOOPT]       = TARGET_ENOPROTOOPT,
-    [EPROTONOSUPPORT]   = TARGET_EPROTONOSUPPORT,
-    [ESOCKTNOSUPPORT]   = TARGET_ESOCKTNOSUPPORT,
-    [EOPNOTSUPP]        = TARGET_EOPNOTSUPP,
-    [EPFNOSUPPORT]      = TARGET_EPFNOSUPPORT,
-    [EAFNOSUPPORT]      = TARGET_EAFNOSUPPORT,
-    [EADDRINUSE]        = TARGET_EADDRINUSE,
-    [EADDRNOTAVAIL]     = TARGET_EADDRNOTAVAIL,
-    [ENETDOWN]          = TARGET_ENETDOWN,
-    [ENETUNREACH]       = TARGET_ENETUNREACH,
-    [ENETRESET]         = TARGET_ENETRESET,
-    [ECONNABORTED]      = TARGET_ECONNABORTED,
-    [ECONNRESET]        = TARGET_ECONNRESET,
-    [ENOBUFS]           = TARGET_ENOBUFS,
-    [EISCONN]           = TARGET_EISCONN,
-    [ENOTCONN]          = TARGET_ENOTCONN,
-    [EUCLEAN]           = TARGET_EUCLEAN,
-    [ENOTNAM]           = TARGET_ENOTNAM,
-    [ENAVAIL]           = TARGET_ENAVAIL,
-    [EISNAM]            = TARGET_EISNAM,
-    [EREMOTEIO]         = TARGET_EREMOTEIO,
-    [EDQUOT]            = TARGET_EDQUOT,
-    [ESHUTDOWN]         = TARGET_ESHUTDOWN,
-    [ETOOMANYREFS]      = TARGET_ETOOMANYREFS,
-    [ETIMEDOUT]         = TARGET_ETIMEDOUT,
-    [ECONNREFUSED]      = TARGET_ECONNREFUSED,
-    [EHOSTDOWN]         = TARGET_EHOSTDOWN,
-    [EHOSTUNREACH]      = TARGET_EHOSTUNREACH,
-    [EALREADY]          = TARGET_EALREADY,
-    [EINPROGRESS]       = TARGET_EINPROGRESS,
-    [ESTALE]            = TARGET_ESTALE,
-    [ECANCELED]         = TARGET_ECANCELED,
-    [ENOMEDIUM]         = TARGET_ENOMEDIUM,
-    [EMEDIUMTYPE]       = TARGET_EMEDIUMTYPE,
-#ifdef ENOKEY
-    [ENOKEY]            = TARGET_ENOKEY,
-#endif
-#ifdef EKEYEXPIRED
-    [EKEYEXPIRED]       = TARGET_EKEYEXPIRED,
-#endif
-#ifdef EKEYREVOKED
-    [EKEYREVOKED]       = TARGET_EKEYREVOKED,
-#endif
-#ifdef EKEYREJECTED
-    [EKEYREJECTED]      = TARGET_EKEYREJECTED,
-#endif
-#ifdef EOWNERDEAD
-    [EOWNERDEAD]        = TARGET_EOWNERDEAD,
-#endif
-#ifdef ENOTRECOVERABLE
-    [ENOTRECOVERABLE]   = TARGET_ENOTRECOVERABLE,
-#endif
-#ifdef ENOMSG
-    [ENOMSG]            = TARGET_ENOMSG,
-#endif
-#ifdef ERKFILL
-    [ERFKILL]           = TARGET_ERFKILL,
-#endif
-#ifdef EHWPOISON
-    [EHWPOISON]         = TARGET_EHWPOISON,
-#endif
-};
-
-static void target_to_host_errno_table_init(void)
-{
-    /*
-     * Build target_to_host_errno_table[] table
-     * from host_to_target_errno_table[].
-     */
-    for (int i = 0; i < ERRNO_TABLE_SIZE; i++) {
-        target_to_host_errno_table[host_to_target_errno_table[i]] = i;
-    }
-}
-
-static inline int host_to_target_errno(int err)
-{
-    if (err >= 0 && err < ERRNO_TABLE_SIZE &&
-        host_to_target_errno_table[err]) {
-        return host_to_target_errno_table[err];
-    }
-    return err;
-}
-
-static inline int target_to_host_errno(int err)
-{
-    if (err >= 0 && err < ERRNO_TABLE_SIZE &&
-        target_to_host_errno_table[err]) {
-        return target_to_host_errno_table[err];
-    }
-    return err;
-}
-
 static inline abi_long get_errno(abi_long ret)
 {
     if (ret == -1)
diff --git a/linux-user/target_errno.c b/linux-user/target_errno.c
new file mode 100644
index 00000000000..2a7320d240f
--- /dev/null
+++ b/linux-user/target_errno.c
@@ -0,0 +1,183 @@ 
+/*
+ *  Linux syscalls
+ *
+ *  Copyright (c) 2003 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "target_errno.h"
+#include "errno_defs.h"
+
+/*
+ * target_to_host_errno_table[] is initialized from
+ * host_to_target_errno_table[] in target_to_host_errno_table_init().
+ */
+static uint16_t target_to_host_errno_table[ERRNO_TABLE_SIZE] = {
+};
+
+/*
+ * This list is the union of errno values overridden in asm-<arch>/errno.h
+ * minus the errnos that are not actually generic to all archs.
+ */
+static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
+    [EAGAIN]            = TARGET_EAGAIN,
+    [EIDRM]             = TARGET_EIDRM,
+    [ECHRNG]            = TARGET_ECHRNG,
+    [EL2NSYNC]          = TARGET_EL2NSYNC,
+    [EL3HLT]            = TARGET_EL3HLT,
+    [EL3RST]            = TARGET_EL3RST,
+    [ELNRNG]            = TARGET_ELNRNG,
+    [EUNATCH]           = TARGET_EUNATCH,
+    [ENOCSI]            = TARGET_ENOCSI,
+    [EL2HLT]            = TARGET_EL2HLT,
+    [EDEADLK]           = TARGET_EDEADLK,
+    [ENOLCK]            = TARGET_ENOLCK,
+    [EBADE]             = TARGET_EBADE,
+    [EBADR]             = TARGET_EBADR,
+    [EXFULL]            = TARGET_EXFULL,
+    [ENOANO]            = TARGET_ENOANO,
+    [EBADRQC]           = TARGET_EBADRQC,
+    [EBADSLT]           = TARGET_EBADSLT,
+    [EBFONT]            = TARGET_EBFONT,
+    [ENOSTR]            = TARGET_ENOSTR,
+    [ENODATA]           = TARGET_ENODATA,
+    [ETIME]             = TARGET_ETIME,
+    [ENOSR]             = TARGET_ENOSR,
+    [ENONET]            = TARGET_ENONET,
+    [ENOPKG]            = TARGET_ENOPKG,
+    [EREMOTE]           = TARGET_EREMOTE,
+    [ENOLINK]           = TARGET_ENOLINK,
+    [EADV]              = TARGET_EADV,
+    [ESRMNT]            = TARGET_ESRMNT,
+    [ECOMM]             = TARGET_ECOMM,
+    [EPROTO]            = TARGET_EPROTO,
+    [EDOTDOT]           = TARGET_EDOTDOT,
+    [EMULTIHOP]         = TARGET_EMULTIHOP,
+    [EBADMSG]           = TARGET_EBADMSG,
+    [ENAMETOOLONG]      = TARGET_ENAMETOOLONG,
+    [EOVERFLOW]         = TARGET_EOVERFLOW,
+    [ENOTUNIQ]          = TARGET_ENOTUNIQ,
+    [EBADFD]            = TARGET_EBADFD,
+    [EREMCHG]           = TARGET_EREMCHG,
+    [ELIBACC]           = TARGET_ELIBACC,
+    [ELIBBAD]           = TARGET_ELIBBAD,
+    [ELIBSCN]           = TARGET_ELIBSCN,
+    [ELIBMAX]           = TARGET_ELIBMAX,
+    [ELIBEXEC]          = TARGET_ELIBEXEC,
+    [EILSEQ]            = TARGET_EILSEQ,
+    [ENOSYS]            = TARGET_ENOSYS,
+    [ELOOP]             = TARGET_ELOOP,
+    [ERESTART]          = TARGET_ERESTART,
+    [ESTRPIPE]          = TARGET_ESTRPIPE,
+    [ENOTEMPTY]         = TARGET_ENOTEMPTY,
+    [EUSERS]            = TARGET_EUSERS,
+    [ENOTSOCK]          = TARGET_ENOTSOCK,
+    [EDESTADDRREQ]      = TARGET_EDESTADDRREQ,
+    [EMSGSIZE]          = TARGET_EMSGSIZE,
+    [EPROTOTYPE]        = TARGET_EPROTOTYPE,
+    [ENOPROTOOPT]       = TARGET_ENOPROTOOPT,
+    [EPROTONOSUPPORT]   = TARGET_EPROTONOSUPPORT,
+    [ESOCKTNOSUPPORT]   = TARGET_ESOCKTNOSUPPORT,
+    [EOPNOTSUPP]        = TARGET_EOPNOTSUPP,
+    [EPFNOSUPPORT]      = TARGET_EPFNOSUPPORT,
+    [EAFNOSUPPORT]      = TARGET_EAFNOSUPPORT,
+    [EADDRINUSE]        = TARGET_EADDRINUSE,
+    [EADDRNOTAVAIL]     = TARGET_EADDRNOTAVAIL,
+    [ENETDOWN]          = TARGET_ENETDOWN,
+    [ENETUNREACH]       = TARGET_ENETUNREACH,
+    [ENETRESET]         = TARGET_ENETRESET,
+    [ECONNABORTED]      = TARGET_ECONNABORTED,
+    [ECONNRESET]        = TARGET_ECONNRESET,
+    [ENOBUFS]           = TARGET_ENOBUFS,
+    [EISCONN]           = TARGET_EISCONN,
+    [ENOTCONN]          = TARGET_ENOTCONN,
+    [EUCLEAN]           = TARGET_EUCLEAN,
+    [ENOTNAM]           = TARGET_ENOTNAM,
+    [ENAVAIL]           = TARGET_ENAVAIL,
+    [EISNAM]            = TARGET_EISNAM,
+    [EREMOTEIO]         = TARGET_EREMOTEIO,
+    [EDQUOT]            = TARGET_EDQUOT,
+    [ESHUTDOWN]         = TARGET_ESHUTDOWN,
+    [ETOOMANYREFS]      = TARGET_ETOOMANYREFS,
+    [ETIMEDOUT]         = TARGET_ETIMEDOUT,
+    [ECONNREFUSED]      = TARGET_ECONNREFUSED,
+    [EHOSTDOWN]         = TARGET_EHOSTDOWN,
+    [EHOSTUNREACH]      = TARGET_EHOSTUNREACH,
+    [EALREADY]          = TARGET_EALREADY,
+    [EINPROGRESS]       = TARGET_EINPROGRESS,
+    [ESTALE]            = TARGET_ESTALE,
+    [ECANCELED]         = TARGET_ECANCELED,
+    [ENOMEDIUM]         = TARGET_ENOMEDIUM,
+    [EMEDIUMTYPE]       = TARGET_EMEDIUMTYPE,
+#ifdef ENOKEY
+    [ENOKEY]            = TARGET_ENOKEY,
+#endif
+#ifdef EKEYEXPIRED
+    [EKEYEXPIRED]       = TARGET_EKEYEXPIRED,
+#endif
+#ifdef EKEYREVOKED
+    [EKEYREVOKED]       = TARGET_EKEYREVOKED,
+#endif
+#ifdef EKEYREJECTED
+    [EKEYREJECTED]      = TARGET_EKEYREJECTED,
+#endif
+#ifdef EOWNERDEAD
+    [EOWNERDEAD]        = TARGET_EOWNERDEAD,
+#endif
+#ifdef ENOTRECOVERABLE
+    [ENOTRECOVERABLE]   = TARGET_ENOTRECOVERABLE,
+#endif
+#ifdef ENOMSG
+    [ENOMSG]            = TARGET_ENOMSG,
+#endif
+#ifdef ERKFILL
+    [ERFKILL]           = TARGET_ERFKILL,
+#endif
+#ifdef EHWPOISON
+    [EHWPOISON]         = TARGET_EHWPOISON,
+#endif
+};
+
+void target_to_host_errno_table_init(void)
+{
+    /*
+     * Build target_to_host_errno_table[] table
+     * from host_to_target_errno_table[].
+     */
+    for (int i = 0; i < ERRNO_TABLE_SIZE; i++) {
+        target_to_host_errno_table[host_to_target_errno_table[i]] = i;
+    }
+}
+
+int host_to_target_errno(int err)
+{
+    if (err >= 0 && err < ERRNO_TABLE_SIZE &&
+        host_to_target_errno_table[err]) {
+        return host_to_target_errno_table[err];
+    }
+    return err;
+}
+
+int target_to_host_errno(int err)
+{
+    if (err >= 0 && err < ERRNO_TABLE_SIZE &&
+        target_to_host_errno_table[err]) {
+        return target_to_host_errno_table[err];
+    }
+    return err;
+}
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 9549f81682d..f757b63310b 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -9,6 +9,7 @@ 
   'signal.c',
   'strace.c',
   'syscall.c',
+  'target_errno.c',
   'uaccess.c',
   'uname.c',
 ))