1# common python utility routines for the Bionic tool scripts 2 3import sys, os, commands, string 4 5# support Bionic architectures, add new ones as appropriate 6# 7bionic_archs = [ "arm", "x86", "mips" ] 8 9# basic debugging trace support 10# call D_setlevel to set the verbosity level 11# and D(), D2(), D3(), D4() to add traces 12# 13verbose = 0 14 15def D(msg): 16 global verbose 17 if verbose > 0: 18 print msg 19 20def D2(msg): 21 global verbose 22 if verbose >= 2: 23 print msg 24 25def D3(msg): 26 global verbose 27 if verbose >= 3: 28 print msg 29 30def D4(msg): 31 global verbose 32 if verbose >= 4: 33 print msg 34 35def D_setlevel(level): 36 global verbose 37 verbose = level 38 39 40def find_dir_of(path): 41 '''return the directory name of 'path', or "." if there is none''' 42 # remove trailing slash 43 if len(path) > 1 and path[-1] == '/': 44 path = path[:-1] 45 46 # find parent directory name 47 d = os.path.dirname(path) 48 if d == "": 49 return "." 50 else: 51 return d 52 53# other stuff 54# 55# 56def find_file_from_upwards(from_path,target_file): 57 """find a file in the current directory or its parents. if 'from_path' is None, 58 seach from the current program's directory""" 59 path = from_path 60 if path == None: 61 path = find_dir_of(sys.argv[0]) 62 D("this script seems to be located in: %s" % path) 63 64 while 1: 65 if path == "": 66 path = "." 67 68 file = path + "/" + target_file 69 D("probing "+file) 70 71 if os.path.isfile(file): 72 D("found %s in %s" % (target_file, path)) 73 return file 74 75 if path == ".": 76 break 77 78 path = os.path.dirname(path) 79 80 path = "" 81 while 1: 82 path = "../" + path 83 file = path + target_file 84 D("probing "+file) 85 86 if os.path.isfile(file): 87 D("found %s in %s" % (target_file, path)) 88 return file 89 90 91 return None 92 93def find_bionic_root(): 94 '''find the root of the Bionic source tree. we check for the SYSCALLS.TXT file 95 from the location of the current program's directory.''' 96 97 # note that we can't use find_file_from_upwards() since we can't use os.path.abspath 98 # that's because in some cases the p4 client is in a symlinked directory, and this 99 # function will return the real path instead, which later creates problems when 100 # p4 commands are issued 101 # 102 file = find_file_from_upwards(None, "SYSCALLS.TXT") 103 if file: 104 return os.path.dirname(file) 105 else: 106 return None 107 108def find_original_kernel_headers(): 109 """try to find the directory containing the original kernel headers""" 110 bionic_root = find_bionic_root() 111 if not bionic_root: 112 D("Could not find Bionic root !!") 113 return None 114 115 path = os.path.normpath(bionic_root + "/../../external/kernel-headers/original") 116 if not os.path.isdir(path): 117 D("Could not find %s" % (path)) 118 return None 119 120 return path 121 122def find_kernel_headers(): 123 """try to find the directory containing the kernel headers for this machine""" 124 125 # First try to find the original kernel headers. 126 ret = find_original_kernel_headers() 127 if ret: 128 D("found original kernel headers in: %s" % (ret)) 129 return ret 130 131 status, version = commands.getstatusoutput( "uname -r" ) # get Linux kernel version 132 if status != 0: 133 D("could not execute 'uname -r' command properly") 134 return None 135 136 # get rid of the "-xenU" suffix that is found in Xen virtual machines 137 if len(version) > 5 and version[-5:] == "-xenU": 138 version = version[:-5] 139 140 path = "/usr/src/linux-headers-" + version + "/include" 141 D("probing %s for kernel headers" % (path)) 142 ret = os.path.isdir( path ) 143 if ret: 144 D("found kernel headers in: %s" % (path)) 145 return path 146 return None 147 148def find_arch_header(kernel_headers,arch,header): 149 # First, try in <root>/arch/<arm>/include/<header> 150 # corresponding to the location in the kernel source tree for 151 # certain architectures (e.g. arm). 152 path = "%s/arch/%s/include/asm/%s" % (kernel_headers, arch, header) 153 D("Probing for %s" % path) 154 if os.path.exists(path): 155 return path 156 157 # Try <root>/asm-<arch>/include/<header> corresponding to the location 158 # in the kernel source tree for other architectures (e.g. x86). 159 path = "%s/include/asm-%s/%s" % (kernel_headers, arch, header) 160 D("Probing for %s" % path) 161 if os.path.exists(path): 162 return path 163 164 # Otherwise, look under <root>/asm-<arch>/<header> corresponding 165 # the original kernel headers directory 166 path = "%s/asm-%s/%s" % (kernel_headers, arch, header) 167 D("Probing for %s" % path) 168 if os.path.exists(path): 169 return path 170 171 172 return None 173 174# parser for the SYSCALLS.TXT file 175# 176class SysCallsTxtParser: 177 def __init__(self): 178 self.syscalls = [] 179 self.lineno = 0 180 181 def E(self, msg): 182 print "%d: %s" % (self.lineno, msg) 183 184 def parse_line(self, line): 185 """ parse a syscall spec line. 186 187 line processing, format is 188 return type func_name[:syscall_name[:call_id]] ( [paramlist] ) (syscall_number[,syscall_number_x86])|stub 189 """ 190 pos_lparen = line.find('(') 191 E = self.E 192 if pos_lparen < 0: 193 E("missing left parenthesis in '%s'" % line) 194 return 195 196 pos_rparen = line.rfind(')') 197 if pos_rparen < 0 or pos_rparen <= pos_lparen: 198 E("missing or misplaced right parenthesis in '%s'" % line) 199 return 200 201 return_type = line[:pos_lparen].strip().split() 202 if len(return_type) < 2: 203 E("missing return type in '%s'" % line) 204 return 205 206 syscall_func = return_type[-1] 207 return_type = string.join(return_type[:-1],' ') 208 call_id = -1 209 210 pos_colon = syscall_func.find(':') 211 if pos_colon < 0: 212 syscall_name = syscall_func 213 else: 214 if pos_colon == 0 or pos_colon+1 >= len(syscall_func): 215 E("misplaced colon in '%s'" % line) 216 return 217 218 # now find if there is a call_id for a dispatch-type syscall 219 # after the optional 2nd colon 220 pos_colon2 = syscall_func.find(':', pos_colon + 1) 221 if pos_colon2 < 0: 222 syscall_name = syscall_func[pos_colon+1:] 223 syscall_func = syscall_func[:pos_colon] 224 else: 225 if pos_colon2+1 >= len(syscall_func): 226 E("misplaced colon2 in '%s'" % line) 227 return 228 syscall_name = syscall_func[(pos_colon+1):pos_colon2] 229 call_id = int(syscall_func[pos_colon2+1:]) 230 syscall_func = syscall_func[:pos_colon] 231 232 if pos_rparen > pos_lparen+1: 233 syscall_params = line[pos_lparen+1:pos_rparen].split(',') 234 params = string.join(syscall_params,',') 235 else: 236 syscall_params = [] 237 params = "void" 238 239 number = line[pos_rparen+1:].strip() 240 if number == "stub": 241 syscall_common = -1 242 syscall_arm = -1 243 syscall_x86 = -1 244 syscall_mips = -1 245 else: 246 try: 247 if number[0] == '#': 248 number = number[1:].strip() 249 numbers = string.split(number,',') 250 if len(numbers) == 1: 251 syscall_common = int(numbers[0]) 252 syscall_arm = -1 253 syscall_x86 = -1 254 syscall_mips = -1 255 else: 256 if len(numbers) == 3: 257 syscall_common = -1 258 syscall_arm = int(numbers[0]) 259 syscall_x86 = int(numbers[1]) 260 syscall_mips = int(numbers[2]) 261 else: 262 E("invalid syscall number format in '%s'" % line) 263 return 264 except: 265 E("invalid syscall number in '%s'" % line) 266 return 267 268 global verbose 269 if verbose >= 2: 270 if call_id == -1: 271 if syscall_common == -1: 272 print "%s: %d,%d,%d" % (syscall_name, syscall_arm, syscall_x86, syscall_mips) 273 else: 274 print "%s: %d" % (syscall_name, syscall_common) 275 else: 276 if syscall_common == -1: 277 print "%s(%d): %d,%d,%d" % (syscall_name, call_id, syscall_arm, syscall_x86, syscall_mips) 278 else: 279 print "%s(%d): %d" % (syscall_name, call_id, syscall_common) 280 281 t = { "armid" : syscall_arm, 282 "x86id" : syscall_x86, 283 "mipsid" : syscall_mips, 284 "common" : syscall_common, 285 "cid" : call_id, 286 "name" : syscall_name, 287 "func" : syscall_func, 288 "params" : syscall_params, 289 "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params) } 290 self.syscalls.append(t) 291 292 def parse_file(self, file_path): 293 D2("parse_file: %s" % file_path) 294 fp = open(file_path) 295 for line in fp.xreadlines(): 296 self.lineno += 1 297 line = line.strip() 298 if not line: continue 299 if line[0] == '#': continue 300 self.parse_line(line) 301 302 fp.close() 303 304 305class StringOutput: 306 def __init__(self): 307 self.line = "" 308 309 def write(self,msg): 310 self.line += msg 311 D2("write '%s'" % msg) 312 313 def get(self): 314 return self.line 315 316 317def create_file_path(path): 318 dirs = [] 319 while 1: 320 parent = os.path.dirname(path) 321 if parent == "/": 322 break 323 dirs.append(parent) 324 path = parent 325 326 dirs.reverse() 327 for dir in dirs: 328 #print "dir %s" % dir 329 if os.path.isdir(dir): 330 continue 331 os.mkdir(dir) 332 333def walk_source_files(paths,callback,args,excludes=[]): 334 """recursively walk a list of paths and files, only keeping the source files in directories""" 335 for path in paths: 336 if not os.path.isdir(path): 337 callback(path,args) 338 else: 339 for root, dirs, files in os.walk(path): 340 #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes)) 341 if len(excludes): 342 for d in dirs[:]: 343 if d in excludes: 344 dirs.remove(d) 345 for f in files: 346 r, ext = os.path.splitext(f) 347 if ext in [ ".h", ".c", ".cpp", ".S" ]: 348 callback( "%s/%s" % (root,f), args ) 349 350def cleanup_dir(path): 351 """create a directory if needed, and ensure that it is totally empty 352 by removing any existing content in it""" 353 if not os.path.exists(path): 354 os.mkdir(path) 355 else: 356 for root, dirs, files in os.walk(path, topdown=False): 357 if root.endswith("kernel_headers/"): 358 # skip 'kernel_headers' 359 continue 360 for name in files: 361 os.remove(os.path.join(root, name)) 362 for name in dirs: 363 os.rmdir(os.path.join(root, name)) 364