"""Read dynamic symbols from a 32-bit little-endian ARM ELF. Companion to elfdeps.py. elfdeps answers "which libraries does this need"; this answers "which symbols does it need from them, and which does a library provide". That is the difference between assuming a library substitution is safe and checking it. The netBook Pro rootfs carries its own OpenEmbedded build of several libraries that Debian packages also ship -- libgcrypt, libgnutls, libgnomeprint and friends. Where both exist the device's copy is kept, since other installed programs already link against it, but only after confirming it still defines everything the incoming binaries reference. """ import struct import sys SHT_DYNSYM = 11 STT_FUNC, STT_OBJECT = 2, 1 SHN_UNDEF = 0 STB_WEAK = 2 def _read(path): try: d = open(path, "rb").read() except OSError: return None if d[:4] != b"\x7fELF" or d[4] != 1: # 32-bit only return None return d def _sections(d): e_shoff, = struct.unpack_from(" len(d): break st_name, st_value, st_size, st_info, st_other, st_shndx = \ struct.unpack_from("= sbase + slen: continue end = d.find(b"\x00", p) nm = d[p:end].decode("ascii", "replace") # strip the @VERSION suffix; the device's libraries are mostly # unversioned and comparing bare names is what matters here nm = nm.split("@", 1)[0] if st_shndx == SHN_UNDEF: if st_info >> 4 != STB_WEAK: undefined.add(nm) else: defined.add(nm) return defined, undefined if __name__ == "__main__": for p in sys.argv[1:]: dfn, und = symbols(p) print(f"{p}: {len(dfn)} defined, {len(und)} undefined")