Bug 29079 - Python pretty printer does not work for class members
Summary: Python pretty printer does not work for class members
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: python (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 15.1
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-04-20 23:24 UTC by asmwarrior
Modified: 2023-12-09 09:03 UTC (History)
1 user (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 asmwarrior 2022-04-20 23:24:57 UTC
When I define a Python pretty printer, I see it only works for a normal variable, but not class member variable.

Here is a simple test case, it contains 3 files: main.cpp, reco.h and reco.cpp.

main.cpp
--------------------------------------
#include "reco.h"

class CTest
{
public:

    CTest(float input)
        :r(input), v(18), f(65.7)
    {
    }
    reco r;
    int  v;
    float f;
};

double DummyFunctionForwxreco(void *dummy)
{
    reco* p = (reco*)dummy;
    return p->getWeight();
}

int main() {

    reco sss(5.0);
    CTest ccc(7.8);

    return 0;
}
--------------------------------------

reco.h
--------------------------------------
#ifndef RECO_H
#define RECO_H

class reco {
    public:
        reco(float input);
        ~reco(void);

        virtual float getWeight();

    private:
        float weight;
};

#endif
--------------------------------------

reco.cpp
--------------------------------------
#include "reco.h"

reco::reco(float input) {
    weight = input;
}

reco::~reco(void) {
}

float reco::getWeight() {
    return weight;
}
--------------------------------------


To build the main.exe, you have to type the following command, not the "-g0" option means you don't have debug information in the reco.o.
--------------------------------------
gcc -c -g0 reco.cpp
gcc -c -g main.cpp
g++ -o main.exe main.o reco.o
--------------------------------------

The python pretty printer test.py
--------------------------------------
import gdb
import sys

class recoPrinter:

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

   def to_string(self):
     return gdb.parse_and_eval('DummyFunctionForwxreco((void*)%s)' % self.val.address )    # call the dummy function here!

def CustomPrettyPrinters(val):
   if str(val.type) == 'reco': return recoPrinter(val)
   return None

gdb.pretty_printers.append(CustomPrettyPrinters) 
--------------------------------------

Here is the debug session: you set the breakpoint by this command "b main.cpp:27", and run the exe file by command "r", when it hit the breakpoint, you can try to print some variables.

--------------------------------------
# gdb main.exe
GNU gdb (GDB) 11.2
Copyright (C) 2022 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-w64-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://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"...
Reading symbols from main.exe...
(gdb) b main.cpp:27
Breakpoint 1 at 0x1400015a3: file main.cpp, line 27.
(gdb) r
Starting program: E:\code\gdb-incomplete-type\main.exe

Breakpoint 1, main () at main.cpp:27
27          return 0;
(gdb) p sss
$1 = <incomplete type>
(gdb) p ccc
$2 = {r = <incomplete type>, v = 18, f = 65.6999969}
(gdb) source test.py
(gdb) p sss
$3 = 5
(gdb) p ccc
$4 = {r = <incomplete type>, v = 18, f = 65.6999969}
(gdb)

--------------------------------------


You see, the "p sss" works OK after "source test.py", but the "p ccc" is still not good.

I think the pretty printer is simple, because I don't even use pretty printer for std library.
Comment 1 asmwarrior 2022-04-21 03:02:49 UTC
ssbssa wrote a patch to fix this issue:

Here is the patch:

================
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 6b1531ef442..f540c681403 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -1028,16 +1028,6 @@ common_val_print (struct value *value, struct ui_file *stream, int recurse,
 
   QUIT;
 
-  /* Ensure that the type is complete and not just a stub.  If the type is
-     only a stub and we can't find and substitute its complete type, then
-     print appropriate string and return.  */
-
-  if (real_type->is_stub ())
-    {
-      fprintf_styled (stream, metadata_style.style (), _("<incomplete type>"));
-      return;
-    }
-
   if (!valprint_check_validity (stream, real_type, 0, value))
     return;
 
@@ -1048,6 +1038,16 @@ common_val_print (struct value *value, struct ui_file *stream, int recurse,
 	return;
     }
 
+  /* Ensure that the type is complete and not just a stub.  If the type is
+     only a stub and we can't find and substitute its complete type, then
+     print appropriate string and return.  */
+
+  if (real_type->is_stub ())
+    {
+      fprintf_styled (stream, metadata_style.style (), _("<incomplete type>"));
+      return;
+    }
+
   /* Handle summary mode.  If the value is a scalar, print it;
      otherwise, print an ellipsis.  */
   if (options->summary && !val_print_scalar_type_p (type))

=======================================

For more details, you can see the discussion here:

Re: [solved] Creating a gdb Pretty-Printer for wxIPV4address — https://forums.wxwidgets.org/viewtopic.php?p=211799#p211799
Comment 2 Sourceware Commits 2023-12-08 17:22:42 UTC
The master branch has been updated by Hannes Domani <ssbssa@sourceware.org>:

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

commit 7543c960b00ddea23f6105eff4358ec214a7f93c
Author: Hannes Domani <ssbssa@yahoo.de>
Date:   Fri Dec 8 18:19:42 2023 +0100

    Use pretty printers for struct member stubs
    
    PR29079 shows that pretty printers can be used for an incomplete
    type (stub), but only when printing it directly, not if it's
    part of another struct:
    ```
    (gdb) p s
    $1 = {pp m_i = 5}
    (gdb) p s2
    $2 = {m_s = <incomplete type>, m_l = 20}
    ```
    
    The reason is simply that in common_val_print the check for stubs
    is before any pretty printer is tried.
    It works if the pretty printer is tried before the stub check:
    ```
    (gdb) p s
    $1 = {pp m_i = 5}
    (gdb) p s2
    $2 = {m_s = {pp m_i = 10}, m_l = 20}
    ```
    
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29079
    Approved-By: Tom Tromey <tom@tromey.com>
Comment 3 Hannes Domani 2023-12-08 17:23:20 UTC
Fixed.
Comment 4 asmwarrior 2023-12-09 09:03:25 UTC
It is really nice to see the patch is in gdb git now!

I see GDB 14.1 was just released recently, so will wait for the next release 15.1.

Thanks.