added system.getStackTraceEntries
This commit is contained in:
parent
42be656b94
commit
661ce8b8cb
3 changed files with 77 additions and 22 deletions
|
|
@ -87,3 +87,5 @@ This now needs to be written as:
|
|||
- The ``nim doc`` command is now an alias for ``nim doc2``, the second version of
|
||||
the documentation generator. The old version 1 can still be accessed
|
||||
via the new ``nim doc0`` command.
|
||||
- Added ``system.getStackTraceEntries`` that allows you to access the stack
|
||||
trace in a structured manner without string parsing.
|
||||
|
|
|
|||
|
|
@ -456,6 +456,13 @@ type
|
|||
WriteIOEffect* = object of IOEffect ## Effect describing a write IO operation.
|
||||
ExecIOEffect* = object of IOEffect ## Effect describing an executing IO operation.
|
||||
|
||||
StackTraceEntry* = object ## In debug mode exceptions store the stack trace that led
|
||||
## to them. A StackTraceEntry is a single entry of the
|
||||
## stack trace.
|
||||
procname*: cstring ## name of the proc that is currently executing
|
||||
line*: int ## line number of the proc that is currently executing
|
||||
filename*: cstring ## filename of the proc that is currently executing
|
||||
|
||||
Exception* {.compilerproc.} = object of RootObj ## \
|
||||
## Base exception class.
|
||||
##
|
||||
|
|
@ -468,7 +475,10 @@ type
|
|||
msg* {.exportc: "message".}: string ## the exception's message. Not
|
||||
## providing an exception message
|
||||
## is bad style.
|
||||
trace: string
|
||||
when defined(js):
|
||||
trace: string
|
||||
else:
|
||||
trace: seq[StackTraceEntry]
|
||||
up: ref Exception # used for stacking exceptions. Not exported!
|
||||
|
||||
SystemError* = object of Exception ## \
|
||||
|
|
|
|||
|
|
@ -155,6 +155,52 @@ when not hasThreadSupport:
|
|||
var
|
||||
tempFrames: array[0..127, PFrame] # should not be alloc'd on stack
|
||||
|
||||
const
|
||||
reraisedFromBegin = -10
|
||||
reraisedFromEnd = -100
|
||||
|
||||
template reraisedFrom(z): untyped =
|
||||
StackTraceEntry(procname: nil, line: z, filename: nil)
|
||||
|
||||
proc auxWriteStackTrace(f: PFrame; s: var seq[StackTraceEntry]) =
|
||||
var
|
||||
it = f
|
||||
i = 0
|
||||
while it != nil:
|
||||
inc(i)
|
||||
it = it.prev
|
||||
var last = i-1
|
||||
if s.isNil:
|
||||
s = newSeq[StackTraceEntry](i)
|
||||
else:
|
||||
last = s.len + i - 1
|
||||
s.setLen(last+1)
|
||||
it = f
|
||||
while it != nil:
|
||||
s[last] = StackTraceEntry(procname: it.procname,
|
||||
line: it.line,
|
||||
filename: it.filename)
|
||||
it = it.prev
|
||||
dec last
|
||||
|
||||
template addFrameEntry(s, f: untyped) =
|
||||
var oldLen = s.len
|
||||
add(s, f.filename)
|
||||
if f.line > 0:
|
||||
add(s, '(')
|
||||
add(s, $f.line)
|
||||
add(s, ')')
|
||||
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
|
||||
add(s, f.procname)
|
||||
add(s, "\n")
|
||||
|
||||
proc `$`(s: seq[StackTraceEntry]): string =
|
||||
result = newStringOfCap(2000)
|
||||
for i in 0 .. s.len-1:
|
||||
if s[i].line == reraisedFromBegin: result.add "[[reraised from:\n"
|
||||
elif s[i].line == reraisedFromEnd: result.add "]]\n"
|
||||
else: addFrameEntry(result, s[i])
|
||||
|
||||
proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||
when hasThreadSupport:
|
||||
var
|
||||
|
|
@ -194,17 +240,9 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
|
|||
if tempFrames[j] == nil:
|
||||
add(s, "(")
|
||||
add(s, $skipped)
|
||||
add(s, " calls omitted) ...")
|
||||
add(s, " calls omitted) ...\n")
|
||||
else:
|
||||
var oldLen = s.len
|
||||
add(s, tempFrames[j].filename)
|
||||
if tempFrames[j].line > 0:
|
||||
add(s, '(')
|
||||
add(s, $tempFrames[j].line)
|
||||
add(s, ')')
|
||||
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
|
||||
add(s, tempFrames[j].procname)
|
||||
add(s, "\n")
|
||||
addFrameEntry(s, tempFrames[j])
|
||||
|
||||
proc stackTraceAvailable*(): bool
|
||||
|
||||
|
|
@ -221,6 +259,13 @@ when hasSomeStackTrace:
|
|||
auxWriteStackTraceWithBacktrace(s)
|
||||
else:
|
||||
add(s, "No stack traceback available\n")
|
||||
|
||||
proc rawWriteStackTrace(s: var seq[StackTraceEntry]) =
|
||||
when NimStackTrace:
|
||||
auxWriteStackTrace(framePtr, s)
|
||||
else:
|
||||
s = nil
|
||||
|
||||
proc stackTraceAvailable(): bool =
|
||||
when NimStackTrace:
|
||||
if framePtr == nil:
|
||||
|
|
@ -240,12 +285,6 @@ proc quitOrDebug() {.inline.} =
|
|||
else:
|
||||
endbStep() # call the debugger
|
||||
|
||||
when false:
|
||||
proc rawRaise*(e: ref Exception) =
|
||||
## undocumented. Do not use.
|
||||
pushCurrentException(e)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
|
||||
var onUnhandledException*: (proc (errorMsg: string) {.
|
||||
nimcall.}) ## set this error \
|
||||
## handler to override the existing behaviour on an unhandled exception.
|
||||
|
|
@ -282,7 +321,7 @@ proc raiseExceptionAux(e: ref Exception) =
|
|||
when hasSomeStackTrace:
|
||||
var buf = newStringOfCap(2000)
|
||||
if isNil(e.trace): rawWriteStackTrace(buf)
|
||||
else: add(buf, e.trace)
|
||||
else: add(buf, $e.trace)
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
if not isNil(e.msg): add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
|
|
@ -318,12 +357,11 @@ proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
|
|||
if e.name.isNil: e.name = ename
|
||||
when hasSomeStackTrace:
|
||||
if e.trace.isNil:
|
||||
e.trace = ""
|
||||
rawWriteStackTrace(e.trace)
|
||||
elif framePtr != nil:
|
||||
e.trace.add "[[reraised from:\n"
|
||||
e.trace.add reraisedFrom(reraisedFromBegin)
|
||||
auxWriteStackTrace(framePtr, e.trace)
|
||||
e.trace.add "]]\n"
|
||||
e.trace.add reraisedFrom(reraisedFromEnd)
|
||||
raiseExceptionAux(e)
|
||||
|
||||
proc reraiseException() {.compilerRtl.} =
|
||||
|
|
@ -349,10 +387,15 @@ proc getStackTrace(): string =
|
|||
|
||||
proc getStackTrace(e: ref Exception): string =
|
||||
if not isNil(e) and not isNil(e.trace):
|
||||
result = e.trace
|
||||
result = $e.trace
|
||||
else:
|
||||
result = ""
|
||||
|
||||
proc getStackTraceEntries*(e: ref Exception): seq[StackTraceEntry] =
|
||||
## Returns the attached stack trace to the exception ``e`` as
|
||||
## a ``seq``. This is not yet available for the JS backend.
|
||||
shallowCopy(result, e.trace)
|
||||
|
||||
when defined(nimRequiresNimFrame):
|
||||
proc stackOverflow() {.noinline.} =
|
||||
writeStackTrace()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue