Author Topic: Custom Watch Script Pluggins  (Read 38168 times)

Offline mandrav

  • Project Leader
  • Administrator
  • Lives here!
  • *****
  • Posts: 4315
    • Code::Blocks IDE
Re: Custom Watch Script Pluggins
« Reply #15 on: January 24, 2006, 12:03:27 pm »
Quote
It looks like it gives a query to run and defines a function to parse the output. Would it not be simpler (and possibly more powerful) if the script could ask the debugger driver to run certain queries? That way you can run multiple queries and the script logic can even dynamically adjust which ones and/or how many times. It also allows for more abstraction from the actual queries, which might allow the same scripts to be used by both GDB and CDB.

(I 'm gonna use gdb examples here)

Before evaluating a variable, the driver runs a "whatis <var>" which gives the variable's type. This is then checked for matches by any script-registered type using the script-supplied regular expression.

If a script that matches is found, the previously defined "print_<typename>" gdb function is called. That would be "print_wxstring" in the above code case.
When we receive output from this command, the script's parse function (GDB_ParseWXString in the code above) is called.

The second argument will be filled with the result in a format similar to gdb's "output" command (the watches parsing works with this). So it will always be a string. I can elaborate on the format if you want it...

The first argument that is passed to the script is more interesting though. It contains the driver's output of the previously run command (print_wxstring in this case).
Depending on print_wxstring's definition, this string might be multiline but it doesn't matter. The parser function (GDB_ParseWXString) should parse it correctly and put the parsing result in the second function argument we talked about earlier.

All the above mean that you can parse practically whatever. If you want, I can post an example for parsing a std::vector. It's perfectly possible with this setup.

Finally, I haven't settled with this design yet. I 'm still evaluating it...
Thanks for the feedback though :)
Be patient!
This bug will be fixed soon...

Offline killerbot

  • Administrator
  • Lives here!
  • *****
  • Posts: 5490
Re: Custom Watch Script Pluggins
« Reply #16 on: January 24, 2006, 12:26:58 pm »
Quote
All the above mean that you can parse practically whatever. If you want, I can post an example for parsing a std::vector. It's perfectly possible with this setup.

Please do.

Offline Urxae

  • Regular
  • ***
  • Posts: 376
Re: Custom Watch Script Pluggins
« Reply #17 on: January 24, 2006, 01:57:04 pm »
In the script you posted I noticed you called $arg0.Len(). Does this mean the debugger can call member functions? That would be a great help when generalizing/porting scripts to multiple implementations (such as different standard libraries, or different versions of libraries with the same interface but different implementation), as long as variables of that type can be completely described by calls to member functions (which is true for a lot of types).

Quote
It looks like it gives a query to run and defines a function to parse the output. Would it not be simpler (and possibly more powerful) if the script could ask the debugger driver to run certain queries? That way you can run multiple queries and the script logic can even dynamically adjust which ones and/or how many times. It also allows for more abstraction from the actual queries, which might allow the same scripts to be used by both GDB and CDB.

(I 'm gonna use gdb examples here)

Before evaluating a variable, the driver runs a "whatis <var>" which gives the variable's type. This is then checked for matches by any script-registered type using the script-supplied regular expression.

If a script that matches is found, the previously defined "print_<typename>" gdb function is called. That would be "print_wxstring" in the above code case.
When we receive output from this command, the script's parse function (GDB_ParseWXString in the code above) is called.

Does this mean these things would have to be rewritten for each debugger? Is there maybe a way to abstract this a bit more, even if it's just the most basic functionality?
If the output needs to be in the same representation as a debugger output command, maybe the script should have access to some helper functions that produce the output in a more high-level way. This would not only be helpful in providing a more understandable way to create the output, but also allows for more uniform access to output formats for different debuggers.
This would basically entail some helper functions and/or classes. (Does AngelScript even have classes?)

Quote
The second argument will be filled with the result in a format similar to gdb's "output" command (the watches parsing works with this). So it will always be a string. I can elaborate on the format if you want it...

Hmm... I don't know much about gdb, but does this mean you could already write such a generic vector parsing script that would be parsed by C::B into a tree representation? (taking into account the scripts for the element type etc.)

Quote
The first argument that is passed to the script is more interesting though. It contains the driver's output of the previously run command (print_wxstring in this case).
Depending on print_wxstring's definition, this string might be multiline but it doesn't matter. The parser function (GDB_ParseWXString) should parse it correctly and put the parsing result in the second function argument we talked about earlier.

But some types may not be easy to print in one command, especially for people who've never used gdb directly (like me). I'm especially thinking about containers here.
Here a few parsing helper functions/classes would probably also be helpful. (Presumably, different debuggers write out different formats)

Quote
All the above mean that you can parse practically whatever. If you want, I can post an example for parsing a std::vector. It's perfectly possible with this setup.

I guess that already answers one of my questions. As often noted on these forums, you guys are fast :lol:.
Seriously, that would probably be quite instructional, especially with extensive comments that explain everything.

Quote
Finally, I haven't settled with this design yet. I 'm still evaluating it...
Thanks for the feedback though :)

