Bug 29792 - DWARF: Not all inline concrete instances are being generated
Summary: DWARF: Not all inline concrete instances are being generated
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-11-10 02:55 UTC by Arnaldo Carvalho de Melo
Modified: 2019-09-12 04:26 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Preprocessed sched.c (104.35 KB, text/plain)
2006-11-10 03:20 UTC, Arnaldo Carvalho de Melo
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Arnaldo Carvalho de Melo 2006-11-10 02:55:09 UTC
I'm working on tools to use the DWARF information to do several things, such as finding holes in structures, help in finding inline functions to uninline, etc, the tools are available at this git repository: http://www.kernel.org/git/?p=linux/kernel/git/acme/pahole.git;a=summary

One of the tools is called pfunct and one of its outputs is:

/* /pub/scm/linux/kernel/git/acme/net-2.6.20/kernel/sched.c:4107 */
int sched_setscheduler(struct task_struct * p, int policy, struct sched_param * param);

/* inline expansions in sched_setscheduler:
current_thread_info: 7
unlock_task_sighand: 5
get_current: 9
__raw_local_irq_save: 3
task_running: 6
resched_task: 11
raw_local_irq_restore: 2
raw_local_irq_restore: 8
resched_task: 13
*/
[acme@newtoy net-2.6.20]$

I.e. it searches in DW_TAG_subprogram trees for DW_TAG_inlined_subroutine entries, and uses the DW_AT_high_pc, DW_AT_low_pc and DW_AT_ranges to print the size of each inline expansion.

Another tool goes thru the functions return types, parameter list, variables in all lexical blocks, inline expansions and recursively counts the references to the various tags, in the end it looks for entries that aren't referenced to help in reorganizing includes definitions, etc.

In doing this I noticed that not all concrete inline instances are being emitted, such as __task_rq_lock, a inline function, used in sched_setscheduler in the above example, several other cases aren't also emitted, and this is confirmed by using elfutils's readelf as well as binutils equivalent tools.

Searching for similar problems I've found the 19191 ticket, where the problem was worse, no concrete inline were being emitted, now most are being emitted, but not all, is this a know issue?

More information, dumps, whatever I can do to help in fixing this problem can be provided if requested.

This is my first ticket ever for gcc bugzilla, so here are more info:

[acme@newtoy net-2.6.20]$ gcc -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: /home/acme/svn/gcc/configure --prefix=/home/acme/gcc-cvs --enable-languages=c --with-dwarf2 --enable-targets=i686-mandriva-linux-gnu --disable-nls --with-gmp=/home/acme/gcc-infrastructure --with-mpfr=/home/acme/gcc-infrastructure
Thread model: posix
gcc version 4.3.0 20061108 (experimental)
[acme@newtoy net-2.6.20]$

But the same problem happens at least with:

[acme@newtoy net-2.6.20]$ gcc -v
Using built-in specs.
Target: i586-mandriva-linux-gnu
Configured with: ../configure --prefix=/usr --libexecdir=/usr/lib --with-slibdir=/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --enable-languages=c,c++,ada,fortran,objc,obj-c++,java --host=i586-mandriva-linux-gnu --with-cpu=generic --with-system-zlib --enable-long-long --enable-__cxa_atexit --enable-clocale=gnu --disable-libunwind-exceptions --enable-java-awt=gtk --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --enable-gtk-cairo --enable-ssp --disable-libssp
Thread model: posix
gcc version 4.1.1 20060724 (prerelease) (4.1.1-3mdk)
[acme@newtoy net-2.6.20]$

