Bug 17728 - gdb.LazyString is confused by typedefs
Summary: gdb.LazyString is confused by typedefs
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: python (show other bugs)
Version: 7.8
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-12-18 13:55 UTC by Jonathan Wakely
Modified: 2018-04-22 21:25 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Wakely 2014-12-18 13:55:24 UTC
tmp$ cat > str.cc
struct Foo {
    Foo() : str("foo"), len(3) { }
    const char* str;
    int len;
};

struct Bar {
    Bar() : str("bar"), len(3) { }
    typedef const char* pointer;
    pointer str;
    int len;
};

int main()
{
  Foo foo;
  Bar bar;
  return 0;
}
tmp$ cat > a.out-gdb.py
import gdb

class StrPrinter:
    "Print a stringy thingie"

    def __init__ (self, val):
        self.val = val

    def to_string (self):
        s = self.val['str']
        l = self.val['len']
        return s.lazy_string(length = l)

    def display_hint(self):
        return 'string'

def str_lookup_function(val):
    lookup_tag = val.type.tag
    if lookup_tag == "Foo" or lookup_tag == "Bar":
        return StrPrinter(val)
    return None

gdb.current_objfile().pretty_printers.append(str_lookup_function)
tmp$ g++ -g str.cc
tmp$ ~/gcc/gdb/7.8.50/bin/gdb 
GNU gdb (GDB) 7.8.50.20141216-cvs
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) set auto-load safe-path /
(gdb) file a.out
Reading symbols from a.out...done.
(gdb) start
Temporary breakpoint 1 at 0x4005b8: file str.cc, line 16.
Starting program: /tmp/a.out 

Temporary breakpoint 1, main () at str.cc:16
16        Foo foo;
(gdb) n
17        Bar bar;
(gdb) p foo
$1 = "foo"
(gdb) n
18        return 0;
(gdb) p bar
$2 = "\x4006b4\003\000\000\000\000\000\000\000\x4006b0"
(gdb) 

The LazyString seems to be confused by the fact that Bar::str is declared with a typedef, so it prints the contents of &bar.str instead of bar.str

The only solution I've found is to strip the typedef first:

    def to_string (self):
        s = self.val['str']
        s = s.cast(s.type.strip_typedefs())
        l = self.val['len']
        return s.lazy_string(length = l)
Comment 1 Jonathan Wakely 2014-12-18 14:00:50 UTC
This seems odd:

(gdb) python print StrPrinter(gdb.parse_and_eval('foo')).to_string().type
const char
(gdb) python print StrPrinter(gdb.parse_and_eval('bar')).to_string().type
Bar::pointer

https://sourceware.org/gdb/onlinedocs/gdb/Lazy-Strings-In-Python.html says type "will always be a pointer type" but the lazy string for foo is not a pointer. The lazy string for bar is a typedef for a pointer, but doesn't work correctly.

Also odd:

(gdb) python print StrPrinter(gdb.parse_and_eval('foo')).to_string().value()
102 'f'
(gdb) python print StrPrinter(gdb.parse_and_eval('bar')).to_string().value()
0x4006b4 "bar"

The LazyString.value() method shows the right thing for bar, but not for foo (which is at least consistent with the .type attribute which says that foo's type is just a char not a char*)
Comment 2 Sourceware Commits 2017-03-16 16:31:13 UTC
The master branch has been updated by Doug Evans <devans@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=34b433203b5f56149c27a8dfea21a921392cb158

commit 34b433203b5f56149c27a8dfea21a921392cb158
Author: Doug Evans <dje@google.com>
Date:   Wed Mar 15 15:35:13 2017 -0700

    Fix various python lazy string bugs.
    
    gdb/ChangeLog:
    
    	PR python/17728, python/18439, python/18779
    	* python/py-lazy-string.c (lazy_string_object): Clarify use of LENGTH
    	member.  Change type of TYPE member to PyObject *.  All uses updated.
    	(stpy_convert_to_value): Fix handling of TYPE_CODE_PTR.
    	(gdbpy_create_lazy_string_object): Flag bad length values.
    	Handle TYPE_CODE_ARRAY with possibly different user-provided length.
    	Handle typedefs in incoming type.
    	(stpy_lazy_string_elt_type): New function.
    	(gdbpy_extract_lazy_string): Call it.
    	* python/py-value.c (valpy_lazy_string): Flag bad length values.
    	Fix handling of TYPE_CODE_PTR.  Handle TYPE_CODE_ARRAY.  Handle
    	typedefs in incoming type.
    
    gdb/testsuite/ChangeLog:
    
    	PR python/17728, python/18439, python/18779
    	* gdb.python/py-value.c (main) Delete locals sptr, sn.
    	* gdb.python/py-lazy-string.c (pointer): New typedef.
    	(main): New locals ptr, array, typedef_ptr.
    	* gdb.python/py-value.exp: Move lazy string tests to ...
    	* gdb.python/py-lazy-string.exp: ... here.  Add more tests for pointer,
    	array, typedef lazy strings.
Comment 3 Phil Muldoon 2017-08-08 09:57:22 UTC
Can we close this bug, Doug?
Comment 4 Tom Tromey 2018-04-22 21:25:28 UTC
I tried the original test case and it is fixed.