[fpc-pascal] fpDebug extension for Visual Studio Code

Martin Frb lazarus at mfriebe.de
Wed May 20 19:54:56 CEST 2020

On 20/05/2020 17:50, Joost van der Sluis wrote:
> I was very disappointed when i (re?)-discovered that fpDebug has a 
> dependency on DebuggerIntf.
It is a bit of a catch22:
- On the one hand, FpDebug is/should be stand alone.
- On the other hand, it would be a pity to have to copy all the used types.

There is basic stuff like TDbgPtr. If needs must, that could be 
redeclared, with IFDEF....
But there is also result classes for PascalBuilder (and probably 
somewhere stackframes). Removing this may add a lot of overhead.

FpDebug also uses LazUtils package. And that wont be easy to resolve, 
unless by "copy and paste" :(

> Picture1: http://amira.cnoc.nl/fpc/FPDebugDesign1.svg
> Picture1 show what I want to achieve. I want to use the formatting of 
> variables and such in another environment as Lazarus. And ind the long 
> term I want to make it possible  for Lazarus to use other debuggers. 
> Also for other languages. (Using DAB or others)
Should the arrows be the other way round?
   console  === "has a / uses " ===> var/type-formatter

> Picture2: http://amira.cnoc.nl/fpc/FPDebugDesign2.svg
> Picture2 shows the current situation at a high abstraction level. The 
> logic for displaying variables is all over the place, as you explained.
> Please correct me, if I'm wrong somewhere.
"There are several implementations of DebuggerIntf, each for a specifig 
There is only one "DebuggerIntf" (aka API).
The Interface is "designed" to provide base-classes for both: the IDE 
and each backend.

So GDBMIDebugger is a "debugger backend". As such it inherits the 
provided base classes of the DebuggerIntf.
The Backends then use an actual debugger (gdb, lldb, fpDebug)

Formatting does not really happen in the Frontend (IDE) or DebuggerIntf.

It happens either in the "Backend": reformat from what gdb gave us.
Or in the debugger: FpDebug/PascalBuilder.

> Picture3: http://amira.cnoc.nl/fpc/FPDebugDesign3.svg
> Picture3 shows a possible solution. We add a new class, in the picture 
> called 'formatter' to handle the display of variables. As an input it 
> will need some 'handler' which implements an interface with functions 
> to retrieve debug-information and access memory. It's output can be in 
> something like the TDbgVariable format I showed before. (Needs 
> adaptation, though).
I think some arrows go the wrong way round?

> In the picture I let the IDE make a direct connection to this new 
> 'formatter'. But maybe it is better to do this in DebuggerIntf.
> I also thought about a migration-path: we can just add this new route, 
> without using it. And then enable it bit-by-bit. We could alse add a 
> 'default' implementation in DebuggerIntf. So all debug-handlers may 
> use it, or add overrides to do it in a different way.

DAB and Console => those should be handled like debugger backends. 
Except they do not need IDE compatibility. But they do the same task.
And add FpDebugServer.

First of all "Formatter" (PascalBuilder) is already somewhat exchangeable.
It is currently up to the "backend" what to call to get text.
   "Backend" calls Parser (currently PascalParser) to get FpDebug 
internal value.
   "Backend" hands result to Formatter (PascalBuilder)
The Formatter still needs to read memory. This needs to be the case, as 
the amount of memory to be read can depend on the format (i.e. a pointer 
in the data may display the address, or read the data at the address).

Some formatting should be responsibility of the IDE (or debugger frontend)
1) I.e Changing decimal to hex => no need for the backend
2) On the other hand, the IDE does not know, how to display a 
"structure" (record, class, object, or even none Pascal). That is work 
the backend needs to do.
    (That is as a single text, not be expanding a [+] subitems view)
3) The backend also needs to deliver different data for hex dump.

Most of that exists, in the current classes in TDebuggerIntf. (with some 
issues though)

If you look at using FpDebug directly, then you use TFpValue. (returned 
by PascalParser, or any Parser you want to add)
All you need is to encapsulate PascalBuilder into a class.
And stick the value and the builder into yet another object, holding 
both of them.

TPascalBuilder would then be a formatter class.
It would also deliver the structures for fields, elements, children.....

TPascalBuilder  can be configured, for verbosity. (optino to skip all 
the typenames, it currently includes)

With TPascalBuilder  it can also be passed to whatever code builds 
stackframes. So formatting for those can be affected. (because the class 
carries the config)

For the IDE it is more work. There needs to be an abstraction that works 
with all backends.
And the abstraction must be serializable (for DebugHistory window) / or 
partly serializable.

For the IDE it is important that the "formatter" delivers fields, 
elements, children in the classes provided by TDebuggerInf.
Otherwise the backends, must copy all the data into the expected classes 
(duplicating all the data)


The problem of "use instance class".  This is neither parser, nor 
The steps are:
- Eval: Sender
- use formatter (or other tool) to get the classname of the instance
- write new watch "TButton(Sender)"
- Eval "TButton(Sender)"

"classname of the instance" can not be done by PascalBuilder.
It needs FpcPascalBuilder. (or ability to call functions)

There is no field for "classname of the instance" (not in dwarf).
Actually, maybe if you have full debug info for RTL, and can go via 
PVmt..... But normally not.
The debugger relies on the hardcoded info of where the name is in the 
So only an Fpc specific class can be allowed to access this.

Once you got the classname of the instance, the typecasting can be done, 
and the watch can be substituted.

More information about the fpc-pascal mailing list