#!/usr/bin/env python3
# Copyright 2023 Collabora Ltd.
# SPDX-License-Identifier: BSD-3-Clause

import os
import re
import subprocess
import sys
from pathlib import Path
from typing import (Dict, Set)


def main() -> None:
    needed: Dict[int, Set[str]] = {}
    dlopened: Dict[int, Set[str]] = {}
    LIB = re.compile(r'^lib.*?\.so(?:\..*?)$')

    for arg in sys.argv[1:]:
        for (dirpath, dirnames, filenames) in os.walk(arg):
            for f in filenames:
                path = Path(dirpath) / f

                if path.is_symlink() or not path.is_file():
                    continue

                with open(path, 'rb') as binary_reader:
                    blob = binary_reader.read(5)

                    if blob == b'\x7FELF\x01':
                        bitness = 32
                    elif blob == b'\x7FELF\x02':
                        bitness = 64
                    else:
                        continue

                completed = subprocess.run(
                    ['objdump', '-T', '-x', '--', path],
                    stdout=subprocess.PIPE,
                )

                for line in completed.stdout.splitlines():
                    if b'NEEDED' in line:
                        soname_bytes = line.split(b'NEEDED', 1)[1].strip()
                        soname = soname_bytes.decode('utf-8')
                        needed.setdefault(bitness, set()).add(soname)

                completed = subprocess.run(
                    ['strings', '--', path],
                    stdout=subprocess.PIPE,
                )

                for line in completed.stdout.splitlines():
                    if line.startswith(b'lib') and b'.so' in line:
                        text = line.strip().decode('utf-8', 'replace')
                        if LIB.match(text):
                            dlopened.setdefault(bitness, set()).add(text)

    for bitness in sorted(needed.keys()):
        for soname in sorted(needed[bitness]):
            print('{}\t{}'.format(bitness, soname))

    for bitness in sorted(dlopened.keys()):
        for soname in sorted(dlopened[bitness]):
            if soname not in needed[bitness]:
                print('{}?\t{}'.format(bitness, soname))


if __name__ == '__main__':
    main()
