import sys import os import operator if len(sys.argv) != 2: sys.stderr.write("Wrong number of argmuments. Wanted one, the name of the\ arch to use, got %s" % sys.argv) arch = sys.argv[1] f = open(os.path.join(arch, 'ioctl_list')) # found by find_ioctls.py m = open(os.path.join(arch, 'manually_found')) # found by the Mach V Eyeball i = open(os.path.join(arch, 'ignore_list')) # removed from the output of find_ioctls.py print("// Initially generated by process_ioctls.py") consts = { "mips": { "NONE": 1, "READ": 2, "WRITE": 4, "SIZEBITS": 13, "DIRBITS": 3}, "powerpc": { "NONE": 1, "READ": 2, "WRITE": 4, "SIZEBITS": 13, "DIRBITS": 3}, "x86": { "NONE": 0, "READ": 2, "WRITE": 1, "SIZEBITS": 14, "DIRBITS": 2}, "x86_64": { "NONE": 0, "READ": 2, "WRITE": 1, "SIZEBITS": 14, "DIRBITS": 2}, "arm": { "NONE": 0, "READ": 2, "WRITE": 1, "SIZEBITS": 14, "DIRBITS": 2}, "aarch64": { "NONE": 0, "READ": 2, "WRITE": 1, "SIZEBITS": 14, "DIRBITS": 2}, } ioc_consts = { "SIOCPROTOPRIVATE": 0x89E0, "SIOCDEVPRIVATE": 0x89F0, "PCIIOC_BASE": (ord('P') << 24 | ord('C') << 16 | ord('I') << 8), "FIONREAD": 0x541B, "CZIOC": ord('M') << 8, "TIOCOUTQ": 0x5411, "TIOCM_CAR": 0x040, "TIOCM_RNG": 0x080, } NONE = consts[arch]["NONE"] READ = consts[arch]["READ"] WRITE = consts[arch]["WRITE"] SIZEBITS = consts[arch]["SIZEBITS"] DIRBITS = consts[arch]["DIRBITS"] NRBITS = 8 TYPEBITS = 8 NRSHIFT = 0 TYPESHIFT = NRSHIFT + NRBITS SIZESHIFT = TYPESHIFT + SIZEBITS DIRSHIFT = SIZESHIFT + DIRBITS NRMASK = (1 << NRBITS) - 1 TYPEMASK = (1 << TYPEBITS) - 1 SIZEMASK = (1 << SIZEBITS) - 1 DIRMASK = (1 << DIRBITS) - 1 def decode(val): return (((val >> DIRSHIFT) & DIRMASK), ((val >> TYPESHIFT) & TYPEMASK), ((val >> NRSHIFT) & NRMASK), ((val >> SIZESHIFT) & SIZEMASK)) ioctls = [] # ones we want to actually process for ioctl in f: ioctls.append(eval(ioctl)) for ioctl in m: ioctls.append(eval(ioctl)) mp = { "_IO": "none", "_IOR": "read", "_IOW": "write", "_IOWR": "readwrite", "DRM_IO": "none", "DRM_IOR": "read", "DRM_IOW": "write", "DRM_IOWR": "readwrite"} tys = { "__uint8_t": "u8", "__uint16": "u16", "__uint32_t": "u32", "__uint64_t": "u64", "__int8_t": "i8", "__int16": "i16", "__int32_t": "i32", "__int64_t": "i64", "uint8_t": "u8", "uint16": "u16", "uint32_t": "u32", "uint64_t": "u64", "int8_t": "i8", "int16": "i16", "int32_t": "i32", "int64_t": "i64", "__u8": "u8", "__u16": "u16", "__u32": "u32", "__u64": "u64", "__s8": "i8", "__s16": "i16", "__s32": "i32", "__s64": "i64", "int": "::libc::c_int", "long": "::libc::c_long", "char": "::libc::c_char", "size_t": "::libc::size_t", } utys = { "int": "::libc::c_uint", "long": "::libc::c_ulong", "char": "::libc::c_uchar", } known_structs = ["input_id", "ff_effect", "ff_trigger", "ff_replay"] manually_bound = ["EVIOCGNAME", "EVIOCGPHYS", "EVIOCGUNIQ", "EVIOCGPROP", "EVIOCGMTSLOTS", "EVIOCGKEY", "EVIOCGLED", "EVIOCGSND", "EVIOCGSW", "EVIOCGBIT", "EVIOCGABS", "EVIOCSABS", "EVIOCGRAB", "EVIOCREVOKE", "EVIOCSCLOCKID"] bad_recovery = {} def translate(ty): if len(ty) == 1: return tys.get(ty[0], "FIXME1<%s>" % ty) elif ty[-1] == '*': return "*mut " + translate(ty[:-1]) elif len(ty) == 2: if ty[0] == "struct": return "/*struct*/ %s" % ty[1] elif ty[0] == "unsigned": return utys[ty[1]] else: return "FIXME2<%s>" % ty elif ty[-1] == ']': count = ty[-2] return "[%s; %s]" % (translate(ty[:-3]), count) else: return "FIXME3<%s>" % ty def translate_type_code(ty): if ty[0] == "'": return "b" + ty else: return ty def bad(name, val): if name in bad_recovery: process(bad_recovery[name]) else: pval = None try: pval = int(val, 0) except: pass if pval is None: print("ioctl!(bad %s with %s);" % (name.lower(), val)) else: (dr, ty, nr, sz) = decode(pval) if dr == NONE: print("ioctl!(none %s with %s, %s);" % (name.lower(), ty, nr)) elif dr == READ: print("ioctl!(read %s with %s, %s; [u8; %s]);" % (name.lower(), ty, nr, sz)); elif dr == WRITE: print("ioctl!(write %s with %s, %s; [u8; %s]);" % (name.lower(), ty, nr, sz)); elif dr == READ|WRITE: print("ioctl!(readwrite %s with %s, %s; [u8; %s]);" % (name.lower(), ty, nr, sz)); else: raise "This really shouldn't happen" def bad2(name, val1, val2, op): if val1 in ioc_consts: val1 = ioc_consts[val1] else: val1 = int(val1, 0) if val2 in ioc_consts: val2 = ioc_consts[val2] else: val2 = int(val2, 0) bad(name, str(op(val1, val2))) def process(ioctl): name = ioctl[0] rhs = ioctl[1:-1] # remove '#' or trailing comment cmd = rhs[0] body = rhs[2:-1] if name in manually_bound: return elif cmd == "_IO": print("ioctl!(none %s with %s, %s);" % (name.lower(), translate_type_code(body[0]), body[2])) elif cmd == '_IOR' or cmd == '_IOW' or cmd == '_IOWR': if body[3] == ',': # this looks like _IOR(X, B, type...) first = body[0] second = body[2] ty = body[4:] ty = translate(ty) if "FIXME" in ty or "/*struct*/" in ty and not ty[11:] in known_structs: print("// ioctl!(%s %s with %s, %s; %s);" % (mp[cmd], name.lower(), translate_type_code(first), second, ty)) else: print("ioctl!(%s %s with %s, %s; %s);" % (mp[cmd], name.lower(), translate_type_code(first), second, ty)) elif body[3] == '+': first = body[0] second = " ".join(body[2:5]) ty = body[6:] ty = translate(ty) if "FIXME" in ty or "/*struct*/" in ty and not ty[11:] in known_structs: print("// ioctl!(%s %s with %s, %s; %s);" % (mp[cmd], name.lower(), translate_type_code(first), second, ty)) else: print("ioctl!(%s %s with %s, %s; %s);" % (mp[cmd], name.lower(), translate_type_code(first), second, ty)) # We probably have _IOR(X, B + C, type...) else: raise "This really shouldn't happen" elif cmd == "DRM_IO" or cmd == "DRM_IOR" or cmd == "DRM_IOW" or cmd == "DRM_IOWR": # rewrite into "canonical" version. process([name, cmd[3:], "(", "DRM_IOCTL_BASE", ","] + rhs[2:] + ["#"]) elif len(rhs) == 1: # single constant :( bad(name.lower(), ioc_consts.get(rhs[0], rhs[0])) elif len(rhs) == 3 and rhs[0] == "(": # single constant in parens bad(name.lower(), ioc_consts.get(rhs[1], rhs[1])) elif rhs[2] == "+": # we have the sum of two constants try: bad2(name.lower(), rhs[1], rhs[3], operator.add) except: bad(name.lower(), " ".join(rhs[1:-1])) elif rhs[2] == "|": # we have an or of two constants (eugh) try: bad2(name.lower(), rhs[1], rhs[3], operator.or_) except: bad(name.lower(), " ".join(rhs[1:-1])) else: print("// TODO #define %s %s" % (name, " ".join(rhs))) for ioctl in ioctls: process(ioctl)