Author Topic: Extend GDB plugin to communicate with other plugins  (Read 4307 times)

Online oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 10262
Re: Extend GDB plugin to communicate with other plugins
« Reply #30 on: August 01, 2017, 01:14:38 am »
With this kind of watch it would be possible to do all this things from a plugin.
I really doubt it. Especially if you want to transfer tons of data.

At the moment i would like to implement it and for this i need to know what api the devs would support.
It will be good if you could try the minimal version of the watch idea. In order to see if it is worth pursuing. Nothing fancy and complex on the UI part. Get adding (use some hardcoded path to a svd file for example) and updating watches to work. My original thought was to put the register watches in the watches window, because it will make it easier to experiment with it.

For optimization is later time, if the bottleneck is found.
The problem with api design is that you should design for performance up front. It is very hard to make a system really performant if the api is not optimal.

Why is this a bad idea?
It creates delays for the user when you need the data. I guess here it won't be that bad and it could be disabled if it creates too many ux problems. I'm not sure I like the similar implementation in the gdb/mi plugin.

...because from my experience the problem is codeblocks<->gdb and not gdb or codeblocks at program level.
Sometimes gdb is slow, because it has tons of data to process and produces small amount of data.

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...)
This could be done in the gdb plugin. Because it is its job to iterate the register-watches and decide what commands to issue. It might be possible to merge different memory ranges. If they overlap or next to each other.
<debugger plugin maintainer>
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline BlueHazzard

  • Lives here!
  • ****
  • Posts: 1516
Re: Extend GDB plugin to communicate with other plugins
« Reply #31 on: August 06, 2017, 05:07:33 pm »
I tried to implement the way you suggested. We need to distinguish between a "symbol" watch and a "memory" watch, because the gdb command for asking a symbol is "output" and for a memory region it is "x". Now my first try is to make the distinguish within the watch. For this is have to:
1) Extend the cbWatch class with
Code: [Select]

        enum cbWatchType
        {
            cbWatchType_SYMBOL,
            cbWatchType_MEMORY
        };

        virtual void AddMemoryRange(uint64_t address, uint64_t size, const wxString &id ) = 0;
        cbWatchType  GetWatchType()     {return m_watchType;};

        private:
            cbWatchType m_watchType;

2) Modify the GDBWatch class:
Code: [Select]
void GDBWatch::AddMemoryRange(uint64_t address, uint64_t size, const wxString &id )
{
    m_symbol = wxString::Format(wxT("/%ulub %lx"), size, address);
    m_watchType = cbWatchType_MEMORY;
}

void GDBWatch::SetSymbol(const wxString& symbol)
{
    m_symbol = symbol;
    m_watchType = cbWatchType_SYMBOL;
}
now my plan was to modify the class GdbCmd_Watch to distinguish between memory and symbol watch
Code: [Select]
        GdbCmd_Watch(DebuggerDriver* driver, cb::shared_ptr<GDBWatch> watch) :
            DebuggerCmd(driver),
            m_watch(watch)
        {
            wxString type;
            wxString symbol;

            m_watch->GetSymbol(symbol);
            m_watch->GetType(type);

            if(m_watch->GetWatchType == cbWatchType_MEMORY)
            {
                m_Cmd << "x " << symbol;
                return;
            }
// old code from here on

            type.Trim(true);
            type.Trim(false);
            m_Cmd = static_cast<GDB_driver*>(m_pDriver)->GetScriptedTypeCommand(type, m_ParseFunc);
            if (m_Cmd.IsEmpty())
            {
Now i wanted to modify the
Code: [Select]
ParseGDBWatchValuefunction to parse a memory and symbol watch differently. But it is not that easy....
There is also the GdbCmd_FindWatchType command. I have discovered that the process for updating a watch is to
1) Queue a GdbCmd_FindWatchType command.
2) After successful action this command queues a GdbCmd_Watch
Now the GdbCmd_FindWatchType is useless for the memory watch. So i have to insert even more logic, or modify it future up...

Is this really the way you want to go?

Online oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 10262
Re: Extend GDB plugin to communicate with other plugins
« Reply #32 on: August 06, 2017, 05:25:12 pm »
Why do you want to reuse the watch parsing and querying in the gdb plugin?
When adding memory watches you can add them to a separate array of objects and treat them differently inside the plugin.
The idea is to reuse the interface of cbWatch, but not the implementation inside the plugin.

I don't see why the cbWatch needs to have a type at this point in time of development.
Probably when you start to do the UI you'll have to add some field that is used to specify the widget and some what to get the data for the widget, but you are not at this step yet.

p.p. C::B is using C++11 now, so you can take advantage of the better enums and don't have to explicitly add namespace.
<debugger plugin maintainer>
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline BlueHazzard

  • Lives here!
  • ****
  • Posts: 1516
Re: Extend GDB plugin to communicate with other plugins
« Reply #33 on: August 07, 2017, 02:12:47 am »
ok, i have now implemented a first version of the whole thing:
https://youtu.be/ELOoFKLemmQ

i will upload the source code to github as soon as possible...

Offline BlueHazzard

  • Lives here!
  • ****
  • Posts: 1516
