Remove ENDB (#12095)

This commit is contained in:
Clyybber
2019-08-31 07:44:53 +02:00
committed by Andreas Rumpf
parent 82d5e773e3
commit f9600b7207
16 changed files with 19 additions and 1216 deletions

View File

@@ -1161,36 +1161,10 @@ proc genEmit(p: BProc, t: PNode) =
genLineDir(p, t)
line(p, cpsStmts, s)
proc genBreakPoint(p: BProc, t: PNode) =
var name: string
if optEndb in p.options:
if t.kind == nkExprColonExpr:
assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
name = normalize(t.sons[1].strVal)
else:
inc(p.module.g.breakPointId)
name = "bp" & $p.module.g.breakPointId
genLineDir(p, t) # BUGFIX
appcg(p.module, p.module.g.breakpoints,
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
toLinenumber(t.info), makeCString(toFilename(p.config, t.info)),
makeCString(name)])
proc genWatchpoint(p: BProc, n: PNode) =
if optEndb notin p.options: return
var a: TLoc
initLocExpr(p, n.sons[1], a)
let typ = skipTypes(n.sons[1].typ, abstractVarRange)
lineCg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n",
[addrLoc(p.config, a), makeCString(renderTree(n.sons[1])),
genTypeInfo(p.module, typ, n.info)])
proc genPragma(p: BProc, n: PNode) =
for it in n.sons:
case whichPragma(it)
of wEmit: genEmit(p, it)
of wBreakpoint: genBreakPoint(p, it)
of wWatchPoint: genWatchpoint(p, it)
of wInjectStmt:
var p = newProc(nil, p.module)
p.options = p.options - {optLineTrace, optStackTrace}

View File

@@ -264,13 +264,7 @@ proc genLineDir(p: BProc, t: PNode) =
if optEmbedOrigSrc in p.config.globalOptions:
add(p.s(cpsStmts), ~"//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p.config)
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags):
if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "#endb($1, $2);$N",
[line, makeCString(toFilename(p.config, t.info))])
elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
@@ -479,19 +473,6 @@ proc deinitGCFrame(p: BProc): Rope =
result = ropecg(p.module,
"if (((NU)&GCFRAME_) < 4096) #nimGCFrame(&GCFRAME_);$n", [])
proc localDebugInfo(p: BProc, s: PSym, retType: PType) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
# XXX work around a bug: No type information for open arrays possible:
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
var a = "&" & s.loc.r
if s.kind == skParam and ccgIntroducedPtr(p.config, s, retType): a = s.loc.r
lineF(p, cpsInit,
"FR_.s[$1].address = (void*)$3; FR_.s[$1].typ = $4; FR_.s[$1].name = $2;$n",
[p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t, s.info)])
inc(p.maxFrameLen)
inc p.blocks[p.blocks.len-1].frameLen
proc localVarDecl(p: BProc; n: PNode): Rope =
let s = n.sym
if s.loc.k == locNone:
@@ -515,7 +496,6 @@ proc assignLocalVar(p: BProc, n: PNode) =
let nl = if optLineDir in p.config.options: "" else: "\L"
let decl = localVarDecl(p, n) & ";" & nl
line(p, cpsLocals, decl)
localDebugInfo(p, n.sym, nil)
include ccgthreadvars
@@ -562,17 +542,10 @@ proc assignGlobalVar(p: BProc, n: PNode) =
if p.withinLoop > 0:
# fixes tests/run/tzeroarray:
resetLoc(p, s.loc)
if p.module.module.options * {optStackTrace, optEndb} ==
{optStackTrace, optEndb}:
appcg(p.module, p.module.s[cfsDebugInit],
"#dbgRegisterGlobal($1, &$2, $3);$n",
[makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
s.loc.r, genTypeInfo(p.module, s.typ, n.info)])
proc assignParam(p: BProc, s: PSym, retType: PType) =
assert(s.loc.r != nil)
scopeMangledParam(p, s)
localDebugInfo(p, s, retType)
proc fillProcLoc(m: BModule; n: PNode) =
let sym = n.sym
@@ -689,7 +662,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
[loadlib, genStringLiteral(m, lib.path)])
else:
var p = newProc(nil, m)
p.options = p.options - {optStackTrace, optEndb}
p.options = p.options - {optStackTrace}
var dest: TLoc
initLoc(dest, locTemp, lib.path, OnStack)
dest.r = getTempName(m)
@@ -1318,7 +1291,6 @@ proc genMainProc(m: BModule) =
PreMainBody = "$N" &
"void PreMainInner(void) {$N" &
"$2" &
"$3" &
"}$N$N" &
PosixCmdLine &
"void PreMain(void) {$N" &
@@ -1408,17 +1380,11 @@ proc genMainProc(m: BModule) =
elif m.config.target.targetOS == osGenode:
m.includeHeader("<libc/component.h>")
if optEndb in m.config.options:
for i in 0..<m.config.m.fileInfos.len:
m.g.breakpoints.addf("dbgRegisterFilename($1);$N",
[m.config.m.fileInfos[i].projPath.string.makeCString])
let initStackBottomCall =
if m.config.target.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
inc(m.labels)
appcg(m, m.s[cfsProcs], PreMainBody, [
m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit])
appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit])
if m.config.target.targetOS == osWindows and
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
@@ -2024,11 +1990,6 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
discard cgsym(m, "initThreadVarsEmulation")
if m.g.breakpoints != nil:
discard cgsym(m, "dbgRegisterBreakpoint")
if optEndb in m.config.options:
discard cgsym(m, "dbgRegisterFilename")
if m.g.forwardedProcs.len == 0:
incl m.flags, objHasKidsValid
let disp = generateMethodDispatchers(graph)

View File

@@ -117,8 +117,6 @@ type
modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed
forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
generatedHeader*: BModule
breakPointId*: int
breakpoints*: Rope # later the breakpoints are inserted into the main proc
typeInfoMarker*: TypeCacheWithOwner
config*: ConfigRef
graph*: ModuleGraph

View File

