Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2018-11

Switching debugger based on Project settings for embedded targets

9 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Michael Ring

Hi!

Since a while I am using lazarus not only to edit/compile projects for embededded controllers, but also debugging now works very nicely.

There is only one issue I see at the moment, the debugger is a global setting, afaik I cannot change the debugger configuration based on a project.

The problem is that for debugging arm I will have to use arm-none-eabi-gdb, for pic32 I will have to use mips-sde-elf-gdb for debugging and both will have to use a special debugger class for interfacing with Segger JLink Debug Probe and possibly openocd in the future.

Other people, that use Lazaeus for Windows/Linux/Mac Development would also need to change the global setting when switching from embedded development to native development to the default gdb debugger.

What is the best way to implement this project based override, I guess I can do the coding myself as I have also created my own debugger for JLink, but I do not know how to do this debugger switching in the proper 'Lazarus' way.....

Thanks in advance,

Michael

Reply by email

Martin Frb
to Michael Ring
Michael Ring wrote 18 lines
There is only one issue I see at the moment, the debugger is a global setting, afaik I cannot change the debugger configuration based on a project. The problem is that for debugging arm I will have to use arm-none-eabi-gdb, for pic32 I will have to use mips-sde-elf-gdb for debugging and both will have to use a special debugger class for interfacing with Segger JLink Debug Probe and possibly openocd in the future. Other people, that use Lazaeus for Windows/Linux/Mac Development would also need to change the global setting when switching from embedded development to native development to the default gdb debugger. What is the best way to implement this project based override, I guess I can do the coding myself as I have also created my own debugger for JLink, but I do not know how to do this debugger switching in the proper 'Lazarus' way.....

Indeed an issue that several people raised....
Well first of all, it depends on how much work you want to spent. There are several approaches possible.
Just some initial thoughts, ideas are welcome...

* All of them should really refactor the "debugger setting" related stuff from the big TEnvironmentOptions class into its own class, so that it can be re-used as needed.

Some details are more than what would be really required to have a working version. Up to you how far you want to go. (I got a bit carried away while typing)

1) Have an override in the project. All the settings can be stored there too.
That may require duplication of the frontend, so the project options can show the same setting page.
Not my favourite (and not sure if the least work)

2) Expand the TEnvironmentOptions, so they can have a list of named options. The project then chooses by name/ID (for each buildmode).
- That just adds a name dropdown / add/del button to the existing config.
- The config must then be stored like the units in the project lpi, each config in a different path.
  The current path <CONFIG>  <EnvironmentOptions> <Debugger ...> would then be replaced by <CONFIG> <EnvironmentOptions> <Debuggers>  <Debugger1 name="" ...>
  The EnvOptsVersion would be increased so code knows what to load.

The DebugManager would ask the TEnvironmentOptions via TEnvironmentOptions.GetDebuggerConfByName(name) and get the refactored/extracted object that holds all the debugger setting. So outside the TEnvironmentOptions changes will be minimal. (Hopefully)

- Name or ID could be used. This has an impact when projects are shared between people.
  It needs some additional thought what to do, if a name/id is not found.   Also names have the issue, that the same name, does not guarantee the same settings.
  ID could be UUID, but then you would never have the correct settings for some one else's project. And you cant change the UUID in the lpi (or the other person has a problem), so you must create the same ID in your TEnvironmentOptions....,
 Maybe storing (in the lpi) a name, with DebuggerType/Class (eg GDBMI) and optional an ID. Then if you do not have the ID, you can import it, to any of your configs (so each config in TEnvironmentOptions can have many IDs)

- Optional/Later: there could be an option where to save the setting EnvironmentOptions/project.lpi/project.lps
  But it would still be the TEnvironmentOptions responsibility to coordinate everything.
  Note that some setting, like Ignored-Exceptions are already on the project. They do not need to be affected.

3)
Your idea?

-----------------
I like the 2nd, but please bring forward any thoughts you have. Let me know your ideas, and what you think is plausible for you to do, and we can look at implementation details.

