2

I have a struct in C++ something like this:

struct HeapBlock {
    char* data;
}

struct DataBlock {
    int size;
    HeapBlock hb;
}

These are part of a framework and have several other members, helpers and so on, but these are are the important parts. I would like to show this in a Python GDB pretty-printer something like this:

NAME                  TYPE             VALUE
DataBlock:            DataBlock       "Size 2000 @ 0x445343"
  |--->size           int             2000
  |--->data           HeapBlock       {...}
        |--->[0]      char            0x34
        |--->[1]      char            0x45
        ....
        <more values>

So far, I have failed at getting the HeapBlock to be shown as a separate child. I have successfully abused an iterator to produce:

NAME                  TYPE             VALUE
DataBlock:            DataBlock      
  |--->size           int              2000
  |--->[0]            char             0x34
  |--->[1]            char             0x45
   ....
   <more values>

This was done by returning the db["size"] in the first result from the iterator returned by DataBlockPrinter's children() method, and then from db["hb"]["data"] for the next size results.

I have also tried to use a separate printer for HeapBlocks, but the problem there is that a HeapBlock has no idea how big it is: that is stored in the parent (DataBlock), so the HeapBlock printer also doesn't know when to stop iterating.

Is it possible to get the size field to the HeapBlock pretty printer when it is printed as part of DataBlock here?

Inductiveload
  • 6,094
  • 4
  • 29
  • 55

2 Answers2

1

I found another way

#convert to vector
class DataBlock:
  def iter(self):
    p=self.v['p']
    emtp=p.type.target().unqualified().strip_typedefs()
    pv=emtp.vector(self.cnt-1).pointer()#convert to vector,the actual type is char (*) __attribute__ (vector_size(self.cnt)))
    yield('p',p.cast(pv))
#We register this type
def regCls(v):
    if str(v.type).find(") __attribute__ ((vector_size")>0:
      return _py_vector(v)
def regMyPP():gdb.pretty_printers.append(regCls) 
#Then parse this type out
class _py_vector:
  def __init__(self,v):self.v=v
  def tp(self):
    s=str(self.v.type)
    return gdb.lookup_type(s[:s.find('(')-1]).pointer()#eg.char
  def sz(self):
    s=str(self.v.type)
    st=s.find('vector_size(')+12
    ed=s.find(')',st)
    return int(s[st:ed])#Get it's size
  def to_string(self): return self.v.cast(self.tp()).lazy_string(length=self.sz())
  def display_hint(self): return 'string' 
Adrian
  • 10,246
  • 4
  • 44
  • 110
陈林熙
  • 21
  • 1
  • 4
0

Unfortunately there is no built-in way to do this. I believe there is a bug open about it in gdb bugzilla.

It might be possible to do it with a hack: in the DataBlock printer, record the address and size of the HeapBlock in a hash table. Then the HeapBlock printer could look this up. Of course then the problem becomes one of deciding how to invalidate the cache. Offhand I can't think of a good way :-( But maybe it's ok to simply not invalidate it. You might try invalidating when the DataBlock printer is destroyed; gdb doesn't guarantee that this will work, but it might be ok in practice.

Tom Tromey
  • 21,507
  • 2
  • 45
  • 63
  • Seems like a combination of https://sourceware.org/bugzilla/show_bug.cgi?id=12806 and https://sourceware.org/bugzilla/show_bug.cgi?id=16436? – Inductiveload Mar 09 '15 at 16:09