1from typing import Tuple, Optional 2 3from ..sim_type import parse_file, parse_cpp_file, normalize_cpp_function_name, SimTypeCppFunction, SimTypeFd, \ 4 register_types, parse_types 5 6 7def get_function_name(s): 8 """ 9 Get the function name from a C-style function declaration string. 10 11 :param str s: A C-style function declaration string. 12 :return: The function name. 13 :rtype: str 14 """ 15 16 s = s.strip() 17 if s.startswith("__attribute__"): 18 # Remove "__attribute__ ((foobar))" 19 if "))" not in s: 20 raise ValueError("__attribute__ is present, but I cannot find double-right parenthesis in the function " 21 "declaration string.") 22 23 s = s[s.index("))") + 2 : ].strip() 24 25 if '(' not in s: 26 raise ValueError("Cannot find any left parenthesis in the function declaration string.") 27 28 func_name = s[:s.index('(')].strip() 29 30 for i, ch in enumerate(reversed(func_name)): 31 if ch == ' ': 32 pos = len(func_name) - 1 - i 33 break 34 else: 35 raise ValueError('Cannot find any space in the function declaration string.') 36 37 func_name = func_name[pos + 1 : ] 38 return func_name 39 40def register_kernel_types(): 41 register_types(parse_types(""" 42 typedef int mode_t; 43 typedef unsigned int umode_t; 44 typedef int clockid_t; 45 typedef int pid_t; 46 typedef int qid_t; 47 typedef int key_t; 48 typedef int mqd_t; 49 typedef void *timer_t; 50 typedef uint32_t u32; 51 typedef uint32_t __u32; 52 typedef uint64_t u64; 53 typedef int32_t __s32; 54 typedef int64_t loff_t; 55 """)) 56 57 58def convert_cproto_to_py(c_decl): 59 """ 60 Convert a C-style function declaration string to its corresponding SimTypes-based Python representation. 61 62 :param str c_decl: The C-style function declaration string. 63 :return: A tuple of the function name, the prototype, and a string representing the 64 SimType-based Python representation. 65 :rtype: tuple 66 """ 67 68 s = [ ] 69 70 try: 71 s.append('# %s' % c_decl) # comment string 72 73 parsed = parse_file(c_decl) 74 parsed_decl = parsed[0] 75 if not parsed_decl: 76 raise ValueError('Cannot parse the function prototype.') 77 78 func_name, func_proto = next(iter(parsed_decl.items())) 79 80 s.append('"%s": %s,' % (func_name, func_proto._init_str())) # The real Python string 81 82 except Exception: # pylint:disable=broad-except 83 # Silently catch all parsing errors... supporting all function declarations is impossible 84 try: 85 func_name = get_function_name(c_decl) 86 func_proto = None 87 s.append('"%s": None,' % func_name) 88 except ValueError: 89 # Failed to extract the function name. Is it a function declaration? 90 func_name, func_proto = None, None 91 92 return func_name, func_proto, "\n".join(s) 93 94 95def convert_cppproto_to_py(cpp_decl: str, 96 with_param_names: bool=False) -> Tuple[Optional[str],Optional[SimTypeCppFunction],Optional[str]]: 97 """ 98 Pre-process a C++-style function declaration string to its corresponding SimTypes-based Python representation. 99 100 :param cpp_decl: The C++-style function declaration string. 101 :return: A tuple of the function name, the prototype, and a string representing the SimType-based Python 102 representation. 103 """ 104 105 s = [ ] 106 try: 107 s.append("# %s" % cpp_decl) 108 109 parsed = parse_cpp_file(cpp_decl, with_param_names=with_param_names) 110 parsed_decl = parsed[0] 111 if not parsed_decl: 112 raise ValueError("Cannot parse the function prototype.") 113 114 func_name, func_proto = next(iter(parsed_decl.items())) 115 116 s.append('"%s": %s,' % (func_name, func_proto._init_str())) # The real Python string 117 118 except Exception: # pylint:disable=broad-except 119 try: 120 func_name = get_function_name(cpp_decl) 121 func_proto = None 122 s.append('"%s": None,' % func_name) 123 except ValueError: 124 # Failed to extract the function name. Is it a function declaration? 125 func_name, func_proto = None, None 126 127 return func_name, func_proto, "\n".join(s) 128 129 130def cprotos2py(cprotos, fd_spots=frozenset(), remove_sys_prefix=False): 131 """ 132 Parse a list of C function declarations and output to Python code that can be embedded into 133 angr.procedures.definitions. 134 135 >>> # parse the list of glibc C prototypes and output to a file 136 >>> from angr.procedures.definitions import glibc 137 >>> with open("glibc_protos", "w") as f: f.write(cprotos2py(glibc._libc_c_decls)) 138 139 :param list cprotos: A list of C prototype strings. 140 :return: A Python string. 141 :rtype: str 142 """ 143 s = "" 144 for decl in cprotos: 145 func_name, proto_, str_ = convert_cproto_to_py(decl) # pylint:disable=unused-variable 146 if remove_sys_prefix and func_name.startswith('sys'): 147 func_name = '_'.join(func_name.split('_')[1:]) 148 if proto_ is not None: 149 if (func_name, -1) in fd_spots: 150 proto_.returnty = SimTypeFd(label=proto_.returnty.label) 151 for i, arg in enumerate(proto_.args): 152 if (func_name, i) in fd_spots: 153 proto_.args[i] = SimTypeFd(label=arg.label) 154 155 line1 = ' '*8 + '# ' + decl + '\n' 156 line2 = ' '*8 + repr(func_name) + ": " + (proto_._init_str() if proto_ is not None else "None") + ',' + '\n' 157 s += line1 + line2 158 return s 159 160 161def get_cpp_function_name(demangled_name, specialized=True, qualified=True): 162 if not specialized: 163 # remove "<???>"s 164 name = normalize_cpp_function_name(demangled_name) 165 else: 166 name = demangled_name 167 168 if not qualified: 169 # remove leading namespaces 170 chunks = name.split("::") 171 name = "::".join(chunks[-2:]) 172 173 # remove arguments 174 if "(" in name: 175 name = name[: name.find("(")] 176 177 return name 178