I presumed you hadn't settled on it yet. Actually, that's why I gave the feedback. I just wanted to make sure this would work for more complex structures that are best presented as multiple values. Best to do so before anything is settled on, right? ;)
« Last Edit: January 24, 2006, 02:02:43 pm by Urxae »

Offline mandrav

  • Project Leader
  • Administrator
  • Lives here!
  • *****
  • Posts: 4315
    • Code::Blocks IDE
Re: Custom Watch Script Pluggins
« Reply #18 on: January 24, 2006, 02:05:13 pm »
Quote
All the above mean that you can parse practically whatever. If you want, I can post an example for parsing a std::vector. It's perfectly possible with this setup.

Please do.

Here it is:

Code: cpp
void RegisterTypes(DebuggerDriver@ driver)
{
    driver.RegisterType(
        "StdVector",

        "[^[:alnum:]_]*vector<.*",

        "GDB_ParseStdVector",

        "set $vec = ($arg0)\n"
        "set $vec_size = $vec->_M_impl._M_finish - $vec->_M_impl._M_start\n"
        "if ($vec_size != 0)\n"
        "  set $i = 0\n"
        "  while ($i < $vec_size)\n"
        "    p *($vec->_M_impl._M_start+$i)\n"
        "    set $i++\n"
        "  end\n"
        "end\n"
    );
}

void GDB_ParseStdVector(const wxString& in a_str, wxString& out result)
{
    result = "{" + a_str + "}";
    result.Replace("\n", ",", true);
}

EDIT: The attached image shows a std::vector<float> being watched.
Still needs some work, but as you see it is possible :)

[attachment deleted by admin]
« Last Edit: January 24, 2006, 02:11:15 pm by mandrav »
Be patient!
This bug will be fixed soon...

Offline mandrav

  • Project Leader
  • Administrator
  • Lives here!
  • *****
  • Posts: 4315
    • Code::Blocks IDE
Re: Custom Watch Script Pluggins
« Reply #19 on: January 24, 2006, 02:17:49 pm »
Quote
In the script you posted I noticed you called $arg0.Len(). Does this mean the debugger can call member functions?

Yes, you can call functions, do casts, basically whatever the language allows. As long as the debugger has full info on the type that is...

Quote
Does this mean these things would have to be rewritten for each debugger?

As it is now, yes. But I plan change this. I 'm rethinking the whole process. In the std::vector example I posted above, I doubt it would work with wxStrings (well it would work, but not using the print_wxstring function).
So maybe I will expose some debugger commands to the scripts so they can call the debugger directly as needed. I 'm thinking it over...

Quote
Hmm... I don't know much about gdb, but does this mean you could already write such a generic vector parsing script that would be parsed by C::B into a tree representation? (taking into account the scripts for the element type etc.)

See my post above.
Be patient!
This bug will be fixed soon...

Offline Urxae

  • Regular
  • ***
  • Posts: 376
Re: Custom Watch Script Pluggins
« Reply #20 on: January 24, 2006, 03:55:30 pm »
Code: cpp
void RegisterTypes(DebuggerDriver@ driver)
{
    driver.RegisterType(
        "StdVector",

        "[^[:alnum:]_]*vector<.*",

        "GDB_ParseStdVector",

        "set $vec = ($arg0)\n"
        "set $vec_size = $vec->_M_impl._M_finish - $vec->_M_impl._M_start\n"
        "if ($vec_size != 0)\n"
        "  set $i = 0\n"
        "  while ($i < $vec_size)\n"
        "    p *($vec->_M_impl._M_start+$i)\n"
        "    set $i++\n"
        "  end\n"
        "end\n"
    );
}

void GDB_ParseStdVector(const wxString& in a_str, wxString& out result)
{
    result = "{" + a_str + "}";
    result.Replace("\n", ",", true);
}

That seems to do most of the work in some weird gdb script though. It looks like the angelscript is mostly just a wrapper because it needs to be done in angelscript ;).

Quote
In the script you posted I noticed you called $arg0.Len(). Does this mean the debugger can call member functions?

Yes, you can call functions, do casts, basically whatever the language allows. As long as the debugger has full info on the type that is...

