vserver 1.9.5.x5
[linux-2.6.git] / scripts / mod / modpost.c
1 /* Postprocess module symbol versions
2  *
3  * Copyright 2003       Kai Germaschewski
4  * Copyright 2002-2004  Rusty Russell, IBM Corporation
5  *
6  * Based in part on module-init-tools/depmod.c,file2alias
7  *
8  * This software may be used and distributed according to the terms
9  * of the GNU General Public License, incorporated herein by reference.
10  *
11  * Usage: modpost vmlinux module1.o module2.o ...
12  */
13
14 #include <ctype.h>
15 #include "modpost.h"
16
17 /* Are we using CONFIG_MODVERSIONS? */
18 int modversions = 0;
19 /* Warn about undefined symbols? (do so if we have vmlinux) */
20 int have_vmlinux = 0;
21 /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
22 static int all_versions = 0;
23
24 void
25 fatal(const char *fmt, ...)
26 {
27         va_list arglist;
28
29         fprintf(stderr, "FATAL: ");
30
31         va_start(arglist, fmt);
32         vfprintf(stderr, fmt, arglist);
33         va_end(arglist);
34
35         exit(1);
36 }
37
38 void
39 warn(const char *fmt, ...)
40 {
41         va_list arglist;
42
43         fprintf(stderr, "WARNING: ");
44
45         va_start(arglist, fmt);
46         vfprintf(stderr, fmt, arglist);
47         va_end(arglist);
48 }
49
50 void *do_nofail(void *ptr, const char *file, int line, const char *expr)
51 {
52         if (!ptr) {
53                 fatal("Memory allocation failure %s line %d: %s.\n",
54                       file, line, expr);
55         }
56         return ptr;
57 }
58
59 /* A list of all modules we processed */
60
61 static struct module *modules;
62
63 struct module *
64 find_module(char *modname)
65 {
66         struct module *mod;
67
68         for (mod = modules; mod; mod = mod->next)
69                 if (strcmp(mod->name, modname) == 0)
70                         break;
71         return mod;
72 }
73
74 struct module *
75 new_module(char *modname)
76 {
77         struct module *mod;
78         char *p, *s;
79         
80         mod = NOFAIL(malloc(sizeof(*mod)));
81         memset(mod, 0, sizeof(*mod));
82         p = NOFAIL(strdup(modname));
83
84         /* strip trailing .o */
85         if ((s = strrchr(p, '.')) != NULL)
86                 if (strcmp(s, ".o") == 0)
87                         *s = '\0';
88
89         /* add to list */
90         mod->name = p;
91         mod->next = modules;
92         modules = mod;
93
94         return mod;
95 }
96
97 /* A hash of all exported symbols,
98  * struct symbol is also used for lists of unresolved symbols */
99
100 #define SYMBOL_HASH_SIZE 1024
101
102 struct symbol {
103         struct symbol *next;
104         struct module *module;
105         unsigned int crc;
106         int crc_valid;
107         unsigned int weak:1;
108         char name[0];
109 };
110
111 static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
112
113 /* This is based on the hash agorithm from gdbm, via tdb */
114 static inline unsigned int tdb_hash(const char *name)
115 {
116         unsigned value; /* Used to compute the hash value.  */
117         unsigned   i;   /* Used to cycle through random values. */
118
119         /* Set the initial value from the key size. */
120         for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
121                 value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
122
123         return (1103515243 * value + 12345);
124 }
125
126 /* Allocate a new symbols for use in the hash of exported symbols or
127  * the list of unresolved symbols per module */
128
129 struct symbol *
130 alloc_symbol(const char *name, unsigned int weak, struct symbol *next)
131 {
132         struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
133
134         memset(s, 0, sizeof(*s));
135         strcpy(s->name, name);
136         s->weak = weak;
137         s->next = next;
138         return s;
139 }
140
141 /* For the hash of exported symbols */
142
143 void
144 new_symbol(const char *name, struct module *module, unsigned int *crc)
145 {
146         unsigned int hash;
147         struct symbol *new;
148
149         hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
150         new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
151         new->module = module;
152         if (crc) {
153                 new->crc = *crc;
154                 new->crc_valid = 1;
155         }
156 }
157
158 struct symbol *
159 find_symbol(const char *name)
160 {
161         struct symbol *s;
162
163         /* For our purposes, .foo matches foo.  PPC64 needs this. */
164         if (name[0] == '.')
165                 name++;
166
167         for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s=s->next) {
168                 if (strcmp(s->name, name) == 0)
169                         return s;
170         }
171         return NULL;
172 }
173
174 /* Add an exported symbol - it may have already been added without a
175  * CRC, in this case just update the CRC */
176 void
177 add_exported_symbol(const char *name, struct module *module, unsigned int *crc)
178 {
179         struct symbol *s = find_symbol(name);
180
181         if (!s) {
182                 new_symbol(name, module, crc);
183                 return;
184         }
185         if (crc) {
186                 s->crc = *crc;
187                 s->crc_valid = 1;
188         }
189 }
190
191 void *
192 grab_file(const char *filename, unsigned long *size)
193 {
194         struct stat st;
195         void *map;
196         int fd;
197
198         fd = open(filename, O_RDONLY);
199         if (fd < 0 || fstat(fd, &st) != 0)
200                 return NULL;
201
202         *size = st.st_size;
203         map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
204         close(fd);
205
206         if (map == MAP_FAILED)
207                 return NULL;
208         return map;
209 }
210
211 /*
212    Return a copy of the next line in a mmap'ed file.
213    spaces in the beginning of the line is trimmed away.
214    Return a pointer to a static buffer.
215 */
216 char*
217 get_next_line(unsigned long *pos, void *file, unsigned long size)
218 {
219         static char line[4096];
220         int skip = 1;
221         size_t len = 0;
222         signed char *p = (signed char *)file + *pos;
223         char *s = line;
224
225         for (; *pos < size ; (*pos)++)
226         {
227                 if (skip && isspace(*p)) {
228                         p++;
229                         continue;
230                 }
231                 skip = 0;
232                 if (*p != '\n' && (*pos < size)) {
233                         len++;
234                         *s++ = *p++;
235                         if (len > 4095)
236                                 break; /* Too long, stop */
237                 } else {
238                         /* End of string */
239                         *s = '\0';
240                         return line;
241                 }
242         }
243         /* End of buffer */
244         return NULL;
245 }
246
247 void
248 release_file(void *file, unsigned long size)
249 {
250         munmap(file, size);
251 }
252
253 void
254 parse_elf(struct elf_info *info, const char *filename)
255 {
256         unsigned int i;
257         Elf_Ehdr *hdr = info->hdr;
258         Elf_Shdr *sechdrs;
259         Elf_Sym  *sym;
260
261         hdr = grab_file(filename, &info->size);
262         if (!hdr) {
263                 perror(filename);
264                 abort();
265         }
266         info->hdr = hdr;
267         if (info->size < sizeof(*hdr))
268                 goto truncated;
269
270         /* Fix endianness in ELF header */
271         hdr->e_shoff    = TO_NATIVE(hdr->e_shoff);
272         hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
273         hdr->e_shnum    = TO_NATIVE(hdr->e_shnum);
274         hdr->e_machine  = TO_NATIVE(hdr->e_machine);
275         sechdrs = (void *)hdr + hdr->e_shoff;
276         info->sechdrs = sechdrs;
277
278         /* Fix endianness in section headers */
279         for (i = 0; i < hdr->e_shnum; i++) {
280                 sechdrs[i].sh_type   = TO_NATIVE(sechdrs[i].sh_type);
281                 sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
282                 sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
283                 sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
284                 sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
285         }
286         /* Find symbol table. */
287         for (i = 1; i < hdr->e_shnum; i++) {
288                 const char *secstrings
289                         = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
290
291                 if (sechdrs[i].sh_offset > info->size)
292                         goto truncated;
293                 if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) {
294                         info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
295                         info->modinfo_len = sechdrs[i].sh_size;
296                 }
297                 if (sechdrs[i].sh_type != SHT_SYMTAB)
298                         continue;
299
300                 info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
301                 info->symtab_stop  = (void *)hdr + sechdrs[i].sh_offset 
302                                                  + sechdrs[i].sh_size;
303                 info->strtab       = (void *)hdr + 
304                                      sechdrs[sechdrs[i].sh_link].sh_offset;
305         }
306         if (!info->symtab_start) {
307                 fprintf(stderr, "modpost: %s no symtab?\n", filename);
308                 abort();
309         }
310         /* Fix endianness in symbols */
311         for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
312                 sym->st_shndx = TO_NATIVE(sym->st_shndx);
313                 sym->st_name  = TO_NATIVE(sym->st_name);
314                 sym->st_value = TO_NATIVE(sym->st_value);
315                 sym->st_size  = TO_NATIVE(sym->st_size);
316         }
317         return;
318
319  truncated:
320         fprintf(stderr, "modpost: %s is truncated.\n", filename);
321         abort();
322 }
323
324 void
325 parse_elf_finish(struct elf_info *info)
326 {
327         release_file(info->hdr, info->size);
328 }
329
330 #define CRC_PFX     MODULE_SYMBOL_PREFIX "__crc_"
331 #define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_"
332
333 void
334 handle_modversions(struct module *mod, struct elf_info *info,
335                    Elf_Sym *sym, const char *symname)
336 {
337         unsigned int crc;
338
339         switch (sym->st_shndx) {
340         case SHN_COMMON:
341                 fprintf(stderr, "*** Warning: \"%s\" [%s] is COMMON symbol\n",
342                         symname, mod->name);
343                 break;
344         case SHN_ABS:
345                 /* CRC'd symbol */
346                 if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
347                         crc = (unsigned int) sym->st_value;
348                         add_exported_symbol(symname + strlen(CRC_PFX),
349                                             mod, &crc);
350                 }
351                 break;
352         case SHN_UNDEF:
353                 /* undefined symbol */
354                 if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL &&
355                     ELF_ST_BIND(sym->st_info) != STB_WEAK)
356                         break;
357                 /* ignore global offset table */
358                 if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0)
359                         break;
360                 /* ignore __this_module, it will be resolved shortly */
361                 if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0)
362                         break;
363 #ifdef STT_REGISTER
364                 if (info->hdr->e_machine == EM_SPARC ||
365                     info->hdr->e_machine == EM_SPARCV9) {
366                         /* Ignore register directives. */
367                         if (ELF_ST_TYPE(sym->st_info) == STT_REGISTER)
368                                 break;
369                 }
370 #endif
371                 
372                 if (memcmp(symname, MODULE_SYMBOL_PREFIX,
373                            strlen(MODULE_SYMBOL_PREFIX)) == 0)
374                         mod->unres = alloc_symbol(symname +
375                                                   strlen(MODULE_SYMBOL_PREFIX),
376                                                   ELF_ST_BIND(sym->st_info) == STB_WEAK,
377                                                   mod->unres);
378                 break;
379         default:
380                 /* All exported symbols */
381                 if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
382                         add_exported_symbol(symname + strlen(KSYMTAB_PFX),
383                                             mod, NULL);
384                 }
385                 if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
386                         mod->has_init = 1;
387                 if (strcmp(symname, MODULE_SYMBOL_PREFIX "cleanup_module") == 0)
388                         mod->has_cleanup = 1;
389                 break;
390         }
391 }
392
393 int
394 is_vmlinux(const char *modname)
395 {
396         const char *myname;
397
398         if ((myname = strrchr(modname, '/')))
399                 myname++;
400         else
401                 myname = modname;
402
403         return strcmp(myname, "vmlinux") == 0;
404 }
405
406 /* Parse tag=value strings from .modinfo section */
407 static char *next_string(char *string, unsigned long *secsize)
408 {
409         /* Skip non-zero chars */
410         while (string[0]) {
411                 string++;
412                 if ((*secsize)-- <= 1)
413                         return NULL;
414         }
415
416         /* Skip any zero padding. */
417         while (!string[0]) {
418                 string++;
419                 if ((*secsize)-- <= 1)
420                         return NULL;
421         }
422         return string;
423 }
424
425 static char *get_modinfo(void *modinfo, unsigned long modinfo_len,
426                          const char *tag)
427 {
428         char *p;
429         unsigned int taglen = strlen(tag);
430         unsigned long size = modinfo_len;
431
432         for (p = modinfo; p; p = next_string(p, &size)) {
433                 if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
434                         return p + taglen + 1;
435         }
436         return NULL;
437 }
438
439 void
440 read_symbols(char *modname)
441 {
442         const char *symname;
443         char *version;
444         struct module *mod;
445         struct elf_info info = { };
446         Elf_Sym *sym;
447
448         parse_elf(&info, modname);
449
450         mod = new_module(modname);
451
452         /* When there's no vmlinux, don't print warnings about
453          * unresolved symbols (since there'll be too many ;) */
454         if (is_vmlinux(modname)) {
455                 unsigned int fake_crc = 0;
456                 have_vmlinux = 1;
457                 add_exported_symbol("struct_module", mod, &fake_crc);
458                 mod->skip = 1;
459         }
460
461         for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
462                 symname = info.strtab + sym->st_name;
463
464                 handle_modversions(mod, &info, sym, symname);
465                 handle_moddevtable(mod, &info, sym, symname);
466         }
467
468         version = get_modinfo(info.modinfo, info.modinfo_len, "version");
469         if (version)
470                 maybe_frob_rcs_version(modname, version, info.modinfo,
471                                        version - (char *)info.hdr);
472         if (version || (all_versions && !is_vmlinux(modname)))
473                 get_src_version(modname, mod->srcversion,
474                                 sizeof(mod->srcversion)-1);
475
476         parse_elf_finish(&info);
477
478         /* Our trick to get versioning for struct_module - it's
479          * never passed as an argument to an exported function, so
480          * the automatic versioning doesn't pick it up, but it's really
481          * important anyhow */
482         if (modversions)
483                 mod->unres = alloc_symbol("struct_module", 0, mod->unres);
484 }
485
486 #define SZ 500
487
488 /* We first write the generated file into memory using the
489  * following helper, then compare to the file on disk and
490  * only update the later if anything changed */
491
492 void __attribute__((format(printf, 2, 3)))
493 buf_printf(struct buffer *buf, const char *fmt, ...)
494 {
495         char tmp[SZ];
496         int len;
497         va_list ap;
498         
499         va_start(ap, fmt);
500         len = vsnprintf(tmp, SZ, fmt, ap);
501         if (buf->size - buf->pos < len + 1) {
502                 buf->size += 128;
503                 buf->p = realloc(buf->p, buf->size);
504         }
505         strncpy(buf->p + buf->pos, tmp, len + 1);
506         buf->pos += len;
507         va_end(ap);
508 }
509
510 void
511 buf_write(struct buffer *buf, const char *s, int len)
512 {
513         if (buf->size - buf->pos < len) {
514                 buf->size += len;
515                 buf->p = realloc(buf->p, buf->size);
516         }
517         strncpy(buf->p + buf->pos, s, len);
518         buf->pos += len;
519 }
520
521 /* Header for the generated file */
522
523 void
524 add_header(struct buffer *b, struct module *mod)
525 {
526         buf_printf(b, "#include <linux/module.h>\n");
527         buf_printf(b, "#include <linux/vermagic.h>\n");
528         buf_printf(b, "#include <linux/compiler.h>\n");
529         buf_printf(b, "\n");
530         buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
531         buf_printf(b, "\n");
532         buf_printf(b, "#undef unix\n"); /* We have a module called "unix" */
533         buf_printf(b, "struct module __this_module\n");
534         buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
535         buf_printf(b, " .name = __stringify(KBUILD_MODNAME),\n");
536         if (mod->has_init)
537                 buf_printf(b, " .init = init_module,\n");
538         if (mod->has_cleanup)
539                 buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
540                               " .exit = cleanup_module,\n"
541                               "#endif\n");
542         buf_printf(b, "};\n");
543 }
544
545 /* Record CRCs for unresolved symbols */
546
547 void
548 add_versions(struct buffer *b, struct module *mod)
549 {
550         struct symbol *s, *exp;
551
552         for (s = mod->unres; s; s = s->next) {
553                 exp = find_symbol(s->name);
554                 if (!exp || exp->module == mod) {
555                         if (have_vmlinux && !s->weak)
556                                 fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
557                                 "undefined!\n", s->name, mod->name);
558                         continue;
559                 }
560                 s->module = exp->module;
561                 s->crc_valid = exp->crc_valid;
562                 s->crc = exp->crc;
563         }
564
565         if (!modversions)
566                 return;
567
568         buf_printf(b, "\n");
569         buf_printf(b, "static const struct modversion_info ____versions[]\n");
570         buf_printf(b, "__attribute_used__\n");
571         buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
572
573         for (s = mod->unres; s; s = s->next) {
574                 if (!s->module) {
575                         continue;
576                 }
577                 if (!s->crc_valid) {
578                         fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
579                                 "has no CRC!\n",
580                                 s->name, mod->name);
581                         continue;
582                 }
583                 buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name);
584         }
585
586         buf_printf(b, "};\n");
587 }
588
589 void
590 add_depends(struct buffer *b, struct module *mod, struct module *modules)
591 {
592         struct symbol *s;
593         struct module *m;
594         int first = 1;
595
596         for (m = modules; m; m = m->next) {
597                 m->seen = is_vmlinux(m->name);
598         }
599
600         buf_printf(b, "\n");
601         buf_printf(b, "static const char __module_depends[]\n");
602         buf_printf(b, "__attribute_used__\n");
603         buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
604         buf_printf(b, "\"depends=");
605         for (s = mod->unres; s; s = s->next) {
606                 if (!s->module)
607                         continue;
608
609                 if (s->module->seen)
610                         continue;
611
612                 s->module->seen = 1;
613                 buf_printf(b, "%s%s", first ? "" : ",",
614                            strrchr(s->module->name, '/') + 1);
615                 first = 0;
616         }
617         buf_printf(b, "\";\n");
618 }
619
620 void
621 add_srcversion(struct buffer *b, struct module *mod)
622 {
623         if (mod->srcversion[0]) {
624                 buf_printf(b, "\n");
625                 buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
626                            mod->srcversion);
627         }
628 }
629
630 void
631 write_if_changed(struct buffer *b, const char *fname)
632 {
633         char *tmp;
634         FILE *file;
635         struct stat st;
636
637         file = fopen(fname, "r");
638         if (!file)
639                 goto write;
640
641         if (fstat(fileno(file), &st) < 0)
642                 goto close_write;
643
644         if (st.st_size != b->pos)
645                 goto close_write;
646
647         tmp = NOFAIL(malloc(b->pos));
648         if (fread(tmp, 1, b->pos, file) != b->pos)
649                 goto free_write;
650
651         if (memcmp(tmp, b->p, b->pos) != 0)
652                 goto free_write;
653
654         free(tmp);
655         fclose(file);
656         return;
657
658  free_write:
659         free(tmp);
660  close_write:
661         fclose(file);
662  write:
663         file = fopen(fname, "w");
664         if (!file) {
665                 perror(fname);
666                 exit(1);
667         }
668         if (fwrite(b->p, 1, b->pos, file) != b->pos) {
669                 perror(fname);
670                 exit(1);
671         }
672         fclose(file);
673 }
674
675 void
676 read_dump(const char *fname)
677 {
678         unsigned long size, pos = 0;
679         void *file = grab_file(fname, &size);
680         char *line;
681
682         if (!file)
683                 /* No symbol versions, silently ignore */
684                 return;
685
686         while ((line = get_next_line(&pos, file, size))) {
687                 char *symname, *modname, *d;
688                 unsigned int crc;
689                 struct module *mod;
690
691                 if (!(symname = strchr(line, '\t')))
692                         goto fail;
693                 *symname++ = '\0';
694                 if (!(modname = strchr(symname, '\t')))
695                         goto fail;
696                 *modname++ = '\0';
697                 if (strchr(modname, '\t'))
698                         goto fail;
699                 crc = strtoul(line, &d, 16);
700                 if (*symname == '\0' || *modname == '\0' || *d != '\0')
701                         goto fail;
702
703                 if (!(mod = find_module(modname))) {
704                         if (is_vmlinux(modname)) {
705                                 have_vmlinux = 1;
706                         }
707                         mod = new_module(NOFAIL(strdup(modname)));
708                         mod->skip = 1;
709                 }
710                 add_exported_symbol(symname, mod, &crc);
711         }
712         return;
713 fail:
714         fatal("parse error in symbol dump file\n");
715 }
716
717 void
718 write_dump(const char *fname)
719 {
720         struct buffer buf = { };
721         struct symbol *symbol;
722         int n;
723
724         for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
725                 symbol = symbolhash[n];
726                 while (symbol) {
727                         symbol = symbol->next;
728                 }
729         }
730
731         for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
732                 symbol = symbolhash[n];
733                 while (symbol) {
734                         buf_printf(&buf, "0x%08x\t%s\t%s\n", symbol->crc,
735                                 symbol->name, symbol->module->name);
736                         symbol = symbol->next;
737                 }
738         }
739         write_if_changed(&buf, fname);
740 }
741
742 int
743 main(int argc, char **argv)
744 {
745         struct module *mod;
746         struct buffer buf = { };
747         char fname[SZ];
748         char *dump_read = NULL, *dump_write = NULL;
749         int opt;
750
751         while ((opt = getopt(argc, argv, "i:mo:a")) != -1) {
752                 switch(opt) {
753                         case 'i':
754                                 dump_read = optarg;
755                                 break;
756                         case 'm':
757                                 modversions = 1;
758                                 break;
759                         case 'o':
760                                 dump_write = optarg;
761                                 break;
762                         case 'a':
763                                 all_versions = 1;
764                                 break;
765                         default:
766                                 exit(1);
767                 }
768         }
769
770         if (dump_read)
771                 read_dump(dump_read);
772
773         while (optind < argc) {
774                 read_symbols(argv[optind++]);
775         }
776
777         for (mod = modules; mod; mod = mod->next) {
778                 if (mod->skip)
779                         continue;
780
781                 buf.pos = 0;
782
783                 add_header(&buf, mod);
784                 add_versions(&buf, mod);
785                 add_depends(&buf, mod, modules);
786                 add_moddevtable(&buf, mod);
787                 add_srcversion(&buf, mod);
788
789                 sprintf(fname, "%s.mod.c", mod->name);
790                 write_if_changed(&buf, fname);
791         }
792
793         if (dump_write)
794                 write_dump(dump_write);
795
796         return 0;
797 }
798