mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
272 lines
8.3 KiB
Python
Executable File
272 lines
8.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from binascii import hexlify
|
|
from ctypes.util import find_library
|
|
try:
|
|
from shutil import which
|
|
except ImportError:
|
|
from backports.shutil_which import which
|
|
|
|
from revng_translate import register_translate, run_translate
|
|
from revng_support import build_command_with_loads, set_verbose, get_command, run
|
|
|
|
search_prefixes = []
|
|
real_argv0 = os.environ.get("REAL_ARGV0", sys.argv[0])
|
|
|
|
def split_dash_dash(args):
|
|
if not args:
|
|
return [], []
|
|
|
|
extra_args = []
|
|
while (len(args) != 0) and (args[0] != "--"):
|
|
extra_args.append(args[0])
|
|
del args[0]
|
|
|
|
# Drop the delimiter
|
|
if len(args) != 0:
|
|
del args[0]
|
|
|
|
return list(extra_args), args
|
|
|
|
|
|
def find_file(name, paths):
|
|
for path in paths:
|
|
path = os.path.join(path, name)
|
|
if os.path.isfile(path):
|
|
return path
|
|
|
|
log_error("Can't find the following file: {}".format(name))
|
|
assert False
|
|
|
|
|
|
def get_stderr(args):
|
|
with subprocess.Popen(args, stderr=subprocess.PIPE) as process:
|
|
return process.stderr.read()
|
|
|
|
|
|
def run_cc(args, search_path, search_prefixes, command_prefix):
|
|
# Collect translate options
|
|
translated_args = []
|
|
if "--" in args:
|
|
translate_args, args = split_dash_dash(args)
|
|
|
|
if (not args) or ("--help" in args):
|
|
log_error(f"Usage: {real_argv0} cc [[translate-options] --] compiler "
|
|
+ "[compiler-options]")
|
|
return -1
|
|
|
|
res = subprocess.call(args)
|
|
if res != 0:
|
|
return res
|
|
|
|
# Are we linking?
|
|
if not ("-c" in args):
|
|
assert "-o" in args
|
|
|
|
# Identify the path of the final program
|
|
output = os.path.abspath(args[args.index("-o") + 1])
|
|
|
|
original = output + ".original"
|
|
translated = original + ".translated"
|
|
os.rename(output, original)
|
|
|
|
result = run_translate(translate_args + [original],
|
|
search_path,
|
|
search_prefixes,
|
|
command_prefix)
|
|
if result != 0:
|
|
return result
|
|
|
|
os.rename(translated, output)
|
|
|
|
return res
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="The rev.ng driver.")
|
|
parser.add_argument("--version",
|
|
action="store_true",
|
|
help="Display version information.")
|
|
parser.add_argument("--verbose",
|
|
action="store_true",
|
|
help="Log all executed commands.")
|
|
parser.add_argument("--perf",
|
|
action="store_true",
|
|
help="Run programs under perf (for use with hotspot).")
|
|
parser.add_argument("--heaptrack",
|
|
action="store_true",
|
|
help="Run programs under heaptrack.")
|
|
parser.add_argument("--gdb",
|
|
action="store_true",
|
|
help="Run programs under gdb.")
|
|
parser.add_argument("--lldb",
|
|
action="store_true",
|
|
help="Run programs under lldb.")
|
|
parser.add_argument("--valgrind",
|
|
action="store_true",
|
|
help="Run programs under valgrind.")
|
|
parser.add_argument("--callgrind",
|
|
action="store_true",
|
|
help="Run programs under callgrind.")
|
|
parser.add_argument("--prefix",
|
|
action="append",
|
|
metavar="PREFIX",
|
|
help="Additional search prefix.")
|
|
|
|
# Get script_path
|
|
global script_path
|
|
script_path = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
# Create a custom PATH variable to find programs
|
|
search_path = os.environ["PATH"]
|
|
if search_path:
|
|
search_path = "{}:{}".format(script_path, search_path)
|
|
search_path = "{}:{}".format(os.path.dirname(script_path), search_path)
|
|
else:
|
|
search_path = script_path
|
|
|
|
subparsers = parser.add_subparsers(dest="command_name",
|
|
help='sub-commands help')
|
|
|
|
register_translate(subparsers)
|
|
|
|
subparsers.add_parser("cc",
|
|
help="compile, link and translate transparently",
|
|
add_help=False)
|
|
subparsers.add_parser("opt",
|
|
help="LLVM's opt with rev.ng passes",
|
|
add_help=False)
|
|
subparsers.add_parser("model",
|
|
help="Model commands",
|
|
add_help=False)
|
|
|
|
programs = set()
|
|
prefix = "revng-"
|
|
for path in search_path.split(":"):
|
|
if os.path.isdir(path):
|
|
for program in os.listdir(path):
|
|
if program.startswith(prefix) and which(program, path=search_path):
|
|
name = program[len(prefix):]
|
|
subparsers.add_parser(name,
|
|
help=f"see {name} --help",
|
|
add_help=False)
|
|
global revng_parser
|
|
revng_parser = parser
|
|
|
|
# Strip away arguments -- so we can forward them to revng-lift
|
|
base_args, post_dash_dash = split_dash_dash(sys.argv[1:])
|
|
|
|
args, unknown_args = parser.parse_known_args(base_args)
|
|
|
|
global search_prefixes
|
|
search_prefixes = ((args.prefix or [])
|
|
+ [os.path.join(script_path, "..")])
|
|
|
|
if args.verbose:
|
|
set_verbose()
|
|
|
|
command_prefix = []
|
|
|
|
assert (args.gdb + args.lldb + args.valgrind + args.callgrind) <= 1
|
|
|
|
if args.gdb:
|
|
command_prefix += ["gdb", "-q", "--args"]
|
|
|
|
if args.lldb:
|
|
command_prefix += ["lldb", "--"]
|
|
|
|
if args.valgrind:
|
|
command_prefix += ["valgrind"]
|
|
|
|
if args.callgrind:
|
|
command_prefix += ["valgrind", "--tool=callgrind"]
|
|
|
|
if args.perf:
|
|
command_prefix += ["perf",
|
|
"record",
|
|
"--call-graph", "dwarf",
|
|
"--output=perf.data"]
|
|
|
|
if args.heaptrack:
|
|
command_prefix += ["heaptrack"]
|
|
|
|
if args.version:
|
|
sys.stdout.write("rev.ng version @VERSION@\n")
|
|
return 0
|
|
|
|
return run_command(args,
|
|
unknown_args,
|
|
post_dash_dash,
|
|
search_path,
|
|
search_prefixes,
|
|
command_prefix)
|
|
|
|
|
|
def run_subcommand(command, all_args, search_path, command_prefix):
|
|
executable = "revng-" + command
|
|
if not which(executable, path=search_path):
|
|
log_error("Can't find the following command: {}".format(executable))
|
|
return 1
|
|
|
|
in_path = get_command(executable, search_path)
|
|
if in_path:
|
|
arguments = [os.path.abspath(in_path)] + all_args
|
|
run(arguments, command_prefix)
|
|
else:
|
|
log_error("\"revng-{}\" is not a valid command".format(command))
|
|
return 1
|
|
|
|
|
|
def run_command(args,
|
|
unknown_args,
|
|
post_dash_dash,
|
|
search_path,
|
|
search_prefixes,
|
|
command_prefix):
|
|
command = args.command_name
|
|
if not command:
|
|
log_error("No command specified")
|
|
return 1
|
|
|
|
all_args = list(unknown_args)
|
|
if post_dash_dash:
|
|
all_args += ["--"] + post_dash_dash
|
|
|
|
# First consider the hardcoded commands
|
|
if command == "opt":
|
|
opt_command = build_command_with_loads("opt",
|
|
all_args + ["-serialize-model"],
|
|
search_path,
|
|
search_prefixes)
|
|
run(opt_command, command_prefix)
|
|
elif command == "cc":
|
|
return run_cc(all_args, search_path, search_prefixes, command_prefix)
|
|
elif command == "translate":
|
|
return run_translate(args, post_dash_dash, search_path, search_prefixes, command_prefix)
|
|
elif command == "model":
|
|
if not all_args:
|
|
log_error("No subcommand specified")
|
|
return 1
|
|
command += "-" + all_args[0]
|
|
del all_args[0]
|
|
|
|
if command == "model-import":
|
|
if not all_args:
|
|
log_error("No subcommand specified")
|
|
return 1
|
|
command += "-" + all_args[0]
|
|
del all_args[0]
|
|
|
|
return run_subcommand(command, all_args, search_path, command_prefix)
|
|
else:
|
|
return run_subcommand(command, all_args, search_path, command_prefix)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|