From d46a29d919058fb383d19fe35c234fab58286f71 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Fri, 24 Sep 2021 10:59:47 +0200 Subject: libphobos: Define main function as extern(C) when compiling without D runtime (PR102476) The default supplied main function as read when compiling with `-fmain' has extern(D) linkage. However this does not work when mixing this option together with `-fno-druntime'. PR d/102476 gcc/testsuite/ChangeLog: * gdc.dg/pr102476.d: New test. libphobos/ChangeLog: * libdruntime/__main.di: Define main function as extern(C) when compiling without D runtime. --- libphobos/libdruntime/__main.di | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'libphobos/libdruntime') diff --git a/libphobos/libdruntime/__main.di b/libphobos/libdruntime/__main.di index 8062bf4..ab1264b 100644 --- a/libphobos/libdruntime/__main.di +++ b/libphobos/libdruntime/__main.di @@ -20,7 +20,17 @@ module __main; -int main(char[][]) +version (D_BetterC) { - return 0; + extern (C) int main(int, char**) + { + return 0; + } +} +else +{ + int main(char[][]) + { + return 0; + } } -- cgit v1.1 From efa5449a094d3887e124d400ff0410af2c745b2d Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sat, 25 Sep 2021 19:50:52 +0200 Subject: libphobos: Give _Unwind_Exception an alignment that best resembles __attribute__((aligned)) For interoperability with C++ EH, the alignment should match, otherwise D may not be able to intercept exceptions thrown from C++. libphobos/ChangeLog: * libdruntime/gcc/unwind/generic.d (__aligned__): Define. (_Unwind_Exception): Align struct to __aligned__. --- libphobos/libdruntime/gcc/unwind/generic.d | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'libphobos/libdruntime') diff --git a/libphobos/libdruntime/gcc/unwind/generic.d b/libphobos/libdruntime/gcc/unwind/generic.d index 592b3af..68ddd1d 100644 --- a/libphobos/libdruntime/gcc/unwind/generic.d +++ b/libphobos/libdruntime/gcc/unwind/generic.d @@ -123,7 +123,27 @@ enum : _Unwind_Reason_Code // @@@ The IA-64 ABI says that this structure must be double-word aligned. // Taking that literally does not make much sense generically. Instead we // provide the maximum alignment required by any type for the machine. -struct _Unwind_Exception + version (ARM) private enum __aligned__ = 8; +else version (AArch64) private enum __aligned__ = 16; +else version (HPPA) private enum __aligned__ = 8; +else version (HPPA64) private enum __aligned__ = 16; +else version (MIPS_N32) private enum __aligned__ = 16; +else version (MIPS_N64) private enum __aligned__ = 16; +else version (MIPS32) private enum __aligned__ = 8; +else version (MIPS64) private enum __aligned__ = 8; +else version (PPC) private enum __aligned__ = 16; +else version (PPC64) private enum __aligned__ = 16; +else version (RISCV32) private enum __aligned__ = 16; +else version (RISCV64) private enum __aligned__ = 16; +else version (S390) private enum __aligned__ = 8; +else version (SPARC) private enum __aligned__ = 8; +else version (SPARC64) private enum __aligned__ = 16; +else version (SystemZ) private enum __aligned__ = 8; +else version (X86) private enum __aligned__ = 16; +else version (X86_64) private enum __aligned__ = 16; +else static assert( false, "Platform not supported."); + +align(__aligned__) struct _Unwind_Exception { _Unwind_Exception_Class exception_class; _Unwind_Exception_Cleanup_Fn exception_cleanup; -- cgit v1.1 From 0111153234120de7f87b050df78f0d9819ca4214 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Fri, 24 Sep 2021 10:49:13 +0200 Subject: libphobos: Remove unused variables in gcc.backtrace. The core.runtime module always overrides the default parameter value for constructor calls. MaxAlignment is not required because a class can be created on the stack with the `scope' keyword. libphobos/ChangeLog: * libdruntime/core/runtime.d (runModuleUnitTests): Use scope to new LibBacktrace on the stack. * libdruntime/gcc/backtrace.d (FIRSTFRAME): Remove. (LibBacktrace.MaxAlignment): Remove. (LibBacktrace.this): Remove default initialization of firstFrame. (UnwindBacktrace.this): Likewise. --- libphobos/libdruntime/core/runtime.d | 14 +++----------- libphobos/libdruntime/gcc/backtrace.d | 24 ++---------------------- 2 files changed, 5 insertions(+), 33 deletions(-) (limited to 'libphobos/libdruntime') diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d index 848b607..5fc9904 100644 --- a/libphobos/libdruntime/core/runtime.d +++ b/libphobos/libdruntime/core/runtime.d @@ -483,17 +483,9 @@ extern (C) bool runModuleUnitTests() fprintf(stderr, "Segmentation fault while running unittests:\n"); fprintf(stderr, "----------------\n"); - enum alignment = LibBacktrace.MaxAlignment; - enum classSize = __traits(classInstanceSize, LibBacktrace); - - void[classSize + alignment] bt_store = void; - void* alignedAddress = cast(byte*)((cast(size_t)(bt_store.ptr + alignment - 1)) - & ~(alignment - 1)); - - (alignedAddress[0 .. classSize]) = typeid(LibBacktrace).initializer[]; - auto bt = cast(LibBacktrace)(alignedAddress); - // First frame is LibBacktrace ctor. Second is signal handler, but include that for now - bt.__ctor(1); + // First frame is LibBacktrace ctor. Second is signal handler, + // but include that for now + scope bt = new LibBacktrace(1); foreach (size_t i, const(char[]) msg; bt) fprintf(stderr, "%s\n", msg.ptr ? msg.ptr : "???"); diff --git a/libphobos/libdruntime/gcc/backtrace.d b/libphobos/libdruntime/gcc/backtrace.d index 8f5582d..3c4d65f 100644 --- a/libphobos/libdruntime/gcc/backtrace.d +++ b/libphobos/libdruntime/gcc/backtrace.d @@ -24,24 +24,6 @@ module gcc.backtrace; import gcc.libbacktrace; -version (Posix) -{ - // NOTE: The first 5 frames with the current implementation are - // inside core.runtime and the object code, so eliminate - // these for readability. The alternative would be to - // exclude the first N frames that are in a list of - // mangled function names. - private enum FIRSTFRAME = 5; -} -else -{ - // NOTE: On Windows, the number of frames to exclude is based on - // whether the exception is user or system-generated, so - // it may be necessary to exclude a list of function names - // instead. - private enum FIRSTFRAME = 0; -} - // Max size per line of the traceback. private enum MAX_BUFSIZE = 1536; @@ -205,8 +187,6 @@ static if (BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC) // FIXME: state is never freed as libbacktrace doesn't provide a free function... public class LibBacktrace : Throwable.TraceInfo { - enum MaxAlignment = (void*).alignof; - static void initLibBacktrace() { if (!initialized) @@ -216,7 +196,7 @@ static if (BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC) } } - this(int firstFrame = FIRSTFRAME) + this(int firstFrame) { _firstFrame = firstFrame; @@ -365,7 +345,7 @@ else */ public class UnwindBacktrace : Throwable.TraceInfo { - this(int firstFrame = FIRSTFRAME) + this(int firstFrame) { _firstFrame = firstFrame; _callstack = getBacktrace(); -- cgit v1.1 From ed3ec7343b7d104a3285336fbfc1e4719719f9b6 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sat, 25 Sep 2021 23:03:41 +0200 Subject: libphobos: Print stacktrace before terminating program due to uncaught exception. By default, D run-time has a top level exception handler to catch anything that was uncaught by user code. However when the `rt_trapExceptions' flag is cleared, this handler would not be enabled, and this termination would occur, aborting the program, but without any information about the exception. libphobos/ChangeLog: * libdruntime/gcc/deh.d (_d_print_throwable): Declare. (_d_throw): Print stacktrace before terminating program due to uncaught exception. --- libphobos/libdruntime/gcc/deh.d | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'libphobos/libdruntime') diff --git a/libphobos/libdruntime/gcc/deh.d b/libphobos/libdruntime/gcc/deh.d index eb83751c..a7eb37c 100644 --- a/libphobos/libdruntime/gcc/deh.d +++ b/libphobos/libdruntime/gcc/deh.d @@ -34,6 +34,7 @@ extern(C) { int _d_isbaseof(ClassInfo, ClassInfo); void _d_createTrace(Object, void*); + void _d_print_throwable(Throwable t); } /** @@ -510,7 +511,11 @@ extern(C) void _d_throw(Throwable object) // things, almost certainly we will have crashed before now, rather than // actually being able to diagnose the problem. if (r == _URC_END_OF_STACK) + { + __gdc_begin_catch(&eh.unwindHeader); + _d_print_throwable(object); terminate("uncaught exception", __LINE__); + } terminate("unwind error", __LINE__); } -- cgit v1.1 From 8088a33df5f62fd6416fb8cb158b791e639aa707 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sat, 25 Sep 2021 23:18:53 +0200 Subject: libphobos: Select the appropriate exception handler in getClassInfo This is analogous to __gdc_personality, which ignores in-flight exceptions that we haven't collided with yet. libphobos/ChangeLog: * libdruntime/gcc/deh.d (ExceptionHeader.getClassInfo): Move to... (getClassInfo): ...here as free function. Add lsda parameter. (scanLSDA): Pass lsda to actionTableLookup. (actionTableLookup): Add lsda parameter, pass to getClassInfo. (__gdc_personality): Remove currentCfa variable. --- libphobos/libdruntime/gcc/deh.d | 74 ++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 30 deletions(-) (limited to 'libphobos/libdruntime') diff --git a/libphobos/libdruntime/gcc/deh.d b/libphobos/libdruntime/gcc/deh.d index a7eb37c..ba57fed 100644 --- a/libphobos/libdruntime/gcc/deh.d +++ b/libphobos/libdruntime/gcc/deh.d @@ -280,26 +280,6 @@ struct ExceptionHeader } /** - * Look at the chain of inflight exceptions and pick the class type that'll - * be looked for in catch clauses. - */ - static ClassInfo getClassInfo(_Unwind_Exception* unwindHeader) @nogc - { - ExceptionHeader* eh = toExceptionHeader(unwindHeader); - // The first thrown Exception at the top of the stack takes precedence - // over others that are inflight, unless an Error was thrown, in which - // case, we search for error handlers instead. - Throwable ehobject = eh.object; - for (ExceptionHeader* ehn = eh.next; ehn; ehn = ehn.next) - { - Error e = cast(Error)ehobject; - if (e is null || (cast(Error)ehn.object) !is null) - ehobject = ehn.object; - } - return ehobject.classinfo; - } - - /** * Convert from pointer to unwindHeader to pointer to ExceptionHeader * that it is embedded inside of. */ @@ -666,7 +646,7 @@ _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class excepti { // Otherwise we have a catch handler or exception specification. handler = actionTableLookup(actions, unwindHeader, actionRecord, - exceptionClass, TTypeBase, + lsda, exceptionClass, TTypeBase, TType, TTypeEncoding, saw_handler, saw_cleanup); } @@ -694,7 +674,8 @@ _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class excepti * Look up and return the handler index of the classType in Action Table. */ int actionTableLookup(_Unwind_Action actions, _Unwind_Exception* unwindHeader, - const(ubyte)* actionRecord, _Unwind_Exception_Class exceptionClass, + const(ubyte)* actionRecord, const(ubyte)* lsda, + _Unwind_Exception_Class exceptionClass, _Unwind_Ptr TTypeBase, const(ubyte)* TType, ubyte TTypeEncoding, out bool saw_handler, out bool saw_cleanup) @@ -702,7 +683,7 @@ int actionTableLookup(_Unwind_Action actions, _Unwind_Exception* unwindHeader, ClassInfo thrownType; if (isGdcExceptionClass(exceptionClass)) { - thrownType = ExceptionHeader.getClassInfo(unwindHeader); + thrownType = getClassInfo(unwindHeader, lsda); } while (1) @@ -779,6 +760,41 @@ int actionTableLookup(_Unwind_Action actions, _Unwind_Exception* unwindHeader, } /** + * Look at the chain of inflight exceptions and pick the class type that'll + * be looked for in catch clauses. + */ +ClassInfo getClassInfo(_Unwind_Exception* unwindHeader, + const(ubyte)* currentLsd) @nogc +{ + ExceptionHeader* eh = ExceptionHeader.toExceptionHeader(unwindHeader); + // The first thrown Exception at the top of the stack takes precedence + // over others that are inflight, unless an Error was thrown, in which + // case, we search for error handlers instead. + Throwable ehobject = eh.object; + for (ExceptionHeader* ehn = eh.next; ehn; ehn = ehn.next) + { + const(ubyte)* nextLsd = void; + _Unwind_Ptr nextLandingPad = void; + _Unwind_Word nextCfa = void; + int nextHandler = void; + + ExceptionHeader.restore(&ehn.unwindHeader, nextHandler, nextLsd, nextLandingPad, nextCfa); + + // Don't combine when the exceptions are from different functions. + if (currentLsd != nextLsd) + break; + + Error e = cast(Error)ehobject; + if (e is null || (cast(Error)ehn.object) !is null) + { + currentLsd = nextLsd; + ehobject = ehn.object; + } + } + return ehobject.classinfo; +} + +/** * Called when the personality function has found neither a cleanup or handler. * To support ARM EABI personality routines, that must also unwind the stack. */ @@ -934,16 +950,15 @@ private _Unwind_Reason_Code __gdc_personality(_Unwind_Action actions, // current object onto the end of the prevous object. ExceptionHeader* eh = ExceptionHeader.toExceptionHeader(unwindHeader); auto currentLsd = lsda; - auto currentCfa = cfa; bool bypassed = false; while (eh.next) { ExceptionHeader* ehn = eh.next; - const(ubyte)* nextLsd; - _Unwind_Ptr nextLandingPad; - _Unwind_Word nextCfa; - int nextHandler; + const(ubyte)* nextLsd = void; + _Unwind_Ptr nextLandingPad = void; + _Unwind_Word nextCfa = void; + int nextHandler = void; ExceptionHeader.restore(&ehn.unwindHeader, nextHandler, nextLsd, nextLandingPad, nextCfa); @@ -952,14 +967,13 @@ private _Unwind_Reason_Code __gdc_personality(_Unwind_Action actions, { // We found an Error, bypass the exception chain. currentLsd = nextLsd; - currentCfa = nextCfa; eh = ehn; bypassed = true; continue; } // Don't combine when the exceptions are from different functions. - if (currentLsd != nextLsd && currentCfa != nextCfa) + if (currentLsd != nextLsd) break; // Add our object onto the end of the existing chain. -- cgit v1.1