52

I'd like to find unused functions in a codebase - including across compilations units. I'm using gcc as my compiler.

Here's an example:

foo.c (assume appropriate foo.h):

void foo() {
   ....
}

void bar() {
   ....
}

main.c:

#include <stdio.h>
#include "foo.h"  

int main(void)  {
    bar();
    return 0;
}

In this example, I'd like to get warned about foo() not being used.

There is the -Wunused-function gcc option:

-Wunused-function

Warn whenever a static function is declared but not defined or a non-inline static function is unused. This warning is enabled by -Wall.

but it's only for static functions - it won't produce a warning on the example above.

I'll also accept suggestions of tools/scripts/other compilers that can do this for me - though I'd prefer to stick with gcc if possible.

Timothy Jones
  • 21,495
  • 6
  • 60
  • 90
  • 9
    There's a good reason not to warn on unused non-static functions by default. A non-static function is part of the public interface, since you could easily feed a gcc-generated .o file through the linker to generate a .a or .so library in which all those non-static functions are made available to whomever links with the library. That said, this is still a great question, which I hope will have a useful answer. – Adam Mihalcin Feb 01 '12 at 05:52
  • 4
    Absolutely, it shouldn't be on by default. Still, I'd like to be able to turn it on at final link time if the feature exists :) – Timothy Jones Feb 01 '12 at 05:53
  • 1
    Relevant http://gcc.gnu.org/ml/gcc-help/2003-08/msg00072.html ? – shadyabhi Feb 01 '12 at 05:55
  • 2
    You could consider using a code coverage tool :) – Billy ONeal Feb 01 '12 at 05:59
  • 1
    You can try and compile all your files at once using `-fwhole-program`; perhaps that'll give you additional warnings. – Kerrek SB Feb 01 '12 at 06:05
  • @BillyONeal I wondered about that. However, code coverage tools I've used previously only show the coverage of actually executed code in some run or runs of the binary. I'm after more of a "this function isn't called". Please expand in an answer if you think there's a C code coverage tool that can do this :) – Timothy Jones Feb 01 '12 at 06:10
  • Thanks @KerrekSB, but I didn't get any new warnings compiling that way :( – Timothy Jones Feb 01 '12 at 06:11
  • This SO answer might be of some help: http://stackoverflow.com/a/4449936/12711 – Michael Burr Feb 01 '12 at 07:44
  • 1
    code coverage tools are for runtime checking, it'd be interesting to find some alternative that checks this also using #define-s. I doubt there is an easy answer. – Tomas Pruzina Feb 20 '12 at 13:37

6 Answers6

52

Caolan Mc Namara, a LibreOffice developer, has made a small tool to detect this type of thing in LibreOffice source code. They had around thousands functions & methods unused in LibreOffice. His tool is a key element for removing them.

It's called callcatcher. It can

collect functions/methods defined and subtract called/referenced

It works directly on assembler output and so, it works only for x86 and x86_64 architecture. It can produce output like this. You can integrate it with your traditional compiling and linking call to gcc.

Caolan agrees that it should become a gcc plugin.

Coren
  • 5,517
  • 1
  • 21
  • 34
  • This does exactly what I want, out of the box. Thank you! – Timothy Jones Feb 21 '12 at 05:45
  • 5
    That's brilliant. For your entertainment value, the project I'm working on at work has **1257 unused functions**. I had the impression that there might be more than a few in this code base... – Greg Hewgill Mar 02 '12 at 02:17
  • 1
    Original link is dead. This seems to be the reference tool. https://github.com/caolanm/callcatcher – Taekahn Aug 08 '18 at 21:24
  • The first link in this post is now broken. An archived version is at `https://web.archive.org/web/20120127161255/http://blogs.linux.ie/caolan/` – AJM Jun 21 '22 at 18:05
  • 1
    I fixed the link with the new url of his blog : http://caolanm.blogspot.com/ – Coren Jun 22 '22 at 08:03
7

I know you asked for warnings and prefers not to use gcc option but it is really easy.

You can use linker optimization (--gc-sections) in order to remove the dead code from your application.

From ld's man page:

--gc-sections --no-gc-sections Enable garbage collection of unused input sections. It is ignored on targets that do not support this option. The default behaviour (of not performing this garbage collection) can be restored by specifying --no-gc-sections on the command line.

--print-gc-sections --no-print-gc-sections List all sections removed by garbage collection. The listing is printed on stderr. This option is only effective if garbage collection has been enabled via the --gc-sections) option. The default behaviour (of not listing the sections that are removed) can be restored by specifying --no-print-gc-sections on the command line.

