Skip to content

[libc] Add printf strerror conversion (%m) #105891

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions libc/config/baremetal/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
},
"LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE": {
"value": false
},
"LIBC_CONF_PRINTF_DISABLE_STRERROR": {
"value": true
}
},
"qsort": {
Expand Down
4 changes: 4 additions & 0 deletions libc/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
"LIBC_CONF_PRINTF_DISABLE_FIXED_POINT": {
"value": false,
"doc": "Disable printing fixed point values in printf and friends."
},
"LIBC_CONF_PRINTF_DISABLE_STRERROR": {
"value": false,
"doc": "Disable handling of %m to print strerror in printf and friends."
}
},
"scanf": {
Expand Down
3 changes: 3 additions & 0 deletions libc/config/gpu/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
},
"LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE": {
"value": false
},
"LIBC_CONF_PRINTF_DISABLE_STRERROR": {
"value": true
}
},
"scanf": {
Expand Down
1 change: 1 addition & 0 deletions libc/docs/configure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ to learn about the defaults for your platform and target.
- ``LIBC_CONF_PRINTF_DISABLE_FIXED_POINT``: Disable printing fixed point values in printf and friends.
- ``LIBC_CONF_PRINTF_DISABLE_FLOAT``: Disable printing floating point values in printf and friends.
- ``LIBC_CONF_PRINTF_DISABLE_INDEX_MODE``: Disable index mode in the printf format string.
- ``LIBC_CONF_PRINTF_DISABLE_STRERROR``: Disable handling of %m to print strerror in printf and friends.
- ``LIBC_CONF_PRINTF_DISABLE_WRITE_INT``: Disable handling of %n in printf format string.
- ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE``: Use large table for better printf long double performance.
* **"pthread" options**
Expand Down
12 changes: 12 additions & 0 deletions libc/docs/dev/printf_behavior.rst
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,15 @@ The %r, %R, %k, and %K fixed point number format specifiers are accepted as
defined in ISO/IEC TR 18037 (the fixed point number extension). These are
available when the compiler is detected as having support for fixed point
numbers and the LIBC_COPT_PRINTF_DISABLE_FIXED_POINT flag is not set.

The %m conversion will behave as specified by POSIX for syslog: It takes no
arguments, and outputs the result of strerror(errno). Additionally, to match
existing printf behaviors, it will behave as if it is a %s string conversion for
the purpose of all options, except for the alt form flag. If the alt form flag
is specified, %m will instead output a string matching the macro name of the
value of errno (e.g. "ERANGE" for errno = ERANGE), again treating it as a string
conversion. If there is no corresponding macro, then alt form %m will print the
value of errno as an integer with the %d format, including all options. If
errno = 0 and alt form is specified, the conversion will be a string conversion
on "0" for simplicity of implementation. This matches what other libcs
implementing this feature have done.
11 changes: 9 additions & 2 deletions libc/src/__support/StringUtil/error_to_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ constexpr size_t TOTAL_STR_LEN = total_str_len(PLATFORM_ERRORS);
constexpr size_t ERR_ARRAY_SIZE = max_key_val(PLATFORM_ERRORS) + 1;

constexpr MessageMapper<ERR_ARRAY_SIZE, TOTAL_STR_LEN>
error_mapper(PLATFORM_ERRORS);
ERROR_MAPPER(PLATFORM_ERRORS);

constexpr MessageMapper<ERR_ARRAY_SIZE, TOTAL_STR_LEN>
ERRNO_NAME_MAPPER(PLATFORM_ERRNO_NAMES);

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
Expand All @@ -68,11 +71,15 @@ cpp::string_view get_error_string(int err_num) {
}

cpp::string_view get_error_string(int err_num, cpp::span<char> buffer) {
auto opt_str = internal::error_mapper.get_str(err_num);
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);
}

cpp::optional<cpp::string_view> try_get_errno_name(int err_num) {
return internal::ERRNO_NAME_MAPPER.get_str(err_num);
}

} // namespace LIBC_NAMESPACE_DECL
3 changes: 3 additions & 0 deletions libc/src/__support/StringUtil/error_to_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_ERROR_TO_STRING_H
#define LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_ERROR_TO_STRING_H

#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/span.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/macros/config.h"
Expand All @@ -19,6 +20,8 @@ cpp::string_view get_error_string(int err_num);

cpp::string_view get_error_string(int err_num, cpp::span<char> buffer);

