fpDebug extension for Visual Studio Code

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

fpDebug extension for Visual Studio Code

Joost van der Sluis
Hi all,

As I wrote before I'm working on a fpDebug-extension for Visual Studio
Code, based on the DAB (Debug Adapter Protocol).

This protocol is also used by other editors.

I have a first version ready. It consists of the parts: the fpdserver
which implements the DAB-protocal and the fpDebug plugin which is just a
wrapper with some configuration-settings.

I'm a little bit amazed that the plugin has 10 install already, without
ever noticing it. Or maybe these are just bots or something...

All the basics should work, if someone could test it a bit that would be
nice.

Threading-support is still very lacking, and how variables are presented
is not really nice. I'll be working on that.

And maybe someone can create an icon for it?

Here are the links:

FPDServer:
https://gitlab.freepascal.org/Joost/fpdserver

fpDebug plugin:
https://marketplace.visualstudio.com/items?itemName=CNOC.fpdebug

Regards,

Joost.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Martin Frb
On 18/05/2020 23:43, Joost van der Sluis wrote:
> All the basics should work, if someone could test it a bit that would
> be nice.
>
> Threading-support is still very lacking, and how variables are
> presented is not really nice. I'll be working on that.

While this can be changed in PascalBuilder, there are some considerations.

Some of those may want to become configurable. So not sure yet.
More likely the formatting may want to depend an arguments passed to the
functions.
In the Lazarus IDE currently representation of the values is entirely to
the backend. And that is plain wrong. The IDE will have to have some
influence on that.

I haven't yet given it much consideration. Just putting it out there for
thought....
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Joost van der Sluis
On 5/19/20 12:22 AM, Martin Frb wrote:

> On 18/05/2020 23:43, Joost van der Sluis wrote:
>> All the basics should work, if someone could test it a bit that would
>> be nice.
>>
>> Threading-support is still very lacking, and how variables are
>> presented is not really nice. I'll be working on that.
>
> While this can be changed in PascalBuilder, there are some considerations.
>
> Some of those may want to become configurable. So not sure yet.
> More likely the formatting may want to depend an arguments passed to the
> functions.
> In the Lazarus IDE currently representation of the values is entirely to
> the backend. And that is plain wrong. The IDE will have to have some
> influence on that.
>
> I haven't yet given it much consideration. Just putting it out there for
> thought....

Yes, you write about it earlier. Now it's time to discuss things.

Looking at the DAB-protocol I came to some new insights. Microsoft
managed to create a simple interface which makes it possible for all
kinds of debuggers to work with the same GUI. Just by adding an
abstraction layer.

Only thing is that I missed a few functions and do not need others.

So I've added my own abstraction layer. Now it is in the FPDServer
project, but I think it should be made part of fpDebug itself.

