Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/config/linux/x86_64/entrypoints.txt1
-rw-r--r--libc/spec/posix.td5
-rw-r--r--libc/src/__support/CMakeLists.txt14
-rw-r--r--libc/src/__support/StringUtil/CMakeLists.txt39
-rw-r--r--libc/src/__support/StringUtil/error_to_string.cpp216
-rw-r--r--libc/src/__support/StringUtil/error_to_string.h (renamed from libc/src/__support/error_to_string.h)4
-rw-r--r--libc/src/__support/StringUtil/message_mapper.h77
-rw-r--r--libc/src/__support/StringUtil/signal_to_string.cpp117
-rw-r--r--libc/src/__support/StringUtil/signal_to_string.h23
-rw-r--r--libc/src/__support/error_to_string.cpp257
-rw-r--r--libc/src/string/CMakeLists.txt14
-rw-r--r--libc/src/string/strerror.cpp2
-rw-r--r--libc/src/string/strerror.h2
-rw-r--r--libc/src/string/strerror_r.cpp2
-rw-r--r--libc/src/string/strsignal.cpp20
-rw-r--r--libc/src/string/strsignal.h19
-rw-r--r--libc/test/src/string/CMakeLists.txt10
-rw-r--r--libc/test/src/string/strsignal_test.cpp83
18 files changed, 628 insertions, 277 deletions
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 5ed5f0cd9747..9874cb80d74d 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -55,6 +55,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.string.strnlen
libc.src.string.strpbrk
libc.src.string.strrchr
+ libc.src.string.strsignal
libc.src.string.strspn
libc.src.string.strstr
libc.src.string.strtok
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index ee5a15980edc..912d39ff4283 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -604,6 +604,11 @@ def POSIX : StandardSpec<"POSIX"> {
ArgSpec<ConstRestrictedCharPtr>,
ArgSpec<CharRestrictedDoublePtr>]
>,
+ FunctionSpec<
+ "strsignal",
+ RetValSpec<CharPtr>,
+ [ArgSpec<IntType>]
+ >,
]
>;
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index 78d5df553946..0a159723dbc3 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -72,19 +72,6 @@ add_header_library(
libc.src.errno.errno
)
-
-add_object_library(
- error_to_string
- HDRS
- error_to_string.h
- SRCS
- error_to_string.cpp
- DEPENDS
- libc.include.errno
- libc.src.__support.CPP.string_view
- libc.src.__support.CPP.stringstream
-)
-
add_header_library(
integer_operations
HDRS
@@ -123,6 +110,7 @@ add_header_library(
add_subdirectory(FPUtil)
add_subdirectory(OSUtil)
+add_subdirectory(StringUtil)
# Thread support is used by other "File". So, we add the "threads"
# before "File".
diff --git a/libc/src/__support/StringUtil/CMakeLists.txt b/libc/src/__support/StringUtil/CMakeLists.txt
new file mode 100644
index 000000000000..5c4c69f2bc6f
--- /dev/null
+++ b/libc/src/__support/StringUtil/CMakeLists.txt
@@ -0,0 +1,39 @@
+add_header_library(
+ message_mapper
+ HDRS
+ message_mapper.h
+ DEPENDS
+ libc.src.__support.CPP.string_view
+ libc.src.__support.CPP.optional
+)
+
+add_object_library(
+ error_to_string
+ HDRS
+ error_to_string.h
+ SRCS
+ error_to_string.cpp
+ DEPENDS
+ .message_mapper
+ libc.include.errno
+ libc.src.__support.CPP.span
+ libc.src.__support.CPP.string_view
+ libc.src.__support.CPP.stringstream
+ libc.src.__support.integer_to_string
+)
+
+
+add_object_library(
+ signal_to_string
+ HDRS
+ signal_to_string.h
+ SRCS
+ signal_to_string.cpp
+ DEPENDS
+ .message_mapper
+ libc.include.signal
+ libc.src.__support.CPP.span
+ libc.src.__support.CPP.string_view
+ libc.src.__support.CPP.stringstream
+ libc.src.__support.integer_to_string
+)
diff --git a/libc/src/__support/StringUtil/error_to_string.cpp b/libc/src/__support/StringUtil/error_to_string.cpp
new file mode 100644
index 000000000000..98e2fbdee82c
--- /dev/null
+++ b/libc/src/__support/StringUtil/error_to_string.cpp
@@ -0,0 +1,216 @@
+//===-- Implementation of a class for mapping errors to strings -----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/StringUtil/error_to_string.h"
+
+#include "src/__support/CPP/span.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/CPP/stringstream.h"
+#include "src/__support/StringUtil/message_mapper.h"
+#include "src/__support/integer_to_string.h"
+
+#include <errno.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace internal {
+
+constexpr size_t max_buff_size() {
+ constexpr size_t unknown_str_len = sizeof("Unknown error");
+ constexpr size_t max_num_len =
+ __llvm_libc::IntegerToString::dec_bufsize<int>();
+ // the buffer should be able to hold "Unknown error" + ' ' + num_str
+ return (unknown_str_len + 1 + max_num_len) * sizeof(char);
+}
+
+// This is to hold error strings that have to be custom built. It may be
+// rewritten on every call to strerror (or other error to string function).
+constexpr size_t ERR_BUFFER_SIZE = max_buff_size();
+thread_local char error_buffer[ERR_BUFFER_SIZE];
+
+// Since the StringMappings array is a map from error numbers to their
+// corresponding strings, we have to have an array large enough we can use the
+// error numbers as indexes. Thankfully there are 132 errors in the above list
+// (41 and 58 are skipped) and the highest number is 133. If other platforms use
+// different error numbers, then this number may need to be adjusted.
+// Also if negative numbers or particularly large numbers are used, then the
+// array should be turned into a proper hashmap.
+constexpr size_t ERR_ARRAY_SIZE = 134;
+
+constexpr MsgMapping raw_err_array[] = {
+ MsgMapping(0, "Success"),
+ MsgMapping(EPERM, "Operation not permitted"),
+ MsgMapping(ENOENT, "No such file or directory"),
+ MsgMapping(ESRCH, "No such process"),
+ MsgMapping(EINTR, "Interrupted system call"),
+ MsgMapping(EIO, "Input/output error"),
+ MsgMapping(ENXIO, "No such device or address"),
+ MsgMapping(E2BIG, "Argument list too long"),
+ MsgMapping(ENOEXEC, "Exec format error"),
+ MsgMapping(EBADF, "Bad file descriptor"),
+ MsgMapping(ECHILD, "No child processes"),
+ MsgMapping(EAGAIN, "Resource temporarily unavailable"),
+ MsgMapping(ENOMEM, "Cannot allocate memory"),
+ MsgMapping(EACCES, "Permission denied"),
+ MsgMapping(EFAULT, "Bad address"),
+ MsgMapping(ENOTBLK, "Block device required"),
+ MsgMapping(EBUSY, "Device or resource busy"),
+ MsgMapping(EEXIST, "File exists"),
+ MsgMapping(EXDEV, "Invalid cross-device link"),
+ MsgMapping(ENODEV, "No such device"),
+ MsgMapping(ENOTDIR, "Not a directory"),
+ MsgMapping(EISDIR, "Is a directory"),
+ MsgMapping(EINVAL, "Invalid argument"),
+ MsgMapping(ENFILE, "Too many open files in system"),
+ MsgMapping(EMFILE, "Too many open files"),
+ MsgMapping(ENOTTY, "Inappropriate ioctl for device"),
+ MsgMapping(ETXTBSY, "Text file busy"),
+ MsgMapping(EFBIG, "File too large"),
+ MsgMapping(ENOSPC, "No space left on device"),
+ MsgMapping(ESPIPE, "Illegal seek"),
+ MsgMapping(EROFS, "Read-only file system"),
+ MsgMapping(EMLINK, "Too many links"),
+ MsgMapping(EPIPE, "Broken pipe"),
+ MsgMapping(EDOM, "Numerical argument out of domain"),
+ MsgMapping(ERANGE, "Numerical result out of range"),
+ MsgMapping(EDEADLK, "Resource deadlock avoided"),
+ MsgMapping(ENAMETOOLONG, "File name too long"),
+ MsgMapping(ENOLCK, "No locks available"),
+ MsgMapping(ENOSYS, "Function not implemented"),
+ MsgMapping(ENOTEMPTY, "Directory not empty"),
+ MsgMapping(ELOOP, "Too many levels of symbolic links"),
+ // No error for 41. Would be EWOULDBLOCK
+ MsgMapping(ENOMSG, "No message of desired type"),
+ MsgMapping(EIDRM, "Identifier removed"),
+ MsgMapping(ECHRNG, "Channel number out of range"),
+ MsgMapping(EL2NSYNC, "Level 2 not synchronized"),
+ MsgMapping(EL3HLT, "Level 3 halted"),
+ MsgMapping(EL3RST, "Level 3 reset"),
+ MsgMapping(ELNRNG, "Link number out of range"),
+ MsgMapping(EUNATCH, "Protocol driver not attached"),
+ MsgMapping(ENOCSI, "No CSI structure available"),
+ MsgMapping(EL2HLT, "Level 2 halted"),
+ MsgMapping(EBADE, "Invalid exchange"),
+ MsgMapping(EBADR, "Invalid request descriptor"),
+ MsgMapping(EXFULL, "Exchange full"),
+ MsgMapping(ENOANO, "No anode"),
+ MsgMapping(EBADRQC, "Invalid request code"),
+ MsgMapping(EBADSLT, "Invalid slot"),
+ // No error for 58. Would be EDEADLOCK.
+ MsgMapping(EBFONT, "Bad font file format"),
+ MsgMapping(ENOSTR, "Device not a stream"),
+ MsgMapping(ENODATA, "No data available"),
+ MsgMapping(ETIME, "Timer expired"),
+ MsgMapping(ENOSR, "Out of streams resources"),
+ MsgMapping(ENONET, "Machine is not on the network"),
+ MsgMapping(ENOPKG, "Package not installed"),
+ MsgMapping(EREMOTE, "Object is remote"),
+ MsgMapping(ENOLINK, "Link has been severed"),
+ MsgMapping(EADV, "Advertise error"),
+ MsgMapping(ESRMNT, "Srmount error"),
+ MsgMapping(ECOMM, "Communication error on send"),
+ MsgMapping(EPROTO, "Protocol error"),
+ MsgMapping(EMULTIHOP, "Multihop attempted"),
+ MsgMapping(EDOTDOT, "RFS specific error"),
+ MsgMapping(EBADMSG, "Bad message"),
+ MsgMapping(EOVERFLOW, "Value too large for defined data type"),
+ MsgMapping(ENOTUNIQ, "Name not unique on network"),
+ MsgMapping(EBADFD, "File descriptor in bad state"),
+ MsgMapping(EREMCHG, "Remote address changed"),
+ MsgMapping(ELIBACC, "Can not access a needed shared library"),
+ MsgMapping(ELIBBAD, "Accessing a corrupted shared library"),
+ MsgMapping(ELIBSCN, ".lib section in a.out corrupted"),
+ MsgMapping(ELIBMAX, "Attempting to link in too many shared libraries"),
+ MsgMapping(ELIBEXEC, "Cannot exec a shared library directly"),
+ MsgMapping(EILSEQ, "Invalid or incomplete multibyte or wide character"),
+ MsgMapping(ERESTART, "Interrupted system call should be restarted"),
+ MsgMapping(ESTRPIPE, "Streams pipe error"),
+ MsgMapping(EUSERS, "Too many users"),
+ MsgMapping(ENOTSOCK, "Socket operation on non-socket"),
+ MsgMapping(EDESTADDRREQ, "Destination address required"),
+ MsgMapping(EMSGSIZE, "Message too long"),
+ MsgMapping(EPROTOTYPE, "Protocol wrong type for socket"),
+ MsgMapping(ENOPROTOOPT, "Protocol not available"),
+ MsgMapping(EPROTONOSUPPORT, "Protocol not supported"),
+ MsgMapping(ESOCKTNOSUPPORT, "Socket type not supported"),
+ MsgMapping(ENOTSUP, "Operation not supported"),
+ MsgMapping(EPFNOSUPPORT, "Protocol family not supported"),
+ MsgMapping(EAFNOSUPPORT, "Address family not supported by protocol"),
+ MsgMapping(EADDRINUSE, "Address already in use"),
+ MsgMapping(EADDRNOTAVAIL, "Cannot assign requested address"),
+ MsgMapping(ENETDOWN, "Network is down"),
+ MsgMapping(ENETUNREACH, "Network is unreachable"),
+ MsgMapping(ENETRESET, "Network dropped connection on reset"),
+ MsgMapping(ECONNABORTED, "Software caused connection abort"),
+ MsgMapping(ECONNRESET, "Connection reset by peer"),
+ MsgMapping(ENOBUFS, "No buffer space available"),
+ MsgMapping(EISCONN, "Transport endpoint is already connected"),
+ MsgMapping(ENOTCONN, "Transport endpoint is not connected"),
+ MsgMapping(ESHUTDOWN, "Cannot send after transport endpoint shutdown"),
+ MsgMapping(ETOOMANYREFS, "Too many references: cannot splice"),
+ MsgMapping(ETIMEDOUT, "Connection timed out"),
+ MsgMapping(ECONNREFUSED, "Connection refused"),
+ MsgMapping(EHOSTDOWN, "Host is down"),
+ MsgMapping(EHOSTUNREACH, "No route to host"),
+ MsgMapping(EALREADY, "Operation already in progress"),
+ MsgMapping(EINPROGRESS, "Operation now in progress"),
+ MsgMapping(ESTALE, "Stale file handle"),
+ MsgMapping(EUCLEAN, "Structure needs cleaning"),
+ MsgMapping(ENOTNAM, "Not a XENIX named type file"),
+ MsgMapping(ENAVAIL, "No XENIX semaphores available"),
+ MsgMapping(EISNAM, "Is a named type file"),
+ MsgMapping(EREMOTEIO, "Remote I/O error"),
+ MsgMapping(EDQUOT, "Disk quota exceeded"),
+ MsgMapping(ENOMEDIUM, "No medium found"),
+ MsgMapping(EMEDIUMTYPE, "Wrong medium type"),
+ MsgMapping(ECANCELED, "Operation canceled"),
+ MsgMapping(ENOKEY, "Required key not available"),
+ MsgMapping(EKEYEXPIRED, "Key has expired"),
+ MsgMapping(EKEYREVOKED, "Key has been revoked"),
+ MsgMapping(EKEYREJECTED, "Key was rejected by service"),
+ MsgMapping(EOWNERDEAD, "Owner died"),
+ MsgMapping(ENOTRECOVERABLE, "State not recoverable"),
+ MsgMapping(ERFKILL, "Operation not possible due to RF-kill"),
+ MsgMapping(EHWPOISON, "Memory page has hardware error"),
+};
+
+constexpr size_t RAW_ARRAY_LEN = sizeof(raw_err_array) / sizeof(MsgMapping);
+constexpr size_t TOTAL_STR_LEN = total_str_len(raw_err_array, RAW_ARRAY_LEN);
+
+static constexpr MessageMapper<ERR_ARRAY_SIZE, TOTAL_STR_LEN>
+ error_mapper(raw_err_array, RAW_ARRAY_LEN);
+
+cpp::string_view build_error_string(int err_num, cpp::span<char> buffer) {
+ // if the buffer can't hold "Unknown error" + ' ' + num_str, then just
+ // return "Unknown error".
+ if (buffer.size() <
+ (sizeof("Unknown error") + 1 + IntegerToString::dec_bufsize<int>()))
+ return const_cast<char *>("Unknown error");
+
+ cpp::StringStream buffer_stream(
+ {const_cast<char *>(buffer.data()), buffer.size()});
+ buffer_stream << "Unknown error" << ' ' << err_num << '\0';
+ return buffer_stream.str();
+}
+
+} // namespace internal
+
+cpp::string_view get_error_string(int err_num) {
+ return get_error_string(err_num,
+ {internal::error_buffer, internal::ERR_BUFFER_SIZE});
+}
+
+cpp::string_view get_error_string(int err_num, cpp::span<char> buffer) {
+ auto opt_str = internal::error_mapper.get_str(err_num);
+ if (opt_str)
+ return *opt_str;
+ else
+ return internal::build_error_string(err_num, buffer);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/__support/error_to_string.h b/libc/src/__support/StringUtil/error_to_string.h
index afc5e39dab8a..8b07ee2c17ab 100644
--- a/libc/src/__support/error_to_string.h
+++ b/libc/src/__support/StringUtil/error_to_string.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
+#include "src/__support/CPP/span.h"
#include "src/__support/CPP/string_view.h"
-#include "src/__support/integer_to_string.h"
#ifndef LLVM_LIBC_SRC_SUPPORT_ERROR_TO_STRING
#define LLVM_LIBC_SRC_SUPPORT_ERROR_TO_STRING
@@ -16,7 +16,7 @@ namespace __llvm_libc {
cpp::string_view get_error_string(int err_num);
-cpp::string_view get_error_string(int err_num, cpp::string_view buffer);
+cpp::string_view get_error_string(int err_num, cpp::span<char> buffer);
} // namespace __llvm_libc
diff --git a/libc/src/__support/StringUtil/message_mapper.h b/libc/src/__support/StringUtil/message_mapper.h
new file mode 100644
index 000000000000..ae8e7593edd2
--- /dev/null
+++ b/libc/src/__support/StringUtil/message_mapper.h
@@ -0,0 +1,77 @@
+//===-- A class for number to string mappings -------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_STRING_UTIL_MESSAGE_MAPPER
+#define LLVM_LIBC_SRC_SUPPORT_STRING_UTIL_MESSAGE_MAPPER
+
+#include "src/__support/CPP/optional.h"
+#include "src/__support/CPP/string_view.h"
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace internal {
+
+struct MsgMapping {
+ int num;
+ cpp::string_view msg;
+
+ constexpr MsgMapping(int init_num, const char *init_msg)
+ : num(init_num), msg(init_msg) {
+ ;
+ }
+};
+
+constexpr size_t total_str_len(const MsgMapping *array, size_t len) {
+ size_t total = 0;
+ for (size_t i = 0; i < len; ++i) {
+ // add 1 for the null terminator.
+ total += array[i].msg.size() + 1;
+ }
+ return total;
+}
+
+template <size_t ARR_SIZE, size_t TOTAL_STR_LEN> class MessageMapper {
+ int msg_offsets[ARR_SIZE] = {-1};
+ char string_array[TOTAL_STR_LEN] = {'\0'};
+
+public:
+ constexpr MessageMapper(const MsgMapping raw_array[], size_t raw_array_len) {
+ cpp::string_view string_mappings[ARR_SIZE] = {""};
+ for (size_t i = 0; i < raw_array_len; ++i)
+ string_mappings[raw_array[i].num] = raw_array[i].msg;
+
+ size_t string_array_index = 0;
+ for (size_t cur_num = 0; cur_num < ARR_SIZE; ++cur_num) {
+ if (string_mappings[cur_num].size() != 0) {
+ msg_offsets[cur_num] = string_array_index;
+ // No need to replace with proper strcpy, this is evaluated at compile
+ // time.
+ for (size_t i = 0; i < string_mappings[cur_num].size() + 1;
+ ++i, ++string_array_index) {
+ string_array[string_array_index] = string_mappings[cur_num][i];
+ }
+ } else {
+ msg_offsets[cur_num] = -1;
+ }
+ }
+ }
+
+ cpp::optional<cpp::string_view> get_str(int num) const {
+ if (num >= 0 && static_cast<size_t>(num) < ARR_SIZE &&
+ msg_offsets[num] != -1) {
+ return {string_array + msg_offsets[num]};
+ } else {
+ return cpp::optional<cpp::string_view>();
+ }
+ }
+};
+
+} // namespace internal
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SUPPORT_STRING_UTIL_MESSAGE_MAPPER
diff --git a/libc/src/__support/StringUtil/signal_to_string.cpp b/libc/src/__support/StringUtil/signal_to_string.cpp
new file mode 100644
index 000000000000..a64f26adca65
--- /dev/null
+++ b/libc/src/__support/StringUtil/signal_to_string.cpp
@@ -0,0 +1,117 @@
+//===-- Implementation of a class for mapping signals to strings ----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/StringUtil/signal_to_string.h"
+
+#include "src/__support/CPP/span.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/CPP/stringstream.h"
+#include "src/__support/StringUtil/message_mapper.h"
+#include "src/__support/integer_to_string.h"
+
+#include <signal.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace internal {
+
+constexpr size_t max_buff_size() {
+ constexpr size_t base_str_len = sizeof("Real-time signal");
+ constexpr size_t max_num_len =
+ __llvm_libc::IntegerToString::dec_bufsize<int>();
+ // the buffer should be able to hold "Real-time signal" + ' ' + num_str
+ return (base_str_len + 1 + max_num_len) * sizeof(char);
+}
+
+// This is to hold signal strings that have to be custom built. It may be
+// rewritten on every call to strsignal (or other signal to string function).
+constexpr size_t SIG_BUFFER_SIZE = max_buff_size();
+thread_local char signal_buffer[SIG_BUFFER_SIZE];
+
+constexpr MsgMapping raw_sig_array[] = {
+ MsgMapping(SIGHUP, "Hangup"), MsgMapping(SIGINT, "Interrupt"),
+ MsgMapping(SIGQUIT, "Quit"), MsgMapping(SIGILL, "Illegal instruction"),
+ MsgMapping(SIGTRAP, "Trace/breakpoint trap"),
+ MsgMapping(SIGABRT, "Aborted"), MsgMapping(SIGBUS, "Bus error"),
+ MsgMapping(SIGFPE, "Floating point exception"),
+ MsgMapping(SIGKILL, "Killed"), MsgMapping(SIGUSR1, "User defined signal 1"),
+ MsgMapping(SIGSEGV, "Segmentation fault"),
+ MsgMapping(SIGUSR2, "User defined signal 2"),
+ MsgMapping(SIGPIPE, "Broken pipe"), MsgMapping(SIGALRM, "Alarm clock"),
+ MsgMapping(SIGTERM, "Terminated"),
+ // SIGSTKFLT (may not exist)
+ MsgMapping(SIGCHLD, "Child exited"), MsgMapping(SIGCONT, "Continued"),
+ MsgMapping(SIGSTOP, "Stopped (signal)"), MsgMapping(SIGTSTP, "Stopped"),
+ MsgMapping(SIGTTIN, "Stopped (tty input)"),
+ MsgMapping(SIGTTOU, "Stopped (tty output)"),
+ MsgMapping(SIGURG, "Urgent I/O condition"),
+ MsgMapping(SIGXCPU, "CPU time limit exceeded"),
+ MsgMapping(SIGXFSZ, "File size limit exceeded"),
+ MsgMapping(SIGVTALRM, "Virtual timer expired"),
+ MsgMapping(SIGPROF, "Profiling timer expired"),
+ MsgMapping(SIGWINCH, "Window changed"), MsgMapping(SIGPOLL, "I/O possible"),
+ // SIGPWR (may not exist)
+ MsgMapping(SIGSYS, "Bad system call"),
+
+#ifdef SIGSTKFLT
+ MsgMapping(SIGSTKFLT, "Stack fault"), // unused
+#endif
+#ifdef SIGPWR
+ MsgMapping(SIGPWR, "Power failure"), // ignored
+#endif
+};
+
+// Since the string_mappings array is a map from signal numbers to their
+// corresponding strings, we have to have an array large enough we can use the
+// signal numbers as indexes. The highest signal is SIGSYS at 31, so an array of
+// 32 elements will be large enough to hold all of them.
+constexpr size_t SIG_ARRAY_SIZE = 32;
+
+constexpr size_t RAW_ARRAY_LEN = sizeof(raw_sig_array) / sizeof(MsgMapping);
+constexpr size_t TOTAL_STR_LEN = total_str_len(raw_sig_array, RAW_ARRAY_LEN);
+
+static constexpr MessageMapper<SIG_ARRAY_SIZE, TOTAL_STR_LEN>
+ signal_mapper(raw_sig_array, RAW_ARRAY_LEN);
+
+cpp::string_view build_signal_string(int sig_num, cpp::span<char> buffer) {
+ cpp::string_view base_str;
+ if (sig_num >= SIGRTMIN && sig_num <= SIGRTMAX) {
+ base_str = cpp::string_view("Real-time signal");
+ sig_num -= SIGRTMIN;
+ } else {
+ base_str = cpp::string_view("Unknown signal");
+ }
+
+ // if the buffer can't hold "Unknown signal" + ' ' + num_str, then just
+ // return "Unknown signal".
+ if (buffer.size() <
+ (base_str.size() + 1 + IntegerToString::dec_bufsize<int>()))
+ return base_str;
+
+ cpp::StringStream buffer_stream(
+ {const_cast<char *>(buffer.data()), buffer.size()});
+ buffer_stream << base_str << ' ' << sig_num << '\0';
+ return buffer_stream.str();
+}
+
+} // namespace internal
+
+cpp::string_view get_signal_string(int sig_num) {
+ return get_signal_string(
+ sig_num, {internal::signal_buffer, internal::SIG_BUFFER_SIZE});
+}
+
+cpp::string_view get_signal_string(int sig_num, cpp::span<char> buffer) {
+ auto opt_str = internal::signal_mapper.get_str(sig_num);
+ if (opt_str)
+ return *opt_str;
+ else
+ return internal::build_signal_string(sig_num, buffer);
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/__support/StringUtil/signal_to_string.h b/libc/src/__support/StringUtil/signal_to_string.h
new file mode 100644
index 000000000000..ad04f3697750
--- /dev/null
+++ b/libc/src/__support/StringUtil/signal_to_string.h
@@ -0,0 +1,23 @@
+//===-- Function prototype for mapping signals to strings -------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/span.h"
+#include "src/__support/CPP/string_view.h"
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_SIGNAL_TO_STRING
+#define LLVM_LIBC_SRC_SUPPORT_SIGNAL_TO_STRING
+
+namespace __llvm_libc {
+
+cpp::string_view get_signal_string(int err_num);
+
+cpp::string_view get_signal_string(int err_num, cpp::span<char> buffer);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SUPPORT_SIGNAL_TO_STRING
diff --git a/libc/src/__support/error_to_string.cpp b/libc/src/__support/error_to_string.cpp
deleted file mode 100644
index f84819ccc7c2..000000000000
--- a/libc/src/__support/error_to_string.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-//===-- Implementation of a class for mapping errors to strings -----------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/__support/error_to_string.h"
-#include "src/__support/CPP/string_view.h"
-#include "src/__support/CPP/stringstream.h"
-#include <errno.h>
-#include <stddef.h>
-
-namespace __llvm_libc {
-namespace internal {
-
-constexpr size_t max_buff_size() {
- constexpr size_t unknown_str_len = sizeof("Unknown error");
- constexpr size_t max_num_len =
- __llvm_libc::IntegerToString::dec_bufsize<int>();
- // the buffer should be able to hold "Unknown error" + ' ' + num_str
- return (unknown_str_len + 1 + max_num_len) * sizeof(char);
-}
-
-// This is to hold error strings that have to be custom built. It may be
-// rewritten on every call to strerror (or other error to string function).
-constexpr size_t BUFFER_SIZE = max_buff_size();
-thread_local char error_buffer[BUFFER_SIZE];
-
-struct ErrMsgMapping {
- int err_num;
- cpp::string_view err_msg;
-
-public:
- constexpr ErrMsgMapping(int num, const char *msg)
- : err_num(num), err_msg(msg) {
- ;
- }
-};
-
-constexpr ErrMsgMapping raw_err_array[] = {
- ErrMsgMapping(0, "Success"),
- ErrMsgMapping(EPERM, "Operation not permitted"),
- ErrMsgMapping(ENOENT, "No such file or directory"),
- ErrMsgMapping(ESRCH, "No such process"),
- ErrMsgMapping(EINTR, "Interrupted system call"),
- ErrMsgMapping(EIO, "Input/output error"),
- ErrMsgMapping(ENXIO, "No such device or address"),
- ErrMsgMapping(E2BIG, "Argument list too long"),
- ErrMsgMapping(ENOEXEC, "Exec format error"),
- ErrMsgMapping(EBADF, "Bad file descriptor"),
- ErrMsgMapping(ECHILD, "No child processes"),
- ErrMsgMapping(EAGAIN, "Resource temporarily unavailable"),
- ErrMsgMapping(ENOMEM, "Cannot allocate memory"),
- ErrMsgMapping(EACCES, "Permission denied"),
- ErrMsgMapping(EFAULT, "Bad address"),
- ErrMsgMapping(ENOTBLK, "Block device required"),
- ErrMsgMapping(EBUSY, "Device or resource busy"),
- ErrMsgMapping(EEXIST, "File exists"),
- ErrMsgMapping(EXDEV, "Invalid cross-device link"),
- ErrMsgMapping(ENODEV, "No such device"),
- ErrMsgMapping(ENOTDIR, "Not a directory"),
- ErrMsgMapping(EISDIR, "Is a directory"),
- ErrMsgMapping(EINVAL, "Invalid argument"),
- ErrMsgMapping(ENFILE, "Too many open files in system"),
- ErrMsgMapping(EMFILE, "Too many open files"),
- ErrMsgMapping(ENOTTY, "Inappropriate ioctl for device"),
- ErrMsgMapping(ETXTBSY, "Text file busy"),
- ErrMsgMapping(EFBIG, "File too large"),
- ErrMsgMapping(ENOSPC, "No space left on device"),
- ErrMsgMapping(ESPIPE, "Illegal seek"),
- ErrMsgMapping(EROFS, "Read-only file system"),
- ErrMsgMapping(EMLINK, "Too many links"),
- ErrMsgMapping(EPIPE, "Broken pipe"),
- ErrMsgMapping(EDOM, "Numerical argument out of domain"),
- ErrMsgMapping(ERANGE, "Numerical result out of range"),
- ErrMsgMapping(EDEADLK, "Resource deadlock avoided"),
- ErrMsgMapping(ENAMETOOLONG, "File name too long"),
- ErrMsgMapping(ENOLCK, "No locks available"),
- ErrMsgMapping(ENOSYS, "Function not implemented"),
- ErrMsgMapping(ENOTEMPTY, "Directory not empty"),
- ErrMsgMapping(ELOOP, "Too many levels of symbolic links"),
- // No error for 41. Would be EWOULDBLOCK
- ErrMsgMapping(ENOMSG, "No message of desired type"),
- ErrMsgMapping(EIDRM, "Identifier removed"),
- ErrMsgMapping(ECHRNG, "Channel number out of range"),
- ErrMsgMapping(EL2NSYNC, "Level 2 not synchronized"),
- ErrMsgMapping(EL3HLT, "Level 3 halted"),
- ErrMsgMapping(EL3RST, "Level 3 reset"),
- ErrMsgMapping(ELNRNG, "Link number out of range"),
- ErrMsgMapping(EUNATCH, "Protocol driver not attached"),
- ErrMsgMapping(ENOCSI, "No CSI structure available"),
- ErrMsgMapping(EL2HLT, "Level 2 halted"),
- ErrMsgMapping(EBADE, "Invalid exchange"),
- ErrMsgMapping(EBADR, "Invalid request descriptor"),
- ErrMsgMapping(EXFULL, "Exchange full"),
- ErrMsgMapping(ENOANO, "No anode"),
- ErrMsgMapping(EBADRQC, "Invalid request code"),
- ErrMsgMapping(EBADSLT, "Invalid slot"),
- // No error for 58. Would be EDEADLOCK.
- ErrMsgMapping(EBFONT, "Bad font file format"),
- ErrMsgMapping(ENOSTR, "Device not a stream"),
- ErrMsgMapping(ENODATA, "No data available"),
- ErrMsgMapping(ETIME, "Timer expired"),
- ErrMsgMapping(ENOSR, "Out of streams resources"),
- ErrMsgMapping(ENONET, "Machine is not on the network"),
- ErrMsgMapping(ENOPKG, "Package not installed"),
- ErrMsgMapping(EREMOTE, "Object is remote"),
- ErrMsgMapping(ENOLINK, "Link has been severed"),
- ErrMsgMapping(EADV, "Advertise error"),
- ErrMsgMapping(ESRMNT, "Srmount error"),
- ErrMsgMapping(ECOMM, "Communication error on send"),
- ErrMsgMapping(EPROTO, "Protocol error"),
- ErrMsgMapping(EMULTIHOP, "Multihop attempted"),
- ErrMsgMapping(EDOTDOT, "RFS specific error"),
- ErrMsgMapping(EBADMSG, "Bad message"),
- ErrMsgMapping(EOVERFLOW, "Value too large for defined data type"),
- ErrMsgMapping(ENOTUNIQ, "Name not unique on network"),
- ErrMsgMapping(EBADFD, "File descriptor in bad state"),
- ErrMsgMapping(EREMCHG, "Remote address changed"),
- ErrMsgMapping(ELIBACC, "Can not access a needed shared library"),
- ErrMsgMapping(ELIBBAD, "Accessing a corrupted shared library"),
- ErrMsgMapping(ELIBSCN, ".lib section in a.out corrupted"),
- ErrMsgMapping(ELIBMAX, "Attempting to link in too many shared libraries"),
- ErrMsgMapping(ELIBEXEC, "Cannot exec a shared library directly"),
- ErrMsgMapping(EILSEQ, "Invalid or incomplete multibyte or wide character"),
- ErrMsgMapping(ERESTART, "Interrupted system call should be restarted"),
- ErrMsgMapping(ESTRPIPE, "Streams pipe error"),
- ErrMsgMapping(EUSERS, "Too many users"),
- ErrMsgMapping(ENOTSOCK, "Socket operation on non-socket"),
- ErrMsgMapping(EDESTADDRREQ, "Destination address required"),
- ErrMsgMapping(EMSGSIZE, "Message too long"),
- ErrMsgMapping(EPROTOTYPE, "Protocol wrong type for socket"),
- ErrMsgMapping(ENOPROTOOPT, "Protocol not available"),
- ErrMsgMapping(EPROTONOSUPPORT, "Protocol not supported"),
- ErrMsgMapping(ESOCKTNOSUPPORT, "Socket type not supported"),
- ErrMsgMapping(ENOTSUP, "Operation not supported"),
- ErrMsgMapping(EPFNOSUPPORT, "Protocol family not supported"),
- ErrMsgMapping(EAFNOSUPPORT, "Address family not supported by protocol"),
- ErrMsgMapping(EADDRINUSE, "Address already in use"),
- ErrMsgMapping(EADDRNOTAVAIL, "Cannot assign requested address"),
- ErrMsgMapping(ENETDOWN, "Network is down"),
- ErrMsgMapping(ENETUNREACH, "Network is unreachable"),
- ErrMsgMapping(ENETRESET, "Network dropped connection on reset"),
- ErrMsgMapping(ECONNABORTED, "Software caused connection abort"),
- ErrMsgMapping(ECONNRESET, "Connection reset by peer"),
- ErrMsgMapping(ENOBUFS, "No buffer space available"),
- ErrMsgMapping(EISCONN, "Transport endpoint is already connected"),
- ErrMsgMapping(ENOTCONN, "Transport endpoint is not connected"),
- ErrMsgMapping(ESHUTDOWN, "Cannot send after transport endpoint shutdown"),
- ErrMsgMapping(ETOOMANYREFS, "Too many references: cannot splice"),
- ErrMsgMapping(ETIMEDOUT, "Connection timed out"),
- ErrMsgMapping(ECONNREFUSED, "Connection refused"),
- ErrMsgMapping(EHOSTDOWN, "Host is down"),
- ErrMsgMapping(EHOSTUNREACH, "No route to host"),
- ErrMsgMapping(EALREADY, "Operation already in progress"),
- ErrMsgMapping(EINPROGRESS, "Operation now in progress"),
- ErrMsgMapping(ESTALE, "Stale file handle"),
- ErrMsgMapping(EUCLEAN, "Structure needs cleaning"),
- ErrMsgMapping(ENOTNAM, "Not a XENIX named type file"),
- ErrMsgMapping(ENAVAIL, "No XENIX semaphores available"),
- ErrMsgMapping(EISNAM, "Is a named type file"),
- ErrMsgMapping(EREMOTEIO, "Remote I/O error"),
- ErrMsgMapping(EDQUOT, "Disk quota exceeded"),
- ErrMsgMapping(ENOMEDIUM, "No medium found"),
- ErrMsgMapping(EMEDIUMTYPE, "Wrong medium type"),
- ErrMsgMapping(ECANCELED, "Operation canceled"),
- ErrMsgMapping(ENOKEY, "Required key not available"),
- ErrMsgMapping(EKEYEXPIRED, "Key has expired"),
- ErrMsgMapping(EKEYREVOKED, "Key has been revoked"),
- ErrMsgMapping(EKEYREJECTED, "Key was rejected by service"),
- ErrMsgMapping(EOWNERDEAD, "Owner died"),
- ErrMsgMapping(ENOTRECOVERABLE, "State not recoverable"),
- ErrMsgMapping(ERFKILL, "Operation not possible due to RF-kill"),
- ErrMsgMapping(EHWPOISON, "Memory page has hardware error"),
-};
-
-constexpr size_t total_str_len(const ErrMsgMapping *array, size_t len) {
- size_t total = 0;
- for (size_t i = 0; i < len; ++i) {
- // add 1 for the null terminator.
- total += array[i].err_msg.size() + 1;
- }
- return total;
-}
-
-// Since the StringMappings array is a map from error numbers to their
-// corresponding strings, we have to have an array large enough we can use the
-// error numbers as indexes. Thankfully there are 132 errors in the above list
-// (41 and 58 are skipped) and the highest number is 133. If other platforms use
-// different error numbers, then this number may need to be adjusted.
-// Also if negative numbers or particularly large numbers are used, then the
-// array should be turned into a proper hashmap.
-constexpr size_t ERR_ARRAY_SIZE = 134;
-
-class ErrorMapper {
-
- // const char *StringMappings[ERR_ARRAY_SIZE] = {""};
- int err_offsets[ERR_ARRAY_SIZE] = {-1};
- char string_array[total_str_len(
- raw_err_array, sizeof(raw_err_array) / sizeof(ErrMsgMapping))] = {'\0'};
-
-public:
- constexpr ErrorMapper() {
- cpp::string_view string_mappings[ERR_ARRAY_SIZE] = {""};
- for (size_t i = 0; i < (sizeof(raw_err_array) / sizeof(ErrMsgMapping)); ++i)
- string_mappings[raw_err_array[i].err_num] = raw_err_array[i].err_msg;
-
- size_t string_array_index = 0;
- for (size_t cur_err = 0; cur_err < ERR_ARRAY_SIZE; ++cur_err) {
- if (string_mappings[cur_err].size() != 0) {
- err_offsets[cur_err] = string_array_index;
- // No need to replace with proper strcpy, this is evaluated at compile
- // time.
- for (size_t i = 0; i < string_mappings[cur_err].size() + 1;
- ++i, ++string_array_index) {
- string_array[string_array_index] = string_mappings[cur_err][i];
- }
- } else {
- err_offsets[cur_err] = -1;
- }
- }
- }
-
- cpp::string_view get_str(int err_num, cpp::string_view buffer) const {
- if (err_num >= 0 && static_cast<size_t>(err_num) < ERR_ARRAY_SIZE &&
- err_offsets[err_num] != -1) {
- return const_cast<char *>(string_array + err_offsets[err_num]);
- } else {
- // if the buffer can't hold "Unknown error" + ' ' + num_str, then just
- // return "Unknown error".
- if (buffer.size() <
- (sizeof("Unknown error") + 1 + IntegerToString::dec_bufsize<int>()))
- return const_cast<char *>("Unknown error");
-
- cpp::StringStream buffer_stream(
- {const_cast<char *>(buffer.data()), buffer.size()});
- buffer_stream << "Unknown error" << ' ' << err_num << '\0';
- return buffer_stream.str();
- }
- }
-};
-
-static constexpr ErrorMapper error_mapper;
-
-} // namespace internal
-
-cpp::string_view get_error_string(int err_num) {
- return internal::error_mapper.get_str(
- err_num, {internal::error_buffer, internal::BUFFER_SIZE});
-}
-
-cpp::string_view get_error_string(int err_num, cpp::string_view buffer) {
- return internal::error_mapper.get_str(err_num, buffer);
-}
-} // namespace __llvm_libc
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index 1af5472c218d..3525e8724049 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -135,7 +135,7 @@ add_entrypoint_object(
HDRS
strerror.h
DEPENDS
- libc.src.__support.error_to_string
+ libc.src.__support.StringUtil.error_to_string
)
add_entrypoint_object(
@@ -145,7 +145,7 @@ add_entrypoint_object(
HDRS
strerror_r.h
DEPENDS
- libc.src.__support.error_to_string
+ libc.src.__support.StringUtil.error_to_string
)
add_entrypoint_object(
@@ -248,6 +248,16 @@ add_entrypoint_object(
)
add_entrypoint_object(
+ strsignal
+ SRCS
+ strsignal.cpp
+ HDRS
+ strsignal.h
+ DEPENDS
+ libc.src.__support.StringUtil.signal_to_string
+)
+
+add_entrypoint_object(
strspn
SRCS
strspn.cpp
diff --git a/libc/src/string/strerror.cpp b/libc/src/string/strerror.cpp
index e99793fb3591..014a51a622fd 100644
--- a/libc/src/string/strerror.cpp
+++ b/libc/src/string/strerror.cpp
@@ -7,8 +7,8 @@
//===----------------------------------------------------------------------===//
#include "src/string/strerror.h"
+#include "src/__support/StringUtil/error_to_string.h"
#include "src/__support/common.h"
-#include "src/__support/error_to_string.h"
namespace __llvm_libc {
diff --git a/libc/src/string/strerror.h b/libc/src/string/strerror.h
index b9ddd71d6285..ce3366db529d 100644
--- a/libc/src/string/strerror.h
+++ b/libc/src/string/strerror.h
@@ -11,7 +11,7 @@
namespace __llvm_libc {
-char *strerror(int errnum);
+char *strerror(int err_num);
} // namespace __llvm_libc
diff --git a/libc/src/string/strerror_r.cpp b/libc/src/string/strerror_r.cpp
index 30147152c448..efdc8d3723c4 100644
--- a/libc/src/string/strerror_r.cpp
+++ b/libc/src/string/strerror_r.cpp
@@ -7,8 +7,8 @@
//===----------------------------------------------------------------------===//
#include "src/string/strerror_r.h"
+#include "src/__support/StringUtil/error_to_string.h"
#include "src/__support/common.h"
-#include "src/__support/error_to_string.h"
#include <stddef.h>
diff --git a/libc/src/string/strsignal.cpp b/libc/src/string/strsignal.cpp
new file mode 100644
index 000000000000..bad69b6f5415
--- /dev/null
+++ b/libc/src/string/strsignal.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of strsignal
+//----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strsignal.h"
+#include "src/__support/StringUtil/signal_to_string.h"
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(char *, strsignal, (int sig_num)) {
+ return const_cast<char *>(get_signal_string(sig_num).data());
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/strsignal.h b/libc/src/string/strsignal.h
new file mode 100644
index 000000000000..346f3960d3aa
--- /dev/null
+++ b/libc/src/string/strsignal.h
@@ -0,0 +1,19 @@
+//===-- Implementation header for strsignal ----------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_STRSIGNAL_H
+#define LLVM_LIBC_SRC_STRING_STRSIGNAL_H
+
+namespace __llvm_libc {
+
+char *strsignal(int sig_num);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STRSIGNAL_H
diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index 723fbd502ba4..bbd990935aa5 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -246,6 +246,16 @@ add_libc_unittest(
)
add_libc_unittest(
+ strsignal_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ strsignal_test.cpp
+ DEPENDS
+ libc.src.string.strsignal
+)
+
+add_libc_unittest(
strspn_test
SUITE
libc_string_unittests
diff --git a/libc/test/src/string/strsignal_test.cpp b/libc/test/src/string/strsignal_test.cpp
new file mode 100644
index 000000000000..959d0f4bc04c
--- /dev/null
+++ b/libc/test/src/string/strsignal_test.cpp
@@ -0,0 +1,83 @@
+//===-- Unittests for strsignal -------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strsignal.h"
+#include "utils/UnitTest/Test.h"
+
+#include <signal.h>
+
+TEST(LlvmLibcStrSignalTest, KnownSignals) {
+ ASSERT_STREQ(__llvm_libc::strsignal(1), "Hangup");
+
+ const char *message_array[] = {
+ "Unknown signal 0", // unknown
+ "Hangup",
+ "Interrupt",
+ "Quit",
+ "Illegal instruction",
+ "Trace/breakpoint trap",
+ "Aborted",
+ "Bus error",
+ "Floating point exception",
+ "Killed",
+ "User defined signal 1",
+ "Segmentation fault",
+ "User defined signal 2",
+ "Broken pipe",
+ "Alarm clock",
+ "Terminated",
+ "Stack fault",
+ "Child exited",
+ "Continued",
+ "Stopped (signal)",
+ "Stopped",
+ "Stopped (tty input)",
+ "Stopped (tty output)",
+ "Urgent I/O condition",
+ "CPU time limit exceeded",
+ "File size limit exceeded",
+ "Virtual timer expired",
+ "Profiling timer expired",
+ "Window changed",
+ "I/O possible",
+ "Power failure",
+ "Bad system call",
+ };
+
+ // There are supposed to be 32 of these, but sometimes SIGRTMIN is shifted to
+ // reserve some.
+ const char *rt_message_array[] = {
+ "Real-time signal 0", "Real-time signal 1", "Real-time signal 2",
+ "Real-time signal 3", "Real-time signal 4", "Real-time signal 5",
+ "Real-time signal 6", "Real-time signal 7", "Real-time signal 8",
+ "Real-time signal 9", "Real-time signal 10", "Real-time signal 11",
+ "Real-time signal 12", "Real-time signal 13", "Real-time signal 14",
+ "Real-time signal 15", "Real-time signal 16", "Real-time signal 17",
+ "Real-time signal 18", "Real-time signal 19", "Real-time signal 20",
+ "Real-time signal 21", "Real-time signal 22", "Real-time signal 23",
+ "Real-time signal 24", "Real-time signal 25", "Real-time signal 26",
+ "Real-time signal 27", "Real-time signal 28", "Real-time signal 29",
+ "Real-time signal 30", "Real-time signal 31", "Real-time signal 32",
+ };
+
+ for (size_t i = 0; i < (sizeof(message_array) / sizeof(char *)); ++i) {
+ EXPECT_STREQ(__llvm_libc::strsignal(i), message_array[i]);
+ }
+
+ for (size_t i = 0; i < SIGRTMAX - SIGRTMIN; ++i) {
+ EXPECT_STREQ(__llvm_libc::strsignal(i + SIGRTMIN), rt_message_array[i]);
+ }
+}
+
+TEST(LlvmLibcStrsignalTest, UnknownSignals) {
+ ASSERT_STREQ(__llvm_libc::strsignal(-1), "Unknown signal -1");
+ ASSERT_STREQ(__llvm_libc::strsignal(65), "Unknown signal 65");
+ ASSERT_STREQ(__llvm_libc::strsignal(2147483647), "Unknown signal 2147483647");
+ ASSERT_STREQ(__llvm_libc::strsignal(-2147483648),
+ "Unknown signal -2147483648");
+}