Cc: xe-linux-external@xxxxxxxxx
Cc: Valerii Chernous <vchernou@xxxxxxxxx>
Signed-off-by: Valerii Chernous <vchernou@xxxxxxxxx>
---
libkmod/libkmod-internal.h | 5 ++
libkmod/libkmod-module.c | 5 --
shared/util.c | 20 ++++++
shared/util.h | 1 +
tools/depmod.c | 144 +++++++++++++++++++++++++++++++++----
5 files changed, 155 insertions(+), 20 deletions(-)
diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index 3bc6e11..0a274e7 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -68,6 +68,11 @@ enum kmod_file_compression_type {
KMOD_FILE_COMPRESSION_ZLIB,
};
+struct kmod_module_info {
+ char *key;
+ char value[];
+};
+
struct kmod_list *kmod_list_append(struct kmod_list *list, const void *data) _must_check_ __attribute__((nonnull(2)));
struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data) _must_check_ __attribute__((nonnull(2)));
struct kmod_list *kmod_list_remove(struct kmod_list *list) _must_check_;
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index d309948..2cdec34 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -2261,11 +2261,6 @@ static struct kmod_elf *kmod_module_get_elf(const struct kmod_module *mod)
return kmod_file_get_elf(mod->file);
}
-struct kmod_module_info {
- char *key;
- char value[];
-};
-
static struct kmod_module_info *kmod_module_info_new(const char *key, size_t keylen, const char *value, size_t valuelen)
{
struct kmod_module_info *info;
diff --git a/shared/util.c b/shared/util.c
index e2bab83..ea4b9c0 100644
--- a/shared/util.c
+++ b/shared/util.c
@@ -546,3 +546,23 @@ unsigned long long stat_mstamp(const struct stat *st)
return (unsigned long long) st->st_mtime;
#endif
}
+
+int str_in_coma_separated_str_list(const char *where, const char *what)
+{
+ char *p = strstr(where, what);
+ if (p) {
+ int is_head_ok, is_tail_ok;
+ size_t l = strlen(what);
+ if (p == where || (p > where && *(p-1) == ','))
+ is_head_ok = 1;
+ else
+ is_head_ok = 0;
+ if (*(p+l) == 0 || *(p+l) == ',')
+ is_tail_ok = 1;
+ else
+ is_tail_ok = 0;
+ if (is_head_ok == 1 && is_tail_ok == 1)
+ return p - where;
+ }
+ return -1;
+}
diff --git a/shared/util.h b/shared/util.h
index c4a3916..4337bd6 100644
--- a/shared/util.h
+++ b/shared/util.h
@@ -17,6 +17,7 @@
#define strstartswith(a, b) (strncmp(a, b, strlen(b)) == 0)
char *strchr_replace(char *s, char c, char r);
void *memdup(const void *p, size_t n) __attribute__((nonnull(1)));
+int str_in_coma_separated_str_list(const char *where, const char *what);
/* module-related functions */
/* ************************************************************************ */
diff --git a/tools/depmod.c b/tools/depmod.c
index 43fc354..24f79c4 100644
--- a/tools/depmod.c
+++ b/tools/depmod.c
@@ -59,7 +59,7 @@ static const char *const default_cfg_paths[] = {
NULL
};
-static const char cmdopts_s[] = "aAb:o:C:E:F:euqrvnP:wmVh";
+static const char cmdopts_s[] = "aAb:o:C:E:F:DeuqrvnP:wmVh";
static const struct option cmdopts[] = {
{ "all", no_argument, 0, 'a' },
{ "quick", no_argument, 0, 'A' },
@@ -68,6 +68,7 @@ static const struct option cmdopts[] = {
{ "config", required_argument, 0, 'C' },
{ "symvers", required_argument, 0, 'E' },
{ "filesyms", required_argument, 0, 'F' },
+ { "deps-alternatives", no_argument, 0, 'D' },
{ "errsyms", no_argument, 0, 'e' },
{ "unresolved-error", no_argument, 0, 'u' }, /* deprecated */
{ "quiet", no_argument, 0, 'q' }, /* deprecated */
@@ -95,6 +96,7 @@ static void help(void)
"Options:\n"
"\t-a, --all Probe all modules\n"
"\t-A, --quick Only does the work if there's a new module\n"
+ "\t-D, --deps-alternatives using symbols alternatives for generating modules deps\n"
"\t-e, --errsyms Report not supplied symbols\n"
"\t-n, --show Write the dependency file on stdout only\n"
"\t-P, --symbol-prefix Architecture symbol prefix\n"
@@ -476,6 +478,7 @@ struct cfg {
uint8_t check_symvers;
uint8_t print_unknown;
uint8_t warn_dups;
+ uint8_t use_deps_alternatives;
struct cfg_override *overrides;
struct cfg_search *searches;
struct cfg_external *externals;
@@ -924,10 +927,12 @@ struct mod {
uint16_t users; /* how many modules depend on this one */
bool visited; /* helper field to report cycles */
struct vertex *vertex; /* helper field to report cycles */
+ struct kmod_module_info *deps_from_mod_info;
char modname[];
};
struct symbol {
+ struct symbol *next;
struct mod *owner;
uint64_t crc;
char name[];
@@ -975,13 +980,40 @@ static int mod_add_dependency(struct mod *mod, struct symbol *sym)
return 0;
}
-static void symbol_free(struct symbol *sym)
+static void symbol_free_sub(struct symbol *sym)
{
DBG("free %p sym=%s, owner=%p %s\n", sym, sym->name, sym->owner,
sym->owner != NULL ? sym->owner->path : "");
free(sym);
}
+static void symbol_free(struct symbol *sym)
+{
+ struct symbol *sym_i, *sym_i_tmp;
+ sym_i = sym;
+ while (sym_i != NULL) {
+ sym_i_tmp = sym_i;
+ sym_i = sym_i->next;
+ symbol_free_sub(sym_i_tmp);
+ }
+}
+
+static struct kmod_module_info *depmod_get_mod_info(struct mod *mod, const char *key)
+{
+ struct kmod_list *l;
+ struct kmod_module_info *rval = NULL;
+
+ kmod_list_foreach(l, mod->info_list) {
+ struct kmod_module_info *info;
+ info = (struct kmod_module_info *)l->data;
+ if (strcmp(info->key, key) == 0 ) {
+ rval = info;
+ break;
+ }
+ }
+ return rval;
+}
+
static int depmod_init(struct depmod *depmod, struct cfg *cfg,
struct kmod_ctx *ctx)
{
@@ -1537,8 +1569,9 @@ static int depmod_symbol_add(struct depmod *depmod, const char *name,
const struct mod *owner)
{
size_t namelen;
- int err;
struct symbol *sym;
+ int err = 0;
+ struct symbol *sym_l = NULL, *sym_li = NULL;
if (!prefix_skipped && (name[0] == depmod->cfg->sym_prefix))
name++;
@@ -1548,20 +1581,49 @@ static int depmod_symbol_add(struct depmod *depmod, const char *name,
if (sym == NULL)
return -ENOMEM;
+ sym->next = NULL;
sym->owner = (struct mod *)owner;
sym->crc = crc;
memcpy(sym->name, name, namelen);
- err = hash_add(depmod->symbols, sym->name, sym);
- if (err < 0) {
- free(sym);
- return err;
+ if (depmod->cfg->use_deps_alternatives == 0) {
+ err = hash_add(depmod->symbols, sym->name, sym);
+ if (err < 0)
+ goto err_ext;
+ } else {
+ sym_l = hash_find(depmod->symbols, sym->name);
+ for (sym_li = sym_l; sym_li != NULL; sym_li = sym_li->next)
+ if (sym_li->crc == sym->crc && sym_li->owner == sym->owner)
+ break;
+ if (sym_li != NULL)
+ // symbol already in the list
+ goto clr_ext;
+ else {
+ if (sym_l != NULL) {
+ // insert new sym at second pos to left start list pointer from
+ // hash without changes
+ sym->next = sym_l->next;
+ sym_l->next = sym;
+ } else {
+ // new symbol
+ err = hash_add(depmod->symbols, sym->name, sym);
+ if (err < 0)
+ goto err_ext;
+ }
+ }
}
- DBG("add %p sym=%s, owner=%p %s\n", sym, sym->name, owner,
+ DBG("add %p sym=%s,crc(%#"PRIx64"), owner=%p %s\n", sym, name, crc, owner,
owner != NULL ? owner->path : "");
return 0;
+
+err_ext:
+ ERR("Failed to add %p sym=%s,crc(%#"PRIx64"), owner=%p %s\n", sym, name, crc, owner,
+ owner != NULL ? owner->path : "");
+clr_ext:
+ symbol_free(sym);
+ return err;
}
static struct symbol *depmod_symbol_find(const struct depmod *depmod,
@@ -1571,7 +1633,7 @@ static struct symbol *depmod_symbol_find(const struct depmod *depmod,
name++;
if (name[0] == depmod->cfg->sym_prefix)
name++;
- return hash_find(depmod->symbols, name);
+ return (struct symbol *)hash_find(depmod->symbols, name);
}
static int depmod_load_modules(struct depmod *depmod)
@@ -1615,6 +1677,40 @@ load_info:
return 0;
}
+static struct symbol *depmod_symbol_get_primary(const struct depmod *depmod,
+ const char *name,
+ struct mod *mod)
+{
+ struct symbol *sym, *sym_l;
+ sym_l = depmod_symbol_find(depmod, name);
+ if (sym_l == NULL)
+ sym = NULL;
+ else if (sym_l->next == NULL)
+ sym = sym_l;
+ else {
+ struct symbol *sym_li;
+ if (mod->deps_from_mod_info == NULL && mod->info_list != NULL)
+ mod->deps_from_mod_info = depmod_get_mod_info(mod, "depends");
+ if (mod->deps_from_mod_info == NULL)
+ sym = sym_l;
+ else {
+ sym = NULL;
+ for (sym_li = sym_l; sym_li != NULL; sym_li = sym_li->next) {
+ if (sym_li->owner->modname != NULL &&
+ str_in_coma_separated_str_list(mod->deps_from_mod_info->value, sym_li->owner->modname) >= 0) {
+ sym = sym_li;
+ break;
+ }
+ }
+ if (sym == NULL) {
+ DBG("Can't find proper owner for symbol: %s use first from list\n", name);
+ sym = sym_l;
+ }
+ }
+ }
+ return sym;
+}
+
static int depmod_load_module_dependencies(struct depmod *depmod, struct mod *mod)
{
const struct cfg *cfg = depmod->cfg;
@@ -1625,7 +1721,7 @@ static int depmod_load_module_dependencies(struct depmod *depmod, struct mod *mo
const char *name = kmod_module_dependency_symbol_get_symbol(l);
uint64_t crc = kmod_module_dependency_symbol_get_crc(l);
int bindtype = kmod_module_dependency_symbol_get_bind(l);
- struct symbol *sym = depmod_symbol_find(depmod, name);
+ struct symbol *sym = depmod_symbol_get_primary(depmod, name, mod);
uint8_t is_weak = bindtype == KMOD_SYMBOL_WEAK;
if (sym == NULL) {
@@ -2306,12 +2402,27 @@ static int output_symbols(struct depmod *depmod, FILE *out)
hash_iter_init(depmod->symbols, &iter);
while (hash_iter_next(&iter, NULL, &v)) {
- const struct symbol *sym = v;
- if (sym->owner == NULL)
- continue;
-
- fprintf(out, "alias symbol:%s %s\n",
+ if (depmod->cfg->use_deps_alternatives == 0) {
+ const struct symbol *sym = v;
+ if (sym->owner == NULL)
+ continue;
+ fprintf(out, "alias symbol:%s %s\n",
sym->name, sym->owner->modname);
+ } else {
+ struct symbol *sym_li;
+ int is_printed = 0;
+ for ( sym_li = (struct symbol*)v; sym_li != NULL; sym_li = sym_li->next) {
+ if (sym_li->owner == NULL)
+ continue;
+ if ( is_printed == 0 ) {
+ fprintf(out, "alias symbol:%s", sym_li->name);
+ is_printed = 1;
+ }
+ fprintf(out, " %s", sym_li->owner->modname);
+ }
+ if ( is_printed == 1 )
+ fprintf(out,"\n");
+ }
}
return 0;
@@ -2956,6 +3067,9 @@ static int do_depmod(int argc, char *argv[])
config_paths[n_config_paths] = NULL;
break;
}
+ case 'D':
+ cfg.use_deps_alternatives = 1;
+ break;
case 'E':
module_symvers = optarg;
cfg.check_symvers = 1;
--
2.35.6