]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
elf: implement kmod_module_get_dependency_symbols()
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 20 Dec 2011 13:54:53 +0000 (11:54 -0200)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Sat, 24 Dec 2011 03:44:31 +0000 (01:44 -0200)
Uses kmod_elf_get_dependency_symbols() that looks into ".symtab" for
UNDEF symbols and matches the name from ".strtab" to "__versions" to
get crc.

Likely the public API should unify the symbol information getters and
list release, they are almost the same.

TODO
libkmod/libkmod-elf.c
libkmod/libkmod-module.c
libkmod/libkmod-private.h
libkmod/libkmod.h
libkmod/libkmod.sym
test/test-elf.c

diff --git a/TODO b/TODO
index d23a4d8dbb0f55662acdf334f36020b730c70bb6..cbc54401e16569c92c5eac1de6733364b49af89a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -18,6 +18,24 @@ Features:
 * provide 1:1 compatibility with module-init-tools's modprobe
    - dump configuration
 
+* provide depmod:
+   - add missing libkmod-elf.c functions:
+     - fetch_tables()
+     - deref_sym() (used by fetch_tables)
+   - add index writing functions to kmod-depmod.c
+   - 1:1 compatible kmod-depmod.c
+
+* review API, maybe unify all of these setters:
+   - kmod_module_version_get_symbol()
+   - kmod_module_version_get_crc()
+   - kmod_module_symbol_get_symbol()
+   - kmod_module_symbol_get_crc()
+   - kmod_module_dependency_symbol_get_symbol()
+   - kmod_module_dependency_symbol_get_crc()
+   - kmod_module_versions_free_list()
+   - kmod_module_symbols_free_list()
+   - kmod_module_dependency_symbols_free_list()
+
 * provide modules.archive, a cache file with all modules compressed
   and a fast access. It's like a tar.gz, but with each entry
   compressed as opposed to the whole tar compressed, easy to pick
index 8c39c065b754f6e4d60ea3f97dbf26e1c2ff1f93..8052e4e671031bbc02645d9dd04577f7ad34dc54 100644 (file)
@@ -34,6 +34,17 @@ enum kmod_elf_class {
        KMOD_ELF_MSB = (1 << 4)
 };
 
+/* as defined in module-init-tools */
+struct kmod_modversion32 {
+       uint32_t crc;
+       char name[64 - sizeof(uint32_t)];
+};
+
+struct kmod_modversion64 {
+       uint64_t crc;
+       char name[64 - sizeof(uint64_t)];
+};
+
 #ifdef WORDS_BIGENDIAN
 static const enum kmod_elf_class native_endianess = KMOD_ELF_MSB;
 #else
@@ -57,6 +68,7 @@ struct kmod_elf {
                        uint64_t offset;
                        uint32_t nameoff; /* offset in strings itself */
                } strings;
+               uint16_t machine;
        } header;
 };
 
@@ -296,7 +308,8 @@ struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
        elf->header.section.offset = READV(e_shoff);            \
        elf->header.section.count = READV(e_shnum);             \
        elf->header.section.entry_size = READV(e_shentsize);    \