@@ -266,7 +266,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis)
of "stacktrace": result = contains(conf.options, optStackTrace)
of "linetrace": result = contains(conf.options, optLineTrace)
of "debugger": result = contains(conf.options, optEndb)
of "debugger": result = contains(conf.globalOptions, optCDebug)
of "profiler": result = contains(conf.options, optProfiler)
of "memtracker": result = contains(conf.options, optMemTracker)
of "checks", "x": result = conf.options * ChecksOptions == ChecksOptions
@@ -473,24 +473,18 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info)
of "debugger":
case arg.normalize
of "on", "endb":
conf.options.incl optEndb
defineSymbol(conf.symbols, "endb")
of "off":
conf.options.excl optEndb
undefSymbol(conf.symbols, "endb")
of "native", "gdb":
incl(conf.globalOptions, optCDebug)
conf.options = conf.options + {optLineDir} - {optEndb}
of "on", "native", "gdb":
conf.globalOptions.incl optCDebug
conf.options.incl optLineDir
#defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
undefSymbol(conf.symbols, "endb")
of "off":
conf.globalOptions.excl optCDebug
else:
localError(conf, info, "expected endb|gdb but found " & arg)
localError(conf, info, "expected native|gdb|on|off but found " & arg)
of "g": # alias for --debugger:native
incl(conf.globalOptions, optCDebug)
conf.options = conf.options + {optLineDir} - {optEndb}
conf.globalOptions.incl optCDebug
conf.options.incl optLineDir
#defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
undefSymbol(conf.symbols, "endb")
of "profiler":
processOnOffSwitch(conf, {optProfiler}, arg, pass, info)
if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler")

View File

@@ -658,11 +658,7 @@ proc genLineDir(p: PProc, n: PNode) =
if optLineDir in p.options:
lineF(p, "// line $2 \"$1\"$n",
[rope(toFilename(p.config, n.info)), rope(line)])
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
((p.prc == nil) or sfPure notin p.prc.flags):
useMagic(p, "endb")
lineF(p, "endb($1);$n", [rope(line)])
elif hasFrameInfo(p):
if hasFrameInfo(p):
lineF(p, "F.line = $1;$n", [rope(line)])
proc genWhileStmt(p: PProc, n: PNode) =

View File

@@ -30,7 +30,6 @@ type # please make sure we have under 32 options
optAssert, optLineDir, optWarns, optHints,
optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
optLineTrace, # line tracing support (includes stack tracing)
optEndb, # embedded debugger
optByRef, # use pass by ref for objects
# (for interfacing with C)
optProfiler, # profiler turned on

View File

@@ -44,7 +44,7 @@ const
wWarnings, wHints,
wLineDir, wStackTrace, wLineTrace, wOptimization, wHint, wWarning, wError,
wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
wBreakpoint, wWatchPoint, wPassl, wPassc,
wPassl, wPassc,
wDeadCodeElimUnused, # deprecated, always on
wDeprecated,
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
@@ -345,7 +345,7 @@ proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} =
of wLineDir: {optLineDir}
of wStackTrace: {optStackTrace}
of wLineTrace: {optLineTrace}
of wDebugger: {optEndb}
of wDebugger: {optNone}
of wProfiler: {optProfiler, optMemTracker}
of wMemTracker: {optMemTracker}
of wByRef: {optByRef}
@@ -513,15 +513,6 @@ proc processLink(c: PContext, n: PNode) =
extccomp.addExternalFileToLink(c.config, found)
recordPragma(c, n, "link", found.string)
proc pragmaBreakpoint(c: PContext, n: PNode) =
discard getOptionalStr(c, n, "")
proc pragmaWatchpoint(c: PContext, n: PNode) =
if n.kind in nkPragmaCallKinds and n.len == 2:
n.sons[1] = c.semExpr(c, n.sons[1])
else:
invalidPragma(c, n)
proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
case n.sons[1].kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
@@ -996,8 +987,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
let s = expectStrLit(c, it)
extccomp.addCompileOption(c.config, s)
recordPragma(c, it, "passc", s)
of wBreakpoint: pragmaBreakpoint(c, it)
of wWatchPoint: pragmaWatchpoint(c, it)
of wPush:
processPush(c, n, i + 1)
result = true

View File

@@ -48,7 +48,7 @@ type
wCompilerProc, wCore, wProcVar, wBase, wUsed,
wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
wLineDir, wStackTrace, wLineTrace, wLink, wCompile,
wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger,
wLinksys, wDeprecated, wVarargs, wCallconv, wDebugger,
wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline,
wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangeChecks,
wBoundChecks, wOverflowChecks, wNilChecks,
@@ -62,8 +62,7 @@ type
wCompileTime, wNoInit,
wPassc, wPassl, wBorrow, wDiscardable,
wFieldChecks,
wWatchPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
wInjectStmt, wExperimental,
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
wAsmNoStackFrame,
@@ -138,7 +137,7 @@ const
"fatal", "error", "warning", "hint", "line",
"push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
"link", "compile", "linksys", "deprecated", "varargs",
"callconv", "breakpoint", "debugger", "nimcall", "stdcall",
"callconv", "debugger", "nimcall", "stdcall",
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
"noconv", "on", "off", "checks", "rangechecks", "boundchecks",
"overflowchecks", "nilchecks",
@@ -152,7 +151,6 @@ const
"pragma",
"compiletime", "noinit",
"passc", "passl", "borrow", "discardable", "fieldchecks",
"watchpoint",
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
"computedgoto", "injectstmt", "experimental",
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",

View File

