1#!/usr/bin/env python 2 3from __future__ import print_function 4import re 5import sys 6 7re_identifier = re.compile(r'^[a-zA-Z_]') 8re_compat_handle = re.compile(r'^COMPAT_HANDLE\((.*)\)$') 9re_pad = re.compile(r'^_pad\d*$') 10re_compat = re.compile(r'^compat_.*_t$') 11 12def removeprefix(s, prefix): 13 if s.startswith(prefix): 14 return s[len(prefix):] 15 return s 16 17def removesuffix(s, suffix): 18 if s.endswith(suffix): 19 return s[:-len(suffix)] 20 return s 21 22def get_fields(looking_for, header_tokens): 23 level = 1 24 aggr = 0 25 fields = [] 26 name = '' 27 28 for token in header_tokens: 29 if token in ('struct', 'union'): 30 if level == 1: 31 aggr = 1 32 fields = [] 33 name = '' 34 elif token == '{': 35 level += 1 36 elif token == '}': 37 level -= 1 38 if level == 1 and name == looking_for: 39 fields.append(token) 40 return fields 41 elif re_identifier.match(token): 42 if not (aggr == 0 or name != ''): 43 name = token 44 45 if aggr != 0: 46 fields.append(token) 47 48 return [] 49 50def build_enums(name, tokens): 51 level = 1 52 kind = '' 53 named = '' 54 fields = [] 55 members = [] 56 id = '' 57 58 for token in tokens: 59 if token in ('struct', 'union'): 60 if not level != 2: 61 fields = [''] 62 kind = "%s;%s" % (token, kind) 63 elif token == '{': 64 level += 1 65 elif token == '}': 66 level -= 1 67 if level == 1: 68 subkind = kind 69 (subkind, _, _) = subkind.partition(';') 70 if subkind == 'union': 71 print("\nenum XLAT_%s {" % (name,)) 72 for m in members: 73 print(" XLAT_%s_%s," % (name, m)) 74 print("};") 75 return 76 elif level == 2: 77 named = '?' 78 elif re_identifier.match(token): 79 id = token 80 k = kind 81 (_, _, k) = k.partition(';') 82 if named != '' and k != '': 83 if len(fields) > 0 and fields[0] == '': 84 fields.pop(0) 85 build_enums("%s_%s" % (name, token), fields) 86 named = '!' 87 elif token == ',': 88 if level == 2: 89 members.append(id) 90 elif token == ';': 91 if level == 2: 92 members.append(id) 93 if named != '': 94 (_, _, kind) = kind.partition(';') 95 named = '' 96 if len(fields) != 0: 97 fields.append(token) 98 99def handle_field(prefix, name, id, type, fields): 100 if len(fields) == 0: 101 print(" \\") 102 if type == '': 103 print("%s(_d_)->%s = (_s_)->%s;" % (prefix, id, id), end='') 104 else: 105 k = id.replace('.', '_') 106 print("%sXLAT_%s_HNDL_%s(_d_, _s_);" % (prefix, name, k), end='') 107 elif not '{' in fields: 108 tag = ' '.join(fields) 109 tag = re.sub(r'\s*(struct|union)\s+(compat_)?(\w+)\s.*', '\\3', tag) 110 print(" \\") 111 print("%sXLAT_%s(&(_d_)->%s, &(_s_)->%s);" % (prefix, tag, id, id), end='') 112 else: 113 func_id = id 114 func_tokens = fields 115 kind = '' 116 array = "" 117 level = 1 118 arrlvl = 1 119 array_type = '' 120 id = '' 121 type = '' 122 fields = [] 123 for token in func_tokens: 124 if token in ('struct', 'union'): 125 if level == 2: 126 fields = [''] 127 if level == 1: 128 kind = token 129 if kind == 'union': 130 tmp = func_id.replace('.', '_') 131 print(" \\") 132 print("%sswitch (%s) {" % (prefix, tmp), end='') 133 elif token == '{': 134 level += 1 135 id = '' 136 elif token == '}': 137 level -= 1 138 id = '' 139 if level == 1 and kind == 'union': 140 print(" \\") 141 print("%s}" % (prefix,), end='') 142 elif token == '[': 143 if level != 2 or arrlvl != 1: 144 pass 145 elif array == '': 146 array = ' ' 147 else: 148 array = "%s;" % (array,) 149 arrlvl += 1 150 elif token == ']': 151 arrlvl -= 1 152 elif re_compat_handle.match(token): 153 if level == 2 and id == '': 154 m = re_compat_handle.match(token) 155 type = m.groups()[0] 156 type = removeprefix(type, 'compat_') 157 elif token == "compat_domain_handle_t": 158 if level == 2 and id == '': 159 array_type = token 160 elif re_identifier.match(token): 161 id = token 162 elif token in (',', ';'): 163 if level == 2 and not re_pad.match(id): 164 if kind == 'union': 165 tmp = "%s.%s" % (func_id, id) 166 tmp = tmp.replace('.', '_') 167 print(" \\") 168 print("%scase XLAT_%s_%s:" % (prefix, name, tmp), end='') 169 if len(fields) > 0 and fields[0] == '': 170 fields.pop(0) 171 handle_field("%s " % (prefix,), name, "%s.%s" % (func_id, id), type, fields) 172 elif array == '' and array_type == '': 173 if len(fields) > 0 and fields[0] == '': 174 fields.pop(0) 175 handle_field(prefix, name, "%s.%s" % (func_id, id), type, fields) 176 elif array == '': 177 copy_array(" ", "%s.%s" % (func_id, id)) 178 else: 179 (_, _, array) = array.partition(';') 180 if len(fields) > 0 and fields[0] == '': 181 fields.pop(0) 182 handle_array(prefix, name, "{func_id}.{id}", array, type, fields) 183 if token == ';': 184 fields = [] 185 id = '' 186 type = '' 187 array = '' 188 if kind == 'union': 189 print(" \\") 190 print("%s break;" % (prefix,), end='') 191 else: 192 if array != '': 193 array = "%s %s" % (array, token) 194 if len(fields) > 0: 195 fields.append(token) 196 197def copy_array(prefix, id): 198 print(" \\") 199 print("%sif ((_d_)->%s != (_s_)->%s) \\" % (prefix, id, id)) 200 print("%s memcpy((_d_)->%s, (_s_)->%s, sizeof((_d_)->%s));" % (prefix, id, id, id), end='') 201 202def handle_array(prefix, name, id, array, type, fields): 203 i = re.sub(r'[^;]', '', array) 204 i = "i%s" % (len(i),) 205 206 print(" \\") 207 print("%s{ \\" % (prefix,)) 208 print("%s unsigned int %s; \\" % (prefix, i)) 209 (head, _, tail) = array.partition(';') 210 head = head.strip() 211 print("%s for (%s = 0; %s < %s; ++%s) {" % (prefix, i, i, head, i), end='') 212 if not ';' in array: 213 handle_field("%s " % (prefix,), name, "%s[%s]" % (id, i), type, fields) 214 else: 215 handle_array("%s " % (prefix,) , name, "%s[%s]" % (id, i), tail, type, fields) 216 print(" \\") 217 print("%s } \\" % (prefix,)) 218 print("%s}" % (prefix,), end='') 219 220def build_body(name, tokens): 221 level = 1 222 id = '' 223 array = '' 224 arrlvl = 1 225 array_type = '' 226 type = '' 227 fields = [] 228 229 print("\n#define XLAT_%s(_d_, _s_) do {" % (name,), end='') 230 231 for token in tokens: 232 if token in ('struct', 'union'): 233 if level == 2: 234 fields = [''] 235 elif token == '{': 236 level += 1 237 id = '' 238 elif token == '}': 239 level -= 1 240 id = '' 241 elif token == '[': 242 if level != 2 or arrlvl != 1: 243 pass 244 elif array == '': 245 array = ' ' 246 else: 247 array = "%s;" % (array,) 248 arrlvl += 1 249 elif token == ']': 250 arrlvl -= 1 251 elif re_compat_handle.match(token): 252 if level == 2 and id == '': 253 m = re_compat_handle.match(token) 254 type = m.groups()[0] 255 type = removeprefix(type, 'compat_') 256 elif token == "compat_domain_handle_t": 257 if level == 2 and id == '': 258 array_type = token 259 elif re_identifier.match(token): 260 if array != '': 261 array = "%s %s" % (array, token) 262 else: 263 id = token 264 elif token in (',', ';'): 265 if level == 2 and not re_pad.match(id): 266 if array == '' and array_type == '': 267 if len(fields) > 0 and fields[0] == '': 268 fields.pop(0) 269 handle_field(" ", name, id, type, fields) 270 elif array == '': 271 copy_array(" ", id) 272 else: 273 (head, sep, tmp) = array.partition(';') 274 if sep == '': 275 tmp = head 276 if len(fields) > 0 and fields[0] == '': 277 fields.pop(0) 278 handle_array(" ", name, id, tmp, type, fields) 279 if token == ';': 280 fields = [] 281 id = '' 282 type = '' 283 array = '' 284 else: 285 if array != '': 286 array = "%s %s" % (array, token) 287 if len(fields) > 0: 288 fields.append(token) 289 print(" \\\n} while (0)") 290 291def check_field(kind, name, field, extrafields): 292 if not '{' in extrafields: 293 print("; \\") 294 if len(extrafields) != 0: 295 for token in extrafields: 296 if token in ('struct', 'union'): 297 pass 298 elif re_identifier.match(token): 299 print(" CHECK_%s" % (removeprefix(token, 'xen_'),), end='') 300 break 301 else: 302 raise Exception("Malformed compound declaration: '%s'" % (token,)) 303 elif not '.' in field: 304 print(" CHECK_FIELD_(%s, %s, %s)" % (kind, name, field), end='') 305 else: 306 n = field.count('.') 307 field = field.replace('.', ', ') 308 print(" CHECK_SUBFIELD_%s_(%s, %s, %s)" % (n, kind, name, field), end='') 309 else: 310 level = 1 311 fields = [] 312 id = '' 313 314 for token in extrafields: 315 if token in ('struct', 'union'): 316 if level == 2: 317 fields = [''] 318 elif token == '{': 319 level += 1 320 id = '' 321 elif token == '}': 322 level -= 1 323 id = '' 324 elif re_compat.match(token): 325 if level == 2: 326 fields = [''] 327 token = removesuffix(token, '_t') 328 token = removeprefix(token, 'compat_') 329 elif re.match(r'^evtchn_.*_compat_t$', token): 330 if level == 2 and token != "evtchn_port_compat_t": 331 fields = [''] 332 token = removesuffix(token, '_compat_t') 333 elif re_identifier.match(token): 334 id = token 335 elif token in (',', ';'): 336 if level == 2 and not re_pad.match(id): 337 if len(fields) > 0 and fields[0] == '': 338 fields.pop(0) 339 check_field(kind, name, "%s.%s" % (field, id), fields) 340 if token == ";": 341 fields = [] 342 id = '' 343 if len(fields) > 0: 344 fields.append(token) 345 346def build_check(name, tokens): 347 level = 1 348 fields = [] 349 kind = '' 350 id = '' 351 arrlvl = 1 352 353 print("") 354 print("#define CHECK_%s \\" % (name,)) 355 356 for token in tokens: 357 if token in ('struct', 'union'): 358 if level == 1: 359 kind = token 360 print(" CHECK_SIZE_(%s, %s)" % (kind, name), end='') 361 elif level == 2: 362 fields = [''] 363 elif token == '{': 364 level += 1 365 id = '' 366 elif token == '}': 367 level -= 1 368 id = '' 369 elif token == '[': 370 arrlvl += 1 371 elif token == ']': 372 arrlvl -= 1 373 elif re_compat.match(token): 374 if level == 2 and token != "compat_argo_port_t": 375 fields = [''] 376 token = removesuffix(token, '_t') 377 token = removeprefix(token, 'compat_') 378 elif re_identifier.match(token): 379 if not (level != 2 or arrlvl != 1): 380 id = token 381 elif token in (',', ';'): 382 if level == 2 and not re_pad.match(id): 383 if len(fields) > 0 and fields[0] == '': 384 fields.pop(0) 385 check_field(kind, name, id, fields) 386 if token == ";": 387 fields = [] 388 id = '' 389 390 if len(fields) > 0: 391 fields.append(token) 392 print("") 393 394 395def main(): 396 header_tokens = [] 397 re_tokenazier = re.compile(r'\s+') 398 re_skip_line = re.compile(r'^\s*(#|$)') 399 re_spacer = re.compile(r'([\]\[,;:{}])') 400 401 with open(sys.argv[1]) as header: 402 for line in header: 403 if re_skip_line.match(line): 404 continue 405 line = re_spacer.sub(' \\1 ', line) 406 line = line.strip() 407 header_tokens += re_tokenazier.split(line) 408 409 with open(sys.argv[2]) as compat_list: 410 for line in compat_list: 411 words = re_tokenazier.split(line, maxsplit=1) 412 what = words[0] 413 name = words[1] 414 415 name = removeprefix(name, 'xen') 416 name = name.strip() 417 418 fields = get_fields("compat_%s" % (name,), header_tokens) 419 if len(fields) == 0: 420 raise Exception("Fields of 'compat_%s' not found in '%s'" % (name, sys.argv[1])) 421 422 if what == "!": 423 build_enums(name, fields) 424 build_body(name, fields) 425 elif what == "?": 426 build_check(name, fields) 427 else: 428 raise Exception("Invalid translation indicator: '%s'" % (what,)) 429 430if __name__ == '__main__': 431 main() 432