-       elf->header.strings.section = READV(e_shstrndx)
+       elf->header.strings.section = READV(e_shstrndx);        \
+       elf->header.machine = READV(e_machine)
        if (elf->class & KMOD_ELF_32) {
                const Elf32_Ehdr *hdr = elf_get_mem(elf, 0);
                LOAD_HEADER;
@@ -473,14 +486,6 @@ int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion
        const void *buf;
        char *itr;
        int i, count, err;
-       struct kmod_modversion32 {
-               uint32_t crc;
-               char name[64 - sizeof(uint32_t)];
-       };
-       struct kmod_modversion64 {
-               uint64_t crc;
-               char name[64 - sizeof(uint64_t)];
-       };
 #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64))
 
        assert(sizeof(struct kmod_modversion64) ==
@@ -533,7 +538,7 @@ int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion
                        symbol++;
 
                a[i].crc = crc;
-               a[i].bind = KMOD_MODVERSION_UNDEF;
+               a[i].bind = KMOD_SYMBOL_UNDEF;
                a[i].symbol = itr;
                symbollen = strlen(symbol) + 1;
                memcpy(itr, symbol, symbollen);
@@ -684,7 +689,7 @@ static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_m
                                continue;
                        }
                        a[count].crc = 0;
-                       a[count].bind = KMOD_MODVERSION_GLOBAL;
+                       a[count].bind = KMOD_SYMBOL_GLOBAL;
                        a[count].symbol = itr;
                        memcpy(itr, strings + last, slen);
                        itr[slen] = '\0';
@@ -696,7 +701,7 @@ static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_m
        if (strings[i - 1] != '\0') {
                size_t slen = i - last;
                a[count].crc = 0;
-               a[count].bind = KMOD_MODVERSION_GLOBAL;
+               a[count].bind = KMOD_SYMBOL_GLOBAL;
                a[count].symbol = itr;
                memcpy(itr, strings + last, slen);
                itr[slen] = '\0';
@@ -707,17 +712,17 @@ static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_m
        return count;
 }
 
-static inline uint8_t kmod_modversion_bind_from_elf(uint8_t elf_value)
+static inline uint8_t kmod_symbol_bind_from_elf(uint8_t elf_value)
 {
        switch (elf_value) {
        case STB_LOCAL:
-               return KMOD_MODVERSION_LOCAL;
+               return KMOD_SYMBOL_LOCAL;
        case STB_GLOBAL:
-               return KMOD_MODVERSION_GLOBAL;
+               return KMOD_SYMBOL_GLOBAL;
        case STB_WEAK:
-               return KMOD_MODVERSION_WEAK;
+               return KMOD_SYMBOL_WEAK;
        default:
-               return KMOD_MODVERSION_NONE;
+               return KMOD_SYMBOL_NONE;
        }
 }
 
@@ -831,7 +836,7 @@ int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **ar
                        bind = ELF64_ST_BIND(info);
 
                a[count].crc = crc;
-               a[count].bind = kmod_modversion_bind_from_elf(bind);
+               a[count].bind = kmod_symbol_bind_from_elf(bind);
                a[count].symbol = itr;
                slen = strlen(name);
                memcpy(itr, name, slen);
@@ -845,3 +850,315 @@ fallback:
        ELFDBG(elf, "Falling back to __ksymtab_strings!\n");
        return kmod_elf_get_symbols_symtab(elf, array);
 }