@@ -1,203 +0,0 @@
==============================================
Embedded Nim Debugger (ENDB) User Guide
==============================================
:Author: Andreas Rumpf
:Version: |nimversion|
.. contents::
**WARNING**: ENDB is not maintained anymore! Please help if you're interested
in this tool.
Nim comes with a platform independent debugger -
the Embedded Nim Debugger (ENDB). The debugger is
*embedded* into your executable if it has been
compiled with the ``--debugger:on`` command line option.
This also defines the conditional symbol ``ENDB`` for you.
Note: You must not compile your program with the ``--app:gui``
command line option because then there would be no console
available for the debugger.
If you start your program the debugger will immediately show
a prompt on the console. You can now enter a command. The next sections
deal with the possible commands. As usual in Nim in all commands
underscores and case do not matter. Optional components of a command
are listed in brackets ``[...]`` here.
General Commands
================
``h``, ``help``
Display a quick reference of the possible commands.
``q``, ``quit``
Quit the debugger and the program.
<ENTER>
(Without any typed command) repeat the previous debugger command.
If there is no previous command, ``step_into`` is assumed.
Executing Commands
==================
``s``, ``step_into``
Single step, stepping into routine calls.
``n``, ``step_over``
Single step, without stepping into routine calls.
``f``, ``skip_current``
Continue execution until the current routine finishes.
``c``, ``continue``
Continue execution until the next breakpoint.
``i``, ``ignore``
Continue execution, ignore all breakpoints. This effectively quits
the debugger and runs the program until it finishes.
Breakpoint Commands
===================
``b``, ``setbreak`` [fromline [toline]] [file]
Set a new breakpoint for the given file
and line numbers. If no file is given, the current execution point's
filename is used. If the filename has no extension, ``.nim`` is
appended for your convenience.
If no line numbers are given, the current execution point's
line is used. If both ``fromline`` and ``toline`` are given the
breakpoint contains a line number range. Some examples if it is still
unclear:
* ``b 12 15 thallo`` creates a breakpoint that
will be triggered if the instruction pointer reaches one of the
lines 12-15 in the file ``thallo.nim``.
* ``b 12 thallo`` creates a breakpoint that
will be triggered if the instruction pointer reaches the
line 12 in the file ``thallo.nim``.
* ``b 12`` creates a breakpoint that
will be triggered if the instruction pointer reaches the
line 12 in the current file.
* ``b`` creates a breakpoint that
will be triggered if the instruction pointer reaches the
current line in the current file again.
``breakpoints``
Display the entire breakpoint list.
``disable`` <identifier>
Disable a breakpoint. It remains disabled until you turn it on again
with the ``enable`` command.
``enable`` <identifier>
Enable a breakpoint.
Often it happens when debugging that you keep retyping the breakpoints again
and again because they are lost when you restart your program. This is not
necessary: A special pragma has been defined for this:
The ``breakpoint`` pragma
-------------------------
The ``breakpoint`` pragma is syntactically a statement. It can be used
to mark the *following line* as a breakpoint:
.. code-block:: Nim
write("1")
{.breakpoint: "before_write_2".}
write("2")
The name of the breakpoint here is ``before_write_2``. Of course the
breakpoint's name is optional - the compiler will generate one for you
if you leave it out.
Code for the ``breakpoint`` pragma is only generated if the debugger
is turned on, so you don't need to remove it from your source code after
debugging.
The ``watchpoint`` pragma
-------------------------
The ``watchpoint`` pragma is syntactically a statement. It can be used
to mark a location as a watchpoint:
.. code-block:: Nim
var a: array[0..20, int]
{.watchpoint: a[3].}
for i in 0 .. 20: a[i] = i
ENDB then writes a stack trace whenever the content of the location ``a[3]``
changes. The current implementation only tracks a hash value of the location's
contents and so locations that are not word sized may encounter false
negatives in very rare cases.
Code for the ``watchpoint`` pragma is only generated if the debugger
is turned on, so you don't need to remove it from your source code after
debugging.
Due to the primitive implementation watchpoints are even slower than
breakpoints: After *every* executed Nim code line it is checked whether the
location changed.
Data Display Commands
=====================
``e``, ``eval`` <exp>
Evaluate the expression <exp>. Note that ENDB has no full-blown expression
evaluator built-in. So expressions are limited:
* To display global variables prefix their names with their
owning module: ``nim1.globalVar``
* To display local variables or parameters just type in
their name: ``localVar``. If you want to inspect variables that are not
in the current stack frame, use the ``up`` or ``down`` command.
Unfortunately, only inspecting variables is possible at the moment. Maybe
a future version will implement a full-blown Nim expression evaluator,
but this is not easy to do and would bloat the debugger's code.
Since displaying the whole data structures is often not needed and
painfully slow, the debugger uses a *maximal display depth* concept for
displaying.
You can alter the maximal display depth with the ``maxdisplay``
command.
``maxdisplay`` <natural>
Sets the maximal display depth to the given integer value. A value of 0
means there is no maximal display depth. Default is 3.
``o``, ``out`` <filename> <exp>
Evaluate the expression <exp> and store its string representation into a
file named <filename>. If the file does not exist, it will be created,
otherwise it will be opened for appending.
``w``, ``where``
Display the current execution point.
``u``, ``up``
Go up in the call stack.
``d``, ``down``
Go down in the call stack.
``stackframe`` [file]
Displays the content of the current stack frame in ``stdout`` or
appends it to the file, depending on whether a file is given.
``callstack``
Display the entire call stack (but not its content).
``l``, ``locals``
Display the available local variables in the current stack frame.
``g``, ``globals``
Display all the global variables that are available for inspection.

View File

@@ -3639,10 +3639,6 @@ when not defined(JS): #and not defined(nimscript):
if result == 0:
result = x.len - y.len
when not defined(nimscript) and hostOS != "standalone":
when defined(endb):
proc endbStep()
when declared(newSeq):
proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
## Converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
@@ -3816,9 +3812,6 @@ when not defined(JS): #and not defined(nimscript):
currException = exc
{.push stack_trace: off, profiler:off.}
when defined(endb) and not defined(nimscript):
include "system/debugger"
when (defined(profiler) or defined(memProfiler)) and not defined(nimscript):
include "system/profiler"
{.pop.} # stacktrace

View File

