News:

The new Release 25.03 is out! You can download binaries for Windows and many major Linux distros here .

Main Menu

Custom Watch Script Pluggins

Started by Game_Ender, January 23, 2006, 05:26:49 PM

Previous topic - Next topic

mandrav

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

killerbot

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

Urxae

#17
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 from: mandrav on January 24, 2006, 12:03:27 PM
QuoteIt 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? ;)

mandrav

#18
Quote from: killerbot on January 24, 2006, 12:26:58 PM
QuoteAll 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) Select

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]
Be patient!
This bug will be fixed soon...

mandrav

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

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

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

Urxae

Quote from: mandrav on January 24, 2006, 02:05:13 PM
Code (cpp) Select

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 from: mandrav on January 24, 2006, 02:17:49 PM
QuoteIn 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
QuoteDoes 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
QuoteHmm... 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) Select

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)

mandrav

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

rickg22

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.

thomas

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

Quote from: thomas on January 25, 2006, 11:20:46 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:

mandrav

Quote from: rickg22 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.

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

rickg22

Pardon me, don Corleone, I was just making a suggestion, please don't kill me :lol:

thomas

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

Quote from: rickg22 on January 25, 2006, 11:25:42 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:

Game_Ender

Quote from: thomas on January 25, 2006, 11:20:46 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?