From de43bdfa70b010b0f67e5f26b4cdd97617941e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Sun, 29 Dec 2019 15:46:01 +0100 Subject: [PATCH] generic stack trace overriding mechanism (#12922) * libbacktrace support * switch to a generic stack trace overriding mechanism When "nimStackTraceOverride" is defined, once of the imported modules can register its own procedure to replace the default stack trace generation by calling `registerStackTraceOverride(myOwnProc)`. Tested with `./koch boot -d:release --debugger:native -d:nimStackTraceOverride --import:libbacktrace` for the compiler itself and `./bin/nim c -r -f --stacktrace:off --debugger:native -d:nimStackTraceOverride --import:libbacktrace foo.nim` for an external program. * make the StackTraceOverrideProc {.noinline.} (cherry picked from commit ee9ee297d8d79ae17438343a6cb590906609f734) --- lib/system/excpt.nim | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 9cec924c9a29..c6de410b10f8 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -139,8 +139,23 @@ proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} = const nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and not NimStackTrace - hasSomeStackTrace = NimStackTrace or - defined(nativeStackTrace) and nativeStackTraceSupported + hasSomeStackTrace = NimStackTrace or defined(nimStackTraceOverride) or + (defined(nativeStackTrace) and nativeStackTraceSupported) + +when defined(nimStackTraceOverride): + type StackTraceOverrideProc* = proc (): string {.nimcall, noinline, benign, raises: [], tags: [].} + ## Procedure type for overriding the default stack trace. + + var stackTraceOverrideGetTraceback: StackTraceOverrideProc = proc(): string {.noinline.} = + result = "Stack trace override procedure not registered.\n" + + proc registerStackTraceOverride*(overrideProc: StackTraceOverrideProc) = + ## Override the default stack trace inside rawWriteStackTrace() with your + ## own procedure. + stackTraceOverrideGetTraceback = overrideProc + + proc auxWriteStackTraceWithOverride(s: var string) = + add(s, stackTraceOverrideGetTraceback()) when defined(nativeStacktrace) and nativeStackTraceSupported: type @@ -288,7 +303,10 @@ proc stackTraceAvailable*(): bool when hasSomeStackTrace: proc rawWriteStackTrace(s: var string) = - when NimStackTrace: + when defined(nimStackTraceOverride): + add(s, "Traceback (most recent call last, using override)\n") + auxWriteStackTraceWithOverride(s) + elif NimStackTrace: if framePtr == nil: add(s, "No stack traceback available\n") else: @@ -307,7 +325,9 @@ when hasSomeStackTrace: s = @[] proc stackTraceAvailable(): bool = - when NimStackTrace: + when defined(nimStackTraceOverride): + result = true + elif NimStackTrace: if framePtr == nil: result = false else: @@ -395,12 +415,15 @@ proc raiseExceptionAux(e: ref Exception) = proc raiseExceptionEx(e: ref Exception, ename, procname, filename: cstring, line: int) {.compilerRtl.} = if e.name.isNil: e.name = ename when hasSomeStackTrace: - if e.trace.len == 0: - rawWriteStackTrace(e.trace) - elif framePtr != nil: - e.trace.add reraisedFrom(reraisedFromBegin) - auxWriteStackTrace(framePtr, e.trace) - e.trace.add reraisedFrom(reraisedFromEnd) + when defined(nimStackTraceOverride): + e.trace = @[] + elif NimStackTrace: + if e.trace.len == 0: + rawWriteStackTrace(e.trace) + elif framePtr != nil: + e.trace.add reraisedFrom(reraisedFromBegin) + auxWriteStackTrace(framePtr, e.trace) + e.trace.add reraisedFrom(reraisedFromEnd) else: if procname != nil and filename != nil: e.trace.add StackTraceEntry(procname: procname, filename: filename, line: line)