2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #include <shared/util.h>
29 #include "libkmod-internal.h"
32 KMOD_ELF_32 = (1 << 1),
33 KMOD_ELF_64 = (1 << 2),
34 KMOD_ELF_LSB = (1 << 3),
35 KMOD_ELF_MSB = (1 << 4)
38 /* as defined in module-init-tools */
39 struct kmod_modversion32 {
41 char name[64 - sizeof(uint32_t)];
44 struct kmod_modversion64 {
46 char name[64 - sizeof(uint64_t)];
50 const uint8_t *memory;
53 enum kmod_elf_class class;
54 struct kmod_elf_header {
61 uint16_t section; /* index of the strings section */
64 uint32_t nameoff; /* offset in strings itself */
70 //#define ENABLE_ELFDBG 1
72 #if defined(ENABLE_LOGGING) && defined(ENABLE_ELFDBG)
73 #define ELFDBG(elf, ...) \
74 _elf_dbg(elf, __FILE__, __LINE__, __func__, __VA_ARGS__);
76 static inline void _elf_dbg(const struct kmod_elf *elf, const char *fname, unsigned line, const char *func, const char *fmt, ...)
80 fprintf(stderr, "ELFDBG-%d%c: %s:%u %s() ",
81 (elf->class & KMOD_ELF_32) ? 32 : 64,
82 (elf->class & KMOD_ELF_MSB) ? 'M' : 'L',
85 vfprintf(stderr, fmt, args);
89 #define ELFDBG(elf, ...)
93 static int elf_identify(const void *memory, uint64_t size)
95 const uint8_t *p = memory;
98 if (size <= EI_NIDENT || memcmp(p, ELFMAG, SELFMAG) != 0)
101 switch (p[EI_CLASS]) {
103 if (size <= sizeof(Elf32_Ehdr))
105 class |= KMOD_ELF_32;
108 if (size <= sizeof(Elf64_Ehdr))
110 class |= KMOD_ELF_64;
116 switch (p[EI_DATA]) {
118 class |= KMOD_ELF_LSB;
121 class |= KMOD_ELF_MSB;
130 static inline uint64_t elf_get_uint(const struct kmod_elf *elf, uint64_t offset, uint16_t size)
136 assert(size <= sizeof(uint64_t));
137 assert(offset + size <= elf->size);
138 if (offset + size > elf->size) {
139 ELFDBG(elf, "out of bounds: %"PRIu64" + %"PRIu16" = %"PRIu64"> %"PRIu64" (ELF size)\n",
140 offset, size, offset + size, elf->size);
144 p = elf->memory + offset;
145 if (elf->class & KMOD_ELF_MSB) {
146 for (i = 0; i < size; i++)
147 ret = (ret << 8) | p[i];
149 for (i = 1; i <= size; i++)
150 ret = (ret << 8) | p[size - i];
153 ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64"\n",
159 static inline int elf_set_uint(struct kmod_elf *elf, uint64_t offset, uint64_t size, uint64_t value)
164 ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64" write memory=%p\n",
165 size, offset, value, elf->changed);
167 assert(size <= sizeof(uint64_t));
168 assert(offset + size <= elf->size);
169 if (offset + size > elf->size) {
170 ELFDBG(elf, "out of bounds: %"PRIu64" + %"PRIu16" = %"PRIu64"> %"PRIu64" (ELF size)\n",
171 offset, size, offset + size, elf->size);
175 if (elf->changed == NULL) {
176 elf->changed = malloc(elf->size);
177 if (elf->changed == NULL)
179 memcpy(elf->changed, elf->memory, elf->size);
180 elf->memory = elf->changed;
181 ELFDBG(elf, "copied memory to allow writing.\n");
184 p = elf->changed + offset;
185 if (elf->class & KMOD_ELF_MSB) {
186 for (i = 1; i <= size; i++) {
187 p[size - i] = value & 0xff;
188 value = (value & 0xffffffffffffff00) >> 8;
191 for (i = 0; i < size; i++) {
193 value = (value & 0xffffffffffffff00) >> 8;
200 static inline const void *elf_get_mem(const struct kmod_elf *elf, uint64_t offset)
202 assert(offset < elf->size);
203 if (offset >= elf->size) {
204 ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n",
208 return elf->memory + offset;
211 static inline const void *elf_get_section_header(const struct kmod_elf *elf, uint16_t idx)
213 assert(idx != SHN_UNDEF);
214 assert(idx < elf->header.section.count);
215 if (idx == SHN_UNDEF || idx >= elf->header.section.count) {
216 ELFDBG(elf, "invalid section number: %"PRIu16", last=%"PRIu16"\n",
217 idx, elf->header.section.count);
220 return elf_get_mem(elf, elf->header.section.offset +
221 (uint64_t)(idx * elf->header.section.entry_size));
224 static inline int elf_get_section_info(const struct kmod_elf *elf, uint16_t idx, uint64_t *offset, uint64_t *size, uint32_t *nameoff)
226 const uint8_t *p = elf_get_section_header(elf, idx);
227 uint64_t min_size, off = p - elf->memory;
230 ELFDBG(elf, "no section at %"PRIu16"\n", idx);
237 #define READV(field) \
238 elf_get_uint(elf, off + offsetof(typeof(*hdr), field), sizeof(hdr->field))
240 if (elf->class & KMOD_ELF_32) {
241 const Elf32_Shdr *hdr _unused_ = (const Elf32_Shdr *)p;
242 *size = READV(sh_size);
243 *offset = READV(sh_offset);
244 *nameoff = READV(sh_name);
246 const Elf64_Shdr *hdr _unused_ = (const Elf64_Shdr *)p;
247 *size = READV(sh_size);
248 *offset = READV(sh_offset);
249 *nameoff = READV(sh_name);
253 if (addu64_overflow(*offset, *size, &min_size)
254 || min_size > elf->size) {
255 ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n",
256 min_size, elf->size);
260 ELFDBG(elf, "section=%"PRIu16" is: offset=%"PRIu64" size=%"PRIu64" nameoff=%"PRIu32"\n",
261 idx, *offset, *size, *nameoff);
266 static const char *elf_get_strings_section(const struct kmod_elf *elf, uint64_t *size)
268 *size = elf->header.strings.size;
269 return elf_get_mem(elf, elf->header.strings.offset);
272 struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
274 struct kmod_elf *elf;
276 size_t shdrs_size, shdr_size;
279 assert_cc(sizeof(uint16_t) == sizeof(Elf32_Half));
280 assert_cc(sizeof(uint16_t) == sizeof(Elf64_Half));
281 assert_cc(sizeof(uint32_t) == sizeof(Elf32_Word));
282 assert_cc(sizeof(uint32_t) == sizeof(Elf64_Word));
284 class = elf_identify(memory, size);
290 elf = malloc(sizeof(struct kmod_elf));
295 elf->memory = memory;
300 #define READV(field) \
301 elf_get_uint(elf, offsetof(typeof(*hdr), field), sizeof(hdr->field))
303 #define LOAD_HEADER \
304 elf->header.section.offset = READV(e_shoff); \
305 elf->header.section.count = READV(e_shnum); \
306 elf->header.section.entry_size = READV(e_shentsize); \
307 elf->header.strings.section = READV(e_shstrndx); \
308 elf->header.machine = READV(e_machine)
309 if (elf->class & KMOD_ELF_32) {
310 const Elf32_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
312 shdr_size = sizeof(Elf32_Shdr);
314 const Elf64_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
316 shdr_size = sizeof(Elf64_Shdr);
321 ELFDBG(elf, "section: offset=%"PRIu64" count=%"PRIu16" entry_size=%"PRIu16" strings index=%"PRIu16"\n",
322 elf->header.section.offset,
323 elf->header.section.count,
324 elf->header.section.entry_size,
325 elf->header.strings.section);
327 if (elf->header.section.entry_size != shdr_size) {
328 ELFDBG(elf, "unexpected section entry size: %"PRIu16", expected %"PRIu16"\n",
329 elf->header.section.entry_size, shdr_size);
332 shdrs_size = shdr_size * elf->header.section.count;
333 if (addu64_overflow(shdrs_size, elf->header.section.offset, &min_size)
334 || min_size > elf->size) {
335 ELFDBG(elf, "file is too short to hold sections\n");
339 if (elf_get_section_info(elf, elf->header.strings.section,
340 &elf->header.strings.offset,
341 &elf->header.strings.size,
342 &elf->header.strings.nameoff) < 0) {
343 ELFDBG(elf, "could not get strings section\n");
347 const char *s = elf_get_strings_section(elf, &slen);
348 if (slen == 0 || s[slen - 1] != '\0') {
349 ELFDBG(elf, "strings section does not ends with \\0\n");
362 void kmod_elf_unref(struct kmod_elf *elf)
368 const void *kmod_elf_get_memory(const struct kmod_elf *elf)
373 static int elf_find_section(const struct kmod_elf *elf, const char *section)
376 const char *names = elf_get_strings_section(elf, &nameslen);
379 for (i = 1; i < elf->header.section.count; i++) {
383 int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
386 if (nameoff >= nameslen)
389 if (!streq(section, n))
398 int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, const void **buf, uint64_t *buf_size)
401 const char *names = elf_get_strings_section(elf, &nameslen);
407 for (i = 1; i < elf->header.section.count; i++) {
411 int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
414 if (nameoff >= nameslen)
417 if (!streq(section, n))
420 *buf = elf_get_mem(elf, off);
428 /* array will be allocated with strings in a single malloc, just free *array */
429 int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array)
440 err = kmod_elf_get_section(elf, section, &buf, &size);
445 if (strings == NULL || size == 0)
448 /* skip zero padding */
449 while (strings[0] == '\0' && size > 1) {
457 for (i = 0, count = 0; i < size; ) {
458 if (strings[i] != '\0') {
463 while (strings[i] == '\0' && i < size)
469 if (strings[i - 1] != '\0')
472 *array = a = malloc(size + 1 + sizeof(char *) * (count + 1));
476 s = (char *)(a + count + 1);
477 memcpy(s, strings, size);
479 /* make sure the last string is NULL-terminated */
484 for (i = 0, j = 1; j < count && i < size; ) {
490 while (strings[i] == '\0' && i < size)
500 /* array will be allocated with strings in a single malloc, just free *array */
501 int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array)
503 size_t off, offcrc, slen;
505 struct kmod_modversion *a;
509 #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64))
511 assert_cc(sizeof(struct kmod_modversion64) ==
512 sizeof(struct kmod_modversion32));
514 if (elf->class & KMOD_ELF_32)
515 offcrc = sizeof(uint32_t);
517 offcrc = sizeof(uint64_t);
521 err = kmod_elf_get_section(elf, "__versions", &buf, &size);
525 if (buf == NULL || size == 0)
528 if (size % MODVERSION_SEC_SIZE != 0)
531 count = size / MODVERSION_SEC_SIZE;
533 off = (const uint8_t *)buf - elf->memory;
536 for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
537 const char *symbol = elf_get_mem(elf, off + offcrc);
539 if (symbol[0] == '.')
542 slen += strlen(symbol) + 1;
545 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
549 itr = (char *)(a + count);
550 off = (const uint8_t *)buf - elf->memory;
552 for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
553 uint64_t crc = elf_get_uint(elf, off, offcrc);
554 const char *symbol = elf_get_mem(elf, off + offcrc);
557 if (symbol[0] == '.')
561 a[i].bind = KMOD_SYMBOL_UNDEF;
563 symbollen = strlen(symbol) + 1;
564 memcpy(itr, symbol, symbollen);
571 int kmod_elf_strip_section(struct kmod_elf *elf, const char *section)
575 int idx = elf_find_section(elf, section);
581 buf = elf_get_section_header(elf, idx);
582 off = (const uint8_t *)buf - elf->memory;
584 if (elf->class & KMOD_ELF_32) {
585 off += offsetof(Elf32_Shdr, sh_flags);
586 size = sizeof(((Elf32_Shdr *)buf)->sh_flags);
588 off += offsetof(Elf64_Shdr, sh_flags);
589 size = sizeof(((Elf64_Shdr *)buf)->sh_flags);
592 val = elf_get_uint(elf, off, size);
593 val &= ~(uint64_t)SHF_ALLOC;
595 return elf_set_uint(elf, off, size, val);
598 int kmod_elf_strip_vermagic(struct kmod_elf *elf)
605 err = kmod_elf_get_section(elf, ".modinfo", &buf, &size);
609 if (strings == NULL || size == 0)
612 /* skip zero padding */
613 while (strings[0] == '\0' && size > 1) {
620 for (i = 0; i < size; i++) {
624 if (strings[i] == '\0')
630 len = sizeof("vermagic=") - 1;
633 if (strncmp(s, "vermagic=", len) != 0) {
637 off = (const uint8_t *)s - elf->memory;
639 if (elf->changed == NULL) {
640 elf->changed = malloc(elf->size);
641 if (elf->changed == NULL)
643 memcpy(elf->changed, elf->memory, elf->size);
644 elf->memory = elf->changed;
645 ELFDBG(elf, "copied memory to allow writing.\n");
649 ELFDBG(elf, "clear .modinfo vermagic \"%s\" (%zd bytes)\n",
651 memset(elf->changed + off, '\0', len);
655 ELFDBG(elf, "no vermagic found in .modinfo\n");
660 static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_modversion **array)
662 uint64_t i, last, size;
666 struct kmod_modversion *a;
671 err = kmod_elf_get_section(elf, "__ksymtab_strings", &buf, &size);
675 if (strings == NULL || size == 0)
678 /* skip zero padding */
679 while (strings[0] == '\0' && size > 1) {
687 for (i = 0, count = 0; i < size; i++) {
688 if (strings[i] == '\0') {
697 if (strings[i - 1] != '\0')
700 *array = a = malloc(size + 1 + sizeof(struct kmod_modversion) * count);
704 itr = (char *)(a + count);
706 for (i = 0, count = 0; i < size; i++) {
707 if (strings[i] == '\0') {
708 size_t slen = i - last;
714 a[count].bind = KMOD_SYMBOL_GLOBAL;
715 a[count].symbol = itr;
716 memcpy(itr, strings + last, slen);
723 if (strings[i - 1] != '\0') {
724 size_t slen = i - last;
726 a[count].bind = KMOD_SYMBOL_GLOBAL;
727 a[count].symbol = itr;
728 memcpy(itr, strings + last, slen);
736 static inline uint8_t kmod_symbol_bind_from_elf(uint8_t elf_value)
740 return KMOD_SYMBOL_LOCAL;
742 return KMOD_SYMBOL_GLOBAL;
744 return KMOD_SYMBOL_WEAK;
746 return KMOD_SYMBOL_NONE;
750 static uint64_t kmod_elf_resolve_crc(const struct kmod_elf *elf, uint64_t crc, uint16_t shndx)
756 if (shndx == SHN_ABS || shndx == SHN_UNDEF)
759 err = elf_get_section_info(elf, shndx, &off, &size, &nameoff);
761 ELFDBG("Cound not find section index %"PRIu16" for crc", shndx);
765 if (crc > (size - sizeof(uint32_t))) {
766 ELFDBG("CRC offset %"PRIu64" is too big, section %"PRIu16" size is %"PRIu64"\n",
771 crc = elf_get_uint(elf, off + crc, sizeof(uint32_t));
775 /* array will be allocated with strings in a single malloc, just free *array */
776 int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
778 static const char crc_str[] = "__crc_";
779 static const size_t crc_strlen = sizeof(crc_str) - 1;
780 uint64_t strtablen, symtablen, str_off, sym_off;
781 const void *strtab, *symtab;
782 struct kmod_modversion *a;
785 int i, count, symcount, err;
787 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
789 ELFDBG(elf, "no .strtab found.\n");
793 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
795 ELFDBG(elf, "no .symtab found.\n");
799 if (elf->class & KMOD_ELF_32)
800 symlen = sizeof(Elf32_Sym);
802 symlen = sizeof(Elf64_Sym);
804 if (symtablen % symlen != 0) {
805 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
809 symcount = symtablen / symlen;
812 str_off = (const uint8_t *)strtab - elf->memory;
813 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
814 for (i = 1; i < symcount; i++, sym_off += symlen) {
818 #define READV(field) \
819 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
821 if (elf->class & KMOD_ELF_32) {
823 name_off = READV(st_name);
826 name_off = READV(st_name);
829 if (name_off >= strtablen) {
830 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
834 name = elf_get_mem(elf, str_off + name_off);
836 if (strncmp(name, crc_str, crc_strlen) != 0)
838 slen += strlen(name + crc_strlen) + 1;
845 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
849 itr = (char *)(a + count);
851 str_off = (const uint8_t *)strtab - elf->memory;
852 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
853 for (i = 1; i < symcount; i++, sym_off += symlen) {
860 #define READV(field) \
861 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
863 if (elf->class & KMOD_ELF_32) {
865 name_off = READV(st_name);
866 crc = READV(st_value);
867 info = READV(st_info);
868 shndx = READV(st_shndx);
871 name_off = READV(st_name);
872 crc = READV(st_value);
873 info = READV(st_info);
874 shndx = READV(st_shndx);
877 name = elf_get_mem(elf, str_off + name_off);
878 if (strncmp(name, crc_str, crc_strlen) != 0)
882 if (elf->class & KMOD_ELF_32)
883 bind = ELF32_ST_BIND(info);
885 bind = ELF64_ST_BIND(info);
887 a[count].crc = kmod_elf_resolve_crc(elf, crc, shndx);
888 a[count].bind = kmod_symbol_bind_from_elf(bind);
889 a[count].symbol = itr;
891 memcpy(itr, name, slen);
899 ELFDBG(elf, "Falling back to __ksymtab_strings!\n");
900 return kmod_elf_get_symbols_symtab(elf, array);
903 static int kmod_elf_crc_find(const struct kmod_elf *elf, const void *versions, uint64_t versionslen, const char *name, uint64_t *crc)
905 size_t verlen, crclen, off;
908 if (elf->class & KMOD_ELF_32) {
909 struct kmod_modversion32 *mv;
910 verlen = sizeof(*mv);
911 crclen = sizeof(mv->crc);
913 struct kmod_modversion64 *mv;
914 verlen = sizeof(*mv);
915 crclen = sizeof(mv->crc);
918 off = (const uint8_t *)versions - elf->memory;
919 for (i = 0; i < versionslen; i += verlen) {
920 const char *symbol = elf_get_mem(elf, off + i + crclen);
921 if (!streq(name, symbol))
923 *crc = elf_get_uint(elf, off + i, crclen);
927 ELFDBG(elf, "could not find crc for symbol '%s'\n", name);
932 /* from module-init-tools:elfops_core.c */
934 #define STT_REGISTER 13 /* Global register reserved to app. */
937 /* array will be allocated with strings in a single malloc, just free *array */
938 int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
940 uint64_t versionslen, strtablen, symtablen, str_off, sym_off, ver_off;
941 const void *versions, *strtab, *symtab;
942 struct kmod_modversion *a;
944 size_t slen, verlen, symlen, crclen;
945 int i, count, symcount, vercount, err;
946 bool handle_register_symbols;
947 uint8_t *visited_versions;
950 err = kmod_elf_get_section(elf, "__versions", &versions, &versionslen);
957 if (elf->class & KMOD_ELF_32) {
958 struct kmod_modversion32 *mv;
959 verlen = sizeof(*mv);
960 crclen = sizeof(mv->crc);
962 struct kmod_modversion64 *mv;
963 verlen = sizeof(*mv);
964 crclen = sizeof(mv->crc);
966 if (versionslen % verlen != 0) {
967 ELFDBG(elf, "unexpected __versions of length %"PRIu64", not multiple of %zd as expected.\n", versionslen, verlen);
973 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
975 ELFDBG(elf, "no .strtab found.\n");
979 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
981 ELFDBG(elf, "no .symtab found.\n");
985 if (elf->class & KMOD_ELF_32)
986 symlen = sizeof(Elf32_Sym);
988 symlen = sizeof(Elf64_Sym);
990 if (symtablen % symlen != 0) {
991 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
995 if (versionslen == 0) {
997 visited_versions = NULL;
999 vercount = versionslen / verlen;
1000 visited_versions = calloc(vercount, sizeof(uint8_t));
1001 if (visited_versions == NULL)
1005 handle_register_symbols = (elf->header.machine == EM_SPARC ||
1006 elf->header.machine == EM_SPARCV9);
1008 symcount = symtablen / symlen;
1011 str_off = (const uint8_t *)strtab - elf->memory;
1012 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
1014 symcrcs = calloc(symcount, sizeof(uint64_t));
1015 if (symcrcs == NULL) {
1016 free(visited_versions);
1020 for (i = 1; i < symcount; i++, sym_off += symlen) {
1028 #define READV(field) \
1029 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1031 if (elf->class & KMOD_ELF_32) {
1033 name_off = READV(st_name);
1034 secidx = READV(st_shndx);
1035 info = READV(st_info);
1038 name_off = READV(st_name);
1039 secidx = READV(st_shndx);
1040 info = READV(st_info);
1043 if (secidx != SHN_UNDEF)
1046 if (handle_register_symbols) {
1048 if (elf->class & KMOD_ELF_32)
1049 type = ELF32_ST_TYPE(info);
1051 type = ELF64_ST_TYPE(info);
1053 /* Not really undefined: sparc gcc 3.3 creates
1054 * U references when you have global asm
1055 * variables, to avoid anyone else misusing
1058 if (type == STT_REGISTER)
1062 if (name_off >= strtablen) {
1063 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
1064 free(visited_versions);
1069 name = elf_get_mem(elf, str_off + name_off);
1070 if (name[0] == '\0') {
1071 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1075 slen += strlen(name) + 1;
1078 idx = kmod_elf_crc_find(elf, versions, versionslen, name, &crc);
1079 if (idx >= 0 && visited_versions != NULL)
1080 visited_versions[idx] = 1;
1084 if (visited_versions != NULL) {
1085 /* module_layout/struct_module are not visited, but needed */
1086 ver_off = (const uint8_t *)versions - elf->memory;
1087 for (i = 0; i < vercount; i++) {
1088 if (visited_versions[i] == 0) {
1090 name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1091 slen += strlen(name) + 1;
1099 free(visited_versions);
1105 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
1106 if (*array == NULL) {
1107 free(visited_versions);
1112 itr = (char *)(a + count);
1114 str_off = (const uint8_t *)strtab - elf->memory;
1115 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
1116 for (i = 1; i < symcount; i++, sym_off += symlen) {
1123 #define READV(field) \
1124 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1126 if (elf->class & KMOD_ELF_32) {
1128 name_off = READV(st_name);
1129 secidx = READV(st_shndx);
1130 info = READV(st_info);
1133 name_off = READV(st_name);
1134 secidx = READV(st_shndx);
1135 info = READV(st_info);
1138 if (secidx != SHN_UNDEF)
1141 if (handle_register_symbols) {
1143 if (elf->class & KMOD_ELF_32)
1144 type = ELF32_ST_TYPE(info);
1146 type = ELF64_ST_TYPE(info);
1148 /* Not really undefined: sparc gcc 3.3 creates
1149 * U references when you have global asm
1150 * variables, to avoid anyone else misusing
1153 if (type == STT_REGISTER)
1157 name = elf_get_mem(elf, str_off + name_off);
1158 if (name[0] == '\0') {
1159 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1163 if (elf->class & KMOD_ELF_32)
1164 bind = ELF32_ST_BIND(info);
1166 bind = ELF64_ST_BIND(info);
1167 if (bind == STB_WEAK)
1168 bind = KMOD_SYMBOL_WEAK;
1170 bind = KMOD_SYMBOL_UNDEF;
1172 slen = strlen(name);
1176 a[count].bind = bind;
1177 a[count].symbol = itr;
1178 memcpy(itr, name, slen);
1187 if (visited_versions == NULL)
1190 /* add unvisited (module_layout/struct_module) */
1191 ver_off = (const uint8_t *)versions - elf->memory;
1192 for (i = 0; i < vercount; i++) {
1196 if (visited_versions[i] != 0)
1199 name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1200 slen = strlen(name);
1201 crc = elf_get_uint(elf, ver_off + i * verlen, crclen);
1204 a[count].bind = KMOD_SYMBOL_UNDEF;
1205 a[count].symbol = itr;
1206 memcpy(itr, name, slen);
1212 free(visited_versions);