I've been using Ulrich Drepper's excellent libdw DWARF library, found in the elfutils package.
Comment 1 Andrew Pinski 2006-11-10 03:09:14 UTC
Can you supply a preprocessed source of sched.c and the options which you compiled it with?
Comment 2 Arnaldo Carvalho de Melo 2006-11-10 03:19:06 UTC
(In reply to comment #1)
> Can you supply a preprocessed source of sched.c and the options which you
> compiled it with?
> 

Find the kernel/sched.i file attached, the options were these ones:

gcc -m32 -Wp,-MD,kernel/.sched.o.d  -nostdinc -isystem /home/acme/gcc-cvs/lib/gcc/i686-pc-linux-gnu/4.3.0/include -D__KERNEL__ -Iinclude -Iinclude2 -I/pub/scm/linux/kernel/git/acme/net-2.6.20/include -include include/linux/autoconf.h -I/pub/scm/linux/kernel/git/acme/net-2.6.20/kernel -Ikernel -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -pipe -msoft-float -mpreferred-stack-boundary=2 -march=i686 -ffreestanding -maccumulate-outgoing-args -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -I/pub/scm/linux/kernel/git/acme/net-2.6.20/include/asm-i386/mach-default -Iinclude/asm-i386/mach-default -fomit-frame-pointer -g -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -fno-omit-frame-pointer  -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(sched)"  -D"KBUILD_MODNAME=KBUILD_STR(sched)" -c -o kernel/sched.o /pub/scm/linux/kernel/git/acme/net-2.6.20/kernel/sched.c
Comment 3 Arnaldo Carvalho de Melo 2006-11-10 03:20:37 UTC
Created attachment 12584 [details]
Preprocessed sched.c
Comment 4 Andrew Pinski 2006-11-12 08:35:25 UTC
The only thing left from __task_rq_lock is a label.
If we look at that inlined function, we see:
static inline __attribute__((always_inline)) struct rq *__task_rq_lock(struct task_struct *p)

{
 struct rq *rq;

repeat_lock_task:
 rq = (&(*((void)((task_cpu(p))), &per_cpu__runqueues)));
 do { do { } while (0); (void)0; (void)(&rq->lock); } while (0);
 if (__builtin_expect(!!(rq != (&(*((void)((task_cpu(p))), &per_cpu__runqueues)))), 0)) {
  do { do { } while (0); (void)0; (void)(&rq->lock); } while (0);
  goto repeat_lock_task;
 }
 return rq;
}


the if is never true as rq is always equal to &per_cpu__runqueues. The calls to task_cpu were inlined and we constant proped the value of rq the first of the way through the function which we inlined this to.
Comment 5 Arnaldo Carvalho de Melo 2006-11-12 20:39:43 UTC
(In reply to comment #4)
> The only thing left from __task_rq_lock is a label.

<SNIP>

> task_cpu were inlined and we constant proped the value of rq the first of the
> way through the function which we inlined this to.

OK, I thought that this was due to something like what you described, even not knowing that much about gcc internals, but I thought that even in this case the DW_TAG_inlined_subroutine would be emitted, or hoped to as it would allow me to do what I want with my tools :-\
Comment 6 Arnaldo Carvalho de Melo 2006-11-13 12:24:45 UTC
Has an interesting discussion about "Thin inlines":

http://sourceware.org/ml/dwarf2/2001-q1/msg00124.html
Comment 7 Daniel Berlin 2006-11-13 16:00:16 UTC
Subject: Re:  DWARF: Not all inline concrete instances are being generated

On 12 Nov 2006 20:39:43 -0000, acme at mandriva dot com
<gcc-bugzilla@gcc.gnu.org> wrote:
>
>
> ------- Comment #5 from acme at mandriva dot com  2006-11-12 20:39 -------
> (In reply to comment #4)
> > The only thing left from __task_rq_lock is a label.
>
> <SNIP>
>
> > task_cpu were inlined and we constant proped the value of rq the first of the
> > way through the function which we inlined this to.
>
> OK, I thought that this was due to something like what you described, even not
> knowing that much about gcc internals, but I thought that even in this case the
> DW_TAG_inlined_subroutine would be emitted, or hoped to as it would allow me to
> do what I want with my tools :-\

There is nothing to emit debug info about, so we don't.
Comment 8 Arnaldo Carvalho de Melo 2006-11-13 16:16:50 UTC
> > OK, I thought that this was due to something like what you described, even not
> > knowing that much about gcc internals, but I thought that even in this case the
> > DW_TAG_inlined_subroutine would be emitted, or hoped to as it would allow me to
> > do what I want with my tools :-\
> 
> There is nothing to emit debug info about, so we don't.
> 

Well, at least gcc emits this:

 <1><a2f2>: Abbrev Number: 65 (DW_TAG_subprogram)
     DW_AT_sibling     : <a324>
     DW_AT_name        : (indirect string, offset: 0x4515): __task_rq_lock
     DW_AT_decl_file   : 1
     DW_AT_decl_line   : 378
     DW_AT_prototyped  : 1
     DW_AT_type        : <9a2f>
     DW_AT_inline      : 3      (declared as inline and inlined)

But no DW_TAG_inlined_subroutine, as we've been discussing:

[acme@newtoy net-2.6.20]$ readelf -wi ../OUTPUT/qemu/net-2.6.20/kernel/sched.o | grep a2f2
     DW_AT_sibling     : <a2f2>
 <1><a2f2>: Abbrev Number: 65 (DW_TAG_subprogram)
[acme@newtoy net-2.6.20]$

:-\
Comment 9 Daniel Berlin 2006-11-14 04:53:45 UTC
Subject: Re:  DWARF: Not all inline concrete instances are being generated

On 13 Nov 2006 16:16:50 -0000, acme at mandriva dot com
<gcc-bugzilla@gcc.gnu.org> wrote:
>
>
> ------- Comment #8 from acme at mandriva dot com  2006-11-13 16:16 -------
> > > OK, I thought that this was due to something like what you described, even not
> > > knowing that much about gcc internals, but I thought that even in this case the
> > > DW_TAG_inlined_subroutine would be emitted, or hoped to as it would allow me to
> > > do what I want with my tools :-\
> >
> > There is nothing to emit debug info about, so we don't.
> >
>
> Well, at least gcc emits this:
>
>  <1><a2f2>: Abbrev Number: 65 (DW_TAG_subprogram)
>      DW_AT_sibling     : <a324>
>      DW_AT_name        : (indirect string, offset: 0x4515): __task_rq_lock
>      DW_AT_decl_file   : 1
>      DW_AT_decl_line   : 378
>      DW_AT_prototyped  : 1
>      DW_AT_type        : <9a2f>
>      DW_AT_inline      : 3      (declared as inline and inlined)
>
> But no DW_TAG_inlined_subroutine, as we've been discussing:
>
> [acme@newtoy net-2.6.20]$ readelf -wi ../OUTPUT/qemu/net-2.6.20/kernel/sched.o
> | grep a2f2
>      DW_AT_sibling     : <a2f2>
>  <1><a2f2>: Abbrev Number: 65 (DW_TAG_subprogram)
> [acme@newtoy net-2.6.20]$

I'm quite aware of what GCC outputs here :)

However, past the initial declarations, we don't output debug
information about what the state of the IR is at random points in the
compilation, only about what the final output looks like.  Since there
is no inlined code left, we don't end up saying there is an inlined
subroutine.

Even if we could change this, i'm not sure we'd want to.  It doesn't
seem incorrect at all to do what we do.
Otherwise, you'd end up with inlined subroutine dies with no low
pc/high pc associated with them, which seems nonsensical.
Comment 10 Arnaldo Carvalho de Melo 2006-11-14 17:19:15 UTC
(In reply to comment #9)
> 
> I'm quite aware of what GCC outputs here :)
> 
> However, past the initial declarations, we don't output debug
> information about what the state of the IR is at random points in the
> compilation, only about what the final output looks like.  Since there
> is no inlined code left, we don't end up saying there is an inlined
> subroutine.
> 
> Even if we could change this, i'm not sure we'd want to.  It doesn't
> seem incorrect at all to do what we do.
> Otherwise, you'd end up with inlined subroutine dies with no low
> pc/high pc associated with them, which seems nonsensical.

OK, so I'll have to find another way of using the DWARF info to see if a inline routine, such as __task_rq_lock was used at all in the build or was just included in the DWARF info but not referenced anywhere, have to dig more into the available information...

BTW, if, in these cases, DW_TAG_subroutine is not referenced, what is the purpose of it being included? Is there a reason my limited knowledge is not realising?

Comment 11 Daniel Berlin 2006-11-15 03:55:05 UTC
Subject: Re:  DWARF: Not all inline concrete instances are being generated

> OK, so I'll have to find another way of using the DWARF info to see if a inline
> routine, such as __task_rq_lock was used at all in the build or was just
> included in the DWARF info but not referenced anywhere, have to dig more into
> the available information...
>
> BTW, if, in these cases, DW_TAG_subroutine is not referenced, what is the
> purpose of it being included? Is there a reason my limited knowledge is not
> realising?

Well, it is referenced. It did exist in the source, and was inlined.
That's what we output.  DW_TAG_subprogram with no PC range is actually
common.

Because all the inlined instances were optimized away, there are no
DW_TAG_inlined_* entries for them.

>
>
> --
>
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29792
>
>
Comment 12 Arnaldo Carvalho de Melo 2006-11-16 01:53:39 UTC
(In reply to comment #11)
> Subject: Re:  DWARF: Not all inline concrete instances are being generated
> 
> > OK, so I'll have to find another way of using the DWARF info to see if a inline
> > routine, such as __task_rq_lock was used at all in the build or was just
> > included in the DWARF info but not referenced anywhere, have to dig more into
> > the available information...
> >
> > BTW, if, in these cases, DW_TAG_subroutine is not referenced, what is the
> > purpose of it being included? Is there a reason my limited knowledge is not
> > realising?
> 
> Well, it is referenced. It did exist in the source, and was inlined.
> That's what we output.  DW_TAG_subprogram with no PC range is actually
> common.
> 
> Because all the inlined instances were optimized away, there are no
> DW_TAG_inlined_* entries for them.

/me slaps himself in the face

Duh, should have checked this :-)

[acme@newtoy examples]$ cat a.c
static inline int foo(int i)
{
        return i + 10;
}

int main(void)
{
}
[acme@newtoy examples]$ readelf -wi a |grep foo
[acme@newtoy examples]$

Excellent, only if its not static:

[acme@newtoy examples]$ cat a.c
inline int foo(int i)
{
        return i + 10;
}

int main(void)
{
}
[acme@newtoy examples]$ readelf -wi a |grep foo
     DW_AT_name        : foo
[acme@newtoy examples]$

And in this case my tool, prefcnt, should warn that this routine, inline or not, is not being used at all and is eligible to go to the dustbin.

Thanks a lot for your patience and advise, closing the ticket as INVALID.