It is basically this class: (see
https://gitlab.freepascal.org/Joost/fpdserver/blob/master/fpdbgvariables.pas)

   TDbgVariable = class
   private
     FName: string;
     FValue: string;
     FType: string;
     FVisibleInScope: Boolean;
     FFlags: TStringArray;
     FAdditionalInfo: TDbgVariableList;
     FInheritedChildren: TDbgVariableList;
     FChildren: TDbgVariableList;
   published
     property Name: string read FName write FName;
     property Value: string read FValue write FValue;
     property &Type: string read FType write FType;
     property VisibleInScope: Boolean read FVisibleInScope write
FVisibleInScope;
     property Flags: TStringArray read FFlags write FFlags;
     property AdditionalInfo: TDbgVariableList read FAdditionalInfo;
     property InheritedChildren: TDbgVariableList read FInheritedChildren;
     property Children: TDbgVariableList read FChildren;
   end;

I think that we can give a frontend (Lazarus, Console, DAB) all the
information it needs with this structure.

The advantage is that it is layered, so a GUI can collapse information.
We could expand the TDbgVariableBuilder to create these structures.

For strings for example, we could add the length, string-type,
binary-representation and character-set of the string in AdditionalInfo.
In VS Code this info will end-up as a child of the variable, which a
user could expand if needed.

A lot of the existing functionality can be used.

Regards,

Joost.




_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Martin Frb
On 19/05/2020 10:42, Joost van der Sluis wrote:

>
> Yes, you write about it earlier. Now it's time to discuss things.
>
> Looking at the DAB-protocol I came to some new insights. Microsoft
> managed to create a simple interface which makes it possible for all
> kinds of debuggers to work with the same GUI. Just by adding an
> abstraction layer.
>
> Only thing is that I missed a few functions and do not need others.
>
> So I've added my own abstraction layer. Now it is in the FPDServer
> project, but I think it should be made part of fpDebug itself.
>
> It is basically this class: (see
> https://gitlab.freepascal.org/Joost/fpdserver/blob/master/fpdbgvariables.pas)
>
>   TDbgVariable = class
>   private
>     FName: string;
>     FValue: string;
>     FType: string;
>     FVisibleInScope: Boolean;
>     FFlags: TStringArray;
>     FAdditionalInfo: TDbgVariableList;
>     FInheritedChildren: TDbgVariableList;
>     FChildren: TDbgVariableList;
>   published
>     property Name: string read FName write FName;
>     property Value: string read FValue write FValue;
>     property &Type: string read FType write FType;
>     property VisibleInScope: Boolean read FVisibleInScope write
> FVisibleInScope;
>     property Flags: TStringArray read FFlags write FFlags;
>     property AdditionalInfo: TDbgVariableList read FAdditionalInfo;
>     property InheritedChildren: TDbgVariableList read FInheritedChildren;
>     property Children: TDbgVariableList read FChildren;
>   end;
>
> I think that we can give a frontend (Lazarus, Console, DAB) all the
> information it needs with this structure.
>
> The advantage is that it is layered, so a GUI can collapse
> information. We could expand the TDbgVariableBuilder to create these
> structures.
>
> For strings for example, we could add the length, string-type,
> binary-representation and character-set of the string in
> AdditionalInfo. In VS Code this info will end-up as a child of the
> variable, which a user could expand if needed.
>
> A lot of the existing functionality can be used.
Where is that documented? Assuming this is part of the API?
E.g. what goes into Flags/AdditionalInfo?

Btw, for Children (I guess Fields of a struct?) we have TDbgFields. So
maybe that can be replaced? But it affects all debuggers....

Things like Children should have a Getter, so they can be produced on
demand.
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.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Martin Frb
On 19/05/2020 12:59, Martin Frb wrote:
> Where is that documented? Assuming this is part of the API?
The closest I could find:
https://microsoft.github.io/debug-adapter-protocol/specification#Types_Variable

I would much prefer if "Flags: TStringArray" could be a "set of (...)"
And then somehow be mapped.

FpDebug could take a "class of TDbgVariable". And then create whatever
subclass you need.
So your subclass could map that into strings.


_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Joost van der Sluis
In reply to this post by Martin Frb
On 5/19/20 12:59 PM, Martin Frb wrote:

> On 19/05/2020 10:42, Joost van der Sluis wrote:
>> It is basically this class: (see
>> https://gitlab.freepascal.org/Joost/fpdserver/blob/master/fpdbgvariables.pas)
>>
>>
>>   TDbgVariable = class
>>   private
>>     FName: string;
>>     FValue: string;
>>     FType: string;
>>     FVisibleInScope: Boolean;
>>     FFlags: TStringArray;
>>     FAdditionalInfo: TDbgVariableList;
>>     FInheritedChildren: TDbgVariableList;
>>     FChildren: TDbgVariableList;
>>   published
>>     property Name: string read FName write FName;
>>     property Value: string read FValue write FValue;
>>     property &Type: string read FType write FType;
>>     property VisibleInScope: Boolean read FVisibleInScope write
>> FVisibleInScope;
>>     property Flags: TStringArray read FFlags write FFlags;
>>     property AdditionalInfo: TDbgVariableList read FAdditionalInfo;
>>     property InheritedChildren: TDbgVariableList read FInheritedChildren;
>>     property Children: TDbgVariableList read FChildren;
>>   end;

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

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

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.

> Things like Children should have a Getter, so they can be produced on
> demand.

Yep. But I see this structure more as a an interface. A definition about
how the data should be structured.

In DAB they resolve this by setting some reference-id. So instead of the
children, you get an ID. And if you want to have the children, just send
a request with the given Id, and you will receive the children.

Not a real solution for our case, I would think.

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

Regards,

Joost.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

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


_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Joost van der Sluis
Seems like the first message did not make it to the list. Maybe because
of the attachments... Retry:

Op 19-05-2020 om 16:42 schreef Martin Frb:

> On 19/05/2020 15:55, Joost van der Sluis wrote:
>> 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.
>
> 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....

I was very disappointed when i (re?)-discovered that fpDebug has a
dependency on DebuggerIntf.

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

It is even more complex then I could remember.
   Thanks for the update, very useful. I think it is difficult to
discuss a new design/solution at a distance. I've tried to catch the
problems in some pictures.

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)

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.

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

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.

What do you think?

Regards,

Joost.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Martin Frb
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
debugger"
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.


*** FORMATTER CLASS
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
formatter...
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
Vmt....
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.



_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Martin Frb
On 20/05/2020 19:54, Martin Frb wrote:

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

And then there is/was the idea with: getting data on request.

Creating a list of objects for all the fields of a class, needs to be
optional.
Well it is, by means of flags passed to Pascalbuilder.

What is missing, is the ability to later upgrade. There are 2
considerations.
1) re-reading target mem.
There already is a cache for target mem.
If TFpValue and TPascalBuilder are hold by a "watch value class", this
can control the cache, and keep the memory.
This memory is only the class. Vaules by ref, like strings are not included.

2) adding list of fields, to watch that was text only
This will also rebuild the text. That can be suppressed, if needed....
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Martin Frb
In reply to this post by Martin Frb
Ok, here are some of my ideas/hopes/dreams/wishes for the IDE....
They are all "ideas only", with on knowledge of when/if they may be done.

