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)];
49 #ifdef WORDS_BIGENDIAN
50 static const enum kmod_elf_class native_endianess
= KMOD_ELF_MSB
;
52 static const enum kmod_elf_class native_endianess
= KMOD_ELF_LSB
;
56 const uint8_t *memory
;
59 enum kmod_elf_class
class;
60 struct kmod_elf_header
{
67 uint16_t section
; /* index of the strings section */
70 uint32_t nameoff
; /* offset in strings itself */
76 //#define ENABLE_ELFDBG 1
78 #if defined(ENABLE_LOGGING) && defined(ENABLE_ELFDBG)
79 #define ELFDBG(elf, ...) \
80 _elf_dbg(elf, __FILE__, __LINE__, __func__, __VA_ARGS__);
82 static inline void _elf_dbg(const struct kmod_elf
*elf
, const char *fname
, unsigned line
, const char *func
, const char *fmt
, ...)
86 fprintf(stderr
, "ELFDBG-%d%c: %s:%u %s() ",
87 (elf
->class & KMOD_ELF_32
) ? 32 : 64,
88 (elf
->class & KMOD_ELF_MSB
) ? 'M' : 'L',
91 vfprintf(stderr
, fmt
, args
);
95 #define ELFDBG(elf, ...)
99 static int elf_identify(const void *memory
, uint64_t size
)
101 const uint8_t *p
= memory
;
104 if (size
<= EI_NIDENT
|| memcmp(p
, ELFMAG
, SELFMAG
) != 0)
107 switch (p
[EI_CLASS
]) {
109 if (size
<= sizeof(Elf32_Ehdr
))
111 class |= KMOD_ELF_32
;
114 if (size
<= sizeof(Elf64_Ehdr
))
116 class |= KMOD_ELF_64
;
122 switch (p
[EI_DATA
]) {
124 class |= KMOD_ELF_LSB
;
127 class |= KMOD_ELF_MSB
;
136 static inline uint64_t elf_get_uint(const struct kmod_elf
*elf
, uint64_t offset
, uint16_t size
)
142 assert(size
<= sizeof(uint64_t));
143 assert(offset
+ size
<= elf
->size
);
144 if (offset
+ size
> elf
->size
) {
145 ELFDBG(elf
, "out of bounds: %"PRIu64
" + %"PRIu16
" = %"PRIu64
"> %"PRIu64
" (ELF size)\n",
146 offset
, size
, offset
+ size
, elf
->size
);
150 p
= elf
->memory
+ offset
;
151 if (elf
->class & KMOD_ELF_MSB
) {
152 for (i
= 0; i
< size
; i
++)
153 ret
= (ret
<< 8) | p
[i
];
155 for (i
= 1; i
<= size
; i
++)
156 ret
= (ret
<< 8) | p
[size
- i
];
159 ELFDBG(elf
, "size=%"PRIu16
" offset=%"PRIu64
" value=%"PRIu64
"\n",
165 static inline int elf_set_uint(struct kmod_elf
*elf
, uint64_t offset
, uint64_t size
, uint64_t value
)
170 ELFDBG(elf
, "size=%"PRIu16
" offset=%"PRIu64
" value=%"PRIu64
" write memory=%p\n",
171 size
, offset
, value
, elf
->changed
);
173 assert(size
<= sizeof(uint64_t));
174 assert(offset
+ size
<= elf
->size
);
175 if (offset
+ size
> elf
->size
) {
176 ELFDBG(elf
, "out of bounds: %"PRIu64
" + %"PRIu16
" = %"PRIu64
"> %"PRIu64
" (ELF size)\n",
177 offset
, size
, offset
+ size
, elf
->size
);
181 if (elf
->changed
== NULL
) {
182 elf
->changed
= malloc(elf
->size
);
183 if (elf
->changed
== NULL
)
185 memcpy(elf
->changed
, elf
->memory
, elf
->size
);
186 elf
->memory
= elf
->changed
;
187 ELFDBG(elf
, "copied memory to allow writing.\n");
190 p
= elf
->changed
+ offset
;
191 if (elf
->class & KMOD_ELF_MSB
) {
192 for (i
= 1; i
<= size
; i
++) {
193 p
[size
- i
] = value
& 0xff;
194 value
= (value
& 0xffffffffffffff00) >> 8;
197 for (i
= 0; i
< size
; i
++) {
199 value
= (value
& 0xffffffffffffff00) >> 8;
206 static inline const void *elf_get_mem(const struct kmod_elf
*elf
, uint64_t offset
)
208 assert(offset
< elf
->size
);
209 if (offset
>= elf
->size
) {
210 ELFDBG(elf
, "out-of-bounds: %"PRIu64
" >= %"PRIu64
" (ELF size)\n",
214 return elf
->memory
+ offset
;
217 static inline const void *elf_get_section_header(const struct kmod_elf
*elf
, uint16_t idx
)
219 assert(idx
!= SHN_UNDEF
);
220 assert(idx
< elf
->header
.section
.count
);
221 if (idx
== SHN_UNDEF
|| idx
>= elf
->header
.section
.count
) {
222 ELFDBG(elf
, "invalid section number: %"PRIu16
", last=%"PRIu16
"\n",
223 idx
, elf
->header
.section
.count
);
226 return elf_get_mem(elf
, elf
->header
.section
.offset
+
227 idx
* elf
->header
.section
.entry_size
);
230 static inline int elf_get_section_info(const struct kmod_elf
*elf
, uint16_t idx
, uint64_t *offset
, uint64_t *size
, uint32_t *nameoff
)
232 const uint8_t *p
= elf_get_section_header(elf
, idx
);
233 uint64_t min_size
, off
= p
- elf
->memory
;
236 ELFDBG(elf
, "no section at %"PRIu16
"\n", idx
);
243 #define READV(field) \
244 elf_get_uint(elf, off + offsetof(typeof(*hdr), field), sizeof(hdr->field))
246 if (elf
->class & KMOD_ELF_32
) {
247 const Elf32_Shdr
*hdr _unused_
= (const Elf32_Shdr
*)p
;
248 *size
= READV(sh_size
);
249 *offset
= READV(sh_offset
);
250 *nameoff
= READV(sh_name
);
252 const Elf64_Shdr
*hdr _unused_
= (const Elf64_Shdr
*)p
;
253 *size
= READV(sh_size
);
254 *offset
= READV(sh_offset
);
255 *nameoff
= READV(sh_name
);
259 min_size
= *offset
+ *size
;
260 if (min_size
> elf
->size
) {
261 ELFDBG(elf
, "out-of-bounds: %"PRIu64
" >= %"PRIu64
" (ELF size)\n",
262 min_size
, elf
->size
);
266 ELFDBG(elf
, "section=%"PRIu16
" is: offset=%"PRIu64
" size=%"PRIu64
" nameoff=%"PRIu32
"\n",
267 idx
, *offset
, *size
, *nameoff
);
272 static const char *elf_get_strings_section(const struct kmod_elf
*elf
, uint64_t *size
)
274 *size
= elf
->header
.strings
.size
;
275 return elf_get_mem(elf
, elf
->header
.strings
.offset
);
278 struct kmod_elf
*kmod_elf_new(const void *memory
, off_t size
)
280 struct kmod_elf
*elf
;
281 size_t hdr_size
, shdr_size
, min_size
;
284 assert_cc(sizeof(uint16_t) == sizeof(Elf32_Half
));
285 assert_cc(sizeof(uint16_t) == sizeof(Elf64_Half
));
286 assert_cc(sizeof(uint32_t) == sizeof(Elf32_Word
));
287 assert_cc(sizeof(uint32_t) == sizeof(Elf64_Word
));
289 class = elf_identify(memory
, size
);
295 elf
= malloc(sizeof(struct kmod_elf
));
300 elf
->memory
= memory
;
305 #define READV(field) \
306 elf_get_uint(elf, offsetof(typeof(*hdr), field), sizeof(hdr->field))
308 #define LOAD_HEADER \
309 elf->header.section.offset = READV(e_shoff); \
310 elf->header.section.count = READV(e_shnum); \
311 elf->header.section.entry_size = READV(e_shentsize); \
312 elf->header.strings.section = READV(e_shstrndx); \
313 elf->header.machine = READV(e_machine)
314 if (elf
->class & KMOD_ELF_32
) {
315 const Elf32_Ehdr
*hdr _unused_
= elf_get_mem(elf
, 0);
317 hdr_size
= sizeof(Elf32_Ehdr
);
318 shdr_size
= sizeof(Elf32_Shdr
);
320 const Elf64_Ehdr
*hdr _unused_
= elf_get_mem(elf
, 0);
322 hdr_size
= sizeof(Elf64_Ehdr
);
323 shdr_size
= sizeof(Elf64_Shdr
);
328 ELFDBG(elf
, "section: offset=%"PRIu64
" count=%"PRIu16
" entry_size=%"PRIu16
" strings index=%"PRIu16
"\n",
329 elf
->header
.section
.offset
,
330 elf
->header
.section
.count
,
331 elf
->header
.section
.entry_size
,
332 elf
->header
.strings
.section
);
334 if (elf
->header
.section
.entry_size
!= shdr_size
) {
335 ELFDBG(elf
, "unexpected section entry size: %"PRIu16
", expected %"PRIu16
"\n",
336 elf
->header
.section
.entry_size
, shdr_size
);
339 min_size
= hdr_size
+ shdr_size
* elf
->header
.section
.count
;
340 if (min_size
>= elf
->size
) {
341 ELFDBG(elf
, "file is too short to hold sections\n");
345 if (elf_get_section_info(elf
, elf
->header
.strings
.section
,
346 &elf
->header
.strings
.offset
,
347 &elf
->header
.strings
.size
,
348 &elf
->header
.strings
.nameoff
) < 0) {
349 ELFDBG(elf
, "could not get strings section\n");
353 const char *s
= elf_get_strings_section(elf
, &slen
);
354 if (slen
== 0 || s
[slen
- 1] != '\0') {
355 ELFDBG(elf
, "strings section does not ends with \\0\n");
368 void kmod_elf_unref(struct kmod_elf
*elf
)
374 const void *kmod_elf_get_memory(const struct kmod_elf
*elf
)
379 static int elf_find_section(const struct kmod_elf
*elf
, const char *section
)
382 const char *names
= elf_get_strings_section(elf
, &nameslen
);
385 for (i
= 1; i
< elf
->header
.section
.count
; i
++) {
389 int err
= elf_get_section_info(elf
, i
, &off
, &size
, &nameoff
);
392 if (nameoff
>= nameslen
)
395 if (!streq(section
, n
))
404 int kmod_elf_get_section(const struct kmod_elf
*elf
, const char *section
, const void **buf
, uint64_t *buf_size
)
407 const char *names
= elf_get_strings_section(elf
, &nameslen
);
413 for (i
= 1; i
< elf
->header
.section
.count
; i
++) {
417 int err
= elf_get_section_info(elf
, i
, &off
, &size
, &nameoff
);
420 if (nameoff
>= nameslen
)
423 if (!streq(section
, n
))
426 *buf
= elf_get_mem(elf
, off
);
434 /* array will be allocated with strings in a single malloc, just free *array */
435 int kmod_elf_get_strings(const struct kmod_elf
*elf
, const char *section
, char ***array
)
446 err
= kmod_elf_get_section(elf
, section
, &buf
, &size
);
451 if (strings
== NULL
|| size
== 0)
454 /* skip zero padding */
455 while (strings
[0] == '\0' && size
> 1) {
463 for (i
= 0, count
= 0; i
< size
; ) {
464 if (strings
[i
] != '\0') {
469 while (strings
[i
] == '\0' && i
< size
)
475 if (strings
[i
- 1] != '\0')
478 *array
= a
= malloc(size
+ 1 + sizeof(char *) * (count
+ 1));
482 s
= (char *)(a
+ count
+ 1);
483 memcpy(s
, strings
, size
);
485 /* make sure the last string is NULL-terminated */
490 for (i
= 0, j
= 1; j
< count
&& i
< size
; ) {
496 while (strings
[i
] == '\0' && i
< size
)
506 /* array will be allocated with strings in a single malloc, just free *array */
507 int kmod_elf_get_modversions(const struct kmod_elf
*elf
, struct kmod_modversion
**array
)
509 size_t off
, offcrc
, slen
;
511 struct kmod_modversion
*a
;
515 #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64))
517 assert_cc(sizeof(struct kmod_modversion64
) ==
518 sizeof(struct kmod_modversion32
));
520 if (elf
->class & KMOD_ELF_32
)
521 offcrc
= sizeof(uint32_t);
523 offcrc
= sizeof(uint64_t);
527 err
= kmod_elf_get_section(elf
, "__versions", &buf
, &size
);
531 if (buf
== NULL
|| size
== 0)
534 if (size
% MODVERSION_SEC_SIZE
!= 0)
537 count
= size
/ MODVERSION_SEC_SIZE
;
539 off
= (const uint8_t *)buf
- elf
->memory
;
542 for (i
= 0; i
< count
; i
++, off
+= MODVERSION_SEC_SIZE
) {
543 const char *symbol
= elf_get_mem(elf
, off
+ offcrc
);
545 if (symbol
[0] == '.')
548 slen
+= strlen(symbol
) + 1;
551 *array
= a
= malloc(sizeof(struct kmod_modversion
) * count
+ slen
);
555 itr
= (char *)(a
+ count
);
556 off
= (const uint8_t *)buf
- elf
->memory
;
558 for (i
= 0; i
< count
; i
++, off
+= MODVERSION_SEC_SIZE
) {
559 uint64_t crc
= elf_get_uint(elf
, off
, offcrc
);
560 const char *symbol
= elf_get_mem(elf
, off
+ offcrc
);
563 if (symbol
[0] == '.')
567 a
[i
].bind
= KMOD_SYMBOL_UNDEF
;
569 symbollen
= strlen(symbol
) + 1;
570 memcpy(itr
, symbol
, symbollen
);
577 int kmod_elf_strip_section(struct kmod_elf
*elf
, const char *section
)
581 int idx
= elf_find_section(elf
, section
);
587 buf
= elf_get_section_header(elf
, idx
);
588 off
= (const uint8_t *)buf
- elf
->memory
;
590 if (elf
->class & KMOD_ELF_32
) {
591 off
+= offsetof(Elf32_Shdr
, sh_flags
);
592 size
= sizeof(((Elf32_Shdr
*)buf
)->sh_flags
);
594 off
+= offsetof(Elf64_Shdr
, sh_flags
);
595 size
= sizeof(((Elf64_Shdr
*)buf
)->sh_flags
);
598 val
= elf_get_uint(elf
, off
, size
);
599 val
&= ~(uint64_t)SHF_ALLOC
;
601 return elf_set_uint(elf
, off
, size
, val
);
604 int kmod_elf_strip_vermagic(struct kmod_elf
*elf
)
611 err
= kmod_elf_get_section(elf
, ".modinfo", &buf
, &size
);
615 if (strings
== NULL
|| size
== 0)
618 /* skip zero padding */
619 while (strings
[0] == '\0' && size
> 1) {
626 for (i
= 0; i
< size
; i
++) {
630 if (strings
[i
] == '\0')
636 len
= sizeof("vermagic=") - 1;
639 if (strncmp(s
, "vermagic=", len
) != 0) {
643 off
= (const uint8_t *)s
- elf
->memory
;
645 if (elf
->changed
== NULL
) {
646 elf
->changed
= malloc(elf
->size
);
647 if (elf
->changed
== NULL
)
649 memcpy(elf
->changed
, elf
->memory
, elf
->size
);
650 elf
->memory
= elf
->changed
;
651 ELFDBG(elf
, "copied memory to allow writing.\n");
655 ELFDBG(elf
, "clear .modinfo vermagic \"%s\" (%zd bytes)\n",
657 memset(elf
->changed
+ off
, '\0', len
);
661 ELFDBG(elf
, "no vermagic found in .modinfo\n");
666 static int kmod_elf_get_symbols_symtab(const struct kmod_elf
*elf
, struct kmod_modversion
**array
)
668 uint64_t i
, last
, size
;
672 struct kmod_modversion
*a
;
677 err
= kmod_elf_get_section(elf
, "__ksymtab_strings", &buf
, &size
);
681 if (strings
== NULL
|| size
== 0)
684 /* skip zero padding */
685 while (strings
[0] == '\0' && size
> 1) {
693 for (i
= 0, count
= 0; i
< size
; i
++) {
694 if (strings
[i
] == '\0') {
703 if (strings
[i
- 1] != '\0')
706 *array
= a
= malloc(size
+ 1 + sizeof(struct kmod_modversion
) * count
);
710 itr
= (char *)(a
+ count
);
712 for (i
= 0, count
= 0; i
< size
; i
++) {
713 if (strings
[i
] == '\0') {
714 size_t slen
= i
- last
;
720 a
[count
].bind
= KMOD_SYMBOL_GLOBAL
;
721 a
[count
].symbol
= itr
;
722 memcpy(itr
, strings
+ last
, slen
);
729 if (strings
[i
- 1] != '\0') {
730 size_t slen
= i
- last
;
732 a
[count
].bind
= KMOD_SYMBOL_GLOBAL
;
733 a
[count
].symbol
= itr
;
734 memcpy(itr
, strings
+ last
, slen
);
742 static inline uint8_t kmod_symbol_bind_from_elf(uint8_t elf_value
)
746 return KMOD_SYMBOL_LOCAL
;
748 return KMOD_SYMBOL_GLOBAL
;
750 return KMOD_SYMBOL_WEAK
;
752 return KMOD_SYMBOL_NONE
;
756 /* array will be allocated with strings in a single malloc, just free *array */
757 int kmod_elf_get_symbols(const struct kmod_elf
*elf
, struct kmod_modversion
**array
)
759 static const char crc_str
[] = "__crc_";
760 static const size_t crc_strlen
= sizeof(crc_str
) - 1;
761 uint64_t strtablen
, symtablen
, str_off
, sym_off
;
762 const void *strtab
, *symtab
;
763 struct kmod_modversion
*a
;
766 int i
, count
, symcount
, err
;
768 err
= kmod_elf_get_section(elf
, ".strtab", &strtab
, &strtablen
);
770 ELFDBG(elf
, "no .strtab found.\n");
774 err
= kmod_elf_get_section(elf
, ".symtab", &symtab
, &symtablen
);
776 ELFDBG(elf
, "no .symtab found.\n");
780 if (elf
->class & KMOD_ELF_32
)
781 symlen
= sizeof(Elf32_Sym
);
783 symlen
= sizeof(Elf64_Sym
);
785 if (symtablen
% symlen
!= 0) {
786 ELFDBG(elf
, "unexpected .symtab of length %"PRIu64
", not multiple of %"PRIu64
" as expected.\n", symtablen
, symlen
);
790 symcount
= symtablen
/ symlen
;
793 str_off
= (const uint8_t *)strtab
- elf
->memory
;
794 sym_off
= (const uint8_t *)symtab
- elf
->memory
+ symlen
;
795 for (i
= 1; i
< symcount
; i
++, sym_off
+= symlen
) {
799 #define READV(field) \
800 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
802 if (elf
->class & KMOD_ELF_32
) {
804 name_off
= READV(st_name
);
807 name_off
= READV(st_name
);
810 if (name_off
>= strtablen
) {
811 ELFDBG(elf
, ".strtab is %"PRIu64
" bytes, but .symtab entry %d wants to access offset %"PRIu32
".\n", strtablen
, i
, name_off
);
815 name
= elf_get_mem(elf
, str_off
+ name_off
);
817 if (strncmp(name
, crc_str
, crc_strlen
) != 0)
819 slen
+= strlen(name
+ crc_strlen
) + 1;
826 *array
= a
= malloc(sizeof(struct kmod_modversion
) * count
+ slen
);
830 itr
= (char *)(a
+ count
);
832 str_off
= (const uint8_t *)strtab
- elf
->memory
;
833 sym_off
= (const uint8_t *)symtab
- elf
->memory
+ symlen
;
834 for (i
= 1; i
< symcount
; i
++, sym_off
+= symlen
) {
840 #define READV(field) \
841 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
843 if (elf
->class & KMOD_ELF_32
) {
845 name_off
= READV(st_name
);
846 crc
= READV(st_value
);
847 info
= READV(st_info
);
850 name_off
= READV(st_name
);
851 crc
= READV(st_value
);
852 info
= READV(st_info
);
855 name
= elf_get_mem(elf
, str_off
+ name_off
);
856 if (strncmp(name
, crc_str
, crc_strlen
) != 0)
860 if (elf
->class & KMOD_ELF_32
)
861 bind
= ELF32_ST_BIND(info
);
863 bind
= ELF64_ST_BIND(info
);
866 a
[count
].bind
= kmod_symbol_bind_from_elf(bind
);
867 a
[count
].symbol
= itr
;
869 memcpy(itr
, name
, slen
);
877 ELFDBG(elf
, "Falling back to __ksymtab_strings!\n");
878 return kmod_elf_get_symbols_symtab(elf
, array
);
881 static int kmod_elf_crc_find(const struct kmod_elf
*elf
, const void *versions
, uint64_t versionslen
, const char *name
, uint64_t *crc
)
883 size_t verlen
, crclen
, off
;
886 if (elf
->class & KMOD_ELF_32
) {
887 struct kmod_modversion32
*mv
;
888 verlen
= sizeof(*mv
);
889 crclen
= sizeof(mv
->crc
);
891 struct kmod_modversion64
*mv
;
892 verlen
= sizeof(*mv
);
893 crclen
= sizeof(mv
->crc
);
896 off
= (const uint8_t *)versions
- elf
->memory
;
897 for (i
= 0; i
< versionslen
; i
+= verlen
) {
898 const char *symbol
= elf_get_mem(elf
, off
+ i
+ crclen
);
899 if (!streq(name
, symbol
))
901 *crc
= elf_get_uint(elf
, off
+ i
, crclen
);
905 ELFDBG(elf
, "could not find crc for symbol '%s'\n", name
);
910 /* from module-init-tools:elfops_core.c */
912 #define STT_REGISTER 13 /* Global register reserved to app. */
915 /* array will be allocated with strings in a single malloc, just free *array */
916 int kmod_elf_get_dependency_symbols(const struct kmod_elf
*elf
, struct kmod_modversion
**array
)
918 uint64_t versionslen
, strtablen
, symtablen
, str_off
, sym_off
, ver_off
;
919 const void *versions
, *strtab
, *symtab
;
920 struct kmod_modversion
*a
;
922 size_t slen
, verlen
, symlen
, crclen
;
923 int i
, count
, symcount
, vercount
, err
;
924 bool handle_register_symbols
;
925 uint8_t *visited_versions
;
928 err
= kmod_elf_get_section(elf
, "__versions", &versions
, &versionslen
);
935 if (elf
->class & KMOD_ELF_32
) {
936 struct kmod_modversion32
*mv
;
937 verlen
= sizeof(*mv
);
938 crclen
= sizeof(mv
->crc
);
940 struct kmod_modversion64
*mv
;
941 verlen
= sizeof(*mv
);
942 crclen
= sizeof(mv
->crc
);
944 if (versionslen
% verlen
!= 0) {
945 ELFDBG(elf
, "unexpected __versions of length %"PRIu64
", not multiple of %zd as expected.\n", versionslen
, verlen
);
951 err
= kmod_elf_get_section(elf
, ".strtab", &strtab
, &strtablen
);
953 ELFDBG(elf
, "no .strtab found.\n");
957 err
= kmod_elf_get_section(elf
, ".symtab", &symtab
, &symtablen
);
959 ELFDBG(elf
, "no .symtab found.\n");
963 if (elf
->class & KMOD_ELF_32
)
964 symlen
= sizeof(Elf32_Sym
);
966 symlen
= sizeof(Elf64_Sym
);
968 if (symtablen
% symlen
!= 0) {
969 ELFDBG(elf
, "unexpected .symtab of length %"PRIu64
", not multiple of %"PRIu64
" as expected.\n", symtablen
, symlen
);
973 if (versionslen
== 0) {
975 visited_versions
= NULL
;
977 vercount
= versionslen
/ verlen
;
978 visited_versions
= calloc(vercount
, sizeof(uint8_t));
979 if (visited_versions
== NULL
)
983 handle_register_symbols
= (elf
->header
.machine
== EM_SPARC
||
984 elf
->header
.machine
== EM_SPARCV9
);
986 symcount
= symtablen
/ symlen
;
989 str_off
= (const uint8_t *)strtab
- elf
->memory
;
990 sym_off
= (const uint8_t *)symtab
- elf
->memory
+ symlen
;
992 symcrcs
= calloc(symcount
, sizeof(uint64_t));
993 if (symcrcs
== NULL
) {
994 free(visited_versions
);
998 for (i
= 1; i
< symcount
; i
++, sym_off
+= symlen
) {
1006 #define READV(field) \
1007 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1009 if (elf
->class & KMOD_ELF_32
) {
1011 name_off
= READV(st_name
);
1012 secidx
= READV(st_shndx
);
1013 info
= READV(st_info
);
1016 name_off
= READV(st_name
);
1017 secidx
= READV(st_shndx
);
1018 info
= READV(st_info
);
1021 if (secidx
!= SHN_UNDEF
)
1024 if (handle_register_symbols
) {
1026 if (elf
->class & KMOD_ELF_32
)
1027 type
= ELF32_ST_TYPE(info
);
1029 type
= ELF64_ST_TYPE(info
);
1031 /* Not really undefined: sparc gcc 3.3 creates
1032 * U references when you have global asm
1033 * variables, to avoid anyone else misusing
1036 if (type
== STT_REGISTER
)
1040 if (name_off
>= strtablen
) {
1041 ELFDBG(elf
, ".strtab is %"PRIu64
" bytes, but .symtab entry %d wants to access offset %"PRIu32
".\n", strtablen
, i
, name_off
);
1042 free(visited_versions
);
1047 name
= elf_get_mem(elf
, str_off
+ name_off
);
1048 if (name
[0] == '\0') {
1049 ELFDBG(elf
, "empty symbol name at index %"PRIu64
"\n", i
);
1053 slen
+= strlen(name
) + 1;
1056 idx
= kmod_elf_crc_find(elf
, versions
, versionslen
, name
, &crc
);
1057 if (idx
>= 0 && visited_versions
!= NULL
)
1058 visited_versions
[idx
] = 1;
1062 if (visited_versions
!= NULL
) {
1063 /* module_layout/struct_module are not visited, but needed */
1064 ver_off
= (const uint8_t *)versions
- elf
->memory
;
1065 for (i
= 0; i
< vercount
; i
++) {
1066 if (visited_versions
[i
] == 0) {
1068 name
= elf_get_mem(elf
, ver_off
+ i
* verlen
+ crclen
);
1069 slen
+= strlen(name
) + 1;
1077 free(visited_versions
);
1083 *array
= a
= malloc(sizeof(struct kmod_modversion
) * count
+ slen
);
1084 if (*array
== NULL
) {
1085 free(visited_versions
);
1090 itr
= (char *)(a
+ count
);
1092 str_off
= (const uint8_t *)strtab
- elf
->memory
;
1093 sym_off
= (const uint8_t *)symtab
- elf
->memory
+ symlen
;
1094 for (i
= 1; i
< symcount
; i
++, sym_off
+= symlen
) {
1101 #define READV(field) \
1102 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1104 if (elf
->class & KMOD_ELF_32
) {
1106 name_off
= READV(st_name
);
1107 secidx
= READV(st_shndx
);
1108 info
= READV(st_info
);
1111 name_off
= READV(st_name
);
1112 secidx
= READV(st_shndx
);
1113 info
= READV(st_info
);
1116 if (secidx
!= SHN_UNDEF
)
1119 if (handle_register_symbols
) {
1121 if (elf
->class & KMOD_ELF_32
)
1122 type
= ELF32_ST_TYPE(info
);
1124 type
= ELF64_ST_TYPE(info
);
1126 /* Not really undefined: sparc gcc 3.3 creates
1127 * U references when you have global asm
1128 * variables, to avoid anyone else misusing
1131 if (type
== STT_REGISTER
)
1135 name
= elf_get_mem(elf
, str_off
+ name_off
);
1136 if (name
[0] == '\0') {
1137 ELFDBG(elf
, "empty symbol name at index %"PRIu64
"\n", i
);
1141 if (elf
->class & KMOD_ELF_32
)
1142 bind
= ELF32_ST_BIND(info
);
1144 bind
= ELF64_ST_BIND(info
);
1145 if (bind
== STB_WEAK
)
1146 bind
= KMOD_SYMBOL_WEAK
;
1148 bind
= KMOD_SYMBOL_UNDEF
;
1150 slen
= strlen(name
);
1154 a
[count
].bind
= bind
;
1155 a
[count
].symbol
= itr
;
1156 memcpy(itr
, name
, slen
);
1165 if (visited_versions
== NULL
)
1168 /* add unvisited (module_layout/struct_module) */
1169 ver_off
= (const uint8_t *)versions
- elf
->memory
;
1170 for (i
= 0; i
< vercount
; i
++) {
1174 if (visited_versions
[i
] != 0)
1177 name
= elf_get_mem(elf
, ver_off
+ i
* verlen
+ crclen
);
1178 slen
= strlen(name
);
1179 crc
= elf_get_uint(elf
, ver_off
+ i
* verlen
, crclen
);
1182 a
[count
].bind
= KMOD_SYMBOL_UNDEF
;
1183 a
[count
].symbol
= itr
;
1184 memcpy(itr
, name
, slen
);
1190 free(visited_versions
);