Ejemplo n.º 1
0
def modinfo(basedir, kernel, module):
    if "." not in module and "/" not in module:
        moddir = os.path.join(basedir, MODULE_DIR, kernel)
        (file, raw) = gzopen(os.path.join(moddir, "modules.dep"))
        with raw:
            for line in file:
                line = line.strip()
                if line.startswith(b"#"):
                    continue
                try:
                    (filename, deps) = line.split(b":", 1)
                except ValueError:
                    continue
                filename = os.fsdecode(filename)
                candidate = basename(filename)
                
                if candidate.find(".") != len(module):
                    continue
                for (i, c) in enumerate(module):
                    if c == ":":
                        continue
                    cc = candidate[i]
                    if c == cc:
                        continue
                    if c in "_-" and cc in "_-":
                        continue
                    break
                else:
                    break
            else:
                msg = "Could not find module {}".format(module)
                raise LookupError(msg)
            
            if os.path.isabs(filename):
                module = os.path.join(basedir, filename[1:])
            else:
                module = os.path.join(moddir, filename)
    
    ret = defaultdict(list, filename=module, params=list())
    param_indexes = dict()
    PARAM_TAGS = (b"parm", b"parmtype")
    with open_elf(module) as modelf:
        for info in elf.iter_strings(modelf, b".modinfo"):
            for tag in PARAM_TAGS:
                if not info.startswith(tag + b"="):
                    continue
                param = info[len(tag) + 1:]
                (param_name, param_info) = param.split(b":", 1)
                
                try:
                    i = param_indexes[param_name]
                except LookupError:
                    i = len(ret["params"])
                    param = dict.fromkeys(PARAM_TAGS)
                    param.update(name=param_name)
                    ret["params"].append(param)
                ret["params"][i][tag] = param_info
                break
            
            else:
                try:
                    (tag, eq) = info.split(b"=", 1)
                except ValueError:
                    msg = '{}: Missing "=" separator in ".modinfo" tag'
                    print(msg.format(module), file=sys.stderr)
                    continue
                
                ret[tag].append(eq)
    
    return ret
