]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
kmod-depmod: implement -F and -E options.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Sat, 24 Dec 2011 12:31:55 +0000 (10:31 -0200)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Tue, 27 Dec 2011 14:09:16 +0000 (12:09 -0200)
Read System.map and Module.symvers from kernel built, then be able to
report unknown symbols.

tools/kmod-depmod.c

index a5ec631141d0aa701afdc8eb41a642147e314d64..89a339cdc29fe2063d8e35b9b752b671a1745e82 100644 (file)
@@ -2688,6 +2688,112 @@ static int depmod_output(struct depmod *depmod, FILE *out)
        return err;
 }
 
+static void depmod_add_fake_syms(struct depmod *depmod)
+{
+       /* __this_module is magic inserted by kernel loader. */
+       depmod_symbol_add(depmod, "__this_module", 0, NULL);
+       /* On S390, this is faked up too */
+       depmod_symbol_add(depmod, "_GLOBAL_OFFSET_TABLE_", 0, NULL);
+}
+
+static int depmod_load_symvers(struct depmod *depmod, const char *filename)
+{
+       char line[10240];
+       FILE *fp;
+       unsigned int linenum = 0;
+       int err;
+
+       fp = fopen(filename, "r");
+       err = -errno;
+       DBG("load symvers: %s: %s\n", filename, strerror(-err));
+       if (fp == NULL)
+               return err;
+
+       /* eg. "0xb352177e\tfind_first_bit\tvmlinux\tEXPORT_SYMBOL" */
+       while (fgets(line, sizeof(line), fp) != NULL) {
+               const char *ver, *sym, *where;
+               char *verend;
+               uint64_t crc;
+
+               linenum++;
+
+               ver = strtok(line, " \t");
+               sym = strtok(NULL, " \t");
+               where = strtok(NULL, " \t");
+               if (!ver || !sym || !where)
+                       continue;
+
+               if (!streq(where, "vmlinux"))
+                       continue;
+
+               crc = strtoull(ver, &verend, 16);
+               if (verend[0] != '\0') {
+                       ERR("%s:%u Invalid symbol version %s: %m\n",
+                           filename, linenum, ver);
+                       continue;
+               }
+
+               depmod_symbol_add(depmod, sym, crc, NULL);
+       }
+       depmod_add_fake_syms(depmod);
+
+       DBG("loaded symvers: %s: %s\n", filename, strerror(-err));
+
+       fclose(fp);
+       return err;
+}
+
+static int depmod_load_system_map(struct depmod *depmod, const char *filename)
+{
+       const char ksymstr[] = "__ksymtab_";
+       const size_t ksymstr_len = sizeof(ksymstr) - 1;
+       char line[10240];
+       FILE *fp;
+       unsigned int linenum = 0;
+       int err;
+
+       fp = fopen(filename, "r");
+       err = -errno;
+       DBG("load System.map: %s: %s\n", filename, strerror(-err));
+       if (fp == NULL)
+               return err;
+
+       /* eg. c0294200 R __ksymtab_devfs_alloc_devnum */
+       while (fgets(line, sizeof(line), fp) != NULL) {
+               char *p, *end;
+
+               linenum++;
+
+               p = strchr(line, ' ');
+               if (p == NULL)
+                       goto invalid_syntax;
+               p++;
+               p = strchr(p, ' ');
+               if (p == NULL)
+                       goto invalid_syntax;
+               p++;
+
+               /* Covers gpl-only and normal symbols. */
+               if (strncmp(p, ksymstr, ksymstr_len) != 0)
+                       continue;
+
+               end = strchr(p, '\n');
+               if (end != NULL)
+                       *end = '\0';
+
+               depmod_symbol_add(depmod, p + ksymstr_len, 0, NULL);
+               continue;
+
+       invalid_syntax:
+               ERR("%s:%u: invalid line: %s\n", filename, linenum, line);
+       }
+       depmod_add_fake_syms(depmod);
+
+       DBG("loaded System.map: %s: %s\n", filename, strerror(-err));
+
+       fclose(fp);
+       return err;
+}
 
 static int depfile_up_to_date(const char *dirname)
 {
@@ -2843,6 +2949,25 @@ int main(int argc, char *argv[])
        }
        ctx = NULL; /* owned by depmod */
 
+       if (module_symvers != NULL) {
+               err = depmod_load_symvers(&depmod, module_symvers);
+               if (err < 0) {
+                       CRIT("Could not load %s: %s\n", module_symvers,
+                            strerror(-err));
+                       goto cmdline_failed;
+               }
+       } else if (system_map != NULL) {
+               err = depmod_load_system_map(&depmod, system_map);
+               if (err < 0) {
+                       CRIT("Could not load %s: %s\n", module_symvers,
+                            strerror(-err));
+                       goto cmdline_failed;
+               }
+       } else if (cfg.print_unknown) {
+               WRN("-e needs -E or -F\n");
+               cfg.print_unknown = 0;
+       }
+
        if (all) {
                err = cfg_load(&cfg, config_paths);
                if (err < 0) {