Re: Extend GDB plugin to communicate with other plugins
« Reply #34 on: August 07, 2017, 02:39:44 am »
Ok, codeblocks code is here:
https://github.com/bluehazzard/codeblocks_sf/tree/debugger/memory_range_watch

for the plugin code i need more time. I have to clean up a bit...

Online oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 10262
Re: Extend GDB plugin to communicate with other plugins
« Reply #35 on: August 07, 2017, 09:42:36 am »
DeleteMemoryRange and HasMemoryRange seem redundant...
Also I'm not sure it is a good idea to use GDBWatch as a class and to store the command in the symbol field or the result as a string in the value.
<debugger plugin maintainer>
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline BlueHazzard

  • Lives here!
  • ****
  • Posts: 1516
Re: Extend GDB plugin to communicate with other plugins
« Reply #36 on: August 08, 2017, 10:28:48 am »
Quote
DeleteMemoryRange and HasMemoryRange seem redundant...
i agree with that.. This popped up my mind as soon as i pushed the code

Quote
Also I'm not sure it is a good idea to use GDBWatch as a class and to store the command in the symbol field or the result as a string in the value.
This could easily be made, and honestly i would prefer it. But the result has to be stored in the value member as string, because otherwise the cbWatch has to be modified, or how do you think to get the result from outside of the gdb plugin? One possibility would be to add a function
Code: [Select]
bool GetMemoryRangeValue(cb:shared_ptr<cbWatch> watch, std::vector<char> &data) to cbDebuggerPlugin, but this seems not intuitive if the normal use of cbWatch is GetValue().

Online oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 10262
Re: Extend GDB plugin to communicate with other plugins
« Reply #37 on: August 08, 2017, 02:21:28 pm »
This could easily be made, and honestly i would prefer it. But the result has to be stored in the value member as string, because otherwise the cbWatch has to be modified, or how do you think to get the result from outside of the gdb plugin?
It depends what you want to do with the data. Do you know what operations you want to do?

One possibility would be to add a function
Code: [Select]
bool GetMemoryRangeValue(cb:shared_ptr<cbWatch> watch, std::vector<char> &data) to cbDebuggerPlugin, but this seems not intuitive if the normal use of cbWatch is GetValue().
Do not go this route, please.
<debugger plugin maintainer>
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline BlueHazzard

  • Lives here!
  • ****
  • Posts: 1516
Re: Extend GDB plugin to communicate with other plugins
« Reply #38 on: August 30, 2017, 08:18:29 pm »
Hi,
i reworked the implementation: https://github.com/bluehazzard/codeblocks_sf/tree/debugger/memory_range_watch

The interface to all plugins is only one function:
Code: [Select]
cb::shared_ptr<cbWatch>  cbDebuggerPlugin::AddMemoryRange(uint64_t address, uint64_t size, const wxString &id ) = 0;
This function returns a cbWatch object that represents a memory range. The value of the Watch (the memory raw data directly from ram) can be get with (pseudo code):
Code: [Select]
cb::shared_ptr<cbWatch> m_watch = dbg_plugin->AddMemoryRange(0x400000, 16, wxEmtyString );
// Run the debugger
wxString tmp;
m_watch->GetValue(tmp);
size_t lengthOfData = tmp.size();
char* memoryContetn = new char[ lengthOfData ];
memcpy(memoryContent, tmp.To8BitData(), 16);
// yay: ram content in memoryContent for your free use and interpretation
// i know there is a uint16_t @ 0x400002
uint16_t myNeededValue = 0;
memcpy(&myNeededValue, memoryContent+2, 2);

At plugin level there is a internal watch class: GDBMemoryRangeWatch that represents a memory range. It derives from cbWatch and stores the address and size of the range.
All the memory range watches are stored in
Code: [Select]
std::vector<cb::shared_ptr<GDBMemoryRangeWatch> > m_memoryRange;
and the following functions are transparent for normal and memory range watches:
Code: [Select]
void DebuggerGDB::DeleteWatch(cb::shared_ptr<cbWatch> watch)
bool DebuggerGDB::HasWatch(cb::shared_ptr<cbWatch> watch)
there is an additional function (at the moment only for GDBPlugin but it can be added to cbDebuggerPlugin) to check if the watch is a memory range watch
Code: [Select]
bool DebuggerGDB::IsMemoryRangeWatch(cb::shared_ptr<cbWatch> watch)

The actual reading of the memory from gdb is implemented like the normal watches with a
Code: [Select]
class GdbCmd_MemoryRangeWatch : public DebuggerCmd

This implementation works nice and transparent. It is relatively fast and i use it in the new plugin i showed with the video above. I will post the link to the source later tody...

conclusion:
To add a interface for other plugins to read random ram content from the debugger, only one new function has to be added to cbDebuggerPlugin. The data is exchanged through wxString::To8BitData() so the cbWatch class has not to be altered.

@oBFusCATed: Is this interface somehow acceptable for you?

Offline BlueHazzard

  • Lives here!
  • ****
  • Posts: 1516
Re: Extend GDB plugin to communicate with other plugins
« Reply #39 on: October 11, 2017, 02:07:12 am »
Ok, this is my suggestion for a pull request. I think the commits are not to large and quite obvious...

https://github.com/bluehazzard/codeblocks_sf/tree/debugger/pull_candidate/memory_range_watch/1

any thoughts on this?