summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
authorȘtefan Talpalaru <stefantalpalaru@yahoo.com>2019-12-29 15:46:01 +0100
committerAndreas Rumpf <rumpf_a@web.de>2019-12-29 15:46:01 +0100
commitee9ee297d8d79ae17438343a6cb590906609f734 (patch)
tree5404ecae45279a44877ac58e041ba0c50ce92fc8 /lib/system
parent37e93eab668d836826be9eb334bb77bcf95f38af (diff)
downloadNim-ee9ee297d8d79ae17438343a6cb590906609f734.tar.gz
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.}
Diffstat (limited to 'lib/system')
-rw-r--r--lib/system/excpt.nim43
1 files changed, 33 insertions, 10 deletions
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 6e06b10f8..140cd00b8 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -140,8 +140,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
@@ -289,7 +304,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:
@@ -308,7 +326,9 @@ when hasSomeStackTrace:
       s = @[]
 
   proc stackTraceAvailable(): bool =
-    when NimStackTrace:
+    when defined(nimStackTraceOverride):
+      result = true
+    elif NimStackTrace:
       if framePtr == nil:
         result = false
       else:
@@ -443,12 +463,15 @@ proc raiseExceptionEx(e: sink(ref Exception), ename, procname, filename: cstring
                       line: int) {.compilerRtl, nodestroy.} =
   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)