Developer forums (C::B DEVELOPMENT STRICTLY!) > Plugins development
Extend GDB plugin to communicate with other plugins
BlueHazzard:
--- Quote ---API Breakage is not problematic. I just don't want to make the API big. I prefer if we could re-use as much as possible.
--- End quote ---
But you have to give people a possibility to work with it.
With the current implementation of the watches, every watch saved in the interna of the debugger is mirrored to the watches window. For this purpose this is not wanted...
--- Quote ---Do you expect to add "watches" for all supported "registers" from the file at once or do you add them one by one (the ones you need at the moment)?
--- End quote ---
Probably as needed. It would be nice to make the first read out to read all registers but this can be a lot data (11kByte) and so it is probably better to read only the current open registers. This should be as fast as possible...
--- Quote ---Can you find some example svd file and then show the UI we should generate? So we can have something more concrete example we could discuss.
If you read every register with a single x command then the performance will be rather bad (similarly bad as if you add many watches).
--- End quote ---
I updated my test app to populate a property grid. This is by far not complete (1), but you will get a idea (img is attached)
The corresponding part of the svd file (only the uart/MR register is shown:
--- Code: --- <name>UART</name>
<version>6418H</version>
<description>Universal Asynchronous Receiver Transmitter</description>
<prependToName>UART_</prependToName>
<baseAddress>0x400E0800</baseAddress>
<addressBlock>
<offset>0</offset>
<size>0x128</size>
<usage>registers</usage>
</addressBlock>
<interrupt>
<name>UART</name>
<value>8</value>
</interrupt>
<registers>
<name>CR</name>
<description>Control Register</description>
<addressOffset>0x00000000</addressOffset>
<size>32</size>
<access>write-only</access>
<fields>
<field>
<name>RSTRX</name>
<description>Reset Receiver</description>
<bitOffset>2</bitOffset>
<bitWidth>1</bitWidth>
<access>write-only</access>
</field>
<field>
<name>RSTTX</name>
<description>Reset Transmitter</description>
<bitOffset>3</bitOffset>
<bitWidth>1</bitWidth>
<access>write-only</access>
</field>
<field>
<name>RXEN</name>
<description>Receiver Enable</description>
<bitOffset>4</bitOffset>
<bitWidth>1</bitWidth>
<access>write-only</access>
</field>
<field>
<name>RXDIS</name>
<description>Receiver Disable</description>
<bitOffset>5</bitOffset>
<bitWidth>1</bitWidth>
<access>write-only</access>
</field>
<field>
<name>TXEN</name>
<description>Transmitter Enable</description>
<bitOffset>6</bitOffset>
<bitWidth>1</bitWidth>
<access>write-only</access>
</field>
<field>
<name>TXDIS</name>
<description>Transmitter Disable</description>
<bitOffset>7</bitOffset>
<bitWidth>1</bitWidth>
<access>write-only</access>
</field>
<field>
<name>RSTSTA</name>
<description>Reset Status Bits</description>
<bitOffset>8</bitOffset>
<bitWidth>1</bitWidth>
<access>write-only</access>
</field>
</fields>
</register>
<register>
<name>MR</name>
<description>Mode Register</description>
<addressOffset>0x00000004</addressOffset>
<size>32</size>
<access>read-write</access>
<resetValue>0x00000000</resetValue>
<fields>
<field>
<name>PAR</name>
<description>Parity Type</description>
<bitOffset>9</bitOffset>
<bitWidth>3</bitWidth>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>EVEN</name>
<description>Even Parity</description>
<value>0x0</value>
</enumeratedValue>
<enumeratedValue>
<name>ODD</name>
<description>Odd Parity</description>
<value>0x1</value>
</enumeratedValue>
<enumeratedValue>
<name>SPACE</name>
<description>Space: parity forced to 0</description>
<value>0x2</value>
</enumeratedValue>
<enumeratedValue>
<name>MARK</name>
<description>Mark: parity forced to 1</description>
<value>0x3</value>
</enumeratedValue>
<enumeratedValue>
<name>NO</name>
<description>No Parity</description>
<value>0x4</value>
</enumeratedValue>
</enumeratedValues>
</field>
<field>
<name>CHMODE</name>
<description>Channel Mode</description>
<bitOffset>14</bitOffset>
<bitWidth>2</bitWidth>
<access>read-write</access>
<enumeratedValues>
<enumeratedValue>
<name>NORMAL</name>
<description>Normal Mode</description>
<value>0x0</value>
</enumeratedValue>
<enumeratedValue>
<name>AUTOMATIC</name>
<description>Automatic Echo</description>
<value>0x1</value>
</enumeratedValue>
<enumeratedValue>
<name>LOCAL_LOOPBACK</name>
<description>Local Loopback</description>
<value>0x2</value>
</enumeratedValue>
<enumeratedValue>
<name>REMOTE_LOOPBACK</name>
<description>Remote Loopback</description>
<value>0x3</value>
</enumeratedValue>
</enumeratedValues>
</field>
</fields>
</register>
--- End code ---
(1) For example i would like to post the value of the current slected enumeration in the 3. column of the property gird, but was not able to do it... Also some icons would be nice. Make custom controls for only boolean register, display the bit field width in the 4. column and so on...
oBFusCATed:
--- Quote from: BlueHazzard on July 30, 2017, 02:19:38 am ---With the current implementation of the watches, every watch saved in the interna of the debugger is mirrored to the watches window. For this purpose this is not wanted...
--- End quote ---
Do you mean that there are GDBWatch and WatchesProperties objects? The cbWatch objects are managed by the debugger, because it knows best what additional data it needs for them to keep them up-to-date.
For this new cbWatch type we could add something like:
--- Code: ---cbWatch* cbDebuggerPlugin::AddPeripheralRegister(uint64_t address, uint64_t size, const wxString &id (or fullname) )
--- End code ---
--- Quote from: BlueHazzard on July 30, 2017, 02:19:38 am ---Probably as needed. It would be nice to make the first read out to read all registers but this can be a lot data (11kByte) and so it is probably better to read only the current open registers. This should be as fast as possible...
--- End quote ---
There is no way to be notified of changes in the memory locations (hw watch points are too limited for this purpose).
So if you want all "registers" to be updated at every "next line" or "step into" command then this will be massively slow.
In the watches window there is functionality that makes it possible to mark that you want only certain watches to be auto updated. And there is manual update command per watch. Similar mechanism should be use here, too.
BlueHazzard:
--- Quote ---Quote from: BlueHazzard on Yesterday at 02:19:38
With the current implementation of the watches, every watch saved in the interna of the debugger is mirrored to the watches window. For this purpose this is not wanted...
Do you mean that there are GDBWatch and WatchesProperties objects? The cbWatch objects are managed by the debugger, because it knows best what additional data it needs for them to keep them up-to-date.
--- End quote ---
i looked again in the code and now i think i understand what is going on:
1) Watches window creates a new watch with Manager::Get()->GetDebuggerManager()->AddWatch() and stores the returned value as a shared pointer in a list
2) If the watches window needs to update its state it reads the data from the shared pointer what contains the actual data, updated by the debugger plugin.
so you use shared pointer to share data between the plugin and the interface
So your proposal should be ok.
--- Quote ---For this new cbWatch type we could add something like:
Code:
cbWatch* cbDebuggerPlugin::AddPeripheralRegister(uint64_t address, uint64_t size, const wxString &id (or fullname) )
--- End quote ---
Again, i would not make this (the name AddPeripheralRegister) so special... Just lets read a count of bytes from some memory location. This would allow us to make this way more flexible...
--- Quote ---There is no way to be notified of changes in the memory locations (hw watch points are too limited for this purpose).
So if you want all "registers" to be updated at every "next line" or "step into" command then this will be massively slow.
In the watches window there is functionality that makes it possible to mark that you want only certain watches to be auto updated. And there is manual update command per watch. Similar mechanism should be use here, too.
--- End quote ---
Let me describe the procedure:
1) Start the debugger
2) Open the "System peripheral window". This window lists all registers from the svd file in a property grid-tree. All nodes are closed.
3) The target is halted for the first time (on the main entry point, this is some default behavior if you are debugging in embedded systems. The debugger stops after a reset/start and whaits for the user to run the target)
4) Optional: All registers are read for after reset state ( i don't think this is needed)
5) The user expands one or more peripheral nodes from the "System peripheral window". The debugger updates this elements from the target
6) User hits "run"
7) Target runs until breakpoint
8) debugger halts and updates all expanded registers from the "System peripheral window"
9) The user changes one value from a register
10) The debugger writes the new value to memory
11) The debugger updates the register view (to check if the write was successful)
11) User hits run
12) Loop to 6)
oBFusCATed:
--- Quote from: BlueHazzard on July 31, 2017, 01:49:34 pm ---Again, i would not make this (the name AddPeripheralRegister) so special... Just lets read a count of bytes from some memory location. This would allow us to make this way more flexible...
--- End quote ---
What do you mean by flexible here? I don't care much about the exact name, but I don't like MemoryWatch, because it is too similar to data breakpoint and tracepoints. Which are different things.
About step 1: How do you select the svd file? The user selects it every time the window is being opened? It is stored in a project/target/the window and the window resets it every time new debug session is started?
About Step 5: linking the expanding of the property and updating the values is not a good idea. At least for the watches it is a terrible idea, but I guess it might work for these fixed set of "registers" kind of window.
Step 8 will definitely be supper slow in the current implementation. I'm not sure if it will be fast in a gdb/mi implementation, too. The gdb/mi performance depends more on the gdb's performance than the integration.
BlueHazzard:
--- Quote ---What do you mean by flexible here? I don't care much about the exact name, but I don't like MemoryWatch, because it is too similar to data breakpoint and tracepoints. Which are different things.
--- End quote ---
It would be possible for other plugins to read out memory from the microcontroller and use it for own things (for example https://www.segger.com/products/debug-probes/j-link/technology/real-time-transfer/general-information/#tab-15668-1 this is only a general idea, there are countless other things, like generating memory maps from MMU and DMA and so on) In general, if you can read the ram from a microcontroller you can do a hell lot of things. With this kind of watch it would be possible to do all this things from a plugin.
--- Quote ---About step 1: How do you select the svd file? The user selects it every time the window is being opened? It is stored in a project/target/the window and the window resets it every time new debug session is started?
--- End quote ---
Of course it should be saved at project or target level. But this can be done from the plugin and codeblocks provides a api for this, so no problems here ( as far as i know a plugin can add notebooks to the Project->Settings dialog, at least the gdb plugin does it and so there is also a place for the setting entry). The svd file is parsed on load of the project (and when the file is changed in the options of corse). The window is populated at the opening of the debugger, with all elements. The window provides a search control so the user can find the needed register pretty fast. The update of the data is then a other problem, but there is the possibility to optimize, for example find the best size between count of watches and size of a singe watch.
At the moment i would like to implement it and for this i need to know what api the devs would support. For optimization is later time, if the bottleneck is found.
--- Quote ---About Step 5: linking the expanding of the property and updating the values is not a good idea. At least for the watches it is a terrible idea,
--- End quote ---
Why is this a bad idea? Only get the data from the debugger as you need it, because from my experience the problem is codeblocks<->gdb and not gdb or codeblocks at program level. I think the mi gdb plugin does this and it is fast and reliable. You can cache the values and only update if the debugger was running in the mean time... In any way it is faster then updating the whole register map (if the map is 11kByte big, on smaller targets it may be a possibility. Don't optimize until you know where the problem is...)
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version