+
+static int kmod_elf_crc_find(const struct kmod_elf *elf, const void *versions, uint64_t versionslen, const char *name, uint64_t *crc)
+{
+       size_t verlen, crclen, off;
+       uint64_t i;
+
+       if (elf->class & KMOD_ELF_32) {
+               struct kmod_modversion32 *mv;
+               verlen = sizeof(*mv);
+               crclen = sizeof(mv->crc);
+       } else {
+               struct kmod_modversion64 *mv;
+               verlen = sizeof(*mv);
+               crclen = sizeof(mv->crc);
+       }
+
+       off = (const uint8_t *)versions - elf->memory;
+       for (i = 0; i < versionslen; i += verlen) {
+               const char *symbol = elf_get_mem(elf, off + i + crclen);
+               if (!streq(name, symbol))
+                       continue;
+               *crc = elf_get_uint(elf, off + i, crclen);
+               return i / verlen;
+       }
+
+       ELFDBG(elf, "could not find crc for symbol '%s'\n", name);
+       *crc = 0;
+       return -1;
+}
+
+/* from module-init-tools:elfops_core.c */
+#ifndef STT_REGISTER
+#define STT_REGISTER    13              /* Global register reserved to app. */
+#endif
+
+/* array will be allocated with strings in a single malloc, just free *array */
+int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
+{
+       uint64_t versionslen, strtablen, symtablen, str_off, sym_off, ver_off;
+       const void *versions, *strtab, *symtab;
+       struct kmod_modversion *a;
+       char *itr;
+       size_t slen, verlen, symlen, crclen;
+       int i, count, symcount, vercount, err;
+       bool handle_register_symbols;
+       uint8_t *visited_versions;
+       uint64_t *symcrcs;
+
+       err = kmod_elf_get_section(elf, "__versions", &versions, &versionslen);
+       if (err < 0) {
+               versions = NULL;
+               versionslen = 0;
+               verlen = 0;
+               crclen = 0;
+       } else {
+               if (elf->class & KMOD_ELF_32) {
+                       struct kmod_modversion32 *mv;
+                       verlen = sizeof(*mv);
+                       crclen = sizeof(mv->crc);
+               } else {
+                       struct kmod_modversion64 *mv;
+                       verlen = sizeof(*mv);
+                       crclen = sizeof(mv->crc);
+               }
+               if (versionslen % verlen != 0) {
+                       ELFDBG(elf, "unexpected __versions of length %"PRIu64", not multiple of %zd as expected.\n", versionslen, verlen);
+                       versions = NULL;
+                       versionslen = 0;
+               }
+       }
+
+       err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
+       if (err < 0) {
+               ELFDBG(elf, "no .strtab found.\n");
+               return -EINVAL;
+       }
+
+       err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
+       if (err < 0) {
+               ELFDBG(elf, "no .symtab found.\n");
+               return -EINVAL;
+       }
+
+       if (elf->class & KMOD_ELF_32)
+               symlen = sizeof(Elf32_Sym);
+       else
+               symlen = sizeof(Elf64_Sym);
+
+       if (symtablen % symlen != 0) {
+               ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
+               return -EINVAL;
+       }
+
+       if (versionslen == 0) {
+               vercount = 0;
+               visited_versions = NULL;
+       } else {
+               vercount = versionslen / verlen;
+               visited_versions = calloc(vercount, sizeof(uint8_t));
+               if (visited_versions == NULL)
+                       return -ENOMEM;
+       }
+
+       handle_register_symbols = (elf->header.machine == EM_SPARC ||
+                                  elf->header.machine == EM_SPARCV9);
+
+       symcount = symtablen / symlen;
+       count = 0;
+       slen = 0;
+       str_off = (const uint8_t *)strtab - elf->memory;
+       sym_off = (const uint8_t *)symtab - elf->memory + symlen;
+
+       symcrcs = calloc(symcount, sizeof(uint64_t));
+       if (symcrcs == NULL) {
+               free(visited_versions);
+               return -ENOMEM;
+       }
+
+       for (i = 1; i < symcount; i++, sym_off += symlen) {
+               const char *name;
+               uint64_t crc;
+               uint32_t name_off;
+               uint16_t secidx;
+               uint8_t info;
+               int idx;
+
+#define READV(field)                                                   \
+               elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
+                            sizeof(s->field))
+               if (elf->class & KMOD_ELF_32) {
+                       Elf32_Sym *s;
+                       name_off = READV(st_name);
+                       secidx = READV(st_shndx);
+                       info = READV(st_info);
+               } else {
+                       Elf64_Sym *s;
+                       name_off = READV(st_name);
+                       secidx = READV(st_shndx);
+                       info = READV(st_info);
+               }
+#undef READV
+               if (secidx != SHN_UNDEF)
+                       continue;
+
+               if (handle_register_symbols) {
+                       uint8_t type;
+                       if (elf->class & KMOD_ELF_32)
+                               type = ELF32_ST_TYPE(info);
+                       else
+                               type = ELF64_ST_TYPE(info);
+
+                       /* Not really undefined: sparc gcc 3.3 creates
+                        * U references when you have global asm
+                        * variables, to avoid anyone else misusing
+                        * them.
+                        */
+                       if (type == STT_REGISTER)
+                               continue;
+               }
+
+               if (name_off >= strtablen) {
+                       ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
+                       free(visited_versions);
+                       free(symcrcs);
+                       return -EINVAL;
+               }
+
+               name = elf_get_mem(elf, str_off + name_off);
+               if (name[0] == '\0') {
+                       ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
+                       continue;
+               }
+
+               slen += strlen(name) + 1;
+               count++;
+
+               idx = kmod_elf_crc_find(elf, versions, versionslen, name, &crc);
+               if (idx >= 0 && visited_versions != NULL)
+                       visited_versions[idx] = 1;
+               symcrcs[i] = crc;
+       }
+
+       if (visited_versions != NULL) {
+               /* module_layout/struct_module are not visited, but needed */
+               ver_off = (const uint8_t *)versions - elf->memory;
+               for (i = 0; i < vercount; i++) {
+                       if (visited_versions[i] == 0) {
+                               const char *name;
+                               name = elf_get_mem(elf, ver_off + i * verlen + crclen);
+                               slen += strlen(name) + 1;
+
+                               count++;
+                       }
+               }
+       }
+
+       if (count == 0) {
+               free(visited_versions);
+               free(symcrcs);
+               return 0;
+       }
+
+       *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
+       if (*array == NULL) {
+               free(visited_versions);
+               free(symcrcs);
+               return -errno;
+       }
+
+       itr = (char *)(a + count);
+       count = 0;
+       str_off = (const uint8_t *)strtab - elf->memory;
+       sym_off = (const uint8_t *)symtab - elf->memory + symlen;
+       for (i = 1; i < symcount; i++, sym_off += symlen) {
+               const char *name;
+               uint64_t crc;
+               uint32_t name_off;
+               uint16_t secidx;
+               uint8_t info, bind;
+
+#define READV(field)                                                   \
+               elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
+                            sizeof(s->field))
+               if (elf->class & KMOD_ELF_32) {
+                       Elf32_Sym *s;
+                       name_off = READV(st_name);
+                       secidx = READV(st_shndx);
+                       info = READV(st_info);
+               } else {
+                       Elf64_Sym *s;
+                       name_off = READV(st_name);
+                       secidx = READV(st_shndx);
+                       info = READV(st_info);
+               }
+#undef READV
+               if (secidx != SHN_UNDEF)
+                       continue;
+
+               if (handle_register_symbols) {
+                       uint8_t type;
+                       if (elf->class & KMOD_ELF_32)
+                               type = ELF32_ST_TYPE(info);
+                       else
+                               type = ELF64_ST_TYPE(info);
+
+                       /* Not really undefined: sparc gcc 3.3 creates
+                        * U references when you have global asm
+                        * variables, to avoid anyone else misusing
+                        * them.
+                        */
+                       if (type == STT_REGISTER)
+                               continue;
+               }
+
+               name = elf_get_mem(elf, str_off + name_off);
+               if (name[0] == '\0') {
+                       ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
+                       continue;
+               }
+
+               if (elf->class & KMOD_ELF_32)
+                       bind = ELF32_ST_BIND(info);
+               else
+                       bind = ELF64_ST_BIND(info);
+               if (bind == STB_WEAK)
+                       bind = KMOD_SYMBOL_WEAK;
+               else
+                       bind = KMOD_SYMBOL_UNDEF;
+
+               slen = strlen(name);
+               crc = symcrcs[i];
+
+               a[count].crc = crc;
+               a[count].bind = bind;
+               a[count].symbol = itr;
+               memcpy(itr, name, slen);
+               itr[slen] = '\0';
+               itr += slen + 1;
+
+               count++;
+       }
+
+       free(symcrcs);
+
+       if (visited_versions == NULL)
+               return count;
+
+       /* add unvisited (module_layout/struct_module) */
+       ver_off = (const uint8_t *)versions - elf->memory;
+       for (i = 0; i < vercount; i++) {
+               const char *name;
+               uint64_t crc;
+
+               if (visited_versions[i] != 0)
+                       continue;
+
+               name = elf_get_mem(elf, ver_off + i * verlen + crclen);
+               slen = strlen(name);
+               crc = elf_get_uint(elf, ver_off + i * verlen, crclen);
+
+               a[count].crc = crc;
+               a[count].bind = KMOD_SYMBOL_UNDEF;
+               a[count].symbol = itr;
+               memcpy(itr, name, slen);
+               itr[slen] = '\0';
+               itr += slen + 1;
+
+               count++;
+       }
+       free(visited_versions);
+       return count;
+}
index 089c61ed7f76db9295e06b07f6b36ca90f613fa8..4d85b76cacd227f402caca510faf3e0f52e37e04 100644 (file)
@@ -2061,3 +2061,193 @@ KMOD_EXPORT void kmod_module_symbols_free_list(struct kmod_list *list)
                list = kmod_list_remove(list);
        }
 }
