diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2003-02-14 08:35:21 -0600 |
|---|---|---|
| committer | Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de> | 2003-02-14 08:35:21 -0600 |
| commit | 0e5064f80d41d75abbb10e040bbd7c600e08299c (patch) | |
| tree | 6eb8bdc574cf01754670b2f34396b1a152092b1c | |
| parent | 0571739cd43b80de3bfa08f55fbcf410878cbe75 (diff) | |
kbuild: Module alias and device table support
Introduces "MODULE_ALIAS" which modules can use to embed their own
aliases for modprobe to use. Also adds a "finishing" step to modules to
supplement their aliases based on MODULE_TABLE declarations, eg.
'usb:v0506p4601dl*dh*dc*dsc*dp*ic*isc*ip*' for drivers/usb/net/pegasus.o
| -rw-r--r-- | include/linux/mod_devicetable.h | 118 | ||||
| -rw-r--r-- | include/linux/module.h | 12 | ||||
| -rw-r--r-- | include/linux/pci.h | 11 | ||||
| -rw-r--r-- | include/linux/usb.h | 94 | ||||
| -rw-r--r-- | scripts/Makefile | 3 | ||||
| -rw-r--r-- | scripts/Makefile.modver | 19 | ||||
| -rw-r--r-- | scripts/file2alias.c | 259 | ||||
| -rw-r--r-- | scripts/file2alias_inc.c | 79 |
8 files changed, 485 insertions, 110 deletions
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h new file mode 100644 index 000000000000..f285481d5c79 --- /dev/null +++ b/include/linux/mod_devicetable.h @@ -0,0 +1,118 @@ +/* + * Device tables which are exported to userspace via + * scripts/table2alias.c. You must keep that file in sync with this + * header. + */ + +#ifndef LINUX_MOD_DEVICETABLE_H +#define LINUX_MOD_DEVICETABLE_H + +#include <linux/types.h> + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +#define PCI_ANY_ID (~0) + +struct pci_device_id { + unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ + unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +/* + * Device table entry for "new style" table-driven USB drivers. + * User mode code can read these tables to choose which modules to load. + * Declare the table as a MODULE_DEVICE_TABLE. + * + * A probe() parameter will point to a matching entry from this table. + * Use the driver_info field for each match to hold information tied + * to that match: device quirks, etc. + * + * Terminate the driver's table with an all-zeroes entry. + * Use the flag values to control which fields are compared. + */ + +/** + * struct usb_device_id - identifies USB devices for probing and hotplugging + * @match_flags: Bit mask controlling of the other fields are used to match + * against new devices. Any field except for driver_info may be used, + * although some only make sense in conjunction with other fields. + * This is usually set by a USB_DEVICE_*() macro, which sets all + * other fields in this structure except for driver_info. + * @idVendor: USB vendor ID for a device; numbers are assigned + * by the USB forum to its members. + * @idProduct: Vendor-assigned product ID. + * @bcdDevice_lo: Low end of range of vendor-assigned product version numbers. + * This is also used to identify individual product versions, for + * a range consisting of a single device. + * @bcdDevice_hi: High end of version number range. The range of product + * versions is inclusive. + * @bDeviceClass: Class of device; numbers are assigned + * by the USB forum. Products may choose to implement classes, + * or be vendor-specific. Device classes specify behavior of all + * the interfaces on a devices. + * @bDeviceSubClass: Subclass of device; associated with bDeviceClass. + * @bDeviceProtocol: Protocol of device; associated with bDeviceClass. + * @bInterfaceClass: Class of interface; numbers are assigned + * by the USB forum. Products may choose to implement classes, + * or be vendor-specific. Interface classes specify behavior only + * of a given interface; other interfaces may support other classes. + * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass. + * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass. + * @driver_info: Holds information used by the driver. Usually it holds + * a pointer to a descriptor understood by the driver, or perhaps + * device flags. + * + * In most cases, drivers will create a table of device IDs by using + * USB_DEVICE(), or similar macros designed for that purpose. + * They will then export it to userspace using MODULE_DEVICE_TABLE(), + * and provide it to the USB core through their usb_driver structure. + * + * See the usb_match_id() function for information about how matches are + * performed. Briefly, you will normally use one of several macros to help + * construct these entries. Each entry you provide will either identify + * one or more specific products, or will identify a class of products + * which have agreed to behave the same. You should put the more specific + * matches towards the beginning of your table, so that driver_info can + * record quirks of specific products. + */ +struct usb_device_id { + /* which fields to match against? */ + __u16 match_flags; + + /* Used for product specific matches; range is inclusive */ + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice_lo; + __u16 bcdDevice_hi; + + /* Used for device class matches */ + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + + /* Used for interface class matches */ + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + + /* not matched against */ + kernel_ulong_t driver_info; +}; + +/* Some useful macros to use to create struct usb_device_id */ +#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 +#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 +#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 +#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 +#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 +#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 +#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 +#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 +#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 +#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 + +#endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/module.h b/include/linux/module.h index 53b4d2ea5987..d10249bfb667 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -57,13 +57,14 @@ search_extable(const struct exception_table_entry *first, unsigned long value); #ifdef MODULE +#define ___module_cat(a,b) a ## b +#define __module_cat(a,b) ___module_cat(a,b) +/* For userspace: you can also call me... */ +#define MODULE_ALIAS(alias) \ + static const char __module_cat(__alias_,__LINE__)[] \ + __attribute__((section(".modinfo"),unused)) = "alias=" alias -/* For replacement modutils, use an alias not a pointer. */ #define MODULE_GENERIC_TABLE(gtype,name) \ -static const unsigned long __module_##gtype##_size \ - __attribute__ ((unused)) = sizeof(struct gtype##_id); \ -static const struct gtype##_id * __module_##gtype##_table \ - __attribute__ ((unused)) = name; \ extern const struct gtype##_id __mod_##gtype##_table \ __attribute__ ((unused, alias(__stringify(name)))) @@ -103,6 +104,7 @@ extern const struct gtype##_id __mod_##gtype##_table \ #else /* !MODULE */ +#define MODULE_ALIAS(alias) #define MODULE_GENERIC_TABLE(gtype,name) #define THIS_MODULE ((struct module *)0) #define MOD_INC_USE_COUNT do { } while (0) diff --git a/include/linux/pci.h b/include/linux/pci.h index 7b42110379ac..e63da00d4cf6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -17,6 +17,8 @@ #ifndef LINUX_PCI_H #define LINUX_PCI_H +#include <linux/mod_devicetable.h> + /* * Under PCI, each device has 256 bytes of configuration address space, * of which the first 64 bytes are standardized as follows: @@ -359,8 +361,6 @@ enum pci_mmap_state { #define DEVICE_COUNT_DMA 2 #define DEVICE_COUNT_RESOURCE 12 -#define PCI_ANY_ID (~0) - /* * The pci_dev structure is used to describe PCI devices. */ @@ -491,13 +491,6 @@ struct pbus_set_ranges_data unsigned long prefetch_start, prefetch_end; }; -struct pci_device_id { - unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ - unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ - unsigned long driver_data; /* Data private to the driver */ -}; - struct pci_driver { struct list_head node; char *name; diff --git a/include/linux/usb.h b/include/linux/usb.h index cb5c0db14aa1..b0873cc6d8e1 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1,6 +1,7 @@ #ifndef __LINUX_USB_H #define __LINUX_USB_H +#include <linux/mod_devicetable.h> #include <linux/usb_ch9.h> #define USB_MAJOR 180 @@ -314,99 +315,6 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) /*-------------------------------------------------------------------------*/ -/* - * Device table entry for "new style" table-driven USB drivers. - * User mode code can read these tables to choose which modules to load. - * Declare the table as a MODULE_DEVICE_TABLE. - * - * A probe() parameter will point to a matching entry from this table. - * Use the driver_info field for each match to hold information tied - * to that match: device quirks, etc. - * - * Terminate the driver's table with an all-zeroes entry. - * Use the flag values to control which fields are compared. - */ - -/** - * struct usb_device_id - identifies USB devices for probing and hotplugging - * @match_flags: Bit mask controlling of the other fields are used to match - * against new devices. Any field except for driver_info may be used, - * although some only make sense in conjunction with other fields. - * This is usually set by a USB_DEVICE_*() macro, which sets all - * other fields in this structure except for driver_info. - * @idVendor: USB vendor ID for a device; numbers are assigned - * by the USB forum to its members. - * @idProduct: Vendor-assigned product ID. - * @bcdDevice_lo: Low end of range of vendor-assigned product version numbers. - * This is also used to identify individual product versions, for - * a range consisting of a single device. - * @bcdDevice_hi: High end of version number range. The range of product - * versions is inclusive. - * @bDeviceClass: Class of device; numbers are assigned - * by the USB forum. Products may choose to implement classes, - * or be vendor-specific. Device classes specify behavior of all - * the interfaces on a devices. - * @bDeviceSubClass: Subclass of device; associated with bDeviceClass. - * @bDeviceProtocol: Protocol of device; associated with bDeviceClass. - * @bInterfaceClass: Class of interface; numbers are assigned - * by the USB forum. Products may choose to implement classes, - * or be vendor-specific. Interface classes specify behavior only - * of a given interface; other interfaces may support other classes. - * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass. - * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass. - * @driver_info: Holds information used by the driver. Usually it holds - * a pointer to a descriptor understood by the driver, or perhaps - * device flags. - * - * In most cases, drivers will create a table of device IDs by using - * USB_DEVICE(), or similar macros designed for that purpose. - * They will then export it to userspace using MODULE_DEVICE_TABLE(), - * and provide it to the USB core through their usb_driver structure. - * - * See the usb_match_id() function for information about how matches are - * performed. Briefly, you will normally use one of several macros to help - * construct these entries. Each entry you provide will either identify - * one or more specific products, or will identify a class of products - * which have agreed to behave the same. You should put the more specific - * matches towards the beginning of your table, so that driver_info can - * record quirks of specific products. - */ -struct usb_device_id { - /* which fields to match against? */ - __u16 match_flags; - - /* Used for product specific matches; range is inclusive */ - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice_lo; - __u16 bcdDevice_hi; - - /* Used for device class matches */ - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - - /* Used for interface class matches */ - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - - /* not matched against */ - unsigned long driver_info; -}; - -/* Some useful macros to use to create struct usb_device_id */ -#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 -#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 -#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 -#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 -#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 -#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 -#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 -#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 -#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 -#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 - #define USB_DEVICE_ID_MATCH_DEVICE (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) #define USB_DEVICE_ID_MATCH_DEV_RANGE (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI) #define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE) diff --git a/scripts/Makefile b/scripts/Makefile index 3927e5eab97f..cf5a1862ea1d 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -8,7 +8,8 @@ # docproc: Preprocess .tmpl file in order to generate .sgml documentation # conmakehash: Create arrays for initializing the kernel console tables -host-progs := fixdep split-include conmakehash docproc kallsyms modpost +host-progs := fixdep split-include conmakehash docproc kallsyms modpost \ + file2alias build-targets := $(host-progs) # Let clean descend into subdirs diff --git a/scripts/Makefile.modver b/scripts/Makefile.modver index 252dc42f7203..6d1a3cb32232 100644 --- a/scripts/Makefile.modver +++ b/scripts/Makefile.modver @@ -27,7 +27,7 @@ quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ $(filter-out FORCE,$^) -$(modules): %.ko :%.o %.ver.o FORCE +$(modules): %.ko :%.o %.ver.o $(if CONFIG_HOTPLUG,%.aliases.o) FORCE $(call if_changed,ld_ko_o) targets += $(modules) @@ -35,7 +35,7 @@ targets += $(modules) # Compile version info for unresolved symbols quiet_cmd_cc_o_c = CC $@ - cmd_cc_o_c = $(CC) $(CFLAGS) -c -o $@ $< + cmd_cc_o_c = $(CC) $(CFLAGS) $(CFLAGS_MODULE) -c -o $@ $< # We have a fake dependency on compile.h to make sure that we # notice if the compiler version changes under us. @@ -45,6 +45,21 @@ $(modules:.ko=.ver.o): %.ver.o: %.ver.c include/linux/compile.h FORCE targets += $(modules:.ko=.ver.o) +$(modules:.ko=.aliases.o): %.aliases.o: %.aliases.c FORCE + $(call if_changed,cc_o_c) + +targets += $(modules:.ko=.aliases.o) + +# Generate aliases + +quiet_cmd_file2alias = ALIAS $@ + cmd_file2alias = scripts/file2alias $< > $@ + +$(modules:.ko=.aliases.c): %.aliases.c: %.o FORCE + $(call if_changed,file2alias) + +targets += $(modules:.ko=.aliases.c) + # All the .ver.c files are generated using the helper "modpost" .PHONY: __modpost diff --git a/scripts/file2alias.c b/scripts/file2alias.c new file mode 100644 index 000000000000..525a766bab3e --- /dev/null +++ b/scripts/file2alias.c @@ -0,0 +1,259 @@ +/* Simple code to turn various tables in an ELF file into alias definitions. + This deals with kernel datastructures where they should be + dealt with: in the kernel source. + (C) 2002 Rusty Russell IBM Corporation. +*/ +#include <stdio.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <elf.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> + +/* 32 bits: if it turns out to be 64, we add explicitly (see EXTRA_SIZE). */ +typedef int kernel_ulong_t; +#include "../include/linux/types.h" +#include "../include/linux/mod_devicetable.h" + +static int switch_endian; + +static void __endian(const void *src, void *dest, unsigned int size) +{ + unsigned int i; + for (i = 0; i < size; i++) + ((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1]; +} + +#define TO_NATIVE(x) \ +({ \ + typeof(x) __x; \ + if (switch_endian) __endian(&(x), &(__x), sizeof(__x)); \ + else __x = x; \ + __x; \ +}) + +#define ADD(str, sep, cond, field) \ +do { \ + strcat(str, sep); \ + if (cond) \ + sprintf(str + strlen(str), \ + sizeof(field) == 1 ? "%02X" : \ + sizeof(field) == 2 ? "%04X" : \ + sizeof(field) == 4 ? "%08X" : "", \ + field); \ + else \ + sprintf(str + strlen(str), "*"); \ +} while(0) + +/* Looks like "usb:vNpNdlNdhNdcNdscNdpNicNiscNipN" */ +static int do_usb_entry(const char *filename, + struct usb_device_id *id, char *alias) +{ + id->match_flags = TO_NATIVE(id->match_flags); + id->idVendor = TO_NATIVE(id->idVendor); + id->idProduct = TO_NATIVE(id->idProduct); + id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo); + id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi); + + strcpy(alias, "usb:"); + ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR, + id->idVendor); + ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT, + id->idProduct); + ADD(alias, "dl", id->match_flags&USB_DEVICE_ID_MATCH_DEV_LO, + id->bcdDevice_lo); + ADD(alias, "dh", id->match_flags&USB_DEVICE_ID_MATCH_DEV_HI, + id->bcdDevice_hi); + ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, + id->bDeviceClass); + ADD(alias, "dsc", + id->match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, + id->bDeviceSubClass); + ADD(alias, "dp", + id->match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, + id->bDeviceProtocol); + ADD(alias, "ic", + id->match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, + id->bInterfaceClass); + ADD(alias, "isc", + id->match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, + id->bInterfaceSubClass); + ADD(alias, "ip", + id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, + id->bInterfaceProtocol); + return 1; +} + +/* Looks like: pci:vNdNsvNsdNcN. */ +static int do_pci_entry(const char *filename, + struct pci_device_id *id, char *alias) +{ + id->vendor = TO_NATIVE(id->vendor); + id->device = TO_NATIVE(id->device); + id->subvendor = TO_NATIVE(id->subvendor); + id->subdevice = TO_NATIVE(id->subdevice); + id->class = TO_NATIVE(id->class); + id->class_mask = TO_NATIVE(id->class_mask); + + strcpy(alias, "pci:"); + ADD(alias, "v", id->vendor != PCI_ANY_ID, id->vendor); + ADD(alias, "d", id->device != PCI_ANY_ID, id->device); + ADD(alias, "sv", id->subvendor != PCI_ANY_ID, id->subvendor); + ADD(alias, "sd", id->subdevice != PCI_ANY_ID, id->subdevice); + if (id->class_mask != 0 && id->class_mask != ~0) { + fprintf(stderr, + "file2alias: Can't handle class_mask in %s:%04X\n", + filename, id->class_mask); + return 0; + } + ADD(alias, "c", id->class_mask == ~0, id->class); + return 1; +} + +/* Ignore any prefix, eg. v850 prepends _ */ +static inline int sym_is(const char *symbol, const char *name) +{ + const char *match; + + match = strstr(symbol, name); + if (!match) + return 0; + return match[strlen(symbol)] == '\0'; +} + +/* Returns 1 if we output anything. */ +static int do_table(void *symval, unsigned long size, + unsigned long id_size, + void *function, + const char *filename, int *first) +{ + unsigned int i; + char alias[500]; + int (*do_entry)(const char *, void *entry, char *alias) = function; + int wrote = 0; + + if (size % id_size || size < id_size) { + fprintf(stderr, "WARNING: %s ids %lu bad size (each on %lu)\n", + filename, size, id_size); + return 0; + } + /* Leave last one: it's the terminator. */ + size -= id_size; + + for (i = 0; i < size; i += id_size) { + if (do_entry(filename, symval+i, alias)) { + /* Always end in a wildcard, for future extension */ + if (alias[strlen(alias)-1] != '*') + strcat(alias, "*"); + if (*first) { + printf("#include <linux/module.h>\n\n"); + *first = 0; + } + printf("MODULE_ALIAS(\"%s\");\n", alias); + wrote = 1; + } + } + return wrote; +} + +/* This is the best way of doing this without making a complete mess + of the code. */ +#undef analyse_file +#undef Elf_Ehdr +#undef Elf_Shdr +#undef Elf_Sym +#undef EXTRA_SIZE +#define analyse_file analyze_file32 +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define EXTRA_SIZE 0 +#include "file2alias_inc.c" +#undef analyse_file +#undef Elf_Ehdr +#undef Elf_Shdr +#undef Elf_Sym +#undef EXTRA_SIZE +#define analyse_file analyze_file64 +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define EXTRA_SIZE 4 +#include "file2alias_inc.c" + +static void *grab_file(const char *filename, unsigned long *size) +{ + struct stat st; + void *map; + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + if (fstat(fd, &st) != 0) { + close(fd); + return NULL; + } + *size = st.st_size; + map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (mmap == MAP_FAILED) { + close(fd); + return NULL; + } + close(fd); + return map; +} + +/* Look through files for __mod_*_device_table: emit alias definitions + for compiling in. */ +int main(int argc, char *argv[]) +{ + void *file; + unsigned long size; + int endian; + union { short s; char c[2]; } endian_test; + + endian_test.s = 1; + if (endian_test.c[1] == 1) endian = ELFDATA2MSB; + else if (endian_test.c[0] == 1) endian = ELFDATA2LSB; + else + abort(); + + for (; argv[1]; argv++) { + file = grab_file(argv[1], &size); + if (!file) { + fprintf(stderr, "file2alias: opening %s: %s\n", + argv[1], strerror(errno)); + continue; + } + + if (size < SELFMAG || memcmp(file, ELFMAG, SELFMAG) != 0) + goto bad_elf; + + if (((unsigned char *)file)[EI_DATA] != endian) + switch_endian = 1; + + switch (((unsigned char *)file)[EI_CLASS]) { + case ELFCLASS32: + analyze_file32(file, size, argv[1]); + break; + case ELFCLASS64: + analyze_file64(file, size, argv[1]); + break; + default: + goto bad_elf; + } + munmap(file, size); + continue; + + bad_elf: + fprintf(stderr, "file2alias: %s is not elf\n", argv[1]); + return 1; + } + return 0; +} diff --git a/scripts/file2alias_inc.c b/scripts/file2alias_inc.c new file mode 100644 index 000000000000..3fcf52e0e3d4 --- /dev/null +++ b/scripts/file2alias_inc.c @@ -0,0 +1,79 @@ +/* This contains the cookie-cutter code for ELF handling (32 v 64). + Return true if anything output. */ +static void analyse_file(Elf_Ehdr *hdr, + unsigned int size, + const char *filename) +{ + unsigned int i, num_syms = 0; + Elf_Shdr *sechdrs; + Elf_Sym *syms = NULL; + char *secstrings, *strtab = NULL; + int first = 1; + + if (size < sizeof(*hdr)) + goto truncated; + + sechdrs = (void *)hdr + TO_NATIVE(hdr->e_shoff); + if (switch_endian) { + hdr->e_shoff = TO_NATIVE(hdr->e_shoff); + hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); + hdr->e_shnum = TO_NATIVE(hdr->e_shnum); + for (i = 0; i < hdr->e_shnum; i++) { + sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); + sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset); + sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); + sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); + } + } + + /* Find symbol table. */ + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + for (i = 1; i < hdr->e_shnum; i++) { + if (sechdrs[i].sh_offset > size) + goto truncated; + if (sechdrs[i].sh_type == SHT_SYMTAB) { + syms = (void *)hdr + sechdrs[i].sh_offset; + num_syms = sechdrs[i].sh_size / sizeof(syms[0]); + } else if (sechdrs[i].sh_type == SHT_STRTAB) + strtab = (void *)hdr + sechdrs[i].sh_offset; + } + + if (!strtab || !syms) { + fprintf(stderr, "table2alias: %s no symtab?\n", filename); + return; + } + + for (i = 0; i < num_syms; i++) { + const char *symname; + void *symval; + + if (switch_endian) { + syms[i].st_shndx = TO_NATIVE(syms[i].st_shndx); + syms[i].st_name = TO_NATIVE(syms[i].st_name); + syms[i].st_value = TO_NATIVE(syms[i].st_value); + syms[i].st_size = TO_NATIVE(syms[i].st_size); + } + + if (!syms[i].st_shndx || syms[i].st_shndx >= hdr->e_shnum) + continue; + + symname = strtab + syms[i].st_name; + symval = (void *)hdr + + sechdrs[syms[i].st_shndx].sh_offset + + syms[i].st_value; + if (sym_is(symname, "__mod_pci_device_table")) + do_table(symval, syms[i].st_size, + sizeof(struct pci_device_id) + EXTRA_SIZE * 1, + do_pci_entry, filename, &first); + else if (sym_is(symname, "__mod_usb_device_table")) + do_table(symval, syms[i].st_size, + sizeof(struct usb_device_id) + EXTRA_SIZE * 1, + do_usb_entry, filename, &first); + } + return; + + truncated: + fprintf(stderr, "table2alias: %s is truncated.\n", filename); + return; +} |
