#!/bin/bash

DEBUGDIR="/usr/lib/debug"

extract_debug_line()
{
    local binary=$1
    local dest=$2
    local original_debuginfo="$DEBUGDIR$binary.debug"

    dd if=$original_debuginfo of=$dest bs=1 `eu-readelf -S $original_debuginfo | grep "\.debug_line" | awk --non-decimal-data '{print "count=" (("0x"$6)+0) " skip="(("0x"$5)+0)}'`  &> /dev/null
}


minimize_symbols()
{
    local binary=$1
    local dest=$2
    local original_debuginfo="$DEBUGDIR$binary.debug"

    local dynsyms=`mktemp`
    local funcsyms=`mktemp`
    local keep_symbols=`mktemp`
    nm -D "$binary" --format=posix --defined-only | awk '{ print $1 }' | sort > $dynsyms
    nm "$original_debuginfo" --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t") print $1 }' | sort > $funcsyms
    comm -13 $dynsyms $funcsyms > $keep_symbols
    objcopy -S --remove-section .gdb_index --remove-section .comment --keep-symbols=$keep_symbols $original_debuginfo $dest &> /dev/null
    rm -f $dynsyms $funcsyms $keep_symbols
}

print_percent()
{
    MINI_SIZE_PERC=`echo "scale=2; 100 * $2 / $1" | bc`
    MINI_XZ_SIZE_PERC=`echo "scale=2; 100 * $3 / $1" | bc`
    MINI_LINE_SIZE_PERC=`echo "scale=2; 100 * $4 / $1" | bc`
    MINI_LINE_XZ_SIZE_PERC=`echo "scale=2; 100 * $5 / $1" | bc`
    echo "|| $MINI_SIZE_PERC% || $MINI_XZ_SIZE_PERC% || $MINI_LINE_SIZE_PERC% || $MINI_LINE_XZ_SIZE_PERC%"
}

print_stats_for_binary()
{
    local binary=$1
    
    local minified=`mktemp`
    local debuglines=`mktemp`

    BIN_SIZE=`stat -L --printf="%s" $binary`
    minimize_symbols $1 $minified
    MINI_SIZE=`stat -L --printf="%s" $minified`

    xz --keep $minified
    MINI_XZ_SIZE=`stat -L --printf="%s" ${minified}.xz`
    rm $minified.xz

    extract_debug_line $1 $debuglines
    objcopy --add-section .debug_line=$debuglines $minified &> /dev/null

    MINI_LINE_SIZE=`stat -L --printf="%s" $minified`
    xz --keep $minified
    MINI_LINE_XZ_SIZE=`stat -L --printf="%s" ${minified}.xz`

    rm $minified.xz $minified $debuglines
    
    echo "$binary: $BIN_SIZE $MINI_SIZE $MINI_XZ_SIZE $MINI_LINE_SIZE $MINI_LINE_XZ_SIZE"
    print_percent $BIN_SIZE $MINI_SIZE $MINI_XZ_SIZE $MINI_LINE_SIZE $MINI_LINE_XZ_SIZE

    TOTAL_BIN_SIZE=`echo "$TOTAL_BIN_SIZE + $BIN_SIZE" | bc`
    TOTAL_MINI_SIZE=`echo "$TOTAL_MINI_SIZE + $MINI_SIZE" | bc`
    TOTAL_MINI_XZ_SIZE=`echo "$TOTAL_MINI_XZ_SIZE + $MINI_XZ_SIZE" | bc`
    TOTAL_MINI_LINE_SIZE=`echo "$TOTAL_MINI_LINE_SIZE + $MINI_LINE_SIZE" | bc`
    TOTAL_MINI_LINE_XZ_SIZE=`echo "$TOTAL_MINI_LINE_XZ_SIZE + $MINI_LINE_XZ_SIZE" | bc`

}

print_stats_for_package()
{
    TOTAL_BIN_SIZE=0
    TOTAL_MINI_SIZE=0
    TOTAL_MINI_XZ_SIZE=0
    TOTAL_MINI_LINE_SIZE=0
    TOTAL_MINI_LINE_XZ_SIZE=0

    for i in `rpm -ql $1 | file -N -f - | sed -n -e 's/^\(.*\):[ ]*.*ELF.*/\1/p'`; do
	if test -e "$DEBUGDIR$i.debug"; then
	    print_stats_for_binary $i &> /dev/null
	fi
    done

    echo -n "| $1 || " `echo "$TOTAL_BIN_SIZE / 1024" | bc` "Kb"
    print_percent $TOTAL_BIN_SIZE $TOTAL_MINI_SIZE $TOTAL_MINI_XZ_SIZE $TOTAL_MINI_LINE_SIZE $TOTAL_MINI_LINE_XZ_SIZE

    TOTAL_TOTAL_BIN_SIZE=`echo "$TOTAL_TOTAL_BIN_SIZE + $TOTAL_BIN_SIZE" | bc`
    TOTAL_TOTAL_MINI_SIZE=`echo "$TOTAL_TOTAL_MINI_SIZE + $TOTAL_MINI_SIZE" | bc`
    TOTAL_TOTAL_MINI_XZ_SIZE=`echo "$TOTAL_TOTAL_MINI_XZ_SIZE + $TOTAL_MINI_XZ_SIZE" | bc`
    TOTAL_TOTAL_MINI_LINE_SIZE=`echo "$TOTAL_TOTAL_MINI_LINE_SIZE + $TOTAL_MINI_LINE_SIZE" | bc`
    TOTAL_TOTAL_MINI_LINE_XZ_SIZE=`echo "$TOTAL_TOTAL_MINI_LINE_XZ_SIZE + $TOTAL_MINI_LINE_XZ_SIZE" | bc`
}

TOTAL_TOTAL_BIN_SIZE=0
TOTAL_TOTAL_MINI_SIZE=0
TOTAL_TOTAL_MINI_XZ_SIZE=0
TOTAL_TOTAL_MINI_LINE_SIZE=0
TOTAL_TOTAL_MINI_LINE_XZ_SIZE=0

echo "{|"
echo "! Package !! Size of executables !! symbols !! xz symbols !! symbols+lines !! xz symbols+lines"
echo "|-"

for package in $*; do
    print_stats_for_package $package
echo "|-"
done

echo -n "| Total || " `echo "$TOTAL_TOTAL_BIN_SIZE / 1024" | bc` "Kb"
print_percent $TOTAL_TOTAL_BIN_SIZE $TOTAL_TOTAL_MINI_SIZE $TOTAL_TOTAL_MINI_XZ_SIZE $TOTAL_TOTAL_MINI_LINE_SIZE $TOTAL_TOTAL_MINI_LINE_XZ_SIZE

echo "|}"
