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
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)