@@ -1,303 +0,0 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This file implements basic features for any debugger.
type
VarSlot* {.compilerproc, final.} = object ## a slot in a frame
address*: pointer ## the variable's address
typ*: PNimType ## the variable's type
name*: cstring ## the variable's name; for globals this is "module.name"
PExtendedFrame = ptr ExtendedFrame
ExtendedFrame = object # If the debugger is enabled the compiler
# provides an extended frame. Of course
# only slots that are
# needed are allocated and not 10_000,
# except for the global data description.
f: TFrame
slots: array[0..10_000, VarSlot]
var
dbgGlobalData: ExtendedFrame # this reserves much space, but
# for now it is the most practical way
proc dbgRegisterGlobal(name: cstring, address: pointer,
typ: PNimType) {.compilerproc.} =
let i = dbgGlobalData.f.len
if i >= high(dbgGlobalData.slots):
#debugOut("[Warning] cannot register global ")
return
dbgGlobalData.slots[i].name = name
dbgGlobalData.slots[i].typ = typ
dbgGlobalData.slots[i].address = address
inc(dbgGlobalData.f.len)
proc getLocal*(frame: PFrame; slot: int): VarSlot {.inline.} =
## retrieves the meta data for the local variable at `slot`. CAUTION: An
## invalid `slot` value causes a corruption!
result = cast[PExtendedFrame](frame).slots[slot]
proc getGlobalLen*(): int {.inline.} =
## gets the number of registered globals.
result = dbgGlobalData.f.len
proc getGlobal*(slot: int): VarSlot {.inline.} =
## retrieves the meta data for the global variable at `slot`. CAUTION: An
## invalid `slot` value causes a corruption!
result = dbgGlobalData.slots[slot]
# ------------------- breakpoint support ------------------------------------
type
Breakpoint* = object ## represents a break point
low*, high*: int ## range from low to high; if disabled
## both low and high are set to their negative values
filename*: cstring ## the filename of the breakpoint
var
dbgBP: array[0..127, Breakpoint] # breakpoints
dbgBPlen: int
dbgBPbloom: int64 # we use a bloom filter to speed up breakpoint checking
dbgFilenames*: array[0..300, cstring] ## registered filenames;
## 'nil' terminated
dbgFilenameLen: int
proc dbgRegisterFilename(filename: cstring) {.compilerproc.} =
# XXX we could check for duplicates here for DLL support
dbgFilenames[dbgFilenameLen] = filename
inc dbgFilenameLen
proc dbgRegisterBreakpoint(line: int,
filename, name: cstring) {.compilerproc.} =
let x = dbgBPlen
if x >= high(dbgBP):
#debugOut("[Warning] cannot register breakpoint")
return
inc(dbgBPlen)
dbgBP[x].filename = filename
dbgBP[x].low = line
dbgBP[x].high = line
dbgBPbloom = dbgBPbloom or line
proc addBreakpoint*(filename: cstring, lo, hi: int): bool =
let x = dbgBPlen
if x >= high(dbgBP): return false
inc(dbgBPlen)
result = true
dbgBP[x].filename = filename
dbgBP[x].low = lo
dbgBP[x].high = hi
for line in lo..hi: dbgBPbloom = dbgBPbloom or line
const
FileSystemCaseInsensitive = defined(windows) or defined(dos) or defined(os2)
proc fileMatches(c, bp: cstring): bool =
# bp = breakpoint filename
# c = current filename
# we consider it a match if bp is a suffix of c
# and the character for the suffix does not exist or
# is one of: \ / :
# depending on the OS case does not matter!
var blen: int = bp.len
var clen: int = c.len
if blen > clen: return false
# check for \ / :
if clen-blen-1 >= 0 and c[clen-blen-1] notin {'\\', '/', ':'}:
return false
var i = 0
while i < blen:
var x = bp[i]
var y = c[i+clen-blen]
when FileSystemCaseInsensitive:
if x >= 'A' and x <= 'Z': x = chr(ord(x) - ord('A') + ord('a'))
if y >= 'A' and y <= 'Z': y = chr(ord(y) - ord('A') + ord('a'))
if x != y: return false
inc(i)
return true
proc canonFilename*(filename: cstring): cstring =
## returns 'nil' if the filename cannot be found.
for i in 0 .. dbgFilenameLen-1:
result = dbgFilenames[i]
if fileMatches(result, filename): return result
result = nil
iterator listBreakpoints*(): ptr Breakpoint =
## lists all breakpoints.
for i in 0..dbgBPlen-1: yield addr(dbgBP[i])
proc isActive*(b: ptr Breakpoint): bool = b.low > 0
proc flip*(b: ptr Breakpoint) =
## enables or disables 'b' depending on its current state.
b.low = -b.low; b.high = -b.high
proc checkBreakpoints*(filename: cstring, line: int): ptr Breakpoint =
## in which breakpoint (if any) we are.
if (dbgBPbloom and line) != line: return nil
for b in listBreakpoints():
if line >= b.low and line <= b.high and filename == b.filename: return b
# ------------------- watchpoint support ------------------------------------
type
Hash = int
Watchpoint {.pure, final.} = object
name: cstring
address: pointer
typ: PNimType
oldValue: Hash
var
watchpoints: array[0..99, Watchpoint]
watchpointsLen: int
proc `!&`(h: Hash, val: int): Hash {.inline.} =
result = h +% val
result = result +% result shl 10
result = result xor (result shr 6)
proc `!$`(h: Hash): Hash {.inline.} =
result = h +% h shl 3
result = result xor (result shr 11)
result = result +% result shl 15
proc hash(data: pointer, size: int): Hash =
var h: Hash = 0
var p = cast[cstring](data)
var i = 0
var s = size
while s > 0:
h = h !& ord(p[i])
inc(i)
dec(s)
result = !$h
proc hashGcHeader(data: pointer): Hash =
const headerSize = sizeof(int)*2
result = hash(cast[pointer](cast[int](data) -% headerSize), headerSize)
proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
h: Hash): Hash
proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool,
h: Hash): Hash =
var d = cast[ByteAddress](dest)
case n.kind
of nkSlot:
result = genericHashAux(cast[pointer](d +% n.offset), n.typ, shallow, h)
of nkList:
result = h
for i in 0..n.len-1:
result = result !& genericHashAux(dest, n.sons[i], shallow, result)
of nkCase:
result = h !& hash(cast[pointer](d +% n.offset), n.typ.size)
var m = selectBranch(dest, n)
if m != nil: result = genericHashAux(dest, m, shallow, result)
of nkNone: sysAssert(false, "genericHashAux")
proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
h: Hash): Hash =
sysAssert(mt != nil, "genericHashAux 2")
case mt.kind
of tyString:
var x = cast[PPointer](dest)[]
result = h
if x != nil:
let s = cast[NimString](x)
when defined(trackGcHeaders):
result = result !& hashGcHeader(x)
else:
result = result !& hash(x, s.len)
of tySequence:
var x = cast[PPointer](dest)
var dst = cast[ByteAddress](cast[PPointer](dest)[])
result = h
if dst != 0:
when defined(trackGcHeaders):
result = result !& hashGcHeader(cast[PPointer](dest)[])
else:
for i in 0..cast[PGenericSeq](dst).len-1:
result = result !& genericHashAux(
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
mt.base, shallow, result)
of tyObject, tyTuple:
# we don't need to copy m_type field for tyObject, as they are equal anyway
result = genericHashAux(dest, mt.node, shallow, h)
of tyArray, tyArrayConstr:
let d = cast[ByteAddress](dest)
result = h
for i in 0..(mt.size div mt.base.size)-1:
result = result !& genericHashAux(cast[pointer](d +% i*% mt.base.size),
mt.base, shallow, result)
of tyRef:
when defined(trackGcHeaders):
var s = cast[PPointer](dest)[]
if s != nil:
result = result !& hashGcHeader(s)
else:
if shallow:
result = h !& hash(dest, mt.size)
else:
result = h
var s = cast[PPointer](dest)[]
if s != nil:
result = result !& genericHashAux(s, mt.base, shallow, result)
else:
result = h !& hash(dest, mt.size) # hash raw bits
proc genericHash(dest: pointer, mt: PNimType): int =
result = genericHashAux(dest, mt, false, 0)
proc dbgRegisterWatchpoint(address: pointer, name: cstring,
typ: PNimType) {.compilerproc.} =
let L = watchPointsLen
for i in 0 .. pred(L):
if watchPoints[i].name == name:
# address may have changed:
watchPoints[i].address = address
return
if L >= watchPoints.high:
#debugOut("[Warning] cannot register watchpoint")
return
watchPoints[L].name = name
watchPoints[L].address = address
watchPoints[L].typ = typ
watchPoints[L].oldValue = genericHash(address, typ)
inc watchPointsLen
proc dbgUnregisterWatchpoints*() =
watchPointsLen = 0
var
dbgLineHook*: proc () {.nimcall.}
## set this variable to provide a procedure that should be called before
## each executed instruction. This should only be used by debuggers!
## Only code compiled with the ``debugger:on`` switch calls this hook.
dbgWatchpointHook*: proc (watchpointName: cstring) {.nimcall.}
proc checkWatchpoints =
let L = watchPointsLen
for i in 0 .. pred(L):
let newHash = genericHash(watchPoints[i].address, watchPoints[i].typ)
if newHash != watchPoints[i].oldValue:
dbgWatchpointHook(watchPoints[i].name)
watchPoints[i].oldValue = newHash
proc endb(line: int, file: cstring) {.compilerproc, noinline.} =
# This proc is called before every Nim code line!
if framePtr == nil: return
if dbgWatchpointHook != nil: checkWatchpoints()
framePtr.line = line # this is done here for smaller code size!
framePtr.filename = file
if dbgLineHook != nil: dbgLineHook()
include "system/endb"