+
+struct kmod_module_dependency_symbol {
+       uint64_t crc;
+       uint8_t bind;
+       char symbol[];
+};
+
+static struct kmod_module_dependency_symbol *kmod_module_dependency_symbols_new(uint64_t crc, uint8_t bind, const char *symbol)
+{
+       struct kmod_module_dependency_symbol *mv;
+       size_t symbollen = strlen(symbol) + 1;
+
+       mv = malloc(sizeof(struct kmod_module_dependency_symbol) + symbollen);
+       if (mv == NULL)
+               return NULL;
+
+       mv->crc = crc;
+       mv->bind = bind;
+       memcpy(mv->symbol, symbol, symbollen);
+       return mv;
+}
+
+static void kmod_module_dependency_symbol_free(struct kmod_module_dependency_symbol *dependency_symbol)
+{
+       free(dependency_symbol);
+}
+
+/**
+ * kmod_module_get_dependency_symbols:
+ * @mod: kmod module
+ * @list: where to return list of module dependency_symbols. Use
+ *        kmod_module_dependency_symbol_get_symbol() and
+ *        kmod_module_dependency_symbol_get_crc(). Release this list with
+ *        kmod_module_dependency_symbols_free_list()
+ *
+ * Get a list of entries in ELF section ".symtab" or "__ksymtab_strings".
+ *
+ * After use, free the @list by calling
+ * kmod_module_dependency_symbols_free_list().
+ *
+ * Returns: 0 on success or < 0 otherwise.
+ */
+KMOD_EXPORT int kmod_module_get_dependency_symbols(const struct kmod_module *mod, struct kmod_list **list)
+{
+       struct kmod_file *file;
+       struct kmod_elf *elf;
+       const char *path;
+       const void *mem;
+       struct kmod_modversion *symbols;
+       size_t size;
+       int i, count, ret = 0;
+
+       if (mod == NULL || list == NULL)
+               return -ENOENT;
+
+       assert(*list == NULL);
+
+       path = kmod_module_get_path(mod);
+       if (path == NULL)
+               return -ENOENT;
+
+       file = kmod_file_open(path);
+       if (file == NULL)
+               return -errno;
+
+       size = kmod_file_get_size(file);
+       mem = kmod_file_get_contents(file);
+
+       elf = kmod_elf_new(mem, size);
+       if (elf == NULL) {
+               ret = -errno;
+               goto elf_open_error;
+       }
+
+       count = kmod_elf_get_dependency_symbols(elf, &symbols);
+       if (count < 0) {
+               ret = count;
+               goto get_strings_error;
+       }
+
+       for (i = 0; i < count; i++) {
+               struct kmod_module_dependency_symbol *mv;
+               struct kmod_list *n;
+
+               mv = kmod_module_dependency_symbols_new(symbols[i].crc,
+                                                       symbols[i].bind,
+                                                       symbols[i].symbol);
+               if (mv == NULL) {
+                       ret = -errno;
+                       kmod_module_dependency_symbols_free_list(*list);
+                       *list = NULL;
+                       goto list_error;
+               }
+
+               n = kmod_list_append(*list, mv);
+               if (n != NULL)
+                       *list = n;
+               else {
+                       kmod_module_dependency_symbol_free(mv);
+                       kmod_module_dependency_symbols_free_list(*list);
+                       *list = NULL;
+                       ret = -ENOMEM;
+                       goto list_error;
+               }
+       }
+       ret = count;
+
+list_error:
+       free(symbols);
+get_strings_error:
+       kmod_elf_unref(elf);
+elf_open_error:
+       kmod_file_unref(file);
+
+       return ret;
+}
+
+/**
+ * kmod_module_dependency_symbol_get_symbol:
+ * @entry: a list entry representing a kmod module dependency_symbols
+ *
+ * Get the dependency symbol of a kmod module
+ *
+ * Returns: the symbol of this kmod module dependency_symbols on success or NULL
+ * on failure. The string is owned by the dependency_symbols, do not free it.
+ */
+KMOD_EXPORT const char *kmod_module_dependency_symbol_get_symbol(const struct kmod_list *entry)
+{
+       struct kmod_module_dependency_symbol *dependency_symbol;
+
+       if (entry == NULL)
+               return NULL;
+
+       dependency_symbol = entry->data;
+       return dependency_symbol->symbol;
+}
+
+/**
+ * kmod_module_dependency_symbol_get_crc:
+ * @entry: a list entry representing a kmod module dependency_symbol
+ *
+ * Get the crc of a kmod module dependency_symbol.
+ *
+ * Returns: the crc of this kmod module dependency_symbol on success or NULL on
+ * failure. The string is owned by the dependency_symbol, do not free it.
+ */
+KMOD_EXPORT uint64_t kmod_module_dependency_symbol_get_crc(const struct kmod_list *entry)
+{
+       struct kmod_module_dependency_symbol *dependency_symbol;
+
+       if (entry == NULL)
+               return 0;
+
+       dependency_symbol = entry->data;
+       return dependency_symbol->crc;
+}
+
+/**
+ * kmod_module_dependency_symbol_get_bind:
+ * @entry: a list entry representing a kmod module dependency_symbol
+ *
+ * Get the bind type of a kmod module dependency_symbol.
+ *
+ * Returns: the bind of this kmod module dependency_symbol on success
+ * or < 0 on failure.
+ */
+KMOD_EXPORT int kmod_module_dependency_symbol_get_bind(const struct kmod_list *entry)
+{
+       struct kmod_module_dependency_symbol *dependency_symbol;
+
+       if (entry == NULL)
+               return 0;
+
+       dependency_symbol = entry->data;
+       return dependency_symbol->bind;
+}
+
+/**
+ * kmod_module_dependency_symbols_free_list:
+ * @list: kmod module dependency_symbols list
+ *
+ * Release the resources taken by @list
+ */
+KMOD_EXPORT void kmod_module_dependency_symbols_free_list(struct kmod_list *list)
+{
+       while (list) {
+               kmod_module_dependency_symbol_free(list->data);
+               list = kmod_list_remove(list);
+       }
+}
index 6da8eefffc069a81c341a14cb1d503517017838b..436ebf34308171ad43bc18695452f44a52ce885a 100644 (file)
@@ -144,13 +144,7 @@ void kmod_file_unref(struct kmod_file *file) __attribute__((nonnull(1)));
 struct kmod_elf;
 struct kmod_modversion {
        uint64_t crc;
-       enum kmod_modversion_bind {
-               KMOD_MODVERSION_NONE = '\0',
-               KMOD_MODVERSION_LOCAL = 'L',
-               KMOD_MODVERSION_GLOBAL = 'G',
-               KMOD_MODVERSION_WEAK = 'W',
-               KMOD_MODVERSION_UNDEF = 'U'
-       } bind;
+       enum kmod_symbol_bind bind;
        char *symbol;
 };
 
