From f8967e9274015d5d6a47dc18dfa47ebfcf83771d Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 24 Feb 2024 04:02:46 -0800 Subject: [PATCH] Implement strerror --- native/src/crt0/Android.mk | 2 + native/src/crt0/bionic/dirent.cpp | 19 +- .../src/crt0/bionic/private/ErrnoRestorer.h | 36 ++++ .../src/crt0/bionic/private/bionic_errdefs.h | 171 ++++++++++++++++++ native/src/crt0/bionic/strerror.cpp | 100 ++++++++++ 5 files changed, 311 insertions(+), 17 deletions(-) create mode 100644 native/src/crt0/bionic/private/ErrnoRestorer.h create mode 100644 native/src/crt0/bionic/private/bionic_errdefs.h create mode 100644 native/src/crt0/bionic/strerror.cpp diff --git a/native/src/crt0/Android.mk b/native/src/crt0/Android.mk index 261062e01..5f13c046a 100644 --- a/native/src/crt0/Android.mk +++ b/native/src/crt0/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE := crt0 LOCAL_compiler_rt := $(shell $(TARGET_CC) -target $(LLVM_TRIPLE)$(TARGET_PLATFORM_LEVEL) --print-libgcc-file-name) LOCAL_EXPORT_LDFLAGS := -static -nostartfiles -nodefaultlibs $(LOCAL_compiler_rt) -Wl,--error-limit=0 +LOCAL_CFLAGS := -Wno-c99-designator LOCAL_SRC_FILES := \ malloc.c \ @@ -16,6 +17,7 @@ LOCAL_SRC_FILES := \ stdio.c \ syscall.c \ bionic/dirent.cpp \ + bionic/strerror.cpp \ bionic/syscall-$(TARGET_ARCH).S \ tinystdio/tinystdio.c diff --git a/native/src/crt0/bionic/dirent.cpp b/native/src/crt0/bionic/dirent.cpp index fdc93457f..6d4c1bf21 100644 --- a/native/src/crt0/bionic/dirent.cpp +++ b/native/src/crt0/bionic/dirent.cpp @@ -36,25 +36,10 @@ #include #include +#include "private/ErrnoRestorer.h" + extern "C" int sys_getdents64(unsigned int, dirent*, unsigned int); -class ErrnoRestorer { -public: - explicit ErrnoRestorer() : saved_errno_(errno) { - } - - ~ErrnoRestorer() { - errno = saved_errno_; - } - - void override(int new_errno) { - saved_errno_ = new_errno; - } - -private: - int saved_errno_; -}; - // Apportable decided to copy the data structure from this file // and use it in their own code, but they also call into readdir. // In order to avoid a lockup, the structure must be maintained in diff --git a/native/src/crt0/bionic/private/ErrnoRestorer.h b/native/src/crt0/bionic/private/ErrnoRestorer.h new file mode 100644 index 000000000..e698bb614 --- /dev/null +++ b/native/src/crt0/bionic/private/ErrnoRestorer.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +class ErrnoRestorer { + public: + explicit ErrnoRestorer() : saved_errno_(errno) { + } + + ~ErrnoRestorer() { + errno = saved_errno_; + } + + void override(int new_errno) { + saved_errno_ = new_errno; + } + + private: + int saved_errno_; +}; diff --git a/native/src/crt0/bionic/private/bionic_errdefs.h b/native/src/crt0/bionic/private/bionic_errdefs.h new file mode 100644 index 000000000..435d49bc3 --- /dev/null +++ b/native/src/crt0/bionic/private/bionic_errdefs.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This header is used to define error constants and names; + * it might be included several times. + */ + +#ifndef __BIONIC_ERRDEF +#error __BIONIC_ERRDEF not defined +#endif + +__BIONIC_ERRDEF(0, "Success") +__BIONIC_ERRDEF(EPERM, "Operation not permitted") +__BIONIC_ERRDEF(ENOENT, "No such file or directory") +__BIONIC_ERRDEF(ESRCH, "No such process") +__BIONIC_ERRDEF(EINTR, "Interrupted system call") +__BIONIC_ERRDEF(EIO, "I/O error") +__BIONIC_ERRDEF(ENXIO, "No such device or address") +__BIONIC_ERRDEF(E2BIG, "Argument list too long") +__BIONIC_ERRDEF(ENOEXEC, "Exec format error") +__BIONIC_ERRDEF(EBADF, "Bad file descriptor") +__BIONIC_ERRDEF(ECHILD, "No child processes") +__BIONIC_ERRDEF(EAGAIN, "Try again") +__BIONIC_ERRDEF(ENOMEM, "Out of memory") +__BIONIC_ERRDEF(EACCES, "Permission denied") +__BIONIC_ERRDEF(EFAULT, "Bad address") +__BIONIC_ERRDEF(ENOTBLK, "Block device required") +__BIONIC_ERRDEF(EBUSY, "Device or resource busy") +__BIONIC_ERRDEF(EEXIST, "File exists") +__BIONIC_ERRDEF(EXDEV, "Cross-device link") +__BIONIC_ERRDEF(ENODEV, "No such device") +__BIONIC_ERRDEF(ENOTDIR, "Not a directory") +__BIONIC_ERRDEF(EISDIR, "Is a directory") +__BIONIC_ERRDEF(EINVAL, "Invalid argument") +__BIONIC_ERRDEF(ENFILE, "File table overflow") +__BIONIC_ERRDEF(EMFILE, "Too many open files") +__BIONIC_ERRDEF(ENOTTY, "Inappropriate ioctl for device") +__BIONIC_ERRDEF(ETXTBSY, "Text file busy") +__BIONIC_ERRDEF(EFBIG, "File too large") +__BIONIC_ERRDEF(ENOSPC, "No space left on device") +__BIONIC_ERRDEF(ESPIPE, "Illegal seek") +__BIONIC_ERRDEF(EROFS, "Read-only file system") +__BIONIC_ERRDEF(EMLINK, "Too many links") +__BIONIC_ERRDEF(EPIPE, "Broken pipe") +__BIONIC_ERRDEF(EDOM, "Math argument out of domain of func") +__BIONIC_ERRDEF(ERANGE, "Math result not representable") +__BIONIC_ERRDEF(EDEADLK, "Resource deadlock would occur") +__BIONIC_ERRDEF(ENAMETOOLONG, "File name too long") +__BIONIC_ERRDEF(ENOLCK, "No record locks available") +__BIONIC_ERRDEF(ENOSYS, "Function not implemented") +__BIONIC_ERRDEF(ENOTEMPTY, "Directory not empty") +__BIONIC_ERRDEF(ELOOP, "Too many symbolic links encountered") +__BIONIC_ERRDEF(ENOMSG, "No message of desired type") +__BIONIC_ERRDEF(EIDRM, "Identifier removed") +__BIONIC_ERRDEF(ECHRNG, "Channel number out of range") +__BIONIC_ERRDEF(EL2NSYNC, "Level 2 not synchronized") +__BIONIC_ERRDEF(EL3HLT, "Level 3 halted") +__BIONIC_ERRDEF(EL3RST, "Level 3 reset") +__BIONIC_ERRDEF(ELNRNG, "Link number out of range") +__BIONIC_ERRDEF(EUNATCH, "Protocol driver not attached") +__BIONIC_ERRDEF(ENOCSI, "No CSI structure available") +__BIONIC_ERRDEF(EL2HLT, "Level 2 halted") +__BIONIC_ERRDEF(EBADE, "Invalid exchange") +__BIONIC_ERRDEF(EBADR, "Invalid request descriptor") +__BIONIC_ERRDEF(EXFULL, "Exchange full") +__BIONIC_ERRDEF(ENOANO, "No anode") +__BIONIC_ERRDEF(EBADRQC, "Invalid request code") +__BIONIC_ERRDEF(EBADSLT, "Invalid slot") +__BIONIC_ERRDEF(EBFONT, "Bad font file format") +__BIONIC_ERRDEF(ENOSTR, "Device not a stream") +__BIONIC_ERRDEF(ENODATA, "No data available") +__BIONIC_ERRDEF(ETIME, "Timer expired") +__BIONIC_ERRDEF(ENOSR, "Out of streams resources") +__BIONIC_ERRDEF(ENONET, "Machine is not on the network") +__BIONIC_ERRDEF(ENOPKG, "Package not installed") +__BIONIC_ERRDEF(EREMOTE, "Object is remote") +__BIONIC_ERRDEF(ENOLINK, "Link has been severed") +__BIONIC_ERRDEF(EADV, "Advertise error") +__BIONIC_ERRDEF(ESRMNT, "Srmount error") +__BIONIC_ERRDEF(ECOMM, "Communication error on send") +__BIONIC_ERRDEF(EPROTO, "Protocol error") +__BIONIC_ERRDEF(EMULTIHOP, "Multihop attempted") +__BIONIC_ERRDEF(EDOTDOT, "RFS specific error") +__BIONIC_ERRDEF(EBADMSG, "Not a data message") +__BIONIC_ERRDEF(EOVERFLOW, "Value too large for defined data type") +__BIONIC_ERRDEF(ENOTUNIQ, "Name not unique on network") +__BIONIC_ERRDEF(EBADFD, "File descriptor in bad state") +__BIONIC_ERRDEF(EREMCHG, "Remote address changed") +__BIONIC_ERRDEF(ELIBACC, "Can not access a needed shared library") +__BIONIC_ERRDEF(ELIBBAD, "Accessing a corrupted shared library") +__BIONIC_ERRDEF(ELIBSCN, ".lib section in a.out corrupted") +__BIONIC_ERRDEF(ELIBMAX, "Attempting to link in too many shared libraries") +__BIONIC_ERRDEF(ELIBEXEC, "Cannot exec a shared library directly") +__BIONIC_ERRDEF(EILSEQ, "Illegal byte sequence") +__BIONIC_ERRDEF(ERESTART, "Interrupted system call should be restarted") +__BIONIC_ERRDEF(ESTRPIPE, "Streams pipe error") +__BIONIC_ERRDEF(EUSERS, "Too many users") +__BIONIC_ERRDEF(ENOTSOCK, "Socket operation on non-socket") +__BIONIC_ERRDEF(EDESTADDRREQ, "Destination address required") +__BIONIC_ERRDEF(EMSGSIZE, "Message too long") +__BIONIC_ERRDEF(EPROTOTYPE, "Protocol wrong type for socket") +__BIONIC_ERRDEF(ENOPROTOOPT, "Protocol not available") +__BIONIC_ERRDEF(EPROTONOSUPPORT, "Protocol not supported") +__BIONIC_ERRDEF(ESOCKTNOSUPPORT, "Socket type not supported") +__BIONIC_ERRDEF(EOPNOTSUPP, "Operation not supported on transport endpoint") +__BIONIC_ERRDEF(EPFNOSUPPORT, "Protocol family not supported") +__BIONIC_ERRDEF(EAFNOSUPPORT, "Address family not supported by protocol") +__BIONIC_ERRDEF(EADDRINUSE, "Address already in use") +__BIONIC_ERRDEF(EADDRNOTAVAIL, "Cannot assign requested address") +__BIONIC_ERRDEF(ENETDOWN, "Network is down") +__BIONIC_ERRDEF(ENETUNREACH, "Network is unreachable") +__BIONIC_ERRDEF(ENETRESET, "Network dropped connection because of reset") +__BIONIC_ERRDEF(ECONNABORTED, "Software caused connection abort") +__BIONIC_ERRDEF(ECONNRESET, "Connection reset by peer") +__BIONIC_ERRDEF(ENOBUFS, "No buffer space available") +__BIONIC_ERRDEF(EISCONN, "Transport endpoint is already connected") +__BIONIC_ERRDEF(ENOTCONN, "Transport endpoint is not connected") +__BIONIC_ERRDEF(ESHUTDOWN, "Cannot send after transport endpoint shutdown") +__BIONIC_ERRDEF(ETOOMANYREFS, "Too many references: cannot splice") +__BIONIC_ERRDEF(ETIMEDOUT, "Connection timed out") +__BIONIC_ERRDEF(ECONNREFUSED, "Connection refused") +__BIONIC_ERRDEF(EHOSTDOWN, "Host is down") +__BIONIC_ERRDEF(EHOSTUNREACH, "No route to host") +__BIONIC_ERRDEF(EALREADY, "Operation already in progress") +__BIONIC_ERRDEF(EINPROGRESS, "Operation now in progress") +__BIONIC_ERRDEF(ESTALE, "Stale NFS file handle") +__BIONIC_ERRDEF(EUCLEAN, "Structure needs cleaning") +__BIONIC_ERRDEF(ENOTNAM, "Not a XENIX named type file") +__BIONIC_ERRDEF(ENAVAIL, "No XENIX semaphores available") +__BIONIC_ERRDEF(EISNAM, "Is a named type file") +__BIONIC_ERRDEF(EREMOTEIO, "Remote I/O error") +__BIONIC_ERRDEF(EDQUOT, "Quota exceeded") +__BIONIC_ERRDEF(ENOMEDIUM, "No medium found") +__BIONIC_ERRDEF(EMEDIUMTYPE, "Wrong medium type") +__BIONIC_ERRDEF(ECANCELED, "Operation Canceled") +__BIONIC_ERRDEF(ENOKEY, "Required key not available") +__BIONIC_ERRDEF(EKEYEXPIRED, "Key has expired") +__BIONIC_ERRDEF(EKEYREVOKED, "Key has been revoked") +__BIONIC_ERRDEF(EKEYREJECTED, "Key was rejected by service") +__BIONIC_ERRDEF(EOWNERDEAD, "Owner died") +__BIONIC_ERRDEF(ENOTRECOVERABLE, "State not recoverable") +__BIONIC_ERRDEF(ERFKILL, "Operation not possible due to RF-kill") +__BIONIC_ERRDEF(EHWPOISON, "Memory page has hardware error") + +#undef __BIONIC_ERRDEF diff --git a/native/src/crt0/bionic/strerror.cpp b/native/src/crt0/bionic/strerror.cpp new file mode 100644 index 000000000..b6a8f5e99 --- /dev/null +++ b/native/src/crt0/bionic/strerror.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +// -std=gnu++XX automatically defines _GNU_SOURCE, which then means that +// gives us the GNU variant, which is not what we're defining here. +#undef _GNU_SOURCE + +#include + +#include +#include + +#include "private/ErrnoRestorer.h" + +#include +#include + +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. +// +// One caveat is that arraysize() doesn't accept any array of an +// anonymous type or a type defined inside a function. +// +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template +char (&ArraySizeHelper(T (&array)[N]))[N]; // NOLINT(readability/casting) + +#define arraysize(array) (sizeof(ArraySizeHelper(array))) + +static const char* __sys_error_descriptions[] = { +#define __BIONIC_ERRDEF(error_number, error_description) [error_number] = error_description, +#include "private/bionic_errdefs.h" +}; + +static inline const char* __strerror_lookup(int error_number) { + if (error_number < 0 || error_number >= static_cast(arraysize(__sys_error_descriptions))) { + return nullptr; + } + return __sys_error_descriptions[error_number]; +} + +int strerror_r(int error_number, char* buf, size_t buf_len) { + ErrnoRestorer errno_restorer; + size_t length; + + const char* error_name = __strerror_lookup(error_number); + if (error_name != nullptr) { + length = strlcpy(buf, error_name, buf_len); + } else { + length = snprintf(buf, buf_len, "Unknown error %d", error_number); + } + if (length >= buf_len) { + return ERANGE; + } + + return 0; +} + +char* strerror(int error_number) { + static char strerror_buf[NL_TEXTMAX]; + + // Just return the original constant in the easy cases. + char* result = const_cast(__strerror_lookup(error_number)); + if (result != nullptr) { + return result; + } + + result = strerror_buf; + strerror_r(error_number, result, sizeof(strerror_buf)); + return result; +}