View File

@@ -1,579 +0,0 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This file implements the embedded debugger that can be linked
# with the application. Mostly we do not use dynamic memory here as that
# would interfere with the GC and trigger ON/OFF errors if the
# user program corrupts memory. Unfortunately, for dispaying
# variables we use the ``system.repr()`` proc which uses Nim
# strings and thus allocates memory from the heap. Pity, but
# I do not want to implement ``repr()`` twice.
const
EndbBeg = "*** endb"
EndbEnd = "***\n"
type
StaticStr = object
len: int
data: array[0..100, char]
BreakpointFilename = object
b: ptr Breakpoint
filename: StaticStr
DbgState = enum
dbOff, # debugger is turned off
dbStepInto, # debugger is in tracing mode
dbStepOver,
dbSkipCurrent,
dbQuiting, # debugger wants to quit
dbBreakpoints # debugger is only interested in breakpoints
var
dbgUser: StaticStr # buffer for user input; first command is ``step_into``
# needs to be global cause we store the last command
# in it
dbgState: DbgState # state of debugger
dbgSkipToFrame: PFrame # frame to be skipped to
maxDisplayRecDepth: int = 5 # do not display too much data!
brkPoints: array[0..127, BreakpointFilename]
proc setLen(s: var StaticStr, newLen=0) =
s.len = newLen
s.data[newLen] = '\0'
proc add(s: var StaticStr, c: char) =
if s.len < high(s.data)-1:
s.data[s.len] = c
s.data[s.len+1] = '\0'
inc s.len
proc add(s: var StaticStr, c: cstring) =
var i = 0
while c[i] != '\0':
add s, c[i]
inc i
proc assign(s: var StaticStr, c: cstring) =
setLen(s)
add s, c
proc `==`(a, b: StaticStr): bool =
if a.len == b.len:
for i in 0 .. a.len-1:
if a.data[i] != b.data[i]: return false
return true
proc `==`(a: StaticStr, b: cstring): bool =
result = c_strcmp(unsafeAddr a.data, b) == 0
proc write(f: CFilePtr, s: cstring) = c_fputs(s, f)
proc writeLine(f: CFilePtr, s: cstring) =
c_fputs(s, f)
c_fputs("\n", f)
proc write(f: CFilePtr, s: StaticStr) =
write(f, cstring(unsafeAddr s.data))
proc write(f: CFilePtr, i: int) =
when sizeof(int) == 8:
discard c_fprintf(f, "%lld", i)
else:
discard c_fprintf(f, "%ld", i)
proc close(f: CFilePtr): cint {.
importc: "fclose", header: "<stdio.h>", discardable.}
proc c_fgetc(stream: CFilePtr): cint {.
importc: "fgetc", header: "<stdio.h>".}
proc c_ungetc(c: cint, f: CFilePtr): cint {.
importc: "ungetc", header: "<stdio.h>", discardable.}
var
cstdin* {.importc: "stdin", header: "<stdio.h>".}: CFilePtr
proc listBreakPoints() =
write(cstdout, EndbBeg)
write(cstdout, "| Breakpoints:\n")
for b in listBreakpoints():
write(cstdout, abs(b.low))
if b.high != b.low:
write(cstdout, "..")
write(cstdout, abs(b.high))
write(cstdout, " ")
write(cstdout, b.filename)
if b.isActive:
write(cstdout, " [disabled]\n")
else:
write(cstdout, "\n")
write(cstdout, EndbEnd)
proc openAppend(filename: cstring): CFilePtr =
proc fopen(filename, mode: cstring): CFilePtr {.importc: "fopen", header: "<stdio.h>".}
result = fopen(filename, "ab")
if result != nil:
write(result, "----------------------------------------\n")
proc dbgRepr(p: pointer, typ: PNimType): string =
var cl: ReprClosure
initReprClosure(cl)
cl.recDepth = maxDisplayRecDepth
# locks for the GC turned out to be a bad idea...
# inc(recGcLock)
result = ""
reprAux(result, p, typ, cl)
# dec(recGcLock)
deinitReprClosure(cl)
proc writeVariable(stream: CFilePtr, slot: VarSlot) =
write(stream, slot.name)
write(stream, " = ")
writeLine(stream, dbgRepr(slot.address, slot.typ))
proc listFrame(stream: CFilePtr, f: PFrame) =
write(stream, EndbBeg)
write(stream, "| Frame (")
write(stream, f.len)
write(stream, " slots):\n")
for i in 0 .. f.len-1:
writeLine(stream, getLocal(f, i).name)
write(stream, EndbEnd)
proc listLocals(stream: CFilePtr, f: PFrame) =
write(stream, EndbBeg)
write(stream, "| Frame (")
write(stream, f.len)
write(stream, " slots):\n")
for i in 0 .. f.len-1:
writeVariable(stream, getLocal(f, i))
write(stream, EndbEnd)
proc listGlobals(stream: CFilePtr) =
write(stream, EndbBeg)
write(stream, "| Globals:\n")
for i in 0 .. getGlobalLen()-1:
writeLine(stream, getGlobal(i).name)
write(stream, EndbEnd)
proc debugOut(msg: cstring) =
# the *** *** markers are for easy recognition of debugger
# output for external frontends.
write(cstdout, EndbBeg)
write(cstdout, "| ")
write(cstdout, msg)
write(cstdout, EndbEnd)
proc dbgFatal(msg: cstring) =
debugOut(msg)
dbgAborting = true # the debugger wants to abort
quit(1)
proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
if dbgFramePointer != nil:
write(cstdout, "*** endb| now in proc: ")
write(cstdout, dbgFramePointer.procname)
write(cstdout, " ***\n")
else:
write(cstdout, "*** endb| (proc name not available) ***\n")
proc dbgShowExecutionPoint() =
write(cstdout, "*** endb| ")
write(cstdout, framePtr.filename)
write(cstdout, "(")
write(cstdout, framePtr.line)
write(cstdout, ") ")
write(cstdout, framePtr.procname)
write(cstdout, " ***\n")
proc scanAndAppendWord(src: cstring, a: var StaticStr, start: int): int =
result = start
# skip whitespace:
while src[result] in {'\t', ' '}: inc(result)
while true:
case src[result]
of 'a'..'z', '0'..'9': add(a, src[result])
of '_': discard # just skip it
of 'A'..'Z': add(a, chr(ord(src[result]) - ord('A') + ord('a')))
else: break
inc(result)
proc scanWord(src: cstring, a: var StaticStr, start: int): int =
setlen(a)
result = scanAndAppendWord(src, a, start)
proc scanFilename(src: cstring, a: var StaticStr, start: int): int =
result = start
setLen a
while src[result] in {'\t', ' '}: inc(result)
while src[result] notin {'\t', ' ', '\0'}:
add(a, src[result])
inc(result)
proc scanNumber(src: cstring, a: var int, start: int): int =
result = start
a = 0
while src[result] in {'\t', ' '}: inc(result)
while true:
case src[result]
of '0'..'9': a = a * 10 + ord(src[result]) - ord('0')
of '_': discard # skip underscores (nice for long line numbers)
else: break
inc(result)
proc dbgHelp() =
debugOut("""
list of commands (see the manual for further help):
GENERAL
h, help display this help message
q, quit quit the debugger and the program
<ENTER> repeat the previous debugger command
EXECUTING
s, step single step, stepping into routine calls
n, next single step, without stepping into routine calls
f, skipcurrent continue execution until the current routine finishes
c, continue, r, run continue execution until the next breakpoint
i, ignore continue execution, ignore all breakpoints
BREAKPOINTS
b, break [fromline [toline]] [file]
set a new breakpoint for line and file
if line or file are omitted the current one is used
breakpoints display the entire breakpoint list
toggle fromline [file] enable or disable a breakpoint
filenames list all valid filenames
DATA DISPLAY
e, eval <expr> evaluate the expression <expr>
o, out <file> <expr> evaluate <expr> and write it to <file>
w, where display the current execution point
stackframe [file] display current stack frame [and write it to file]
u, up go up in the call stack
d, down go down in the call stack
bt, backtrace display the entire call stack
l, locals display available local variables
g, globals display available global variables
maxdisplay <integer> set the display's recursion maximum
""")
proc invalidCommand() =
debugOut("[Warning] invalid command ignored (type 'h' for help) ")
proc hasExt(s: cstring): bool =
# returns true if s has a filename extension
var i = 0
while s[i] != '\0':
if s[i] == '.': return true
inc i
proc parseBreakpoint(s: cstring, start: int): Breakpoint =
var dbgTemp: StaticStr
var i = scanNumber(s, result.low, start)
if result.low == 0: result.low = framePtr.line
i = scanNumber(s, result.high, i)
if result.high == 0: result.high = result.low
i = scanFilename(s, dbgTemp, i)
if dbgTemp.len != 0:
if not hasExt(addr dbgTemp.data): add(dbgTemp, ".nim")
result.filename = canonFilename(addr dbgTemp.data)
if result.filename.isNil:
debugOut("[Warning] no breakpoint could be set; unknown filename ")
return
else:
result.filename = framePtr.filename
proc createBreakPoint(s: cstring, start: int) =
let br = parseBreakpoint(s, start)
if not br.filename.isNil:
if not addBreakpoint(br.filename, br.low, br.high):
debugOut("[Warning] no breakpoint could be set; out of breakpoint space ")
proc breakpointToggle(s: cstring, start: int) =
var a = parseBreakpoint(s, start)
if not a.filename.isNil:
var b = checkBreakpoints(a.filename, a.low)
if not b.isNil: b.flip
else: debugOut("[Warning] unknown breakpoint ")
proc dbgEvaluate(stream: CFilePtr, s: cstring, start: int, f: PFrame) =
var dbgTemp: StaticStr
var i = scanWord(s, dbgTemp, start)
while s[i] in {' ', '\t'}: inc(i)
var v: VarSlot
if s[i] == '.':
inc(i)
add(dbgTemp, '.')
i = scanAndAppendWord(s, dbgTemp, i)
for i in 0 .. getGlobalLen()-1:
let v = getGlobal(i)
if c_strcmp(v.name, addr dbgTemp.data) == 0:
writeVariable(stream, v)
else:
for i in 0 .. f.len-1:
let v = getLocal(f, i)
if c_strcmp(v.name, addr dbgTemp.data) == 0:
writeVariable(stream, v)
proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
var dbgTemp: StaticStr
var i = scanFilename(s, dbgTemp, start)
if dbgTemp.len == 0:
invalidCommand()
return
var stream = openAppend(addr dbgTemp.data)
if stream == nil:
debugOut("[Warning] could not open or create file ")
return
dbgEvaluate(stream, s, i, currFrame)
close(stream)
proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
var dbgTemp: StaticStr
var i = scanFilename(s, dbgTemp, start)
if dbgTemp.len == 0:
# just write it to cstdout:
listFrame(cstdout, currFrame)
else:
var stream = openAppend(addr dbgTemp.data)
if stream == nil:
debugOut("[Warning] could not open or create file ")
return
listFrame(stream, currFrame)
close(stream)
proc readLine(f: CFilePtr, line: var StaticStr): bool =
while true:
var c = c_fgetc(f)
if c < 0'i32:
if line.len > 0: break
else: return false
if c == 10'i32: break # LF
if c == 13'i32: # CR
c = c_fgetc(f) # is the next char LF?
if c != 10'i32: discard c_ungetc(c, f) # no, put the character back
break
add line, chr(int(c))
result = true
proc listFilenames() =
write(cstdout, EndbBeg)
write(cstdout, "| Files:\n")
var i = 0
while true:
let x = dbgFilenames[i]
if x.isNil: break
write(cstdout, x)
write(cstdout, "\n")
inc i
write(cstdout, EndbEnd)
proc dbgWriteStackTrace(f: PFrame)
proc commandPrompt() =
# if we return from this routine, user code executes again
var
again = true
dbgFramePtr = framePtr # for going down and up the stack
dbgDown = 0 # how often we did go down
dbgTemp: StaticStr
while again:
write(cstdout, "*** endb| >>")
let oldLen = dbgUser.len
dbgUser.len = 0
if not readLine(cstdin, dbgUser): break
if dbgUser.len == 0: dbgUser.len = oldLen
# now look what we have to do:
var i = scanWord(addr dbgUser.data, dbgTemp, 0)
template `?`(x: untyped): untyped = dbgTemp == cstring(x)
if ?"s" or ?"step":
dbgState = dbStepInto
again = false
elif ?"n" or ?"next":
dbgState = dbStepOver
dbgSkipToFrame = framePtr
again = false
elif ?"f" or ?"skipcurrent":
dbgState = dbSkipCurrent
dbgSkipToFrame = framePtr.prev
again = false
elif ?"c" or ?"continue" or ?"r" or ?"run":
dbgState = dbBreakpoints
again = false
elif ?"i" or ?"ignore":
dbgState = dbOff
again = false
elif ?"h" or ?"help":
dbgHelp()
elif ?"q" or ?"quit":
dbgState = dbQuiting
dbgAborting = true
again = false
quit(1) # BUGFIX: quit with error code > 0
elif ?"e" or ?"eval":
var
prevState = dbgState
prevSkipFrame = dbgSkipToFrame
dbgState = dbSkipCurrent
dbgEvaluate(cstdout, addr dbgUser.data, i, dbgFramePtr)
dbgState = prevState
dbgSkipToFrame = prevSkipFrame
elif ?"o" or ?"out":
dbgOut(addr dbgUser.data, i, dbgFramePtr)
elif ?"stackframe":
dbgStackFrame(addr dbgUser.data, i, dbgFramePtr)
elif ?"w" or ?"where":
dbgShowExecutionPoint()
elif ?"l" or ?"locals":
var
prevState = dbgState
prevSkipFrame = dbgSkipToFrame
dbgState = dbSkipCurrent
listLocals(cstdout, dbgFramePtr)
dbgState = prevState
dbgSkipToFrame = prevSkipFrame
elif ?"g" or ?"globals":
var
prevState = dbgState
prevSkipFrame = dbgSkipToFrame
dbgState = dbSkipCurrent
listGlobals(cstdout)
dbgState = prevState
dbgSkipToFrame = prevSkipFrame
elif ?"u" or ?"up":
if dbgDown <= 0:
debugOut("[Warning] cannot go up any further ")
else:
dbgFramePtr = framePtr
for j in 0 .. dbgDown-2: # BUGFIX
dbgFramePtr = dbgFramePtr.prev
dec(dbgDown)
dbgShowCurrentProc(dbgFramePtr)
elif ?"d" or ?"down":
if dbgFramePtr != nil:
inc(dbgDown)
dbgFramePtr = dbgFramePtr.prev
dbgShowCurrentProc(dbgFramePtr)
else:
debugOut("[Warning] cannot go down any further ")
elif ?"bt" or ?"backtrace":
dbgWriteStackTrace(framePtr)
elif ?"b" or ?"break":
createBreakPoint(addr dbgUser.data, i)
elif ?"breakpoints":
listBreakPoints()
elif ?"toggle":
breakpointToggle(addr dbgUser.data, i)
elif ?"filenames":
listFilenames()
elif ?"maxdisplay":
var parsed: int
i = scanNumber(addr dbgUser.data, parsed, i)
if dbgUser.data[i-1] in {'0'..'9'}:
if parsed == 0: maxDisplayRecDepth = -1
else: maxDisplayRecDepth = parsed
else:
invalidCommand()
else: invalidCommand()
proc endbStep() =
# we get into here if an unhandled exception has been raised
# XXX: do not allow the user to run the program any further?
# XXX: BUG: the frame is lost here!
dbgShowExecutionPoint()
commandPrompt()
proc dbgWriteStackTrace(f: PFrame) =
const
firstCalls = 32
var
it = f
i = 0
total = 0
tempFrames: array[0..127, PFrame]
# setup long head:
while it != nil and i <= high(tempFrames)-firstCalls:
tempFrames[i] = it
inc(i)
inc(total)
it = it.prev
# go up the stack to count 'total':
var b = it
while it != nil:
inc(total)
it = it.prev
var skipped = 0
if total > len(tempFrames):
# skip N
skipped = total-i-firstCalls+1
for j in 1..skipped:
if b != nil: b = b.prev
# create '...' entry:
tempFrames[i] = nil
inc(i)
# setup short tail:
while b != nil and i <= high(tempFrames):
tempFrames[i] = b
inc(i)
b = b.prev
for j in countdown(i-1, 0):
if tempFrames[j] == nil:
write(cstdout, "(")
write(cstdout, skipped)
write(cstdout, " calls omitted) ...")
else:
write(cstdout, tempFrames[j].filename)
if tempFrames[j].line > 0:
write(cstdout, "(")
write(cstdout, tempFrames[j].line)
write(cstdout, ")")
write(cstdout, " ")
write(cstdout, tempFrames[j].procname)
write(cstdout, "\n")
proc checkForBreakpoint =
let b = checkBreakpoints(framePtr.filename, framePtr.line)
if b != nil:
write(cstdout, "*** endb| reached ")
write(cstdout, framePtr.filename)
write(cstdout, "(")
write(cstdout, framePtr.line)
write(cstdout, ") ")
write(cstdout, framePtr.procname)
write(cstdout, " ***\n")
commandPrompt()
proc lineHookImpl() {.nimcall.} =
case dbgState
of dbStepInto:
# we really want the command prompt here:
dbgShowExecutionPoint()
commandPrompt()
of dbSkipCurrent, dbStepOver: # skip current routine
if framePtr == dbgSkipToFrame:
dbgShowExecutionPoint()
commandPrompt()
else:
# breakpoints are wanted though (I guess)
checkForBreakpoint()
of dbBreakpoints:
# debugger is only interested in breakpoints
checkForBreakpoint()
else: discard
proc watchpointHookImpl(name: cstring) {.nimcall.} =
dbgWriteStackTrace(framePtr)
debugOut(name)
proc initDebugger {.inline.} =
dbgState = dbStepInto
dbgUser.len = 1
dbgUser.data[0] = 's'
dbgWatchpointHook = watchpointHookImpl
dbgLineHook = lineHookImpl

