Bug 22686 - gdb.lookup_type fails for array types
Summary: gdb.lookup_type fails for array types
Status: UNCONFIRMED
Alias: None
Product: gdb
Classification: Unclassified
Component: python (show other bugs)
Version: 8.0.1
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-01-09 21:47 UTC by Jonathan Wakely
Modified: 2023-03-07 14:34 UTC (History)
3 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 2018-01-09 21:47:08 UTC
(gdb) py gdb.lookup_type("int []")
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: No type named int [].
Error while executing Python code.
(gdb) py gdb.lookup_type("int [2]")
Traceback (most recent call last):
  File "<string>", line 1, in <module>
gdb.error: No type named int [2].
Error while executing Python code.

Such types can occur as C++ template parameters, e.g. std::unique_ptr<int[]> or std::is_array<int[2]>
Comment 1 Simon Marchi 2018-01-10 12:58:21 UTC
Hi Jonathan,

I think this is expected with the current code, as lookup_type looks up type by name only.  In your case, you could do

  >>> print(gdb.lookup_type('int').array(0, 1))                                                
  int [2]
  >>> print(gdb.lookup_type('int').array(1))
  int [2]

In both cases, the 1 is the inclusive upper bound of the array.

It would be handy to be able to do lookup_type('int[2]') though.  And it might allow things that can't be done today.  For example, I don't know how you would make a function pointer type from scratch.  It would be nice if you could just do lookup_type('int (*)(const char *)').

Well, as a workaround you could always do

  >>> print(gdb.parse_and_eval('(int (*)(const char *)) 0').type)
  int (*)(const char *)

and for the int[2] example:

  >>> print(gdb.parse_and_eval('{int[2]} 0').type)
  int [2]
Comment 2 Jonathan Wakely 2018-01-10 13:18:48 UTC
I see. The place I hit this limitation I don't know the type to lookup, I just have a string "int []" and am trying to find out what its type is.

The specific situation is something like:

std::vector<std::unique_ptr<int[]>> v;

GDB (quite correctly) says the real type is:

std::vector<std::unique_ptr<int [], std::default_delete<int []> >, std::allocator<std::unique_ptr<int [], std::default_delete<int []> > > >

This is ugly, and not what the user wrote, so the libstdc++ pretty printers apply type  printers to remove the default template arguments, so it's displayed as simply std::vector<std::unique_ptr<int[]>>.

See https://gcc.gnu.org/viewcvs/gcc/trunk/libstdc%2B%2B-v3/python/libstdcxx/v6/printers.py?revision=256400&view=markup#l1295

This is done with regular expressions, and recursively applying type printers to the remaining template arguments. So first I turn vector<T, allocator<T>> into vector<T>, then I process T, which turns unique_ptr<int[], default_delete<int[]>> into unique_ptr<int[]>. Then I try to do the same to "int[]" as well, which is when I try to look that up. Because I'm using a regex I only have strings, not gdb.Type objects.

I suppose I could use a regex to match the type in the first place, but do the actual substitutions using gdb.Type not regex substitutions.
Comment 3 Jonathan Wakely 2018-01-10 20:39:01 UTC
(In reply to Jonathan Wakely from comment #2)
> I suppose I could use a regex to match the type in the first place, but do
> the actual substitutions using gdb.Type not regex substitutions.

I've rewritten the type printers to not need to lookup types from strings, so no longer need gdb.lookup_type("int[]"), however this revealed some related problems.

I can't see any way to use the Python API to distinguish int[] and int[1]. Both types are arrays, and gdb.Type.range() returns (0,0) for both.

Type recognizers don't handle T*, T&, T&& or T[N], so to print std::string[2] as std::string (rather than std::basic_string<char, std::char_traits<char>, std::allocator<char> >[2]) I need to do extra work. I can use gdb.Type.target() to strip off the array bounds, apply the recognizers again, then append "[2]" to the result, but for the case of "[]" and "[1]" I have no way to distinguish them except parsing the string by hand.

Could gdb.types.apply_type_recognizers handle pointers and arrays for me?

Could I have a way to distinguish T[] and T[1] in the Python API?

Also, there seems to be no way to create the type T[] given the gdb.Type for T. Unless I'm mistaken, type_obj.array(0) will create the type for T[1]
Comment 4 Jonathan Wakely 2018-01-10 22:47:33 UTC
Actually the recognizers do get used for arrays and compound types, but with inconsistent results. The recognizer only gets used for the name of the type, but the full definition of the type is still printed out.

##########

cat > x.cc << EOT
struct X { int i; };

int main()
{
  X x;
  X x2[2];
  return 0;
}
EOT

cat > xprinter.py << EOT
import gdb

class XPrinter(gdb.types.TypePrinter):
  def __init__(self):
    super(XPrinter, self).__init__('X')
  
  def instantiate(self):
    return self._recognizer()
  
  class _recognizer:
    def recognize(self, typ):
      if typ.name == 'X':
        return '__X__'
      return None

gdb.types.register_type_printer(gdb.current_objfile(), XPrinter())
EOT

g++ -g x.cc

gdb -q -ex 'py sys.path.insert(0, ".")' -ex "py import xprinter" \
  -ex start -ex "ptype x" -ex "ptype x2" -ex cont -ex quit a.out

##########

The GDB output is:

Reading symbols from a.out...done.
Temporary breakpoint 1 at 0x4004ab: file x.cc, line 7.
Starting program: /tmp/a.out 

Temporary breakpoint 1, main () at x.cc:7
7         return 0;
type = __X__
type = struct __X__ {
    int i;
} [2]
Continuing.
[Inferior 1 (process 29374) exited normally]


The first ptype has the expected result, but the second prints:

type = struct __X__ {
    int i;
} [2]

I expected it to be something like "__X__ [2]" instead.
Comment 5 Christian Biesinger 2019-06-25 22:54:27 UTC
duplicate of bug 11797?
Comment 6 Jonathan Wakely 2019-06-26 12:26:56 UTC
(In reply to Christian Biesinger from comment #5)
> duplicate of bug 11797?

Yes, although this bug has a lot more info, and comment 4 is a separate issue.
Comment 7 Tom Tromey 2023-03-07 14:34:06 UTC
Bug 11797 suggests a new 'parse_type' function that applies
the language's type-parsing rules.  This is more or less
what 'ptype' does, with the caveat being that ptype really
accepts any expression and yields its type, which can be
resolved in favor of parsing as if the string were an expression
if there is some ambiguity.  What would be really better is
a separate "type" entry point to the parsers.