I provide them, in the hope they will help choosing a path for the backend.

The IDE should receive a "TWatchWhateverValue" from any of the backend,
that provides:

1) async interface (that is actually for the benefit of the backends)
Currently the IDE would call a method (example callstack)
- IDE calls "count" => not yet known = 0
- the backend starts retriving the value, and once the value is avail,
it triggers an "changed" event
- IDE calls count again.
- IDE starts accessing the items in the list.
   They may be available, but if not the return "evaluating" (or
whatever dummy value), and the backend will get them and trigger
"change" again.

Alternative, there could be a CountState, that would return if the count
is already avail. The trigger to get the count, would still be to call
"count".

However, the backend must be able to retrieve any requested data from
fpdebug, and that should be in a format that is ready for the IDE.
(TDebuggerIntf classes)

Evaluating huge data, may need to be "interruptible" => either called in
small blocks (like the callstack at current), or by run in a thread, and
check for an "abort state".
For single watches this is currently not needed.

2) the IDE must be able to retrieve values in different formats, with
minimum work of the backend (but allowing for async)
- An ordinal value must either be known as ordinal (none text form),
then the IDE can do dec/hex/bin...
   or it can be retrieved from the TWatchWhateverValue in any of those
formats (and does not need complete re-eval)
- Hex representation: this can do a re-eval if needed
- A structure may have different text formats (more or less verbose...)
- objects for fields/members (array element) can be retrieved.
   array element, probably re-use one instance, changing the value. One
would not want to create thousands of instances....

Because any op can be async, the current way of just calling the getter,
and getting a dummy "evaluating" value/object works well.
The IDE does not need to differ if the value is final or not. If it is
not final a "changed" event is triggered, and the IDE starts again (same
as if the debugger entered pause)

3) The TWatchWhateverValue must be able to store (and serialize) its
data. Or a part of it.
It must be able to "work on the stored data only".
Watches are added to debug history. If viewed from history, no further
eval is possible. The debugged app has changed its state...
Currently this stores the display-text. Limiting changed to display format.
It would be up to the IDE how match the watch stores, and the watch
would then only be able to return the stored subset of data.
It also must be able to serialize, as the history can be saved/loaded
to/from xml.

---------------------------------

The async part may make things tricky

IF a watch asks for the list of fields, it gets TDbgFields or similar.
But a field may be an object with fields of its own.
So if this TDbgField is asked for its field, that must somehow be async to.

Yet the baseclass may not necessary need that implementation..
So PascalBuilder would need to create Fields, but the exact subclass
could be given by the backend.

Disclaimer: I have not fully thought that through.... And many thinks
should probably only be added, when they will be needed.
As I said, just to help keeping the design flexible enough.





_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: fpDebug extension for Visual Studio Code

Free Pascal - General mailing list
In reply to this post by Joost van der Sluis


