From 9ddc1a6bfaef8669efd00b36fa1b699c04f6488d Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 25 Sep 2019 11:01:34 +1000 Subject: core/util: trap based assertions Using traps for assertions like Linux does gives a few advantages: - The asm code leading to the failure condition is nicer. - The interrupt gives a clean snapshot of machine state to dump. The difficulty with using traps for this in OPAL is that the runtime component will not deal well with the OS taking the 0x700 interrupt caused by a trap in OPAL. The long term goal is to improve the ability of the OS to inspect and debug OPAL at runtime. For now though, the traps are patched out before passing control to the OS, and the assert falls through to in-line failure handling. Signed-off-by: Nicholas Piggin [oliver: commit prefix, added and renamed the FWTS label, fix tests] Signed-off-by: Oliver O'Halloran --- libc/include/assert.h | 45 ++++++++++++++++++++++++++++++++++++++------- libc/include/stdlib.h | 7 +------ 2 files changed, 39 insertions(+), 13 deletions(-) (limited to 'libc') diff --git a/libc/include/assert.h b/libc/include/assert.h index 2c49fd7..1e511fb 100644 --- a/libc/include/assert.h +++ b/libc/include/assert.h @@ -13,17 +13,48 @@ #ifndef _ASSERT_H #define _ASSERT_H -#define assert(cond) \ - do { if (!(cond)) { \ - assert_fail(__FILE__ \ - ":" stringify(__LINE__) \ - ":" stringify(cond)); } \ - } while(0) +struct trap_table_entry { + unsigned long address; + const char *message; +}; -void __attribute__((noreturn)) assert_fail(const char *msg); +extern struct trap_table_entry __trap_table_start[]; +extern struct trap_table_entry __trap_table_end[]; #define stringify(expr) stringify_1(expr) /* Double-indirection required to stringify expansions */ #define stringify_1(expr) #expr +void __attribute__((noreturn)) assert_fail(const char *msg, + const char *file, + unsigned int line, + const char *function); + +/* + * The 'nop' gets patched to 'trap' after skiboot takes over the exception + * vectors, then patched to 'nop' before booting the OS (see patch_traps). + * This makes assert fall through to assert_fail when we can't use the 0x700 + * interrupt. + */ +#define assert(cond) \ +do { \ + /* evaluate cond exactly once */ \ + const unsigned long __cond = (unsigned long)(cond); \ + asm volatile( \ + " cmpdi %0,0" "\n\t" \ + " bne 2f" "\n\t" \ + "1: nop # assert" "\n\t" \ + "2:" "\n\t" \ + ".section .rodata" "\n\t" \ + "3: .string \"assert failed at " __FILE__ ":" stringify(__LINE__) "\"" "\n\t" \ + ".previous" "\n\t" \ + ".section .trap_table,\"aw\"" "\n\t" \ + ".llong 1b" "\n\t" \ + ".llong 3b" "\n\t" \ + ".previous" "\n\t" \ + : : "r"(__cond) : "cr0"); \ + if (!__cond) \ + assert_fail(stringify(cond), __FILE__, __LINE__, __FUNCTION__); \ +} while (0) + #endif diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index 234bd11..43d5c24 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -26,11 +26,6 @@ long int strtol(const char *nptr, char **endptr, int base); int rand(void); long int __attribute__((const)) labs(long int n); -void __attribute__((noreturn)) _abort(const char *msg); -#define abort() do { \ - _abort("abort():" __FILE__ \ - ":" stringify(__LINE__)); \ - } while(0) - +#define abort() assert(0) #endif -- cgit v1.1