View File

@@ -38,10 +38,7 @@ proc showErrorMessage(data: cstring) {.gcsafe.} =
writeToStdErr(data)
proc quitOrDebug() {.inline.} =
when defined(endb):
endbStep() # call the debugger
else:
quit(1)
quit(1)
proc chckIndx(i, a, b: int): int {.inline, compilerproc, benign.}
proc chckRange(i, a, b: int): int {.inline, compilerproc, benign.}
@@ -469,10 +466,6 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl.} =
framePtr = s
if s.calldepth == nimCallDepthLimit: callDepthLimitReached()
when defined(endb):
var
dbgAborting: bool # whether the debugger wants to abort
when defined(cpp) and appType != "lib" and
not defined(js) and not defined(nimscript) and
hostOS != "standalone" and not defined(noCppExceptions):
@@ -515,8 +508,6 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
elif s == SIGSEGV:
action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
elif s == SIGABRT:
when defined(endb):
if dbgAborting: return # the debugger wants to abort
action("SIGABRT: Abnormal termination.\n")
elif s == SIGFPE: action("SIGFPE: Arithmetic error.\n")
elif s == SIGILL: action("SIGILL: Illegal operation.\n")
@@ -546,7 +537,6 @@ when not defined(noSignalHandler) and not defined(useNimRtl):
msg = y
processSignal(sign, asgn)
showErrorMessage(msg)
when defined(endb): dbgAborting = true
quit(1) # always quit when SIGABRT
proc registerSignalHandler() =

View File

@@ -27,13 +27,11 @@ method eval(e: ref TPlusExpr): int =
proc newLit(x: int): ref TLiteral =
new(result)
{.watchpoint: result.}
result.x = x
result.op1 = $getOccupiedMem()
proc newPlus(a, b: ref TExpr): ref TPlusExpr =
new(result)
{.watchpoint: result.}
result.a = a
result.b = b
result.op2 = $getOccupiedMem()

View File

@@ -48,7 +48,6 @@ echo(["a", "b", "c", "d"].len)
for x in items(["What's", "your", "name", "?", ]):
echo(x)
var `name` = readLine(stdin)
{.breakpoint.}
echo("Hi " & thallo.name & "!\n")
debug(name)

View File

@@ -17,7 +17,6 @@ block tobject2:
z: int # added a field
proc getPoint( p: var TPoint2d) =
{.breakpoint.}
writeLine(stdout, p.x)
var p: TPoint3d