@@ -160,6 +154,7 @@ const void *kmod_elf_get_memory(const struct kmod_elf *elf) __must_check __attri
 int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array) __must_check __attribute__((nonnull(1,2,3)));
 int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array) __must_check __attribute__((nonnull(1,2)));
 int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array) __must_check __attribute__((nonnull(1,2)));
+int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array) __must_check __attribute__((nonnull(1,2)));
 int kmod_elf_strip_section(struct kmod_elf *elf, const char *section) __must_check __attribute__((nonnull(1,2)));
 int kmod_elf_strip_vermagic(struct kmod_elf *elf) __must_check __attribute__((nonnull(1)));
 
index cc3de084d1b1800974d82a17ec879b4269d27b74..ab470956ee2758231c4c7416c5e462457da6b623 100644 (file)
@@ -155,6 +155,20 @@ const char *kmod_module_symbol_get_symbol(const struct kmod_list *entry);
 uint64_t kmod_module_symbol_get_crc(const struct kmod_list *entry);
 void kmod_module_symbols_free_list(struct kmod_list *list);
 
+enum kmod_symbol_bind {
+       KMOD_SYMBOL_NONE = '\0',
+       KMOD_SYMBOL_LOCAL = 'L',
+       KMOD_SYMBOL_GLOBAL = 'G',
+       KMOD_SYMBOL_WEAK = 'W',
+       KMOD_SYMBOL_UNDEF = 'U'
+};
+
+int kmod_module_get_dependency_symbols(const struct kmod_module *mod, struct kmod_list **list);
+const char *kmod_module_dependency_symbol_get_symbol(const struct kmod_list *entry);
+int kmod_module_dependency_symbol_get_bind(const struct kmod_list *entry);
+uint64_t kmod_module_dependency_symbol_get_crc(const struct kmod_list *entry);
+void kmod_module_dependency_symbols_free_list(struct kmod_list *list);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index bf937297df96469e148606a6a5bfd5d57d8afe9c..1a72dd0cabfde110c90b1af6d1027a357b8bcf9f 100644 (file)
@@ -67,6 +67,12 @@ global:
        kmod_module_symbol_get_symbol;
        kmod_module_symbol_get_crc;
        kmod_module_symbols_free_list;
