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?

2015-09-06 13:17:38

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.

2015-09-06 16:07:34
I think
  • it is a handy (quick and easy to use) way of doing debugging, without needing to learn the full blown power of gdb.
  • Of course endb is limited (not useful if you are doing heavy stuff: multitasking, or complex objects: macros and ....).

So I see it as helping out newbies, so they can step thru their code and see what it is doing.

Will I add tests and volunteer to maintain it?
  • I am trying to work out if it is worth it, first
Further clarification required:

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

2015-09-06 23:21:08
Well, a fairly recent addition is the getType procedure for macros. Would that help? 2015-09-07 05:38:29

@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
  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

2015-09-07 07:01:57
ccgtypes.genTypeInfo handles tyVar differently than tyPtr for reasons I cannot remember. Likely an attempt to keep generated code size to a minimum.
2015-09-07 14:06:44
  • (I do solemnly swear ... )
  • I put my hand up for maintaining endb.
  • I will put in a issue on the tyVar extension for endb
  • I will look into adding tests for endb.
  • put some PRs in on improvements I have made
2015-09-07 23:09:14


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?)


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

  MyObj = object
    s: string
    i: int
  i = 123
  s = "Hello there"
  m = MyObj(s: "Some string", i: 42)

proc p1(s: var string, i: var int): string =
  var s2 = "Wow"
    i2: int
  i2 = 123
  s = "Another string"
  i *= 2
  {.watchpoint: i.}
  result = s & " " & $i & " :: " & $i2 & " " & s2

proc main() =
    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

  • source code of the current line displayed as:

  • file(line): proc -> source_code, eg

tst_endb.nim(6): tst_endb -> i = 123

  • watch points display file/line/name/type/value where the value is the repr() of the variable
  • listing local/global vars display like:

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.

2017-03-18 14:19:44
That looks very nice! 2017-03-18 15:22:51