cpp::optional<cpp::string_view> try_get_errno_name(int err_num);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_ERROR_TO_STRING_H
55 changes: 55 additions & 0 deletions libc/src/__support/StringUtil/tables/linux_extension_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,61 @@ constexpr MsgTable<52> LINUX_ERRORS = {
MsgMapping(EHWPOISON, "Memory page has hardware error"),
};

constexpr MsgTable<52> LINUX_ERRNO_NAMES = {
MsgMapping(ENOTBLK, "ENOTBLK"),
MsgMapping(ECHRNG, "ECHRNG"),
MsgMapping(EL2NSYNC, "EL2NSYNC"),
MsgMapping(EL3HLT, "EL3HLT"),
MsgMapping(EL3RST, "EL3RST"),
MsgMapping(ELNRNG, "ELNRNG"),
MsgMapping(EUNATCH, "EUNATCH"),
MsgMapping(ENOCSI, "ENOCSI"),
MsgMapping(EL2HLT, "EL2HLT"),
MsgMapping(EBADE, "EBADE"),
MsgMapping(EBADR, "EBADR"),
MsgMapping(EXFULL, "EXFULL"),
MsgMapping(ENOANO, "ENOANO"),
MsgMapping(EBADRQC, "EBADRQC"),
MsgMapping(EBADSLT, "EBADSLT"),
MsgMapping(EBFONT, "EBFONT"),
MsgMapping(ENONET, "ENONET"),
MsgMapping(ENOPKG, "ENOPKG"),
MsgMapping(EREMOTE, "EREMOTE"),
MsgMapping(EADV, "EADV"),
MsgMapping(ESRMNT, "ESRMNT"),
MsgMapping(ECOMM, "ECOMM"),
MsgMapping(EDOTDOT, "EDOTDOT"),
MsgMapping(ENOTUNIQ, "ENOTUNIQ"),
MsgMapping(EBADFD, "EBADFD"),
MsgMapping(EREMCHG, "EREMCHG"),
MsgMapping(ELIBACC, "ELIBACC"),
MsgMapping(ELIBBAD, "ELIBBAD"),
MsgMapping(ELIBSCN, "ELIBSCN"),
MsgMapping(ELIBMAX, "ELIBMAX"),
MsgMapping(ELIBEXEC, "ELIBEXEC"),
MsgMapping(ERESTART, "ERESTART"),
MsgMapping(ESTRPIPE, "ESTRPIPE"),
MsgMapping(EUSERS, "EUSERS"),
MsgMapping(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"),
MsgMapping(EPFNOSUPPORT, "EPFNOSUPPORT"),
MsgMapping(ESHUTDOWN, "ESHUTDOWN"),
MsgMapping(ETOOMANYREFS, "ETOOMANYREFS"),
MsgMapping(EHOSTDOWN, "EHOSTDOWN"),
MsgMapping(EUCLEAN, "EUCLEAN"),
MsgMapping(ENOTNAM, "ENOTNAM"),
MsgMapping(ENAVAIL, "ENAVAIL"),
MsgMapping(EISNAM, "EISNAM"),
MsgMapping(EREMOTEIO, "EREMOTEIO"),
MsgMapping(ENOMEDIUM, "ENOMEDIUM"),
MsgMapping(EMEDIUMTYPE, "EMEDIUMTYPE"),
MsgMapping(ENOKEY, "ENOKEY"),
MsgMapping(EKEYEXPIRED, "EKEYEXPIRED"),
MsgMapping(EKEYREVOKED, "EKEYREVOKED"),
MsgMapping(EKEYREJECTED, "EKEYREJECTED"),
MsgMapping(ERFKILL, "ERFKILL"),
MsgMapping(EHWPOISON, "EHWPOISON"),
};

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_TABLES_LINUX_EXTENSION_ERRORS_H
3 changes: 3 additions & 0 deletions libc/src/__support/StringUtil/tables/linux_platform_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ namespace LIBC_NAMESPACE_DECL {
LIBC_INLINE_VAR constexpr auto PLATFORM_ERRORS =
STDC_ERRORS + POSIX_ERRORS + LINUX_ERRORS;

LIBC_INLINE_VAR constexpr auto PLATFORM_ERRNO_NAMES =
STDC_ERRNO_NAMES + POSIX_ERRNO_NAMES + LINUX_ERRNO_NAMES;

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_TABLES_LINUX_PLATFORM_ERRORS_H
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace LIBC_NAMESPACE_DECL {

LIBC_INLINE_VAR constexpr auto PLATFORM_ERRORS = STDC_ERRORS;

LIBC_INLINE_VAR constexpr auto PLATFORM_ERRNO_NAMES = STDC_ERRNO_NAMES;

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_TABLES_MINIMAL_PLATFORM_ERRORS_H
79 changes: 79 additions & 0 deletions libc/src/__support/StringUtil/tables/posix_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,85 @@ LIBC_INLINE_VAR constexpr MsgTable<76> POSIX_ERRORS = {
MsgMapping(ENOTRECOVERABLE, "State not recoverable"),
};

LIBC_INLINE_VAR constexpr MsgTable<76> POSIX_ERRNO_NAMES = {
MsgMapping(EPERM, "EPERM"),
MsgMapping(ENOENT, "ENOENT"),
MsgMapping(ESRCH, "ESRCH"),
MsgMapping(EINTR, "EINTR"),
MsgMapping(EIO, "EIO"),
MsgMapping(ENXIO, "ENXIO"),
MsgMapping(E2BIG, "E2BIG"),
MsgMapping(ENOEXEC, "ENOEXEC"),
MsgMapping(EBADF, "EBADF"),
MsgMapping(ECHILD, "ECHILD"),
MsgMapping(EAGAIN, "EAGAIN"),
MsgMapping(ENOMEM, "ENOMEM"),
MsgMapping(EACCES, "EACCES"),
MsgMapping(EFAULT, "EFAULT"),
MsgMapping(EBUSY, "EBUSY"),
MsgMapping(EEXIST, "EEXIST"),
MsgMapping(EXDEV, "EXDEV"),
MsgMapping(ENODEV, "ENODEV"),
MsgMapping(ENOTDIR, "ENOTDIR"),
MsgMapping(EISDIR, "EISDIR"),
MsgMapping(EINVAL, "EINVAL"),
MsgMapping(ENFILE, "ENFILE"),
MsgMapping(EMFILE, "EMFILE"),
MsgMapping(ENOTTY, "ENOTTY"),
MsgMapping(ETXTBSY, "ETXTBSY"),
MsgMapping(EFBIG, "EFBIG"),
MsgMapping(ENOSPC, "ENOSPC"),
MsgMapping(ESPIPE, "ESPIPE"),
MsgMapping(EROFS, "EROFS"),
MsgMapping(EMLINK, "EMLINK"),
MsgMapping(EPIPE, "EPIPE"),
MsgMapping(EDEADLK, "EDEADLK"),
MsgMapping(ENAMETOOLONG, "ENAMETOOLONG"),
MsgMapping(ENOLCK, "ENOLCK"),
MsgMapping(ENOSYS, "ENOSYS"),
MsgMapping(ENOTEMPTY, "ENOTEMPTY"),
MsgMapping(ELOOP, "ELOOP"),
MsgMapping(ENOMSG, "ENOMSG"),
MsgMapping(EIDRM, "EIDRM"),
MsgMapping(ENOSTR, "ENOSTR"),
MsgMapping(ENODATA, "ENODATA"),
MsgMapping(ETIME, "ETIME"),
MsgMapping(ENOSR, "ENOSR"),
MsgMapping(ENOLINK, "ENOLINK"),
MsgMapping(EPROTO, "EPROTO"),
MsgMapping(EMULTIHOP, "EMULTIHOP"),
MsgMapping(EBADMSG, "EBADMSG"),
MsgMapping(EOVERFLOW, "EOVERFLOW"),
MsgMapping(ENOTSOCK, "ENOTSOCK"),
MsgMapping(EDESTADDRREQ, "EDESTADDRREQ"),
MsgMapping(EMSGSIZE, "EMSGSIZE"),
MsgMapping(EPROTOTYPE, "EPROTOTYPE"),
MsgMapping(ENOPROTOOPT, "ENOPROTOOPT"),
MsgMapping(EPROTONOSUPPORT, "EPROTONOSUPPORT"),
MsgMapping(ENOTSUP, "ENOTSUP"),
MsgMapping(EAFNOSUPPORT, "EAFNOSUPPORT"),
MsgMapping(EADDRINUSE, "EADDRINUSE"),
MsgMapping(EADDRNOTAVAIL, "EADDRNOTAVAIL"),
MsgMapping(ENETDOWN, "ENETDOWN"),
MsgMapping(ENETUNREACH, "ENETUNREACH"),
MsgMapping(ENETRESET, "ENETRESET"),
MsgMapping(ECONNABORTED, "ECONNABORTED"),
MsgMapping(ECONNRESET, "ECONNRESET"),
MsgMapping(ENOBUFS, "ENOBUFS"),
MsgMapping(EISCONN, "EISCONN"),
MsgMapping(ENOTCONN, "ENOTCONN"),
MsgMapping(ETIMEDOUT, "ETIMEDOUT"),
MsgMapping(ECONNREFUSED, "ECONNREFUSED"),
MsgMapping(EHOSTUNREACH, "EHOSTUNREACH"),
MsgMapping(EALREADY, "EALREADY"),
MsgMapping(EINPROGRESS, "EINPROGRESS"),
MsgMapping(ESTALE, "ESTALE"),
MsgMapping(EDQUOT, "EDQUOT"),
MsgMapping(ECANCELED, "ECANCELED"),
MsgMapping(EOWNERDEAD, "EOWNERDEAD"),
MsgMapping(ENOTRECOVERABLE, "ENOTRECOVERABLE"),
};

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_TABLES_POSIX_ERRORS_H
7 changes: 7 additions & 0 deletions libc/src/__support/StringUtil/tables/stdc_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ LIBC_INLINE_VAR constexpr const MsgTable<4> STDC_ERRORS = {
MsgMapping(EILSEQ, "Invalid or incomplete multibyte or wide character"),
};

LIBC_INLINE_VAR constexpr const MsgTable<4> STDC_ERRNO_NAMES = {
MsgMapping(0, "0"),
MsgMapping(EDOM, "EDOM"),
MsgMapping(ERANGE, "ERANGE"),
MsgMapping(EILSEQ, "EILSEQ"),
};

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC___SUPPORT_STRINGUTIL_TABLES_STDC_ERRORS_H
5 changes: 5 additions & 0 deletions libc/src/stdio/printf_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ endif()
if(LIBC_CONF_PRINTF_DISABLE_FIXED_POINT)
list(APPEND printf_config_copts "-DLIBC_COPT_PRINTF_DISABLE_FIXED_POINT")
endif()
if(LIBC_CONF_PRINTF_DISABLE_STRERROR)
list(APPEND printf_config_copts "-DLIBC_COPT_PRINTF_DISABLE_STRERROR")
endif()
if(printf_config_copts)
list(PREPEND printf_config_copts "COMPILE_OPTIONS")
endif()
Expand Down Expand Up @@ -81,6 +84,7 @@ add_object_library(
float_hex_converter.h
float_dec_converter.h
fixed_converter.h #TODO: Check if this should be disabled when fixed unavail
strerror_converter.h
DEPENDS
.core_structs
.printf_config
Expand All @@ -97,6 +101,7 @@ add_object_library(
libc.src.__support.integer_to_string
libc.src.__support.libc_assert
libc.src.__support.uint128
libc.src.__support.StringUtil.error_to_string
)

add_object_library(
Expand Down
5 changes: 5 additions & 0 deletions libc/src/stdio/printf_core/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/stdio/printf_core/printf_config.h"
#include "src/stdio/printf_core/strerror_converter.h"
#include "src/stdio/printf_core/writer.h"

// This option allows for replacing all of the conversion functions with custom
Expand Down Expand Up @@ -84,6 +85,10 @@ int convert(Writer *writer, const FormatSection &to_conv) {
case 'K':
return convert_fixed(writer, to_conv);
#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR
case 'm':
return convert_strerror(writer, to_conv);
#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR
#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT
case 'n':
return convert_write_int(writer, to_conv);
Expand Down
5 changes: 5 additions & 0 deletions libc/src/stdio/printf_core/converter_atlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@
// defines convert_pointer
#include "src/stdio/printf_core/ptr_converter.h"

#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR
// defines convert_strerror
#include "src/stdio/printf_core/strerror_converter.h"
#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR

#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CONVERTER_ATLAS_H
14 changes: 12 additions & 2 deletions libc/src/stdio/printf_core/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
#include "src/__support/fixed_point/fx_rep.h"
#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR
#include "src/errno/libc_errno.h"
#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR

namespace LIBC_NAMESPACE_DECL {
namespace printf_core {
Expand Down Expand Up @@ -258,9 +261,16 @@ template <typename ArgProvider> class Parser {
}
break;
#endif // LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
#ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR
case ('m'):
// %m is an odd conversion in that it doesn't consume an argument, it
// just takes the current value of errno as its argument.
section.conv_val_raw = libc_errno;
break;
#endif // LIBC_COPT_PRINTF_DISABLE_STRERROR
#ifndef LIBC_COPT_PRINTF_DISABLE_WRITE_INT
case ('n'):
#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT
case ('n'): // Intentional fallthrough
#endif // LIBC_COPT_PRINTF_DISABLE_WRITE_INT
case ('p'):
WRITE_ARG_VAL_SIMPLEST(section.conv_val_ptr, void *, conv_index);
break;
Expand Down
Loading
Loading