diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -71,6 +71,12 @@ static_assert(sizeof(GDBRemoteFStatData) == 64, "size of GDBRemoteFStatData is not 64"); +enum GDBErrno { +#define HANDLE_ERRNO(name, value) GDB_##name = value, +#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def" + GDB_EUNKNOWN = 9999 +}; + class ProcessGDBRemote; class GDBRemoteCommunication : public Communication { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3062,6 +3062,17 @@ return Status(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); } +static int gdb_errno_to_system(int err) { + switch (err) { +#define HANDLE_ERRNO(name, value) \ + case GDB_##name: \ + return name; +#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def" + default: + return -1; + } +} + static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response, uint64_t fail_result, Status &error) { response.SetFilePos(0); @@ -3071,8 +3082,8 @@ if (result == -2) return fail_result; if (response.GetChar() == ',') { - int result_errno = response.GetS32(-2, 16); - if (result_errno != -2) + int result_errno = gdb_errno_to_system(response.GetS32(-1, 16)); + if (result_errno != -1) error.SetError(result_errno, eErrorTypePOSIX); else error.SetError(-1, eErrorTypeGeneric); @@ -3225,7 +3236,7 @@ const uint32_t mode = response.GetS32(-1, 16); if (static_cast(mode) == -1) { if (response.GetChar() == ',') { - int response_errno = response.GetS32(-1, 16); + int response_errno = gdb_errno_to_system(response.GetS32(-1, 16)); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); else @@ -3266,7 +3277,7 @@ if (retcode == -1) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { - int response_errno = response.GetS32(-1, 16); + int response_errno = gdb_errno_to_system(response.GetS32(-1, 16)); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } @@ -3309,7 +3320,7 @@ if (bytes_written == -1) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { - int response_errno = response.GetS32(-1, 16); + int response_errno = gdb_errno_to_system(response.GetS32(-1, 16)); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } @@ -3341,7 +3352,7 @@ if (result != 0) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { - int response_errno = response.GetS32(-1, 16); + int response_errno = gdb_errno_to_system(response.GetS32(-1, 16)); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } @@ -3372,7 +3383,7 @@ if (result != 0) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { - int response_errno = response.GetS32(-1, 16); + int response_errno = gdb_errno_to_system(response.GetS32(-1, 16)); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -534,6 +534,17 @@ return SendErrorResponse(18); } +static GDBErrno system_errno_to_gdb(int err) { + switch (err) { +#define HANDLE_ERRNO(name, value) \ + case name: \ + return GDB_##name; +#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def" + default: + return GDB_EUNKNOWN; + } +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_Close( StringExtractorGDBRemote &packet) { @@ -553,7 +564,7 @@ response.PutChar('F'); response.Printf("%x", err); if (save_errno) - response.Printf(",%x", save_errno); + response.Printf(",%x", system_errno_to_gdb(save_errno)); return SendPacketNoLock(response.GetString()); } @@ -584,7 +595,7 @@ } else { response.PutCString("-1"); if (save_errno) - response.Printf(",%x", save_errno); + response.Printf(",%x", system_errno_to_gdb(save_errno)); } return SendPacketNoLock(response.GetString()); } @@ -616,7 +627,7 @@ else { response.PutCString("-1"); if (save_errno) - response.Printf(",%x", save_errno); + response.Printf(",%x", system_errno_to_gdb(save_errno)); } } else { response.Printf("-1,%x", EINVAL); @@ -774,7 +785,7 @@ struct stat file_stats; if (::fstat(fd, &file_stats) == -1) { const int save_errno = errno; - response.Printf("F-1,%x", save_errno); + response.Printf("F-1,%x", system_errno_to_gdb(save_errno)); return SendPacketNoLock(response.GetString()); } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteErrno.def b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteErrno.def new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteErrno.def @@ -0,0 +1,39 @@ +//===-- GDBRemoteErrno.def --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// NOTE: NO INCLUDE GUARD DESIRED! + +// HANDLE_ERRNO(name, value) +#ifndef HANDLE_ERRNO +#error "HANDLE_ERRNO must be defined" +#endif + +// from gdb's include/gdb/fileio.h +HANDLE_ERRNO(EPERM, 1) +HANDLE_ERRNO(ENOENT, 2) +HANDLE_ERRNO(EINTR, 4) +HANDLE_ERRNO(EIO, 5) +HANDLE_ERRNO(EBADF, 9) +HANDLE_ERRNO(EACCES, 13) +HANDLE_ERRNO(EFAULT, 14) +HANDLE_ERRNO(EBUSY, 16) +HANDLE_ERRNO(EEXIST, 17) +HANDLE_ERRNO(ENODEV, 19) +HANDLE_ERRNO(ENOTDIR, 20) +HANDLE_ERRNO(EISDIR, 21) +HANDLE_ERRNO(EINVAL, 22) +HANDLE_ERRNO(ENFILE, 23) +HANDLE_ERRNO(EMFILE, 24) +HANDLE_ERRNO(EFBIG, 27) +HANDLE_ERRNO(ENOSPC, 28) +HANDLE_ERRNO(ESPIPE, 29) +HANDLE_ERRNO(EROFS, 30) +HANDLE_ERRNO(ENOSYS, 88) +HANDLE_ERRNO(ENAMETOOLONG, 91) + +#undef HANDLE_ERRNO diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py --- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemotePlatformFile.py @@ -15,7 +15,7 @@ return "Fa" elif packet.startswith("vFile:close:"): return "F0" - return "F-1,16" + return "F-1,58" self.server.responder = Responder() @@ -39,21 +39,23 @@ class Responder(MockGDBServerResponder): def vFile(self, packet): - return "F-1,16" + # use ENOSYS as this constant differs between GDB Remote + # Protocol and Linux, so we can test the translation + return "F-1,58" self.server.responder = Responder() self.match("platform file open /some/file.txt -v 0755", - [r"error: Invalid argument"], + [r"error: Function not implemented"], error=True) self.match("platform file read 16 -o 11 -c 13", - [r"error: Invalid argument"], + [r"error: Function not implemented"], error=True) self.match("platform file write 16 -o 11 -d teststring", - [r"error: Invalid argument"], + [r"error: Function not implemented"], error=True) self.match("platform file close 16", - [r"error: Invalid argument"], + [r"error: Function not implemented"], error=True) self.assertPacketLogContains([ "vFile:open:2f736f6d652f66696c652e747874,00000202,000001ed",