Explanation:

--gc-sections decides which input sections are used by examining symbols and relocations. The section containing the entry symbol and all sections containing symbols undefined on the command-line will be kept, as will sections containing symbols referenced by dynamic objects. Note that when building shared libraries, the linker must assume that any visible symbol is referenced. Once this initial set of sections has been determined, the linker recursively marks as used any section referenced by their relocations. See --entry and --undefined.

This option can be set when doing a partial link (enabled with option -r). In this case the root of symbols kept must be explicitly specified either by an --entry or --undefined option or by a "ENTRY" command in the linker script.

rtrrtr
  • 563
  • 5
  • 7
eyalm
  • 3,366
  • 19
  • 21
  • 8
    Sadly I'm not looking to remove the code from the binary - I'm looking to find out which parts of the source can be cleaned up – Timothy Jones Feb 15 '12 at 03:28
  • 10
    If I remember correctly, there is a verbosity option that will print a list of optimizations that was done by gc-sections. I think it is "--print-gc-sections" – eyalm Feb 15 '12 at 05:13
  • @eyalm I think you answer gonna get lot more upvotes if you'd change it a bit to add the print-gc-sections option with an example. – Hi-Angel Jul 06 '18 at 10:13
  • The quoted information is in [ld's manpage](https://linux.die.net/man/1/ld), not gcc's. – AJM May 09 '22 at 17:54
6

Add the gcc option -ffunction-sections to your compiles, and --gc-sections and --print-gc-sections to your link command. If you invoke the linker via gcc, use -Wl,--gc-sections,--print-gc-sections to pas these through to ld.

This will strip out the unused object code, which you said you don't want. In that case, remove --gc-sections once you've generated the desired output.

You didn't ask about identifying unused data, but to do that, add the -fdata-sections option to your compiles as well.

Scott Cooper
  • 71
  • 1
  • 4
4

First, if you want such warnings to be program-wide, you certainly need the -flto flag, since it should be resolved at link time, not at time of compilation of each individual unit. But I don't think that GCC provide such warnings, even this way.

Then, in the general case, I would understand it won't be wise to provide it (because e.g. the linked libc probably has a lot of functions your application don't need). Also, an application could use dlsym tricks to reach an apparently uncalled function...

However, it is a good example of a potential use case for a GCC plugin or MELT extension, which would register each call occurrence somewhere, with a later utility finding all non-called functions. (But coding a plugin or a MELT extension for GCC will take you several days at least, because you'll need to understand GCC internals).

You could also use profiling techniques to get the dynamically unused (not called) functions.

Feel free to ask me more by email.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 1
    +1 Thanks. If I end up going the GCC plugin route I'll almost certainly send you an email :) – Timothy Jones Feb 01 '12 at 06:12
  • I'm much more qualified to help you on MELT extensions than on GCC plugins in C. – Basile Starynkevitch Feb 01 '12 at 06:19
  • @BasileStarynkevitch: maybe you'll be interested to see what Caolan Mc Namara has done about this. See my answer for more details. – Coren Feb 17 '12 at 08:43
  • But you are affiliated with MELT. That wasn't revealed. "[Basile Starynkevitch](http://www.starynkevitch.net/Basile/index_en.html) ... My main work was on GCC, notably its MELT branch" – Peter Mortensen Sep 03 '22 at 09:41
  • "*[The gcc-melt.org domain has been lost in April 2018.](http://starynkevitch.net/Basile/gcc-melt/)*". And *[Documentation about GCC MELT](http://starynkevitch.net/Basile/gcc-melt/docum.html)* – Peter Mortensen Sep 03 '22 at 09:44
4

gprof is the simplest solution I guess. I compiled the sample program you've put up with -pg option so that we get the gmon.out when we run a.out (which gprof can use later) and then I finally ran gprof -z a.out gmon.out | tee output.txt . I could find your function foo in the unused list! i.e called 0 times. -z is the option you should use along with gprof to track unused routines.

Thanks to this thread for the appropriate pointer!

PS: gprof threw up a slew of other unused library functions along with your unused function foo. I seriously don't know how to filter this :)

Pavan Manjunath
  • 27,404
  • 12
  • 99
  • 125
1

Eclipse CDT does have code analysis, which you can set to mark unused static functions and unused function declarations (among other useful things). As already told, only linker could tell certain (non-static) function was not used in certain binary...

dbrank0
  • 9,026
  • 2
  • 37
  • 55