User forums > Announcements

Release 12.11 has arrived

<< < (16/18) > >>

pitti platsch:

--- Quote from: Taiki on December 26, 2012, 12:43:10 am ---1- Watches window: no more a list of variable of the current function: well, I deal with some quite big functions with over 50 variables. To deal with so much, I've functions that modify a lot of them in the same time but as I don't want to read the whole function, with the old system, I'd to watch on what become red after the function, now, I'll have to add _every variable_ to the window, manually... Please, tell me there is a way to get them all easily, the new system seems to have a lot of things to show but without this, I can't do anything :(

--- End quote ---

Hi,
if you use a recent Python-scriptable GDB (see http://forums.codeblocks.org/index.php/topic,11301.0.html), you can register a pretty printer by calling the register_peter_printers(None) from the following code which I just hacked together. Then add a watch to `(void*****)"FRAME"` and you see all local variables and function arguments.

--- Code: ---import sys
import gdb
import re

class static:
    "Creates a 'static' method"
    def __init__(self, function):
        self.__call__ = function
       
peter_pretty_printers = []
def register_pretty_printer(pretty_printer):
    "Registers a Pretty Printer"
    peter_pretty_printers.append(pretty_printer)
    return pretty_printer

@register_pretty_printer
class AllLocalsOrArgumentsPrinter:
    """ pretty prints `(void*****)"LOCALS"` as a map of all local variables
        or `(void*****)"ARGS"` as a map of all function arguments
        or `(void*****)"FRAME"` as both
    """
   
    @static
    def supports_value(val):
        if val.type != gdb.parse_and_eval("(void*****)0").type:
            return False

        try:
            return val.cast(gdb.lookup_type('char').pointer()).string() in ['LOCALS', 'ARGS', 'FRAME']
        except:
            return False

    def __init__(self, val):
        self.cmd = val.cast(gdb.lookup_type('char').pointer()).string()
   
    @static
    def info_to_string(gdb_command):
        result = gdb.execute(gdb_command, to_string=True).strip()
        if result in ['No locals.', 'No arguments.']:
            return '{}'
        # make unique
        split_result = re.split(r'^([a-zA-Z_][a-zA-Z0-9_]*) = ', result, flags=re.MULTILINE)
        split_result.remove('')
        tuples = [(split_result[2*i], split_result[2*i+1].strip('\n')) for i in range(len(split_result)/2)]
        tuples.reverse()
        result = ''.join([',\n' + k + ' = ' + v for (k,v) in dict(tuples).iteritems()]).lstrip(',')
        return '{' + result + '\n}'
   
    def to_string(self):
        if self.cmd == 'LOCALS':
            return AllLocalsOrArgumentsPrinter.info_to_string('info local')
        if self.cmd == 'ARGS':
            return AllLocalsOrArgumentsPrinter.info_to_string('info arg')
        if self.cmd == 'FRAME':
            locals = AllLocalsOrArgumentsPrinter.info_to_string('info local')
            args   = AllLocalsOrArgumentsPrinter.info_to_string('info arg')
            return '{\nLocal Variables = ' + locals + ',\nFunction Arguments = ' + args + '\n}'
        return '?'

def register_peter_printers(obj):
    if obj == None:
        obj = gdb

    obj.pretty_printers.append(lookup_function)

def lookup_function(val):
    for pp in peter_pretty_printers:
        if pp.supports_value(val):
            return pp(val)
    return None

--- End code ---

cheers,
Peter

ollydbg:
pitti platsch, I see you wrap the gdb command in a "dummy variable in python" :). Please note that why we remove such feature in the debugger plugin. In my gdb release: unofficial MinGW GDB gdb with python released, I use a special patch that compare the current instruction line(Program counter) with the line of a local variable definition, this can void the python script print the uninitialzed local variables.

pitti platsch:
@ollydbg: Yes, my pretty printer works best (or only  ;D) with your patched gdb. If I knew a way to iterate all symbols of a frame in python, I would not just call "info local".

But in my opinion, gdb pretty printers must be able to deal with arbitrary/corrupt data.
If a pretty printer crashes/turns into an infinite loop/takes too long to complete when handed some arbitrary bytes, then that pretty printer is buggy and needs to be fixed or disabled:
One of the main points in debugging is to inspect data corruption bugs.

ollydbg:

--- Quote from: pitti platsch on February 04, 2013, 01:43:06 pm ---@ollydbg: Yes, my pretty printer works best (or only  ;D) with your patched gdb.

--- End quote ---
Did you test some uninitialzed C++ container as local variables. E.g.

--- Code: ---void f()
{
    int a;
    vector<string> b;
    ....Some statement;
    map<string,string> c;
}
--- End code ---
If you set a breakpoint in the first line of "f", then "b" and "c" are uninitialized variables, they will cause the python pretty printer try to print a large number of elements. Sometimes, it will take a long time, sometime, gdb may crash. Currently no good way to detect a variable is initialized or not. If not, it may have some corrupt values, as the constructor of the container is not called, mayb, the size of the container may be a large value.


--- Quote ---If I knew a way to iterate all symbols of a frame in python, I would not just call "info local".
But in my opinion, gdb pretty printers must be able to deal with arbitrary/corrupt data.
If a pretty printer crashes/turns into an infinite loop/takes too long to complete when handed some arbitrary bytes, then that pretty printer is buggy and needs to be fixed or disabled:
One of the main points in debugging is to inspect data corruption bugs.

--- End quote ---
I have asked such question in gdb maillist, but it looks like there is no quick solution/fix to handle this issue. Mostly I think the c-runtime-library should fill the memory with some value like "0xCDCDCDCD", and gdb try to exam its value when it want to deference a pointer.....:)

pitti platsch:
With your patched gdb, the variables b and c are not listed in "info local" until I hit there declaration lines. And directly adding a watch to b displays as `No symbol "b" in current context.` when I just enter the function.

You are right that there is no nice simple solution yet. My `(void*****)"LOCALS"` python code is just an ugly hack for those who missed the feature and/or do plain C programming without many other fancy pretty printers. It was the only regression that stopped me from upgrading until I learned python. But now I already fell in love with the 'Evaluate expression' tooltips :)

Apart from that, it would be nice to have a checkbox next to each entry in the Watches window to temporarily enable/disable the watch.

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version