Files
idapython-src/tools/patch_constants.py
2022-08-22 10:14:21 +02:00

158 lines
5.2 KiB
Python

"""
This script replaces the long sequence of calls like:
SWIG_Python_SetConstant(d, "s39_xg",SWIG_From_int(static_cast< int >(s39_xg)));
SWIG_Python_SetConstant(d, "s39_xgr",SWIG_From_int(static_cast< int >(s39_xgr)));
by a table of names+values and a loop calling the function.
This is necessitated by the huge slowdown in GCC when trying to optimize a huge list of such calls
in allins.cpp SWIG wrapper (~20 min).
"""
from __future__ import print_function
import re
from argparse import ArgumentParser
parser = ArgumentParser(description='Patch calling conventions for some functions, so it builds on windows')
parser.add_argument("-i", "--input", required=True)
parser.add_argument("-o", "--output", required=True)
parser.add_argument("-v", "--verbose", default=False, action="store_true")
args = parser.parse_args()
outlines = []
STAT_SEEKING = 1
STAT_ALMOST_THERE = 2
STAT_COLLECTING = 3
almost_there_re = re.compile(r"^\s+\*\s+Partial Init method.*")
start_collecting_re = re.compile(r"^#ifdef __cplusplus.*")
end_collecting_re = re.compile(r"^\s*/\* Initialize threading \*/")
# SWIG_Python_SetConstant(d, "BADADDR",SWIG_From_unsigned_SS_int(static_cast< unsigned int >(ea_t(-1))));
set_constant_re = re.compile(r"^\s*SWIG_Python_SetConstant\(\s*d\s*,([^,]*),(.*)\);$")
# Supported types we can simply expression for
# SWIG_From_int(static_cast< int >(0x00C0))
pyobj_expr_int = re.compile(r"SWIG_From_int\(static_cast<\s*int\s*>\((.*)\)\)")
# SWIG_From_unsigned_SS_int(static_cast< unsigned int >((1u << 16)))
pyobj_expr_uint = re.compile(r"SWIG_From_unsigned_SS_int\(static_cast<\s*unsigned\s+int\s*>\((.*)\)\)")
# SWIG_From_long(static_cast< long >(0x00002000L))
pyobj_expr_long = re.compile(r"SWIG_From_long\(static_cast<\s*long\s*>\((.*)\)\)")
# SWIG_From_unsigned_SS_long(static_cast< unsigned long >(0xF0000000LU))
pyobj_expr_ulong = re.compile(r"SWIG_From_unsigned_SS_long\(static_cast<\s*unsigned\s+long\s*>\((.*)\)\)")
# SWIG_FromCharPtr("\22")
pyobj_expr_str = re.compile(r"SWIG_FromCharPtr\((.*)\)")
status = STAT_SEEKING
class Foldable(object):
def __init__(self, re, enum, initializer, cast, replacement):
self.re = re
self.enum = enum
self.initializer = initializer
self.cast = cast
self.replacement = replacement
self.found_any = False
subexprs = {
"i" : Foldable(
pyobj_expr_int,
"cit_int",
"i",
"int",
"SWIG_From_int(static_cast< int >(ci.val))"),
}
def generate_constants(constants):
# now, generate the array & loop
outlines.append("""
/* 'SetConstant' replacement */
static const ida_local struct ci_t
{
const char *name;
int val;
} cis[%d] = {
""" % len(constants))
for c in constants:
name = c[0]
expr = c[1]
# Analyze expression. If it is one of the
# supported types, let's simplify the code.
for kind in ["i"]:
subexpr = subexprs[kind]
sematch = subexpr.re.search(expr)
if sematch:
citype = subexpr.enum
expr = sematch.group(1)
init = subexpr.initializer
cast = subexpr.cast
subexpr.found_any = True
break
outlines.append("\t{%s, static_cast< int >(%s)},\n" % (name, expr))
outlines.append("""
};
for ( size_t _cidx = 0; _cidx < qnumber(cis); ++_cidx )
{
const ci_t &ci = cis[_cidx];
PyObject *o = """)
subexpr = subexprs["i"]
outlines.append("""%s;""" % (subexpr.replacement))
outlines.append("""
SWIG_Python_SetConstant(d, ci.name, o);
}
""")
with open(args.input) as f:
constants = []
for line in f:
if status == STAT_SEEKING:
if almost_there_re.match(line):
status = STAT_ALMOST_THERE
if args.verbose:
print("Almost there at line: '%s'" % line)
outlines.append(line)
elif status == STAT_ALMOST_THERE:
if start_collecting_re.match(line):
status = STAT_COLLECTING
if args.verbose:
print("Starting to collect at line: '%s'" % line)
outlines.append("#ifdef __NT__\n")
outlines.append("#pragma warning(disable: 4883)\n")
outlines.append("#endif // __NT__\n")
outlines.append(line)
elif status == STAT_COLLECTING:
if end_collecting_re.match(line):
outlines.append(line)
if len(constants):
generate_constants(constants)
status = STAT_SEEKING
if args.verbose:
print("Done collecting at line: '%s'" % line)
else:
match = set_constant_re.search(line)
if match and pyobj_expr_int.search(match.group(2)):
tpl = (match.group(1), match.group(2))
constants.append(tpl)
if args.verbose:
print("Found 'SetConstant' expression: %s => %s" % tpl)
else:
outlines.append(line)
import tempfile
temp = tempfile.NamedTemporaryFile(mode="w", delete=False)
temp.write("".join(outlines))
temp.close()
import shutil
shutil.move(temp.name, args.output)