import argparse
import os
import sys
NAME_INDEX = 0
HEADER_INDEX = 1
COND_INDEX = 2
RETTYPE_INDEX = 3
PARM1_INDEX = 4
POINTER_SIGNATURE = ['...', '*', '_sa_handler_t', ',mbstate_t']
BLACK_LIST = ['sigqueue', 'pthread_create', 'pthread_detach',
'pthread_cancel', 'pthread_key_create', 'pthread_key_delete',
'pthread_getspecific', 'pthread_setspecific', 'mallinfo',
'crypt', 'crypt_r']
VA_ADDITIONAL_FUNCS = [
'asprintf', 'fprintf', 'fscanf', 'printf', 'snprintf', 'sprintf',
'sprintf', 'sscanf', 'sscanf', 'swprintf', 'syslog',
]
VA_LIST_FUNCS = [
'vasprintf', 'vfprintf', 'vprintf', 'vscanf', 'vsnprintf', 'vsprintf',
'vsscanf', 'vsyslog',
]
def is_strip_function(name):
for black in BLACK_LIST:
if black == name:
return True
return False
def is_va_additional_function(name):
for va in VA_ADDITIONAL_FUNCS:
if va == name:
return True
return False
def is_va_list_function(name):
for va in VA_LIST_FUNCS:
if va == name:
return True
return False
def generate_include(csv, out):
headers = []
for line in csv.readlines():
sline = line.strip()
if sline == '':
break
args = []
for arg in sline.split(","):
args.append(arg.strip().strip('\"'))
if is_strip_function(args[NAME_INDEX]):
continue
if len(args[HEADER_INDEX]) != 0 and args[HEADER_INDEX] not in headers:
headers.append(args[HEADER_INDEX])
headers.sort()
for header in headers:
out.write(f"#include <{header}>\n")
out.write("\n")
out.write("#include <wasm_export.h>\n")
out.write("\n")
csv.seek(0)
def generate_functions(csv, out, lib):
for line in csv.readlines():
sline = line.strip()
if sline == '':
break
args = []
for arg in sline.split("\","):
args.append(arg.strip().strip('\"'))
if is_strip_function(args[NAME_INDEX]):
continue
nodef = (len(args[COND_INDEX]) != 0)
if nodef:
out.write("#if " + args[COND_INDEX] + "\n\n")
out.write(f"#ifndef GLUE_FUNCTION_{args[NAME_INDEX]}\n")
out.write(f"#define GLUE_FUNCTION_{args[NAME_INDEX]}\n")
noreturn = args[RETTYPE_INDEX] == 'void' or \
args[RETTYPE_INDEX] == 'noreturn'
if noreturn:
out.write(f"void glue_{args[NAME_INDEX]}(wasm_exec_env_t env")
else:
out.write(f"uintptr_t glue_{args[NAME_INDEX]}(wasm_exec_env_t env")
if is_va_additional_function(args[NAME_INDEX]):
findex = len(args) - 2
vprefix = 'v'
elif is_va_list_function(args[NAME_INDEX]):
findex = len(args) - 2
else:
findex = 0
vprefix = ''
for index in range(PARM1_INDEX, len(args)):
if findex == index:
out.write(", uintptr_t format")
elif args[index] == '...':
out.write(", va_list ap")
break
elif args[index] == 'va_list' and findex != 0:
out.write(", va_list ap")
break
elif args[index] == 'void':
continue
else:
out.write(f", uintptr_t parm{index - PARM1_INDEX + 1}")
out.write(")\n{\n")
out.write(" wasm_module_inst_t module_inst = get_module_inst(env);\n")
out.write(" uintptr_t ret;\n")
is_addr = False
for index in range(PARM1_INDEX, len(args)):
if '*' in args[index]:
is_addr = True
continue
if 'va_list' in args[index] or '...' in args[index]:
is_addr = False
break
if is_addr:
out.write(" void *addr_app = addr_app_to_native((uintptr_t)NULL);\n")
for index in range(PARM1_INDEX, len(args)):
if '*' in args[index]:
out.write(f" if ((void *)parm{index - PARM1_INDEX + 1} == addr_app)\n")
out.write(f" parm{index - PARM1_INDEX + 1} = (uintptr_t)NULL;\n")
out.write("\n")
if findex != 0:
if 'scanf' in args[NAME_INDEX]:
out.write(" scanf_begin(module_inst, ap);\n")
else:
out.write(" va_list_string2native(env, format, ap);\n")
if noreturn:
noret = ''
else:
noret = 'return'
addrcov = ''
if '*' in args[RETTYPE_INDEX]:
addrcov = 'addr_native_to_app((uintptr_t)'
if noreturn:
out.write(f" {addrcov}{vprefix}{args[NAME_INDEX]}(")
else:
out.write(f" ret = {addrcov}{vprefix}{args[NAME_INDEX]}(")
for index in range(PARM1_INDEX, len(args)):
if index > PARM1_INDEX:
out.write(", ")
if args[index] == '...':
if index < len(args) - 1 and args[NAME_INDEX] == 'ioctl':
out.write(
f"(*(uintptr_t **)&ap != NULL && **(uintptr_t **)&ap != (uintptr_t)NULL) ? (uintptr_t)addr_app_to_native((uintptr_t)va_arg(ap, {args[index + 1]})) : (uintptr_t)NULL")
elif index < len(args) - 1:
out.write(
f"(*(uintptr_t **)&ap != NULL && **(uintptr_t **)&ap != (uintptr_t)NULL) ? (uintptr_t)va_arg(ap, {args[index + 1]}) : (uintptr_t)NULL")
else:
out.write("ap")
break
if args[index] == 'va_list' and findex != 0:
out.write("ap")
break
if args[index] == 'void':
continue
if '|' in args[index]:
args[index] = args[index].split("|")[1]
if findex == index:
out.write(f"({args[index]})format")
else:
out.write(f"({args[index]})parm{index - PARM1_INDEX + 1}")
if addrcov != '':
out.write(")")
out.write(");\n")
if findex != 0:
if 'scanf' in args[NAME_INDEX]:
out.write(" scanf_end(module_inst, ap);\n")
else:
out.write(" va_list_string2app(env, format, ap);\n")
if noreturn:
pass
else:
out.write(" return ret;\n")
out.write("}\n\n")
out.write(f"#endif /* GLUE_FUNCTION_{args[NAME_INDEX]} */\n")
if nodef:
out.write(f"#endif /* {args[COND_INDEX]} */\n\n")
csv.seek(0)
def generate_table(csv, out, lib):
out.write("#ifndef native_function\n")
out.write("#define native_function(func_name, signature) \\\n")
out.write(" { #func_name, glue_##func_name, signature, NULL }\n\n")
out.write("#endif\n")
lib.write("static void empty_stub(void) {}\n\n")
lib.write("#ifndef native_function\n")
lib.write("#define native_function(func_name, signature) \\\n")
lib.write(" { #func_name, empty_stub, signature, NULL }\n\n")
lib.write("#endif\n")
out.write(f"static NativeSymbol g_{os.path.splitext(os.path.basename(csv.name))[0]}_native_symbols[] =\n")
lib.write(f"static NativeSymbol g_{os.path.splitext(os.path.basename(csv.name))[0]}_native_symbols[] =\n")
out.write("{\n")
lib.write("{\n")
for line in csv.readlines():
sline = line.strip()
if sline == '':
break
args = []
for arg in sline.split("\","):
args.append(arg.strip().strip('\"'))
if is_strip_function(args[NAME_INDEX]):
continue
nodef = (len(args[COND_INDEX]) != 0)
if nodef:
out.write("#if " + args[COND_INDEX] + "\n")
out.write(f"#ifndef GLUE_ENTRY_{args[NAME_INDEX]}\n")
out.write(f"#define GLUE_ENTRY_{args[NAME_INDEX]}\n")
out.write(f" native_function({args[NAME_INDEX]},\"(")
lib.write(f" native_function({args[NAME_INDEX]},\"(")
noreturn = args[RETTYPE_INDEX] == 'void' or \
args[RETTYPE_INDEX] == 'noreturn'
signature = ''
for index in range(PARM1_INDEX, len(args)):
if '(*)' in args[index]:
signature += 'i'
elif 'float' in args[index]:
signature += 'f'
elif 'double' in args[index]:
signature += 'F'
elif 'long long' in args[index]:
signature += 'I'
elif 'char *' in args[index]:
signature += '$'
elif 'off_t' in args[index]:
signature += 'I'
elif 'uintptr_t' in args[index]:
signature += 'i'
elif 'va_list' in args[index]:
signature += '*'
else:
defval = True
for sig in POINTER_SIGNATURE:
if sig in args[index]:
signature += '*'
defval = False
break
if defval:
signature += 'i'
if '...' in args[index]:
break
out.write(signature)
lib.write(signature)
out.write(")")
lib.write(")")
retval = ''
if not noreturn:
if '*' in args[RETTYPE_INDEX]:
retval = 'i'
elif 'off_t' in args[RETTYPE_INDEX]:
retval = 'I'
elif 'time_t' in args[RETTYPE_INDEX]:
retval = 'I'
elif 'double' in args[RETTYPE_INDEX]:
retval = 'F'
elif 'float' in args[RETTYPE_INDEX]:
retval = 'f'
elif 'long long' in args[RETTYPE_INDEX]:
retval = 'I'
else:
retval = 'i'
out.write(retval)
lib.write(retval)
out.write("\"),\n")
lib.write("\"),\n")
out.write(f"#endif /* GLUE_ENTRY_{args[NAME_INDEX]} */\n")
if nodef:
out.write(f"#endif /* {args[COND_INDEX]} */\n\n")
out.write("};\n")
lib.write("};\n")
lib.write("\n")
lib.write("uint32_t get_native_lib(char **p_module_name, NativeSymbol **p_base_lib_apis) {\n")
lib.write(f" *p_module_name = \"env\";\n")
lib.write(f" *p_base_lib_apis = g_{os.path.splitext(os.path.basename(csv.name))[0]}_native_symbols;\n")
lib.write(f" return sizeof(g_{os.path.splitext(os.path.basename(csv.name))[0]}_native_symbols) / sizeof(NativeSymbol);\n")
lib.write("}\n\n")
csv.seek(0)
def generate_glue(csv, out, lib):
generate_include(csv, out)
generate_functions(csv, out, lib)
generate_table(csv, out, lib)
def parse_args():
global args
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False)
parser.add_argument("-i", "--input", required=True,
help="CSV(Comma-Separated-Value) file")
parser.add_argument(
"-o", "--output", help="Output header file", default="glue.c")
parser.add_argument("-v", "--verbose", action="count", default=0,
help="Verbose Output")
args = parser.parse_args()
def main():
parse_args()
if not os.path.isfile(args.input):
sys.exit(1)
infile = open(args.input, "r")
outfile = open(args.output, "w")
libfile = open(f"signature_{args.output}", "w")
outfile.write("#include <nuttx/config.h>\n")
outfile.write("#include <stdint.h>\n")
libfile.write("#include <stdarg.h>\n")
libfile.write("#include <stddef.h>\n")
libfile.write("#include \"wamr/core/iwasm/include/lib_export.h\"\n\n")
generate_glue(infile, outfile, libfile)
infile.close()
outfile.close()
libfile.close()
if __name__ == "__main__":
main()