blob: 90da89aebbaf67c692d55e78f150830b957087ae [file] [log] [blame]
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -02001/*
2 * libkmod - interface to kernel module operations
3 *
Lucas De Marchie6b0e492013-01-16 11:27:21 -02004 * Copyright (C) 2011-2013 ProFUSION embedded systems
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -02005 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Lucas De Marchidea2dfe2014-12-25 23:32:03 -020017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020018 */
19
Lucas De Marchic2e42862014-10-03 01:41:42 -030020#include <assert.h>
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020021#include <elf.h>
Lucas De Marchic2e42862014-10-03 01:41:42 -030022#include <errno.h>
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020023#include <stdlib.h>
24#include <string.h>
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020025
Lucas De Marchi96573a02014-10-03 00:01:35 -030026#include <shared/util.h>
27
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020028#include "libkmod.h"
Lucas De Marchi83b855a2013-07-04 16:13:11 -030029#include "libkmod-internal.h"
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020030
31enum kmod_elf_class {
32 KMOD_ELF_32 = (1 << 1),
33 KMOD_ELF_64 = (1 << 2),
34 KMOD_ELF_LSB = (1 << 3),
35 KMOD_ELF_MSB = (1 << 4)
36};
37
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -020038/* as defined in module-init-tools */
39struct kmod_modversion32 {
40 uint32_t crc;
41 char name[64 - sizeof(uint32_t)];
42};
43
44struct kmod_modversion64 {
45 uint64_t crc;
46 char name[64 - sizeof(uint64_t)];
47};
48
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020049struct kmod_elf {
50 const uint8_t *memory;
51 uint8_t *changed;
52 uint64_t size;
53 enum kmod_elf_class class;
54 struct kmod_elf_header {
55 struct {
56 uint64_t offset;
57 uint16_t count;
58 uint16_t entry_size;
59 } section;
60 struct {
61 uint16_t section; /* index of the strings section */
62 uint64_t size;
63 uint64_t offset;
64 uint32_t nameoff; /* offset in strings itself */
65 } strings;
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -020066 uint16_t machine;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020067 } header;
68};
69
70//#define ENABLE_ELFDBG 1
71
72#if defined(ENABLE_LOGGING) && defined(ENABLE_ELFDBG)
73#define ELFDBG(elf, ...) \
Jan Engelhardt87beacc2011-12-20 16:27:40 +010074 _elf_dbg(elf, __FILE__, __LINE__, __func__, __VA_ARGS__);
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -020075
76static inline void _elf_dbg(const struct kmod_elf *elf, const char *fname, unsigned line, const char *func, const char *fmt, ...)
77{
78 va_list args;
79
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',
83 fname, line, func);
84 va_start(args, fmt);
85 vfprintf(stderr, fmt, args);
86 va_end(args);
87}
88#else
89#define ELFDBG(elf, ...)
90#endif
91
92
93static int elf_identify(const void *memory, uint64_t size)
94{
95 const uint8_t *p = memory;
96 int class = 0;
97
98 if (size <= EI_NIDENT || memcmp(p, ELFMAG, SELFMAG) != 0)
99 return -ENOEXEC;
100
101 switch (p[EI_CLASS]) {
102 case ELFCLASS32:
103 if (size <= sizeof(Elf32_Ehdr))
104 return -EINVAL;
105 class |= KMOD_ELF_32;
106 break;
107 case ELFCLASS64:
108 if (size <= sizeof(Elf64_Ehdr))
109 return -EINVAL;
110 class |= KMOD_ELF_64;
111 break;
112 default:
113 return -EINVAL;
114 }
115
116 switch (p[EI_DATA]) {
117 case ELFDATA2LSB:
118 class |= KMOD_ELF_LSB;
119 break;
120 case ELFDATA2MSB:
121 class |= KMOD_ELF_MSB;
122 break;
123 default:
124 return -EINVAL;
125 }
126
127 return class;
128}
129
130static inline uint64_t elf_get_uint(const struct kmod_elf *elf, uint64_t offset, uint16_t size)
131{
132 const uint8_t *p;
133 uint64_t ret = 0;
134 size_t i;
135
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);
141 return (uint64_t)-1;
142 }
143
144 p = elf->memory + offset;
145 if (elf->class & KMOD_ELF_MSB) {
146 for (i = 0; i < size; i++)
Gustavo Sverzut Barbierifc8e58b2011-12-19 21:51:31 -0200147 ret = (ret << 8) | p[i];
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200148 } else {
149 for (i = 1; i <= size; i++)
150 ret = (ret << 8) | p[size - i];
151 }
152
153 ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64"\n",
154 size, offset, ret);
155
156 return ret;
157}
158
159static inline int elf_set_uint(struct kmod_elf *elf, uint64_t offset, uint64_t size, uint64_t value)
160{
161 uint8_t *p;
162 size_t i;
163
164 ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64" write memory=%p\n",
165 size, offset, value, elf->changed);
166
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);
172 return -1;
173 }
174
175 if (elf->changed == NULL) {
176 elf->changed = malloc(elf->size);
177 if (elf->changed == NULL)
178 return -errno;
179 memcpy(elf->changed, elf->memory, elf->size);
180 elf->memory = elf->changed;
181 ELFDBG(elf, "copied memory to allow writing.\n");
182 }
183
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;
189 }
190 } else {
191 for (i = 0; i < size; i++) {
192 p[i] = value & 0xff;
193 value = (value & 0xffffffffffffff00) >> 8;
194 }
195 }
196
197 return 0;
198}
199
200static inline const void *elf_get_mem(const struct kmod_elf *elf, uint64_t offset)
201{
202 assert(offset < elf->size);
203 if (offset >= elf->size) {
204 ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n",
205 offset, elf->size);
206 return NULL;
207 }
208 return elf->memory + offset;
209}
210
211static inline const void *elf_get_section_header(const struct kmod_elf *elf, uint16_t idx)
212{
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);
218 return NULL;
219 }
220 return elf_get_mem(elf, elf->header.section.offset +
Lucas De Marchid98f2d32015-02-28 16:07:55 -0300221 (uint64_t)(idx * elf->header.section.entry_size));
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200222}
223
224static inline int elf_get_section_info(const struct kmod_elf *elf, uint16_t idx, uint64_t *offset, uint64_t *size, uint32_t *nameoff)
225{
226 const uint8_t *p = elf_get_section_header(elf, idx);
227 uint64_t min_size, off = p - elf->memory;
228
229 if (p == NULL) {
230 ELFDBG(elf, "no section at %"PRIu16"\n", idx);
231 *offset = 0;
232 *size = 0;
233 *nameoff = 0;
234 return -EINVAL;
235 }
236
237#define READV(field) \
238 elf_get_uint(elf, off + offsetof(typeof(*hdr), field), sizeof(hdr->field))
239
240 if (elf->class & KMOD_ELF_32) {
Lucas De Marchi9e2eadb2012-05-23 20:28:53 -0300241 const Elf32_Shdr *hdr _unused_ = (const Elf32_Shdr *)p;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200242 *size = READV(sh_size);
243 *offset = READV(sh_offset);
244 *nameoff = READV(sh_name);
245 } else {
Lucas De Marchi9e2eadb2012-05-23 20:28:53 -0300246 const Elf64_Shdr *hdr _unused_ = (const Elf64_Shdr *)p;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200247 *size = READV(sh_size);
248 *offset = READV(sh_offset);
249 *nameoff = READV(sh_name);
250 }
251#undef READV
252
Lucas De Marchi66841022015-02-10 10:46:26 -0200253 if (addu64_overflow(*offset, *size, &min_size)
254 || min_size > elf->size) {
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200255 ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n",
256 min_size, elf->size);
257 return -EINVAL;
258 }
259
260 ELFDBG(elf, "section=%"PRIu16" is: offset=%"PRIu64" size=%"PRIu64" nameoff=%"PRIu32"\n",
261 idx, *offset, *size, *nameoff);
262
263 return 0;
264}
265
266static const char *elf_get_strings_section(const struct kmod_elf *elf, uint64_t *size)
267{
268 *size = elf->header.strings.size;
269 return elf_get_mem(elf, elf->header.strings.offset);
270}
271
272struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
273{
274 struct kmod_elf *elf;
Tobias Stoeckmann249dc592015-02-10 19:46:40 +0100275 uint64_t min_size;
276 size_t shdrs_size, shdr_size;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200277 int class;
278
Lucas De Marchia20a37c2013-04-15 14:14:07 -0300279 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));
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200283
284 class = elf_identify(memory, size);
285 if (class < 0) {
286 errno = -class;
287 return NULL;
288 }
289
290 elf = malloc(sizeof(struct kmod_elf));
291 if (elf == NULL) {
292 return NULL;
293 }
294
295 elf->memory = memory;
296 elf->changed = NULL;
297 elf->size = size;
298 elf->class = class;
299
300#define READV(field) \
301 elf_get_uint(elf, offsetof(typeof(*hdr), field), sizeof(hdr->field))
302
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); \
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200307 elf->header.strings.section = READV(e_shstrndx); \
308 elf->header.machine = READV(e_machine)
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200309 if (elf->class & KMOD_ELF_32) {
Lucas De Marchi9e2eadb2012-05-23 20:28:53 -0300310 const Elf32_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200311 LOAD_HEADER;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200312 shdr_size = sizeof(Elf32_Shdr);
313 } else {
Lucas De Marchi9e2eadb2012-05-23 20:28:53 -0300314 const Elf64_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200315 LOAD_HEADER;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200316 shdr_size = sizeof(Elf64_Shdr);
317 }
318#undef LOAD_HEADER
319#undef READV
320
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);
326
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);
330 goto invalid;
331 }
Tobias Stoeckmann249dc592015-02-10 19:46:40 +0100332 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) {
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200335 ELFDBG(elf, "file is too short to hold sections\n");
336 goto invalid;
337 }
338
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");
344 goto invalid;
345 } else {
346 uint64_t slen;
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");
350 goto invalid;
351 }
352 }
353
354 return elf;
355
356invalid:
357 free(elf);
358 errno = EINVAL;
359 return NULL;
360}
361
362void kmod_elf_unref(struct kmod_elf *elf)
363{
364 free(elf->changed);
365 free(elf);
366}
367
368const void *kmod_elf_get_memory(const struct kmod_elf *elf)
369{
370 return elf->memory;
371}
372
Lucas De Marchia4578662012-11-21 20:17:25 -0200373static int elf_find_section(const struct kmod_elf *elf, const char *section)
374{
375 uint64_t nameslen;
376 const char *names = elf_get_strings_section(elf, &nameslen);
377 uint16_t i;
378
379 for (i = 1; i < elf->header.section.count; i++) {
380 uint64_t off, size;
381 uint32_t nameoff;
382 const char *n;
383 int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
384 if (err < 0)
385 continue;
386 if (nameoff >= nameslen)
387 continue;
388 n = names + nameoff;
389 if (!streq(section, n))
390 continue;
391
392 return i;
393 }
394
395 return -ENOENT;
396}
397
Lucas De Marchiea17e2b2012-01-26 01:21:17 -0200398int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, const void **buf, uint64_t *buf_size)
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200399{
400 uint64_t nameslen;
401 const char *names = elf_get_strings_section(elf, &nameslen);
402 uint16_t i;
403
404 *buf = NULL;
405 *buf_size = 0;
406
407 for (i = 1; i < elf->header.section.count; i++) {
408 uint64_t off, size;
409 uint32_t nameoff;
410 const char *n;
411 int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
412 if (err < 0)
413 continue;
414 if (nameoff >= nameslen)
415 continue;
416 n = names + nameoff;
417 if (!streq(section, n))
418 continue;
419
420 *buf = elf_get_mem(elf, off);
421 *buf_size = size;
422 return 0;
423 }
424
425 return -ENOENT;
426}
427
428/* array will be allocated with strings in a single malloc, just free *array */
429int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array)
430{
Luis Felipe Strano Moraesa9693762011-12-20 07:11:46 -0800431 size_t i, j, count;
432 uint64_t size;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200433 const void *buf;
434 const char *strings;
Lucas De Marchif8fa5252011-12-20 03:25:23 -0200435 char *s, **a;
436 int err;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200437
438 *array = NULL;
439
440 err = kmod_elf_get_section(elf, section, &buf, &size);
441 if (err < 0)
442 return err;
Lucas De Marchi052656f2011-12-20 03:10:58 -0200443
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200444 strings = buf;
445 if (strings == NULL || size == 0)
446 return 0;
447
448 /* skip zero padding */
449 while (strings[0] == '\0' && size > 1) {
450 strings++;
451 size--;
452 }
Lucas De Marchi052656f2011-12-20 03:10:58 -0200453
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200454 if (size <= 1)
455 return 0;
456
Lucas De Marchi76b80312011-12-20 12:04:21 -0200457 for (i = 0, count = 0; i < size; ) {
458 if (strings[i] != '\0') {
459 i++;
Lucas De Marchi4f0f0e72011-12-20 03:08:09 -0200460 continue;
Lucas De Marchi76b80312011-12-20 12:04:21 -0200461 }
462
463 while (strings[i] == '\0' && i < size)
464 i++;
Lucas De Marchi4f0f0e72011-12-20 03:08:09 -0200465
Lucas De Marchi4f0f0e72011-12-20 03:08:09 -0200466 count++;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200467 }
Lucas De Marchi052656f2011-12-20 03:10:58 -0200468
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200469 if (strings[i - 1] != '\0')
470 count++;
471
Lucas De Marchi32670262011-12-20 03:09:58 -0200472 *array = a = malloc(size + 1 + sizeof(char *) * (count + 1));
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200473 if (*array == NULL)
474 return -errno;
475
Lucas De Marchif8fa5252011-12-20 03:25:23 -0200476 s = (char *)(a + count + 1);
477 memcpy(s, strings, size);
478
479 /* make sure the last string is NULL-terminated */
480 s[size] = '\0';
Lucas De Marchi32670262011-12-20 03:09:58 -0200481 a[count] = NULL;
Lucas De Marchif8fa5252011-12-20 03:25:23 -0200482 a[0] = s;
Lucas De Marchi052656f2011-12-20 03:10:58 -0200483
Lucas De Marchi76b80312011-12-20 12:04:21 -0200484 for (i = 0, j = 1; j < count && i < size; ) {
485 if (s[i] != '\0') {
486 i++;
Lucas De Marchif8fa5252011-12-20 03:25:23 -0200487 continue;
Lucas De Marchi76b80312011-12-20 12:04:21 -0200488 }
Lucas De Marchi052656f2011-12-20 03:10:58 -0200489
Lucas De Marchi76b80312011-12-20 12:04:21 -0200490 while (strings[i] == '\0' && i < size)
491 i++;
492
493 a[j] = &s[i];
Lucas De Marchif8fa5252011-12-20 03:25:23 -0200494 j++;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200495 }
496
497 return count;
498}
499
500/* array will be allocated with strings in a single malloc, just free *array */
501int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array)
502{
Luis Felipe Strano Moraesa9693762011-12-20 07:11:46 -0800503 size_t off, offcrc, slen;
504 uint64_t size;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200505 struct kmod_modversion *a;
506 const void *buf;
507 char *itr;
508 int i, count, err;
Lucas De Marchi58b71912011-12-20 04:02:15 -0200509#define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64))
510
Lucas De Marchia20a37c2013-04-15 14:14:07 -0300511 assert_cc(sizeof(struct kmod_modversion64) ==
Lucas De Marchi58b71912011-12-20 04:02:15 -0200512 sizeof(struct kmod_modversion32));
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200513
Lucas De Marchifea655d2014-03-07 01:17:10 -0300514 if (elf->class & KMOD_ELF_32)
Lucas De Marchi51c409b2011-12-20 11:41:19 -0200515 offcrc = sizeof(uint32_t);
516 else
517 offcrc = sizeof(uint64_t);
518
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200519 *array = NULL;
520
521 err = kmod_elf_get_section(elf, "__versions", &buf, &size);
522 if (err < 0)
523 return err;
Lucas De Marchi58b71912011-12-20 04:02:15 -0200524
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200525 if (buf == NULL || size == 0)
526 return 0;
527
Lucas De Marchi58b71912011-12-20 04:02:15 -0200528 if (size % MODVERSION_SEC_SIZE != 0)
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200529 return -EINVAL;
Lucas De Marchi58b71912011-12-20 04:02:15 -0200530
531 count = size / MODVERSION_SEC_SIZE;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200532
533 off = (const uint8_t *)buf - elf->memory;
534 slen = 0;
Lucas De Marchi51c409b2011-12-20 11:41:19 -0200535
Lucas De Marchi58b71912011-12-20 04:02:15 -0200536 for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
Lucas De Marchi51c409b2011-12-20 11:41:19 -0200537 const char *symbol = elf_get_mem(elf, off + offcrc);
538
Gustavo Sverzut Barbieri1c585902011-12-19 21:53:24 -0200539 if (symbol[0] == '.')
540 symbol++;
Lucas De Marchi51c409b2011-12-20 11:41:19 -0200541
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200542 slen += strlen(symbol) + 1;
543 }
544
545 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
546 if (*array == NULL)
547 return -errno;
548
549 itr = (char *)(a + count);
550 off = (const uint8_t *)buf - elf->memory;
Lucas De Marchi51c409b2011-12-20 11:41:19 -0200551
Lucas De Marchi58b71912011-12-20 04:02:15 -0200552 for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
Lucas De Marchi51c409b2011-12-20 11:41:19 -0200553 uint64_t crc = elf_get_uint(elf, off, offcrc);
554 const char *symbol = elf_get_mem(elf, off + offcrc);
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200555 size_t symbollen;
Lucas De Marchi51c409b2011-12-20 11:41:19 -0200556
Gustavo Sverzut Barbieri1c585902011-12-19 21:53:24 -0200557 if (symbol[0] == '.')
558 symbol++;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200559
560 a[i].crc = crc;
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200561 a[i].bind = KMOD_SYMBOL_UNDEF;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200562 a[i].symbol = itr;
563 symbollen = strlen(symbol) + 1;
564 memcpy(itr, symbol, symbollen);
565 itr += symbollen;
566 }
567
568 return count;
569}
570
571int kmod_elf_strip_section(struct kmod_elf *elf, const char *section)
572{
Lucas De Marchia4578662012-11-21 20:17:25 -0200573 uint64_t off, size;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200574 const void *buf;
Lucas De Marchia4578662012-11-21 20:17:25 -0200575 int idx = elf_find_section(elf, section);
576 uint64_t val;
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200577
Lucas De Marchia4578662012-11-21 20:17:25 -0200578 if (idx < 0)
579 return idx;
580
581 buf = elf_get_section_header(elf, idx);
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200582 off = (const uint8_t *)buf - elf->memory;
583
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200584 if (elf->class & KMOD_ELF_32) {
Lucas De Marchia4578662012-11-21 20:17:25 -0200585 off += offsetof(Elf32_Shdr, sh_flags);
586 size = sizeof(((Elf32_Shdr *)buf)->sh_flags);
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200587 } else {
Lucas De Marchia4578662012-11-21 20:17:25 -0200588 off += offsetof(Elf64_Shdr, sh_flags);
589 size = sizeof(((Elf64_Shdr *)buf)->sh_flags);
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200590 }
Lucas De Marchia4578662012-11-21 20:17:25 -0200591
592 val = elf_get_uint(elf, off, size);
593 val &= ~(uint64_t)SHF_ALLOC;
594
595 return elf_set_uint(elf, off, size, val);
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200596}
597
598int kmod_elf_strip_vermagic(struct kmod_elf *elf)
599{
600 uint64_t i, size;
601 const void *buf;
602 const char *strings;
603 int err;
604
605 err = kmod_elf_get_section(elf, ".modinfo", &buf, &size);
606 if (err < 0)
607 return err;
608 strings = buf;
609 if (strings == NULL || size == 0)
610 return 0;
611
612 /* skip zero padding */
613 while (strings[0] == '\0' && size > 1) {
614 strings++;
615 size--;
616 }
617 if (size <= 1)
618 return 0;
619
620 for (i = 0; i < size; i++) {
621 const char *s;
622 size_t off, len;
623
624 if (strings[i] == '\0')
625 continue;
626 if (i + 1 >= size)
627 continue;
628
629 s = strings + i;
630 len = sizeof("vermagic=") - 1;
631 if (i + len >= size)
632 continue;
633 if (strncmp(s, "vermagic=", len) != 0) {
634 i += strlen(s);
635 continue;
636 }
Gustavo Sverzut Barbieri708624a2011-12-18 01:25:06 -0200637 off = (const uint8_t *)s - elf->memory;
638
639 if (elf->changed == NULL) {
640 elf->changed = malloc(elf->size);
641 if (elf->changed == NULL)
642 return -errno;
643 memcpy(elf->changed, elf->memory, elf->size);
644 elf->memory = elf->changed;
645 ELFDBG(elf, "copied memory to allow writing.\n");
646 }
647
648 len = strlen(s);
649 ELFDBG(elf, "clear .modinfo vermagic \"%s\" (%zd bytes)\n",
650 s, len);
651 memset(elf->changed + off, '\0', len);
652 return 0;
653 }
654
655 ELFDBG(elf, "no vermagic found in .modinfo\n");
656 return -ENOENT;
657}
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200658
659
660static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_modversion **array)
661{
662 uint64_t i, last, size;
663 const void *buf;
664 const char *strings;
665 char *itr;
666 struct kmod_modversion *a;
667 int count, err;
668
669 *array = NULL;
670
671 err = kmod_elf_get_section(elf, "__ksymtab_strings", &buf, &size);
672 if (err < 0)
673 return err;
674 strings = buf;
675 if (strings == NULL || size == 0)
676 return 0;
677
678 /* skip zero padding */
679 while (strings[0] == '\0' && size > 1) {
680 strings++;
681 size--;
682 }
683 if (size <= 1)
684 return 0;
685
686 last = 0;
687 for (i = 0, count = 0; i < size; i++) {
688 if (strings[i] == '\0') {
689 if (last == i) {
690 last = i + 1;
691 continue;
692 }
693 count++;
694 last = i + 1;
695 }
696 }
697 if (strings[i - 1] != '\0')
698 count++;
699
700 *array = a = malloc(size + 1 + sizeof(struct kmod_modversion) * count);
701 if (*array == NULL)
702 return -errno;
703
704 itr = (char *)(a + count);
705 last = 0;
706 for (i = 0, count = 0; i < size; i++) {
707 if (strings[i] == '\0') {
708 size_t slen = i - last;
709 if (last == i) {
710 last = i + 1;
711 continue;
712 }
713 a[count].crc = 0;
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200714 a[count].bind = KMOD_SYMBOL_GLOBAL;
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200715 a[count].symbol = itr;
716 memcpy(itr, strings + last, slen);
717 itr[slen] = '\0';
718 itr += slen + 1;
719 count++;
720 last = i + 1;
721 }
722 }
723 if (strings[i - 1] != '\0') {
724 size_t slen = i - last;
725 a[count].crc = 0;
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200726 a[count].bind = KMOD_SYMBOL_GLOBAL;
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200727 a[count].symbol = itr;
728 memcpy(itr, strings + last, slen);
729 itr[slen] = '\0';
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200730 count++;
731 }
732
733 return count;
734}
735
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200736static inline uint8_t kmod_symbol_bind_from_elf(uint8_t elf_value)
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200737{
738 switch (elf_value) {
739 case STB_LOCAL:
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200740 return KMOD_SYMBOL_LOCAL;
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200741 case STB_GLOBAL:
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200742 return KMOD_SYMBOL_GLOBAL;
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200743 case STB_WEAK:
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200744 return KMOD_SYMBOL_WEAK;
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200745 default:
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200746 return KMOD_SYMBOL_NONE;
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200747 }
748}
749
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200750/* array will be allocated with strings in a single malloc, just free *array */
751int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
752{
753 static const char crc_str[] = "__crc_";
754 static const size_t crc_strlen = sizeof(crc_str) - 1;
755 uint64_t strtablen, symtablen, str_off, sym_off;
756 const void *strtab, *symtab;
757 struct kmod_modversion *a;
758 char *itr;
759 size_t slen, symlen;
760 int i, count, symcount, err;
761
762 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
763 if (err < 0) {
764 ELFDBG(elf, "no .strtab found.\n");
765 goto fallback;
766 }
767
768 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
769 if (err < 0) {
770 ELFDBG(elf, "no .symtab found.\n");
771 goto fallback;
772 }
773
774 if (elf->class & KMOD_ELF_32)
775 symlen = sizeof(Elf32_Sym);
776 else
777 symlen = sizeof(Elf64_Sym);
778
779 if (symtablen % symlen != 0) {
780 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
781 goto fallback;
782 }
783
784 symcount = symtablen / symlen;
785 count = 0;
786 slen = 0;
787 str_off = (const uint8_t *)strtab - elf->memory;
788 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
789 for (i = 1; i < symcount; i++, sym_off += symlen) {
790 const char *name;
791 uint32_t name_off;
792
793#define READV(field) \
794 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
795 sizeof(s->field))
796 if (elf->class & KMOD_ELF_32) {
797 Elf32_Sym *s;
798 name_off = READV(st_name);
799 } else {
800 Elf64_Sym *s;
801 name_off = READV(st_name);
802 }
803#undef READV
804 if (name_off >= strtablen) {
805 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
806 goto fallback;
807 }
808
809 name = elf_get_mem(elf, str_off + name_off);
810
811 if (strncmp(name, crc_str, crc_strlen) != 0)
812 continue;
813 slen += strlen(name + crc_strlen) + 1;
814 count++;
815 }
816
817 if (count == 0)
818 goto fallback;
819
820 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
821 if (*array == NULL)
822 return -errno;
823
824 itr = (char *)(a + count);
825 count = 0;
826 str_off = (const uint8_t *)strtab - elf->memory;
827 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
828 for (i = 1; i < symcount; i++, sym_off += symlen) {
829 const char *name;
830 uint32_t name_off;
831 uint64_t crc;
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200832 uint8_t info, bind;
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200833
834#define READV(field) \
835 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
836 sizeof(s->field))
837 if (elf->class & KMOD_ELF_32) {
838 Elf32_Sym *s;
839 name_off = READV(st_name);
840 crc = READV(st_value);
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200841 info = READV(st_info);
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200842 } else {
843 Elf64_Sym *s;
844 name_off = READV(st_name);
845 crc = READV(st_value);
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200846 info = READV(st_info);
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200847 }
848#undef READV
849 name = elf_get_mem(elf, str_off + name_off);
850 if (strncmp(name, crc_str, crc_strlen) != 0)
851 continue;
852 name += crc_strlen;
853
Gustavo Sverzut Barbieri4b55bef2011-12-20 10:11:22 -0200854 if (elf->class & KMOD_ELF_32)
855 bind = ELF32_ST_BIND(info);
856 else
857 bind = ELF64_ST_BIND(info);
858
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200859 a[count].crc = crc;
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200860 a[count].bind = kmod_symbol_bind_from_elf(bind);
Gustavo Sverzut Barbieri45e6db92011-12-19 21:23:13 -0200861 a[count].symbol = itr;
862 slen = strlen(name);
863 memcpy(itr, name, slen);
864 itr[slen] = '\0';
865 itr += slen + 1;
866 count++;
867 }
868 return count;
869
870fallback:
871 ELFDBG(elf, "Falling back to __ksymtab_strings!\n");
872 return kmod_elf_get_symbols_symtab(elf, array);
873}
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -0200874
875static int kmod_elf_crc_find(const struct kmod_elf *elf, const void *versions, uint64_t versionslen, const char *name, uint64_t *crc)
876{
877 size_t verlen, crclen, off;
878 uint64_t i;
879
880 if (elf->class & KMOD_ELF_32) {
881 struct kmod_modversion32 *mv;
882 verlen = sizeof(*mv);
883 crclen = sizeof(mv->crc);
884 } else {
885 struct kmod_modversion64 *mv;
886 verlen = sizeof(*mv);
887 crclen = sizeof(mv->crc);
888 }
889
890 off = (const uint8_t *)versions - elf->memory;
891 for (i = 0; i < versionslen; i += verlen) {
892 const char *symbol = elf_get_mem(elf, off + i + crclen);
893 if (!streq(name, symbol))
894 continue;
895 *crc = elf_get_uint(elf, off + i, crclen);
896 return i / verlen;
897 }
898
899 ELFDBG(elf, "could not find crc for symbol '%s'\n", name);
900 *crc = 0;
901 return -1;
902}
903
904/* from module-init-tools:elfops_core.c */
905#ifndef STT_REGISTER
906#define STT_REGISTER 13 /* Global register reserved to app. */
907#endif
908
909/* array will be allocated with strings in a single malloc, just free *array */
910int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
911{
912 uint64_t versionslen, strtablen, symtablen, str_off, sym_off, ver_off;
913 const void *versions, *strtab, *symtab;
914 struct kmod_modversion *a;
915 char *itr;
916 size_t slen, verlen, symlen, crclen;
917 int i, count, symcount, vercount, err;
918 bool handle_register_symbols;
919 uint8_t *visited_versions;
920 uint64_t *symcrcs;
921
922 err = kmod_elf_get_section(elf, "__versions", &versions, &versionslen);
923 if (err < 0) {
924 versions = NULL;
925 versionslen = 0;
926 verlen = 0;
927 crclen = 0;
928 } else {
929 if (elf->class & KMOD_ELF_32) {
930 struct kmod_modversion32 *mv;
931 verlen = sizeof(*mv);
932 crclen = sizeof(mv->crc);
933 } else {
934 struct kmod_modversion64 *mv;
935 verlen = sizeof(*mv);
936 crclen = sizeof(mv->crc);
937 }
938 if (versionslen % verlen != 0) {
939 ELFDBG(elf, "unexpected __versions of length %"PRIu64", not multiple of %zd as expected.\n", versionslen, verlen);
940 versions = NULL;
941 versionslen = 0;
942 }
943 }
944
945 err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
946 if (err < 0) {
947 ELFDBG(elf, "no .strtab found.\n");
948 return -EINVAL;
949 }
950
951 err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
952 if (err < 0) {
953 ELFDBG(elf, "no .symtab found.\n");
954 return -EINVAL;
955 }
956
957 if (elf->class & KMOD_ELF_32)
958 symlen = sizeof(Elf32_Sym);
959 else
960 symlen = sizeof(Elf64_Sym);
961
962 if (symtablen % symlen != 0) {
963 ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
964 return -EINVAL;
965 }
966
967 if (versionslen == 0) {
968 vercount = 0;
969 visited_versions = NULL;
970 } else {
971 vercount = versionslen / verlen;
972 visited_versions = calloc(vercount, sizeof(uint8_t));
973 if (visited_versions == NULL)
974 return -ENOMEM;
975 }
976
977 handle_register_symbols = (elf->header.machine == EM_SPARC ||
978 elf->header.machine == EM_SPARCV9);
979
980 symcount = symtablen / symlen;
981 count = 0;
982 slen = 0;
983 str_off = (const uint8_t *)strtab - elf->memory;
984 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
985
986 symcrcs = calloc(symcount, sizeof(uint64_t));
987 if (symcrcs == NULL) {
988 free(visited_versions);
989 return -ENOMEM;
990 }
991
992 for (i = 1; i < symcount; i++, sym_off += symlen) {
993 const char *name;
994 uint64_t crc;
995 uint32_t name_off;
996 uint16_t secidx;
997 uint8_t info;
998 int idx;
999
1000#define READV(field) \
1001 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1002 sizeof(s->field))
1003 if (elf->class & KMOD_ELF_32) {
1004 Elf32_Sym *s;
1005 name_off = READV(st_name);
1006 secidx = READV(st_shndx);
1007 info = READV(st_info);
1008 } else {
1009 Elf64_Sym *s;
1010 name_off = READV(st_name);
1011 secidx = READV(st_shndx);
1012 info = READV(st_info);
1013 }
1014#undef READV
1015 if (secidx != SHN_UNDEF)
1016 continue;
1017
1018 if (handle_register_symbols) {
1019 uint8_t type;
1020 if (elf->class & KMOD_ELF_32)
1021 type = ELF32_ST_TYPE(info);
1022 else
1023 type = ELF64_ST_TYPE(info);
1024
1025 /* Not really undefined: sparc gcc 3.3 creates
1026 * U references when you have global asm
1027 * variables, to avoid anyone else misusing
1028 * them.
1029 */
1030 if (type == STT_REGISTER)
1031 continue;
1032 }
1033
1034 if (name_off >= strtablen) {
1035 ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
1036 free(visited_versions);
1037 free(symcrcs);
1038 return -EINVAL;
1039 }
1040
1041 name = elf_get_mem(elf, str_off + name_off);
1042 if (name[0] == '\0') {
1043 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1044 continue;
1045 }
1046
1047 slen += strlen(name) + 1;
1048 count++;
1049
1050 idx = kmod_elf_crc_find(elf, versions, versionslen, name, &crc);
1051 if (idx >= 0 && visited_versions != NULL)
1052 visited_versions[idx] = 1;
1053 symcrcs[i] = crc;
1054 }
1055
1056 if (visited_versions != NULL) {
1057 /* module_layout/struct_module are not visited, but needed */
1058 ver_off = (const uint8_t *)versions - elf->memory;
1059 for (i = 0; i < vercount; i++) {
1060 if (visited_versions[i] == 0) {
1061 const char *name;
1062 name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1063 slen += strlen(name) + 1;
1064
1065 count++;
1066 }
1067 }
1068 }
1069
1070 if (count == 0) {
1071 free(visited_versions);
1072 free(symcrcs);
Gustavo Sverzut Barbieri599a0322012-01-03 14:53:15 -02001073 *array = NULL;
Gustavo Sverzut Barbieri674f8592011-12-20 11:54:53 -02001074 return 0;
1075 }
1076
1077 *array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
1078 if (*array == NULL) {
1079 free(visited_versions);
1080 free(symcrcs);
1081 return -errno;
1082 }
1083
1084 itr = (char *)(a + count);
1085 count = 0;
1086 str_off = (const uint8_t *)strtab - elf->memory;
1087 sym_off = (const uint8_t *)symtab - elf->memory + symlen;
1088 for (i = 1; i < symcount; i++, sym_off += symlen) {
1089 const char *name;
1090 uint64_t crc;
1091 uint32_t name_off;
1092 uint16_t secidx;
1093 uint8_t info, bind;
1094
1095#define READV(field) \
1096 elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1097 sizeof(s->field))
1098 if (elf->class & KMOD_ELF_32) {
1099 Elf32_Sym *s;
1100 name_off = READV(st_name);
1101 secidx = READV(st_shndx);
1102 info = READV(st_info);
1103 } else {
1104 Elf64_Sym *s;
1105 name_off = READV(st_name);
1106 secidx = READV(st_shndx);
1107 info = READV(st_info);
1108 }
1109#undef READV
1110 if (secidx != SHN_UNDEF)
1111 continue;
1112
1113 if (handle_register_symbols) {
1114 uint8_t type;
1115 if (elf->class & KMOD_ELF_32)
1116 type = ELF32_ST_TYPE(info);
1117 else
1118 type = ELF64_ST_TYPE(info);
1119
1120 /* Not really undefined: sparc gcc 3.3 creates
1121 * U references when you have global asm
1122 * variables, to avoid anyone else misusing
1123 * them.
1124 */
1125 if (type == STT_REGISTER)
1126 continue;
1127 }
1128
1129 name = elf_get_mem(elf, str_off + name_off);
1130 if (name[0] == '\0') {
1131 ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1132 continue;
1133 }
1134
1135 if (elf->class & KMOD_ELF_32)
1136 bind = ELF32_ST_BIND(info);
1137 else
1138 bind = ELF64_ST_BIND(info);
1139 if (bind == STB_WEAK)
1140 bind = KMOD_SYMBOL_WEAK;
1141 else
1142 bind = KMOD_SYMBOL_UNDEF;
1143
1144 slen = strlen(name);
1145 crc = symcrcs[i];
1146
1147 a[count].crc = crc;
1148 a[count].bind = bind;
1149 a[count].symbol = itr;
1150 memcpy(itr, name, slen);
1151 itr[slen] = '\0';
1152 itr += slen + 1;
1153
1154 count++;
1155 }
1156
1157 free(symcrcs);
1158
1159 if (visited_versions == NULL)
1160 return count;
1161
1162 /* add unvisited (module_layout/struct_module) */
1163 ver_off = (const uint8_t *)versions - elf->memory;
1164 for (i = 0; i < vercount; i++) {
1165 const char *name;
1166 uint64_t crc;
1167
1168 if (visited_versions[i] != 0)
1169 continue;
1170
1171 name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1172 slen = strlen(name);
1173 crc = elf_get_uint(elf, ver_off + i * verlen, crclen);
1174
1175 a[count].crc = crc;
1176 a[count].bind = KMOD_SYMBOL_UNDEF;
1177 a[count].symbol = itr;
1178 memcpy(itr, name, slen);
1179 itr[slen] = '\0';
1180 itr += slen + 1;
1181
1182 count++;
1183 }
1184 free(visited_versions);
1185 return count;
1186}