News:

Accounts with zero posts and zero activity during the last months will be deleted periodically to fight SPAM!

Main Menu

Custom Watch Script Pluggins

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

Previous topic - Next topic

Game_Ender

Currently the debbugger has the ability to automatically detect things such as wxStrings and produce cleaner watch output.  I think it would be greate to be able to add support for more custom watches through angel scripts.  The script define would the value necessary to determine that the variable we are watching is indeed of the right of type, then it could just supply a watch script.  When the debugger starts up it could run each script to register each custom variable type, and then call the script when ever the variable is seen to get the proper watch commands with which to display the variable.

mandrav

Be patient!
This bug will be fixed soon...

Game_Ender

#2
If you need any help on this feature just let me know, I think something like this is vital to easy of use.  It will turn that sometimes obscure tree into something very usefull.  I would love to be able to write custom watches for all the key classes in my applications.  That would make debugging quite easy.

mandrav

Quote from: Game_Ender on January 23, 2006, 06:45:25 PM
If you need any help on this feature just let me know, I think something like this is vital to easy of use.  It will turn that sometimes obscure tree into something very usefull.  I would love to be able to write custom watches for all the key classes in my applications.  That would make debugging quite easy.

No kidding, I loved the idea :lol: (besides, I really want to put scripting into wide use).
I already moved wxString type recognition and parsing into its own script and will now implement the binding.
Be patient!
This bug will be fixed soon...

280Z28

std::map<> and other STL enumerations automatically in the debugger is only available in Visual Studio 2005 right now. If we get that in a script it's another push for Code::Blocks as a first class IDE.
78 280Z, "a few bolt-ons" - 12.71@109.04
99 Trans Am, "Daily Driver" - 525rwhp/475rwtq
Check out The Sam Zone :cool:

yop

We are talking about a major improvement here. Game_Ender it is an excellent idea. The scripting support proves to be very powerfull indeed. And I was wondering what it could do...
Life would be so much easier if we could just look at the source code.

rickg22

Hey, if we're onto scripting for debugging, how about changing the watches depending on the context? I hate it when i exit a function and i have 3864* watches that suddenly go undefined.

* Value may vary.

sethjackson

Quote from: rickg22 on January 24, 2006, 01:10:32 AM
I hate it when i exit a function and i have 3864* watches that suddenly go undefined.

* Value may vary.


:lol:

duncanka

#8
I'd like to add to this suggestion that there should be a way of configuring each variable type to display a certain data member as the value, as is possible in Visual C++.  It's a bit annoying to have to travel down several layers of tree just to look at a simple std::string's content.  (Or was that obvious?  :) )

By the way, will any of this affect saved watch files?  Are those going to be script-ified also?  I guess that would kind of be what Rick is talking about - having predefined watch files or something to be activated at different lines/breakpoints/whatevers.

EDIT - OK, apparently I can't read.  Sorry for stating the glaringly obvious  :oops:...

Game_Ender

Quote from: duncanka on January 24, 2006, 04:52:45 AM
I'd like to add to this suggestion that there should be a way of configuring each variable type to display a certain data member as the value, as is possible in Visual C++.  It's a bit annoying to have to travel down several layers of tree just to look at a simple std::string's content.  (Or was that obvious?  :) )

Yeah that was way obvious because that is exactly what I said.  The Debugger pluggin asks the script to register the its custom variable, in this case a string.  Then when ever that variable is encountered the script is called and either returns the needed debugger print commands or is allowed to call them on the debugger itself.  For a string this would be something like "print myStringVar._M_impl_.m_Stuff._MObscureLayers._content_".  That result would be shown in the watch wind as "myStringVar = content".

yop

And then we could provide ready to use scrips for various APIs that we use. It's going to be beautiful :)
Life would be so much easier if we could just look at the source code.

mandrav

Implemented it in GDB :lol:
I will have to study CDB a little more before I can implement it there too...

I have not committed it yet because I was in the middle of some other debugger changes. I will finish them all and then commit.

Here's the script that adds wxString support in GDB:

Code (cpp) Select

////////////////////////////////////////////////////////////////////////////////
// Parses GDB's output of unicode wxString and turns it to human-readable
////////////////////////////////////////////////////////////////////////////////
//
// Example input:
// {38 '&', 69 'E', 110 'n', 97 'a', 98 'b', 108 'l', 101 'e'}
//
// Example output:
// "&Enable"
////////////////////////////////////////////////////////////////////////////////

