diff mbox series

[3/4] target/mips: Rewrite UHI errno_mips() using GHashTable

Message ID 20210704170736.617895-4-f4bug@amsat.org
State New
Headers show
Series target/mips: Rewrite UHI errno_mips() to allow building on Haiku OS | expand

Commit Message

Philippe Mathieu-Daudé July 4, 2021, 5:07 p.m. UTC
Linking on Haiku OS fails:

  /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
  error: libqemu-mips-softmmu.fa.p/target_mips_tcg_sysemu_mips-semi.c.o(.rodata) is too large (0xffff405a bytes)
  /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
  final link failed: memory exhausted
  collect2: error: ld returned 1 exit status

This is because the host_to_mips_errno[] uses errno as index,
for example:

  static const uint16_t host_to_mips_errno[] = {
      [ENAMETOOLONG] = 91,
      ...

and Haiku defines [*] ENAMETOOLONG as:

   12 /* Error baselines */
   13 #define B_GENERAL_ERROR_BASE              INT_MIN
   ..
   22 #define B_STORAGE_ERROR_BASE              (B_GENERAL_ERROR_BASE + 0x6000)
  ...
  106 #define B_NAME_TOO_LONG                   (B_STORAGE_ERROR_BASE + 4)
  ...
  211 #define ENAMETOOLONG                      B_TO_POSIX_ERROR(B_NAME_TOO_LONG)

so the array ends up beeing indeed too big.

Since POSIX errno can't be use as indexes on Haiku,
rewrite errno_mips() using a GHashTable.

[*] https://github.com/haiku/haiku/blob/r1beta3/headers/os/support/Errors.h#L130

Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 target/mips/tcg/sysemu/mips-semi.c | 62 ++++++++++++++++++++++--------
 1 file changed, 45 insertions(+), 17 deletions(-)

Comments

Peter Maydell July 4, 2021, 5:25 p.m. UTC | #1
On Sun, 4 Jul 2021 at 18:07, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> Linking on Haiku OS fails:
>
>   /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
>   error: libqemu-mips-softmmu.fa.p/target_mips_tcg_sysemu_mips-semi.c.o(.rodata) is too large (0xffff405a bytes)
>   /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
>   final link failed: memory exhausted
>   collect2: error: ld returned 1 exit status
>
> This is because the host_to_mips_errno[] uses errno as index,
> for example:
>
>   static const uint16_t host_to_mips_errno[] = {
>       [ENAMETOOLONG] = 91,
>       ...
>
> and Haiku defines [*] ENAMETOOLONG as:
>
>    12 /* Error baselines */
>    13 #define B_GENERAL_ERROR_BASE              INT_MIN
>    ..
>    22 #define B_STORAGE_ERROR_BASE              (B_GENERAL_ERROR_BASE + 0x6000)
>   ...
>   106 #define B_NAME_TOO_LONG                   (B_STORAGE_ERROR_BASE + 4)
>   ...
>   211 #define ENAMETOOLONG                      B_TO_POSIX_ERROR(B_NAME_TOO_LONG)
>
> so the array ends up beeing indeed too big.
>
> Since POSIX errno can't be use as indexes on Haiku,
> rewrite errno_mips() using a GHashTable.
>
> [*] https://github.com/haiku/haiku/blob/r1beta3/headers/os/support/Errors.h#L130
>
> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>  target/mips/tcg/sysemu/mips-semi.c | 62 ++++++++++++++++++++++--------
>  1 file changed, 45 insertions(+), 17 deletions(-)

>  static int errno_mips(int host_errno)
>  {
> -    if (host_errno < 0 || host_errno >= ARRAY_SIZE(host_to_mips_errno)) {
> -        return EINVAL;
> -    } else if (host_to_mips_errno[host_errno]) {
> -        return host_to_mips_errno[host_errno];
> -    } else {
> -        return host_errno;
> +    gpointer uhi_errno;
> +
> +    if (uhi_errno_hash_table == NULL) {
> +        uhi_errno_init();
>      }
> +
> +    if (host_errno == 0) {
> +        return 0;
> +    }
> +    if (g_hash_table_lookup_extended(uhi_errno_hash_table,
> +                                     GINT_TO_POINTER(host_errno),
> +                                     NULL, &uhi_errno)) {
> +        return GPOINTER_TO_INT(uhi_errno);
> +    }
> +    return EINVAL; /* Not reachable per the specification */

Per whose specification? This function is passed the errno as set
by various host OS functions like open(), lseek(), read(). POSIX allows
those functions to set errno to any value, so this "we don't know
a guest errno value for that" code is definitely reachable.

thanks
-- PMM
Philippe Mathieu-Daudé July 4, 2021, 6:25 p.m. UTC | #2
On 7/4/21 7:25 PM, Peter Maydell wrote:
> On Sun, 4 Jul 2021 at 18:07, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>
>> Linking on Haiku OS fails:
>>
>>   /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
>>   error: libqemu-mips-softmmu.fa.p/target_mips_tcg_sysemu_mips-semi.c.o(.rodata) is too large (0xffff405a bytes)
>>   /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
>>   final link failed: memory exhausted
>>   collect2: error: ld returned 1 exit status
>>
>> This is because the host_to_mips_errno[] uses errno as index,
>> for example:
>>
>>   static const uint16_t host_to_mips_errno[] = {
>>       [ENAMETOOLONG] = 91,
>>       ...
>>
>> and Haiku defines [*] ENAMETOOLONG as:
>>
>>    12 /* Error baselines */
>>    13 #define B_GENERAL_ERROR_BASE              INT_MIN
>>    ..
>>    22 #define B_STORAGE_ERROR_BASE              (B_GENERAL_ERROR_BASE + 0x6000)
>>   ...
>>   106 #define B_NAME_TOO_LONG                   (B_STORAGE_ERROR_BASE + 4)
>>   ...
>>   211 #define ENAMETOOLONG                      B_TO_POSIX_ERROR(B_NAME_TOO_LONG)
>>
>> so the array ends up beeing indeed too big.
>>
>> Since POSIX errno can't be use as indexes on Haiku,
>> rewrite errno_mips() using a GHashTable.
>>
>> [*] https://github.com/haiku/haiku/blob/r1beta3/headers/os/support/Errors.h#L130
>>
>> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>> ---
>>  target/mips/tcg/sysemu/mips-semi.c | 62 ++++++++++++++++++++++--------
>>  1 file changed, 45 insertions(+), 17 deletions(-)
> 
>>  static int errno_mips(int host_errno)
>>  {
>> -    if (host_errno < 0 || host_errno >= ARRAY_SIZE(host_to_mips_errno)) {
>> -        return EINVAL;
>> -    } else if (host_to_mips_errno[host_errno]) {
>> -        return host_to_mips_errno[host_errno];
>> -    } else {
>> -        return host_errno;
>> +    gpointer uhi_errno;
>> +
>> +    if (uhi_errno_hash_table == NULL) {
>> +        uhi_errno_init();
>>      }
>> +
>> +    if (host_errno == 0) {
>> +        return 0;
>> +    }
>> +    if (g_hash_table_lookup_extended(uhi_errno_hash_table,
>> +                                     GINT_TO_POINTER(host_errno),
>> +                                     NULL, &uhi_errno)) {
>> +        return GPOINTER_TO_INT(uhi_errno);
>> +    }
>> +    return EINVAL; /* Not reachable per the specification */
> 
> Per whose specification? This function is passed the errno as set
> by various host OS functions like open(), lseek(), read(). POSIX allows
> those functions to set errno to any value, so this "we don't know
> a guest errno value for that" code is definitely reachable.

You are right, it is reachable. What I meant is other errnos are
not expected, and returning EINVAL for them doesn't seem ideal,
but the spec doesn't define a particular errno for unsupported
errnos. I'll reword as "Unsupported errno is not specified, use EINVAL".
Thomas Huth July 4, 2021, 6:38 p.m. UTC | #3
On 04/07/2021 19.07, Philippe Mathieu-Daudé wrote:
> Linking on Haiku OS fails:
> 
>    /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
>    error: libqemu-mips-softmmu.fa.p/target_mips_tcg_sysemu_mips-semi.c.o(.rodata) is too large (0xffff405a bytes)
>    /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
>    final link failed: memory exhausted
>    collect2: error: ld returned 1 exit status
> 
> This is because the host_to_mips_errno[] uses errno as index,
> for example:
> 
>    static const uint16_t host_to_mips_errno[] = {
>        [ENAMETOOLONG] = 91,
>        ...
> 
> and Haiku defines [*] ENAMETOOLONG as:
> 
>     12 /* Error baselines */
>     13 #define B_GENERAL_ERROR_BASE              INT_MIN
>     ..
>     22 #define B_STORAGE_ERROR_BASE              (B_GENERAL_ERROR_BASE + 0x6000)
>    ...
>    106 #define B_NAME_TOO_LONG                   (B_STORAGE_ERROR_BASE + 4)
>    ...
>    211 #define ENAMETOOLONG                      B_TO_POSIX_ERROR(B_NAME_TOO_LONG)
> 
> so the array ends up beeing indeed too big.
> 
> Since POSIX errno can't be use as indexes on Haiku,
> rewrite errno_mips() using a GHashTable.
> 
> [*] https://github.com/haiku/haiku/blob/r1beta3/headers/os/support/Errors.h#L130
> 
> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>   target/mips/tcg/sysemu/mips-semi.c | 62 ++++++++++++++++++++++--------
>   1 file changed, 45 insertions(+), 17 deletions(-)
> 
> diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
> index 4c924273c1b..3e91c9eb76c 100644
> --- a/target/mips/tcg/sysemu/mips-semi.c
> +++ b/target/mips/tcg/sysemu/mips-semi.c
> @@ -4,6 +4,7 @@
>    * Specifications: MD01069 Reference Manual (rev 1.1.6, 06 Jul 2015)
>    *
>    * Copyright (c) 2015 Imagination Technologies
> + * Copyright (c) 2021 Philippe Mathieu-Daudé
>    *
>    * This library is free software; you can redistribute it and/or
>    * modify it under the terms of the GNU Lesser General Public
> @@ -76,29 +77,56 @@ enum UHIOpenFlags {
>       UHIOpen_EXCL   = 0x800
>   };
>   
> -/*
> - * Unified Hosting Interface (rev 1.1.6)
> - * Appendix A. "Error values"
> - */
> -static const uint16_t host_to_mips_errno[] = {
> -    [ENAMETOOLONG] = 91,
> -#ifdef EOVERFLOW
> -    [EOVERFLOW]    = 139,
> -#endif
> +static GHashTable *uhi_errno_hash_table;
> +
> +static void uhi_errno_insert(int host_errno, int uhi_errno)
> +{
> +    gboolean ret = TRUE;
> +
> +    assert(uhi_errno_hash_table != NULL);
> +    ret = g_hash_table_insert(uhi_errno_hash_table,
> +                              GINT_TO_POINTER(host_errno),
> +                              GINT_TO_POINTER(uhi_errno));
> +    assert(ret == TRUE);
> +}
> +
> +static void uhi_errno_init(void)
> +{
> +    gboolean ret = TRUE;
> +
> +    uhi_errno_hash_table = g_hash_table_new(NULL, NULL);
> +
> +    /*
> +     * Unified Hosting Interface (rev 1.1.6)
> +     * Appendix A. "Error values"
> +     */
> +    uhi_errno_insert(ENAMETOOLONG,  91);
>   #ifdef ELOOP
> -    [ELOOP]        = 92,
> +    uhi_errno_insert(ELOOP,         92);
>   #endif
> -};
> +#ifdef EOVERFLOW
> +    uhi_errno_insert(EOVERFLOW,     139);
> +#endif
> +    assert(ret == TRUE);
> +}
>   
>   static int errno_mips(int host_errno)
>   {
> -    if (host_errno < 0 || host_errno >= ARRAY_SIZE(host_to_mips_errno)) {
> -        return EINVAL;
> -    } else if (host_to_mips_errno[host_errno]) {
> -        return host_to_mips_errno[host_errno];
> -    } else {
> -        return host_errno;
> +    gpointer uhi_errno;
> +
> +    if (uhi_errno_hash_table == NULL) {
> +        uhi_errno_init();
>       }
> +
> +    if (host_errno == 0) {
> +        return 0;
> +    }
> +    if (g_hash_table_lookup_extended(uhi_errno_hash_table,
> +                                     GINT_TO_POINTER(host_errno),
> +                                     NULL, &uhi_errno)) {
> +        return GPOINTER_TO_INT(uhi_errno);
> +    }
> +    return EINVAL; /* Not reachable per the specification */
>   }

Why not simply use a switch-case statement instead? ... that's simpler and 
still allows to compiler to optimize if the errno values are in a compact range.

  Thomas
Philippe Mathieu-Daudé July 4, 2021, 6:44 p.m. UTC | #4
On 7/4/21 8:38 PM, Thomas Huth wrote:
> On 04/07/2021 19.07, Philippe Mathieu-Daudé wrote:
>> Linking on Haiku OS fails:
>>
>>   
>> /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
>>
>>    error:
>> libqemu-mips-softmmu.fa.p/target_mips_tcg_sysemu_mips-semi.c.o(.rodata) is
>> too large (0xffff405a bytes)
>>   
>> /boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/8.3.0/../../../../x86_64-unknown-haiku/bin/ld:
>>
>>    final link failed: memory exhausted
>>    collect2: error: ld returned 1 exit status
>>
>> This is because the host_to_mips_errno[] uses errno as index,
>> for example:
>>
>>    static const uint16_t host_to_mips_errno[] = {
>>        [ENAMETOOLONG] = 91,
>>        ...
>>
>> and Haiku defines [*] ENAMETOOLONG as:
>>
>>     12 /* Error baselines */
>>     13 #define B_GENERAL_ERROR_BASE              INT_MIN
>>     ..
>>     22 #define B_STORAGE_ERROR_BASE              (B_GENERAL_ERROR_BASE
>> + 0x6000)
>>    ...
>>    106 #define B_NAME_TOO_LONG                   (B_STORAGE_ERROR_BASE
>> + 4)
>>    ...
>>    211 #define ENAMETOOLONG                     
>> B_TO_POSIX_ERROR(B_NAME_TOO_LONG)
>>
>> so the array ends up beeing indeed too big.
>>
>> Since POSIX errno can't be use as indexes on Haiku,
>> rewrite errno_mips() using a GHashTable.
>>
>> [*]
>> https://github.com/haiku/haiku/blob/r1beta3/headers/os/support/Errors.h#L130
>>
>>
>> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>> ---
>>   target/mips/tcg/sysemu/mips-semi.c | 62 ++++++++++++++++++++++--------
>>   1 file changed, 45 insertions(+), 17 deletions(-)

>> +static void uhi_errno_init(void)
>> +{
>> +    gboolean ret = TRUE;
>> +
>> +    uhi_errno_hash_table = g_hash_table_new(NULL, NULL);
>> +
>> +    /*
>> +     * Unified Hosting Interface (rev 1.1.6)
>> +     * Appendix A. "Error values"
>> +     */
>> +    uhi_errno_insert(ENAMETOOLONG,  91);
>>   #ifdef ELOOP
>> -    [ELOOP]        = 92,
>> +    uhi_errno_insert(ELOOP,         92);
>>   #endif
>> -};
>> +#ifdef EOVERFLOW
>> +    uhi_errno_insert(EOVERFLOW,     139);
>> +#endif
>> +    assert(ret == TRUE);
>> +}
>>     static int errno_mips(int host_errno)
>>   {
>> -    if (host_errno < 0 || host_errno >=
>> ARRAY_SIZE(host_to_mips_errno)) {
>> -        return EINVAL;
>> -    } else if (host_to_mips_errno[host_errno]) {
>> -        return host_to_mips_errno[host_errno];
>> -    } else {
>> -        return host_errno;
>> +    gpointer uhi_errno;
>> +
>> +    if (uhi_errno_hash_table == NULL) {
>> +        uhi_errno_init();
>>       }
>> +
>> +    if (host_errno == 0) {
>> +        return 0;
>> +    }
>> +    if (g_hash_table_lookup_extended(uhi_errno_hash_table,
>> +                                     GINT_TO_POINTER(host_errno),
>> +                                     NULL, &uhi_errno)) {
>> +        return GPOINTER_TO_INT(uhi_errno);
>> +    }
>> +    return EINVAL; /* Not reachable per the specification */
>>   }
> 
> Why not simply use a switch-case statement instead? ... that's simpler
> and still allows to compiler to optimize if the errno values are in a
> compact range.

I was expecting the #ifdef'ry to be ugly, but there isn't that many
actually. Sigh :(
diff mbox series

Patch

diff --git a/target/mips/tcg/sysemu/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c
index 4c924273c1b..3e91c9eb76c 100644
--- a/target/mips/tcg/sysemu/mips-semi.c
+++ b/target/mips/tcg/sysemu/mips-semi.c
@@ -4,6 +4,7 @@ 
  * Specifications: MD01069 Reference Manual (rev 1.1.6, 06 Jul 2015)
  *
  * Copyright (c) 2015 Imagination Technologies
+ * Copyright (c) 2021 Philippe Mathieu-Daudé
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -76,29 +77,56 @@  enum UHIOpenFlags {
     UHIOpen_EXCL   = 0x800
 };
 
-/*
- * Unified Hosting Interface (rev 1.1.6)
- * Appendix A. "Error values"
- */
-static const uint16_t host_to_mips_errno[] = {
-    [ENAMETOOLONG] = 91,
-#ifdef EOVERFLOW
-    [EOVERFLOW]    = 139,
-#endif
+static GHashTable *uhi_errno_hash_table;
+
+static void uhi_errno_insert(int host_errno, int uhi_errno)
+{
+    gboolean ret = TRUE;
+
+    assert(uhi_errno_hash_table != NULL);
+    ret = g_hash_table_insert(uhi_errno_hash_table,
+                              GINT_TO_POINTER(host_errno),
+                              GINT_TO_POINTER(uhi_errno));
+    assert(ret == TRUE);
+}
+
+static void uhi_errno_init(void)
+{
+    gboolean ret = TRUE;
+
+    uhi_errno_hash_table = g_hash_table_new(NULL, NULL);
+
+    /*
+     * Unified Hosting Interface (rev 1.1.6)
+     * Appendix A. "Error values"
+     */
+    uhi_errno_insert(ENAMETOOLONG,  91);
 #ifdef ELOOP
-    [ELOOP]        = 92,
+    uhi_errno_insert(ELOOP,         92);
 #endif
-};
+#ifdef EOVERFLOW
+    uhi_errno_insert(EOVERFLOW,     139);
+#endif
+    assert(ret == TRUE);
+}
 
 static int errno_mips(int host_errno)
 {
-    if (host_errno < 0 || host_errno >= ARRAY_SIZE(host_to_mips_errno)) {
-        return EINVAL;
-    } else if (host_to_mips_errno[host_errno]) {
-        return host_to_mips_errno[host_errno];
-    } else {
-        return host_errno;
+    gpointer uhi_errno;
+
+    if (uhi_errno_hash_table == NULL) {
+        uhi_errno_init();
     }
+
+    if (host_errno == 0) {
+        return 0;
+    }
+    if (g_hash_table_lookup_extended(uhi_errno_hash_table,
+                                     GINT_TO_POINTER(host_errno),
+                                     NULL, &uhi_errno)) {
+        return GPOINTER_TO_INT(uhi_errno);
+    }
+    return EINVAL; /* Not reachable per the specification */
 }
 
 static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,