]>
git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-elf.c
fb2e3d9293c04bc03bd8c53e2c0c7feb82f1010a
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
);