| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ | |
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| char *strerror(int err_num); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"); | ||
| } |