> On May 19, 2020, at 4:43 AM, Joost van der Sluis <[hidden email]> wrote:
>
> Hi all,
>
> As I wrote before I'm working on a fpDebug-extension for Visual Studio Code, based on the DAB (Debug Adapter Protocol).

Excellent, I applaud your efforts. I'm busy now but I'll be sure to test this later. I'm using LLDB in VSCode as my primary debugger for Pascal now so I'm eager to see what improvements you may have made.

As for the language server I've taken a break from it for a week but I've implemented ~90% of the protocol already and once I get it cleaned up it will be usable also.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

FpDebug hands-on: AnsiStrings

Joost van der Sluis
In reply to this post by Martin Frb
Op 20-05-2020 om 20:48 schreef Martin Frb:
> Ok, here are some of my ideas/hopes/dreams/wishes for the IDE....
> They are all "ideas only", with on knowledge of when/if they may be done.

Ok, clear. Thanks again for the info. I think we can conclude that most
parts are there. It only needs some polishing. Except for the threading
and smoothness of the debugging-experience in Lazarus. There we have
some work to do...

Now, a hands-on example. We can discuss the theory later on again.

I've added codepage-support for ansistrings, compiled with -gw3. This is
done in the TFpValueDwarfV3FreePascalString class, which does the heavy
work regarding the formatting of strings. Although there is also some
code in TFpDebugDebugger.EvaluateExpression and probably other places
that change the formatting of string-values.

So I've made my change in TFpValueDwarfV3FreePascalString, but I don't
know if this is the right place. After all, it is about formatting, and
this class is related to the Dwarf-debug info. On the other hand. I do
understand why this logic in implemented here. This is *the* place where
all the relevant information is present.

But that the design is problematic can be seen in a comment in the file:

   // TODO: XXXXX Dynamic max limit

This seems an easy task, but it is not. TFpValueDwarfV3FreePascalString
is not bound to the GUI or does not have formatting-settings. But it is
the place where the formatting takes place! But adding a
formatting-setting (like a max-length for strings) at this location
would be really strange.

I see two solutions: Besides the AsString property we could add a
GetAsString procedure with some parameters on how to format the string.
Maybe the easiest at this moment, and this morning I though it was a
good idea. (Note that I want to add more stuff, like function to
retrieve the code-page, and the raw-data)

But then again, maybe the other solution, to split this formatting-logic
into another class might be better...

I'll try if I can split the logic. If doable, that might be better.

(Still a lot of theory, though)

Regards,

Joost.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FpDebug hands-on: AnsiStrings

Joost van der Sluis


Op 21-05-2020 om 17:29 schreef Joost van der Sluis:

> Op 20-05-2020 om 20:48 schreef Martin Frb:
>> Ok, here are some of my ideas/hopes/dreams/wishes for the IDE....
>> They are all "ideas only", with on knowledge of when/if they may be done.
>
> Ok, clear. Thanks again for the info. I think we can conclude that most
> parts are there. It only needs some polishing. Except for the threading
> and smoothness of the debugging-experience in Lazarus. There we have
> some work to do...
>
> Now, a hands-on example. We can discuss the theory later on again.
>
> I've added codepage-support for ansistrings, compiled with -gw3. This is
> done in the TFpValueDwarfV3FreePascalString class, which does the heavy
> work regarding the formatting of strings. Although there is also some
> code in TFpDebugDebugger.EvaluateExpression and probably other places
> that change the formatting of string-values.
>
> So I've made my change in TFpValueDwarfV3FreePascalString, but I don't
> know if this is the right place. After all, it is about formatting, and
> this class is related to the Dwarf-debug info. On the other hand. I do
> understand why this logic in implemented here. This is *the* place where
> all the relevant information is present.
>
> But that the design is problematic can be seen in a comment in the file:
>
>    // TODO: XXXXX Dynamic max limit
>
> This seems an easy task, but it is not. TFpValueDwarfV3FreePascalString
> is not bound to the GUI or does not have formatting-settings. But it is
> the place where the formatting takes place! But adding a
> formatting-setting (like a max-length for strings) at this location
> would be really strange.
>
> I see two solutions: Besides the AsString property we could add a
> GetAsString procedure with some parameters on how to format the string.
> Maybe the easiest at this moment, and this morning I though it was a
> good idea. (Note that I want to add more stuff, like function to
> retrieve the code-page, and the raw-data)
>
> But then again, maybe the other solution, to split this formatting-logic
> into another class might be better...
>
> I'll try if I can split the logic. If doable, that might be better.
>
> (Still a lot of theory, though)
>
> Regards,
>
> Joost.
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FpDebug hands-on: AnsiStrings

