#!/usr/bin/bash

searchdir=$1

if [ -z "$searchdir" ]; then
    searchdir=$RPM_BUILD_ROOT
fi

# Ignore the .dwz directory, because it contains compressed debuginfo that
# do not contain .comment section and all the uncomppressed debuginfo is
# already being searched.
for f in `find "$searchdir" -iname .dwz -prune -o -type f -print`; do
    if ! file -b $f | grep -q '^ELF'; then
        # Not an ELF file
        continue
    fi

    echo "--- COMPILER CHECK: $f"

    # Special cases
    # bpf programs do not have a .comment section, so if there is no debuginfo,
    # then the rest of the checks in this files won't find anything.  We can
    # check for the llvm-specific LLVM_ADDRSIG setion type to verify that bpf
    # was used to compile the object file.
    if llvm-readelf -S $f | grep LLVM_ADDRSIG; then
        echo "Ignoring file compiled with BPF $f"
        continue
    fi

    # libpython3.so is a shared object that does not contain any object files,
    # so this script is unable to detect if it was built with clang.
    if basename $f | grep '^libpython3.so'; then
        echo "Ignoring special case $f"
        continue
    fi

    # dyninst has some test cases that are meant for specific compilers.  It
    # goes through a list of compilers and for each one installed on the
    # system, it will build tests with it.  There is really no way to build
    # these tests with clang since they are specific gcc tests.
    if echo "$f" | grep 'usr/lib64/dyninst/testsuite/.\+g[+c][+c].\+$'; then
        echo "Ignoring special case $f"
        continue
    fi

    # QEMU ships a bunch of binary blobs it installs into /usr/share/,
    # which are all built with some version of GCC
    if echo "$f" | grep "usr/share/qemu/"; then
        case "$(basename $f)" in
          "opensbi-riscv32-generic-fw_dynamic.elf" | \
          "opensbi-riscv64-generic-fw_dynamic.elf" | \
          "s390-netboot.img" | "s390-ccw.img" | \
          "palcode-clipper" | \
          "hppa-firmware.img" | \
          "u-boot.e500")
            echo "Ignoring QEMU special case $f"
            continue
            ;;
        esac
    fi

    # Check for a .debug_info section
    llvm-readelf -S $f | grep -q '.debug_info[[:space:]]'
    if [ $? -ne 0 ]; then
        # No .debug_info section found.  This binary may have been stripped.
        # check to see if we can find any debuginfo.
        debug_basename=`basename $f`

        # cockpit generates debuginfo files on its own, so it does not have the standard file
        # names like other packages, so we need to make sure we search for it.
        debug_info=`find $searchdir -iname $debug_basename-$RPM_PACKAGE_VERSION-$RPM_PACKAGE_RELEASE.$RPM_ARCH.debug -o -iname $debug_basename.debug`
        if [ $? -eq 0 -a -n "$debug_info" ]; then
          f=$debug_info
        fi
    fi

    # Skip binaries from languages besides C/C++.
    # We want to be really conservative here.
    lang_attributes=$(llvm-dwarfdump --recurse-depth=0 $f | grep DW_AT_language)
    num_lang_attributes=`echo "$lang_attributes" | wc -l`

    if [ $num_lang_attributes -gt 0 ]; then
      unique_langs=$(echo "$lang_attributes" | sort | uniq)
      num_unique_langs=$(echo "$unique_langs" | wc -l)
      # 0xaf33 is Guile
      skip_langs=("DW_LANG_Fortran95" "DW_LANG_Rust" "DW_AT_language[[:space:]]\+(0xaf33)"
                  "DW_LANG_Mips_Assembler")

      # For every used language of the file, check if the language is in
      # $skip_langs. Only if all of the used languages are in $skip_langs do we
      # want to skip the executable
      num_skipped_langs=0
      for skip_lang in ${skip_langs[@]}; do
        if echo "'$unique_langs'" | grep "$skip_lang" > /dev/null 2>&1; then
          num_skipped_langs=$((num_skipped_langs+1))
        fi
      done

      if [ "$num_unique_langs" -eq "$num_skipped_langs" ]; then
        echo "Skipping $f. Used languages:"
        echo "$unique_langs"
        continue; # Skip this executable
      fi
    fi

    # Check debuginfo to see if a GNU compiler was used
    dwarfdump -P $f | grep '[0-9]\+: GNU' | \
    while read LINE; do
        echo $LINE | grep '\-fbuilding-libgcc'
        # Ignore compile units that are part of libgcc:
        if [ $? -ne 0 ]; then
            echo "$f was built with gcc"
            exit 1
        fi
    done

    # If .comment section exists check to make sure it references clang.
    if llvm-readelf -S $f | grep -q .comment; then
        if ! llvm-readelf --string-dump .comment $f | grep clang; then
            echo "$f was not built with clang"
            exit 1
        fi
    else
        # There is no comment section, so check debug info.
        # gnutls needs this.
        if ! dwarfdump -P $f | grep '[0-9]\+: clang'; then
            echo "$f was not built with clang"
            exit 1
        fi
    fi
    echo "$f built with clang"
done
