Skip to content

Instantly share code, notes, and snippets.

@jld
Last active December 22, 2015 12:18
Show Gist options
  • Select an option

  • Save jld/6471447 to your computer and use it in GitHub Desktop.

Select an option

Save jld/6471447 to your computer and use it in GitHub Desktop.
import os, sys, struct, subprocess
READELF = os.getenv("READELF") or "readelf"
def main(argv):
filename = argv[1]
phdrs = subprocess.Popen([READELF, "-l", filename],
stdout = subprocess.PIPE, stderr = sys.stderr)
offset = None
fsize = None
for line in phdrs.stdout:
fields = line.split()
if len(fields) > 0 and fields[0] == "EXIDX":
offset = int(fields[1], 16)
fsize = int(fields[4], 16)
phdrs.wait()
if phdrs.returncode != 0:
raise Exception("readelf failed")
if not offset:
raise Exception("No EXIDX phdr found")
progs = {}
refs = {}
print ("%u exidx entries" % (fsize / 8))
with open(filename, "rb") as fh:
fh.seek(offset)
for n in xrange(0, fsize / 8):
(pcoff, exidx) = struct.unpack("<LL", fh.read(8))
if exidx == 1:
progs[None] = progs.get(None, 0) + 1
elif exidx & 0x80000000:
prog = struct.pack("<L", exidx)
progs[prog] = progs.get(prog, 0) + 1
else:
rel31 = exidx | -(exidx & 0x40000000)
ref = rel31 + offset + 8 * n + 4
refs[ref] = refs.get(ref, 0) + 1
print ("%u unwinders stored in exidx + %u extab refs" % (len(progs), len(refs)))
for ref in refs:
fh.seek(ref)
buf = fh.read(4)
(hdr,) = struct.unpack("<L", buf)
if hdr >> 24 == 0x81:
words = (hdr >> 16) & 0xff
elif hdr >> 24 == 0x82:
words = hdr & 0xffffff
else:
raise Exception("Unhandled personality %x offset %d" % (hdr, ref))
buf += fh.read(4 * words)
progs[buf] = progs.get(buf, 0) + refs[ref]
print ("%u total unwinders" % (len(progs)))
if __name__ == '__main__':
main(sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment