modpost white list pattern adjustment
[safe/jmp/linux-2.6] / scripts / mod / modpost.c
index e26381e..3f3848f 100644 (file)
@@ -55,6 +55,17 @@ void warn(const char *fmt, ...)
        va_end(arglist);
 }
 
+void merror(const char *fmt, ...)
+{
+       va_list arglist;
+
+       fprintf(stderr, "ERROR: ");
+
+       va_start(arglist, fmt);
+       vfprintf(stderr, fmt, arglist);
+       va_end(arglist);
+}
+
 static int is_vmlinux(const char *modname)
 {
        const char *myname;
@@ -64,7 +75,8 @@ static int is_vmlinux(const char *modname)
        else
                myname = modname;
 
-       return strcmp(myname, "vmlinux") == 0;
+       return (strcmp(myname, "vmlinux") == 0) ||
+              (strcmp(myname, "vmlinux.o") == 0);
 }
 
 void *do_nofail(void *ptr, const char *expr)
@@ -333,10 +345,10 @@ void release_file(void *file, unsigned long size)
        munmap(file, size);
 }
 
-static void parse_elf(struct elf_info *info, const char *filename)
+static int parse_elf(struct elf_info *info, const char *filename)
 {
        unsigned int i;
-       Elf_Ehdr *hdr = info->hdr;
+       Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
        Elf_Sym  *sym;
 
@@ -346,14 +358,24 @@ static void parse_elf(struct elf_info *info, const char *filename)
                exit(1);
        }
        info->hdr = hdr;
-       if (info->size < sizeof(*hdr))
-               goto truncated;
-
+       if (info->size < sizeof(*hdr)) {
+               /* file too small, assume this is an empty .o file */
+               return 0;
+       }
+       /* Is this a valid ELF file? */
+       if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+           (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+           (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+           (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+               /* Not an ELF file - silently ignore it */
+               return 0;
+       }
        /* 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);
        hdr->e_machine  = TO_NATIVE(hdr->e_machine);
+       hdr->e_type     = TO_NATIVE(hdr->e_type);
        sechdrs = (void *)hdr + hdr->e_shoff;
        info->sechdrs = sechdrs;
 
@@ -364,6 +386,8 @@ static void parse_elf(struct elf_info *info, const char *filename)
                sechdrs[i].sh_size   = TO_NATIVE(sechdrs[i].sh_size);
                sechdrs[i].sh_link   = TO_NATIVE(sechdrs[i].sh_link);
                sechdrs[i].sh_name   = TO_NATIVE(sechdrs[i].sh_name);
+               sechdrs[i].sh_info   = TO_NATIVE(sechdrs[i].sh_info);
+               sechdrs[i].sh_addr   = TO_NATIVE(sechdrs[i].sh_addr);
        }
        /* Find symbol table. */
        for (i = 1; i < hdr->e_shnum; i++) {
@@ -371,8 +395,10 @@ static void parse_elf(struct elf_info *info, const char *filename)
                        = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
                const char *secname;
 
-               if (sechdrs[i].sh_offset > info->size)
-                       goto truncated;
+               if (sechdrs[i].sh_offset > info->size) {
+                       fatal("%s is truncated. sechdrs[i].sh_offset=%u > sizeof(*hrd)=%ul\n", filename, (unsigned int)sechdrs[i].sh_offset, sizeof(*hdr));
+                       return 0;
+               }
                secname = secstrings + sechdrs[i].sh_name;
                if (strcmp(secname, ".modinfo") == 0) {
                        info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
@@ -407,10 +433,7 @@ static void parse_elf(struct elf_info *info, const char *filename)
                sym->st_value = TO_NATIVE(sym->st_value);
                sym->st_size  = TO_NATIVE(sym->st_size);
        }
-       return;
-
- truncated:
-       fatal("%s is truncated.\n", filename);
+       return 1;
 }
 
 static void parse_elf_finish(struct elf_info *info)
@@ -563,6 +586,12 @@ static int strrcmp(const char *s, const char *sub)
 
 /**
  * Whitelist to allow certain references to pass with no warning.
+ *
+ * Pattern 0:
+ *   Do not warn if funtion/data are marked with __init_refok/__initdata_refok.
+ *   The pattern is identified by:
+ *   fromsec = .text.init.refok | .data.init.refok
+ *
  * Pattern 1:
  *   If a module parameter is declared __initdata and permissions=0
  *   then this is legal despite the warning generated.
@@ -580,24 +609,53 @@ static int strrcmp(const char *s, const char *sub)
  *   warn here.
  *   the pattern is identified by:
  *   tosec   = .init.text | .exit.text | .init.data
- *   fromsec = .data
- *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one
+ *   fromsec = .data | .data.rel | .data.rel.*
+ *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console, *_timer
+ *
+ * Pattern 3:
+ *   Whitelist all refereces from .text.head to .init.data
+ *   Whitelist all refereces from .text.head to .init.text
+ *
+ * Pattern 4:
+ *   Some symbols belong to init section but still it is ok to reference
+ *   these from non-init sections as these symbols don't have any memory
+ *   allocated for them and symbol address and value are same. So even
+ *   if init section is freed, its ok to reference those symbols.
+ *   For ex. symbols marking the init section boundaries.
+ *   This pattern is identified by
+ *   refsymname = __init_begin, _sinittext, _einittext
+ *
  **/
 static int secref_whitelist(const char *modname, const char *tosec,
-                           const char *fromsec, const char *atsym)
+                           const char *fromsec, const char *atsym,
+                           const char *refsymname)
 {
        int f1 = 1, f2 = 1;
        const char **s;
        const char *pat2sym[] = {
                "driver",
                "_template", /* scsi uses *_template a lot */
+               "_timer",    /* arm uses ops structures named _timer a lot */
                "_sht",      /* scsi also used *_sht to some extent */
                "_ops",
                "_probe",
                "_probe_one",
+               "_console",
                NULL
        };
 
+       const char *pat3refsym[] = {
+               "__init_begin",
+               "_sinittext",
+               "_einittext",
+               NULL
+       };
+
+       /* Check for pattern 0 */
+       if ((strcmp(fromsec, ".text.init.refok") == 0) ||
+           (strcmp(fromsec, ".data.init.refok") == 0))
+               return 1;
+
        /* Check for pattern 1 */
        if (strcmp(tosec, ".init.data") != 0)
                f1 = 0;
@@ -614,7 +672,9 @@ static int secref_whitelist(const char *modname, const char *tosec,
            (strcmp(tosec, ".exit.text") != 0) &&
            (strcmp(tosec, ".init.data") != 0))
                f2 = 0;
-       if (strcmp(fromsec, ".data") != 0)
+       if ((strcmp(fromsec, ".data") != 0) &&
+           (strcmp(fromsec, ".data.rel") != 0) &&
+           (strncmp(fromsec, ".data.rel.", strlen(".data.rel.")) != 0))
                f2 = 0;
 
        for (s = pat2sym; *s; s++)
@@ -623,12 +683,17 @@ static int secref_whitelist(const char *modname, const char *tosec,
        if (f1 && f2)
                return 1;
 
-       /* Whitelist all references from .pci_fixup section if vmlinux */
-       if (is_vmlinux(modname)) {
-               if ((strcmp(fromsec, ".pci_fixup") == 0) &&
-                   (strcmp(tosec, ".init.text") == 0))
-               return 1;
-       }
+       /* Check for pattern 3 */
+       if ((strcmp(fromsec, ".text.head") == 0) &&
+               ((strcmp(tosec, ".init.data") == 0) ||
+               (strcmp(tosec, ".init.text") == 0)))
+       return 1;
+
+       /* Check for pattern 4 */
+       for (s = pat3refsym; *s; s++)
+               if (strcmp(refsymname, *s) == 0)
+                       return 1;
+
        return 0;
 }
 
@@ -649,12 +714,38 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
        for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
                if (sym->st_shndx != relsym->st_shndx)
                        continue;
+               if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
+                       continue;
                if (sym->st_value == addr)
                        return sym;
        }
        return NULL;
 }
 
+static inline int is_arm_mapping_symbol(const char *str)
+{
+       return str[0] == '$' && strchr("atd", str[1])
+              && (str[2] == '\0' || str[2] == '.');
+}
+
+/*
+ * If there's no name there, ignore it; likewise, ignore it if it's
+ * one of the magic symbols emitted used by current ARM tools.
+ *
+ * Otherwise if find_symbols_between() returns those symbols, they'll
+ * fail the whitelist tests and cause lots of false alarms ... fixable
+ * only by merging __exit and __init sections into __text, bloating
+ * the kernel (which is especially evil on embedded platforms).
+ */
+static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym)
+{
+       const char *name = elf->strtab + sym->st_name;
+
+       if (!name || !strlen(name))
+               return 0;
+       return !is_arm_mapping_symbol(name);
+}
+
 /*
  * Find symbols before or equal addr and after addr - in the section sec.
  * If we find two symbols with equal offset prefer one with a valid name.
@@ -683,16 +774,15 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                symsec = secstrings + elf->sechdrs[sym->st_shndx].sh_name;
                if (strcmp(symsec, sec) != 0)
                        continue;
+               if (!is_valid_name(elf, sym))
+                       continue;
                if (sym->st_value <= addr) {
                        if ((addr - sym->st_value) < beforediff) {
                                beforediff = addr - sym->st_value;
                                *before = sym;
                        }
                        else if ((addr - sym->st_value) == beforediff) {
-                               /* equal offset, valid name? */
-                               const char *name = elf->strtab + sym->st_name;
-                               if (name && strlen(name))
-                                       *before = sym;
+                               *before = sym;
                        }
                }
                else
@@ -702,10 +792,7 @@ static void find_symbols_between(struct elf_info *elf, Elf_Addr addr,
                                *after = sym;
                        }
                        else if ((sym->st_value - addr) == afterdiff) {
-                               /* equal offset, valid name? */
-                               const char *name = elf->strtab + sym->st_name;
-                               if (name && strlen(name))
-                                       *after = sym;
+                               *after = sym;
                        }
                }
        }
@@ -737,34 +824,105 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
        /* check whitelist - we may ignore it */
        if (before &&
            secref_whitelist(modname, secname, fromsec,
-                            elf->strtab + before->st_name))
+                            elf->strtab + before->st_name, refsymname))
                return;
 
        if (before && after) {
-               warn("%s - Section mismatch: reference to %s:%s from %s "
-                    "between '%s' (at offset 0x%llx) and '%s'\n",
-                    modname, secname, refsymname, fromsec,
+               warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
+                    "(between '%s' and '%s')\n",
+                    modname, fromsec, (unsigned long long)r.r_offset,
+                    secname, refsymname,
                     elf->strtab + before->st_name,
-                    (long long)r.r_offset,
                     elf->strtab + after->st_name);
        } else if (before) {
-               warn("%s - Section mismatch: reference to %s:%s from %s "
-                    "after '%s' (at offset 0x%llx)\n",
-                    modname, secname, refsymname, fromsec,
-                    elf->strtab + before->st_name,
-                    (long long)r.r_offset);
+               warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
+                    "(after '%s')\n",
+                    modname, fromsec, (unsigned long long)r.r_offset,
+                    secname, refsymname,
+                    elf->strtab + before->st_name);
        } else if (after) {
-               warn("%s - Section mismatch: reference to %s:%s from %s "
+               warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
                     "before '%s' (at offset -0x%llx)\n",
-                    modname, secname, refsymname, fromsec,
-                    elf->strtab + after->st_name,
-                    (long long)r.r_offset);
+                    modname, fromsec, (unsigned long long)r.r_offset,
+                    secname, refsymname,
+                    elf->strtab + after->st_name);
        } else {
-               warn("%s - Section mismatch: reference to %s:%s from %s "
-                    "(offset 0x%llx)\n",
-                    modname, secname, fromsec, refsymname,
-                    (long long)r.r_offset);
+               warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s\n",
+                    modname, fromsec, (unsigned long long)r.r_offset,
+                    secname, refsymname);
+       }
+}
+
+static unsigned int *reloc_location(struct elf_info *elf,
+                                          int rsection, Elf_Rela *r)
+{
+       Elf_Shdr *sechdrs = elf->sechdrs;
+       int section = sechdrs[rsection].sh_info;
+
+       return (void *)elf->hdr + sechdrs[section].sh_offset +
+               (r->r_offset - sechdrs[section].sh_addr);
+}
+
+static int addend_386_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+       unsigned int r_typ = ELF_R_TYPE(r->r_info);
+       unsigned int *location = reloc_location(elf, rsection, r);
+
+       switch (r_typ) {
+       case R_386_32:
+               r->r_addend = TO_NATIVE(*location);
+               break;
+       case R_386_PC32:
+               r->r_addend = TO_NATIVE(*location) + 4;
+               /* For CONFIG_RELOCATABLE=y */
+               if (elf->hdr->e_type == ET_EXEC)
+                       r->r_addend += r->r_offset;
+               break;
+       }
+       return 0;
+}
+
+static int addend_arm_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+       unsigned int r_typ = ELF_R_TYPE(r->r_info);
+
+       switch (r_typ) {
+       case R_ARM_ABS32:
+               /* From ARM ABI: (S + A) | T */
+               r->r_addend = (int)(long)(elf->symtab_start + ELF_R_SYM(r->r_info));
+               break;
+       case R_ARM_PC24:
+               /* From ARM ABI: ((S + A) | T) - P */
+               r->r_addend = (int)(long)(elf->hdr + elf->sechdrs[rsection].sh_offset +
+                                         (r->r_offset - elf->sechdrs[rsection].sh_addr));
+               break;
+       default:
+               return 1;
+       }
+       return 0;
+}
+
+static int addend_mips_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+       unsigned int r_typ = ELF_R_TYPE(r->r_info);
+       unsigned int *location = reloc_location(elf, rsection, r);
+       unsigned int inst;
+
+       if (r_typ == R_MIPS_HI16)
+               return 1;       /* skip this */
+       inst = TO_NATIVE(*location);
+       switch (r_typ) {
+       case R_MIPS_LO16:
+               r->r_addend = inst & 0xffff;
+               break;
+       case R_MIPS_26:
+               r->r_addend = (inst & 0x03ffffff) << 2;
+               break;
+       case R_MIPS_32:
+               r->r_addend = inst;
+               break;
        }
+       return 0;
 }
 
 /**
@@ -810,8 +968,11 @@ static void check_sec_ref(struct module *mod, const char *modname,
                                r.r_offset = TO_NATIVE(rela->r_offset);
 #if KERNEL_ELFCLASS == ELFCLASS64
                                if (hdr->e_machine == EM_MIPS) {
+                                       unsigned int r_typ;
                                        r_sym = ELF64_MIPS_R_SYM(rela->r_info);
                                        r_sym = TO_NATIVE(r_sym);
+                                       r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
+                                       r.r_info = ELF64_R_INFO(r_sym, r_typ);
                                } else {
                                        r.r_info = TO_NATIVE(rela->r_info);
                                        r_sym = ELF_R_SYM(r.r_info);
@@ -844,8 +1005,11 @@ static void check_sec_ref(struct module *mod, const char *modname,
                                r.r_offset = TO_NATIVE(rel->r_offset);
 #if KERNEL_ELFCLASS == ELFCLASS64
                                if (hdr->e_machine == EM_MIPS) {
+                                       unsigned int r_typ;
                                        r_sym = ELF64_MIPS_R_SYM(rel->r_info);
                                        r_sym = TO_NATIVE(r_sym);
+                                       r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
+                                       r.r_info = ELF64_R_INFO(r_sym, r_typ);
                                } else {
                                        r.r_info = TO_NATIVE(rel->r_info);
                                        r_sym = ELF_R_SYM(r.r_info);
@@ -855,6 +1019,20 @@ static void check_sec_ref(struct module *mod, const char *modname,
                                r_sym = ELF_R_SYM(r.r_info);
 #endif
                                r.r_addend = 0;
+                               switch (hdr->e_machine) {
+                               case EM_386:
+                                       if (addend_386_rel(elf, i, &r))
+                                               continue;
+                                       break;
+                               case EM_ARM:
+                                       if(addend_arm_rel(elf, i, &r))
+                                               continue;
+                                       break;
+                               case EM_MIPS:
+                                       if (addend_mips_rel(elf, i, &r))
+                                               continue;
+                                       break;
+                               }
                                sym = elf->symtab_start + r_sym;
                                /* Skip special sections */
                                if (sym->st_shndx >= SHN_LORESERVE)
@@ -870,6 +1048,63 @@ static void check_sec_ref(struct module *mod, const char *modname,
        }
 }
 
+/*
+ * Identify sections from which references to either a
+ * .init or a .exit section is OK.
+ *
+ * [OPD] Keith Ownes <kaos@sgi.com> commented:
+ * For our future {in}sanity, add a comment that this is the ppc .opd
+ * section, not the ia64 .opd section.
+ * ia64 .opd should not point to discarded sections.
+ * [.rodata] like for .init.text we ignore .rodata references -same reason
+ */
+static int initexit_section_ref_ok(const char *name)
+{
+       const char **s;
+       /* Absolute section names */
+       const char *namelist1[] = {
+               "__bug_table",          /* used by powerpc for BUG() */
+               "__ex_table",
+               ".altinstructions",
+               ".cranges",             /* used by sh64 */
+               ".fixup",
+               ".machvec",             /* ia64 + powerpc uses these */
+               ".machine.desc",
+               ".opd",                 /* See comment [OPD] */
+               ".parainstructions",
+               ".pdr",
+               ".plt",                 /* seen on ARCH=um build on x86_64. Harmless */
+               ".smp_locks",
+               ".stab",
+               NULL
+       };
+       /* Start of section names */
+       const char *namelist2[] = {
+               ".debug",
+               ".eh_frame",
+               ".note",                /* ignore ELF notes - may contain anything */
+               ".got",                 /* powerpc - global offset table */
+               ".toc",                 /* powerpc - table of contents */
+               NULL
+       };
+       /* part of section name */
+       const char *namelist3 [] = {
+               ".unwind",  /* Sample: IA_64.unwind.exit.text */
+               NULL
+       };
+
+       for (s = namelist1; *s; s++)
+               if (strcmp(*s, name) == 0)
+                       return 1;
+       for (s = namelist2; *s; s++)
+               if (strncmp(*s, name, strlen(*s)) == 0)
+                       return 1;
+       for (s = namelist3; *s; s++)
+               if (strstr(name, *s) != NULL)
+                       return 1;
+       return 0;
+}
+
 /**
  * Functions used only during module init is marked __init and is stored in
  * a .init.text section. Likewise data is marked __initdata and stored in
@@ -886,7 +1121,7 @@ static int init_section(const char *name)
        return 0;
 }
 
-/**
+/*
  * Identify sections from which references to a .init section is OK.
  *
  * Unfortunately references to read only data that referenced .init
@@ -900,47 +1135,30 @@ static int init_section(const char *name)
  *
  * where vgacon_startup is __init.  If you want to wade through the false
  * positives, take out the check for rodata.
- **/
+ */
 static int init_section_ref_ok(const char *name)
 {
        const char **s;
        /* Absolute section names */
        const char *namelist1[] = {
-               ".init",
-               ".opd",   /* see comment [OPD] at exit_section_ref_ok() */
-               ".toc1",  /* used by ppc64 */
-               ".stab",
-               ".data.rel.ro", /* used by parisc64 */
-               ".parainstructions",
-               ".text.lock",
-               "__bug_table", /* used by powerpc for BUG() */
-               ".pci_fixup_header",
-               ".pci_fixup_final",
-               ".pdr",
-               "__param",
-               "__ex_table",
-               ".fixup",
-               ".smp_locks",
-               ".plt",  /* seen on ARCH=um build on x86_64. Harmless */
                "__ftr_fixup",          /* powerpc cpu feature fixup */
                "__fw_ftr_fixup",       /* powerpc firmware feature fixup */
+               "__param",
+               ".data.rel.ro",         /* used by parisc64 */
+               ".init",
+               ".text.lock",
                NULL
        };
        /* Start of section names */
        const char *namelist2[] = {
                ".init.",
-               ".altinstructions",
-               ".eh_frame",
-               ".debug",
-               ".parainstructions",
+               ".pci_fixup",
                ".rodata",
                NULL
        };
-       /* part of section name */
-       const char *namelist3 [] = {
-               ".unwind",  /* sample: IA_64.unwind.init.text */
-               NULL
-       };
+
+       if (initexit_section_ref_ok(name))
+               return 1;
 
        for (s = namelist1; *s; s++)
                if (strcmp(*s, name) == 0)
@@ -948,9 +1166,10 @@ static int init_section_ref_ok(const char *name)
        for (s = namelist2; *s; s++)
                if (strncmp(*s, name, strlen(*s)) == 0)
                        return 1;
-       for (s = namelist3; *s; s++)
-               if (strstr(name, *s) != NULL)
-                       return 1;
+
+       /* If section name ends with ".init" we allow references
+        * as is the case with .initcallN.init, .early_param.init, .taglist.init etc
+        */
        if (strrcmp(name, ".init") == 0)
                return 1;
        return 0;
@@ -975,56 +1194,25 @@ static int exit_section(const char *name)
 
 /*
  * Identify sections from which references to a .exit section is OK.
- *
- * [OPD] Keith Ownes <kaos@sgi.com> commented:
- * For our future {in}sanity, add a comment that this is the ppc .opd
- * section, not the ia64 .opd section.
- * ia64 .opd should not point to discarded sections.
- * [.rodata] like for .init.text we ignore .rodata references -same reason
- **/
+ */
 static int exit_section_ref_ok(const char *name)
 {
        const char **s;
        /* Absolute section names */
        const char *namelist1[] = {
-               ".exit.text",
                ".exit.data",
-               ".init.text",
-               ".rodata",
-               ".opd", /* See comment [OPD] */
-               ".toc1",  /* used by ppc64 */
-               ".altinstructions",
-               ".pdr",
-               "__bug_table", /* used by powerpc for BUG() */
+               ".exit.text",
                ".exitcall.exit",
-               ".eh_frame",
-               ".stab",
-               "__ex_table",
-               ".fixup",
-               ".smp_locks",
-               ".plt",  /* seen on ARCH=um build on x86_64. Harmless */
-               NULL
-       };
-       /* Start of section names */
-       const char *namelist2[] = {
-               ".debug",
-               NULL
-       };
-       /* part of section name */
-       const char *namelist3 [] = {
-               ".unwind",  /* Sample: IA_64.unwind.exit.text */
+               ".rodata",
                NULL
        };
 
+       if (initexit_section_ref_ok(name))
+               return 1;
+
        for (s = namelist1; *s; s++)
                if (strcmp(*s, name) == 0)
                        return 1;
-       for (s = namelist2; *s; s++)
-               if (strncmp(*s, name, strlen(*s)) == 0)
-                       return 1;
-       for (s = namelist3; *s; s++)
-               if (strstr(name, *s) != NULL)
-                       return 1;
        return 0;
 }
 
@@ -1037,7 +1225,8 @@ static void read_symbols(char *modname)
        struct elf_info info = { };
        Elf_Sym *sym;
 
-       parse_elf(&info, modname);
+       if (!parse_elf(&info, modname))
+               return;
 
        mod = new_module(modname);
 
@@ -1197,6 +1386,7 @@ static void add_header(struct buffer *b, struct module *mod)
                buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
                              " .exit = cleanup_module,\n"
                              "#endif\n");
+       buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
        buf_printf(b, "};\n");
 }
 
@@ -1212,9 +1402,14 @@ static int add_versions(struct buffer *b, struct module *mod)
                exp = find_symbol(s->name);
                if (!exp || exp->module == mod) {
                        if (have_vmlinux && !s->weak) {
-                               warn("\"%s\" [%s.ko] undefined!\n",
-                                    s->name, mod->name);
-                               err = warn_unresolved ? 0 : 1;
+                               if (warn_unresolved) {
+                                       warn("\"%s\" [%s.ko] undefined!\n",
+                                            s->name, mod->name);
+                               } else {
+                                       merror("\"%s\" [%s.ko] undefined!\n",
+                                                 s->name, mod->name);
+                                       err = 1;
+                               }
                        }
                        continue;
                }
@@ -1265,6 +1460,7 @@ static void add_depends(struct buffer *b, struct module *mod,
        buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
        buf_printf(b, "\"depends=");
        for (s = mod->unres; s; s = s->next) {
+               const char *p;
                if (!s->module)
                        continue;
 
@@ -1272,8 +1468,11 @@ static void add_depends(struct buffer *b, struct module *mod,
                        continue;
 
                s->module->seen = 1;
-               buf_printf(b, "%s%s", first ? "" : ",",
-                          strrchr(s->module->name, '/') + 1);
+               if ((p = strrchr(s->module->name, '/')) != NULL)
+                       p++;
+               else
+                       p = s->module->name;
+               buf_printf(b, "%s%s", first ? "" : ",", p);
                first = 0;
        }
        buf_printf(b, "\";\n");