summaryrefslogtreecommitdiff
path: root/libmisc
diff options
context:
space:
mode:
Diffstat (limited to 'libmisc')
-rw-r--r--libmisc/CMakeLists.txt1
-rw-r--r--libmisc/assert.c4
-rw-r--r--libmisc/include/libmisc/_intercept.h21
-rw-r--r--libmisc/include/libmisc/log.h9
-rw-r--r--libmisc/intercept.c25
-rw-r--r--libmisc/log.c10
-rw-r--r--libmisc/tests/test_assert.c18
-rw-r--r--libmisc/tests/test_log.c47
-rw-r--r--libmisc/tests/test_rand.c13
9 files changed, 94 insertions, 54 deletions
diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt
index 5052f29..8d842c3 100644
--- a/libmisc/CMakeLists.txt
+++ b/libmisc/CMakeLists.txt
@@ -7,6 +7,7 @@ add_library(libmisc INTERFACE)
target_include_directories(libmisc SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_sources(libmisc INTERFACE
assert.c
+ intercept.c
log.c
)
target_compile_options(libmisc INTERFACE "$<$<COMPILE_LANGUAGE:C>:-fplan9-extensions>")
diff --git a/libmisc/assert.c b/libmisc/assert.c
index 8231c85..69c0530 100644
--- a/libmisc/assert.c
+++ b/libmisc/assert.c
@@ -5,7 +5,6 @@
*/
#include <stdbool.h> /* for bool, true, false */
-#include <stdlib.h> /* for abort() */
#define LOG_NAME ASSERT
#include <libmisc/log.h> /* for errorf() */
@@ -13,7 +12,6 @@
#include <libmisc/assert.h>
#ifndef NDEBUG
-[[noreturn, gnu::weak]]
void __assert_msg_fail(const char *expr,
const char *file, unsigned int line, const char *func,
const char *msg) {
@@ -26,6 +24,6 @@ void __assert_msg_fail(const char *expr,
msg ? ": " : "", msg ?: "");
in_fail = false;
}
- abort();
+ __lm_abort();
}
#endif
diff --git a/libmisc/include/libmisc/_intercept.h b/libmisc/include/libmisc/_intercept.h
new file mode 100644
index 0000000..47e4620
--- /dev/null
+++ b/libmisc/include/libmisc/_intercept.h
@@ -0,0 +1,21 @@
+/* libmisc/_intercept.h - Interceptable ("weak") functions
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC__INTERCEPT_H_
+#define _LIBMISC__INTERCEPT_H_
+
+/* pico-sdk/newlib define these to be [[gnu:weak]] already, but
+ * depending on optimization options glibc might not, and GCC might
+ * assume it knows what they do and optimize them out. So define our
+ * own `__lm_` wrappers that GCC/glibc won't interfere with.
+ */
+
+[[format(printf, 1, 2)]]
+int __lm_printf(const char *format, ...);
+
+[[noreturn]] void __lm_abort(void);
+
+#endif /* _LIBMISC__INTERCEPT_H_ */
diff --git a/libmisc/include/libmisc/log.h b/libmisc/include/libmisc/log.h
index 8c6d6be..121b0e1 100644
--- a/libmisc/include/libmisc/log.h
+++ b/libmisc/include/libmisc/log.h
@@ -10,6 +10,7 @@
#include <stdint.h> /* for uint8_t */
#include <libmisc/macro.h>
+#include <libmisc/_intercept.h>
#ifndef LOG_NAME
#error "each compilation unit that includes <libmisc/log.h> must define LOG_NAME"
@@ -21,12 +22,10 @@
#define _LOG_NDEBUG 0
#endif
-[[format(printf, 1, 2)]] int _log_printf(const char *format, ...);
-
-#define n_errorf(nam, fmt, ...) do { _log_printf("error: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
-#define n_infof(nam, fmt, ...) do { _log_printf("info : " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+#define n_errorf(nam, fmt, ...) do { __lm_printf("error: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+#define n_infof(nam, fmt, ...) do { __lm_printf("info : " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
#define n_debugf(nam, fmt, ...) do { if (LM_CAT3_(CONFIG_, nam, _DEBUG) && !_LOG_NDEBUG) \
- _log_printf("debug: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+ __lm_printf("debug: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
#define errorf(fmt, ...) n_errorf(LOG_NAME, fmt, __VA_ARGS__)
#define infof(fmt, ...) n_infof(LOG_NAME, fmt, __VA_ARGS__)
diff --git a/libmisc/intercept.c b/libmisc/intercept.c
new file mode 100644
index 0000000..dda8c09
--- /dev/null
+++ b/libmisc/intercept.c
@@ -0,0 +1,25 @@
+/* libmisc/intercept.c - Interceptable ("weak") functions
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <stdarg.h> /* for va_list, va_start(), va_end() */
+#include <stdio.h> /* for vprintf() */
+#include <stdlib.h> /* for abort() */
+
+#include <libmisc/_intercept.h>
+
+[[gnu::weak]]
+int __lm_printf(const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int ret = vprintf(format, va);
+ va_end(va);
+ return ret;
+}
+
+[[gnu::weak]]
+void __lm_abort(void) {
+ abort();
+}
diff --git a/libmisc/log.c b/libmisc/log.c
index 9bf5366..ff4dac6 100644
--- a/libmisc/log.c
+++ b/libmisc/log.c
@@ -7,19 +7,11 @@
#include <stdio.h> /* for vprintf() */
#include <stdarg.h> /* for va_list, va_start(), va_end() */
-#include <libmisc/assert.h>
+#include <libmisc/assert.h> /* for static_assert() */
#define LOG_NAME
#include <libmisc/log.h>
-int _log_printf(const char *format, ...) {
- va_list va;
- va_start(va, format);
- int ret = vprintf(format, va);
- va_end(va);
- return ret;
-}
-
static const char *byte_strs[] = {
"0x00",
"0x01",
diff --git a/libmisc/tests/test_assert.c b/libmisc/tests/test_assert.c
index 189f6de..0c51bbd 100644
--- a/libmisc/tests/test_assert.c
+++ b/libmisc/tests/test_assert.c
@@ -5,12 +5,14 @@
*/
#include <setjmp.h>
+#include <stdarg.h> /* for va_list, va_start(), va_end() */
#include <stdbool.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <libmisc/macro.h>
#include <libmisc/assert.h>
+#include <libmisc/_intercept.h>
#include "test.h"
@@ -28,17 +30,21 @@ jmp_buf global_env;
setjmp(global_env) == 0; \
})
-[[noreturn]] void abort(void) {
+void __lm_abort(void) {
global_failed = true;
longjmp(global_env, 1);
}
-#define __builtin_unreachable() test_assert(0)
-
-int vprintf(const char *format, va_list ap) {
- return vasprintf(&global_log, format, ap);
+int __lm_printf(const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int ret = vasprintf(&global_log, format, va);
+ va_end(va);
+ return ret;
}
+#define __builtin_unreachable() test_assert(0)
+
/* Utilities ******************************************************************/
#define test_should_succeed(test) do { \
diff --git a/libmisc/tests/test_log.c b/libmisc/tests/test_log.c
index 286738d..e819c09 100644
--- a/libmisc/tests/test_log.c
+++ b/libmisc/tests/test_log.c
@@ -13,36 +13,43 @@
#define LOG_NAME FROBNICATE
#include <libmisc/log.h>
+#include <libmisc/_intercept.h>
+
#include "test.h"
/* Intercept output ***********************************************************/
static char *log_output = NULL;
-int vprintf(const char *format, va_list ap) {
- return vasprintf(&log_output, format, ap);
+int __lm_printf(const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ int ret = vasprintf(&log_output, format, va);
+ va_end(va);
+ return ret;
}
/* Actual tests ***************************************************************/
-#define should_print(_exp, cmd) do { \
- char *exp = _exp; \
- test_assert(!log_output); \
- cmd; \
- if (!exp) \
- test_assert(!log_output); \
- else \
- if (!(log_output != NULL && \
- strcmp(log_output, exp) == 0)) { \
- printf("exp = \"%s\"\n" \
- "act = \"%s\"\n", \
- exp, log_output); \
- test_assert(0); \
- } \
- if (log_output) { \
- free(log_output); \
- log_output = NULL; \
- } \
+#define should_print(_exp, cmd) do { \
+ char *exp = _exp; \
+ test_assert(!log_output); \
+ cmd; \
+ if (!exp) \
+ test_assert(!log_output); \
+ else { \
+ test_assert(log_output); \
+ if (strcmp(log_output, exp)) { \
+ printf("exp = \"%s\"\n" \
+ "act = \"%s\"\n", \
+ exp, log_output); \
+ test_assert(0); \
+ } \
+ } \
+ if (log_output) { \
+ free(log_output); \
+ log_output = NULL; \
+ } \
} while (0)
int main() {
diff --git a/libmisc/tests/test_rand.c b/libmisc/tests/test_rand.c
index fff1b27..295ea61 100644
--- a/libmisc/tests/test_rand.c
+++ b/libmisc/tests/test_rand.c
@@ -8,6 +8,7 @@
#include <setjmp.h>
#include <libmisc/rand.h>
+#include <libmisc/_intercept.h>
#include "test.h"
@@ -15,19 +16,9 @@
jmp_buf *__catch;
-void __assert_msg_fail(const char *expr,
- const char *file, unsigned int line, const char *func,
- const char *msg) {
- static bool in_fail = false;
+void __lm_abort(void) {
if (__catch)
longjmp(*__catch, 1);
- if (!in_fail) {
- in_fail = true;
- printf("error: %s:%u:%s(): assertion \"%s\" failed%s%s\n",
- file, line, func,
- expr,
- msg ? ": " : "", msg);
- }
abort();
}