Endb is no longer supported.
Does that mean that the debugging support mechanisms will also be removed at some time in the future?
I ask because there are no debug Frames generated for the outer scope level (on Win 64bit), only for proc calls, and I couldn't see any global variables being registered.
Is this a non issue, or should this be a PR?
Does that mean that the debugging support mechanisms will also be removed at some time in the future?
Not if I know that people use it. ;-)
I ask because there are no debug Frames generated for the outer scope level (on Win 64bit), only for proc calls, and I couldn't see any global variables being registered.
That used to work... Should be easy to make it work again. If you like ENDB, please write some tests for it and volunteer to maintain it. We could also make ENDB a Nimble package if we give the C codegen NimScript support.
So I see it as helping out newbies, so they can step thru their code and see what it is doing.
One limiting factor is that endb (currently) does a poor job of inspecting variables/locals/globals.
For type tyVar (I assume variables), there is no base type info provided as part of PNimType object. Is this something that would be easy to extend?
My thinking is that the issue is that endb needs more info being passed to it by the compiler, as with types like tyVar (correct me if I am wrong).
I haven't pursued this further to see what happens with objects, because I wanted to know if it worth pursuing it further :)
@Varriount, it appears that the mechanism to get type info is there, but doesn't seem to be getting through to the debugger.
As an example, using a source file test_arr1.nim, with a proc definition
proc do_something(pson: var Person, str2: var string, sq2: var seq[int], a2: var array[0..2, int]) =
the compiled nim file (compiler_test_arr1.c) has type definitions like:
TNimType NTI100049; /* Array constructor[0..2, int] */
TNimType NTI100056; /* var Person */
extern TNimType NTI10456; /* var string */
TNimType NTI100060; /* var seq[int] */
TNimType NTI100063; /* var array[0..2, int] */
and a stack frame
nimfrs("do_something", "test_arr1.nim", 4, 4)
FR.s[0].address = (void*)&pson; FR.s[0].typ = (&NTI100056); FR.s[0].name = "pson";
FR.s[1].address = (void*)&str2; FR.s[1].typ = (&NTI10456); FR.s[1].name = "str2";
FR.s[2].address = (void*)&sq2; FR.s[2].typ = (&NTI100060); FR.s[2].name = "sq2";
FR.s[3].address = (void*)&a2; FR.s[3].typ = (&NTI100063); FR.s[3].name = "a2";
endb(14, "test_arr1.nim");
So the typ field of the stack frame(?) has unique type identifiers, but the debugger.nim and endb.nim modules get these as VarSlot
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"
and the typ: PNimType ends up with a kind of tyVar and no other information about the actual base type, like "Person" (NTI100056), "string" (NTI10456), "seq[int]" (NTI100060) and "array[0..2, int]" (NTI100063) respectively
So in summary, I think the mechanism is already there to pass the type info to the endb debugger, but it got lost somewhere in the middle
Wow,
it has taken a while for me to get endb modifications done. It is still a couple of weeks away, and my coding will not pass the rigorous scrutiny of @Araq (and others), so there will be lots of suggested improvements. It has been such a lot of back-and-forth with changes over time - and I will probably have to consolidate all the changes into one commit (as a separate branch to devel so it can be cleaned up easily?)
BUT,
I think it is an improvement (YMMV).
Just to give a bit of a heads up:
The commands have changed slightly:
--------------------- GENERAL -----------------------------
h, help display this help message
q, quit quit the debugger and the program
<ENTER> repeat the previous debugger command
--------------------- EXECUTING ---------------------------
Note: precede the command by a number to repeat: 3 s for three steps
s, step step into a proc, or to next source code line.
ss, sys system step into lib/ files (but not lib/system/ files).
ss to delve into lib/ files; f, s or n to return to
the upper level.
n, next next step, stepping over proc calls.
f, skipcurrent forward steps until the current routine finishes.
c, continue, r, run continue execution until the next breakpoint (if any).
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.
[file] does not require the full path or extension.
bp, breakpoints display the entire breakpoint list.
t, toggle <fromline> [file]
enable or disable a breakpoint.
[file] does not require the full path or extension.
fn, filenames list all valid filenames.
--------------------- DATA DISPLAY ------------------------
e, expand toggle showing values (for local or global variables).
Disable expansion if there are large objects or
sequences with lots of data (default is off).
g, globals [file] display [to file] global variables,
which are vars from global scope or an imported lib.
l, locals [file] display [to file] variables in the current stack frame.
(If objects are displayed as [....], set the md higher)
v, variables [file] display [to file] the variables registered in the
current scope, registered while stepping through code.
p, print <expr> evaluate <expr> and print to screen (if in local or
global list). Evaluates regardless of the Expand setting.
o, out file <expr> evaluate <expr> and write it to <file>
w, where [n] display the current execution point, and optionally
n lines of preceeding step history.
u, up go up in the call stack (doesn't change the execution point).
d, down go down in the call stack.
bt, backtrace display the entire call stack.
md, maxdisplay <integer> set the display's recursion maximum (0..9).
and the output has changed.
So for test source code (filename = tst_end.nim) of
type
MyObj = object
s: string
i: int
var
i = 123
s = "Hello there"
m = MyObj(s: "Some string", i: 42)
proc p1(s: var string, i: var int): string =
var s2 = "Wow"
var
i2: int
i2 = 123
s = "Another string"
i *= 2
{.watchpoint: i.}
result = s & " " & $i & " :: " & $i2 & " " & s2
proc main() =
var
s = "Greetings"
i: int
i = 654
echo p1(m.s, m.i)
when isMainModule:
main() # -> Another string 84 :: 123 Wow
{.watchpoint: m.s .}
echo i, " ",s # -> 123 Hello there
which when run normally produces
Another string 84 :: 123 Wow
123 Hello there
will look this this when stepping through the code (I used 13s to step thirteen times repetitively)
endb| tst_endb.nim(6): tst_endb -> i = 123
endb| >> 13s
endb| tst_endb.nim(7): tst_endb -> s = "Hello there"
endb| tst_endb.nim(8): tst_endb -> m = MyObj(s: "Some string", i: 42)
endb| tst_endb.nim(28): tst_endb -> main() # -> Another string 84 :: 123 Wow
endb| tst_endb.nim(22): main -> s = "Greetings"
endb| tst_endb.nim(24): main -> i = 654
endb| tst_endb.nim(25): main -> echo p1(m.s, m.i)
endb| tst_endb.nim(11): p1 -> var s2 = "Wow"
endb| tst_endb.nim(14): p1 -> i2 = 123
endb| tst_endb.nim(15): p1 -> s = "Another string"
endb| tst_endb.nim(16): p1 -> i *= 2
endb| WATCHPOINT(17) tst_endb.i: int = 84
endb| tst_endb.nim(18): p1 -> result = s & " " & $i & " :: " & $i2 & " " & s2
Another string 84 :: 123 Wow
endb| WATCHPOINT(29) tst_endb.m.s: string = 0000000001da14e8"Another string"
endb| tst_endb.nim(30): tst_endb -> echo i, " ",s # -> 123 Hello there
123 Hello there
So there is
- file(line): proc -> source_code, eg
tst_endb.nim(6): tst_endb -> i = 123
endb| tst_endb.nim(8): m: MyObj = [0000000000691908"Another string", i = 84]
Anyway, probably another couple of weeks of further fixes before it is ready, but it is certainly closer to being ready for scrutiny.