*** Also despite me bringing forward various options, not all of them will be required. ***
*** E.g you could deliver a working version using just a name list in EnvironmentOptions. And a name in the project. Thats afaik the minimum needed ***

Reply by email

Dimitrios Chr. Ioannidis
to Michael Ring: Hi! Since a while I am using lazarus not only to edit/compile projects for embededded…

Hi,

Michael Ring wrote
What is the best way to implement this project based override, I guess I can do the coding myself as I have also created my own debugger for JLink, but I do not know how to do this debugger switching in the proper 'Lazarus' way.....

I would like to be involved / help as I am thinking implementing the mEDBG protocol and intergrate it to Lazarus to debug AVR MCU's using this debugger https://hackaday.io/project/162372-xplained-yourself .

I already tried to use the avr-gdb --> avarice --> dragon --> atmegaxxx combination ( which worked in Linux but not in Windows ) and the result is that I have 3 bricked mcu's ( most probably by flashes has been worn out by software breakpoints) . Not even the HVPP procedure restore them.

Anyway if I can help ( and learn at the same time the Lazarus / Debug internals ) that would be awesome.

regards,

Dimitrios Chr. Ioannidis

Reply by email

Martin Frb
to Dimitrios Chr. Ioannidis
Dimitrios Chr. Ioannidis wrote 12 lines
  I would like to be involved / help as I am thinking implementing the mEDBG protocol and intergrate it to Lazarus to debug AVR MCU's using this debugger https://hackaday.io/project/162372-xplained-yourself .   I already tried to use the avr-gdb --> avarice --> dragon --> atmegaxxx combination ( which worked in Linux but not in Windows ) and the result is that I have 3 bricked mcu's ( most probably by flashes has been worn out by software breakpoints) . Not even the HVPP procedure restore them.   Anyway if I can help ( and learn at the same time the Lazarus / Debug internals ) that would be awesome.

The Debugger in Lazarus consists of 2 layers (plus the external exe, if based on one)

The presentation and IDE control: DebugManager/DebugBoss The BackEnd: LazDebuggerGDBMI, and others.

You would need a new backend.

Backends are based on the DebuggerInterface components\debuggerintf\... This is not yet documented. (And may still be subject to small changes). [Actually someone started to put something on the wiki, I dont know if that has gone anywhere ...., I recommend to look at example code, see below]

The easiest way for you is to look at an existing implementation, and replace the communication with the external exe.
The "simplest" available is:
components\lazdebuggers\lazdebuggerlldb\lazdebuggerlldb.lpk

And you can go back in SVN to its initial revisions, to get an even simpler version.

Depending on how your external exe works, you need some sort of control when to send which message, and how to parse the answers... "lazdebuggerlldb" has 2 internal queues:
- One in commandline debugger, which controls sending individual commands, and waiting for answers.
- One in  the main lazdebuggerlldb, which is hard to explain: The truth is, it shouldn't be a queue, it is a poor replacement for a state. (It happens to be as it is, because it was copied from the gdbmi debugger....). Its purpose is to ensure, that watches do not run, while the target is running, or step/run is not done while evaluating a watch. So basically if an "action" (that may consists of one or many commands to the external exe) needs to wait for the correct debuggerstate, then that somehow happens here. Not all actions need to wait, so they may bypass that queue.....

To start with ignore the inner queue, and send your commands directly to the external exe. Once you can do that, you can start thinking about coordinating the bigger picture.

Reply by email

Dimitrios Chr. Ioannidis
to Martin Frb

Hi,

thx for the info !

Martin Frb wrote
Depending on how your external exe works, you need some sort of control when to send which message, and how to parse the answers...

Actually I'll communicate with the HW Debugger using mEDBG Protocol via Serial ( USB CDC ). So no external exe.

Again thx for the info !

regards,

Dimitrios Chr. Ioannidis

Reply by email