Ejemplo n.º 2
0
def depmod(basedir, kver):
    """Only generates the following files (the real "depmod" generates other
    files as well)
        modules.dep
        modules.dep.bin
        modules.alias.bin
        modules.symbols.bin
        modules.devname
    """
    
    verify_version(kver)
    
    dirname = os.path.join(basedir, MODULE_DIR, kver)
    if not os.access(dirname, os.W_OK):
        msg = "WARNING: {}: No write access!".format(dirname)
        print(msg, file=sys.stderr)
    
    print("Scanning modules in", dirname, file=sys.stderr)
    module_files = dict()
    tree = os.walk(dirname, onerror=raiseerror, followlinks=True)
    for (dirpath, dirnames, filenames) in tree:
        #~ print("Scanning", dirpath, file=sys.stderr)
        for f in filenames:
            if not f.endswith((".ko", ".ko.gz")):
                continue
            
            fullpath = os.path.join(dirpath, f)
            pathname = os.path.relpath(fullpath, dirname)
            if f not in module_files:
                module_files[f] = Module(open_elf(fullpath), pathname)
        
        i = 0
        while i < len(dirnames):
            if dirnames[i] in ("source", "build"):
                del dirnames[i]
            else:
                i = i + 1
    
    print('Ordering modules by "modules.order"', file=sys.stderr)
    module_paths = dict((mod.pathname, mod) for mod in module_files.values())
    
    tlist = list()
    file_name = os.path.join(dirname, "modules.order")
    if os.path.exists(file_name):
        with open(file_name, "r") as modorder:
            for (linenum, line) in enumerate(modorder, 1):
                try:
                    mod = module_paths.pop(line)
                except LookupError:
                    continue
                
                mod["order"] = linenum
                tlist.append(mod)
    tlist.extend(module_paths.values())
    
    print("Reading symbols from modules", file=sys.stderr)
    symbol_owners = defaultdict(list)
    for (i, mod) in enumerate(tlist):
        print("{}/{}".format(i, len(tlist)), end="\r", file=sys.stderr)
        with mod.elf as file:
            for sym in elf.iter_strings(file, b"__ksymtab_strings"):
                symbol_owners[sym].append(mod)
            
            strings = file.get_section_by_name(b".strtab")
            syms = file.get_section_by_name(b".symtab")
            if strings is not None and syms is not None:
                tables = dict.fromkeys((
                    b"pci", b"usb", b"ccw", b"ieee1394", b"pnp", b"pnp_card",
                    b"input", b"serio", b"of",
                ))
                
                for sym in syms.iter_symbols():
                    prefix = b"__mod_"
                    suffix = b"_device_table"
                    if (not sym.name.startswith(prefix) or
                    not sym.name.endswith(suffix)):
                        continue
                    name = sym.name[len(prefix):-len(suffix)]
                    if name not in tables or tables[name] is not None:
                        continue
                    
                    sect = file.get_section(sym["st_shndx"])
                    if sect["sh_type"] == "SHT_NOBITS":
                        continue
                    tables[name] = sect["sh_offset"] + sym["st_value"]
    print("{0}/{0}".format(len(tlist)), file=sys.stderr)
    
    print("Reading dependencies of modules", file=sys.stderr)
    for (i, mod) in enumerate(tlist):
        print("{}/{}".format(i, len(tlist)), end="\r", file=sys.stderr)
        with mod.elf as file:
            strings = file.get_section_by_name(b".strtab")
            syms = file.get_section_by_name(b".symtab")
            if strings is None or syms is None:
                msg = '{}: no ".strtab" nor ".symtab" sections'
                print(msg.format(mod.pathname), file=sys.stderr)
                continue
            
            sparc = file["e_machine"] in {"EM_SPARC", "EM_SPARCV9"}
            for sym in syms.iter_symbols():
                if (sym["st_shndx"] != "SHN_UNDEF" or
                sparc and sym["type"] == elf.STT_SPARC_REGISTER):
                    continue
                
                if sym.name.startswith(b"."):
                    lookup = sym.name[1:]
                else:
                    lookup = sym.name
                
                try:
                    # Original "depmod" places later modules at front of hash
                    # table chain, so take latest module here
                    owner = symbol_owners[lookup][-1]
                except LookupError:
                    continue
                
                #~ msg = "{} needs {!r}: {}"
                #~ msg = msg.format(mod.pathname, name, owner.pathname)
                #~ print(msg, file=sys.stderr)
                mod.deps.add(owner)
    print("{0}/{0}".format(len(tlist)), file=sys.stderr)
    
    deps_index = Index()
    print('Generating "modules.dep"', file=sys.stderr)
    with open(os.path.join(dirname, "modules.dep"), "w") as file:
        for (i, mod) in enumerate(tlist):
            dfs_steps = list()
            ancestors = set()
            visited = set()
            postorder = list()
            
            node = mod
            while True:
                dfs_steps.append(dict(
                    node=node, queue=iter(node.deps)))
                ancestors.add(node)
                
                while dfs_steps:
                    current = dfs_steps[-1]
                    try:
                        node = next(current["queue"])
                    except StopIteration:
                        node = current["node"]
                        ancestors.remove(node)
                        visited.add(node)
                        postorder.append(node)
                        dfs_steps.pop()
                    else:
                        if node in ancestors:
                            msg = ("{}: Ignoring cyclic dependency of {} "
                                "on {}")
                            msg = msg.format(mod.pathname,
                                current["node"].pathname, node.pathname)
                            print(msg, file=sys.stderr)
                            continue
                        if node in visited:
                            continue
                        break
                
                if not dfs_steps:
                    break
            
            line = mod.pathname + ":"
            if mod.deps:
                line += " " + " ".join(dep.pathname
                    for dep in reversed(postorder[:-1]))
            file.write(line)
            file.write("\n")
            
            deps_index.add(modname(mod.pathname), line.encode("ASCII"),
                mod.order)
    
    print('Writing "modules.dep.bin"', file=sys.stderr)
    deps_index.write(dirname, "modules.dep.bin")
    
    print('Generating "modules.alias.bin"', file=sys.stderr)
    alias_index = Index()
    for (i, mod) in enumerate(tlist):
        print("{}/{}".format(i, len(tlist)), end="\r", file=sys.stderr)
        
        name = modname(mod.pathname)
        with mod.elf as file:
            for alias in elf.iter_strings(file, b".modalias"):
                alias_index.add(underscores(alias), name, mod.order)
            
            for p in elf.iter_strings(file, b".modinfo"):
                prefix = b"alias="
                if not p.startswith(prefix):
                    continue
                alias = p[len(prefix):]
                alias_index.add(underscores(alias), name, mod.order)
    print("{0}/{0}".format(len(tlist)), file=sys.stderr)
    alias_index.write(dirname, "modules.alias.bin")
    
    print('Writing "modules.symbols.bin"', file=sys.stderr)
    symbols_index = Index()
    for (name, owners) in symbol_owners.items():
        # Owners list should be ordered according to modules.order
        for owner in owners:
            symbols_index.add(b"symbol:" + name,
                modname(owner.pathname), owner.order)
    symbols_index.write(dirname, "modules.symbols.bin")
    
    print('Writing "modules.devname"', file=sys.stderr)
    with open(os.path.join(dirname, "modules.devname"), "wb") as outfile:
        for (i, mod) in enumerate(tlist):
            print("{}/{}".format(i, len(tlist)), end="\r", file=sys.stderr)
            devname = None
            devid = None
            with mod.elf as modfile:
                for info in elf.iter_strings(modfile, b".modinfo"):
                    if not info.startswith(b"alias="):
                        continue
                    if info.startswith(b"devname:", 6):
                        devname = info[6 + 8:]
                    for type in (b"char", b"block"):
                        prefix = type + b"-major-"
                        if not info.startswith(prefix, 6):
                            continue
                        majorminor = info[6 + len(prefix):]
                        try:
                            (major, minor) = majorminor.split(b"-", 1)
                            major = int(major)
                            minor = minor.decode("ascii", "replace")
                            (minor, _) = slice_int(minor)
                        except ValueError:
                            break
                        devid = "{:c}{}:{}".format(type[0], major, minor)
                        break
                    if devname is not None and devid is not None:
                        break
            if devname is not None:
                if devid is None:
                    msg = ("{}: Ignoring devname "
                        "without major and minor identifiers")
                    print(msg.format(mod.pathname), file=sys.stderr)
                else:
                    outfile.write(modname(mod.pathname))
                    outfile.write(b" ")
                    outfile.write(devname)
                    outfile.write(b" ")
                    outfile.write(devid.encode("ascii"))
                    outfile.write(b"\n")
    print("{0}/{0}".format(len(tlist)), file=sys.stderr)