That opens up some possibilities once the script gets direct access to debugger commands, I think. (Though it's probably possible through that gdb script)

For instance, the use of _M_start isn't portable, but accessing the elements through a standard interface should work for every implementation of std::vector. So []/.operator[]() (if possible), .at() or even iterators (if possible) would make for a much more portable script. And it would be even better if this could be done from a script independent of the compiler and debugger used.

Quote
Quote
Does this mean these things would have to be rewritten for each debugger?

As it is now, yes. But I plan change this. I 'm rethinking the whole process. In the std::vector example I posted above, I doubt it would work with wxStrings (well it would work, but not using the print_wxstring function).
So maybe I will expose some debugger commands to the scripts so they can call the debugger directly as needed. I 'm thinking it over...

That sounds like a good idea.

Quote
Quote
Hmm... I don't know much about gdb, but does this mean you could already write such a generic vector parsing script that would be parsed by C::B into a tree representation? (taking into account the scripts for the element type etc.)

See my post above.

But it doesn't use the custom wxString representation, correct?

I'd like vector script to look more like this:

Code: cpp
void RegisterTypes(DebuggerDriver@ driver)
{
    // Notice: No debugger-dependent code
    driver.RegisterType(
        "StdVector",

        "[^[:alnum:]_]*vector<.*",

        "ParseStdVector"
    );
}

void ParseStdVector(DebuggerDriver@ driver, wxString vecname, DebuggerTree@ tree)
{
    for (size_t i = 0; i < vecname.length(); ++i) {
        wxString index;
        index << "[" << i << "]";
        tree.addChild(index, vecname + index);  // (<label>, <watch expression>)
    }
}

Which would then work for any type of vector (and use custom representations).
DebuggerTree would be a representation of the tree in the watch window.
Maybe addChild() should have an overload for a single string argument too, to allow complete control over the text being shown.

Note: I don't know much about angelscript, if any syntax is wrong please feel free to ignore that and just get the general idea anyway :P. In particular, if operator overloads don't work please imagine I used .Append() (on copies of the string) and .Printf() instead of << and + ;).
If it's not easy to get vector[0] etc. to be evaluated by the debugger, imagine I used .at() or something.

And if gdb/cdb are advanced enough (especially w.r.t. operator overloads) to allow access to and use of iterators, this might be done in an even cooler way: imagine using only one script for ALL stl containers without special cases being necessary (except maybe std::string and variants, which have a more natural representation). 8)

Offline mandrav

  • Project Leader
  • Administrator
  • Lives here!
  • *****
  • Posts: 4315
    • Code::Blocks IDE
Re: Custom Watch Script Pluggins
« Reply #21 on: January 25, 2006, 09:02:34 pm »
Update: for those that haven't noticed, I have committed this WIP feature in a new branch (branches/ym_gdb). So if you want to test-drive it, just use this branch.

Ah, almost forgot. This branch has a nifty little bonus: compiler parallel builds :)
Be patient!
This bug will be fixed soon...

Offline rickg22

  • Lives here!
  • ****
  • Posts: 2283
Re: Custom Watch Script Pluggins
« Reply #22 on: January 25, 2006, 11:17:14 pm »
Yiannis: I don't think it'd be wise to watch *ALL* the members of a vector. I think it'd be more useful to open a watch window for each vector you want to see (this is also known as "Inspect"). But having vectors of 70,000 items, we'd need "start and end" modifiers, too.

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Custom Watch Script Pluggins
« Reply #23 on: January 25, 2006, 11:20:46 pm »
I have the feeling the debugger is getting terribly slow... someone should optimize it.
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

sethjackson

  • Guest
Re: Custom Watch Script Pluggins
« Reply #24 on: January 25, 2006, 11:22:09 pm »
I have the feeling the debugger is getting terribly slow... someone should optimize it.

You are the one to talk with the sig you have.  :lol: :lol: :lol:

Offline mandrav

  • Project Leader
  • Administrator
  • Lives here!
  • *****
  • Posts: 4315
    • Code::Blocks IDE
Re: Custom Watch Script Pluggins
« Reply #25 on: January 25, 2006, 11:24:52 pm »
Yiannis: I don't think it'd be wise to watch *ALL* the members of a vector. I think it'd be more useful to open a watch window for each vector you want to see (this is also known as "Inspect"). But having vectors of 70,000 items, we'd need "start and end" modifiers, too.

Rick, these are just prototypes :)
Be patient!
This bug will be fixed soon...

Offline rickg22

  • Lives here!
  • ****
  • Posts: 2283
Re: Custom Watch Script Pluggins
« Reply #26 on: January 25, 2006, 11:25:42 pm »
Pardon me, don Corleone, I was just making a suggestion, please don't kill me :lol:

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Custom Watch Script Pluggins
« Reply #27 on: January 25, 2006, 11:29:31 pm »
Rick, you don't own a horse, do you :)
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

sethjackson

  • Guest
Re: Custom Watch Script Pluggins
« Reply #28 on: January 25, 2006, 11:30:59 pm »
Pardon me, don Corleone, I was just making a suggestion, please don't kill me :lol:

Bye, bye rick have a nice trip. :lol:

Offline Game_Ender

  • Lives here!
  • ****
  • Posts: 551
Re: Custom Watch Script Pluggins
« Reply #29 on: January 25, 2006, 11:45:25 pm »
I have the feeling the debugger is getting terribly slow... someone should optimize it.

I going to take one of these dangerous stabs in the dark, but does having to comunicate over stdin/stdout put an upper limit on performance?  Is that our current bottleneck?