Martin Frb
to Dimitrios Chr. Ioannidis
Dimitrios Chr. Ioannidis wrote 12 lines
Hi,   thx for the info ! On 2018-11-21 14:25, Martin Frb via lazarus wrote: > Depending on how your external exe works, you need some sort of > control when to send which message, and how to parse the answers...   Actually I'll communicate with the HW Debugger using mEDBG Protocol via Serial ( USB CDC ). So no external exe.   Again thx for the info !

Well then you probably will need to look at the various FpDebug based debuggers too.

FpDebug can read the dwarf info. You will need to implement run/pause/breakpoint (there is something in fpdebug, but I do not know if that works for you).
And then provide memory access, so fpdebug can read data, to evaluate watches.

Reply by email

Michael Ring
to Martin Frb

I can also provide you my implementation for JLink-Debugger if it helps, thanks to some great improovements Martin did in the past the code I needed to add was reduced to a minimum, and I am now checking if I need my own implementation at all....

Michael

Martin Frb wrote 23 lines
On 21/11/2018 14:09, Dimitrios Chr. Ioannidis via lazarus wrote: > Hi, > >   thx for the info ! > > On 2018-11-21 14:25, Martin Frb via lazarus wrote: >> Depending on how your external exe works, you need some sort of >> control when to send which message, and how to parse the answers... > >   Actually I'll communicate with the HW Debugger using mEDBG Protocol > via Serial ( USB CDC ). So no external exe. > >   Again thx for the info ! Well then you probably will need to look at the various FpDebug based debuggers too. FpDebug can read the dwarf info. You will need to implement run/pause/breakpoint (there is something in fpdebug, but I do not know if that works for you). And then provide memory access, so fpdebug can read data, to evaluate watches.

Reply by email

Michael Ring
to Dimitrios Chr. Ioannidis: I would like to be involved / help as I am thinking implementing the mEDBG protocol and…

Hi Martin, thank you for the detailled answer.

I like your idea of creating Id's for debugger configurations and as I want to go step by step (and I have great respect of 130kBytes of code in TEnvironmentOptions) I wanted to start small and grow as I go..... I am tempted to give the full refactoring a pass 8-) and prefer your option 2)

So I thought about how to create a usefull Id and came up with the following:

first part could be CRC16 of the Caption (to define the pricipal debugger Module that is used):

GNU debugger (gdb) --> 0x167E

GNU debugger through SSH (gdb) --> 0xB2AE

GNU remote debugger (gdbserver) --> 0x5579

GNU remote debugger via jlink (jlinkgdbserver) --> 0x463C

then add CRC16 of lowercase basename of gdb used:

gdb --> 0x84FD

mips-sde-elf-gdb -->0x7B4E

arm-none-eabi-gdb -->0xB5E7

and then we could add a CRC32 of all options changed from default (or CRC32 of all options)

so an id could look like this:

167E-84FD-FFFFFFFF for native debugger using gdb

5579-7B4E-FFFFFFFF for gdbserver using mips version of gdb

This would allow us to always select the right debugger module by looking at the first 4 chars, and for people working together there is a high chance that also the debugger part matches. We can of course fill this up to look like a propper UUID.....

That's already a reasonable starting point for a good configuration. We can tell the user (if we want to) that the debugger component used in the project cannot be found, we can also preconfigur the right debugger component when we find it and hint that the proper gdb is not jet configured.

Not perfect, but this hopefully already covers a number of usecases.

The real fun starts with also Checksumming the changes/all options, this allows us to pinpoint the exact configuration needed meaning that a developer will always get the perfect configuration for his own debug task.

I first thought to explicity checksum even more fields (like Debugger_Remote_Port) but as there is no way back from a checksum to an actual setting I think it does not add much more benefit.

What do you guys think?

Michael