// Entry point for testing.
// This is here only for testing the parsing function inside the IDE (while writing it).
// It is *not* used when the script runs in the debugger...
// So, it can safely be removed.
int main()
{
    wxString r;
    GDB_ParseWXString("{38 '&', 69 'E', 110 'n', 97 'a', 98 'b', 108 'l', 101 'e'}", r);
    Log(r);

    return 0;
}

void RegisterTypes(DebuggerDriver@ driver)
{
    driver.RegisterType(
        // The type's name (must be unique, the debugger driver won't accept duplicates).
        "wxString",
        // Regular expression for type matching.
        "[^[:alnum:]_]*wxString[^[:alnum:]_]*",
        // Parser function's name (defined below).
        "GDB_ParseWXString",
        // Define the print function body (this will become a GDB function named print_wxstring).
        // Note that we 're using the m_pchData member of wxString to access
        // its actual data...
        // Also note that we 'll be printing at most 100 chars, i.e. we 're setting a limit.
        "output /c (*$arg0.m_pchData)@(($slen=(unsigned int)$arg0.Len())>100?100:$slen)"
    );
}

// This function parses GDB's output.
// When it returns, the "result" argument contains the parsing result.
void GDB_ParseWXString(const wxString& in a_str, wxString& out result)
{
    result = "\"";
    uint len = a_str.length();
    uint c = 0;
    while (c < len)
    {
        switch (a_str[c])
        {
            case '\'':
                ++c;
                while (c < len)
                {
                    switch (a_str[c])
                    {
                        case '\\':
                            result += a_str[c++];
                            result += a_str[c++];
                            break;
                        default:
                            result += a_str[c++];
                            break;
                    }
                    if (a_str[c] == '\'')
                        break;
                }
                break;

            default:
                break;
        }
        ++c;
    }
    result += "\"";
}
Be patient!
This bug will be fixed soon...

killerbot

what will be the name of the function in GDB ??
parse_wxstring ?
ParseWXString ?
GDB_ParseWXString ?

Unclear beacuse of the type, print function ..

mandrav

Quote from: killerbot on January 24, 2006, 11:03:28 AM
what will be the name of the function in GDB ??
parse_wxstring ?
ParseWXString ?
GDB_ParseWXString ?

Unclear beacuse of the type, print function ..

GDB_ParseWXString is the script's function that does the parsing (arbitrarily chosen - unique of course).
When registering the type, wxString in this case, the debugger prepends "print_" to it and converts it to lowercase so the final gdb function will be 'print_wxstring'. You don't need this info, unless you want to call it yourself by using "Debug->Send command".
Be patient!
This bug will be fixed soon...

Urxae

Quote from: mandrav on January 24, 2006, 10:33:24 AM
Implemented it in GDB :lol:
I will have to study CDB a little more before I can implement it there too...

I have not committed it yet because I was in the middle of some other debugger changes. I will finish them all and then commit.

Here's the script that adds wxString support in GDB:

**snip**

Some points:

  • 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.
  • Is the output only allowed to be a string? What if one wanted to define a script for a container type (such as std::vector or std::list instantiations) and have them be expandable to an enumerated list of the content of the container?
    I'm thinking of something like this:
    + myvec : std::vector<std::string>
    +-[0] "This"
    +-[1] "is"
    +-[2] "a"
    +-[3] "test"
    in the watches area (collapsable to just the first line, of course.
  • Is there any way these scripts can call each other or otherwise make use of each other? A vector script may want to the elements according to their own type's script, for instance.
  • Does this mechanism allow you to watch multiple instantiations of the same template with only one script? (The regex looks promising)
    For example: Would it be possible to write a script that parses std::vector<int>, std::vector<std::string> as well as std::vector<wxString>?

Combining some of the above suggestions, maybe the scripts should create a list as output, with elements like (Name, <Watch expression (or string)>). For instance the vector example would output something like (("[0]", <string at address0>), ("[1]", <string at address1>), ("[2]", <string at address2>), ("[3]", <string at address3>)) (in a data structure, not a string) and then the debugger driver or whatever calls the scripts can use the script for std::string to produce the representation of each individual string.
Preferably this would of course be done without the script needing to know what a std::string even is.