blob: 677b303e84f30258e97ec37b4de6dbf46e855e09 [file] [log] [blame]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2024 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import json
import subprocess
import sys
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--ignore-unresolved-symbol",
action="append",
help="Expected undefined symbol name (may be repeated)",
default=[],
)
parser.add_argument(
"--ignore-all-unresolved-symbols",
action="store_true",
help="Allow all undefined symbol names",
default=False,
)
parser.add_argument(
"--init-array",
action="store_true",
help="Allow SHT_INIT_ARRAY sections",
default=False,
)
parser.add_argument(
"--fini-array",
action="store_true",
help="Allow SHT_FINI_ARRAY sections",
default=False,
)
parser.add_argument(
"--depfile",
type=argparse.FileType("w"),
required=True,
)
parser.add_argument(
"--stamp",
type=argparse.FileType("w"),
help="Stamp file written on success",
required=True,
)
parser.add_argument(
"--rspfile",
type=argparse.FileType("r"),
help="Response file listing name of ET_REL file to check",
required=True,
)
parser.add_argument("readelf", help="llvm-readelf binary", nargs=1)
args = parser.parse_args()
[file] = [line.strip() for line in args.rspfile.readlines()]
args.rspfile.close()
args.depfile.write(f"{args.stamp.name}: {file}\n")
args.depfile.close()
data = json.loads(
subprocess.check_output(
[
args.readelf[0],
"--elf-output-style=JSON",
"--sections",
"--symbols",
file,
]
)
)
sections = [entry["Section"] for entry in data[0]["Sections"]]
symbols = [entry["Symbol"] for entry in data[0]["Symbols"]]
# The section with index 0 is always the null section header, but
# llvm-readelf includes it just like any other.
assert sections[0]["Name"]["Value"] == 0
assert sections[0]["Type"]["Value"] == 0
sections = sections[1:]
init_sections = set(
[
section["Name"]["Name"]
for section in sections
if section["Type"]["Name"] == "SHT_INIT_ARRAY"
]
)
fini_sections = set(
[
section["Name"]["Name"]
for section in sections
if section["Type"]["Name"] == "SHT_FINI_ARRAY"
]
)
# The symbol with index 0 is always the null symbol, but llvm-readelf
# includes it just like any other.
assert symbols[0]["Name"]["Value"] == 0
assert symbols[0]["Section"]["Value"] == 0
symbols = symbols[1:]
ok = True
if not args.ignore_all_unresolved_symbols:
allowed_symbols = set(args.ignore_unresolved_symbol)
undefined_symbols = set(
[
symbol["Name"]["Name"]
for symbol in symbols
if symbol["Section"]["Value"] == 0
]
)
if not undefined_symbols <= allowed_symbols:
ok = False
sys.stderr.write(f"*** {file} FAILED undefined symbol check ***\n")
for extra in sorted(undefined_symbols - allowed_symbols):
sys.stderr.write(f"*** Unexpected reference: {extra}\n")
sys.stderr.write(
f"*** Find references with: llvm-objdump -drl {file}\n"
)
if init_sections and not args.init_array:
ok = False
sys.stderr.write(f"*** {file} FAILED .init_array check ***\n")
for name in sorted(init_sections):
sys.stderr.write(f"*** Unexpected SHT_INIT_ARRAY section {name}\n")
if fini_sections and not args.fini_array:
ok = False
sys.stderr.write(f"*** {file} FAILED .fini_array check ***\n")
for name in sorted(fini_sections):
sys.stderr.write(f"*** Unexpected SHT_FINI_ARRAY section {name}\n")
if not ok:
return 1
args.stamp.write("OK\n")
return 0
if __name__ == "__main__":
sys.exit(main())