Bug 586558

Summary: missing debug info for member functions defined in header file for shared library
Product: Red Hat Enterprise Linux 5 Reporter: Jeff Bastian <jbastian>
Component: gccAssignee: Jakub Jelinek <jakub>
Status: CLOSED NOTABUG QA Contact: qe-baseos-tools-bugs
Severity: medium Docs Contact:
Priority: medium    
Version: 5.5CC: tao
Target Milestone: rcKeywords: Reopened
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2010-05-19 09:31:59 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
demo program none

Description Jeff Bastian 2010-04-27 20:54:34 UTC
Created attachment 409586 [details]
demo program

Description of problem:
If the body of a constructor or other member function is defined in-line within the class definition in a header file, and then the class is compiled into a shared library, the debug info is missing for the constructor and other member functions.

For example, given this foo class defined in foo.h:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class foo
{
  public:
        int f;

        foo() { f = 3; }
        foo(int x) : f(x) { }
        ~foo() { }

        bool operator == (const foo& rhs) const { return f == rhs.f; }
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When compiled into a shared library, the debug info is missing for the constructors, destructor, and == operator.  The only function shown is somefunc (a dummy function so we can at least see one function).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ readelf -wp foo.so
Contents of the .debug_pubnames section:

  Length:                              27
  Version:                             2
  Offset into .debug_info section:     0
  Size of area in .debug_info section: 205

    Offset      Name
    154                 somefunc
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If the member function bodies are moved into the foo.cpp file, there is a lot more debug info to work with:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ readelf -wp foo-modified.so
Contents of the .debug_pubnames section:

  Length:                              127
  Version:                             2
  Offset into .debug_info section:     0
  Size of area in .debug_info section: 803

    Offset      Name
    360                 foo::foo
    398                 foo::foo
    469                 foo::foo
    515                 foo::foo
    606                 foo::~foo
    644                 foo::~foo
    682                 foo::operator==
    752                 somefunc
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The missing debug info makes it difficult to set breakpoints on the member functions.

Version-Release number of selected component (if applicable):
gcc-4.1.2-48.el5.x86_64
gcc-c++-4.1.2-48.el5.x86_64

How reproducible:
every time

Steps to Reproduce:
1. tar xzf foo-members.tar.gz           (see attached)
2. cd foo-members
3. make
 
Actual results:
no debug info for member functions in foo.so

Expected results:
full debug info for member functions in foo.so

Additional info:

Comment 1 Jeff Bastian 2010-04-27 21:08:53 UTC
gdb doesn't know anything about the member functions with foo.so:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ gdb foo.so
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5)
...
Reading symbols from /home/jbastian/scratch/it724583/foo-members/foo.so...done.
(gdb) info functions foo
All functions matching regular expression "foo":
(gdb) 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

But it works much better with foo-modified.so:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ gdb foo-modified.so
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5)
...
Reading symbols from /home/jbastian/scratch/it724583/foo-members/foo-modified.so...done.
(gdb) info functions foo
All functions matching regular expression "foo":

File foo-modified.cpp:
void foo::foo();
void foo::foo();
void foo::foo(int);
void foo::foo(int);
bool foo::operator==(foo const&) const;
void foo::~foo();
void foo::~foo();
(gdb)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


On a side note, it's curious that the constructors and destructor are listed twice...

Comment 2 Jakub Jelinek 2010-05-17 10:31:17 UTC
That's by design, because foo class isn't used at all.
Unused types are pruned by default to avoid debug info being very large.

You can use -fno-eliminate-unused-debug-types to force all types into the debug info.

Comment 3 Jeff Bastian 2010-05-17 13:09:42 UTC
That flag doesn't help.  I also tried -fno-eliminate-unused-debug-symbols.

$ g++ -g -fno-eliminate-unused-debug-types \
         -fno-eliminate-unused-debug-symbols \
         -fPIC -c -o foo.o foo.cpp
$ g++ -g -fno-eliminate-unused-debug-types \
         -fno-eliminate-unused-debug-symbols \
         -shared -o foo.so foo.o
$ readelf -wp foo.so
Contents of the .debug_pubnames section:

  Length:                              27
  Version:                             2
  Offset into .debug_info section:     0
  Size of area in .debug_info section: 375

    Offset      Name
    324                 somefunc

Comment 4 Jakub Jelinek 2010-05-19 09:31:59 UTC
Why are you looking at .debug_pubnames rather than .debug_info?  AFAIK gdb never uses this section and the section has lots of inherent issues that prevent it from being actually used.  If you add foo var; into a CU that just includes that header, you'll see it doesn't emit further .debug_pubnames items either, yet have the DW_TAG_subprogram/DW_TAG_*_type that is needed.

Comment 5 Jakub Jelinek 2010-05-19 13:24:36 UTC
As I said earlier, -fno-eliminate-unused-debug-types makes sure the unused type is emitted in the debug info.

Now, if you want to put a breakpoint on the methods or call them from inferior, you want those methods to be actually emitted.  If they are inline methods, they aren't emitted at all when not used and when used, they are usually inlined and only when not inlined they are emitted out of line.  -g shouldn't affect generated code, it just tells the compiler to describe to the debugger what has been emitted.

If for debugging purposes you need bodies of the inline methods, you can use -fkeep-inline-functions which will grow the size of the generated code considerably (emits everything out of line in addition to all the successful inlines).