commit 4b9ae46e44cd6426064cc64d48777aa1a7fff4ee Author: Bastian Blank Date: Tue Mar 28 21:46:39 2006 +0000 /dists/trunk/linux-kbuild-2.6: Add. svn path=/dists/trunk/linux-kbuild-2.6/; revision=6325 diff --git a/debian/bin/gencontrol.py b/debian/bin/gencontrol.py new file mode 100755 index 000000000..9fcb535df --- /dev/null +++ b/debian/bin/gencontrol.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python2.4 +import sys +sys.path.append("debian/lib/python") +import warnings +from debian_linux.debian import * +from debian_linux.utils import * + +class packages_list(sorted_dict): + def append(self, package): + self[package['Package']] = package + + def extend(self, packages): + for package in packages: + self[package['Package']] = package + +class gencontrol(object): + makefile_targets = ('binary-arch', 'build') + + def __init__(self, underlay = None): + self.changelog = read_changelog() + self.templates = templates() + self.version, self.changelog_vars = self.process_changelog({}) + + def __call__(self): + packages = packages_list() + makefile = [] + + self.do_source(packages) + self.do_main(packages, makefile) + + self.write_control(packages.itervalues()) + self.write_makefile(makefile) + + def do_source(self, packages): + source = self.templates["control.source"] + packages['source'] = self.process_package(source[0], self.changelog_vars) + + def do_main(self, packages, makefile): + makeflags = { + 'VERSION': self.version['version'], + 'SOURCE_UPSTREAM': self.version['source_upstream'], + 'SOURCEVERSION': self.version['source'], + 'UPSTREAMVERSION': self.version['upstream'], + } + + vars = self.changelog_vars.copy() + + self.do_main_setup(vars, makeflags) + self.do_main_packages(packages) + self.do_main_makefile(makefile, makeflags) + + def do_main_setup(self, vars, makeflags): + pass + + def do_main_makefile(self, makefile, makeflags): + makeflags_string = ' '.join(["%s='%s'" % i for i in makeflags.iteritems()]) + + for i in self.makefile_targets: + makefile.append(("%s:" % i, ("$(MAKE) -f debian/rules.real %s %s" % (i, makeflags_string)))) + + def do_main_packages(self, packages): + vars = self.changelog_vars + + main = self.templates["control.main"] + packages.extend(self.process_packages(main, vars)) + + def process_changelog(self, in_vars): + ret = [None, None] + ret[0] = version = self.changelog[0]['Version'] + vars = in_vars.copy() + vars['upstreamversion'] = version['upstream'] + vars['version'] = version['version'] + vars['source_upstream'] = version['source_upstream'] + vars['major'] = version['major'] + ret[1] = vars + return ret + + def process_relation(self, key, e, in_e, vars): + in_dep = in_e[key] + dep = package_relation_list() + for in_groups in in_dep: + groups = package_relation_group() + for in_item in in_groups: + item = package_relation() + item.name = self.substitute(in_item.name, vars) + if in_item.version is not None: + item.version = self.substitute(in_item.version, vars) + item.arches = in_item.arches + groups.append(item) + dep.append(groups) + e[key] = dep + + def process_description(self, e, in_e, vars): + in_desc = in_e['Description'] + desc = in_desc.__class__() + desc.short = self.substitute(in_desc.short, vars) + for i in in_desc.long: + desc.long.append(self.substitute(i, vars)) + e['Description'] = desc + + def process_package(self, in_entry, vars): + e = package() + for key, value in in_entry.iteritems(): + if isinstance(value, package_relation_list): + self.process_relation(key, e, in_entry, vars) + elif key == 'Description': + self.process_description(e, in_entry, vars) + elif key[:2] == 'X-': + pass + else: + e[key] = self.substitute(value, vars) + return e + + def process_packages(self, in_entries, vars): + entries = [] + for i in in_entries: + entries.append(self.process_package(i, vars)) + return entries + + def substitute(self, s, vars): + if isinstance(s, (list, tuple)): + for i in xrange(len(s)): + s[i] = self.substitute(s[i], vars) + return s + def subst(match): + return vars[match.group(1)] + return re.sub(r'@([a-z_]+)@', subst, s) + + def write_control(self, list): + self.write_rfc822(file("debian/control", 'w'), list) + + def write_makefile(self, out_list): + out = file("debian/rules.gen", 'w') + for item in out_list: + if isinstance(item, (list, tuple)): + out.write("%s\n" % item[0]) + cmd_list = item[1] + if isinstance(cmd_list, basestring): + cmd_list = cmd_list.split('\n') + for j in cmd_list: + out.write("\t%s\n" % j) + else: + out.write("%s\n" % item) + + def write_rfc822(self, f, list): + for entry in list: + for key, value in entry.iteritems(): + f.write("%s: %s\n" % (key, value)) + f.write('\n') + + +if __name__ == '__main__': + gencontrol()() diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 000000000..7bc4bc4f4 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +linux-kbuild-2.6 (2.6.16-1) UNRELEASED; urgency=low + + * Initial release. + + -- Bastian Blank Mon, 27 Mar 2006 19:06:30 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 000000000..b8626c4cf --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/lib/python/debian_linux/__init__.py b/debian/lib/python/debian_linux/__init__.py new file mode 100644 index 000000000..b989d7d15 --- /dev/null +++ b/debian/lib/python/debian_linux/__init__.py @@ -0,0 +1,3 @@ +from debian import * +from utils import * + diff --git a/debian/lib/python/debian_linux/debian.py b/debian/lib/python/debian_linux/debian.py new file mode 100644 index 000000000..2b83362c7 --- /dev/null +++ b/debian/lib/python/debian_linux/debian.py @@ -0,0 +1,231 @@ +import itertools, os.path, re, utils + +def read_changelog(dir = ''): + r = re.compile(r""" +^ +( +(?P
+ (?P + \w[-+0-9a-z.]+ + ) + \ + \( + (?P + [^\(\)\ \t]+ + ) + \) + \s+ + (?P + [-0-9a-zA-Z]+ + ) + \; +) +) +""", re.VERBOSE) + f = file(os.path.join(dir, "debian/changelog")) + entries = [] + act_upstream = None + while True: + line = f.readline() + if not line: + break + line = line.strip('\n') + match = r.match(line) + if not match: + continue + if match.group('header'): + e = {} + e['Distribution'] = match.group('header_distribution') + e['Source'] = match.group('header_source') + version = parse_version(match.group('header_version')) + e['Version'] = version + if act_upstream is None: + act_upstream = version['upstream'] + elif version['upstream'] != act_upstream: + break + entries.append(e) + return entries + +def parse_version(version): + version_re = ur""" +^ +(?P + (?P + \d+\.\d+\.\d+\+ + )? + (?P + (?P + (?P\d+\.\d+) + \. + \d+ + ) + (?: + - + (?P + .+? + ) + )? + ) + - + (?P[^-]+) +) +$ +""" + match = re.match(version_re, version, re.X) + if match is None: + raise ValueError + ret = match.groupdict() + if ret['parent'] is not None: + ret['source_upstream'] = ret['parent'] + ret['upstream'] + else: + ret['source_upstream'] = ret['upstream'] + return ret + +class package_description(object): + __slots__ = "short", "long" + + def __init__(self, value = None): + if value is not None: + self.short, long = value.split ("\n", 1) + self.long = long.split ("\n.\n") + else: + self.short = None + self.long = [] + + def __str__(self): + ret = self.short + '\n' + w = utils.wrap(width = 74, fix_sentence_endings = True) + pars = [] + for i in self.long: + pars.append('\n '.join(w.wrap(i))) + return self.short + '\n ' + '\n .\n '.join(pars) + +class package_relation(object): + __slots__ = "name", "version", "arches" + + _re = re.compile(r'^(\S+)(?: \(([^)]+)\))?(?: \[([^]]+)\])?$') + + def __init__(self, value = None): + if value is not None: + match = self._re.match(value) + if match is None: + raise RuntimeError, "Can't parse dependency %s" % value + match = match.groups() + self.name = match[0] + self.version = match[1] + if match[2] is not None: + self.arches = re.split('\s+', match[2]) + else: + self.arches = [] + else: + self.name = None + self.version = None + self.arches = [] + + def __str__(self): + ret = [self.name] + if self.version is not None: + ret.extend([' (', self.version, ')']) + if self.arches: + ret.extend([' [', ' '.join(self.arches), ']']) + return ''.join(ret) + +class package_relation_list(list): + def __init__(self, value = None): + if isinstance(value, (list, tuple)): + self.extend(value) + elif value is not None: + self.extend(value) + + def __str__(self): + return ', '.join([str(i) for i in self]) + + def _match(self, value): + for i in self: + if i._match(value): + return i + return None + + def extend(self, value): + if isinstance(value, basestring): + value = [package_relation_group(j.strip()) for j in re.split(',', value.strip())] + for i in value: + if isinstance(i, basestring): + i = package_relation_group(i) + j = self._match(i) + if j: + j._update_arches(i) + else: + self.append(i) + +class package_relation_group(list): + def __init__(self, value = None): + if isinstance(value, package_relation_list): + self.extend(value) + elif value is not None: + self._extend(value) + + def __str__(self): + return ' | '.join([str(i) for i in self]) + + def _extend(self, value): + self.extend([package_relation(j.strip()) for j in re.split('\|', value.strip())]) + + def _match(self, value): + for i, j in itertools.izip(self, value): + if i.name != j.name or i.version != j.version: + return None + return self + + def _update_arches(self, value): + for i, j in itertools.izip(self, value): + if i.arches: + for arch in j.arches: + if arch not in i.arches: + i.arches.append(arch) + +class package(dict): + _fields = utils.sorted_dict(( + ('Package', str), + ('Source', str), + ('Architecture', utils.field_list), + ('Section', str), + ('Priority', str), + ('Maintainer', str), + ('Uploaders', str), + ('Standards-Version', str), + ('Build-Depends', package_relation_list), + ('Build-Depends-Indep', package_relation_list), + ('Provides', package_relation_list), + ('Depends', package_relation_list), + ('Recommends', package_relation_list), + ('Suggests', package_relation_list), + ('Replaces', package_relation_list), + ('Conflicts', package_relation_list), + ('Reverse-Depends', package_relation_list), # Some sort of hack + ('Description', package_description), + )) + + def __setitem__(self, key, value): + try: + cls = self._fields[key] + if not isinstance(value, cls): + value = cls(value) + except KeyError: pass + super(package, self).__setitem__(key, value) + + def iterkeys(self): + for i in self._fields.iterkeys(): + if self.has_key(i) and self[i]: + yield i + + def iteritems(self): + for i in self._fields.iterkeys(): + if self.has_key(i) and self[i]: + yield (i, self[i]) + + def itervalues(self): + for i in self._fields.iterkeys(): + if self.has_key(i) and self[i]: + yield self[i] + diff --git a/debian/lib/python/debian_linux/utils.py b/debian/lib/python/debian_linux/utils.py new file mode 100644 index 000000000..1519e4ebb --- /dev/null +++ b/debian/lib/python/debian_linux/utils.py @@ -0,0 +1,136 @@ +import debian, re, textwrap + +class sorted_dict(dict): + __slots__ = '_list', + + def __init__(self, entries = None): + super(sorted_dict, self).__init__() + self._list = [] + if entries is not None: + for key, value in entries: + self[key] = value + + def __delitem__(self, key): + super(sorted_dict, self).__delitem__(key) + self._list.remove(key) + + def __setitem__(self, key, value): + super(sorted_dict, self).__setitem__(key, value) + if key not in self._list: + self._list.append(key) + + def iterkeys(self): + for i in iter(self._list): + yield i + + def iteritems(self): + for i in iter(self._list): + yield (i, self[i]) + + def itervalues(self): + for i in iter(self._list): + yield self[i] + +class field_list(list): + TYPE_WHITESPACE = object() + TYPE_COMMATA = object() + + def __init__(self, value = None, type = TYPE_WHITESPACE): + self.type = type + if isinstance(value, field_list): + self.type = value.type + self.extend(value) + elif isinstance(value, (list, tuple)): + self.extend(value) + else: + self._extend(value) + + def __str__(self): + if self.type is self.TYPE_WHITESPACE: + type = ' ' + elif self.type is self.TYPE_COMMATA: + type = ', ' + return type.join(self) + + def _extend(self, value): + if self.type is self.TYPE_WHITESPACE: + type = '\s' + elif self.type is self.TYPE_COMMATA: + type = ',' + if value is not None: + self.extend([j.strip() for j in re.split(type, value.strip())]) + + def extend(self, value): + if isinstance(value, str): + self._extend(value) + else: + super(field_list, self).extend(value) + +class field_list_commata(field_list): + def __init__(self, value = None): + super(field_list_commata, self).__init__(value, field_list.TYPE_COMMATA) + +class field_string(str): + def __str__(self): + return '\n '.join(self.split('\n')) + +class templates(dict): + def __init__(self, dir = None): + if dir is None: + self.dir = "debian/templates" + else: + self.dir = dir + + def __getitem__(self, key): + try: + return dict.__getitem__(self, key) + except KeyError: pass + ret = self._read(key) + dict.__setitem__(self, key, ret) + return ret + + def __setitem__(self, key, value): + raise NotImplemented() + + def _read(self, filename): + entries = [] + + f = file("%s/%s.in" % (self.dir, filename)) + + while True: + e = debian.package() + last = None + lines = [] + while True: + line = f.readline() + if not line: + break + line = line.strip('\n') + if not line: + break + if line[0] in ' \t': + if not last: + raise ValueError('Continuation line seen before first header') + lines.append(line.lstrip()) + continue + if last: + e[last] = '\n'.join(lines) + i = line.find(':') + if i < 0: + raise ValueError("Not a header, not a continuation: ``%s''" % line) + last = line[:i] + lines = [line[i+1:].lstrip()] + if last: + e[last] = '\n'.join(lines) + if not e: + break + + entries.append(e) + + return entries + +class wrap(textwrap.TextWrapper): + wordsep_re = re.compile( + r'(\s+|' # any whitespace + r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash + diff --git a/debian/rules b/debian/rules new file mode 100755 index 000000000..35f00e297 --- /dev/null +++ b/debian/rules @@ -0,0 +1,73 @@ +#!/usr/bin/make -f +SHELL := sh -e +DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH) +DEB_BUILD_ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH) +srcver := $(shell dpkg-parsechangelog | awk '/^Version:/ {print $$2}') +VERSION := $(shell echo $(srcver) | sed -e 's,-[^-]*$$,,') +MAJOR := $(word 1,$(subst ., ,$(VERSION))).$(word 2,$(subst ., ,$(VERSION))) + +include debian/rules.defs + +build: debian/control $(STAMPS_DIR)/build-base +$(STAMPS_DIR)/build-base: $(BUILD_DIR) $(STAMPS_DIR) + dh_testdir + $(MAKE) -f debian/rules.gen build + touch $@ + +$(BUILD_DIR) $(STAMPS_DIR): + @[ -d $@ ] || mkdir $@ + +orig: ../orig/linux-kbuild-$(MAJOR)-$(VERSION) + rsync --delete --exclude debian --exclude .svn --link-dest=$^/ -av $^/ . + +../orig/linux-kbuild-$(MAJOR)-$(VERSION): + if [ -f "../linux-kbuild-$(MAJOR)_$(VERSION).orig.tar.gz" ]; then \ + mkdir -p ../orig; \ + tar -C ../orig -xzf ../linux-kbuild-$(MAJOR)_$(VERSION).orig.tar.gz; \ + else \ + echo "Can't find orig tarball." >&2; \ + exit 1; \ + fi + +maintainerclean: + -rm debian/control debian/control.md5sum debian/rules.gen + -rm -rf scripts + +clean: debian/control + dh_testdir + rm -rf $(BUILD_DIR) $(STAMPS_DIR) debian/lib/python/debian_linux/*.pyc + dh_clean + +binary-indep: + dh_testdir + $(MAKE) -f debian/rules.gen binary-indep + +binary-arch: + dh_testdir + $(MAKE) -f debian/rules.gen binary-arch + +binary: binary-indep binary-arch + +CONTROL_FILES = debian/changelog $(wildcard debian/templates/control.*) +debian/control debian/rules.gen: debian/bin/gencontrol.py $(CONTROL_FILES) + if [ -f debian/control.md5sum ]; then \ + if md5sum $^ | diff - debian/control.md5sum > /dev/null; then true; else \ + $(MAKE) -f debian/rules debian/control-real; \ + fi \ + else \ + $(MAKE) -f debian/rules debian/control-real; \ + fi + +debian/control-real: debian/bin/gencontrol.py $(CONTROL_FILES) + chmod +x $< + $< + md5sum $^ > debian/control.md5sum + @echo + @echo This target is made to fail intentionally, to make sure + @echo that it is NEVER run during the automated build. Please + @echo ignore the following error, the debian/control file has + @echo been generated SUCCESSFULLY. + @echo + exit 1 + +.PHONY: clean build setup binary-indep binary-arch binary diff --git a/debian/rules.defs b/debian/rules.defs new file mode 100644 index 000000000..06b3f3edb --- /dev/null +++ b/debian/rules.defs @@ -0,0 +1,4 @@ +BUILD_DIR = debian/build +STAMPS_DIR = debian/stamps +TEMPLATES_DIR = debian/templates + diff --git a/debian/rules.real b/debian/rules.real new file mode 100644 index 000000000..636cc6496 --- /dev/null +++ b/debian/rules.real @@ -0,0 +1,37 @@ +export DH_OPTIONS + +include debian/rules.defs + +binary-arch: install-kbuild + +build: $(STAMPS_DIR)/build + +$(STAMPS_DIR)/build: DIR=$(BUILD_DIR)/build +$(STAMPS_DIR)/build: + rm -rf '$(DIR)' + mkdir -p '$(DIR)' + cp -al src/* '$(DIR)' + make -C $(DIR) top_srcdir=$(CURDIR) + touch '$@' + +install-kbuild: PACKAGE_NAME = linux-kbuild-$(VERSION) +install-kbuild: DH_OPTIONS = -p$(PACKAGE_NAME) +install-kbuild: BASE_DIR = /usr/src/$(PACKAGE_NAME) +install-kbuild: SOURCE_DIR = $(BUILD_DIR)/build +install-kbuild: DIR = $(CURDIR)/debian/$(PACKAGE_NAME)/$(BASE_DIR) +install-kbuild: $(STAMPS_DIR)/build + dh_testdir + dh_testroot + dh_clean -k -d + make -C $(SOURCE_DIR) install prefix=$(DIR) top_srcdir=$(CURDIR) + dh_installchangelogs + dh_installdocs + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + diff --git a/debian/templates/control.main.in b/debian/templates/control.main.in new file mode 100644 index 000000000..d22603e7a --- /dev/null +++ b/debian/templates/control.main.in @@ -0,0 +1,7 @@ +Package: linux-kbuild-@version@ +Architecture: any +Section: devel +Priority: optional +Provides: linux-kbuild, linux-kbuild-@major@ +Description: Linux kernel + Kbuild diff --git a/debian/templates/control.source.in b/debian/templates/control.source.in new file mode 100644 index 000000000..d9c910587 --- /dev/null +++ b/debian/templates/control.source.in @@ -0,0 +1,7 @@ +Source: linux-kbuild-@major@ +Section: devel +Priority: optional +Maintainer: Debian Kernel Team +Uploaders: Bastian Blank +Standards-Version: 3.6.2.0 +Build-Depends: debhelper (>= 4.1.0) diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 000000000..59c897e78 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,56 @@ +include Makefile.inc + +PROGS = \ + bin2c \ + conmakehash \ + kallsyms \ + pnmtologo + +SCRIPTS = \ + checkconfig.pl \ + checkincludes.pl \ + checkstack.pl \ + checkversion.pl \ + gcc-version.sh \ + gen_initramfs_list.sh \ + Kbuild.include \ + kernel-doc \ + Lindent \ + Makefile.build \ + Makefile.clean \ + Makefile.host \ + Makefile.lib \ + Makefile.modinst \ + Makefile.modpost \ + makelst \ + mksysmap \ + mkuboot.sh \ + mkversion \ + namespace.pl \ + patch-kernel \ + reference_discarded.pl \ + reference_init.pl \ + setlocalversion \ + show_delta \ + ver_linux + +SUBDIRS = \ + basic \ + genksyms \ + kconfig \ + mod + +VPATH = $(top_srcdir)/scripts + +all-local: $(PROGS) + +install-local: $(PROGS) + @list='$(PROGS)'; for p in $$list; do \ + echo " install -D '$$p' '$(prefix)/scripts/$$p'"; \ + install -D "$$p" "$(prefix)/scripts/$$p"; \ + done + @list='$(SCRIPTS)'; for p in $$list; do \ + echo " install -D '$(top_srcdir)/scripts/$$p' '$(prefix)/scripts/$$p'"; \ + install -D "$(top_srcdir)/scripts/$$p" "$(prefix)/scripts/$$p"; \ + done + diff --git a/src/Makefile.inc b/src/Makefile.inc new file mode 100644 index 000000000..54694b90f --- /dev/null +++ b/src/Makefile.inc @@ -0,0 +1,17 @@ +CC = gcc +CXX = g++ +CFLAGS = -Wall -W -O2 +CXXFLAGS = $(CFLAGS) + +all: all-local all-recursive +install: install-local install-recursive + +all-recursive install-recursive: + @target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + $(MAKE) -C $$subdir $$target \ + || exit 1; \ + done + diff --git a/src/basic/Makefile b/src/basic/Makefile new file mode 100644 index 000000000..9e2eee865 --- /dev/null +++ b/src/basic/Makefile @@ -0,0 +1,17 @@ +include ../Makefile.inc + +PROGS = \ + docproc \ + fixdep \ + split-include + +VPATH = $(top_srcdir)/scripts/basic + +all-local: $(PROGS) + +install-local: $(PROGS) + @list='$(PROGS)'; for p in $$list; do \ + echo " install -D '$$p' '$(prefix)/scripts/basic/$$p'"; \ + install -D "$$p" "$(prefix)/scripts/basic/$$p"; \ + done + diff --git a/src/genksyms/Makefile b/src/genksyms/Makefile new file mode 100644 index 000000000..e53e29239 --- /dev/null +++ b/src/genksyms/Makefile @@ -0,0 +1,25 @@ +include ../Makefile.inc + +PROGS = genksyms + +VPATH = $(top_srcdir)/scripts/genksyms + +CFLAGS += -I$(top_srcdir)/scripts/genksyms + +all-local: $(PROGS) + +install-local: $(PROGS) + @list='$(PROGS)'; for p in $$list; do \ + echo " install -D '$$p' '$(prefix)/scripts/genksyms/$$p'"; \ + install -D "$$p" "$(prefix)/scripts/genksyms/$$p"; \ + done + +genksyms: genksyms.o parse.o lex.o + +lex.o: keywords.c parse.h + +%.c: %.c_shipped + ln -s $< $@ + +%.h: %.h_shipped + ln -s $< $@ diff --git a/src/kconfig/Makefile b/src/kconfig/Makefile new file mode 100644 index 000000000..b282b9c0a --- /dev/null +++ b/src/kconfig/Makefile @@ -0,0 +1,25 @@ +include ../Makefile.inc + +PROGS = conf + +VPATH = $(top_srcdir)/scripts/kconfig + +CFLAGS += -I$(top_srcdir)/scripts/kconfig + +all-local: $(PROGS) + +install-local: $(PROGS) + @list='$(PROGS)'; for p in $$list; do \ + echo " install -D '$$p' '$(prefix)/scripts/kconfig/$$p'"; \ + install -D "$$p" "$(prefix)/scripts/kconfig/$$p"; \ + done + +conf: conf.o zconf.tab.o + +zconf.tab.c: zconf.hash.c lex.zconf.c + +%.c: %.c_shipped + ln -s $< $@ + +%.h: %.h_shipped + ln -s $< $@ diff --git a/src/mod/Makefile b/src/mod/Makefile new file mode 100644 index 000000000..7b842c788 --- /dev/null +++ b/src/mod/Makefile @@ -0,0 +1,17 @@ +include ../Makefile.inc + +PROGS = modpost + +all-local: $(PROGS) + +install-local: $(PROGS) + @list='$(PROGS)'; for p in $$list; do \ + echo " install -D '$$p' '$(prefix)/scripts/mod/$$p'"; \ + install -D "$$p" "$(prefix)/scripts/mod/$$p"; \ + done + +modpost: elf.o modpost.o module.o module_devicetable.o module_devicetable_impl_2_6_16.o + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ + +%.o: %.cpp %.hpp endian.hpp + diff --git a/src/mod/elf.cpp b/src/mod/elf.cpp new file mode 100644 index 000000000..bab5f9cb9 --- /dev/null +++ b/src/mod/elf.cpp @@ -0,0 +1,243 @@ +/* + * elf.cpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "elf.hpp" +#include "endian.hpp" + +#include + +#include +#include +#include +#include + +using namespace Elf; + +namespace +{ + template + struct _elfdef + { }; + + template <> + struct _elfdef + { + typedef Elf32_Ehdr Ehdr; + typedef Elf32_Shdr Shdr; + typedef Elf32_Sym Sym; + static inline uint8_t st_bind (uint8_t st_info) throw () { return ELF32_ST_BIND (st_info); } + static inline uint8_t st_type (uint8_t st_info) throw () { return ELF32_ST_TYPE (st_info); } + }; + + template <> + struct _elfdef + { + typedef Elf64_Ehdr Ehdr; + typedef Elf64_Shdr Shdr; + typedef Elf64_Sym Sym; + static inline uint8_t st_bind (uint8_t st_info) throw () { return ELF64_ST_BIND (st_info); } + static inline uint8_t st_type (uint8_t st_info) throw () { return ELF64_ST_TYPE (st_info); } + }; +} + +file::file (const char *filename, void *mem, size_t len) throw (std::bad_alloc) +: filename (std::string (filename)), mem (mem), len (len) +{ } + +file::~file () throw () +{ + ::munmap (mem, len); + for (std::vector
::iterator it = sections.begin (); it != sections.end (); ++it) + delete *it; +} + +file *file::open (const char *filename) throw (std::bad_alloc, std::runtime_error) +{ + struct stat buf; + int fd; + void *mem; + size_t len; + if ((fd = ::open (filename, O_RDONLY)) == -1) + throw std::runtime_error ("mapping failed"); + try + { + if (::fstat (fd, &buf) == -1) + throw std::runtime_error ("mapping failed"); + len = buf.st_size; + if ((mem = ::mmap (0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED) + throw std::runtime_error ("mapping failed"); + + const uint8_t *buf = static_cast (mem); + + switch (buf[EI_CLASS]) + { + case ELFCLASS32: + return open_class (filename, buf, mem, len); + case ELFCLASS64: + return open_class (filename, buf, mem, len); + default: + throw std::runtime_error ("Invalid file class"); + } + } + catch (...) + { + ::close (fd); + throw; + } +} + +template +file *file::open_class (const char *filename, const uint8_t *buf, void * mem, size_t len) throw (std::bad_alloc, std::runtime_error) +{ + switch (buf[EI_DATA]) + { + case ELFDATA2LSB: + return new file_data<_class, file_data_2LSB> (filename, mem, len); + case ELFDATA2MSB: + return new file_data<_class, file_data_2MSB> (filename, mem, len); + default: + throw std::runtime_error ("Invalid file data"); + } +} + +template +file_data<_class, _data>::file_data (const char *filename) throw (std::bad_alloc, std::runtime_error) +: file (filename) +{ + construct (); +} + +template +file_data<_class, _data>::file_data (const char *filename, void *mem, size_t len) throw (std::bad_alloc, std::runtime_error) +: file (filename, mem, len) +{ + construct (); +} + +template +void file_data<_class, _data>::construct () throw (std::bad_alloc, std::runtime_error) +{ + uint8_t *buf = static_cast (this->mem); + if (buf[EI_CLASS] != _class::id) + throw std::runtime_error ("Wrong file class"); + if (buf[EI_DATA] != _data::id) + throw std::runtime_error ("Wrong data encoding"); + + typedef typename _elfdef<_class>::Ehdr Ehdr; + Ehdr *ehdr = static_cast (this->mem); + this->type = convert<_data, typeof (ehdr->e_type )> () (ehdr->e_type ); + this->machine = convert<_data, typeof (ehdr->e_machine )> () (ehdr->e_machine ); + this->shoff = convert<_data, typeof (ehdr->e_shoff )> () (ehdr->e_shoff ); + this->shnum = convert<_data, typeof (ehdr->e_shnum )> () (ehdr->e_shnum ); + this->shstrndx = convert<_data, typeof (ehdr->e_shstrndx)> () (ehdr->e_shstrndx); + + typedef typename _elfdef<_class>::Shdr Shdr; + Shdr *shdrs = static_cast (static_cast (static_cast (this->mem) + this->shoff)); + + this->sections.reserve (this->shnum); + + for (unsigned int i = 0; i < this->shnum; i++) + { + section *temp; + switch (convert<_data, typeof (shdrs[i].sh_type)> () (shdrs[i].sh_type)) + { + case section_type_SYMTAB::id: + temp = new section_real<_class, _data, section_type_SYMTAB> (&shdrs[i], this->mem); + break; + default: + temp = new section_real<_class, _data, section_type_UNDEFINED> (&shdrs[i], this->mem); + break; + } + this->sections.push_back (temp); + } + + for (unsigned int i = 0; i < this->shnum; i++) + this->sections[i]->update_string_table (this); +} + +void section::update_string_table (file *file) throw (std::bad_alloc) +{ + const section *section = file->get_section (file->get_shstrndx ()); + this->name_string = std::string (static_cast (section->_mem ()) + this->name); +} + +template +section_data<_class, _data>::section_data (void *header, void *mem) throw () +{ + typedef typename _elfdef<_class>::Shdr Shdr; + Shdr *shdr = static_cast (header); + this->name = convert<_data, typeof (shdr->sh_name )> () (shdr->sh_name ); + this->type = convert<_data, typeof (shdr->sh_type )> () (shdr->sh_type ); + this->offset = convert<_data, typeof (shdr->sh_offset)> () (shdr->sh_offset); + this->size = convert<_data, typeof (shdr->sh_size )> () (shdr->sh_size ); + this->link = convert<_data, typeof (shdr->sh_link )> () (shdr->sh_link ); + this->mem = static_cast (static_cast (mem) + this->offset); +} + +section_type::~section_type () throw () +{ + for (std::vector::iterator it = symbols.begin (); it != symbols.end (); ++it) + delete *it; +} + +void section_type::update_string_table (file *file) throw (std::bad_alloc) +{ + section::update_string_table (file); + for (unsigned int i = 0; i < symbols.size (); i++) + this->symbols[i]->update_string_table (file, link); +} + +template +section_real<_class, _data, section_type_SYMTAB>::section_real (void *header, void *mem) throw (std::bad_alloc) +: section_data<_class, _data> (header, mem) +{ + if (this->type != SHT_SYMTAB) + throw std::logic_error ("Wrong section type"); + typedef typename _elfdef<_class>::Sym Sym; + Sym *syms = static_cast (this->mem); + unsigned int max = this->size / sizeof (Sym); + + this->symbols.reserve (max); + + for (unsigned int i = 0; i < max; i++) + this->symbols.push_back (new symbol_data<_class, _data> (&syms[i])); +} + +template +symbol_data<_class, _data>::symbol_data (void *mem) throw () +{ + typedef typename _elfdef<_class>::Sym Sym; + Sym *sym = static_cast (mem); + this->name = convert<_data, typeof (sym->st_name )> () (sym->st_name); + this->info = convert<_data, typeof (sym->st_info )> () (sym->st_info); + this->shndx = convert<_data, typeof (sym->st_shndx)> () (sym->st_shndx); + this->value = convert<_data, typeof (sym->st_value)> () (sym->st_value); + this->size = convert<_data, typeof (sym->st_size )> () (sym->st_size); + this->bind = _elfdef<_class>::st_bind (this->info); + this->type = _elfdef<_class>::st_type (this->info); +} + +template +void symbol_data<_class, _data>::update_string_table (file *file, uint16_t s) throw (std::bad_alloc) +{ + const section *section = file->get_section (s); + this->name_string = std::string (static_cast (section->_mem ()) + this->name); +} + diff --git a/src/mod/elf.hpp b/src/mod/elf.hpp new file mode 100644 index 000000000..ef9299780 --- /dev/null +++ b/src/mod/elf.hpp @@ -0,0 +1,219 @@ +/* + * elf.hpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef ELF_HPP +#define ELF_HPP + +#include "endian.hpp" + +#include +#include +#include + +#include + +namespace Elf +{ + class file_class_32 { public: static const unsigned int id = 1; }; + class file_class_64 { public: static const unsigned int id = 2; }; + class file_data_2LSB { public: static const unsigned int id = 1; }; + class file_data_2MSB { public: static const unsigned int id = 2; }; + class section_type_UNDEFINED { }; + class section_type_SYMTAB { public: static const unsigned int id = 2; }; + + class section; + + class file + { + public: + virtual ~file () throw (); + + virtual const uint8_t get_class () const throw () = 0; + virtual const uint8_t get_data () const throw () = 0; + const uint16_t get_type () const throw () { return type; } + const uint16_t get_machine () const throw () { return machine; } + const uint16_t get_shstrndx () const throw () { return shstrndx; } + + const std::vector
get_sections () const throw () { return sections; }; + const section *get_section (unsigned int i) const throw (std::out_of_range) { return sections.at(i); }; + + const void *const _mem () const throw () { return mem; } + + static file *open (const char *filename) throw (std::bad_alloc, std::runtime_error); + + protected: + file (const char *, void *, size_t len) throw (std::bad_alloc); + + template + static file *open_class (const char *, const uint8_t *, void *, size_t) throw (std::bad_alloc, std::runtime_error); + + uint16_t type; + uint16_t machine; + uint64_t shoff; + uint16_t shnum; + uint16_t shstrndx; + + std::vector
sections; + + const std::string filename; + void *mem; + size_t len; + }; + + template + class file_data : public file + { + public: + file_data (const char *) throw (std::bad_alloc, std::runtime_error); + file_data (const char *, void *, size_t len) throw (std::bad_alloc, std::runtime_error); + + const uint8_t get_class () const throw () { return _class::id; } + const uint8_t get_data () const throw () { return _data::id; } + + private: + void construct () throw (std::bad_alloc, std::runtime_error); + }; + + class section + { + public: + virtual ~section () throw () {} + + uint32_t get_type () const throw () { return type; } + uint64_t get_size () const throw () { return size; } + const std::string &get_name_string () const throw () { return name_string; } + + const void *const _mem () const throw () { return mem; } + + virtual void update_string_table (file *) throw (std::bad_alloc); + + protected: + uint32_t name; + uint32_t type; + uint64_t offset; + uint64_t size; + uint32_t link; + + std::string name_string; + + void *mem; + }; + + template + class section_data : public virtual section + { + public: + section_data (void *, void *) throw (); + }; + + template + class section_type : public virtual section + { + }; + + class symbol; + + template <> + class section_type : public virtual section + { + public: + ~section_type () throw (); + + const std::vector &get_symbols () throw () { return symbols; } + + void update_string_table (file *) throw (std::bad_alloc); + + protected: + std::vector symbols; + }; + + template + class section_real : public section_data<_class, _data>, public section_type<_type> + { + public: + section_real (void *, void *) throw (); + }; + + template + class section_real<_class, _data, section_type_UNDEFINED> : public section_data<_class, _data>, public section_type + { + public: + section_real (void *a, void *b) throw () : section_data<_class, _data> (a, b) { } + }; + + template + class section_real<_class, _data, section_type_SYMTAB> : public section_data<_class, _data>, public section_type + { + public: + section_real (void *, void *) throw (std::bad_alloc); + }; + + class symbol + { + public: + virtual ~symbol () throw () {} + + uint8_t get_info () const throw () { return info; } + uint16_t get_shndx () const throw () { return shndx; } + uint64_t get_value () const throw () { return value; } + uint64_t get_size () const throw () { return size; } + uint8_t get_bind () const throw () { return bind; } + uint8_t get_type () const throw () { return type; } + const std::string &get_name_string () const throw () { return name_string; } + + virtual void update_string_table (file *, uint16_t) throw (std::bad_alloc) = 0; + + protected: + uint32_t name; + uint8_t info; + uint16_t shndx; + uint64_t value; + uint64_t size; + uint8_t bind; + uint8_t type; + + std::string name_string; + }; + + template + class symbol_data : public symbol + { + public: + symbol_data (void *) throw (); + + void update_string_table (file *, uint16_t) throw (std::bad_alloc); + + protected: + }; + + template + struct convert + { }; + + template + struct convert : public endian::convert + { }; + + template + struct convert : public endian::convert + { }; +} + +#endif diff --git a/src/mod/endian.hpp b/src/mod/endian.hpp new file mode 100644 index 000000000..082bf44d7 --- /dev/null +++ b/src/mod/endian.hpp @@ -0,0 +1,138 @@ +/* + * endian.hpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef ENDIAN_HPP +#define ENDIAN_HPP + +#include +#include + +namespace endian +{ + class little_endian + { }; + + class big_endian + { }; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + typedef little_endian host_endian; +#elif __BYTE_ORDER == __BIG_ENDIAN + typedef big_endian host_endian; +#endif + + template + struct convert_nop + { + inline type operator () (const type &in) const throw () { return in; } + }; + + template + struct convert_simple + { }; + + template <> + struct convert_simple : public convert_nop + { }; + + template <> + struct convert_simple + { + inline uint16_t operator () (const uint16_t &in) const throw () + { + return (in & 0x00ffU) << 8 | + (in & 0xff00U) >> 8; + } + }; + + template <> + struct convert_simple + { + inline uint32_t operator () (const uint32_t &in) const throw () + { + return (in & 0x000000ffU) << 24 | + (in & 0xff000000U) >> 24 | + (in & 0x0000ff00U) << 8 | + (in & 0x00ff0000U) >> 8; + } + }; + + template <> + struct convert_simple + { + inline uint64_t operator () (const uint64_t &in) const throw () + { + return (in & 0x00000000000000ffULL) << 56 | + (in & 0xff00000000000000ULL) >> 56 | + (in & 0x000000000000ff00ULL) << 40 | + (in & 0x00ff000000000000ULL) >> 40 | + (in & 0x0000000000ff0000ULL) << 24 | + (in & 0x0000ff0000000000ULL) >> 24 | + (in & 0x00000000ff000000ULL) << 8 | + (in & 0x000000ff00000000ULL) >> 8; + } + }; + + template <> + struct convert_simple : public convert_simple + { }; + + template <> + struct convert_simple : public convert_simple + { }; + + template <> + struct convert_simple : public convert_simple + { }; + + template + struct convert_complete + { }; + + template + struct convert_complete : public convert_nop + { }; + + template + struct convert_complete : public convert_simple + { }; + + template + struct convert_complete : public convert_nop + { }; + + template + struct convert_complete : public convert_simple + { }; + + template + struct convert + { }; + + template + struct convert : public convert_complete + { }; + + template + struct convert : public convert_complete + { }; +} + +#endif diff --git a/src/mod/modpost.cpp b/src/mod/modpost.cpp new file mode 100644 index 000000000..4e5a0c899 --- /dev/null +++ b/src/mod/modpost.cpp @@ -0,0 +1,84 @@ +/* + * modpost.cpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "elf.hpp" +#include "module.hpp" + +#include + +#include + +using namespace linuxkernel; + +modulelist modules; + +int main (int argc, char *const argv[]) +{ + int ret = EXIT_SUCCESS; + int opt; + const char *dump_read = 0, *dump_write = 0; + bool all_versions = false, modversions = false;; + + while ((opt = getopt (argc, argv, "ai:mo:")) != -1) + { + switch(opt) { + case 'a': + all_versions = true; + std::clog << "*** Warning: CONFIG_MODULE_SRCVERSION_ALL is not supported!" << std::endl; + return EXIT_FAILURE; + break; + case 'i': + dump_read = optarg; + break; + case 'm': + modversions = true; + break; + case 'o': + dump_write = optarg; + break; + default: + exit(1); + } + } + + if (dump_read) + modules.dump_read (dump_read); + + for (int i = optind; i < argc; i++) + { + std::string filename (argv[i]); + try + { + modules.insert (filename); + } + catch (std::runtime_error &e) + { + std::clog << "*** Warning: \"" << filename << "\" failed to load: " << e.what () << std::endl; + ret = EXIT_FAILURE; + continue; + } + } + modules.write (modversions); + + if (dump_write) + modules.dump_write (dump_write); + + return ret; +} diff --git a/src/mod/module.cpp b/src/mod/module.cpp new file mode 100644 index 000000000..78b00deca --- /dev/null +++ b/src/mod/module.cpp @@ -0,0 +1,469 @@ +/* + * module.cpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "module.hpp" + +#include +#include +#include +#include + +#include + +using namespace linuxkernel; + +const std::string module_real::symbol_name_cleanup ("cleanup_module"); +const std::string module_real::symbol_name_init ("init_module"); +const std::string module_real::symbol_prefix_crc ("__crc_"); +const std::string module_real::symbol_prefix_ksymtab ("__ksymtab_"); + +module::module (const std::string &name) throw () +: name (name) +{ + std::string::size_type t1 = name.find_last_of ('/'); + if (t1 == std::string::npos) + t1 = 0; + else + t1++; + name_short = name.substr (t1, std::string::npos); + + if (name == "vmlinux") + is_vmlinux = true; +} + +module::module (const std::string &filename, bool) throw () +{ + std::string::size_type t1 = filename.find_last_of ('/'); + std::string::size_type t2 = filename.find_last_of ('.'); + if (t1 == std::string::npos) + t1 = 0; + else + t1++; + name = filename.substr (0, t2); + if (t2 != std::string::npos) + t2 -= t1; + name_short = filename.substr (t1, t2); + + if (name == "vmlinux") + is_vmlinux = true; +} + +module_real::module_real (const std::string &filename, Elf::file *file) throw (std::runtime_error) +: module (filename, false), has_init (false), has_cleanup (false), file (file) +{ + const std::vector §ions = file->get_sections (); + Elf::section *modinfo = 0; + symtab = 0; + + for (std::vector ::const_iterator it = sections.begin (); it != sections.end (); ++it) + { + const std::string &name = (*it)->get_name_string (); + uint32_t type = (*it)->get_type (); + if (name == ".modinfo") + modinfo = *it; + if (type == Elf::section_type_SYMTAB::id) + symtab = dynamic_cast *> (*it); + } + + if (!is_vmlinux && !modinfo) + throw std::runtime_error ("Not a kernel module, lacks modinfo section"); + if (!symtab) + throw std::runtime_error ("Not a kernel module, lacks symbol table"); + + if (!is_vmlinux) + { + read_modinfo (modinfo); + symbols_undefined.insert (std::pair ("struct_module", symbol_undefined ("struct_module", 0))); + } + read_symtab (symtab); +} + +const Elf::symbol *module_real::_get_symbol (const std::string &name) const throw () +{ + for (std::vector::const_iterator it = symtab->get_symbols ().begin (); it != symtab->get_symbols ().end (); ++it) + { + Elf::symbol *symbol = *it; + std::string symname = symbol->get_name_string (); + if (symname == name) + return symbol; + } + return 0; +} + +void module_real::write (const modulelist &list, bool modversions) +{ + std::string filename = name + ".mod.c"; + std::ofstream out (filename.c_str ()); + write_header (out); + if (modversions) + write_versions (out, list); + write_depends (out, list); + write_moddevtable (out); +} + +module_real *module_real::open (const std::string &filename) throw (std::bad_alloc, std::runtime_error) +{ + Elf::file *file = Elf::file::open (filename.c_str ()); + switch (file->get_class ()) + { + case Elf::file_class_32::id: + return open_class (filename, file); + case Elf::file_class_64::id: + return open_class (filename, file); + default: + throw std::runtime_error ("Unsupported file class"); + } +} + +template +module_real *module_real::open_class (const std::string &filename, Elf::file *file) throw (std::bad_alloc, std::runtime_error) +{ + switch (file->get_data ()) + { + case Elf::file_data_2LSB::id: + return new module_data (filename, file); + case Elf::file_data_2MSB::id: + return new module_data (filename, file); + default: + throw std::runtime_error ("Unsupported data encoding"); + } +} + +void module_real::read_modinfo (Elf::section *section) throw (std::runtime_error) +{ + const char *act, *end, *temp1, *temp2; + act = static_cast (section->_mem ()); + end = act + section->get_size (); + while (act <= end) + { + temp1 = act; + for (; *act && *act != '=' && act <= end; act++); + if (act > end) + break; + temp2 = ++act; + for (; *act && act <= end; act++); + if (act > end) + break; + modinfo.insert (std::pair (std::string (temp1, temp2 - temp1 - 1), std::string (temp2, act - temp2))); + for (; !*act && act <= end; act++); + } +} + +void module_real::read_symtab (Elf::section_type *section) throw (std::runtime_error) +{ + for (std::vector::const_iterator it = section->get_symbols ().begin (); it != section->get_symbols ().end (); ++it) + { + Elf::symbol *symbol = *it; + std::string symname = symbol->get_name_string (); + + switch (symbol->get_shndx ()) + { + case SHN_COMMON: + std::clog << "*** Warning: \"" << symname << "\" [" << name << "] is COMMON symbol" << std::endl; + break; + case SHN_ABS: + if (symname.compare (0, symbol_prefix_crc.size (), symbol_prefix_crc) == 0) + { + std::string symname_real (symname.substr (symbol_prefix_crc.size ())); + std::map::iterator it = symbols_exported.find (symname_real); + if (it == symbols_exported.end ()) + symbols_exported.insert (std::pair (symname_real, symbol_exported (symname_real, symbol->get_value ()))); + else + it->second.set_crc (symbol->get_value ()); + } + break; + case SHN_UNDEF: + if (symbol->get_bind () != STB_GLOBAL && + symbol->get_bind () != STB_WEAK) + break; + //FIXME: if (symbol->get_type () == STT_REGISTER) + // break; + /* ignore global offset table */ + if (symname == "_GLOBAL_OFFSET_TABLE_") + break; + /* ignore __this_module, it will be resolved shortly */ + if (symname == "__this_module") + break; + symbols_undefined.insert (std::pair (symname, symbol_undefined (symname, symbol->get_bind () == STB_WEAK))); + break; + default: + if (symname.compare (0, symbol_prefix_ksymtab.size (), symbol_prefix_ksymtab) == 0) + { + std::string symname_real (symname.substr (symbol_prefix_ksymtab.size ())); + std::map::iterator it = symbols_exported.find (symname_real); + if (it == symbols_exported.end ()) + symbols_exported.insert (std::pair (symname_real, symbol_exported (symname_real))); + } + else if (symname == symbol_name_cleanup) + has_cleanup = true; + else if (symname == symbol_name_init) + has_init = true; + break; + }; + } +} + +void module_real::write_depends (std::ostream &out, const modulelist &list) +{ + std::set depends; + for (std::map::const_iterator it = symbols_undefined.begin (); it != symbols_undefined.end (); ++it) + { + try + { + const std::string &mod (list.get_module_name_short_for_symbol (it->first)); + if (mod != "vmlinux") + depends.insert (mod); + } + catch (std::out_of_range &) + { } + } + out << + "static const char __module_depends[]\n" + "__attribute_used__\n" + "__attribute__((section(\".modinfo\"))) =\n" + "\"depends="; + if (depends.begin () != depends.end ()) + { + std::set::const_iterator it = depends.begin (); + out << *it; + for (++it; it != depends.end (); ++it) + out << ',' << *it; + } + out << "\";\n\n"; +} + +void module_real::write_header (std::ostream &out) +{ + out << + "#include \n" + "#include \n" + "#include \n" + "\n" + "MODULE_INFO(vermagic, VERMAGIC_STRING);\n" + "\n" + "struct module __this_module\n" + "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n" + " .name = KBUILD_MODNAME,\n"; + if (has_init) + out << " .init = init_module,\n"; + if (has_cleanup) + out << + "#ifdef CONFIG_MODULE_UNLOAD\n" + " .exit = cleanup_module,\n" + "#endif\n"; + out << "};\n\n"; +} + +void module_real::write_moddevtable (std::ostream &out) +{ + for (std::list::iterator it = devicetables.begin (); it != devicetables.end (); ++it) + { + module_devicetable::table_base *ent = *it; + if (ent) + ent->write (out); + } +} + +void module_real::write_versions (std::ostream &out, const modulelist &list) +{ + out << + "static const struct modversion_info ____versions[]\n" + "__attribute_used__\n" + "__attribute__((section(\"__versions\"))) = {\n"; + + for (_symbols_undefined::const_iterator it = symbols_undefined.begin (); it != symbols_undefined.end (); ++it) + { + try + { + const symbol_exported &sym (list.get_symbol (it->first)); + if (sym.get_crc_valid ()) + out << "\t{ 0x" << std::hex << sym.get_crc () << std::dec << ", \"" << it->first << "\" },\n"; + else + std::clog << "*** Warning: \"" << sym.get_name () << "\" [" << name << "] has no CRC!" << std::endl; + } + catch (std::out_of_range &) + { + if (list.report_symbols_missing) + std::clog << "*** Warning: \"" << it->first << "\" is undefined!" << std::endl; + } + } + + out << "};\n\n"; +} + +template +module_data::module_data (const std::string &filename, Elf::file *file) throw (std::runtime_error) +: module_real (filename, file) +{ + module_devicetable::table_create (devicetables, this, file); +} + +modulelist::modulelist () throw () +: report_symbols_missing (false) +{ } + +modulelist::~modulelist () throw () +{ + for (_modules_real::iterator it = modules_real.begin (); it != modules_real.end (); ++it) + delete it->second; + for (_modules_shadow::iterator it = modules_shadow.begin (); it != modules_shadow.end (); ++it) + delete it->second; +} + +void modulelist::dump_read (const std::string &filename) throw (std::runtime_error) +{ + std::ifstream in (filename.c_str ()); + while (in.good ()) + { + char buf[512]; + in.getline (buf, sizeof (buf)); + std::stringstream str (buf); + uint32_t crc; + std::string symbol, module_name; + str >> std::hex >> crc >> std::dec >> symbol >> module_name; + _modules_shadow::const_iterator it = modules_shadow.find (module_name); + module *mod; + if (it == modules_shadow.end ()) + { + mod = new module (module_name); + modules_shadow.insert (_modules_shadow_pair (module_name, mod)); + } + else + mod = it->second; + mod->symbols_exported.insert (std::pair (symbol, symbol_exported (symbol, crc))); + symbols_exported.insert (std::pair (symbol, module_name)); + if (mod->get_is_vmlinux ()) + report_symbols_missing = true; + } +} + +void modulelist::dump_write (const std::string &filename) const throw (std::runtime_error) +{ + char buf[128]; + std::ofstream out (filename.c_str (), std::ios::trunc); + + for (_symbols::const_iterator it = symbols_exported.begin (); it != symbols_exported.end (); ++it) + { + const module *mod = get_module (it->second); + const symbol_exported &sym = get_symbol (it->first); + snprintf (buf, sizeof (buf), "0x%08x\t%s\t%s\n", sym.get_crc (), it->first.c_str (), mod->get_name ().c_str ()); + out << buf; + } +} + +const module *modulelist::get_module (const std::string &name) const throw (std::out_of_range) +{ + _modules_real::const_iterator it1 = modules_real.find (name); + if (it1 != modules_real.end ()) + return it1->second; + _modules_shadow::const_iterator it2 = modules_shadow.find (name); + if (it2 != modules_shadow.end ()) + return it2->second; + throw std::out_of_range ("Don't find module"); +} + +const module *modulelist::get_module_for_symbol (const symbolname &name) const throw (std::out_of_range) +{ + _symbols::const_iterator it = symbols_exported.find (name); + if (it == symbols_exported.end ()) + throw std::out_of_range ("symbol is undefined"); + return get_module (it->second); +} + +const std::string &modulelist::get_module_name_short_for_symbol (const symbolname &name) const throw (std::out_of_range) +{ + const module *mod = get_module_for_symbol (name); + return mod->get_name_short (); +} + +const symbol_exported &modulelist::get_symbol (const symbolname &name) const throw (std::out_of_range) +{ + const module *mod = get_module_for_symbol (name); + std::map::const_iterator it = mod->get_symbols_exported ().find (name); + if (it == mod->get_symbols_exported ().end ()) + throw std::logic_error ("Don't find symbol"); + return it->second; +} + +void modulelist::insert (module_real *mod) throw (std::runtime_error) +{ + bool overwrite = false; + + if (mod->get_is_vmlinux ()) + { + if (!modules_shadow.insert (_modules_shadow_pair (mod->get_name (), mod)).second) + overwrite = true; + report_symbols_missing = true; + } + else + { + if (!modules_real.insert (_modules_real_pair (mod->get_name (), mod)).second) + throw std::runtime_error ("Already know a module with this name"); + } + + for (std::map::const_iterator it = mod->get_symbols_exported ().begin (); + it != mod->get_symbols_exported ().end (); ++it) + if (!symbols_exported.insert (std::pair (it->second.get_name (), mod->get_name ())).second) + if (!overwrite) + std::clog << "*** Warning: \"" << it->second.get_name () << "\" [" << mod->get_name () << "] duplicated symbol!" << std::endl; +} + +void modulelist::insert (const std::string &filename) throw (std::runtime_error) +{ + module_real *mod = module_real::open (filename); + try + { + insert (mod); + } + catch (...) + { + delete mod; + throw; + } +} + +void modulelist::write (bool modversions) +{ + for (_modules_real::iterator it = modules_real.begin (); it != modules_real.end (); ++it) + it->second->write (*this, modversions); +} + +symbol::symbol (const symbolname &name) throw () +: name (name) +{ } + +symbol_exported::symbol_exported (const symbolname &name) throw () +: symbol (name), crc_valid (false) +{ } + +symbol_exported::symbol_exported (const symbolname &name, uint32_t crc) throw () +: symbol (name), crc (crc), crc_valid (true) +{ } + +void symbol_exported::set_crc (uint32_t _crc) throw () +{ + crc = _crc; + crc_valid = true; +} + +symbol_undefined::symbol_undefined (const symbolname &name, bool weak) throw () +: symbol (name), weak (weak) +{ } + diff --git a/src/mod/module.hpp b/src/mod/module.hpp new file mode 100644 index 000000000..a8f9292e6 --- /dev/null +++ b/src/mod/module.hpp @@ -0,0 +1,204 @@ +/* + * module.hpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MODULE_HPP +#define MODULE_HPP + +#define DISABLE_TEMPLATES +#include "elf.hpp" +#include "module_devicetable.hpp" + +#include +#include +#include + +namespace linuxkernel +{ + class modulelist; + class symbolname; + class symbol_exported; + class symbol_undefined; + + class module + { + public: + typedef std::map _symbols_exported; + + module (const std::string &name) throw (); + + bool get_is_vmlinux () const throw () { return is_vmlinux; } + const std::string &get_name () const throw () { return name; } + const std::string &get_name_short () const throw () { return name_short; } + const _symbols_exported &get_symbols_exported () const throw () { return symbols_exported; } + + protected: + module (const std::string &filename, bool) throw (); + + std::string name, name_short; + bool is_vmlinux; + _symbols_exported symbols_exported; + + friend class modulelist; + }; + + class module_real : public module + { + public: + typedef std::map _symbols_undefined; + + module_real (const std::string &filename, Elf::file *file) throw (std::runtime_error); + + const Elf::symbol *_get_symbol (const std::string &name) const throw (); + + void write (const modulelist &, bool modversions); + + static module_real *open (const std::string &filename) throw (std::bad_alloc, std::runtime_error); + + const static std::string symbol_name_cleanup; + const static std::string symbol_name_init; + const static std::string symbol_prefix_crc; + const static std::string symbol_prefix_ksymtab; + + protected: + template + static module_real *open_class (const std::string &filename, Elf::file *) throw (std::bad_alloc, std::runtime_error); + + void read_modinfo (Elf::section *) throw (std::runtime_error); + void read_symtab (Elf::section_type *) throw (std::runtime_error); + + void write_depends (std::ostream &, const modulelist &); + void write_header (std::ostream &); + void write_moddevtable (std::ostream &); + void write_versions (std::ostream &, const modulelist &); + + std::map modinfo; + _symbols_undefined symbols_undefined; + bool has_init; + bool has_cleanup; + Elf::section_type *symtab; + std::list devicetables; + + Elf::file *file; + }; + + template + class module_data : public module_real + { + public: + module_data (const std::string &filename, Elf::file *file) throw (std::runtime_error); + }; + + class modulelist + { + public: + typedef std::map _modules_real; + typedef std::pair _modules_real_pair; + typedef std::map _modules_shadow; + typedef std::pair _modules_shadow_pair; + typedef std::map _symbols; + + modulelist () throw (); + ~modulelist () throw (); + + void dump_read (const std::string &filename) throw (std::runtime_error); + void dump_write (const std::string &filename) const throw (std::runtime_error); + + const _modules_real &get_modules_real () const throw () { return modules_real; } + const _modules_shadow &get_modules_shadow () const throw () { return modules_shadow; } + const module *get_module (const std::string &name) const throw (std::out_of_range); + const module *get_module_for_symbol (const symbolname &name) const throw (std::out_of_range); + const std::string &get_module_name_short_for_symbol (const symbolname &name) const throw (std::out_of_range); + const symbol_exported &get_symbol (const symbolname &name) const throw (std::out_of_range); + const _symbols &get_symbols_exported () const throw () { return symbols_exported; } + + void insert (module_real *) throw (std::runtime_error); + void insert (const std::string &filename) throw (std::runtime_error); + + void write (bool modversions); + + bool report_symbols_missing; + + protected: + _modules_real modules_real; + _modules_shadow modules_shadow; + _symbols symbols_exported; + }; + + class symbolname : public std::string + { + public: + symbolname () throw () {} + symbolname (const std::string &name) throw () + : std::string (name) + { + if (size () && at (0) == '.') + erase (0, 1); + } + symbolname (const char *name) throw () + : std::string (name) + { + if (size () && at (0) == '.') + erase (0, 1); + } + }; + + class symbol + { + public: + symbol () throw () {} + symbol (const symbolname &name) throw (); + + const symbolname &get_name () const throw () { return name; } + + protected: + symbolname name; + }; + + class symbol_exported : public symbol + { + public: + symbol_exported () throw () {} + symbol_exported (const symbolname &name) throw (); + symbol_exported (const symbolname &name, uint32_t) throw (); + + uint32_t get_crc () const throw () { return crc; } + bool get_crc_valid () const throw () { return crc_valid; } + void set_crc (uint32_t) throw (); + + protected: + uint32_t crc; + bool crc_valid; + }; + + class symbol_undefined : public symbol + { + public: + symbol_undefined () throw () {} + symbol_undefined (const symbolname &name, bool weak) throw (); + + protected: + bool weak; + }; +} + +#include "module_devicetable.tpp" + +#undef DISABLE_TEMPLATES +#endif diff --git a/src/mod/module_devicetable.cpp b/src/mod/module_devicetable.cpp new file mode 100644 index 000000000..08387fe5a --- /dev/null +++ b/src/mod/module_devicetable.cpp @@ -0,0 +1,54 @@ +/* + * module_devicetable.cpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "module.hpp" +#include "module_devicetable.hpp" + +namespace linuxkernel +{ + namespace module_devicetable + { + namespace internal + { + const std::string def::symbol = "__mod_ccw_device_table"; + const std::string def::symbol = "__mod_i2c_device_table"; + const std::string def::symbol = "__mod_ieee1394_device_table"; + const std::string def::symbol = "__mod_input_device_table"; + const std::string def::symbol = "__mod_of_device_table"; + const std::string def::symbol = "__mod_pci_device_table"; + const std::string def::symbol = "__mod_pcmcia_device_table"; + const std::string def::symbol = "__mod_pnp_device_table"; + const std::string def::symbol = "__mod_pnp_card_device_table"; + const std::string def::symbol = "__mod_serio_device_table"; + const std::string def::symbol = "__mod_usb_device_table"; + const std::string def::symbol = "__mod_vio_device_table"; + } + + void table_base::write (std::ostream &out) const throw (std::runtime_error) + { + for (std::list::const_iterator it = entries.begin (); it != entries.end (); ++it) + { + out << "MODULE_ALIAS(\""; + (*it)->write (out); + out << "\");\n"; + } + } + } +} diff --git a/src/mod/module_devicetable.hpp b/src/mod/module_devicetable.hpp new file mode 100644 index 000000000..088eed35d --- /dev/null +++ b/src/mod/module_devicetable.hpp @@ -0,0 +1,126 @@ +/* + * module_devicetable.hpp + * + * Copyright (C) 2005, 2006 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MODULE_DEVICETABLE_HPP +#define MODULE_DEVICETABLE_HPP + +#include "elf.hpp" + +#include +#include +#include + +namespace linuxkernel +{ + class module_real; + + namespace module_devicetable + { + class device_ccw { }; + class device_i2c { }; + class device_ieee1394 { }; + class device_input { }; + class device_of { }; + class device_pci { }; + class device_pcmcia { }; + class device_pnp { }; + class device_pnp_card { }; + class device_serio { }; + class device_usb { }; + class device_vio { }; + + class version_2_6_16 { }; + + namespace internal + { + template + struct def {}; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + template<> struct def { static const std::string symbol; }; + } + + class table_entry + { + public: + virtual ~table_entry () {}; + virtual void write (std::ostream &) const throw (std::runtime_error) = 0; + }; + + template + class table_entry_version : public table_entry + { + }; + + template + class table_entry_data : public table_entry_version + { + }; + + class table_base + { + public: + virtual ~table_base () throw () {}; + + void write (std::ostream &out) const throw (std::runtime_error); + + + protected: + table_base () throw () {}; + + std::list entries; + }; + + template + void table_create (std::list &, const module_real *m, const Elf::file *f) throw (std::runtime_error); + + template + class table : public table_base + { + public: + static table_base *create (const module_real *m, const Elf::file *f) throw (std::runtime_error); + + protected: + table () {}; + }; + + template + class table_data : public table + { + public: + table_data (const void *, size_t) throw (std::runtime_error); + }; + } +} + +#ifndef DISABLE_TEMPLATES +#include "module_devicetable.tpp" +#endif + +#endif diff --git a/src/mod/module_devicetable.tpp b/src/mod/module_devicetable.tpp new file mode 100644 index 000000000..466ebaaa2 --- /dev/null +++ b/src/mod/module_devicetable.tpp @@ -0,0 +1,60 @@ +/* + * module_devicetable.tpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MODULE_DEVICETABLE_TPP +#define MODULE_DEVICETABLE_TPP + +#include "module.hpp" + +namespace linuxkernel +{ + namespace module_devicetable + { + template + void table_create (std::list &list, const module_real *m, const Elf::file *file) throw (std::runtime_error) + { + list.push_back (table::create (m, file)); +// list.push_back (table::create (m, file)); + list.push_back (table::create (m, file)); +// list.push_back (table::create (m, file)); +// list.push_back (table::create (m, file)); + list.push_back (table::create (m, file)); +// list.push_back (table::create (m, file)); + list.push_back (table::create (m, file)); + list.push_back (table::create (m, file)); +// list.push_back (table::create (m, file)); + list.push_back (table::create (m, file)); +// list.push_back (table::create (m, file)); + } + + template + table_base *table::create (const module_real *m, const Elf::file *f) throw (std::runtime_error) + { + const Elf::symbol *sym = m->_get_symbol (internal::def::symbol); + if (!sym) + return 0; + const Elf::section *sec = f->get_section (sym->get_shndx ()); + const char *mem = static_cast (sec->_mem ()); + return new table_data (mem + sym->get_value (), sym->get_size ()); + } + } +} + +#endif diff --git a/src/mod/module_devicetable_impl_2_6_16.cpp b/src/mod/module_devicetable_impl_2_6_16.cpp new file mode 100644 index 000000000..eea414f8c --- /dev/null +++ b/src/mod/module_devicetable_impl_2_6_16.cpp @@ -0,0 +1,313 @@ +/* + * module_devicetable_impl_2_6_16.cpp + * + * Copyright (C) 2005 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "module_devicetable_impl_2_6_16.hpp" + +#include +#include +#include + +using namespace linuxkernel::module_devicetable; + +std::ostream &operator << (std::ostream &out, const identifier_value &id) throw () +{ + char buf[4]; + snprintf (buf, sizeof (buf), "%02X", id.value); + out << buf; + return out; +} + +std::ostream &operator << (std::ostream &out, const identifier_value &id) throw () +{ + char buf[8]; + snprintf (buf, sizeof (buf), "%04X", id.value); + out << buf; + return out; +} + +std::ostream &operator << (std::ostream &out, const identifier_value &id) throw () +{ + char buf[12]; + snprintf (buf, sizeof (buf), "%08X", id.value); + out << buf; + return out; +} + +table_entry_version::table_entry_version () throw () : + cu_type ("t"), + dev_type ("m"), + cu_model ("dt"), + dev_model ("dm") +{ } + +void table_entry_version::write (std::ostream &out) const throw (std::runtime_error) +{ + out << "ccw:"; + cu_type.write (out, match_flags & CCW_DEVICE_ID_MATCH_CU_TYPE); + cu_model.write (out, match_flags & CCW_DEVICE_ID_MATCH_CU_MODEL); + dev_type.write (out, match_flags & CCW_DEVICE_ID_MATCH_DEVICE_TYPE); + dev_model.write (out, match_flags & CCW_DEVICE_ID_MATCH_DEVICE_TYPE); +} + +table_entry_version::table_entry_version () throw () : + vendor_id ("ven"), + model_id ("mo"), + specifier_id ("sp"), + version ("ver") +{ } + +void table_entry_version::write (std::ostream &out) const throw (std::runtime_error) +{ + out << "ieee1394:"; + vendor_id.write (out, match_flags & IEEE1394_MATCH_VENDOR_ID); + model_id.write (out, match_flags & IEEE1394_MATCH_MODEL_ID); + specifier_id.write (out, match_flags & IEEE1394_MATCH_SPECIFIER_ID); + version.write (out, match_flags & IEEE1394_MATCH_VERSION, true); +} + +table_entry_version::table_entry_version () throw () : + vendor ("v"), + device ("d"), + subvendor ("sv"), + subdevice ("sd") +{ } + +void table_entry_version::write (std::ostream &out) const throw (std::runtime_error) +{ + out << "pci:"; + vendor.write (out, vendor != PCI_ANY_ID); + device.write (out, device != PCI_ANY_ID); + subvendor.write (out, subvendor != PCI_ANY_ID); + subdevice.write (out, subdevice != PCI_ANY_ID); + + identifier baseclass ("bc", class_id >> 16); + identifier_value baseclass_mask (class_mask >> 16); + identifier subclass ("sc", class_id >> 8); + identifier_value subclass_mask (class_mask >> 8); + identifier interface ("i", class_id); + identifier_value interface_mask (class_mask); + + if ((baseclass_mask != 0 && baseclass_mask != 0xFF) || + (subclass_mask != 0 && subclass_mask != 0xFF) || + (interface_mask != 0 && interface_mask != 0xFF)) + throw std::runtime_error ("Can't handle masks"); + + baseclass.write (out, baseclass_mask == 0xFF); + subclass.write (out, subclass_mask == 0xFF); + interface.write (out, interface_mask == 0xFF, true); +} + +void table_entry_version::write (std::ostream &out) const throw (std::runtime_error) +{ + out << "pnp:" << str << '*'; +} + +void table_entry_version::write (std::ostream &out) const throw (std::runtime_error) +{ + out << "pnp:" << str << '*'; +} + +table_entry_version::table_entry_version () throw () : + idVendor ("v"), + idProduct ("p"), + bDeviceClass ("dc"), + bDeviceSubClass ("dsc"), + bDeviceProtocol ("dp"), + bInterfaceClass ("ic"), + bInterfaceSubClass ("isc"), + bInterfaceProtocol ("ip") +{ } + +void table_entry_version::write (std::ostream &out) const throw (std::runtime_error) +{ + if (!idVendor && !bDeviceClass && !bInterfaceClass) + return; + + out << "usb:"; + idVendor.write (out, match_flags & USB_DEVICE_ID_MATCH_VENDOR); + idProduct.write (out, match_flags & USB_DEVICE_ID_MATCH_PRODUCT); + out << 'd'; + if (bcdDevice_initial_digits) + { + char buf[12]; + snprintf (buf, sizeof (buf), "%0*X", bcdDevice_initial_digits, bcdDevice_initial); + out << buf; + } + if (range_lo == range_hi) + out << static_cast (range_lo); + else if (range_lo > 0 || range_hi < 9) + out << '[' << static_cast (range_lo) << '-' << static_cast (range_hi) << ']'; + if (bcdDevice_initial_digits < 3) + out << '*'; + bDeviceClass.write (out, match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS); + bDeviceSubClass.write (out, match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS); + bDeviceProtocol.write (out, match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL); + bInterfaceClass.write (out, match_flags & USB_DEVICE_ID_MATCH_INT_CLASS); + bInterfaceSubClass.write (out, match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS); + bInterfaceProtocol.write (out, match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL, true); +} + +#define _do_convert(name) name = Elf::convert () (id.name) + +template +table_entry_data::table_entry_data (const device_id &id) throw () +{ + _do_convert (match_flags); + _do_convert (cu_type); + _do_convert (dev_type); + _do_convert (cu_model); + _do_convert (dev_model); +} + +template +table_entry_data::table_entry_data (const device_id &id) throw () +{ + _do_convert (match_flags); + _do_convert (vendor_id); + _do_convert (model_id); + _do_convert (specifier_id); + _do_convert (version); +} + +template +table_entry_data::table_entry_data (const device_id &id) throw () +{ + _do_convert (vendor); + _do_convert (device); + _do_convert (subvendor); + _do_convert (subdevice); + _do_convert (class_id); + _do_convert (class_mask); +} + +template +table_entry_data::table_entry_data (const device_id &id) throw () +{ + std::stringstream s; + s << 'd'; + s << static_cast (static_cast (id.id)); + str = s.str (); +} + +template +table_entry_data::table_entry_data (const device_id &id) throw () +{ + std::stringstream s; + s << 'c'; + s << static_cast (static_cast (id.id)); + for (int i = 0; i < PNP_MAX_DEVICES; i++) + { + if (! *id.devs[i].id) + break; + s << 'd'; + s << static_cast (static_cast (id.devs[i].id)); + } + str = s.str (); +} + +template +table_entry_data::table_entry_data (const device_id &id, uint16_t _bcdDevice_initial, int _bcdDevice_initial_digits, unsigned char _range_lo, unsigned char _range_hi) throw () +{ + _do_convert (match_flags); + _do_convert (idVendor); + _do_convert (idProduct); + _do_convert (bDeviceClass); + _do_convert (bDeviceSubClass); + _do_convert (bDeviceProtocol); + _do_convert (bInterfaceClass); + _do_convert (bInterfaceSubClass); + _do_convert (bInterfaceProtocol); + bcdDevice_initial = _bcdDevice_initial; + bcdDevice_initial_digits = _bcdDevice_initial_digits; + range_lo = _range_lo; + range_hi = _range_hi; +} + +template +void table_entry_data::add (const device_id &id, std::list &table) throw () +{ + uint16_t match_flags; + uint16_t idVendor; + uint16_t bcdDevice_lo = 0; + uint16_t bcdDevice_hi = ~0; + uint8_t bDeviceClass; + uint8_t bInterfaceClass; + + _do_convert (match_flags); + _do_convert (idVendor); + if (match_flags & USB_DEVICE_ID_MATCH_DEV_LO) + _do_convert (bcdDevice_lo); + if (match_flags & USB_DEVICE_ID_MATCH_DEV_HI) + _do_convert (bcdDevice_hi); + _do_convert (bDeviceClass); + _do_convert (bInterfaceClass); + + if (!(idVendor | bDeviceClass | bInterfaceClass)) + return; + + for (int ndigits = 3; bcdDevice_lo <= bcdDevice_hi; ndigits--) + { + unsigned char clo = bcdDevice_lo & 0xf; + unsigned char chi = bcdDevice_hi & 0xf; + + if (chi > 9) /* it's bcd not hex */ + chi = 9; + + bcdDevice_lo >>= 4; + bcdDevice_hi >>= 4; + + if (bcdDevice_lo == bcdDevice_hi || !ndigits) + { + table.push_back (new table_entry_data (id, bcdDevice_lo, ndigits, clo, chi)); + return; + } + + if (clo > 0) + table.push_back (new table_entry_data (id, bcdDevice_lo++, ndigits, clo, 9)); + + if (chi < 9) + table.push_back (new table_entry_data (id, bcdDevice_hi--, ndigits, 0, chi)); + } +} + +template +table_data::table_data (const void *mem, size_t size) throw (std::runtime_error) +{ + if (size % sizeof (devin)) + throw std::runtime_error ("Bad size"); + size_t len = size / sizeof (devin); + // Remove the terminator. + len--; + const devin *e = static_cast (mem); + for (size_t i = 0; i < len; ++i) + table_entry_data::add (e[i], this->entries); +} + +#define make_templates(name) \ +template class table_data; \ +template class table_data; \ +template class table_data; \ +template class table_data +make_templates(device_ccw); +make_templates(device_ieee1394); +make_templates(device_pci); +make_templates(device_pnp); +make_templates(device_pnp_card); +make_templates(device_usb); diff --git a/src/mod/module_devicetable_impl_2_6_16.hpp b/src/mod/module_devicetable_impl_2_6_16.hpp new file mode 100644 index 000000000..950a2365a --- /dev/null +++ b/src/mod/module_devicetable_impl_2_6_16.hpp @@ -0,0 +1,391 @@ +/* + * module_devicetable_impl_2_6_16.hpp + * + * Copyright (C) 2005, 2006 Bastian Blank + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MODULE_DEVICETABLE_IMPL_2_6_16_HPP +#define MODULE_DEVICETABLE_IMPL_2_6_16_HPP + +#include "module_devicetable.hpp" + +#include "elf.hpp" + +namespace +{ + using namespace linuxkernel::module_devicetable; + + template + struct _elfdef + { }; + + template<> + struct _elfdef + { + typedef uint32_t pointer; + }; + + template<> + struct _elfdef + { + typedef uint64_t pointer; + }; + + template + struct device_id + { }; + + template + struct device_id + { + uint16_t match_flags; + uint16_t cu_type; + uint16_t dev_type; + uint8_t cu_model; + uint8_t dev_model; + typename _elfdef::pointer driver_info; + }; + + enum + { + CCW_DEVICE_ID_MATCH_CU_TYPE = 0x01, + CCW_DEVICE_ID_MATCH_CU_MODEL = 0x02, + CCW_DEVICE_ID_MATCH_DEVICE_TYPE = 0x04, + CCW_DEVICE_ID_MATCH_DEVICE_MODEL = 0x08, + }; + + template + struct device_id + { + uint16_t id; + }; + + template + struct device_id + { + uint32_t match_flags; + uint32_t vendor_id; + uint32_t model_id; + uint32_t specifier_id; + uint32_t version; + typename _elfdef::pointer driver_info; + }; + + enum + { + IEEE1394_MATCH_VENDOR_ID = 0x0001, + IEEE1394_MATCH_MODEL_ID = 0x0002, + IEEE1394_MATCH_SPECIFIER_ID = 0x0004, + IEEE1394_MATCH_VERSION = 0x0008, + }; + + template + struct device_id + { + uint32_t vendor, device; + uint32_t subvendor, subdevice; + uint32_t class_id, class_mask; + typename _elfdef::pointer driver_info; + }; + + const unsigned int PCI_ANY_ID = ~0U; + const int PNP_ID_LEN = 8; + const int PNP_MAX_DEVICES = 8; + + template + struct device_id + { + uint8_t id[PNP_ID_LEN]; + typename _elfdef::pointer driver_info; + }; + + template + struct device_id + { + uint8_t id[PNP_ID_LEN]; + typename _elfdef::pointer driver_info; + struct + { + uint8_t id[PNP_ID_LEN]; + } + devs[PNP_MAX_DEVICES]; + }; + + template + struct device_id + { + uint8_t type; + uint8_t extra; + uint8_t id; + uint8_t proto; + }; + + enum + { + SERIO_DEVICE_ID_ANY = 0xff, + }; + + template + struct device_id + { + uint16_t match_flags; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice_lo; + uint16_t bcdDevice_hi; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + typename _elfdef::pointer driver_info; + }; + + enum + { + USB_DEVICE_ID_MATCH_VENDOR = 0x0001, + USB_DEVICE_ID_MATCH_PRODUCT = 0x0002, + USB_DEVICE_ID_MATCH_DEV_LO = 0x0004, + USB_DEVICE_ID_MATCH_DEV_HI = 0x0008, + USB_DEVICE_ID_MATCH_DEV_CLASS = 0x0010, + USB_DEVICE_ID_MATCH_DEV_SUBCLASS = 0x0020, + USB_DEVICE_ID_MATCH_DEV_PROTOCOL = 0x0040, + USB_DEVICE_ID_MATCH_INT_CLASS = 0x0080, + USB_DEVICE_ID_MATCH_INT_SUBCLASS = 0x0100, + USB_DEVICE_ID_MATCH_INT_PROTOCOL = 0x0200, + }; + + template + class identifier_value + { + public: + type value; + + identifier_value () : value (0) { } + identifier_value (const type &value) : value (value) { } + const type &operator = (const type &_value) { value = _value; return value; } + bool operator ! () const { return !value; } + operator type () const { return value; } + template + void set (const type _value) + { value = Elf::convert () (_value); } + }; + + template + class identifier + { + public: + identifier_value value; + std::string sep; + + identifier (const std::string &sep) : sep (sep) { } + identifier (const std::string &sep, const type &value) : value (value), sep (sep) { } + const type &operator = (const type &_value) { value = _value; return value.value; } + bool operator ! () const { return !value; } + operator type () const { return value; } + void write (std::ostream &out, bool enable, bool last = false) const + { + out << sep; + if (enable) + { + out << value; + if (last) + out << '*'; + } + else + out << '*'; + } + }; +} + +std::ostream &operator << (std::ostream &out, const identifier_value &id) throw (); +std::ostream &operator << (std::ostream &out, const identifier_value &id) throw (); +std::ostream &operator << (std::ostream &out, const identifier_value &id) throw (); + +namespace linuxkernel +{ + namespace module_devicetable + { + template<> + class table_entry_version : public table_entry + { + public: + table_entry_version () throw (); + void write (std::ostream &) const throw (std::runtime_error); + + identifier_value match_flags; + identifier cu_type; + identifier dev_type; + identifier cu_model; + identifier dev_model; + }; + + template + class table_entry_data : public table_entry_version + { + protected: + table_entry_data (const device_id &) throw (); + + public: + static void add (const device_id &id, std::list &table) throw () + { + table.push_back (new table_entry_data (id)); + } + }; + + template<> + class table_entry_version : public table_entry + { + public: + table_entry_version () throw (); + void write (std::ostream &) const throw (std::runtime_error); + + identifier_value match_flags; + identifier vendor_id; + identifier model_id; + identifier specifier_id; + identifier version; + }; + + template + class table_entry_data : public table_entry_version + { + protected: + table_entry_data (const device_id &) throw (); + + public: + static void add (const device_id &id, std::list &table) throw () + { + table.push_back (new table_entry_data (id)); + } + }; + + template<> + class table_entry_version : public table_entry + { + public: + table_entry_version () throw (); + void write (std::ostream &) const throw (std::runtime_error); + + identifier vendor, device; + identifier subvendor, subdevice; + identifier_value class_id, class_mask; + }; + + template + class table_entry_data : public table_entry_version + { + protected: + table_entry_data (const device_id &) throw (); + + public: + static void add (const device_id &id, std::list &table) throw () + { + table.push_back (new table_entry_data (id)); + } + }; + + template<> + class table_entry_version : public table_entry + { + public: + void write (std::ostream &) const throw (std::runtime_error); + + std::string str; + }; + + template + class table_entry_data : public table_entry_version + { + protected: + table_entry_data (const device_id &) throw (); + + public: + static void add (const device_id &id, std::list &table) throw () + { + table.push_back (new table_entry_data (id)); + } + }; + + template<> + class table_entry_version : public table_entry + { + public: + void write (std::ostream &) const throw (std::runtime_error); + + std::string str; + }; + + template + class table_entry_data : public table_entry_version + { + protected: + table_entry_data (const device_id &) throw (); + + public: + static void add (const device_id &id, std::list &table) throw () + { + table.push_back (new table_entry_data (id)); + } + }; + + template<> + class table_entry_version : public table_entry + { + public: + table_entry_version () throw (); + void write (std::ostream &) const throw (std::runtime_error); + + identifier_value match_flags; + identifier idVendor; + identifier idProduct; + unsigned int bcdDevice_initial; + int bcdDevice_initial_digits; + unsigned char range_lo; + unsigned char range_hi; + identifier bDeviceClass; + identifier bDeviceSubClass; + identifier bDeviceProtocol; + identifier bInterfaceClass; + identifier bInterfaceSubClass; + identifier bInterfaceProtocol; + }; + + template + class table_entry_data : public table_entry_version + { + protected: + table_entry_data (const device_id &, uint16_t bcdDevice_initial, int bcdDevice_initial_digits, unsigned char range_lo, unsigned char range_hi) throw (); + + public: + static void add (const device_id &, std::list &table) throw (); + }; + + template + class table_data : public table + { + protected: + typedef device_id devin; + + public: + table_data (const void *mem, size_t size) throw (std::runtime_error); + }; + } +} + +#endif