#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018-2023 Free Software Foundation, Inc.
# Contributed by Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
# Inspired by bloat-o-meter from busybox.

# This software may be used and distributed according to the terms and
# conditions of the GNU General Public License as published by the Free
# Software Foundation.

# For a set of object-files, determine symbols that are
#  - public but should be static

# Examples:
# unused_functions.py ./gcc/fortran
# unused_functions.py gcc/c  gcc/c-family/ gcc/*-c.o | grep -v "'gt_"
# unused_functions.py gcc/cp gcc/c-family/ gcc/*-c.o | grep -v "'gt_"

import sys, os
from tempfile import mkdtemp
from subprocess import Popen, PIPE

def usage():
    sys.stderr.write("usage: %s [-v] [dirs | files] [-- <readelf options>]\n"
                        % sys.argv[0])
    sys.stderr.write("\t-v\tVerbose output\n");
    sys.exit(1)

(odir, sym_args, tmpd, verbose) = (set(), "", None, False)

for i in range(1, len(sys.argv)):
    f = sys.argv[i]
    if f == '--': # sym_args
        sym_args = ' '.join(sys.argv[i + 1:])
        break
    if f == '-v':
        verbose = True
        continue
    if not os.path.exists(f):
        sys.stderr.write("Error: No such file or directory '%s'\n" % f)
        usage()
    else:
        if f.endswith('.a') and tmpd is None:
            tmpd = mkdtemp(prefix='unused_fun')
        odir.add(f)

def dbg(args):
    if not verbose: return
    print(args)

def get_symbols(file):
    syms = {}
    rargs = "readelf -W -s %s %s" % (sym_args, file)
    p0 = Popen((a for a in rargs.split(' ') if a.strip() != ''), stdout=PIPE)
    p1 = Popen(["c++filt"], stdin=p0.stdout, stdout=PIPE,
            universal_newlines=True)
    lines = p1.communicate()[0]
    for l in lines.split('\n'):
        l = l.strip()
        if not len(l) or not l[0].isdigit(): continue
        larr = l.split()
        if len(larr) != 8: continue
        num, value, size, typ, bind, vis, ndx, name = larr
        if typ == 'SECTION' or typ == 'FILE': continue
        # I don't think we have many aliases in gcc, re-instate the addr
        # lut otherwise.
        if vis != 'DEFAULT': continue
        #value = int(value, 16)
        #size = int(size, 16) if size.startswith('0x') else int(size)
        defined = ndx != 'UND'
        globl = bind == 'GLOBAL'
        # c++ RID_FUNCTION_NAME dance. FORNOW: Handled as local use
        # Is that correct?
        if name.endswith('::__FUNCTION__') and typ == 'OBJECT':
            name = name[0:(len(name) - len('::__FUNCTION__'))]
            if defined: defined = False
        if defined and not globl: continue
        syms.setdefault(name, {})
        syms[name][['use','def'][defined]] = True
        syms[name][['local','global'][globl]] = True
    # Note: we could filter out e.g. debug_* symbols by looking for
    # value in the debug_macro sections.
    if p1.returncode != 0:
        print("Warning: Reading file '%s' exited with %r|%r"
            % (file, p0.returncode, p1.returncode))
    p0.kill()
    return syms

(oprog, nprog) = ({}, {})

def walker(paths):
    def ar_x(archive):
        dbg("Archive %s" % path)
        f = os.path.abspath(archive)
        f = os.path.splitdrive(f)[1]
        d = tmpd + os.path.sep + f
        d = os.path.normpath(d)
        owd = os.getcwd()
        try:
            os.makedirs(d)
            os.chdir(d)
            p0 = Popen(["ar", "x", "%s" % os.path.join(owd, archive)],
                    stderr=PIPE, universal_newlines=True)
            p0.communicate()
            if p0.returncode > 0: d = None # assume thin archive
        except:
            dbg("ar x: Error: %s: %s" % (archive, sys.exc_info()[0]))
            os.chdir(owd)
            raise
        os.chdir(owd)
        if d: dbg("Extracted to %s" % (d))
        return (archive, d)

    def ar_t(archive):
        dbg("Thin archive, using existing files:")
        try:
            p0 = Popen(["ar", "t", "%s" % archive], stdout=PIPE,
                    universal_newlines=True)
            ret = p0.communicate()[0]
            return ret.split('\n')
        except:
            dbg("ar t: Error: %s: %s" % (archive, sys.exc_info()[0]))
            raise

    prog = {}
    for path in paths:
        if os.path.isdir(path):
            for r, dirs, files in os.walk(path):
                if files: dbg("Files %s" % ", ".join(files))
                if dirs: dbg("Dirs  %s" % ", ".join(dirs))
                prog.update(walker([os.path.join(r, f) for f in files]))
                prog.update(walker([os.path.join(r, d) for d in dirs]))
        else:
            if path.endswith('.a'):
                if ar_x(path)[1] is not None: continue # extract worked
                prog.update(walker(ar_t(path)))
            if not path.endswith('.o'): continue
            dbg("Reading symbols from %s" % (path))
            prog[os.path.normpath(path)] = get_symbols(path)
    return prog

def resolve(prog):
    x = prog.keys()
    use = set()
    # for each unique pair of different files
    for (f, g) in ((f,g) for f in x for g in x if f != g):
        refs = set()
        # for each defined symbol
        for s in (s for s in prog[f] if prog[f][s].get('def') and s in prog[g]):
            if prog[g][s].get('use'):
                refs.add(s)
        for s in refs:
            # Prune externally referenced symbols as speed optimization only
            for i in (i for i in x if s in prog[i]): del prog[i][s]
        use |= refs
    return use

try:
    oprog = walker(odir)
    if tmpd is not None:
        oprog.update(walker([tmpd]))
    oused = resolve(oprog)
finally:
    try:
        p0 = Popen(["rm", "-r", "-f", "%s" % (tmpd)], stderr=PIPE, stdout=PIPE)
        p0.communicate()
        if p0.returncode != 0: raise "rm '%s' didn't work out" % (tmpd)
    except:
        from shutil import rmtree
        rmtree(tmpd, ignore_errors=True)

for (i,s) in ((i,s) for i in oprog.keys() for s in oprog[i] if oprog[i][s]):
    if oprog[i][s].get('def') and not oprog[i][s].get('use'):
        print("%s: Symbol '%s' declared extern but never referenced externally"
            % (i,s))


