diff --git a/libc/log/getsymbol.c b/libc/log/getsymbol.c new file mode 100644 index 000000000..5633d4741 --- /dev/null +++ b/libc/log/getsymbol.c @@ -0,0 +1,39 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/alg/bisectcarleft.internal.h" +#include "libc/log/log.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/symbols.internal.h" + +/** + * Returns name of symbol at address. + */ +char *GetSymbolByAddr(int64_t addr) { + struct SymbolTable *st; + if ((st = GetSymbolTable()) && st->count && + ((intptr_t)addr >= (intptr_t)&_base && + (intptr_t)addr <= (intptr_t)&_end)) { + return st->name_base + + st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols, + st->count, addr - st->addr_base)] + .name_rva; + } else { + return 0; + } +} diff --git a/libc/log/log.h b/libc/log/log.h index db523ee78..da27f8129 100644 --- a/libc/log/log.h +++ b/libc/log/log.h @@ -55,6 +55,9 @@ bool32 IsDebuggerPresent(bool); bool IsRunningUnderMake(void); const char *GetSiCodeName(int, int); void AppendResourceReport(char **, struct rusage *, const char *); +char *GetSymbolByAddr(int64_t); +void PrintGarbage(FILE *); +void PrintGarbageNumeric(FILE *); #define showcrashreports() ShowCrashReports() diff --git a/libc/log/printgarbage.c b/libc/log/printgarbage.c new file mode 100644 index 000000000..30bfecb8c --- /dev/null +++ b/libc/log/printgarbage.c @@ -0,0 +1,42 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/log.h" +#include "libc/nexgen32e/gc.internal.h" +#include "libc/stdio/stdio.h" +/* clang-format off */ + +/** + * Prints list of deferred operations on shadow stack. + */ +void PrintGarbage(FILE *f) { + size_t i; + f = stderr; + fprintf(f, "\n"); + fprintf(f, " SHADOW STACK @ 0x%016lx\n", __builtin_frame_address(0)); + fprintf(f, " garbage entry parent frame original ret callback arg \n"); + fprintf(f, "-------------- -------------- ------------------ ------------------ ------------------\n"); + for (i = __garbage.i; i--;) { + fprintf(f, "0x%012lx 0x%012lx %-18s %-18s 0x%016lx\n", + __garbage.p + i, + __garbage.p[i].frame, + GetSymbolByAddr(__garbage.p[i].ret-1), + GetSymbolByAddr(__garbage.p[i].fn), + __garbage.p[i].arg); + } +} diff --git a/libc/log/printgarbagenumeric.c b/libc/log/printgarbagenumeric.c new file mode 100644 index 000000000..a88e5f718 --- /dev/null +++ b/libc/log/printgarbagenumeric.c @@ -0,0 +1,42 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/log.h" +#include "libc/nexgen32e/gc.internal.h" +#include "libc/stdio/stdio.h" +/* clang-format off */ + +/** + * Prints list of deferred operations on shadow stack w/o symbols. + */ +void PrintGarbageNumeric(FILE *f) { + size_t i; + f = stderr; + fprintf(f, "\n"); + fprintf(f, " SHADOW STACK @ 0x%016lx\n", __builtin_frame_address(0)); + fprintf(f, " garbage entry parent frame original ret callback arg \n"); + fprintf(f, "-------------- -------------- ------------------ ------------------ ------------------\n"); + for (i = __garbage.i; i--;) { + fprintf(f, "0x%012lx 0x%012lx 0x%016lx 0x%016lx 0x%016lx\n", + __garbage.p + i, + __garbage.p[i].frame, + __garbage.p[i].ret, + __garbage.p[i].fn, + __garbage.p[i].arg); + } +} diff --git a/libc/mem/defer.greg.c b/libc/mem/defer.greg.c index 6df5e0f9c..768763d56 100644 --- a/libc/mem/defer.greg.c +++ b/libc/mem/defer.greg.c @@ -42,7 +42,7 @@ void __deferer(struct StackFrame *frame, void *fn, void *arg) { __garbage.p = p2; __garbage.n = n2; } - __garbage.p[__garbage.i].frame = frame->next; + __garbage.p[__garbage.i].frame = frame; __garbage.p[__garbage.i].fn = (intptr_t)fn; __garbage.p[__garbage.i].arg = (intptr_t)arg; __garbage.p[__garbage.i].ret = frame->addr; diff --git a/libc/nexgen32e/gc.S b/libc/nexgen32e/gc.S index a337e3909..782c59a90 100644 --- a/libc/nexgen32e/gc.S +++ b/libc/nexgen32e/gc.S @@ -19,6 +19,7 @@ #include "libc/macros.internal.h" #include "libc/dce.h" #include "libc/notice.inc" + #define INITIAL_CAPACITY 4 // Invokes deferred function calls. @@ -44,19 +45,17 @@ __gc: decq __garbage(%rip) // push %rbp mov %rsp,%rbp - sub $0x20,%rsp + sub $16,%rsp push %rax push %rdx - movdqa %xmm0,-0x20(%rbp) - movdqa %xmm1,-0x10(%rbp) + movdqa %xmm0,-16(%rbp) call *%r9 - movdqa -0x10(%rbp),%xmm1 - movdqa -0x20(%rbp),%xmm0 + movdqa -16(%rbp),%xmm0 pop %rdx pop %rax leave ret -9: call abort +9: hlt .endfn __gc,globl,hidden .source __FILE__ diff --git a/libc/nexgen32e/gclongjmp.S b/libc/nexgen32e/gclongjmp.S index 3787e30e4..200a3b1eb 100644 --- a/libc/nexgen32e/gclongjmp.S +++ b/libc/nexgen32e/gclongjmp.S @@ -30,29 +30,27 @@ // @see examples/ctrlc.c // @noreturn _gclongjmp: - .leafprologue + push %rbp + mov %rsp,%rbp .profilable - .weak __garbage lea __garbage(%rip),%r12 - test %r12,%r12 + mov (%r12),%r13 # garbage.i + test %r13,%r13 jnz .L.unwind.destructors 0: jmp longjmp .L.unwind.destructors: push %rdi push %rsi - mov (%r12),%r13 # garbage.i mov 16(%r12),%r14 # garbage.p mov (%rdi),%r15 # jmp_buf[0] is new %rsp - shl $5,%r13 -1: test %r13,%r13 - jz 2f - sub $32,%r13 - cmp (%r14,%r13),%r15 - ja 2f - mov 8(%r14,%r13),%rax # garbage.p[𝑖].fn + shl $5,%r13 # log2(sizeof(struct Garbage)) +1: sub $32,%r13 # 𝑖-- + js 2f + cmp (%r14,%r13),%r15 # new %rsp > garbage.p[𝑖].frame + jbe 2f mov 16(%r14,%r13),%rdi # garbage.p[𝑖].arg - call *%rax - decq (%r12) + callq *8(%r14,%r13) # garbage.p[𝑖].fn + decq (%r12) # garbage.i-- jmp 1b 2: pop %rsi pop %rdi diff --git a/libc/nexgen32e/longjmp.S b/libc/nexgen32e/longjmp.S index 223d2b5ad..e4e2666ae 100644 --- a/libc/nexgen32e/longjmp.S +++ b/libc/nexgen32e/longjmp.S @@ -27,7 +27,8 @@ // @assume system five nexgen32e abi conformant // @note code built w/ microsoft abi compiler can't call this // @see _gclongjmp() unwinds _gc() destructors -longjmp:mov %esi,%eax +longjmp: + mov %esi,%eax test %eax,%eax jnz 1f inc %eax diff --git a/libc/runtime/gc.internal.h b/libc/runtime/gc.internal.h index b077b118d..fb4a7ce92 100644 --- a/libc/runtime/gc.internal.h +++ b/libc/runtime/gc.internal.h @@ -3,8 +3,9 @@ #include "libc/runtime/gc.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) -#define gc(THING) _gc(THING) -#define defer(FN, ARG) _defer(FN, ARG) +#define gc(THING) _gc(THING) +#define defer(FN, ARG) _defer(FN, ARG) +#define gclongjmp(JB, ARG) _gclongjmp(JB, ARG) #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_RUNTIME_GC_INTERNAL_H_ */ diff --git a/test/libc/nexgen32e/gclongjmp_test.c b/test/libc/nexgen32e/gclongjmp_test.c new file mode 100644 index 000000000..a000df1fb --- /dev/null +++ b/test/libc/nexgen32e/gclongjmp_test.c @@ -0,0 +1,75 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/log.h" +#include "libc/nexgen32e/gc.internal.h" +#include "libc/nexgen32e/nexgen32e.h" +#include "libc/runtime/gc.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +#undef _gc +#define _gc(x) _defer(Free, x) + +char *x; +char *y; +char *z; +jmp_buf jb; + +void Free(char *p) { + strcpy(p, "FREE"); +} + +void C(void) { + x = _gc(strdup("abcd")); + if (0) PrintGarbage(stderr); + _gclongjmp(jb, 1); + abort(); +} + +void B(void C(void)) { + y = _gc(strdup("HIHI")); + C(); + abort(); +} + +void A(void C(void), void B(void(void))) { + z = _gc(strdup("yoyo")); + B(C); + abort(); +} + +void (*Ap)(void(void), void(void(void))) = A; +void (*Bp)(void(void)) = B; +void (*Cp)(void) = C; + +TEST(gclongjmp, test) { + if (!setjmp(jb)) { + Ap(Cp, Bp); + abort(); + } + EXPECT_STREQ("FREE", x); + EXPECT_STREQ("FREE", y); + EXPECT_STREQ("FREE", z); + free(z); + free(y); + free(x); +} diff --git a/third_party/lua/ltests.c b/third_party/lua/ltests.c index da4ebcb15..7658c8c40 100644 --- a/third_party/lua/ltests.c +++ b/third_party/lua/ltests.c @@ -1238,7 +1238,7 @@ static int panicback (lua_State *L) { b = (struct Aux *)lua_touserdata(L, -1); lua_pop(L, 1); /* remove 'Aux' struct */ runC(b->L, L, b->paniccode); /* run optional panic code */ - longjmp(b->jb, 1); + _gclongjmp(b->jb, 1); return 1; /* to avoid warnings */ } diff --git a/third_party/lua/lua.main.c b/third_party/lua/lua.main.c index 1a32a0600..95adf2c4e 100644 --- a/third_party/lua/lua.main.c +++ b/third_party/lua/lua.main.c @@ -646,7 +646,7 @@ static int pmain (lua_State *L) { int main (int argc, char **argv) { int status, result; lua_State *L; - if (IsModeDbg()) ShowCrashReports(); + /* if (IsModeDbg()) ShowCrashReports(); */ L = luaL_newstate(); /* create state */ if (L == NULL) { l_message(argv[0], "cannot create state: not enough memory");