gdbstub/user-target.c | 93 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-)
This patch introduces the function "gdb_host_errno_to_gdb" that maps
host-dependent errno values to their GDB protocol-specific
representations as listed in the GDB manual [1].
The stub now uses the correct GDB errno values in F reply packets.
[1] https://sourceware.org/gdb/current/onlinedocs/gdb.html/Errno-Values.html
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2751
Reported-by: Dominik 'Disconnect3d' Czarnota <dominik.b.czarnota@gmail.com>
Signed-off-by: Yodel Eldar <yodel.eldar@yodel.dev>
---
gdbstub/user-target.c | 93 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 89 insertions(+), 4 deletions(-)
diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c
index 43231e695e..29feb0509c 100644
--- a/gdbstub/user-target.c
+++ b/gdbstub/user-target.c
@@ -302,6 +302,87 @@ static void hostio_reply_with_data(const void *buf, size_t n)
gdbserver_state.str_buf->len, true);
}
+/*
+ * Map host error numbers to their GDB protocol counterparts.
+ * For the list of GDB File-I/O supported error numbers, please consult:
+ * https://sourceware.org/gdb/current/onlinedocs/gdb.html/Errno-Values.html
+ */
+
+static int gdb_host_errno_to_gdb(int errnum)
+{
+ enum {
+ GDB_EPERM = 1,
+ GDB_ENOENT = 2,
+ GDB_EINTR = 4,
+ GDB_EIO = 5,
+ GDB_EBADF = 9,
+ GDB_EACCES = 13,
+ GDB_EFAULT = 14,
+ GDB_EBUSY = 16,
+ GDB_EEXIST = 17,
+ GDB_ENODEV = 19,
+ GDB_ENOTDIR = 20,
+ GDB_EISDIR = 21,
+ GDB_EINVAL = 22,
+ GDB_ENFILE = 23,
+ GDB_EMFILE = 24,
+ GDB_EFBIG = 27,
+ GDB_ENOSPC = 28,
+ GDB_ESPIPE = 29,
+ GDB_EROFS = 30,
+ GDB_ENOSYS = 88,
+ GDB_ENAMETOOLONG = 91,
+ GDB_EUNKNOWN = 9999,
+ };
+
+ switch (errnum) {
+ case EPERM:
+ return GDB_EPERM;
+ case ENOENT:
+ return GDB_ENOENT;
+ case EINTR:
+ return GDB_EINTR;
+ case EIO:
+ return GDB_EIO;
+ case EBADF:
+ return GDB_EBADF;
+ case EACCES:
+ return GDB_EACCES;
+ case EFAULT:
+ return GDB_EFAULT;
+ case EBUSY:
+ return GDB_EBUSY;
+ case EEXIST:
+ return GDB_EEXIST;
+ case ENODEV:
+ return GDB_ENODEV;
+ case ENOTDIR:
+ return GDB_ENOTDIR;
+ case EISDIR:
+ return GDB_EISDIR;
+ case EINVAL:
+ return GDB_EINVAL;
+ case ENFILE:
+ return GDB_ENFILE;
+ case EMFILE:
+ return GDB_EMFILE;
+ case EFBIG:
+ return GDB_EFBIG;
+ case ENOSPC:
+ return GDB_ENOSPC;
+ case ESPIPE:
+ return GDB_ESPIPE;
+ case EROFS:
+ return GDB_EROFS;
+ case ENOSYS:
+ return GDB_ENOSYS;
+ case ENAMETOOLONG:
+ return GDB_ENAMETOOLONG;
+ default:
+ return GDB_EUNKNOWN;
+ }
+}
+
void gdb_handle_v_file_open(GArray *params, void *user_ctx)
{
const char *filename = get_filename_param(params, 0);
@@ -315,7 +396,8 @@ void gdb_handle_v_file_open(GArray *params, void *user_ctx)
int fd = open(filename, flags, mode);
#endif
if (fd < 0) {
- g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
+ int gdb_errno = gdb_host_errno_to_gdb(errno);
+ g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
} else {
g_string_printf(gdbserver_state.str_buf, "F%x", fd);
}
@@ -327,7 +409,8 @@ void gdb_handle_v_file_close(GArray *params, void *user_ctx)
int fd = gdb_get_cmd_param(params, 0)->val_ul;
if (close(fd) == -1) {
- g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
+ int gdb_errno = gdb_host_errno_to_gdb(errno);
+ g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
gdb_put_strbuf();
return;
}
@@ -350,7 +433,8 @@ void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
ssize_t n = pread(fd, buf, bufsiz, offset);
if (n < 0) {
- g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
+ int gdb_errno = gdb_host_errno_to_gdb(errno);
+ g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
gdb_put_strbuf();
return;
}
@@ -373,7 +457,8 @@ void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
ssize_t n = readlink(filename, buf, BUFSIZ);
#endif
if (n < 0) {
- g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
+ int gdb_errno = gdb_host_errno_to_gdb(errno);
+ g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
gdb_put_strbuf();
return;
}
--
2.51.0
Yodel Eldar <yodel.eldar@yodel.dev> writes:
> This patch introduces the function "gdb_host_errno_to_gdb" that maps
> host-dependent errno values to their GDB protocol-specific
> representations as listed in the GDB manual [1].
>
> The stub now uses the correct GDB errno values in F reply packets.
>
> [1] https://sourceware.org/gdb/current/onlinedocs/gdb.html/Errno-Values.html
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2751
> Reported-by: Dominik 'Disconnect3d' Czarnota <dominik.b.czarnota@gmail.com>
> Signed-off-by: Yodel Eldar <yodel.eldar@yodel.dev>
> ---
> gdbstub/user-target.c | 93 +++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 89 insertions(+), 4 deletions(-)
>
> diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c
> index 43231e695e..29feb0509c 100644
> --- a/gdbstub/user-target.c
> +++ b/gdbstub/user-target.c
> @@ -302,6 +302,87 @@ static void hostio_reply_with_data(const void *buf, size_t n)
> gdbserver_state.str_buf->len, true);
> }
>
> +/*
> + * Map host error numbers to their GDB protocol counterparts.
> + * For the list of GDB File-I/O supported error numbers, please consult:
> + * https://sourceware.org/gdb/current/onlinedocs/gdb.html/Errno-Values.html
> + */
> +
> +static int gdb_host_errno_to_gdb(int errnum)
> +{
> + enum {
> + GDB_EPERM = 1,
> + GDB_ENOENT = 2,
> + GDB_EINTR = 4,
> + GDB_EIO = 5,
> + GDB_EBADF = 9,
> + GDB_EACCES = 13,
> + GDB_EFAULT = 14,
> + GDB_EBUSY = 16,
> + GDB_EEXIST = 17,
> + GDB_ENODEV = 19,
> + GDB_ENOTDIR = 20,
> + GDB_EISDIR = 21,
> + GDB_EINVAL = 22,
> + GDB_ENFILE = 23,
> + GDB_EMFILE = 24,
> + GDB_EFBIG = 27,
> + GDB_ENOSPC = 28,
> + GDB_ESPIPE = 29,
> + GDB_EROFS = 30,
> + GDB_ENOSYS = 88,
> + GDB_ENAMETOOLONG = 91,
> + GDB_EUNKNOWN = 9999,
> + };
We have this enum in include/gdbstub/syscalls.h already.
> +
> + switch (errnum) {
> + case EPERM:
> + return GDB_EPERM;
> + case ENOENT:
> + return GDB_ENOENT;
> + case EINTR:
> + return GDB_EINTR;
> + case EIO:
> + return GDB_EIO;
> + case EBADF:
> + return GDB_EBADF;
> + case EACCES:
> + return GDB_EACCES;
> + case EFAULT:
> + return GDB_EFAULT;
> + case EBUSY:
> + return GDB_EBUSY;
> + case EEXIST:
> + return GDB_EEXIST;
> + case ENODEV:
> + return GDB_ENODEV;
> + case ENOTDIR:
> + return GDB_ENOTDIR;
> + case EISDIR:
> + return GDB_EISDIR;
> + case EINVAL:
> + return GDB_EINVAL;
> + case ENFILE:
> + return GDB_ENFILE;
> + case EMFILE:
> + return GDB_EMFILE;
> + case EFBIG:
> + return GDB_EFBIG;
> + case ENOSPC:
> + return GDB_ENOSPC;
> + case ESPIPE:
> + return GDB_ESPIPE;
> + case EROFS:
> + return GDB_EROFS;
> + case ENOSYS:
> + return GDB_ENOSYS;
> + case ENAMETOOLONG:
> + return GDB_ENAMETOOLONG;
> + default:
> + return GDB_EUNKNOWN;
> + }
> +}
> +
> void gdb_handle_v_file_open(GArray *params, void *user_ctx)
> {
> const char *filename = get_filename_param(params, 0);
> @@ -315,7 +396,8 @@ void gdb_handle_v_file_open(GArray *params, void *user_ctx)
> int fd = open(filename, flags, mode);
> #endif
> if (fd < 0) {
> - g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
> + int gdb_errno = gdb_host_errno_to_gdb(errno);
> + g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
> } else {
> g_string_printf(gdbserver_state.str_buf, "F%x", fd);
> }
> @@ -327,7 +409,8 @@ void gdb_handle_v_file_close(GArray *params, void *user_ctx)
> int fd = gdb_get_cmd_param(params, 0)->val_ul;
>
> if (close(fd) == -1) {
> - g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
> + int gdb_errno = gdb_host_errno_to_gdb(errno);
> + g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
> gdb_put_strbuf();
> return;
> }
> @@ -350,7 +433,8 @@ void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
>
> ssize_t n = pread(fd, buf, bufsiz, offset);
> if (n < 0) {
> - g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
> + int gdb_errno = gdb_host_errno_to_gdb(errno);
> + g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
> gdb_put_strbuf();
> return;
> }
> @@ -373,7 +457,8 @@ void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
> ssize_t n = readlink(filename, buf, BUFSIZ);
> #endif
> if (n < 0) {
> - g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
> + int gdb_errno = gdb_host_errno_to_gdb(errno);
> + g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
> gdb_put_strbuf();
> return;
> }
with that fixed:
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
Hi, Alex!
On 10/16/25 9:56 AM, Alex Bennée wrote:
> Yodel Eldar <yodel.eldar@yodel.dev> writes:
>
>> This patch introduces the function "gdb_host_errno_to_gdb" that maps
>> host-dependent errno values to their GDB protocol-specific
>> representations as listed in the GDB manual [1].
>>
>> The stub now uses the correct GDB errno values in F reply packets.
>>
>> [1] https://sourceware.org/gdb/current/onlinedocs/gdb.html/Errno-Values.html
>>
>> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2751
>> Reported-by: Dominik 'Disconnect3d' Czarnota <dominik.b.czarnota@gmail.com>
>> Signed-off-by: Yodel Eldar <yodel.eldar@yodel.dev>
>> ---
>> gdbstub/user-target.c | 93 +++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 89 insertions(+), 4 deletions(-)
>>
>> diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c
>> index 43231e695e..29feb0509c 100644
>> --- a/gdbstub/user-target.c
>> +++ b/gdbstub/user-target.c
>> @@ -302,6 +302,87 @@ static void hostio_reply_with_data(const void *buf, size_t n)
>> gdbserver_state.str_buf->len, true);
>> }
>>
>> +/*
>> + * Map host error numbers to their GDB protocol counterparts.
>> + * For the list of GDB File-I/O supported error numbers, please consult:
>> + * https://sourceware.org/gdb/current/onlinedocs/gdb.html/Errno-Values.html
>> + */
>> +
>> +static int gdb_host_errno_to_gdb(int errnum)
>> +{
>> + enum {
>> + GDB_EPERM = 1,
>> + GDB_ENOENT = 2,
>> + GDB_EINTR = 4,
>> + GDB_EIO = 5,
>> + GDB_EBADF = 9,
>> + GDB_EACCES = 13,
>> + GDB_EFAULT = 14,
>> + GDB_EBUSY = 16,
>> + GDB_EEXIST = 17,
>> + GDB_ENODEV = 19,
>> + GDB_ENOTDIR = 20,
>> + GDB_EISDIR = 21,
>> + GDB_EINVAL = 22,
>> + GDB_ENFILE = 23,
>> + GDB_EMFILE = 24,
>> + GDB_EFBIG = 27,
>> + GDB_ENOSPC = 28,
>> + GDB_ESPIPE = 29,
>> + GDB_EROFS = 30,
>> + GDB_ENOSYS = 88,
>> + GDB_ENAMETOOLONG = 91,
>> + GDB_EUNKNOWN = 9999,
>> + };
>
> We have this enum in include/gdbstub/syscalls.h already.
>
Thanks for pointing that out!
>> +
>> + switch (errnum) {
>> + case EPERM:
>> + return GDB_EPERM;
>> + case ENOENT:
>> + return GDB_ENOENT;
>> + case EINTR:
>> + return GDB_EINTR;
>> + case EIO:
>> + return GDB_EIO;
>> + case EBADF:
>> + return GDB_EBADF;
>> + case EACCES:
>> + return GDB_EACCES;
>> + case EFAULT:
>> + return GDB_EFAULT;
>> + case EBUSY:
>> + return GDB_EBUSY;
>> + case EEXIST:
>> + return GDB_EEXIST;
>> + case ENODEV:
>> + return GDB_ENODEV;
>> + case ENOTDIR:
>> + return GDB_ENOTDIR;
>> + case EISDIR:
>> + return GDB_EISDIR;
>> + case EINVAL:
>> + return GDB_EINVAL;
>> + case ENFILE:
>> + return GDB_ENFILE;
>> + case EMFILE:
>> + return GDB_EMFILE;
>> + case EFBIG:
>> + return GDB_EFBIG;
>> + case ENOSPC:
>> + return GDB_ENOSPC;
>> + case ESPIPE:
>> + return GDB_ESPIPE;
>> + case EROFS:
>> + return GDB_EROFS;
>> + case ENOSYS:
>> + return GDB_ENOSYS;
>> + case ENAMETOOLONG:
>> + return GDB_ENAMETOOLONG;
>> + default:
>> + return GDB_EUNKNOWN;
>> + }
>> +}
>> +
>> void gdb_handle_v_file_open(GArray *params, void *user_ctx)
>> {
>> const char *filename = get_filename_param(params, 0);
>> @@ -315,7 +396,8 @@ void gdb_handle_v_file_open(GArray *params, void *user_ctx)
>> int fd = open(filename, flags, mode);
>> #endif
>> if (fd < 0) {
>> - g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
>> + int gdb_errno = gdb_host_errno_to_gdb(errno);
>> + g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
>> } else {
>> g_string_printf(gdbserver_state.str_buf, "F%x", fd);
>> }
>> @@ -327,7 +409,8 @@ void gdb_handle_v_file_close(GArray *params, void *user_ctx)
>> int fd = gdb_get_cmd_param(params, 0)->val_ul;
>>
>> if (close(fd) == -1) {
>> - g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
>> + int gdb_errno = gdb_host_errno_to_gdb(errno);
>> + g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
>> gdb_put_strbuf();
>> return;
>> }
>> @@ -350,7 +433,8 @@ void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
>>
>> ssize_t n = pread(fd, buf, bufsiz, offset);
>> if (n < 0) {
>> - g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
>> + int gdb_errno = gdb_host_errno_to_gdb(errno);
>> + g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
>> gdb_put_strbuf();
>> return;
>> }
>> @@ -373,7 +457,8 @@ void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
>> ssize_t n = readlink(filename, buf, BUFSIZ);
>> #endif
>> if (n < 0) {
>> - g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno);
>> + int gdb_errno = gdb_host_errno_to_gdb(errno);
>> + g_string_printf(gdbserver_state.str_buf, "F-1,%x", gdb_errno);
>> gdb_put_strbuf();
>> return;
>> }
>
> with that fixed:
>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
>
Since your review, I've noticed that Richard Henderson already authored
a host-to-GDB errno mapping function in commit 7327e6023:
host_to_gdb_errno:target/m68k/m68k-semi.c; it's functionally identical
to the mapping proposed in this patch (albeit missing two errno values
that were undocumented in the GDB manual until recently), but written in
the context of semihosting for the m68k.
So as to avoid duplicating code, I'm considering exporting the existing
host_to_gdb_errno in a minor refactor to use that instead; do you think
that's a better route?
Thanks,
Yodel
On 10/16/25 13:51, Yodel Eldar via wrote: > Since your review, I've noticed that Richard Henderson already authored > a host-to-GDB errno mapping function in commit 7327e6023: > host_to_gdb_errno:target/m68k/m68k-semi.c; it's functionally identical > to the mapping proposed in this patch (albeit missing two errno values > that were undocumented in the GDB manual until recently), but written in > the context of semihosting for the m68k. Heh. I had glanced at your patch and thought "don't we do that already"? > > So as to avoid duplicating code, I'm considering exporting the existing > host_to_gdb_errno in a minor refactor to use that instead; do you think > that's a better route? Yes. r~
On 10/16/25 4:51 PM, Richard Henderson wrote: > On 10/16/25 13:51, Yodel Eldar via wrote: >> Since your review, I've noticed that Richard Henderson already authored >> a host-to-GDB errno mapping function in commit 7327e6023: >> host_to_gdb_errno:target/m68k/m68k-semi.c; it's functionally identical >> to the mapping proposed in this patch (albeit missing two errno values >> that were undocumented in the GDB manual until recently), but written in >> the context of semihosting for the m68k. > > Heh. I had glanced at your patch and thought "don't we do that already"? > >> >> So as to avoid duplicating code, I'm considering exporting the existing >> host_to_gdb_errno in a minor refactor to use that instead; do you think >> that's a better route? > > Yes. > > > r~ > Haha, grateful for your eyes and input on this! I'll be sure to Cc the next time I name-check you. Yodel
© 2016 - 2025 Red Hat, Inc.