[fpc-pascal] fpDebug extension for Visual Studio Code

Martin Frb lazarus at mfriebe.de
Tue May 19 16:42:21 CEST 2020


On 19/05/2020 15:55, Joost van der Sluis wrote:
> On 5/19/20 12:59 PM, Martin Frb wrote:
>> Where is that documented? Assuming this is part of the API?
>> E.g. what goes into Flags/AdditionalInfo?
>
> You misunderstood me. The class above is my own design. The 
> variable-definition of DAB is even simpler. (As you already found out)
>
> It is not documented, and, to be honest, only name, value and type are 
> being used now. It is just a rough idea, we have to figure things out.
Ah, I see.

In that case, the decision to be made is, if the classes from the 
DebuggerIntf package can be used (potentially after being updated).
There already is TFields, and that can be used (and can be generalized) 
for that kind of thing.

About DebuggerIntf:

1) DebuggerIntf was meant to be the API between IDE and the 
debugger-backend.
The backend is TFpDebugDebugger.
FpDebug is not the backend, its used by the backend. But it currently 
provides for the backend, and that means it uses those classes....

2) DebuggerIntf was never "designed".
It was ripped out of GDBMIDebugger, with the hope to be cleaned up and 
refactored. That hope is still there....

That also raises the question what you base your DAB classes on.
Some code that you will need, does live in TFpDebugDebugger
- Detecting the instantiated class, instead of the declared class.
- Checking breakpoint conditions (Though part of this should move into 
FpDebug)
- Handling Exceptions / stepping to except,finally (not sure if that is 
likely to move)


>
>> Btw, for Children (I guess Fields of a struct?) we have TDbgFields. 
>> So maybe that can be replaced? But it affects all debuggers....
>
> They don't have to be fields. It can be anything. To the user it is 
> presented as something they can collapse/expand. If you want to give a 
> hint to the GUI how to represent the data, you can set a flag.
Of course.

Arrays should also be collapse/expand able, so you can inspect each 
element (important of array of struct).
But arrays may contain thousands of elements.  So only a subset would be 
gotten at a time.

When designing collapse/expand, it is important to consider, that in the 
IDE data needs to be retrieved in async calls (i.e. IDE requests, 
debugger triggers event if data is ready)
- This is (not only) because gdb debuggers are slow
- This is also because the IDE needs to keep running when many values 
are queried, and the IDE needs to be able to send "step/run" while eval 
still runs => debugger should abort eval, if user wants to continue
Otherwise stepping becomes very sluggish, if you have a bigger list of 
watches.

> At least that's how it is implemented in DAB. I thought it would be a 
> good idea to add a second 'group of children', the AdditionalInfo. For 
> example for the character-set of a string. Things like that.

There are different kind of children (and the question is, if they can 
be mixed)
- named structure members
- indexed/numbered (array) members (low / high / request any (sub)range)
- internal properties (e.g. charset).
- Flags (set of enum)

Internal properties do not need a name. They could have an ID, which is 
an enum.
FpDebug can only provide internal properties about which it knows. So 
the full list of possible ID must always be known.
It would be a list (unique by ID).

Not sure if we need a list of base classes?
It be enough to have one (internal property) "base class", and search 
that recursively. Or allow it to be called with an index.

There also is the question, should (all/some/none) of the internal 
properties be created by default?
The structure could have a field "set of (id-list)" which indicates the 
available internal props. To be created on request.
And when creating a watch, one could pass in a set of ID, that should be 
pre-created.

There also may need to be control over caching the memory that was read. 
If that will still be needed for evaluating further info. (a cache 
exists, and is used for objects)

>
>> Though that creates issues:
>> - Calling in correct thread
>> - any data retrieval from the debugger needs to be async. I.e. on 
>> callback. The IDE demands the data, and it will be available in/after 
>> a callback.
>> However, maybe that can be done in a subclass/wrapper in the 
>> TFpDebugDebugger class. That is were the async is currently handled.
>
> Maybe. I don't really have a solution yet. Maybe the reference-id is 
> not that bad. (In FPDServer the id is an auto-incremented field. In a 
> map I store the related info, like the thread-id, callstack-index and 
> such. When this info is not available anymore, the item is removed 
> from the map. Seems to work ok)

It depends a lot where the cut between FpDebug and FpDebugDebugger goes.

FpDebug would not be async. But the design should allow for the caller 
to easily add that.

Also one more note:
- It should not affect above design to much
- I have not yet looked into how to archive this, but threading may get 
added to fpdebug at some time (not soon).
That needs to reflect that only one thread can read mem. Either:
- Internally, when FpDebug looks up symbols.
   - Different symbols (from one expression) could be searched in the 
dwarf info in parallel.
   - One Symbol could be searched in several CompilationUnits in 
parallel (that would be the easiest to do)
- Running several expressions in parallel, queuing Mem reads for the one 
thread that is allowed to read.
    (That last one might be the most efficient?)




More information about the fpc-pascal mailing list