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" ] 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 = 1 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_kernel_headers(): 109 """try to find the directory containing the kernel headers for this machine""" 110 status, version = commands.getstatusoutput( "uname -r" ) # get Linux kernel version 111 if status != 0: 112 D("could not execute 'uname -r' command properly") 113 return None 114 115 # get rid of the "-xenU" suffix that is found in Xen virtual machines 116 if len(version) > 5 and version[-5:] == "-xenU": 117 version = version[:-5] 118 119 path = "/usr/src/linux-headers-" + version 120 D("probing %s for kernel headers" % (path+"/include")) 121 ret = os.path.isdir( path ) 122 if ret: 123 D("found kernel headers in: %s" % (path + "/include")) 124 return path 125 return None 126 127 128# parser for the SYSCALLS.TXT file 129# 130class SysCallsTxtParser: 131 def __init__(self): 132 self.syscalls = [] 133 self.lineno = 0 134 135 def E(msg): 136 print "%d: %s" % (self.lineno, msg) 137 138 def parse_line(self, line): 139 """ parse a syscall spec line. 140 141 line processing, format is 142 return type func_name[:syscall_name[:call_id]] ( [paramlist] ) (syscall_number[,syscall_number_x86])|stub 143 """ 144 pos_lparen = line.find('(') 145 E = self.E 146 if pos_lparen < 0: 147 E("missing left parenthesis in '%s'" % line) 148 return 149 150 pos_rparen = line.rfind(')') 151 if pos_rparen < 0 or pos_rparen <= pos_lparen: 152 E("missing or misplaced right parenthesis in '%s'" % line) 153 return 154 155 return_type = line[:pos_lparen].strip().split() 156 if len(return_type) < 2: 157 E("missing return type in '%s'" % line) 158 return 159 160 syscall_func = return_type[-1] 161 return_type = string.join(return_type[:-1],' ') 162 call_id = -1 163 164 pos_colon = syscall_func.find(':') 165 if pos_colon < 0: 166 syscall_name = syscall_func 167 else: 168 if pos_colon == 0 or pos_colon+1 >= len(syscall_func): 169 E("misplaced colon in '%s'" % line) 170 return 171 172 # now find if there is a call_id for a dispatch-type syscall 173 # after the optional 2nd colon 174 pos_colon2 = syscall_func.find(':', pos_colon + 1) 175 if pos_colon2 < 0: 176 syscall_name = syscall_func[pos_colon+1:] 177 syscall_func = syscall_func[:pos_colon] 178 else: 179 if pos_colon2+1 >= len(syscall_func): 180 E("misplaced colon2 in '%s'" % line) 181 return 182 syscall_name = syscall_func[(pos_colon+1):pos_colon2] 183 call_id = int(syscall_func[pos_colon2+1:]) 184 syscall_func = syscall_func[:pos_colon] 185 186 if pos_rparen > pos_lparen+1: 187 syscall_params = line[pos_lparen+1:pos_rparen].split(',') 188 params = string.join(syscall_params,',') 189 else: 190 syscall_params = [] 191 params = "void" 192 193 number = line[pos_rparen+1:].strip() 194 if number == "stub": 195 syscall_id = -1 196 syscall_id2 = -1 197 syscall_id3 = -1 198 else: 199 try: 200 if number[0] == '#': 201 number = number[1:].strip() 202 numbers = string.split(number,',') 203 syscall_id = int(numbers[0]) 204 syscall_id2 = syscall_id 205 syscall_id3 = syscall_id 206 if len(numbers) > 1: 207 syscall_id2 = int(numbers[1]) 208 syscall_id3 = syscall_id2 209 if len(numbers) > 2: 210 syscall_id3 = int(numbers[2]) 211 except: 212 E("invalid syscall number in '%s'" % line) 213 return 214 215 print str(syscall_id) + ':' + str(syscall_id2) + ':' + str(syscall_id3) 216 217 t = { "id" : syscall_id, 218 "id2" : syscall_id2, 219 "id3" : syscall_id3, 220 "cid" : call_id, 221 "name" : syscall_name, 222 "func" : syscall_func, 223 "params" : syscall_params, 224 "decl" : "%-15s %s (%s);" % (return_type, syscall_func, params) } 225 226 self.syscalls.append(t) 227 228 def parse_file(self, file_path): 229 D2("parse_file: %s" % file_path) 230 fp = open(file_path) 231 for line in fp.xreadlines(): 232 self.lineno += 1 233 line = line.strip() 234 if not line: continue 235 if line[0] == '#': continue 236 self.parse_line(line) 237 238 fp.close() 239 240 241class Output: 242 def __init__(self,out=sys.stdout): 243 self.out = out 244 245 def write(self,msg): 246 self.out.write(msg) 247 248 def writeln(self,msg): 249 self.out.write(msg) 250 self.out.write("\n") 251 252class StringOutput: 253 def __init__(self): 254 self.line = "" 255 256 def write(self,msg): 257 self.line += msg 258 D2("write '%s'" % msg) 259 260 def writeln(self,msg): 261 self.line += msg + '\n' 262 D2("write '%s\\n'"% msg) 263 264 def get(self): 265 return self.line 266 267 268def create_file_path(path): 269 dirs = [] 270 while 1: 271 parent = os.path.dirname(path) 272 if parent == "/": 273 break 274 dirs.append(parent) 275 path = parent 276 277 dirs.reverse() 278 for dir in dirs: 279 #print "dir %s" % dir 280 if os.path.isdir(dir): 281 continue 282 os.mkdir(dir) 283 284def walk_source_files(paths,callback,args,excludes=[]): 285 """recursively walk a list of paths and files, only keeping the source files in directories""" 286 for path in paths: 287 if not os.path.isdir(path): 288 callback(path,args) 289 else: 290 for root, dirs, files in os.walk(path): 291 #print "w-- %s (ex: %s)" % (repr((root,dirs)), repr(excludes)) 292 if len(excludes): 293 for d in dirs[:]: 294 if d in excludes: 295 dirs.remove(d) 296 for f in files: 297 r, ext = os.path.splitext(f) 298 if ext in [ ".h", ".c", ".cpp", ".S" ]: 299 callback( "%s/%s" % (root,f), args ) 300 301def cleanup_dir(path): 302 """create a directory if needed, and ensure that it is totally empty 303 by removing any existing content in it""" 304 if not os.path.exists(path): 305 os.mkdir(path) 306 else: 307 for root, dirs, files in os.walk(path, topdown=False): 308 if root.endswith("kernel_headers/"): 309 # skip 'kernel_headers' 310 continue 311 for name in files: 312 os.remove(os.path.join(root, name)) 313 for name in dirs: 314 os.rmdir(os.path.join(root, name)) 315