From 23b83b30f554283aa0996a91e49b8234fc90a5fd Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Thu, 5 Dec 2024 18:55:37 +0000 Subject: [PATCH 01/12] detect musl libc in CMakeLists.txt This introduces the MUSL macro. --- CMakeLists.txt | 12 ++++++++++++ make/configure.cmake.h | 1 + 2 files changed, 13 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa5f9b5a899..c1f4c82a5a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,18 @@ if (APPLE) set(OLDEST_OSX_SUPPPORTED "11.7") elseif (UNIX) set(LINUX 1) + find_program(LDD ldd DOC "util for examing shared object dependency") + if (NOT LDD) + message(STATUS "Unable to find ldd: assume glibc") + else () + execute_process(COMMAND ${LDD} + RESULT_VARIABLE ldd_result + ERROR_VARIABLE ldd_err + OUTPUT_VARIABLE ldd_out) + if (ldd_err MATCHES "^musl libc") + set(MUSL 1) + endif () + endif () endif (APPLE) if (WIN32) set(WINDOWS 1) diff --git a/make/configure.cmake.h b/make/configure.cmake.h index 5af65a6c5f4..879519475d5 100644 --- a/make/configure.cmake.h +++ b/make/configure.cmake.h @@ -65,6 +65,7 @@ /* Used a lot due to the different TLS. We thus provide a convenience define. */ # define MACOS64 #endif +#cmakedefine MUSL /* host, when different */ #cmakedefine DR_HOST_X86 From d5b9e0b3636c71dde8ac3f286fa926588cfaa8bc Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 18:13:48 +0000 Subject: [PATCH 02/12] handle musl case in core/unix/include/siginfo.h bits/wordsize.h is a glibc-specific header, on musl __WORD_SIZE is defined as LONG_BIT. This is okay since Linux kernel assumes the size of long is equal to a machine word. --- core/unix/include/siginfo.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/unix/include/siginfo.h b/core/unix/include/siginfo.h index 28abb62ebed..779e5655f30 100644 --- a/core/unix/include/siginfo.h +++ b/core/unix/include/siginfo.h @@ -17,6 +17,7 @@ * undef them here. */ #include +#include #ifdef MACOS /* For now we just use the system header. */ @@ -33,6 +34,11 @@ typedef clock_t __clock_t; # ifndef __WORDSIZE # define __WORDSIZE 32 # endif +# elif !defined(__GLIBC__) +# define __WORDSIZE LONG_BIT + typedef uid_t __uid_t; + typedef pid_t __pid_t; + typedef clock_t __clock_t; # else # include # endif From bed244365179ba76bb263c67dcfe31293e843ef0 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 18:19:42 +0000 Subject: [PATCH 03/12] fix vendor elfutils build on musl The pre-defined config.h is adjusted to match musl's features. We also to build and link lib/error.c to provide functions for error message handling. --- ext/drsyms/CMakeLists.txt | 4 ++++ ext/drsyms/elfutils/config.h | 12 +++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/ext/drsyms/CMakeLists.txt b/ext/drsyms/CMakeLists.txt index 8a40bdb8aae..14aa751c83c 100644 --- a/ext/drsyms/CMakeLists.txt +++ b/ext/drsyms/CMakeLists.txt @@ -232,6 +232,10 @@ elseif (UNIX) # libdw uses pthread_rwlock_* routines. link_with_pthread(dw_pic) + if (MUSL) + target_sources(elf_pic PRIVATE "${elfutils_dir}/lib/error.c") + endif () + include_directories("${elfutils_dir}/libelf") include_directories("${elfutils_dir}/libdw") set(srcs ${srcs} drsyms_dw.c drsyms_elf.c) diff --git a/ext/drsyms/elfutils/config.h b/ext/drsyms/elfutils/config.h index bc684b2d518..e75ef5f74c3 100644 --- a/ext/drsyms/elfutils/config.h +++ b/ext/drsyms/elfutils/config.h @@ -33,7 +33,9 @@ /* Define if the GNU dcgettext() function is already present or preinstalled. */ -#define HAVE_DCGETTEXT 1 +#if !defined(__linux__) || defined(__GLIBC__) +# define HAVE_DCGETTEXT 1 +#endif /* Define to 1 if you have the declaration of `mempcpy', and to 0 if you don't. */ @@ -49,7 +51,9 @@ /* Define to 1 if you have the declaration of `rawmemchr', and to 0 if you don't. */ -#define HAVE_DECL_RAWMEMCHR 1 +#if !defined(__linux__) || defined(__GLIBC__) +# define HAVE_DECL_RAWMEMCHR 1 +#endif /* Define to 1 if you have the declaration of `reallocarray', and to 0 if you don't. */ @@ -60,7 +64,9 @@ #define HAVE_DECL_STRERROR_R 1 /* Define to 1 if you have the header file. */ -#define HAVE_ERROR_H 1 +#if !defined(__linux__) || defined(__GLIBC__) +# define HAVE_ERROR_H 1 +#endif /* Define to 1 if you have the header file. */ #define HAVE_ERR_H 1 From ec30b5877d4055cc1cefb2de85e2390948a21722 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 18:26:55 +0000 Subject: [PATCH 04/12] remove redundant warnings in core/unix/os.c As DynamoRIO enables -Werror by default, such warnings will prevent a warning-aware build. Since we also issue a warnings during start up, Let's remove it. --- core/unix/os.c | 1 - 1 file changed, 1 deletion(-) diff --git a/core/unix/os.c b/core/unix/os.c index 9d9becdb14f..e2487c18fe3 100644 --- a/core/unix/os.c +++ b/core/unix/os.c @@ -6418,7 +6418,6 @@ set_stdfile_fileno(stdfile_t **stdfile, file_t old_fd, file_t file_no) (*stdfile)->STDFILE_FILENO = file_no; # endif #else -# warning stdfile_t is opaque; DynamoRIO will not set fds of libc FILEs. /* i#1973: musl libc support (and potentially other non-glibcs) */ /* only called by handle_close_pre(), so warning is specific to that. */ SYSLOG_INTERNAL_WARNING_ONCE( From 6fcfa2b8ff6a3766f32b642f548826490a4527ba Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 18:30:56 +0000 Subject: [PATCH 05/12] fix test security-linux/trampolines on Alpine Linux GCC on Alpine Linux enables "-Wtrampolines" by default, breaking the test. Since Alpine is the most widely-used musl-based distribution, it's worth to work around this: let's defaults to -Wno-trampoline on musl systems. --- suite/tests/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 6ba6d409f91..3965a9b1bb4 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -425,6 +425,11 @@ function (set_cflags source) else () set(cflags "${ORIG_CMAKE_C_FLAGS}") endif () + # Alpine Linux enables "-Wtrampolines" by default, breaking + # security-linux/trampoline.c + if (MUSL) + set(cflags "${cflags} -Wno-trampolines") + endif () if ("${source}" MATCHES ".cpp$") # Our C files need -std=gnu99, but that's an invalid flag for C++. # configure_DynamoRIO_global removes unfavorable options for clients, From 0c8fc71cc32365a6158bc40f99f6bbd89a916109 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 19:02:21 +0000 Subject: [PATCH 06/12] disable test client.file_io on musl Some glibc-specific APIs are used in the test, we need to port them to musl. --- suite/tests/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/suite/tests/CMakeLists.txt b/suite/tests/CMakeLists.txt index 3965a9b1bb4..c550d09d373 100644 --- a/suite/tests/CMakeLists.txt +++ b/suite/tests/CMakeLists.txt @@ -2742,7 +2742,9 @@ else (UNIX) tobuild_ci(client.winxfer client-interface/winxfer.c "" "" "") endif (UNIX) -if (NOT APPLE OR NOT AARCH64) # TODO i#5383: Port to Mac M1. +# TODO i#5383: Port to Mac M1. +# TODO i#1973: Port to musl libc +if (NOT APPLE OR NOT AARCH64 AND NOT MUSL) tobuild_ci(client.file_io client-interface/file_io.c "${CMAKE_CURRENT_SOURCE_DIR}/client-interface/file_io_data.txt" "" "") endif () From 3f57b669c43db197a4f219209849a65cfed0c49a Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 19:05:10 +0000 Subject: [PATCH 07/12] workaround naming conflicts on musl DynamoRIO defines REG_* macros for compatibility with old clients, which conflict with signal.h on musl. Use of pragma push_macro/pop_macro to avoid messing musl's header up. --- suite/tests/tools.h | 55 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/suite/tests/tools.h b/suite/tests/tools.h index 442fbeda987..f4eccbdd19f 100644 --- a/suite/tests/tools.h +++ b/suite/tests/tools.h @@ -53,7 +53,62 @@ # include # include /* abort */ # include +# ifdef MUSL +# pragma push_macro("REG_R8") +# pragma push_macro("REG_R9") +# pragma push_macro("REG_R10") +# pragma push_macro("REG_R11") +# pragma push_macro("REG_R12") +# pragma push_macro("REG_R13") +# pragma push_macro("REG_R14") +# pragma push_macro("REG_R15") +# pragma push_macro("REG_RDI") +# pragma push_macro("REG_RSI") +# pragma push_macro("REG_RBP") +# pragma push_macro("REG_RBX") +# pragma push_macro("REG_RDX") +# pragma push_macro("REG_RAX") +# pragma push_macro("REG_RCX") +# pragma push_macro("REG_RSP") +# pragma push_macro("REG_CR2") +# undef REG_R8 +# undef REG_R9 +# undef REG_R10 +# undef REG_R11 +# undef REG_R12 +# undef REG_R13 +# undef REG_R14 +# undef REG_R15 +# undef REG_RDI +# undef REG_RSI +# undef REG_RBP +# undef REG_RBX +# undef REG_RDX +# undef REG_RAX +# undef REG_RCX +# undef REG_RSP +# undef REG_CR2 +# endif # include +# ifdef MUSL +# pragma pop_macro("REG_R8") +# pragma pop_macro("REG_R9") +# pragma pop_macro("REG_R10") +# pragma pop_macro("REG_R11") +# pragma pop_macro("REG_R12") +# pragma pop_macro("REG_R13") +# pragma pop_macro("REG_R14") +# pragma pop_macro("REG_R15") +# pragma pop_macro("REG_RDI") +# pragma pop_macro("REG_RSI") +# pragma pop_macro("REG_RBP") +# pragma pop_macro("REG_RBX") +# pragma pop_macro("REG_RDX") +# pragma pop_macro("REG_RAX") +# pragma pop_macro("REG_RCX") +# pragma pop_macro("REG_RSP") +# pragma pop_macro("REG_CR2") +# endif # ifdef MACOS # define _XOPEN_SOURCE \ 700 /* required to get POSIX, etc. defines out of ucontext.h */ From 0ae1cbf5a7117747fb1a7d056a927e3d80ec5d38 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 19:16:10 +0000 Subject: [PATCH 08/12] fix linux.signal* tests on musl libc --- suite/tests/linux/signal-base.h | 53 +++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/suite/tests/linux/signal-base.h b/suite/tests/linux/signal-base.h index 0cef7de7b5d..2bf1434c54d 100644 --- a/suite/tests/linux/signal-base.h +++ b/suite/tests/linux/signal-base.h @@ -77,6 +77,11 @@ static sigjmp_buf env; # define ITERS 500000 #endif +/* i#1973: __SIGRTMAX isn't available on musl libc */ +#ifdef MUSL +# define __SIGRTMAX SIGRTMAX +#endif + #ifdef AARCHXX /* i#4719: Work around QEMU bugs where QEMU can't handle signals 63 or 64. */ # undef SIGRTMAX @@ -151,25 +156,6 @@ static void break; } -#ifdef LINUX - case __SIGRTMAX: { - sigcontext_t *sc = SIGCXT_FROM_UCXT(ucxt); - void *pc = (void *)sc->SC_XIP; - /* SIGRTMAX has been 64 on Linux since kernel 2.1, from looking at glibc - * sources. */ -# ifndef AARCHXX /* i#4719: Work around QEMU bugs handling signals 63,64. */ - assert(__SIGRTMAX == 64); -# endif - assert(__SIGRTMAX == SIGRTMAX); -# if VERBOSE - print("Got SIGRTMAX @ 0x%08x\n", pc); -# else - print("Got SIGRTMAX\n"); -# endif - break; - } -#endif - #if USE_TIMER case SIGVTALRM: { sigcontext_t *sc = SIGCXT_FROM_UCXT(ucxt); @@ -182,7 +168,28 @@ static void } #endif - default: assert(0); + default: + /* i#1973: SIGRTMAX is a macro over function call, rather a constant on + musl libc. We use an if branch in default block to handle this */ +#ifdef LINUX + if (sig == __SIGRTMAX) { + sigcontext_t *sc = SIGCXT_FROM_UCXT(ucxt); + void *pc = (void *)sc->SC_XIP; + /* SIGRTMAX has been 64 on Linux since kernel 2.1, from looking at glibc + * sources. */ +# ifndef AARCHXX /* i#4719: Work around QEMU bugs handling signals 63,64. */ + assert(__SIGRTMAX == 64); +# endif + assert(__SIGRTMAX == SIGRTMAX); +# if VERBOSE + print("Got SIGRTMAX @ 0x%08x\n", pc); +# else + print("Got SIGRTMAX\n"); +# endif + break; + } +#endif + assert(0); } } @@ -319,9 +326,9 @@ int print("Got some timer hits!\n"); #endif - /* We leave the sigstack in place for the timer so any racy alarm arriving - * after we disabled the itimer will be on the alt stack. - */ + /* We leave the sigstack in place for the timer so any racy alarm arriving + * after we disabled the itimer will be on the alt stack. + */ #if USE_SIGSTACK && !USE_TIMER stack_t check_stack; rc = sigaltstack(NULL, &check_stack); From 05b5c20276f130558f96822e7a37c67b6854c85f Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 19:23:33 +0000 Subject: [PATCH 09/12] fix suite/tests/tools.c on musl --- suite/tests/tools.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/suite/tests/tools.c b/suite/tests/tools.c index 44560c533f0..9ba23bc58b5 100644 --- a/suite/tests/tools.c +++ b/suite/tests/tools.c @@ -381,6 +381,9 @@ nolibc_print(const char *str) 3, # if defined(MACOS) || defined(ANDROID) stderr->_file, + /* TODO i#1973: handle opaque FILE * on musl libc */ +# elif defined(MUSL) + STDERR_FILENO, # else stderr->_fileno, # endif From 733aa8cfb52e70a3f209a34f2f6d6487c7ce4575 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 20:02:49 +0000 Subject: [PATCH 10/12] fix indentation --- core/unix/include/siginfo.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/unix/include/siginfo.h b/core/unix/include/siginfo.h index 779e5655f30..89c8568166f 100644 --- a/core/unix/include/siginfo.h +++ b/core/unix/include/siginfo.h @@ -35,10 +35,10 @@ typedef clock_t __clock_t; # define __WORDSIZE 32 # endif # elif !defined(__GLIBC__) -# define __WORDSIZE LONG_BIT - typedef uid_t __uid_t; - typedef pid_t __pid_t; - typedef clock_t __clock_t; +# define __WORDSIZE LONG_BIT + typedef uid_t __uid_t; + typedef pid_t __pid_t; + typedef clock_t __clock_t; # else # include # endif From 400105e44303e48b86a487e08de00cb68c76e420 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 20:09:07 +0000 Subject: [PATCH 11/12] fix style --- core/unix/include/siginfo.h | 6 +++--- suite/tests/tools.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/unix/include/siginfo.h b/core/unix/include/siginfo.h index 89c8568166f..68be32146cd 100644 --- a/core/unix/include/siginfo.h +++ b/core/unix/include/siginfo.h @@ -36,9 +36,9 @@ typedef clock_t __clock_t; # endif # elif !defined(__GLIBC__) # define __WORDSIZE LONG_BIT - typedef uid_t __uid_t; - typedef pid_t __pid_t; - typedef clock_t __clock_t; +typedef uid_t __uid_t; +typedef pid_t __pid_t; +typedef clock_t __clock_t; # else # include # endif diff --git a/suite/tests/tools.c b/suite/tests/tools.c index 9ba23bc58b5..87feabf4cba 100644 --- a/suite/tests/tools.c +++ b/suite/tests/tools.c @@ -381,7 +381,7 @@ nolibc_print(const char *str) 3, # if defined(MACOS) || defined(ANDROID) stderr->_file, - /* TODO i#1973: handle opaque FILE * on musl libc */ + /* TODO i#1973: handle opaque FILE * on musl libc */ # elif defined(MUSL) STDERR_FILENO, # else From 7aaaba70b131f91829473c867e59462824527914 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Mon, 23 Dec 2024 20:13:57 +0000 Subject: [PATCH 12/12] fix style in signal-base.h --- suite/tests/linux/signal-base.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/suite/tests/linux/signal-base.h b/suite/tests/linux/signal-base.h index 2bf1434c54d..33bf99ea5bf 100644 --- a/suite/tests/linux/signal-base.h +++ b/suite/tests/linux/signal-base.h @@ -326,9 +326,9 @@ int print("Got some timer hits!\n"); #endif - /* We leave the sigstack in place for the timer so any racy alarm arriving - * after we disabled the itimer will be on the alt stack. - */ + /* We leave the sigstack in place for the timer so any racy alarm arriving + * after we disabled the itimer will be on the alt stack. + */ #if USE_SIGSTACK && !USE_TIMER stack_t check_stack; rc = sigaltstack(NULL, &check_stack);