
#!/usr/bin/python
import json
import re
import subprocess
import sys

def count_ctors(filename):
    proc = subprocess.Popen(
        ['readelf', '-W', '-S', filename], stdout=subprocess.PIPE)

    # Some versions of ld produce both .init_array and .ctors.  So we have
    # to check for both.
    n_init_array_ctors = 0
    have_init_array = False
    n_ctors_ctors = 0
    have_ctors = False

    for line in proc.stdout:
        f = line.split()
        if len(f) != 11:
            continue
        # Don't try to int()-parse the header line for the section summaries.
        if not re.match("\\[\\d+\\]", f[0]):
            continue
        section_name, contents, size, align = f[1], f[2], int(f[5], 16), int(f[10])
        if section_name == ".ctors" and contents == "PROGBITS":
            have_ctors = True
            # Subtract 2 for the uintptr_t(-1) header and the null terminator.
            n_ctors_ctors = size / align - 2
        if section_name == ".init_array" and contents == "INIT_ARRAY":
            have_init_array = True
            n_init_array_ctors = size / align

    if have_init_array:
        # Even if we have .ctors, we shouldn't have any constructors in .ctors.
        # Complain if .ctors does not look how we expect it to.
        if have_ctors and n_ctors_ctors != 0:
            print >>sys.stderr, "Unexpected .ctors contents for", filename
            sys.exit(1)
        return n_init_array_ctors
    if have_ctors:
        return n_ctors_ctors

    # We didn't find anything; somebody switched initialization mechanisms on
    # us, or the binary is completely busted.  Complain either way.
    print >>sys.stderr, "Couldn't find .init_array or .ctors in", filename
    sys.exit(1)

if __name__ == '__main__':
    for f in sys.argv[1:]:
        perfherder_data = {
            "framework": {"name": "build_metrics"},
            "suites": [{
                "name": "compiler_metrics",
                "subtests": [{
                    "name": "num_constructors",
                    "value": count_ctors(f),
                    "alertThreshold": 0.25
                }]}
            ]
        }
        print "PERFHERDER_DATA: %s" % json.dumps(perfherder_data)