Joost van der Sluis
In reply to this post by Joost van der Sluis
Excuses for the empty mail...

Op 21-05-2020 om 17:29 schreef Joost van der Sluis:
> This seems an easy task, but it is not. TFpValueDwarfV3FreePascalString
> is not bound to the GUI or does not have formatting-settings. But it is
> the place where the formatting takes place! But adding a
> formatting-setting (like a max-length for strings) at this location
> would be really strange.

I know that it was probably me who who designed it this way. But maybe I
learned a few new things in all those years...

Regards,

Joost.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FpDebug hands-on: AnsiStrings

Martin Frb
In reply to this post by Joost van der Sluis
On 21/05/2020 17:29, Joost van der Sluis wrote:

> I've added codepage-support for ansistrings, compiled with -gw3. This
> is done in the TFpValueDwarfV3FreePascalString class, which does the
> heavy work regarding the formatting of strings. Although there is also
> some code in TFpDebugDebugger.EvaluateExpression and probably other
> places that change the formatting of string-values.
>
> So I've made my change in TFpValueDwarfV3FreePascalString, but I don't
> know if this is the right place. After all, it is about formatting,
> and this class is related to the Dwarf-debug info. On the other hand.
> I do understand why this logic in implemented here. This is *the*
> place where all the relevant information is present.
>
> But that the design is problematic can be seen in a comment in the file:
>
>   // TODO: XXXXX Dynamic max limit
This is not really about formatting. A corrupt debug target, could
return a string length of 2^31, not something that the debugger should
attempt to read. (newer gdb have similar options, if the data is to
large they return nothing / for strings we can do better and get the start)
That can happen when reading locals before the stackframe is set up.

Part 2 is formatting related....  In most cases the user does not need a
10kb string, the user may want offset 1500 len 500. Ideally then the
debugger only reads that part. That part may move to the formatter. But
also may need an extension to target reading the correct subset of the data.

Currently config for FpDebug does not exist. It needs to be integrated
with the config for LazDebuggerFp (i.e. use TDebuggerProperties so it
can be streamed). Yet separated from config that is only for LazDebuggerFp.
That is why the value is hardcoded.
I want to avoid having to copy all the values in from LazDebuggers
config to FpDebug config (which happens now for the 2 configs avail)

max memory limits can be passed via TFpDbgMemReader = class(TDbgMemReader)
TDbgMemReader could have a property that can be read by the dwarf classes.


>
> This seems an easy task, but it is not.
> TFpValueDwarfV3FreePascalString is not bound to the GUI or does not
> have formatting-settings. But it is the place where the formatting
> takes place! But adding a formatting-setting (like a max-length for
> strings) at this location would be really strange.
Well the current code (your commit) does not do formatting.
It adds the info to the string.

The formatter, getting the longstring, can read the codepage from it.
The formatter can also read the string byte by byte.

  SetCodePage(RResult, Codepage, False);
Does not change the raw data in the string (only the meaning it has).
As long as it does not accidentally get converted while being passed around.

> I see two solutions: Besides the AsString property we could add a
> GetAsString procedure with some parameters on how to format the
> string. Maybe the easiest at this moment, and this morning I though it
> was a good idea. (Note that I want to add more stuff, like function to
> retrieve the code-page, and the raw-data)
If needed I would rather add the 2 new functions. Though it seems the
data is actually returned as part of the longstring?

If you need individual calls to retrieve that info, it could be done by
something like GetMember.
GetMember has to much overhead. as it returns a big object.

But something like
    GetDataProperty(AnPropId: Integer): Pointer;
would be generic enough to return any additional data.
(yes ID is integer. quicker to much than doing string compare)

Or you add dedicated properties to TFpValueDwarfV3FreePascalString and
use type casting.  *** For starters, I would go with that, and later
redesign

I am not sure about adding to many methods to for up the hierarchy, and
needing meaningless defaults for them.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FpDebug hands-on: AnsiStrings

Joost van der Sluis
Op 21-05-2020 om 18:25 schreef Martin Frb:

> On 21/05/2020 17:29, Joost van der Sluis wrote:
>>
>> But that the design is problematic can be seen in a comment in the file:
>>
>>   // TODO: XXXXX Dynamic max limit
> This is not really about formatting. A corrupt debug target, could
> return a string length of 2^31, not something that the debugger should
> attempt to read. (newer gdb have similar options, if the data is to
> large they return nothing / for strings we can do better and get the start)
> That can happen when reading locals before the stackframe is set up.

Might be, you could see this as a saveguard. But my goal is to cut-out
the middle part of the string. That's formatting....

> Part 2 is formatting related....  In most cases the user does not need a
> 10kb string, the user may want offset 1500 len 500. Ideally then the
> debugger only reads that part. That part may move to the formatter. But
> also may need an extension to target reading the correct subset of the
> data.

Indeed

> If needed I would rather add the 2 new functions. Though it seems the
> data is actually returned as part of the longstring?

No, it is not, because the result is assigned to an AnsiString, and
therefor the compiler could decide to change it's codepage. In this
function or somewhere further down the line.

> If you need individual calls to retrieve that info, it could be done by
> something like GetMember.
> GetMember has to much overhead. as it returns a big object.
>
> But something like
>     GetDataProperty(AnPropId: Integer): Pointer;
> would be generic enough to return any additional data.
> (yes ID is integer. quicker to much than doing string compare)

What you are saying is that the TFpValue doesn't do the formatting. But
it retrieves the data. And indeed it's very suitable for that.

But then, we should be consistent. And do not let any other classes (The
formatter I was talking about, but also the PrettyPrinter and such)
retrieve data. Such a class could always create a TFpValue for their own
use....

Regards,

Joost.


_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: FpDebug hands-on: AnsiStrings

Martin Frb
On 21/05/2020 20:19, Joost van der Sluis wrote:
> Might be, you could see this as a saveguard. But my goal is to cut-out
> the middle part of the string. That's formatting....
Well, we should have the safeguard. And make it configurable.
... See below

>> Part 2 is formatting related....  In most cases the user does not
>> need a 10kb string, the user may want offset 1500 len 500. Ideally
>> then the debugger only reads that part. That part may move to the
>> formatter. But also may need an extension to target reading the
>> correct subset of the data.
> Indeed

Now for your goal. That does not conflict with the safeguard. When
"getting the middle of a string" is added, then the safeguard still
applies. (Well maybe).

If the user says get me SomeString[1000..1999] (1000 chars) =>
technically the safeguard should apply (no problem if user configurable.
This may sound nonesense, when the user gives hardcode dimensions. But
what if
    SomeString[1000..1000+i]

Btw, It may be a good idea to teach pascal parser that syntax. (also for
arrays)

Anyway: A formatter can temp increase the safeguard. So there is no
problem with keeping it on this level.

To get substrings, one needs to be able to read the length, without
actually starting to retrieve the text. (would be a waste, to retrieve
text that will not be needed).
So maybe implement
   GetMemberCount
to return the amount of "char"s (bytes / words for widestring)

And then one new method is needed to get the substring.
Need to check which other dwarf types could benefit. (For arrays members
are retrieved individually, but maybe target mem could be read and
cached (like for structures)


>
>> If needed I would rather add the 2 new functions. Though it seems the
>> data is actually returned as part of the longstring?
>
> No, it is not, because the result is assigned to an AnsiString, and
> therefor the compiler could decide to change it's codepage. In this
> function or somewhere further down the line.
Then the result type should be changed to rawbytestring or whatever is safe?
At least so that the formatter can get it correct. Other calling code
may assign it to whatever that code wants....

>
> What you are saying is that the TFpValue doesn't do the formatting.
> But it retrieves the data. And indeed it's very suitable for that.
Should be that way.

>
> But then, we should be consistent. And do not let any other classes
> (The formatter I was talking about, but also the PrettyPrinter and
> such) retrieve data. Such a class could always create a TFpValue for
> their own use....
Have to look at it case by case. Ideally yes.

It may have to be judged for performance:
Array members are gotten by re-using the same TFpValue. Otherwise
retrieving a large array would be expensive...
If the formatter would all the sudden need to create extra object for
each array value....

Anyway case by case.







_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal