diff options
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/Makefile | 10 | ||||
| -rw-r--r-- | scripts/Makefile.modver | 19 | ||||
| -rw-r--r-- | scripts/file2alias.c | 236 | ||||
| -rw-r--r-- | scripts/modpost.c | 275 | ||||
| -rw-r--r-- | scripts/modpost.h | 86 |
5 files changed, 324 insertions, 302 deletions
diff --git a/scripts/Makefile b/scripts/Makefile index 59bdaae2e5b7..eeed3759799e 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -9,9 +9,11 @@ # conmakehash: Create arrays for initializing the kernel console tables host-progs := fixdep split-include conmakehash docproc kallsyms modpost \ - file2alias mk_elfconfig + mk_elfconfig build-targets := $(host-progs) empty.o +modpost-objs := modpost.o file2alias.o + # Let clean descend into subdirs subdir- := lxdialog kconfig @@ -20,12 +22,12 @@ $(addprefix $(obj)/,$(filter-out fixdep,$(host-progs))): $(obj)/fixdep # dependencies on generated files need to be listed explicitly -$(obj)/file2alias: $(obj)/elfconfig.h +$(obj)/modpost.o $(obj)/file2alias.o: $(obj)/elfconfig.h -quiet_cmd_elfconfig = MKTARGET $@ +quiet_cmd_elfconfig = MKELF $@ cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@ $(obj)/elfconfig.h: $(obj)/empty.o $(obj)/mk_elfconfig FORCE $(call if_changed,elfconfig) -targets += $(obj)/target.h +targets += $(obj)/elfconfig.h diff --git a/scripts/Makefile.modver b/scripts/Makefile.modver index 6d1a3cb32232..e89ed0955d50 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 $(if CONFIG_HOTPLUG,%.aliases.o) FORCE +$(modules): %.ko :%.o %.ver.o FORCE $(call if_changed,ld_ko_o) targets += $(modules) @@ -45,21 +45,6 @@ $(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 @@ -69,7 +54,7 @@ $(modules:.ko=.ver.c): __modpost ; # Extract all checksums for all exported symbols quiet_cmd_modpost = MODPOST - cmd_modpost = scripts/modpost $(NM) $^ + cmd_modpost = scripts/modpost $^ __modpost: $(wildcard vmlinux) $(modules:.ko=.o) $(call if_changed,modpost) diff --git a/scripts/file2alias.c b/scripts/file2alias.c index b638f80de910..cdb1e4c6a350 100644 --- a/scripts/file2alias.c +++ b/scripts/file2alias.c @@ -1,23 +1,16 @@ /* 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> -#include <stdint.h> -#include <endian.h> - -#include "elfconfig.h" + * This deals with kernel datastructures where they should be + * dealt with: in the kernel source. + * + * Copyright 2002-2003 Rusty Russell, IBM Corporation + * 2003 Kai Germaschewski + * + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ + +#include "modpost.h" /* We use the ELF typedefs, since we can't rely on stdint.h being present. */ @@ -36,45 +29,6 @@ typedef unsigned char __u8; * we handle those differences explicitly below */ #include "../include/linux/mod_devicetable.h" -#if KERNEL_ELFCLASS == ELFCLASS32 - -#define Elf_Ehdr Elf32_Ehdr -#define Elf_Shdr Elf32_Shdr -#define Elf_Sym Elf32_Sym - -#else - -#define Elf_Ehdr Elf64_Ehdr -#define Elf_Shdr Elf64_Shdr -#define Elf_Sym Elf64_Sym - -#endif - -#if KERNEL_ELFDATA != HOST_ELFDATA - -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; \ - __endian(&(x), &(__x), sizeof(__x)); \ - __x; \ -}) - -#else /* endianness matches */ - -#define TO_NATIVE(x) (x) - -#endif - - #define ADD(str, sep, cond, field) \ do { \ strcat(str, sep); \ @@ -145,7 +99,7 @@ static int do_pci_entry(const char *filename, 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", + "*** Warning: Can't handle class_mask in %s:%04X\n", filename, id->class_mask); return 0; } @@ -164,155 +118,61 @@ static inline int sym_is(const char *symbol, const char *name) 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) +static void do_table(void *symval, unsigned long size, + unsigned long id_size, + void *function, + struct module *mod) { 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; + fprintf(stderr, "*** Warning: %s ids %lu bad size " + "(each on %lu)\n", mod->name, size, id_size); } /* 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)) { + if (do_entry(mod->name, 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; + buf_printf(&mod->dev_table_buf, + "MODULE_ALIAS(\"%s\");\n", alias); } } - return wrote; } -/* This contains the cookie-cutter code for ELF handling (32 v 64). */ -static void analyze_file(Elf_Ehdr *hdr, - unsigned int size, - const char *filename) +/* Create MODULE_ALIAS() statements. + * At this time, we cannot write the actual output C source yet, + * so we write into the mod->dev_table_buf buffer. */ +void handle_moddevtable(struct module *mod, struct elf_info *info, + Elf_Sym *sym, const char *symname) { - 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); - 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); - abort(); - } - - for (i = 0; i < num_syms; i++) { - const char *symname; - void *symval; - - 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), - 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), - do_usb_entry, filename, &first); - } - return; - - truncated: - fprintf(stderr, "table2alias: %s is truncated.\n", filename); - abort(); + void *symval; + + /* We're looking for a section relative symbol */ + if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum) + return; + + symval = (void *)info->hdr + + info->sechdrs[sym->st_shndx].sh_offset + + sym->st_value; + + if (sym_is(symname, "__mod_pci_device_table")) + do_table(symval, sym->st_size, sizeof(struct pci_device_id), + do_pci_entry, mod); + else if (sym_is(symname, "__mod_usb_device_table")) + do_table(symval, sym->st_size, sizeof(struct usb_device_id), + do_usb_entry, mod); } -static void *grab_file(const char *filename, unsigned long *size) +/* Now add out buffered information to the generated C source */ +void add_moddevtable(struct buffer *buf, struct module *mod) { - 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; - - for (; argv[1]; argv++) { - file = grab_file(argv[1], &size); - if (!file) { - fprintf(stderr, "file2alias: opening %s: %s\n", - argv[1], strerror(errno)); - abort(); - } - analyze_file(file, size, argv[1]); - munmap(file, size); - } - return 0; + buf_printf(buf, "\n"); + buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos); + free(mod->dev_table_buf.p); } diff --git a/scripts/modpost.c b/scripts/modpost.c index fb8a54414b87..b10352e6a928 100644 --- a/scripts/modpost.c +++ b/scripts/modpost.c @@ -1,38 +1,22 @@ /* Postprocess module symbol versions * * Copyright 2003 Kai Germaschewski - * 2002 Rusty Russell IBM Corporation + * 2002-2003 Rusty Russell, IBM Corporation * - * Based in part on module-init-tools/depmod.c + * Based in part on module-init-tools/depmod.c,file2alias * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * - * Usage: modpost $(NM) vmlinux module1.o module2.o ... + * Usage: modpost vmlinux module1.o module2.o ... */ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -/* nm command */ -const char *nm; +#include "modpost.h" /* Are we using CONFIG_MODVERSIONS? */ int modversions = 0; void -usage(void) -{ - fprintf(stderr, "Usage: modpost $(NM) vmlinux module1.o module2.o\n"); - exit(1); -} - -void fatal(const char *fmt, ...) { va_list arglist; @@ -71,15 +55,30 @@ void *do_nofail(void *ptr, const char *file, int line, const char *expr) /* A list of all modules we processed */ -struct module { - struct module *next; - const char *name; - struct symbol *unres; - int seen; -}; - static struct module *modules; +struct module * +new_module(char *modname) +{ + struct module *mod; + char *p; + + /* strip trailing .o */ + p = strstr(modname, ".o"); + if (p) + *p = 0; + + mod = NOFAIL(malloc(sizeof(*mod))); + memset(mod, 0, sizeof(*mod)); + mod->name = modname; + + /* add to list */ + mod->next = modules; + modules = mod; + + return mod; +} + /* A hash of all exported symbols, * struct symbol is also used for lists of unresolved symbols */ @@ -159,7 +158,7 @@ find_symbol(const char *name) /* Add an exported symbol - it may have already been added without a * CRC, in this case just update the CRC */ void -add_symbol(const char *name, struct module *module, unsigned int *crc) +add_exported_symbol(const char *name, struct module *module, unsigned int *crc) { struct symbol *s = find_symbol(name); @@ -173,74 +172,162 @@ add_symbol(const char *name, struct module *module, unsigned int *crc) } } -#define SZ 500 +void * +grab_file(const char *filename, unsigned long *size) +{ + struct stat st; + void *map; + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + abort(); + } + if (fstat(fd, &st) != 0) { + perror(filename); + abort(); + } + + *size = st.st_size; + map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (mmap == MAP_FAILED) { + perror(filename); + abort(); + } + close(fd); + return map; +} void -read_symbols(char *modname) +parse_elf(struct elf_info *info, const char *filename) { - struct module *mod; - struct symbol *s; - char buf[SZ], sym[SZ], *p; - FILE *pipe; - unsigned int crc; - int rc; + unsigned int i; + Elf_Ehdr *hdr = info->hdr; + Elf_Shdr *sechdrs; + Elf_Sym *sym; + + hdr = grab_file(filename, &info->size); + info->hdr = hdr; + if (info->size < sizeof(*hdr)) + goto truncated; + + /* Fix endianness in ELF header */ + hdr->e_shoff = TO_NATIVE(hdr->e_shoff); + hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); + hdr->e_shnum = TO_NATIVE(hdr->e_shnum); + sechdrs = (void *)hdr + hdr->e_shoff; + info->sechdrs = sechdrs; + + /* Fix endianness in section headers */ + 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. */ + for (i = 1; i < hdr->e_shnum; i++) { + if (sechdrs[i].sh_offset > info->size) + goto truncated; + if (sechdrs[i].sh_type != SHT_SYMTAB) + continue; - /* read nm output */ - snprintf(buf, SZ, "%s --no-sort %s", nm, modname); - pipe = NOFAIL(popen(buf, "r")); + info->symtab_start = (void *)hdr + sechdrs[i].sh_offset; + info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset + + sechdrs[i].sh_size; + info->strtab = (void *)hdr + + sechdrs[sechdrs[i].sh_link].sh_offset; + } + if (!info->symtab_start) { + fprintf(stderr, "modpost: %s no symtab?\n", filename); + abort(); + } + /* Fix endianness in symbols */ + for (sym = info->symtab_start; sym < info->symtab_stop; sym++) { + sym->st_shndx = TO_NATIVE(sym->st_shndx); + sym->st_name = TO_NATIVE(sym->st_name); + sym->st_value = TO_NATIVE(sym->st_value); + sym->st_size = TO_NATIVE(sym->st_size); + } + return; - /* strip trailing .o */ - p = strstr(modname, ".o"); - if (p) - *p = 0; + truncated: + fprintf(stderr, "modpost: %s is truncated.\n", filename); + abort(); +} - mod = NOFAIL(malloc(sizeof(*mod))); - mod->name = modname; - /* add to list */ - mod->next = modules; - modules = mod; - - while (fgets(buf, SZ, pipe)) { - /* actual CRCs */ - rc = sscanf(buf, "%x A __crc_%s\n", &crc, sym); - if (rc == 2) { - add_symbol(sym, mod, &crc); +void +parse_elf_finish(struct elf_info *info) +{ + munmap(info->hdr, info->size); +} + +void +handle_modversions(struct module *mod, struct elf_info *info, + Elf_Sym *sym, const char *symname) +{ + struct symbol *s; + + switch (sym->st_shndx) { + case SHN_COMMON: + fprintf(stderr, "*** Warning: \"%s\" [%s] is COMMON symbol\n", + symname, mod->name); + break; + case SHN_ABS: + /* CRC'd symbol */ + if (memcmp(symname, "__crc_", 6) == 0) { + add_exported_symbol(symname+6, mod, &sym->st_value); modversions = 1; - continue; } - - /* all exported symbols */ - rc = sscanf(buf, "%x r __ksymtab_%s", &crc, sym); - if (rc == 2) { - add_symbol(sym, mod, NULL); - continue; + break; + case SHN_UNDEF: + /* undefined symbol */ + if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) + break; + + s = alloc_symbol(symname); + /* add to list */ + s->next = mod->unres; + mod->unres = s; + break; + default: + /* All exported symbols */ + if (memcmp(symname, "__ksymtab_", 10) == 0) { + add_exported_symbol(symname+10, mod, NULL); } + break; + } +} - /* all unresolved symbols */ - rc = sscanf(buf, " U %s\n", sym); - if (rc == 1) { - s = alloc_symbol(sym); - /* add to list */ - s->next = mod->unres; - mod->unres = s; - continue; - } - }; - pclose(pipe); +void +read_symbols(char *modname) +{ + const char *symname; + struct module *mod; + struct elf_info info = { }; + Elf_Sym *sym; + + parse_elf(&info, modname); + + mod = new_module(modname); + + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { + symname = info.strtab + sym->st_name; + + handle_modversions(mod, &info, sym, symname); + handle_moddevtable(mod, &info, sym, symname); + } + parse_elf_finish(&info); } +#define SZ 500 + /* We first write the generated file into memory using the * following helper, then compare to the file on disk and * only update the later if anything changed */ -struct buffer { - char *p; - int pos; - int size; -}; - -void -__attribute__((format(printf, 2, 3))) +void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, const char *fmt, ...) { char tmp[SZ]; @@ -250,11 +337,7 @@ buf_printf(struct buffer *buf, const char *fmt, ...) va_start(ap, fmt); len = vsnprintf(tmp, SZ, fmt, ap); if (buf->size - buf->pos < len + 1) { - if (buf->size == 0) - buf->size = 1024; - else - buf->size *= 2; - + buf->size += 128; buf->p = realloc(buf->p, buf->size); } strncpy(buf->p + buf->pos, tmp, len + 1); @@ -262,6 +345,17 @@ buf_printf(struct buffer *buf, const char *fmt, ...) va_end(ap); } +void +buf_write(struct buffer *buf, const char *s, int len) +{ + if (buf->size - buf->pos < len) { + buf->size += len; + buf->p = realloc(buf->p, buf->size); + } + strncpy(buf->p + buf->pos, s, len); + buf->pos += len; +} + /* Header for the generated file */ void @@ -399,18 +493,12 @@ write_if_changed(struct buffer *b, const char *fname) int main(int argc, char **argv) { - int i; struct module *mod; struct buffer buf = { }; char fname[SZ]; - if (argc < 3) - usage(); - - nm = argv[1]; - - for (i = 2; i < argc; i++) { - read_symbols(argv[i]); + for (; argv[1]; argv++) { + read_symbols(argv[1]); } for (mod = modules; mod; mod = mod->next) { @@ -422,6 +510,7 @@ main(int argc, char **argv) add_header(&buf); add_versions(&buf, mod); add_depends(&buf, mod, modules); + add_moddevtable(&buf, mod); sprintf(fname, "%s.ver.c", mod->name); write_if_changed(&buf, fname); diff --git a/scripts/modpost.h b/scripts/modpost.h new file mode 100644 index 000000000000..1a5c8e829cc8 --- /dev/null +++ b/scripts/modpost.h @@ -0,0 +1,86 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> +#include <elf.h> + +#include "elfconfig.h" + +#if KERNEL_ELFCLASS == ELFCLASS32 + +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define ELF_ST_BIND ELF32_ST_BIND + +#else + +#define Elf_Ehdr Elf64_Ehdr +#define Elf_Shdr Elf64_Shdr +#define Elf_Sym Elf64_Sym +#define ELF_ST_BIND ELF64_ST_BIND + +#endif + +#if KERNEL_ELFDATA != HOST_ELFDATA + +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; \ + __endian(&(x), &(__x), sizeof(__x)); \ + __x; \ +}) + +#else /* endianness matches */ + +#define TO_NATIVE(x) (x) + +#endif + +struct buffer { + char *p; + int pos; + int size; +}; + +void __attribute__((format(printf, 2, 3))) +buf_printf(struct buffer *buf, const char *fmt, ...); + +void +buf_write(struct buffer *buf, const char *s, int len); + +struct module { + struct module *next; + const char *name; + struct symbol *unres; + int seen; + struct buffer dev_table_buf; +}; + +struct elf_info { + unsigned long size; + Elf_Ehdr *hdr; + Elf_Shdr *sechdrs; + Elf_Sym *symtab_start; + Elf_Sym *symtab_stop; + const char *strtab; +}; + +void handle_moddevtable(struct module *mod, struct elf_info *info, + Elf_Sym *sym, const char *symname); + +void add_moddevtable(struct buffer *buf, struct module *mod); |