Dimitrios Chr. Ioannidis wrote 23 lines
Hi, On 2018-11-20 23:44, Michael Ring via lazarus wrote: > What is the best way to implement this project based override, I guess > I can do the coding myself as I have also created my own debugger for > JLink, but I do not know how to do this debugger switching in the > proper 'Lazarus' way.....   I would like to be involved / help as I am thinking implementing the mEDBG protocol and intergrate it to Lazarus to debug AVR MCU's using this debugger https://hackaday.io/project/162372-xplained-yourself .   I already tried to use the avr-gdb --> avarice --> dragon --> atmegaxxx combination ( which worked in Linux but not in Windows ) and the result is that I have 3 bricked mcu's ( most probably by flashes has been worn out by software breakpoints) . Not even the HVPP procedure restore them.   Anyway if I can help ( and learn at the same time the Lazarus / Debug internals ) that would be awesome. regards,

Reply by email

Martin Frb
to Michael Ring
Michael Ring wrote 7 lines
Hi Martin, thank you for the detailled answer. I like your idea of creating Id's for debugger configurations and as I want to go step by step (and I have great respect of 130kBytes of code in TEnvironmentOptions) I wanted to start small and grow as I go..... I am tempted to give the full refactoring a pass 8-) and prefer your option 2)

good :)

first part could be CRC16 of the Caption (to define the pricipal debugger Module that is used): GNU debugger (gdb) --> 0x167E

I prefer human readable: TGDBMIDebugger, TSSHGDBMIDebugger, ...

then add CRC16 of lowercase basename of gdb used: gdb --> 0x84FD mips-sde-elf-gdb -->0x7B4E

That fails, for example some of my gdb are called gdb_7_7.exe And FpDebug does not have an external exe at all.

This would allow us to always select the right debugger module by looking at the first 4 chars, and for people working together there is a high chance that also the debugger part matches. We can of course fill this up to look like a propper UUID.....

The above considerations are fine, if you look at a project that needs a very special debugger (for which there may be no alternative) But if you work as part of a team on a normal project, then one person may use gdb 7.7, another uses gdb 8.2, and yet another uses FpDebug. And they are all totally interchangeable.

Anyway reading through this may have helped me to get some more clarity what may be needed.
I did myself made it to complex in my first mail (late night mails...)

----------------
Overall, I would suggest to start, with a simple solution, For a single user there are 2 options
- Name (human readable name, as given by user)
- id (UUID)

If you ever get another persons project, then what should happen (even if stored in session, the session could be in the lpi):
- the name can accidentally match
- the ID should never match => so you will be forced to choose a debugger

So ID is better. And you don't need to include what kind of debugger to use (But see below). As developer you should know, that the target will run on FooBar, and you need a debugger that supports this

-----------------
After some thought, I think

- Store all debugger configs in the EnvironmentOpts, each with its own ID
- use an ID  (in form of a UUID)
- store the ID in the projects session (lps)

That should be the base, and you can later add to this. I.e, all else should be optional.

Once that works / Once the IDE can handle many configs => then you can look at the below options.

----------------
**For later **
Option 1:
If you need to choose a debugger, and the IDE should be able to help you to get it right:
=> You can add a hint system.
In the project settings/session this would look like    In LPS:   <DebuggerConfig id="0000-1111-2222-3333-...">    In LPI:   <DebuggerConfigHints Class="TSSHGDBMIDebugger" Target="mips-sde"  Exe="mips-sde-elf-gdb">
The Target depends on the TGDBMIDebugger class being able to return this info.
Not sure how useful the exe name is.

Hints can go into the project lpi. So the IDE can prompt you when the project is first opened.
But then you set up your debugger as you need it, and store the ID in the lps (and the debugger config in the EnvironmentOpts)

Option 2:
Storing the entire config in the project lps. (It still should have an ID) It then is of course only available for that project. (like "Additions and Overrides" that can be stored IDE, lpi or lps) ** For even later**
Storing in the lps will add another problem: even if the many settings can be transferred, the path to the external exe may be different on each PC.

----------------
Another issue is, what to do, if you get a project with an ID, that you do not have.
- The user has to choose one of his debugger settings (or even create it)
- But once you have chosen, and you write your ID back to the project, and commit it to svn/git, then all other team members must choose again.   => Well it should not happen. In such a case the ID should be in the session, and the session should not be in the repository.

Reply by email