# Copyright (c) 2021, Alliance for Open Media. All rights reserved. # # This source code is subject to the terms of the BSD 2 Clause License and # the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License # was not distributed with this source code in the LICENSE file, you can # obtain it at www.aomedia.org/license/software. If the Alliance for Open # Media Patent License 1.0 was not distributed with this source code in the # PATENTS file, you can obtain it at www.aomedia.org/license/patent. #
from __future__ import print_function import sys import os import operator from pycparser import c_parser, c_ast, parse_file from math import *
from inspect import currentframe, getframeinfo from collections import deque
def get_struct_by_typedef_name(self, typedef_name): if typedef_name in self.typedef_name_dic: return self.typedef_name_dic[typedef_name] else: returnNone
def get_struct_by_struct_name(self, struct_name): if struct_name in self.struct_name_dic: return self.struct_name_dic[struct_name] else:
debug_print(getframeinfo(currentframe()))
print('Cant find', struct_name) returnNone
def update_struct_item_list(self): # Collect all struct_items from struct_name_dic and typedef_name_dic # Compute child_decl_map for each struct item. for struct_name in self.struct_name_dic.keys():
struct_item = self.struct_name_dic[struct_name]
struct_item.compute_child_decl_map(self)
self.struct_item_list.append(struct_item)
for typedef_name in self.typedef_name_dic.keys():
struct_item = self.typedef_name_dic[typedef_name] if struct_item.struct_name notin self.struct_name_dic:
struct_item.compute_child_decl_map(self)
self.struct_item_list.append(struct_item)
def update_enum(self, enum_node): if enum_node.name != None:
self.enum_name_dic[enum_node.name] = enum_node
if enum_node.values != None:
enumerator_list = enum_node.values.enumerators for enumerator in enumerator_list:
self.enum_value_dic[enumerator.name] = enum_node
T S N
case 1: o o o
typedef struct P {
int u;
} K;
T S N
case 2: o o x
typedef struct P K;
T S N
case 3: x o o
struct P {
int u;
};
T S N
case 4: o x o
typedef struct {
int u;
} K; """
struct_item = None
# Check whether struct_name or typedef_name is already in the dictionary if struct_name in self.struct_name_dic:
struct_item = self.struct_name_dic[struct_name]
if typedef_name in self.typedef_name_dic:
struct_item = self.typedef_name_dic[typedef_name]
if struct_item == None:
struct_item = StructItem(typedef_name, struct_name, struct_node, is_union)
if struct_node.decls != None:
struct_item.struct_node = struct_node
if struct_name != None:
self.struct_name_dic[struct_name] = struct_item
if typedef_name != None:
self.typedef_name_dic[typedef_name] = struct_item
def get_child_decl_status(self, decl_name): if self.struct_item != None: return self.struct_item.get_child_decl_status(decl_name) else: #TODO(angiebird): 2. Investigage the situation when a struct's definition can't be found. returnNone
def find_end_node(node):
node_list = [] for c in node:
node_list.append(c) if len(node_list) == 0: return node else: return find_end_node(node_list[-1])
def add_child(self, name, decl_status=None):
concrete_node = self.get_concrete_node() if name notin concrete_node.children:
child_id_node = IDStatusNode(name, concrete_node.root)
concrete_node.children[name] = child_id_node if decl_status == None: # Check if the child decl_status can be inferred from its parent's # decl_status if self.decl_status != None:
decl_status = self.decl_status.get_child_decl_status(name)
child_id_node.set_decl_status(decl_status) return concrete_node.children[name]
def get_child(self, name):
concrete_node = self.get_concrete_node() if name in concrete_node.children: return concrete_node.children[name] else: returnNone
def add_descendant(self, id_chain):
current_node = self.get_concrete_node() for name in id_chain:
current_node.add_child(name)
parent_node = current_node
current_node = current_node.get_child(name)
current_node.set_parent(parent_node) return current_node
def get_descendant(self, id_chain):
current_node = self.get_concrete_node() for name in id_chain:
current_node = current_node.get_child(name) if current_node == None: returnNone return current_node
#TODO move this part into a function for param in self.param_id_map:
decl_node = self.param_id_map[param]
decl_status = parse_decl_node(self.struct_info, decl_node)
descendant = self.id_tree_stack.add_id_seed_node(decl_status.name,
decl_status) if call_param_map isnotNoneand param in call_param_map: # This is a function call. # Map the input parameter to the caller's nodes # TODO(angiebird): Can we use add_link_node here?
descendant.set_link_node(call_param_map[param])
def generic_visit(self, node):
prev_parent = self.parent_node
self.parent_node = node for c in node:
self.visit(c)
self.parent_node = prev_parent
# TODO rename def add_new_id_tree(self, node):
self.id_tree_stack.push_id_tree()
self.generic_visit(node)
id_tree = self.id_tree_stack.pop_id_tree() if self.parent_node == Noneand self.keep_body_id_tree == True: # this is function body
self.body_id_tree = id_tree
def visit_Decl(self, node): if node.type.__class__.__name__ != 'FuncDecl':
decl_status = parse_decl_node(self.struct_info, node)
descendant = self.id_tree_stack.add_id_seed_node(decl_status.name,
decl_status) if node.init isnotNone:
init_id_chain = self.process_lvalue(node.init) if init_id_chain != None: if decl_status.struct_item isNone:
init_descendant = self.id_tree_stack.add_id_node(init_id_chain) if init_descendant != None:
init_descendant.set_refer(True, node.coord) else:
self.unknown.append(node)
descendant.set_assign(True, node.coord) else:
self.id_tree_stack.add_link_node(descendant, init_id_chain) else:
self.unknown.append(node) else:
descendant.set_assign(True, node.coord)
self.generic_visit(node)
def is_lvalue(self, node): if self.parent_node isNone: # TODO(angiebird): Do every lvalue has parent_node != None? returnFalse if self.parent_node.__class__.__name__ == 'StructRef': returnFalse if self.parent_node.__class__.__name__ == 'ArrayRef'and node == self.parent_node.name: # if node == self.parent_node.subscript, the node could be lvalue returnFalse if self.parent_node.__class__.__name__ == 'UnaryOp'and self.parent_node.op == '&': returnFalse if self.parent_node.__class__.__name__ == 'UnaryOp'and self.parent_node.op == '*': returnFalse returnTrue
def process_lvalue(self, node):
id_chain = parse_lvalue(node) if id_chain == None: return id_chain elif id_chain[0] in self.struct_info.enum_value_dic: returnNone else: return id_chain
def process_possible_lvalue(self, node): if self.is_lvalue(node):
id_chain = self.process_lvalue(node)
lead_char = get_lvalue_lead(node) # make sure the id is not an enum value if id_chain == None:
self.unknown.append(node) return
descendant = self.id_tree_stack.add_id_node(id_chain) if descendant == None:
self.unknown.append(node) return
decl_status = descendant.get_decl_status() if decl_status == None:
descendant.set_assign(True, node.coord)
descendant.set_refer(True, node.coord)
self.unknown.append(node) return if self.parent_node.__class__.__name__ == 'Assignment': if node is self.parent_node.lvalue: if decl_status.struct_item != None: if len(id_chain) > 1:
descendant.set_assign(True, node.coord) elif len(id_chain) == 1: if lead_char == '*':
descendant.set_assign(True, node.coord) else:
right_id_chain = self.process_lvalue(self.parent_node.rvalue) if right_id_chain != None:
self.id_tree_stack.add_link_node(descendant, right_id_chain) else: #TODO(angiebird): 1.Find a better way to deal with this case.
descendant.set_assign(True, node.coord) else:
debug_print(getframeinfo(currentframe())) else:
descendant.set_assign(True, node.coord) elif node is self.parent_node.rvalue: if decl_status.struct_item isNone:
descendant.set_refer(True, node.coord) if lead_char == '&':
descendant.set_assign(True, node.coord) else:
left_id_chain = self.process_lvalue(self.parent_node.lvalue)
left_lead_char = get_lvalue_lead(self.parent_node.lvalue) if left_id_chain != None: if len(left_id_chain) > 1:
descendant.set_refer(True, node.coord) elif len(left_id_chain) == 1: if left_lead_char == '*':
descendant.set_refer(True, node.coord) else: #TODO(angiebird): Check whether the other node is linked to this node. pass else:
self.unknown.append(self.parent_node.lvalue)
debug_print(getframeinfo(currentframe())) else:
self.unknown.append(self.parent_node.lvalue)
debug_print(getframeinfo(currentframe())) else:
debug_print(getframeinfo(currentframe())) elif self.parent_node.__class__.__name__ == 'UnaryOp': # TODO(angiebird): Consider +=, *=, -=, /= etc if self.parent_node.op == '--'or self.parent_node.op == '++'or\
self.parent_node.op == 'p--'or self.parent_node.op == 'p++':
descendant.set_assign(True, node.coord)
descendant.set_refer(True, node.coord) else:
descendant.set_refer(True, node.coord) elif self.parent_node.__class__.__name__ == 'Decl': #The logic is at visit_Decl pass elif self.parent_node.__class__.__name__ == 'ExprList': #The logic is at visit_FuncCall pass else:
descendant.set_refer(True, node.coord)
def visit_ID(self, node): # If the parent is a FuncCall, this ID is a function name. if self.parent_node.__class__.__name__ != 'FuncCall':
self.process_possible_lvalue(node)
self.generic_visit(node)
def process_func_call(self, func_call_node, func_def_node): # set up a refer/assign for func parameters # return call_param_map
call_param_ls = func_call_node.args.exprs
call_param_map = {}
func_decl = func_def_node.decl.type
decl_param_ls = func_decl.args.params for param_node, decl_node in zip(call_param_ls, decl_param_ls):
id_chain = self.process_lvalue(param_node) if id_chain != None:
descendant = self.id_tree_stack.add_id_node(id_chain) if descendant == None:
self.unknown.append(param_node) else:
decl_status = descendant.get_decl_status() if decl_status != None: if decl_status.struct_item == None: if decl_status.is_ptr_decl == True:
descendant.set_assign(True, param_node.coord)
descendant.set_refer(True, param_node.coord) else:
descendant.set_refer(True, param_node.coord) else:
call_param_map[decl_node.name] = descendant else:
self.unknown.append(param_node) else:
self.unknown.append(param_node) return call_param_map
def build_global_id_tree(ast, struct_info):
global_id_tree = IDStatusNode() for node in ast.ext: if node.__class__.__name__ == 'Decl': # id tree is for tracking assign/refer status # we don't care about function id because they can't be changed if node.type.__class__.__name__ != 'FuncDecl':
decl_status = parse_decl_node(struct_info, node)
descendant = global_id_tree.add_child(decl_status.name, decl_status) return global_id_tree
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.