+
+       kmod_module_get_dependency_symbols;
+       kmod_module_dependency_symbol_get_symbol;
+       kmod_module_dependency_symbol_get_crc;
+       kmod_module_dependency_symbol_get_bind;
+       kmod_module_dependency_symbols_free_list;
 local:
         *;
 };
index 773ca6ba897016db5c85ab1ec8f9923cf532c8bf..23dd1fd4db60122fe07f69d07eb5e00983123b5b 100644 (file)
@@ -80,6 +80,24 @@ int main(int argc, char *argv[])
                kmod_module_symbols_free_list(list);
        }
 
+       list = NULL;
+       err = kmod_module_get_dependency_symbols(mod, &list);
+       if (err <= 0)
+               printf("no dependency symbols! (%s)\n", strerror(-err));
+       else {
+               puts("dependency symbols:");
+               kmod_list_foreach(l, list) {
+                       const char *symbol;
+                       uint8_t bind;
+                       uint64_t crc;
+                       symbol = kmod_module_dependency_symbol_get_symbol(l);
+                       bind = kmod_module_dependency_symbol_get_bind(l);
+                       crc = kmod_module_dependency_symbol_get_crc(l);
+                       printf("\t%s %c: %#"PRIx64"\n", symbol, bind, crc);
+               }
+               kmod_module_dependency_symbols_free_list(list);
+       }
+
        kmod_module_unref(mod);
 module_error:
        kmod_unref(ctx);