def split_ast(ast): """ split the ast into header and initializer headers. initializers cannot be included in more than one translation unit (c file) """ init_decls = [] def extern_inits(decl): # c_ast.ID is used for directives. pass them straight through to both files if isinstance(decl, c_ast.ID): init_decls.append(decl) return decl elif decl.init: init_decls.append( c_ast.Decl(decl.name, decl.quals, decl.storage, decl.funcspec, decl.type, decl.init, decl.bitsize)) decl.storage = ['extern'] decl.init = None return decl else: return decl out_ast = c_ast.FileAST([extern_inits(e) for e in ast.ext]) init_ast = c_ast.FileAST(init_decls) return (out_ast, init_ast)
def merge_ast_tree(ast_tree, ext_index, bock_item_index, new_node, mode): ext_after = [] block_items_after = [] block_items_before = [] ext_before = ast_tree.ext[:ext_index] if (len(ast_tree.ext) > 1): ext_after = ast_tree.ext[ext_index + 1:] func_def_decl = ast_tree.ext[ext_index].decl para_decl = ast_tree.ext[ext_index].param_decls if (bock_item_index + 1 <= len(ast_tree.ext[ext_index].body.block_items)): if (mode == "insert_after"): block_items_before = ast_tree.ext[ ext_index].body.block_items[:bock_item_index + 1] if (mode == "insert_before"): block_items_before = ast_tree.ext[ ext_index].body.block_items[:bock_item_index] if (len(ast_tree.ext[ext_index].body.block_items) > 1): if (mode == "insert_after"): block_items_after = ast_tree.ext[ext_index].body.block_items[ bock_item_index + 1:] if (mode == "insert_before"): block_items_after = ast_tree.ext[ext_index].body.block_items[ bock_item_index:] block_items_before.append(new_node) changed_body = c_ast.Compound(block_items_before + block_items_after) changed_ext = c_ast.FuncDef(func_def_decl, para_decl, changed_body) ext_before.append(changed_ext) ast_tree = c_ast.FileAST(ext_before + ext_after) return ast_tree
def global_log(ast_tree): global_log = c_ast.Decl( 'global_log', [], [], [], c_ast.TypeDecl('global_log', [], c_ast.Struct('Global_Log', None)), None, None) temp_ls1 = [] temp_ls1.append(global_log) temp_ls2 = [] temp_ls2 = copy.deepcopy(ast_tree.ext) global_log = c_ast.FileAST(temp_ls1 + temp_ls2) return global_log
def parse(self, text, filename='', debuglevel=0, initial_type_symbols=set()): self.clex.filename = filename self.clex.reset_lineno() # _scope_stack[-1] is the current (topmost) scope. initial_scope = dict((tpsym, 1) for tpsym in initial_type_symbols) initial_scope.update( dict((tpsym, 1) for tpsym in self.initial_type_symbols)) self._scope_stack = [initial_scope] if not text or text.isspace(): return c_ast.FileAST([]) else: return self.cparser.parse(text, lexer=self.clex, debug=debuglevel)
def run(externs, our_fns, cpp_filter, cpp_all, decompile=True): '''frozenset(str) -> frozenset(str) -> str -> str -> opt:bool -> [c_ast]''' global OUR_FNS, EXTERN_REG_MAP, STKVAR_MAP # for repl convenience OUR_FNS = our_fns fn_segs = data.get_segs(['extern', '.text']) rodata_segs = data.get_segs(['.rodata', '.srdata']) data_segs = data.get_segs(['.data', '.bss']) lit_segs = data.get_segs(['.lit4', '.lit8']) num_lits = data.get_num_literals(lit_segs) str_lits = data.get_str_literals(rodata_segs) data_txt = data.get_data(data_segs, cpp_filter) # XXX FIXME this will be going away once we've added emitting numeric and # string constants directly at their site of use if decompile is True: for (k, v) in num_lits.iteritems(): ty = type(v) if ty is ep_ct.cfloat: print 'float %s = %s;' % (k, v) elif ty is ep_ct.cdouble: print 'double %s = %s;' % (k, v) else: raise Exception('o no') for (k, v) in str_lits.iteritems(): print 'const char *%s = %s;' % (k, data.c_stringify(v)) protos = map(cdecl.make_internal_fn_decl, our_fns) (lib_fns, tds) = data.get_fns_and_types(fn_segs, externs, cpp_all) all_tds = {x.name: x for x in tds} typedefs = cdecl.resolve_typedefs(all_tds) EXTERN_REG_MAP = data.get_fn_arg_map(lib_fns, typedefs) STKVAR_MAP = data.get_stkvars(our_fns) stkvar_decls = data.make_stkvar_txt(our_fns, STKVAR_MAP, cpp_filter) if decompile is True: print XXX_INTRO_HACK return gen_from_node( c_ast.FileAST(data_txt + protos + list( generate(ida.loc_by_name(decl.name), decl, our_fns, EXTERN_REG_MAP, STKVAR_MAP, stkvar_decls) for decl in protos))) else: return
def generate_code(request, response): for proto_file in request.proto_file: output = [] ast = c_ast.FileAST([]) generator = c_generator.CGenerator() ast.ext += [c_ast.EmptyStatement()] # Parse request for item, package in traverse(proto_file): data = { 'package': proto_file.package or '<root>', 'filename': proto_file.name, 'name': item.name, } if isinstance(item, DescriptorProto): data.update({ 'type': 'Message', 'properties': [{'name': f.name, 'type': int(f.type)} for f in item.field] }) elif isinstance(item, EnumDescriptorProto): data.update({ 'type': 'Enum', 'values': [{'name': v.name, 'value': v.number} for v in item.value] }) output.append(data) # Fill response f = response.file.add() f.name = proto_file.name + '.c' f.content = generator.visit(ast)
def generate_sai_api_tbl_h(apis): def createDecl(api): apitype = 'sai_' + api + '_api_t' apivar = 'sai_' + api + '_api_tbl' return c_ast.Decl( apivar, list(), list(), list(), c_ast.PtrDecl( list(), c_ast.TypeDecl(apivar, list(), c_ast.IdentifierType([ apitype, ]))), None, None) tdecls = [createDecl(api) for api in apis] tstruct = c_ast.Struct('_sai_api_tbl_t', tdecls) tdec = c_ast.TypeDecl('sai_api_tbl_t', list(), tstruct) tdef = c_ast.Typedef('sai_api_tbl_t', list(), ['typedef'], tdec) externdec = c_ast.Decl( 'sai_api_tbl', list(), ['extern'], list(), c_ast.TypeDecl('sai_api_tbl', list(), c_ast.IdentifierType(['sai_api_tbl_t'])), None, None) api_t = c_ast.FileAST([tdef, externdec]) generator = c_generator.CGenerator() sai_api_tbl_h_str = r'''#include "sai.h" #ifndef SAI_API_TBL #define SAI_API_TBL ''' sai_api_tbl_h_str += generator.visit(api_t) sai_api_tbl_h_str += r''' extern sai_status_t sai_api_tbl_init(); #endif ''' # print(api_t) print(sai_api_tbl_h_str) with open('adaptor/gen-inc/sai_api_tbl.h', 'w') as f: f.write(sai_api_tbl_h_str)
def to_func_ast(ast): return c_ast.FileAST(ast)
def createProgram(self): self.prog = c_ast.FileAST([self.ast, self.main])
def async_to_sync(async_ast: c_ast.Node, config): """ Given a c99 code in a AST form, returns the corresponding code of its synchronous equivalent program. Notes ----- First step is calculate all code between round variables assigments, then we add all the context needed to reach that piece of code. Entry point if ... if ... Current round Next round * --------------------------------> *----------------------> * A B The code we want to extract is in path B, but we need to collect all the conditions to reach this path, this is obtained collection all c_ast.If in path A. Path A and B can't contain c_ast.Continue nodes. Path B can't contain other round assigments in the middle. """ phase_variable = config['phase'] round_variable = config['round'] labels = config['labels'] # we discard what we won't use main_ast = cast_lib.find_funcdef_node(async_ast, 'main') cast_lib.map_dfs(main_ast, cast_lib.replace_while_with_body, []) cast_lib.filter_nodes(main_ast, remove_declarations) codecfg = cfg.ControlFlowGraph(main_ast) # we search paths between every (monotonically increasing) assigment of round variables paths_between_rounds = paths_between_round_assignments( codecfg, labels, round_variable, phase_variable) # for every protocol's round we calculate all possible paths including its previous context (e.g., ifs conditions) start_node = list(nx.topological_sort(codecfg))[0] complete_paths_by_round = {} for round_label, suffix_paths in paths_between_rounds.items(): complete_paths_by_round[round_label] = [] for suffix_path in suffix_paths: suffix_first_node = list(nx.topological_sort(suffix_path))[0] prefix_paths = get_cfg_paths_between_nodes(codecfg, start_node, suffix_first_node) cp = complete_paths(suffix_path, prefix_paths) complete_paths_by_round[round_label].extend(cp) # the code of a round is the (graph) union of all the complete paths found to belong to that round # the easiest approach is to remove the nodes not included in those paths from the original code using the coord property sync_code = {} for round_label, paths in complete_paths_by_round.items(): round_code_cfg = cfg.ControlFlowGraph() nodes_to_keep = set() for p in paths: for n in p.nodes(): nodes_to_keep.add(str(n.coord)) round_sync_code = copy.deepcopy(main_ast) cast_lib.filter_nodes(round_sync_code, node_coord_not_in_set, nodes_to_keep) sync_code[round_label] = round_sync_code # translate to CompHO compho = {} for round_label, ast_code in sync_code.items(): compho[round_label] = {} ast_send = c_ast.FileAST([copy.deepcopy(ast_code)]) get_compho_send(ast_send) ast_update = c_ast.FileAST([copy.deepcopy(ast_code)]) get_compho_update(ast_update, round_variable, round_label) compho[round_label]['send'] = ast_send compho[round_label]['update'] = ast_update return compho
def gen_c_func_adaptor(astperfile): adaptorH = r'''//Automatically generated by goSAIadapterBuilder. #include "sai_api_tbl.h" ''' adaptorC = r'''//Automatically generated by goSAIadapterBuilder. #include "sai_api_tbl_init.c" ''' adaptorFuncdefs = [] for file_ast_fn in astperfile.keys(): # for file_ast_fn in ['/home/johnnie/Documents/gitprojects/SAI/inc/sairouterinterface.h', ]: # for file_ast_fn in ['/home/johnnie/Documents/gitprojects/SAI/inc/sairoute.h', ]: file_ast = astperfile[file_ast_fn] fn_core = file_ast_fn.split('/')[-1] fileC = r'''//Automatically generated by goSAIadapterBuilder. #include "sai_api_tbl.h" ''' fileH = r'''//Automatically generated by goSAIadapterBuilder. #include "sai.h" ''' api_ast = [ inst for inst in file_ast if 'api' in inst.name and not "sai_common_api_t" == inst.name and not "sai_api" in inst.name ] api = dict([(apidecl.type.type.names[0], apidecl.name) for apitypedef in api_ast for apidecl in apitypedef.type.type.decls]) # print(api) for functypedef in file_ast: if not 'fn' in functypedef.name: continue funcdecl = functypedef.type.type if type(funcdecl.type) is c_ast.TypeDecl: funcdecl.type.declname = funcdecl.type.declname[:-3] funcdeclreturntype = funcdecl.type.type.names[0] else: funcdecl.type.type.declname = funcdecl.type.type.declname[:-3] funcdeclreturntype = funcdecl.type.type.type.names[0] if funcdeclreturntype != 'sai_status_t': print("Ret", funcdeclreturntype) continue tblname = file_ast[-1].name + 'bl' if 'api' not in tblname: tblname = None for td in file_ast: if 'table' in td.name: tblname = td.name if tblname == None: break fdecl = c_ast.Decl(functypedef.name[:-3], list(), list(), list(), type=funcdecl, init=None, bitsize=None) fbody = c_ast.Compound(block_items=[ c_ast.Return(expr=c_ast.FuncCall( name=c_ast.StructRef( name=c_ast.StructRef(name=c_ast.ID(name='sai_api_tbl'), type='.', field=c_ast.ID(name=tblname)), # type='->',field=c_ast.ID(name=functypedef.name[4:-3])), type='->', field=c_ast.ID(name=api[functypedef.name])), args=c_ast.ExprList( exprs=[c_ast.ID(p.name) for p in funcdecl.args.params]))) ]) funcdef = c_ast.FuncDef(decl=fdecl, param_decls=None, body=fbody) # print(funcdef) adaptorFuncdefs.append(fdecl) funcH = generator.visit(c_ast.FileAST(fdecl)) fileH += funcH funcC = generator.visit(funcdef) fileC += funcC # print(file_ast) if fileC[-2:] != '"\n': hname = 'adaptor/gen-inc/' + fn_core[:-2] + "_adaptor.h" with open(hname, 'w') as f: f.write(fileH) print("written to", hname) cname = 'adaptor/gen-src/' + fn_core[:-2] + "_adaptor.c" with open(cname, 'w') as f: f.write(fileC) print("written to", cname) adaptorH += '#include "' + hname + '"\n' adaptorC += '#include "' + cname + '"\n' with open("adaptor/gen-inc/sai_adaptor.h", 'w') as f: f.write(adaptorH) with open("adaptor/sai_adaptor_all.c", 'w') as f: f.write(adaptorC) return adaptorFuncdefs
def remove_defs(headers, base_dir, blacklist, take_typedefs=True, take_funcs=True, take_decls=True, **kwargs): """ Keeps only type definitions and function declarations. :param headers: :param base_dir: :param blacklist: :return: """ parser = c_parser.CParser() def take_coord(coord): pth = coord_path(coord) return pth is not None and pth.startswith(base_dir) class FuncDefVisitor(c_ast.NodeVisitor): def __init__(self): self.defs = [] self.ar = ArrayEval() def visit_FuncDef(self, node): return def visit_Typedef(self, node): if not take_coord( node.coord) or node.name in blacklist or not take_typedefs: return self.ar.visit(node) self.defs.append(node) def visit_FunDecl(self, node): if not take_coord( node.coord ) or node.decl.name in blacklist or not take_funcs: return self.ar.visit(node) self.defs.append(node) def visit_Decl(self, node): if not take_coord( node.coord) or node.name in blacklist or not take_decls: return if 'static' in node.storage: return self.ar.visit(node) self.defs.append(node) to_parse = headers.decode('utf8') # quick hack for sizeof to_parse = replace_sizeofs(to_parse) ast = parser.parse(to_parse, debuglevel=0) v = FuncDefVisitor() v.visit(ast) nast = c_ast.FileAST(v.defs) generator = c_generator.CGenerator() genc = generator.visit(nast) return genc