xref: /aosp_15_r20/external/kmod/libkmod/libkmod-elf.c (revision cc4ad7da8cefe208cb129ac2aa9a357c7c72deb2)
1*cc4ad7daSAndroid Build Coastguard Worker /*
2*cc4ad7daSAndroid Build Coastguard Worker  * libkmod - interface to kernel module operations
3*cc4ad7daSAndroid Build Coastguard Worker  *
4*cc4ad7daSAndroid Build Coastguard Worker  * Copyright (C) 2011-2013  ProFUSION embedded systems
5*cc4ad7daSAndroid Build Coastguard Worker  *
6*cc4ad7daSAndroid Build Coastguard Worker  * This library is free software; you can redistribute it and/or
7*cc4ad7daSAndroid Build Coastguard Worker  * modify it under the terms of the GNU Lesser General Public
8*cc4ad7daSAndroid Build Coastguard Worker  * License as published by the Free Software Foundation; either
9*cc4ad7daSAndroid Build Coastguard Worker  * version 2.1 of the License, or (at your option) any later version.
10*cc4ad7daSAndroid Build Coastguard Worker  *
11*cc4ad7daSAndroid Build Coastguard Worker  * This library is distributed in the hope that it will be useful,
12*cc4ad7daSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*cc4ad7daSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*cc4ad7daSAndroid Build Coastguard Worker  * Lesser General Public License for more details.
15*cc4ad7daSAndroid Build Coastguard Worker  *
16*cc4ad7daSAndroid Build Coastguard Worker  * You should have received a copy of the GNU Lesser General Public
17*cc4ad7daSAndroid Build Coastguard Worker  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*cc4ad7daSAndroid Build Coastguard Worker  */
19*cc4ad7daSAndroid Build Coastguard Worker 
20*cc4ad7daSAndroid Build Coastguard Worker #include <assert.h>
21*cc4ad7daSAndroid Build Coastguard Worker #include <elf.h>
22*cc4ad7daSAndroid Build Coastguard Worker #include <errno.h>
23*cc4ad7daSAndroid Build Coastguard Worker #include <stdlib.h>
24*cc4ad7daSAndroid Build Coastguard Worker #include <string.h>
25*cc4ad7daSAndroid Build Coastguard Worker 
26*cc4ad7daSAndroid Build Coastguard Worker #include <shared/util.h>
27*cc4ad7daSAndroid Build Coastguard Worker 
28*cc4ad7daSAndroid Build Coastguard Worker #include "libkmod.h"
29*cc4ad7daSAndroid Build Coastguard Worker #include "libkmod-internal.h"
30*cc4ad7daSAndroid Build Coastguard Worker 
31*cc4ad7daSAndroid Build Coastguard Worker enum kmod_elf_class {
32*cc4ad7daSAndroid Build Coastguard Worker 	KMOD_ELF_32 = (1 << 1),
33*cc4ad7daSAndroid Build Coastguard Worker 	KMOD_ELF_64 = (1 << 2),
34*cc4ad7daSAndroid Build Coastguard Worker 	KMOD_ELF_LSB = (1 << 3),
35*cc4ad7daSAndroid Build Coastguard Worker 	KMOD_ELF_MSB = (1 << 4)
36*cc4ad7daSAndroid Build Coastguard Worker };
37*cc4ad7daSAndroid Build Coastguard Worker 
38*cc4ad7daSAndroid Build Coastguard Worker /* as defined in module-init-tools */
39*cc4ad7daSAndroid Build Coastguard Worker struct kmod_modversion32 {
40*cc4ad7daSAndroid Build Coastguard Worker 	uint32_t crc;
41*cc4ad7daSAndroid Build Coastguard Worker 	char name[64 - sizeof(uint32_t)];
42*cc4ad7daSAndroid Build Coastguard Worker };
43*cc4ad7daSAndroid Build Coastguard Worker 
44*cc4ad7daSAndroid Build Coastguard Worker struct kmod_modversion64 {
45*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t crc;
46*cc4ad7daSAndroid Build Coastguard Worker 	char name[64 - sizeof(uint64_t)];
47*cc4ad7daSAndroid Build Coastguard Worker };
48*cc4ad7daSAndroid Build Coastguard Worker 
49*cc4ad7daSAndroid Build Coastguard Worker struct kmod_elf {
50*cc4ad7daSAndroid Build Coastguard Worker 	const uint8_t *memory;
51*cc4ad7daSAndroid Build Coastguard Worker 	uint8_t *changed;
52*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t size;
53*cc4ad7daSAndroid Build Coastguard Worker 	enum kmod_elf_class class;
54*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_elf_header {
55*cc4ad7daSAndroid Build Coastguard Worker 		struct {
56*cc4ad7daSAndroid Build Coastguard Worker 			uint64_t offset;
57*cc4ad7daSAndroid Build Coastguard Worker 			uint16_t count;
58*cc4ad7daSAndroid Build Coastguard Worker 			uint16_t entry_size;
59*cc4ad7daSAndroid Build Coastguard Worker 		} section;
60*cc4ad7daSAndroid Build Coastguard Worker 		struct {
61*cc4ad7daSAndroid Build Coastguard Worker 			uint16_t section; /* index of the strings section */
62*cc4ad7daSAndroid Build Coastguard Worker 			uint64_t size;
63*cc4ad7daSAndroid Build Coastguard Worker 			uint64_t offset;
64*cc4ad7daSAndroid Build Coastguard Worker 			uint32_t nameoff; /* offset in strings itself */
65*cc4ad7daSAndroid Build Coastguard Worker 		} strings;
66*cc4ad7daSAndroid Build Coastguard Worker 		uint16_t machine;
67*cc4ad7daSAndroid Build Coastguard Worker 	} header;
68*cc4ad7daSAndroid Build Coastguard Worker };
69*cc4ad7daSAndroid Build Coastguard Worker 
70*cc4ad7daSAndroid Build Coastguard Worker //#define ENABLE_ELFDBG 1
71*cc4ad7daSAndroid Build Coastguard Worker 
72*cc4ad7daSAndroid Build Coastguard Worker #if defined(ENABLE_LOGGING) && defined(ENABLE_ELFDBG)
73*cc4ad7daSAndroid Build Coastguard Worker #define ELFDBG(elf, ...)			\
74*cc4ad7daSAndroid Build Coastguard Worker 	_elf_dbg(elf, __FILE__, __LINE__, __func__, __VA_ARGS__);
75*cc4ad7daSAndroid Build Coastguard Worker 
_elf_dbg(const struct kmod_elf * elf,const char * fname,unsigned line,const char * func,const char * fmt,...)76*cc4ad7daSAndroid Build Coastguard Worker static inline void _elf_dbg(const struct kmod_elf *elf, const char *fname, unsigned line, const char *func, const char *fmt, ...)
77*cc4ad7daSAndroid Build Coastguard Worker {
78*cc4ad7daSAndroid Build Coastguard Worker 	va_list args;
79*cc4ad7daSAndroid Build Coastguard Worker 
80*cc4ad7daSAndroid Build Coastguard Worker 	fprintf(stderr, "ELFDBG-%d%c: %s:%u %s() ",
81*cc4ad7daSAndroid Build Coastguard Worker 		(elf->class & KMOD_ELF_32) ? 32 : 64,
82*cc4ad7daSAndroid Build Coastguard Worker 		(elf->class & KMOD_ELF_MSB) ? 'M' : 'L',
83*cc4ad7daSAndroid Build Coastguard Worker 		fname, line, func);
84*cc4ad7daSAndroid Build Coastguard Worker 	va_start(args, fmt);
85*cc4ad7daSAndroid Build Coastguard Worker 	vfprintf(stderr, fmt, args);
86*cc4ad7daSAndroid Build Coastguard Worker 	va_end(args);
87*cc4ad7daSAndroid Build Coastguard Worker }
88*cc4ad7daSAndroid Build Coastguard Worker #else
89*cc4ad7daSAndroid Build Coastguard Worker #define ELFDBG(elf, ...)
90*cc4ad7daSAndroid Build Coastguard Worker #endif
91*cc4ad7daSAndroid Build Coastguard Worker 
92*cc4ad7daSAndroid Build Coastguard Worker 
elf_identify(const void * memory,uint64_t size)93*cc4ad7daSAndroid Build Coastguard Worker static int elf_identify(const void *memory, uint64_t size)
94*cc4ad7daSAndroid Build Coastguard Worker {
95*cc4ad7daSAndroid Build Coastguard Worker 	const uint8_t *p = memory;
96*cc4ad7daSAndroid Build Coastguard Worker 	int class = 0;
97*cc4ad7daSAndroid Build Coastguard Worker 
98*cc4ad7daSAndroid Build Coastguard Worker 	if (size <= EI_NIDENT || memcmp(p, ELFMAG, SELFMAG) != 0)
99*cc4ad7daSAndroid Build Coastguard Worker 		return -ENOEXEC;
100*cc4ad7daSAndroid Build Coastguard Worker 
101*cc4ad7daSAndroid Build Coastguard Worker 	switch (p[EI_CLASS]) {
102*cc4ad7daSAndroid Build Coastguard Worker 	case ELFCLASS32:
103*cc4ad7daSAndroid Build Coastguard Worker 		if (size <= sizeof(Elf32_Ehdr))
104*cc4ad7daSAndroid Build Coastguard Worker 			return -EINVAL;
105*cc4ad7daSAndroid Build Coastguard Worker 		class |= KMOD_ELF_32;
106*cc4ad7daSAndroid Build Coastguard Worker 		break;
107*cc4ad7daSAndroid Build Coastguard Worker 	case ELFCLASS64:
108*cc4ad7daSAndroid Build Coastguard Worker 		if (size <= sizeof(Elf64_Ehdr))
109*cc4ad7daSAndroid Build Coastguard Worker 			return -EINVAL;
110*cc4ad7daSAndroid Build Coastguard Worker 		class |= KMOD_ELF_64;
111*cc4ad7daSAndroid Build Coastguard Worker 		break;
112*cc4ad7daSAndroid Build Coastguard Worker 	default:
113*cc4ad7daSAndroid Build Coastguard Worker 		return -EINVAL;
114*cc4ad7daSAndroid Build Coastguard Worker 	}
115*cc4ad7daSAndroid Build Coastguard Worker 
116*cc4ad7daSAndroid Build Coastguard Worker 	switch (p[EI_DATA]) {
117*cc4ad7daSAndroid Build Coastguard Worker 	case ELFDATA2LSB:
118*cc4ad7daSAndroid Build Coastguard Worker 		class |= KMOD_ELF_LSB;
119*cc4ad7daSAndroid Build Coastguard Worker 		break;
120*cc4ad7daSAndroid Build Coastguard Worker 	case ELFDATA2MSB:
121*cc4ad7daSAndroid Build Coastguard Worker 		class |= KMOD_ELF_MSB;
122*cc4ad7daSAndroid Build Coastguard Worker 		break;
123*cc4ad7daSAndroid Build Coastguard Worker 	default:
124*cc4ad7daSAndroid Build Coastguard Worker 		return -EINVAL;
125*cc4ad7daSAndroid Build Coastguard Worker 	}
126*cc4ad7daSAndroid Build Coastguard Worker 
127*cc4ad7daSAndroid Build Coastguard Worker 	return class;
128*cc4ad7daSAndroid Build Coastguard Worker }
129*cc4ad7daSAndroid Build Coastguard Worker 
elf_get_uint(const struct kmod_elf * elf,uint64_t offset,uint16_t size)130*cc4ad7daSAndroid Build Coastguard Worker static inline uint64_t elf_get_uint(const struct kmod_elf *elf, uint64_t offset, uint16_t size)
131*cc4ad7daSAndroid Build Coastguard Worker {
132*cc4ad7daSAndroid Build Coastguard Worker 	const uint8_t *p;
133*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t ret = 0;
134*cc4ad7daSAndroid Build Coastguard Worker 	size_t i;
135*cc4ad7daSAndroid Build Coastguard Worker 
136*cc4ad7daSAndroid Build Coastguard Worker 	assert(size <= sizeof(uint64_t));
137*cc4ad7daSAndroid Build Coastguard Worker 	assert(offset + size <= elf->size);
138*cc4ad7daSAndroid Build Coastguard Worker 	if (offset + size > elf->size) {
139*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "out of bounds: %"PRIu64" + %"PRIu16" = %"PRIu64"> %"PRIu64" (ELF size)\n",
140*cc4ad7daSAndroid Build Coastguard Worker 		       offset, size, offset + size, elf->size);
141*cc4ad7daSAndroid Build Coastguard Worker 		return (uint64_t)-1;
142*cc4ad7daSAndroid Build Coastguard Worker 	}
143*cc4ad7daSAndroid Build Coastguard Worker 
144*cc4ad7daSAndroid Build Coastguard Worker 	p = elf->memory + offset;
145*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_MSB) {
146*cc4ad7daSAndroid Build Coastguard Worker 		for (i = 0; i < size; i++)
147*cc4ad7daSAndroid Build Coastguard Worker 			ret = (ret << 8) | p[i];
148*cc4ad7daSAndroid Build Coastguard Worker 	} else {
149*cc4ad7daSAndroid Build Coastguard Worker 		for (i = 1; i <= size; i++)
150*cc4ad7daSAndroid Build Coastguard Worker 			ret = (ret << 8) | p[size - i];
151*cc4ad7daSAndroid Build Coastguard Worker 	}
152*cc4ad7daSAndroid Build Coastguard Worker 
153*cc4ad7daSAndroid Build Coastguard Worker 	ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64"\n",
154*cc4ad7daSAndroid Build Coastguard Worker 	       size, offset, ret);
155*cc4ad7daSAndroid Build Coastguard Worker 
156*cc4ad7daSAndroid Build Coastguard Worker 	return ret;
157*cc4ad7daSAndroid Build Coastguard Worker }
158*cc4ad7daSAndroid Build Coastguard Worker 
elf_set_uint(struct kmod_elf * elf,uint64_t offset,uint64_t size,uint64_t value)159*cc4ad7daSAndroid Build Coastguard Worker static inline int elf_set_uint(struct kmod_elf *elf, uint64_t offset, uint64_t size, uint64_t value)
160*cc4ad7daSAndroid Build Coastguard Worker {
161*cc4ad7daSAndroid Build Coastguard Worker 	uint8_t *p;
162*cc4ad7daSAndroid Build Coastguard Worker 	size_t i;
163*cc4ad7daSAndroid Build Coastguard Worker 
164*cc4ad7daSAndroid Build Coastguard Worker 	ELFDBG(elf, "size=%"PRIu16" offset=%"PRIu64" value=%"PRIu64" write memory=%p\n",
165*cc4ad7daSAndroid Build Coastguard Worker 	       size, offset, value, elf->changed);
166*cc4ad7daSAndroid Build Coastguard Worker 
167*cc4ad7daSAndroid Build Coastguard Worker 	assert(size <= sizeof(uint64_t));
168*cc4ad7daSAndroid Build Coastguard Worker 	assert(offset + size <= elf->size);
169*cc4ad7daSAndroid Build Coastguard Worker 	if (offset + size > elf->size) {
170*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "out of bounds: %"PRIu64" + %"PRIu16" = %"PRIu64"> %"PRIu64" (ELF size)\n",
171*cc4ad7daSAndroid Build Coastguard Worker 		       offset, size, offset + size, elf->size);
172*cc4ad7daSAndroid Build Coastguard Worker 		return -1;
173*cc4ad7daSAndroid Build Coastguard Worker 	}
174*cc4ad7daSAndroid Build Coastguard Worker 
175*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->changed == NULL) {
176*cc4ad7daSAndroid Build Coastguard Worker 		elf->changed = malloc(elf->size);
177*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->changed == NULL)
178*cc4ad7daSAndroid Build Coastguard Worker 			return -errno;
179*cc4ad7daSAndroid Build Coastguard Worker 		memcpy(elf->changed, elf->memory, elf->size);
180*cc4ad7daSAndroid Build Coastguard Worker 		elf->memory = elf->changed;
181*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "copied memory to allow writing.\n");
182*cc4ad7daSAndroid Build Coastguard Worker 	}
183*cc4ad7daSAndroid Build Coastguard Worker 
184*cc4ad7daSAndroid Build Coastguard Worker 	p = elf->changed + offset;
185*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_MSB) {
186*cc4ad7daSAndroid Build Coastguard Worker 		for (i = 1; i <= size; i++) {
187*cc4ad7daSAndroid Build Coastguard Worker 			p[size - i] = value & 0xff;
188*cc4ad7daSAndroid Build Coastguard Worker 			value = (value & 0xffffffffffffff00) >> 8;
189*cc4ad7daSAndroid Build Coastguard Worker 		}
190*cc4ad7daSAndroid Build Coastguard Worker 	} else {
191*cc4ad7daSAndroid Build Coastguard Worker 		for (i = 0; i < size; i++) {
192*cc4ad7daSAndroid Build Coastguard Worker 			p[i] = value & 0xff;
193*cc4ad7daSAndroid Build Coastguard Worker 			value = (value & 0xffffffffffffff00) >> 8;
194*cc4ad7daSAndroid Build Coastguard Worker 		}
195*cc4ad7daSAndroid Build Coastguard Worker 	}
196*cc4ad7daSAndroid Build Coastguard Worker 
197*cc4ad7daSAndroid Build Coastguard Worker 	return 0;
198*cc4ad7daSAndroid Build Coastguard Worker }
199*cc4ad7daSAndroid Build Coastguard Worker 
elf_get_mem(const struct kmod_elf * elf,uint64_t offset)200*cc4ad7daSAndroid Build Coastguard Worker static inline const void *elf_get_mem(const struct kmod_elf *elf, uint64_t offset)
201*cc4ad7daSAndroid Build Coastguard Worker {
202*cc4ad7daSAndroid Build Coastguard Worker 	assert(offset < elf->size);
203*cc4ad7daSAndroid Build Coastguard Worker 	if (offset >= elf->size) {
204*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n",
205*cc4ad7daSAndroid Build Coastguard Worker 		       offset, elf->size);
206*cc4ad7daSAndroid Build Coastguard Worker 		return NULL;
207*cc4ad7daSAndroid Build Coastguard Worker 	}
208*cc4ad7daSAndroid Build Coastguard Worker 	return elf->memory + offset;
209*cc4ad7daSAndroid Build Coastguard Worker }
210*cc4ad7daSAndroid Build Coastguard Worker 
elf_get_section_header(const struct kmod_elf * elf,uint16_t idx)211*cc4ad7daSAndroid Build Coastguard Worker static inline const void *elf_get_section_header(const struct kmod_elf *elf, uint16_t idx)
212*cc4ad7daSAndroid Build Coastguard Worker {
213*cc4ad7daSAndroid Build Coastguard Worker 	assert(idx != SHN_UNDEF);
214*cc4ad7daSAndroid Build Coastguard Worker 	assert(idx < elf->header.section.count);
215*cc4ad7daSAndroid Build Coastguard Worker 	if (idx == SHN_UNDEF || idx >= elf->header.section.count) {
216*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "invalid section number: %"PRIu16", last=%"PRIu16"\n",
217*cc4ad7daSAndroid Build Coastguard Worker 		       idx, elf->header.section.count);
218*cc4ad7daSAndroid Build Coastguard Worker 		return NULL;
219*cc4ad7daSAndroid Build Coastguard Worker 	}
220*cc4ad7daSAndroid Build Coastguard Worker 	return elf_get_mem(elf, elf->header.section.offset +
221*cc4ad7daSAndroid Build Coastguard Worker 			   (uint64_t)(idx * elf->header.section.entry_size));
222*cc4ad7daSAndroid Build Coastguard Worker }
223*cc4ad7daSAndroid Build Coastguard Worker 
elf_get_section_info(const struct kmod_elf * elf,uint16_t idx,uint64_t * offset,uint64_t * size,uint32_t * nameoff)224*cc4ad7daSAndroid Build Coastguard Worker static inline int elf_get_section_info(const struct kmod_elf *elf, uint16_t idx, uint64_t *offset, uint64_t *size, uint32_t *nameoff)
225*cc4ad7daSAndroid Build Coastguard Worker {
226*cc4ad7daSAndroid Build Coastguard Worker 	const uint8_t *p = elf_get_section_header(elf, idx);
227*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t min_size, off = p - elf->memory;
228*cc4ad7daSAndroid Build Coastguard Worker 
229*cc4ad7daSAndroid Build Coastguard Worker 	if (p == NULL) {
230*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "no section at %"PRIu16"\n", idx);
231*cc4ad7daSAndroid Build Coastguard Worker 		*offset = 0;
232*cc4ad7daSAndroid Build Coastguard Worker 		*size = 0;
233*cc4ad7daSAndroid Build Coastguard Worker 		*nameoff = 0;
234*cc4ad7daSAndroid Build Coastguard Worker 		return -EINVAL;
235*cc4ad7daSAndroid Build Coastguard Worker 	}
236*cc4ad7daSAndroid Build Coastguard Worker 
237*cc4ad7daSAndroid Build Coastguard Worker #define READV(field) \
238*cc4ad7daSAndroid Build Coastguard Worker 	elf_get_uint(elf, off + offsetof(typeof(*hdr), field), sizeof(hdr->field))
239*cc4ad7daSAndroid Build Coastguard Worker 
240*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_32) {
241*cc4ad7daSAndroid Build Coastguard Worker 		const Elf32_Shdr *hdr _unused_ = (const Elf32_Shdr *)p;
242*cc4ad7daSAndroid Build Coastguard Worker 		*size = READV(sh_size);
243*cc4ad7daSAndroid Build Coastguard Worker 		*offset = READV(sh_offset);
244*cc4ad7daSAndroid Build Coastguard Worker 		*nameoff = READV(sh_name);
245*cc4ad7daSAndroid Build Coastguard Worker 	} else {
246*cc4ad7daSAndroid Build Coastguard Worker 		const Elf64_Shdr *hdr _unused_ = (const Elf64_Shdr *)p;
247*cc4ad7daSAndroid Build Coastguard Worker 		*size = READV(sh_size);
248*cc4ad7daSAndroid Build Coastguard Worker 		*offset = READV(sh_offset);
249*cc4ad7daSAndroid Build Coastguard Worker 		*nameoff = READV(sh_name);
250*cc4ad7daSAndroid Build Coastguard Worker 	}
251*cc4ad7daSAndroid Build Coastguard Worker #undef READV
252*cc4ad7daSAndroid Build Coastguard Worker 
253*cc4ad7daSAndroid Build Coastguard Worker 	if (addu64_overflow(*offset, *size, &min_size)
254*cc4ad7daSAndroid Build Coastguard Worker 	    || min_size > elf->size) {
255*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "out-of-bounds: %"PRIu64" >= %"PRIu64" (ELF size)\n",
256*cc4ad7daSAndroid Build Coastguard Worker 		       min_size, elf->size);
257*cc4ad7daSAndroid Build Coastguard Worker 		return -EINVAL;
258*cc4ad7daSAndroid Build Coastguard Worker 	}
259*cc4ad7daSAndroid Build Coastguard Worker 
260*cc4ad7daSAndroid Build Coastguard Worker 	ELFDBG(elf, "section=%"PRIu16" is: offset=%"PRIu64" size=%"PRIu64" nameoff=%"PRIu32"\n",
261*cc4ad7daSAndroid Build Coastguard Worker 	       idx, *offset, *size, *nameoff);
262*cc4ad7daSAndroid Build Coastguard Worker 
263*cc4ad7daSAndroid Build Coastguard Worker 	return 0;
264*cc4ad7daSAndroid Build Coastguard Worker }
265*cc4ad7daSAndroid Build Coastguard Worker 
elf_get_strings_section(const struct kmod_elf * elf,uint64_t * size)266*cc4ad7daSAndroid Build Coastguard Worker static const char *elf_get_strings_section(const struct kmod_elf *elf, uint64_t *size)
267*cc4ad7daSAndroid Build Coastguard Worker {
268*cc4ad7daSAndroid Build Coastguard Worker 	*size = elf->header.strings.size;
269*cc4ad7daSAndroid Build Coastguard Worker 	return elf_get_mem(elf, elf->header.strings.offset);
270*cc4ad7daSAndroid Build Coastguard Worker }
271*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_new(const void * memory,off_t size)272*cc4ad7daSAndroid Build Coastguard Worker struct kmod_elf *kmod_elf_new(const void *memory, off_t size)
273*cc4ad7daSAndroid Build Coastguard Worker {
274*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_elf *elf;
275*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t min_size;
276*cc4ad7daSAndroid Build Coastguard Worker 	size_t shdrs_size, shdr_size;
277*cc4ad7daSAndroid Build Coastguard Worker 	int class;
278*cc4ad7daSAndroid Build Coastguard Worker 
279*cc4ad7daSAndroid Build Coastguard Worker 	assert_cc(sizeof(uint16_t) == sizeof(Elf32_Half));
280*cc4ad7daSAndroid Build Coastguard Worker 	assert_cc(sizeof(uint16_t) == sizeof(Elf64_Half));
281*cc4ad7daSAndroid Build Coastguard Worker 	assert_cc(sizeof(uint32_t) == sizeof(Elf32_Word));
282*cc4ad7daSAndroid Build Coastguard Worker 	assert_cc(sizeof(uint32_t) == sizeof(Elf64_Word));
283*cc4ad7daSAndroid Build Coastguard Worker 
284*cc4ad7daSAndroid Build Coastguard Worker 	if (!memory) {
285*cc4ad7daSAndroid Build Coastguard Worker 		errno = -EINVAL;
286*cc4ad7daSAndroid Build Coastguard Worker 		return NULL;
287*cc4ad7daSAndroid Build Coastguard Worker 	}
288*cc4ad7daSAndroid Build Coastguard Worker 
289*cc4ad7daSAndroid Build Coastguard Worker 	class = elf_identify(memory, size);
290*cc4ad7daSAndroid Build Coastguard Worker 	if (class < 0) {
291*cc4ad7daSAndroid Build Coastguard Worker 		errno = -class;
292*cc4ad7daSAndroid Build Coastguard Worker 		return NULL;
293*cc4ad7daSAndroid Build Coastguard Worker 	}
294*cc4ad7daSAndroid Build Coastguard Worker 
295*cc4ad7daSAndroid Build Coastguard Worker 	elf = malloc(sizeof(struct kmod_elf));
296*cc4ad7daSAndroid Build Coastguard Worker 	if (elf == NULL) {
297*cc4ad7daSAndroid Build Coastguard Worker 		return NULL;
298*cc4ad7daSAndroid Build Coastguard Worker 	}
299*cc4ad7daSAndroid Build Coastguard Worker 
300*cc4ad7daSAndroid Build Coastguard Worker 	elf->memory = memory;
301*cc4ad7daSAndroid Build Coastguard Worker 	elf->changed = NULL;
302*cc4ad7daSAndroid Build Coastguard Worker 	elf->size = size;
303*cc4ad7daSAndroid Build Coastguard Worker 	elf->class = class;
304*cc4ad7daSAndroid Build Coastguard Worker 
305*cc4ad7daSAndroid Build Coastguard Worker #define READV(field) \
306*cc4ad7daSAndroid Build Coastguard Worker 	elf_get_uint(elf, offsetof(typeof(*hdr), field), sizeof(hdr->field))
307*cc4ad7daSAndroid Build Coastguard Worker 
308*cc4ad7daSAndroid Build Coastguard Worker #define LOAD_HEADER						\
309*cc4ad7daSAndroid Build Coastguard Worker 	elf->header.section.offset = READV(e_shoff);		\
310*cc4ad7daSAndroid Build Coastguard Worker 	elf->header.section.count = READV(e_shnum);		\
311*cc4ad7daSAndroid Build Coastguard Worker 	elf->header.section.entry_size = READV(e_shentsize);	\
312*cc4ad7daSAndroid Build Coastguard Worker 	elf->header.strings.section = READV(e_shstrndx);	\
313*cc4ad7daSAndroid Build Coastguard Worker 	elf->header.machine = READV(e_machine)
314*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_32) {
315*cc4ad7daSAndroid Build Coastguard Worker 		const Elf32_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
316*cc4ad7daSAndroid Build Coastguard Worker 		LOAD_HEADER;
317*cc4ad7daSAndroid Build Coastguard Worker 		shdr_size = sizeof(Elf32_Shdr);
318*cc4ad7daSAndroid Build Coastguard Worker 	} else {
319*cc4ad7daSAndroid Build Coastguard Worker 		const Elf64_Ehdr *hdr _unused_ = elf_get_mem(elf, 0);
320*cc4ad7daSAndroid Build Coastguard Worker 		LOAD_HEADER;
321*cc4ad7daSAndroid Build Coastguard Worker 		shdr_size = sizeof(Elf64_Shdr);
322*cc4ad7daSAndroid Build Coastguard Worker 	}
323*cc4ad7daSAndroid Build Coastguard Worker #undef LOAD_HEADER
324*cc4ad7daSAndroid Build Coastguard Worker #undef READV
325*cc4ad7daSAndroid Build Coastguard Worker 
326*cc4ad7daSAndroid Build Coastguard Worker 	ELFDBG(elf, "section: offset=%"PRIu64" count=%"PRIu16" entry_size=%"PRIu16" strings index=%"PRIu16"\n",
327*cc4ad7daSAndroid Build Coastguard Worker 	       elf->header.section.offset,
328*cc4ad7daSAndroid Build Coastguard Worker 	       elf->header.section.count,
329*cc4ad7daSAndroid Build Coastguard Worker 	       elf->header.section.entry_size,
330*cc4ad7daSAndroid Build Coastguard Worker 	       elf->header.strings.section);
331*cc4ad7daSAndroid Build Coastguard Worker 
332*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->header.section.entry_size != shdr_size) {
333*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "unexpected section entry size: %"PRIu16", expected %"PRIu16"\n",
334*cc4ad7daSAndroid Build Coastguard Worker 		       elf->header.section.entry_size, shdr_size);
335*cc4ad7daSAndroid Build Coastguard Worker 		goto invalid;
336*cc4ad7daSAndroid Build Coastguard Worker 	}
337*cc4ad7daSAndroid Build Coastguard Worker 	shdrs_size = shdr_size * elf->header.section.count;
338*cc4ad7daSAndroid Build Coastguard Worker 	if (addu64_overflow(shdrs_size, elf->header.section.offset, &min_size)
339*cc4ad7daSAndroid Build Coastguard Worker 	    || min_size > elf->size) {
340*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "file is too short to hold sections\n");
341*cc4ad7daSAndroid Build Coastguard Worker 		goto invalid;
342*cc4ad7daSAndroid Build Coastguard Worker 	}
343*cc4ad7daSAndroid Build Coastguard Worker 
344*cc4ad7daSAndroid Build Coastguard Worker 	if (elf_get_section_info(elf, elf->header.strings.section,
345*cc4ad7daSAndroid Build Coastguard Worker 					&elf->header.strings.offset,
346*cc4ad7daSAndroid Build Coastguard Worker 					&elf->header.strings.size,
347*cc4ad7daSAndroid Build Coastguard Worker 					&elf->header.strings.nameoff) < 0) {
348*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "could not get strings section\n");
349*cc4ad7daSAndroid Build Coastguard Worker 		goto invalid;
350*cc4ad7daSAndroid Build Coastguard Worker 	} else {
351*cc4ad7daSAndroid Build Coastguard Worker 		uint64_t slen;
352*cc4ad7daSAndroid Build Coastguard Worker 		const char *s = elf_get_strings_section(elf, &slen);
353*cc4ad7daSAndroid Build Coastguard Worker 		if (slen == 0 || s[slen - 1] != '\0') {
354*cc4ad7daSAndroid Build Coastguard Worker 			ELFDBG(elf, "strings section does not ends with \\0\n");
355*cc4ad7daSAndroid Build Coastguard Worker 			goto invalid;
356*cc4ad7daSAndroid Build Coastguard Worker 		}
357*cc4ad7daSAndroid Build Coastguard Worker 	}
358*cc4ad7daSAndroid Build Coastguard Worker 
359*cc4ad7daSAndroid Build Coastguard Worker 	return elf;
360*cc4ad7daSAndroid Build Coastguard Worker 
361*cc4ad7daSAndroid Build Coastguard Worker invalid:
362*cc4ad7daSAndroid Build Coastguard Worker 	free(elf);
363*cc4ad7daSAndroid Build Coastguard Worker 	errno = EINVAL;
364*cc4ad7daSAndroid Build Coastguard Worker 	return NULL;
365*cc4ad7daSAndroid Build Coastguard Worker }
366*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_unref(struct kmod_elf * elf)367*cc4ad7daSAndroid Build Coastguard Worker void kmod_elf_unref(struct kmod_elf *elf)
368*cc4ad7daSAndroid Build Coastguard Worker {
369*cc4ad7daSAndroid Build Coastguard Worker 	free(elf->changed);
370*cc4ad7daSAndroid Build Coastguard Worker 	free(elf);
371*cc4ad7daSAndroid Build Coastguard Worker }
372*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_get_memory(const struct kmod_elf * elf)373*cc4ad7daSAndroid Build Coastguard Worker const void *kmod_elf_get_memory(const struct kmod_elf *elf)
374*cc4ad7daSAndroid Build Coastguard Worker {
375*cc4ad7daSAndroid Build Coastguard Worker 	return elf->memory;
376*cc4ad7daSAndroid Build Coastguard Worker }
377*cc4ad7daSAndroid Build Coastguard Worker 
elf_find_section(const struct kmod_elf * elf,const char * section)378*cc4ad7daSAndroid Build Coastguard Worker static int elf_find_section(const struct kmod_elf *elf, const char *section)
379*cc4ad7daSAndroid Build Coastguard Worker {
380*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t nameslen;
381*cc4ad7daSAndroid Build Coastguard Worker 	const char *names = elf_get_strings_section(elf, &nameslen);
382*cc4ad7daSAndroid Build Coastguard Worker 	uint16_t i;
383*cc4ad7daSAndroid Build Coastguard Worker 
384*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 1; i < elf->header.section.count; i++) {
385*cc4ad7daSAndroid Build Coastguard Worker 		uint64_t off, size;
386*cc4ad7daSAndroid Build Coastguard Worker 		uint32_t nameoff;
387*cc4ad7daSAndroid Build Coastguard Worker 		const char *n;
388*cc4ad7daSAndroid Build Coastguard Worker 		int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
389*cc4ad7daSAndroid Build Coastguard Worker 		if (err < 0)
390*cc4ad7daSAndroid Build Coastguard Worker 			continue;
391*cc4ad7daSAndroid Build Coastguard Worker 		if (nameoff >= nameslen)
392*cc4ad7daSAndroid Build Coastguard Worker 			continue;
393*cc4ad7daSAndroid Build Coastguard Worker 		n = names + nameoff;
394*cc4ad7daSAndroid Build Coastguard Worker 		if (!streq(section, n))
395*cc4ad7daSAndroid Build Coastguard Worker 			continue;
396*cc4ad7daSAndroid Build Coastguard Worker 
397*cc4ad7daSAndroid Build Coastguard Worker 		return i;
398*cc4ad7daSAndroid Build Coastguard Worker 	}
399*cc4ad7daSAndroid Build Coastguard Worker 
400*cc4ad7daSAndroid Build Coastguard Worker 	return -ENODATA;
401*cc4ad7daSAndroid Build Coastguard Worker }
402*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_get_section(const struct kmod_elf * elf,const char * section,const void ** buf,uint64_t * buf_size)403*cc4ad7daSAndroid Build Coastguard Worker int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, const void **buf, uint64_t *buf_size)
404*cc4ad7daSAndroid Build Coastguard Worker {
405*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t nameslen;
406*cc4ad7daSAndroid Build Coastguard Worker 	const char *names = elf_get_strings_section(elf, &nameslen);
407*cc4ad7daSAndroid Build Coastguard Worker 	uint16_t i;
408*cc4ad7daSAndroid Build Coastguard Worker 
409*cc4ad7daSAndroid Build Coastguard Worker 	*buf = NULL;
410*cc4ad7daSAndroid Build Coastguard Worker 	*buf_size = 0;
411*cc4ad7daSAndroid Build Coastguard Worker 
412*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 1; i < elf->header.section.count; i++) {
413*cc4ad7daSAndroid Build Coastguard Worker 		uint64_t off, size;
414*cc4ad7daSAndroid Build Coastguard Worker 		uint32_t nameoff;
415*cc4ad7daSAndroid Build Coastguard Worker 		const char *n;
416*cc4ad7daSAndroid Build Coastguard Worker 		int err = elf_get_section_info(elf, i, &off, &size, &nameoff);
417*cc4ad7daSAndroid Build Coastguard Worker 		if (err < 0)
418*cc4ad7daSAndroid Build Coastguard Worker 			continue;
419*cc4ad7daSAndroid Build Coastguard Worker 		if (nameoff >= nameslen)
420*cc4ad7daSAndroid Build Coastguard Worker 			continue;
421*cc4ad7daSAndroid Build Coastguard Worker 		n = names + nameoff;
422*cc4ad7daSAndroid Build Coastguard Worker 		if (!streq(section, n))
423*cc4ad7daSAndroid Build Coastguard Worker 			continue;
424*cc4ad7daSAndroid Build Coastguard Worker 
425*cc4ad7daSAndroid Build Coastguard Worker 		*buf = elf_get_mem(elf, off);
426*cc4ad7daSAndroid Build Coastguard Worker 		*buf_size = size;
427*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
428*cc4ad7daSAndroid Build Coastguard Worker 	}
429*cc4ad7daSAndroid Build Coastguard Worker 
430*cc4ad7daSAndroid Build Coastguard Worker 	return -ENODATA;
431*cc4ad7daSAndroid Build Coastguard Worker }
432*cc4ad7daSAndroid Build Coastguard Worker 
433*cc4ad7daSAndroid Build Coastguard Worker /* array will be allocated with strings in a single malloc, just free *array */
kmod_elf_get_strings(const struct kmod_elf * elf,const char * section,char *** array)434*cc4ad7daSAndroid Build Coastguard Worker int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array)
435*cc4ad7daSAndroid Build Coastguard Worker {
436*cc4ad7daSAndroid Build Coastguard Worker 	size_t i, j, count;
437*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t size;
438*cc4ad7daSAndroid Build Coastguard Worker 	const void *buf;
439*cc4ad7daSAndroid Build Coastguard Worker 	const char *strings;
440*cc4ad7daSAndroid Build Coastguard Worker 	char *s, **a;
441*cc4ad7daSAndroid Build Coastguard Worker 	int err;
442*cc4ad7daSAndroid Build Coastguard Worker 
443*cc4ad7daSAndroid Build Coastguard Worker 	*array = NULL;
444*cc4ad7daSAndroid Build Coastguard Worker 
445*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, section, &buf, &size);
446*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0)
447*cc4ad7daSAndroid Build Coastguard Worker 		return err;
448*cc4ad7daSAndroid Build Coastguard Worker 
449*cc4ad7daSAndroid Build Coastguard Worker 	strings = buf;
450*cc4ad7daSAndroid Build Coastguard Worker 	if (strings == NULL || size == 0)
451*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
452*cc4ad7daSAndroid Build Coastguard Worker 
453*cc4ad7daSAndroid Build Coastguard Worker 	/* skip zero padding */
454*cc4ad7daSAndroid Build Coastguard Worker 	while (strings[0] == '\0' && size > 1) {
455*cc4ad7daSAndroid Build Coastguard Worker 		strings++;
456*cc4ad7daSAndroid Build Coastguard Worker 		size--;
457*cc4ad7daSAndroid Build Coastguard Worker 	}
458*cc4ad7daSAndroid Build Coastguard Worker 
459*cc4ad7daSAndroid Build Coastguard Worker 	if (size <= 1)
460*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
461*cc4ad7daSAndroid Build Coastguard Worker 
462*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0, count = 0; i < size; ) {
463*cc4ad7daSAndroid Build Coastguard Worker 		if (strings[i] != '\0') {
464*cc4ad7daSAndroid Build Coastguard Worker 			i++;
465*cc4ad7daSAndroid Build Coastguard Worker 			continue;
466*cc4ad7daSAndroid Build Coastguard Worker 		}
467*cc4ad7daSAndroid Build Coastguard Worker 
468*cc4ad7daSAndroid Build Coastguard Worker 		while (strings[i] == '\0' && i < size)
469*cc4ad7daSAndroid Build Coastguard Worker 			i++;
470*cc4ad7daSAndroid Build Coastguard Worker 
471*cc4ad7daSAndroid Build Coastguard Worker 		count++;
472*cc4ad7daSAndroid Build Coastguard Worker 	}
473*cc4ad7daSAndroid Build Coastguard Worker 
474*cc4ad7daSAndroid Build Coastguard Worker 	if (strings[i - 1] != '\0')
475*cc4ad7daSAndroid Build Coastguard Worker 		count++;
476*cc4ad7daSAndroid Build Coastguard Worker 
477*cc4ad7daSAndroid Build Coastguard Worker 	*array = a = malloc(size + 1 + sizeof(char *) * (count + 1));
478*cc4ad7daSAndroid Build Coastguard Worker 	if (*array == NULL)
479*cc4ad7daSAndroid Build Coastguard Worker 		return -errno;
480*cc4ad7daSAndroid Build Coastguard Worker 
481*cc4ad7daSAndroid Build Coastguard Worker 	s = (char *)(a + count + 1);
482*cc4ad7daSAndroid Build Coastguard Worker 	memcpy(s, strings, size);
483*cc4ad7daSAndroid Build Coastguard Worker 
484*cc4ad7daSAndroid Build Coastguard Worker 	/* make sure the last string is NULL-terminated */
485*cc4ad7daSAndroid Build Coastguard Worker 	s[size] = '\0';
486*cc4ad7daSAndroid Build Coastguard Worker 	a[count] = NULL;
487*cc4ad7daSAndroid Build Coastguard Worker 	a[0] = s;
488*cc4ad7daSAndroid Build Coastguard Worker 
489*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0, j = 1; j < count && i < size; ) {
490*cc4ad7daSAndroid Build Coastguard Worker 		if (s[i] != '\0') {
491*cc4ad7daSAndroid Build Coastguard Worker 			i++;
492*cc4ad7daSAndroid Build Coastguard Worker 			continue;
493*cc4ad7daSAndroid Build Coastguard Worker 		}
494*cc4ad7daSAndroid Build Coastguard Worker 
495*cc4ad7daSAndroid Build Coastguard Worker 		while (strings[i] == '\0' && i < size)
496*cc4ad7daSAndroid Build Coastguard Worker 			i++;
497*cc4ad7daSAndroid Build Coastguard Worker 
498*cc4ad7daSAndroid Build Coastguard Worker 		a[j] = &s[i];
499*cc4ad7daSAndroid Build Coastguard Worker 		j++;
500*cc4ad7daSAndroid Build Coastguard Worker 	}
501*cc4ad7daSAndroid Build Coastguard Worker 
502*cc4ad7daSAndroid Build Coastguard Worker 	return count;
503*cc4ad7daSAndroid Build Coastguard Worker }
504*cc4ad7daSAndroid Build Coastguard Worker 
505*cc4ad7daSAndroid Build Coastguard Worker /* array will be allocated with strings in a single malloc, just free *array */
kmod_elf_get_modversions(const struct kmod_elf * elf,struct kmod_modversion ** array)506*cc4ad7daSAndroid Build Coastguard Worker int kmod_elf_get_modversions(const struct kmod_elf *elf, struct kmod_modversion **array)
507*cc4ad7daSAndroid Build Coastguard Worker {
508*cc4ad7daSAndroid Build Coastguard Worker 	size_t off, offcrc, slen;
509*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t size;
510*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_modversion *a;
511*cc4ad7daSAndroid Build Coastguard Worker 	const void *buf;
512*cc4ad7daSAndroid Build Coastguard Worker 	char *itr;
513*cc4ad7daSAndroid Build Coastguard Worker 	int i, count, err;
514*cc4ad7daSAndroid Build Coastguard Worker #define MODVERSION_SEC_SIZE (sizeof(struct kmod_modversion64))
515*cc4ad7daSAndroid Build Coastguard Worker 
516*cc4ad7daSAndroid Build Coastguard Worker 	assert_cc(sizeof(struct kmod_modversion64) ==
517*cc4ad7daSAndroid Build Coastguard Worker 					sizeof(struct kmod_modversion32));
518*cc4ad7daSAndroid Build Coastguard Worker 
519*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_32)
520*cc4ad7daSAndroid Build Coastguard Worker 		offcrc = sizeof(uint32_t);
521*cc4ad7daSAndroid Build Coastguard Worker 	else
522*cc4ad7daSAndroid Build Coastguard Worker 		offcrc = sizeof(uint64_t);
523*cc4ad7daSAndroid Build Coastguard Worker 
524*cc4ad7daSAndroid Build Coastguard Worker 	*array = NULL;
525*cc4ad7daSAndroid Build Coastguard Worker 
526*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, "__versions", &buf, &size);
527*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0)
528*cc4ad7daSAndroid Build Coastguard Worker 		return err;
529*cc4ad7daSAndroid Build Coastguard Worker 
530*cc4ad7daSAndroid Build Coastguard Worker 	if (buf == NULL || size == 0)
531*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
532*cc4ad7daSAndroid Build Coastguard Worker 
533*cc4ad7daSAndroid Build Coastguard Worker 	if (size % MODVERSION_SEC_SIZE != 0)
534*cc4ad7daSAndroid Build Coastguard Worker 		return -EINVAL;
535*cc4ad7daSAndroid Build Coastguard Worker 
536*cc4ad7daSAndroid Build Coastguard Worker 	count = size / MODVERSION_SEC_SIZE;
537*cc4ad7daSAndroid Build Coastguard Worker 
538*cc4ad7daSAndroid Build Coastguard Worker 	off = (const uint8_t *)buf - elf->memory;
539*cc4ad7daSAndroid Build Coastguard Worker 	slen = 0;
540*cc4ad7daSAndroid Build Coastguard Worker 
541*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
542*cc4ad7daSAndroid Build Coastguard Worker 		const char *symbol = elf_get_mem(elf, off + offcrc);
543*cc4ad7daSAndroid Build Coastguard Worker 
544*cc4ad7daSAndroid Build Coastguard Worker 		if (symbol[0] == '.')
545*cc4ad7daSAndroid Build Coastguard Worker 			symbol++;
546*cc4ad7daSAndroid Build Coastguard Worker 
547*cc4ad7daSAndroid Build Coastguard Worker 		slen += strlen(symbol) + 1;
548*cc4ad7daSAndroid Build Coastguard Worker 	}
549*cc4ad7daSAndroid Build Coastguard Worker 
550*cc4ad7daSAndroid Build Coastguard Worker 	*array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
551*cc4ad7daSAndroid Build Coastguard Worker 	if (*array == NULL)
552*cc4ad7daSAndroid Build Coastguard Worker 		return -errno;
553*cc4ad7daSAndroid Build Coastguard Worker 
554*cc4ad7daSAndroid Build Coastguard Worker 	itr = (char *)(a + count);
555*cc4ad7daSAndroid Build Coastguard Worker 	off = (const uint8_t *)buf - elf->memory;
556*cc4ad7daSAndroid Build Coastguard Worker 
557*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0; i < count; i++, off += MODVERSION_SEC_SIZE) {
558*cc4ad7daSAndroid Build Coastguard Worker 		uint64_t crc = elf_get_uint(elf, off, offcrc);
559*cc4ad7daSAndroid Build Coastguard Worker 		const char *symbol = elf_get_mem(elf, off + offcrc);
560*cc4ad7daSAndroid Build Coastguard Worker 		size_t symbollen;
561*cc4ad7daSAndroid Build Coastguard Worker 
562*cc4ad7daSAndroid Build Coastguard Worker 		if (symbol[0] == '.')
563*cc4ad7daSAndroid Build Coastguard Worker 			symbol++;
564*cc4ad7daSAndroid Build Coastguard Worker 
565*cc4ad7daSAndroid Build Coastguard Worker 		a[i].crc = crc;
566*cc4ad7daSAndroid Build Coastguard Worker 		a[i].bind = KMOD_SYMBOL_UNDEF;
567*cc4ad7daSAndroid Build Coastguard Worker 		a[i].symbol = itr;
568*cc4ad7daSAndroid Build Coastguard Worker 		symbollen = strlen(symbol) + 1;
569*cc4ad7daSAndroid Build Coastguard Worker 		memcpy(itr, symbol, symbollen);
570*cc4ad7daSAndroid Build Coastguard Worker 		itr += symbollen;
571*cc4ad7daSAndroid Build Coastguard Worker 	}
572*cc4ad7daSAndroid Build Coastguard Worker 
573*cc4ad7daSAndroid Build Coastguard Worker 	return count;
574*cc4ad7daSAndroid Build Coastguard Worker }
575*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_strip_section(struct kmod_elf * elf,const char * section)576*cc4ad7daSAndroid Build Coastguard Worker int kmod_elf_strip_section(struct kmod_elf *elf, const char *section)
577*cc4ad7daSAndroid Build Coastguard Worker {
578*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t off, size;
579*cc4ad7daSAndroid Build Coastguard Worker 	const void *buf;
580*cc4ad7daSAndroid Build Coastguard Worker 	int idx = elf_find_section(elf, section);
581*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t val;
582*cc4ad7daSAndroid Build Coastguard Worker 
583*cc4ad7daSAndroid Build Coastguard Worker 	if (idx < 0)
584*cc4ad7daSAndroid Build Coastguard Worker 		return idx;
585*cc4ad7daSAndroid Build Coastguard Worker 
586*cc4ad7daSAndroid Build Coastguard Worker 	buf = elf_get_section_header(elf, idx);
587*cc4ad7daSAndroid Build Coastguard Worker 	off = (const uint8_t *)buf - elf->memory;
588*cc4ad7daSAndroid Build Coastguard Worker 
589*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_32) {
590*cc4ad7daSAndroid Build Coastguard Worker 		off += offsetof(Elf32_Shdr, sh_flags);
591*cc4ad7daSAndroid Build Coastguard Worker 		size = sizeof(((Elf32_Shdr *)buf)->sh_flags);
592*cc4ad7daSAndroid Build Coastguard Worker 	} else {
593*cc4ad7daSAndroid Build Coastguard Worker 		off += offsetof(Elf64_Shdr, sh_flags);
594*cc4ad7daSAndroid Build Coastguard Worker 		size = sizeof(((Elf64_Shdr *)buf)->sh_flags);
595*cc4ad7daSAndroid Build Coastguard Worker 	}
596*cc4ad7daSAndroid Build Coastguard Worker 
597*cc4ad7daSAndroid Build Coastguard Worker 	val = elf_get_uint(elf, off, size);
598*cc4ad7daSAndroid Build Coastguard Worker 	val &= ~(uint64_t)SHF_ALLOC;
599*cc4ad7daSAndroid Build Coastguard Worker 
600*cc4ad7daSAndroid Build Coastguard Worker 	return elf_set_uint(elf, off, size, val);
601*cc4ad7daSAndroid Build Coastguard Worker }
602*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_strip_vermagic(struct kmod_elf * elf)603*cc4ad7daSAndroid Build Coastguard Worker int kmod_elf_strip_vermagic(struct kmod_elf *elf)
604*cc4ad7daSAndroid Build Coastguard Worker {
605*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t i, size;
606*cc4ad7daSAndroid Build Coastguard Worker 	const void *buf;
607*cc4ad7daSAndroid Build Coastguard Worker 	const char *strings;
608*cc4ad7daSAndroid Build Coastguard Worker 	int err;
609*cc4ad7daSAndroid Build Coastguard Worker 
610*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, ".modinfo", &buf, &size);
611*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0)
612*cc4ad7daSAndroid Build Coastguard Worker 		return err;
613*cc4ad7daSAndroid Build Coastguard Worker 	strings = buf;
614*cc4ad7daSAndroid Build Coastguard Worker 	if (strings == NULL || size == 0)
615*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
616*cc4ad7daSAndroid Build Coastguard Worker 
617*cc4ad7daSAndroid Build Coastguard Worker 	/* skip zero padding */
618*cc4ad7daSAndroid Build Coastguard Worker 	while (strings[0] == '\0' && size > 1) {
619*cc4ad7daSAndroid Build Coastguard Worker 		strings++;
620*cc4ad7daSAndroid Build Coastguard Worker 		size--;
621*cc4ad7daSAndroid Build Coastguard Worker 	}
622*cc4ad7daSAndroid Build Coastguard Worker 	if (size <= 1)
623*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
624*cc4ad7daSAndroid Build Coastguard Worker 
625*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0; i < size; i++) {
626*cc4ad7daSAndroid Build Coastguard Worker 		const char *s;
627*cc4ad7daSAndroid Build Coastguard Worker 		size_t off, len;
628*cc4ad7daSAndroid Build Coastguard Worker 
629*cc4ad7daSAndroid Build Coastguard Worker 		if (strings[i] == '\0')
630*cc4ad7daSAndroid Build Coastguard Worker 			continue;
631*cc4ad7daSAndroid Build Coastguard Worker 		if (i + 1 >= size)
632*cc4ad7daSAndroid Build Coastguard Worker 			continue;
633*cc4ad7daSAndroid Build Coastguard Worker 
634*cc4ad7daSAndroid Build Coastguard Worker 		s = strings + i;
635*cc4ad7daSAndroid Build Coastguard Worker 		len = sizeof("vermagic=") - 1;
636*cc4ad7daSAndroid Build Coastguard Worker 		if (i + len >= size)
637*cc4ad7daSAndroid Build Coastguard Worker 			continue;
638*cc4ad7daSAndroid Build Coastguard Worker 		if (strncmp(s, "vermagic=", len) != 0) {
639*cc4ad7daSAndroid Build Coastguard Worker 			i += strlen(s);
640*cc4ad7daSAndroid Build Coastguard Worker 			continue;
641*cc4ad7daSAndroid Build Coastguard Worker 		}
642*cc4ad7daSAndroid Build Coastguard Worker 		off = (const uint8_t *)s - elf->memory;
643*cc4ad7daSAndroid Build Coastguard Worker 
644*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->changed == NULL) {
645*cc4ad7daSAndroid Build Coastguard Worker 			elf->changed = malloc(elf->size);
646*cc4ad7daSAndroid Build Coastguard Worker 			if (elf->changed == NULL)
647*cc4ad7daSAndroid Build Coastguard Worker 				return -errno;
648*cc4ad7daSAndroid Build Coastguard Worker 			memcpy(elf->changed, elf->memory, elf->size);
649*cc4ad7daSAndroid Build Coastguard Worker 			elf->memory = elf->changed;
650*cc4ad7daSAndroid Build Coastguard Worker 			ELFDBG(elf, "copied memory to allow writing.\n");
651*cc4ad7daSAndroid Build Coastguard Worker 		}
652*cc4ad7daSAndroid Build Coastguard Worker 
653*cc4ad7daSAndroid Build Coastguard Worker 		len = strlen(s);
654*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "clear .modinfo vermagic \"%s\" (%zd bytes)\n",
655*cc4ad7daSAndroid Build Coastguard Worker 		       s, len);
656*cc4ad7daSAndroid Build Coastguard Worker 		memset(elf->changed + off, '\0', len);
657*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
658*cc4ad7daSAndroid Build Coastguard Worker 	}
659*cc4ad7daSAndroid Build Coastguard Worker 
660*cc4ad7daSAndroid Build Coastguard Worker 	ELFDBG(elf, "no vermagic found in .modinfo\n");
661*cc4ad7daSAndroid Build Coastguard Worker 	return -ENODATA;
662*cc4ad7daSAndroid Build Coastguard Worker }
663*cc4ad7daSAndroid Build Coastguard Worker 
664*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_get_symbols_symtab(const struct kmod_elf * elf,struct kmod_modversion ** array)665*cc4ad7daSAndroid Build Coastguard Worker static int kmod_elf_get_symbols_symtab(const struct kmod_elf *elf, struct kmod_modversion **array)
666*cc4ad7daSAndroid Build Coastguard Worker {
667*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t i, last, size;
668*cc4ad7daSAndroid Build Coastguard Worker 	const void *buf;
669*cc4ad7daSAndroid Build Coastguard Worker 	const char *strings;
670*cc4ad7daSAndroid Build Coastguard Worker 	char *itr;
671*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_modversion *a;
672*cc4ad7daSAndroid Build Coastguard Worker 	int count, err;
673*cc4ad7daSAndroid Build Coastguard Worker 
674*cc4ad7daSAndroid Build Coastguard Worker 	*array = NULL;
675*cc4ad7daSAndroid Build Coastguard Worker 
676*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, "__ksymtab_strings", &buf, &size);
677*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0)
678*cc4ad7daSAndroid Build Coastguard Worker 		return err;
679*cc4ad7daSAndroid Build Coastguard Worker 	strings = buf;
680*cc4ad7daSAndroid Build Coastguard Worker 	if (strings == NULL || size == 0)
681*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
682*cc4ad7daSAndroid Build Coastguard Worker 
683*cc4ad7daSAndroid Build Coastguard Worker 	/* skip zero padding */
684*cc4ad7daSAndroid Build Coastguard Worker 	while (strings[0] == '\0' && size > 1) {
685*cc4ad7daSAndroid Build Coastguard Worker 		strings++;
686*cc4ad7daSAndroid Build Coastguard Worker 		size--;
687*cc4ad7daSAndroid Build Coastguard Worker 	}
688*cc4ad7daSAndroid Build Coastguard Worker 	if (size <= 1)
689*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
690*cc4ad7daSAndroid Build Coastguard Worker 
691*cc4ad7daSAndroid Build Coastguard Worker 	last = 0;
692*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0, count = 0; i < size; i++) {
693*cc4ad7daSAndroid Build Coastguard Worker 		if (strings[i] == '\0') {
694*cc4ad7daSAndroid Build Coastguard Worker 			if (last == i) {
695*cc4ad7daSAndroid Build Coastguard Worker 				last = i + 1;
696*cc4ad7daSAndroid Build Coastguard Worker 				continue;
697*cc4ad7daSAndroid Build Coastguard Worker 			}
698*cc4ad7daSAndroid Build Coastguard Worker 			count++;
699*cc4ad7daSAndroid Build Coastguard Worker 			last = i + 1;
700*cc4ad7daSAndroid Build Coastguard Worker 		}
701*cc4ad7daSAndroid Build Coastguard Worker 	}
702*cc4ad7daSAndroid Build Coastguard Worker 	if (strings[i - 1] != '\0')
703*cc4ad7daSAndroid Build Coastguard Worker 		count++;
704*cc4ad7daSAndroid Build Coastguard Worker 
705*cc4ad7daSAndroid Build Coastguard Worker 	*array = a = malloc(size + 1 + sizeof(struct kmod_modversion) * count);
706*cc4ad7daSAndroid Build Coastguard Worker 	if (*array == NULL)
707*cc4ad7daSAndroid Build Coastguard Worker 		return -errno;
708*cc4ad7daSAndroid Build Coastguard Worker 
709*cc4ad7daSAndroid Build Coastguard Worker 	itr = (char *)(a + count);
710*cc4ad7daSAndroid Build Coastguard Worker 	last = 0;
711*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0, count = 0; i < size; i++) {
712*cc4ad7daSAndroid Build Coastguard Worker 		if (strings[i] == '\0') {
713*cc4ad7daSAndroid Build Coastguard Worker 			size_t slen = i - last;
714*cc4ad7daSAndroid Build Coastguard Worker 			if (last == i) {
715*cc4ad7daSAndroid Build Coastguard Worker 				last = i + 1;
716*cc4ad7daSAndroid Build Coastguard Worker 				continue;
717*cc4ad7daSAndroid Build Coastguard Worker 			}
718*cc4ad7daSAndroid Build Coastguard Worker 			a[count].crc = 0;
719*cc4ad7daSAndroid Build Coastguard Worker 			a[count].bind = KMOD_SYMBOL_GLOBAL;
720*cc4ad7daSAndroid Build Coastguard Worker 			a[count].symbol = itr;
721*cc4ad7daSAndroid Build Coastguard Worker 			memcpy(itr, strings + last, slen);
722*cc4ad7daSAndroid Build Coastguard Worker 			itr[slen] = '\0';
723*cc4ad7daSAndroid Build Coastguard Worker 			itr += slen + 1;
724*cc4ad7daSAndroid Build Coastguard Worker 			count++;
725*cc4ad7daSAndroid Build Coastguard Worker 			last = i + 1;
726*cc4ad7daSAndroid Build Coastguard Worker 		}
727*cc4ad7daSAndroid Build Coastguard Worker 	}
728*cc4ad7daSAndroid Build Coastguard Worker 	if (strings[i - 1] != '\0') {
729*cc4ad7daSAndroid Build Coastguard Worker 		size_t slen = i - last;
730*cc4ad7daSAndroid Build Coastguard Worker 		a[count].crc = 0;
731*cc4ad7daSAndroid Build Coastguard Worker 		a[count].bind = KMOD_SYMBOL_GLOBAL;
732*cc4ad7daSAndroid Build Coastguard Worker 		a[count].symbol = itr;
733*cc4ad7daSAndroid Build Coastguard Worker 		memcpy(itr, strings + last, slen);
734*cc4ad7daSAndroid Build Coastguard Worker 		itr[slen] = '\0';
735*cc4ad7daSAndroid Build Coastguard Worker 		count++;
736*cc4ad7daSAndroid Build Coastguard Worker 	}
737*cc4ad7daSAndroid Build Coastguard Worker 
738*cc4ad7daSAndroid Build Coastguard Worker 	return count;
739*cc4ad7daSAndroid Build Coastguard Worker }
740*cc4ad7daSAndroid Build Coastguard Worker 
kmod_symbol_bind_from_elf(uint8_t elf_value)741*cc4ad7daSAndroid Build Coastguard Worker static inline uint8_t kmod_symbol_bind_from_elf(uint8_t elf_value)
742*cc4ad7daSAndroid Build Coastguard Worker {
743*cc4ad7daSAndroid Build Coastguard Worker 	switch (elf_value) {
744*cc4ad7daSAndroid Build Coastguard Worker 	case STB_LOCAL:
745*cc4ad7daSAndroid Build Coastguard Worker 		return KMOD_SYMBOL_LOCAL;
746*cc4ad7daSAndroid Build Coastguard Worker 	case STB_GLOBAL:
747*cc4ad7daSAndroid Build Coastguard Worker 		return KMOD_SYMBOL_GLOBAL;
748*cc4ad7daSAndroid Build Coastguard Worker 	case STB_WEAK:
749*cc4ad7daSAndroid Build Coastguard Worker 		return KMOD_SYMBOL_WEAK;
750*cc4ad7daSAndroid Build Coastguard Worker 	default:
751*cc4ad7daSAndroid Build Coastguard Worker 		return KMOD_SYMBOL_NONE;
752*cc4ad7daSAndroid Build Coastguard Worker 	}
753*cc4ad7daSAndroid Build Coastguard Worker }
754*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_resolve_crc(const struct kmod_elf * elf,uint64_t crc,uint16_t shndx)755*cc4ad7daSAndroid Build Coastguard Worker static uint64_t kmod_elf_resolve_crc(const struct kmod_elf *elf, uint64_t crc, uint16_t shndx)
756*cc4ad7daSAndroid Build Coastguard Worker {
757*cc4ad7daSAndroid Build Coastguard Worker 	int err;
758*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t off, size;
759*cc4ad7daSAndroid Build Coastguard Worker 	uint32_t nameoff;
760*cc4ad7daSAndroid Build Coastguard Worker 
761*cc4ad7daSAndroid Build Coastguard Worker 	if (shndx == SHN_ABS || shndx == SHN_UNDEF)
762*cc4ad7daSAndroid Build Coastguard Worker 		return crc;
763*cc4ad7daSAndroid Build Coastguard Worker 
764*cc4ad7daSAndroid Build Coastguard Worker 	err = elf_get_section_info(elf, shndx, &off, &size, &nameoff);
765*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0) {
766*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG("Cound not find section index %"PRIu16" for crc", shndx);
767*cc4ad7daSAndroid Build Coastguard Worker 		return (uint64_t)-1;
768*cc4ad7daSAndroid Build Coastguard Worker 	}
769*cc4ad7daSAndroid Build Coastguard Worker 
770*cc4ad7daSAndroid Build Coastguard Worker 	if (crc > (size - sizeof(uint32_t))) {
771*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG("CRC offset %"PRIu64" is too big, section %"PRIu16" size is %"PRIu64"\n",
772*cc4ad7daSAndroid Build Coastguard Worker 		       crc, shndx, size);
773*cc4ad7daSAndroid Build Coastguard Worker 		return (uint64_t)-1;
774*cc4ad7daSAndroid Build Coastguard Worker 	}
775*cc4ad7daSAndroid Build Coastguard Worker 
776*cc4ad7daSAndroid Build Coastguard Worker 	crc = elf_get_uint(elf, off + crc, sizeof(uint32_t));
777*cc4ad7daSAndroid Build Coastguard Worker 	return crc;
778*cc4ad7daSAndroid Build Coastguard Worker }
779*cc4ad7daSAndroid Build Coastguard Worker 
780*cc4ad7daSAndroid Build Coastguard Worker /* array will be allocated with strings in a single malloc, just free *array */
kmod_elf_get_symbols(const struct kmod_elf * elf,struct kmod_modversion ** array)781*cc4ad7daSAndroid Build Coastguard Worker int kmod_elf_get_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
782*cc4ad7daSAndroid Build Coastguard Worker {
783*cc4ad7daSAndroid Build Coastguard Worker 	static const char crc_str[] = "__crc_";
784*cc4ad7daSAndroid Build Coastguard Worker 	static const size_t crc_strlen = sizeof(crc_str) - 1;
785*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t strtablen, symtablen, str_off, sym_off;
786*cc4ad7daSAndroid Build Coastguard Worker 	const void *strtab, *symtab;
787*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_modversion *a;
788*cc4ad7daSAndroid Build Coastguard Worker 	char *itr;
789*cc4ad7daSAndroid Build Coastguard Worker 	size_t slen, symlen;
790*cc4ad7daSAndroid Build Coastguard Worker 	int i, count, symcount, err;
791*cc4ad7daSAndroid Build Coastguard Worker 
792*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
793*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0) {
794*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "no .strtab found.\n");
795*cc4ad7daSAndroid Build Coastguard Worker 		goto fallback;
796*cc4ad7daSAndroid Build Coastguard Worker 	}
797*cc4ad7daSAndroid Build Coastguard Worker 
798*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
799*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0) {
800*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "no .symtab found.\n");
801*cc4ad7daSAndroid Build Coastguard Worker 		goto fallback;
802*cc4ad7daSAndroid Build Coastguard Worker 	}
803*cc4ad7daSAndroid Build Coastguard Worker 
804*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_32)
805*cc4ad7daSAndroid Build Coastguard Worker 		symlen = sizeof(Elf32_Sym);
806*cc4ad7daSAndroid Build Coastguard Worker 	else
807*cc4ad7daSAndroid Build Coastguard Worker 		symlen = sizeof(Elf64_Sym);
808*cc4ad7daSAndroid Build Coastguard Worker 
809*cc4ad7daSAndroid Build Coastguard Worker 	if (symtablen % symlen != 0) {
810*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
811*cc4ad7daSAndroid Build Coastguard Worker 		goto fallback;
812*cc4ad7daSAndroid Build Coastguard Worker 	}
813*cc4ad7daSAndroid Build Coastguard Worker 
814*cc4ad7daSAndroid Build Coastguard Worker 	symcount = symtablen / symlen;
815*cc4ad7daSAndroid Build Coastguard Worker 	count = 0;
816*cc4ad7daSAndroid Build Coastguard Worker 	slen = 0;
817*cc4ad7daSAndroid Build Coastguard Worker 	str_off = (const uint8_t *)strtab - elf->memory;
818*cc4ad7daSAndroid Build Coastguard Worker 	sym_off = (const uint8_t *)symtab - elf->memory + symlen;
819*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 1; i < symcount; i++, sym_off += symlen) {
820*cc4ad7daSAndroid Build Coastguard Worker 		const char *name;
821*cc4ad7daSAndroid Build Coastguard Worker 		uint32_t name_off;
822*cc4ad7daSAndroid Build Coastguard Worker 
823*cc4ad7daSAndroid Build Coastguard Worker #define READV(field)							\
824*cc4ad7daSAndroid Build Coastguard Worker 		elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
825*cc4ad7daSAndroid Build Coastguard Worker 			     sizeof(s->field))
826*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->class & KMOD_ELF_32) {
827*cc4ad7daSAndroid Build Coastguard Worker 			Elf32_Sym *s;
828*cc4ad7daSAndroid Build Coastguard Worker 			name_off = READV(st_name);
829*cc4ad7daSAndroid Build Coastguard Worker 		} else {
830*cc4ad7daSAndroid Build Coastguard Worker 			Elf64_Sym *s;
831*cc4ad7daSAndroid Build Coastguard Worker 			name_off = READV(st_name);
832*cc4ad7daSAndroid Build Coastguard Worker 		}
833*cc4ad7daSAndroid Build Coastguard Worker #undef READV
834*cc4ad7daSAndroid Build Coastguard Worker 		if (name_off >= strtablen) {
835*cc4ad7daSAndroid Build Coastguard Worker 			ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
836*cc4ad7daSAndroid Build Coastguard Worker 			goto fallback;
837*cc4ad7daSAndroid Build Coastguard Worker 		}
838*cc4ad7daSAndroid Build Coastguard Worker 
839*cc4ad7daSAndroid Build Coastguard Worker 		name = elf_get_mem(elf, str_off + name_off);
840*cc4ad7daSAndroid Build Coastguard Worker 
841*cc4ad7daSAndroid Build Coastguard Worker 		if (strncmp(name, crc_str, crc_strlen) != 0)
842*cc4ad7daSAndroid Build Coastguard Worker 			continue;
843*cc4ad7daSAndroid Build Coastguard Worker 		slen += strlen(name + crc_strlen) + 1;
844*cc4ad7daSAndroid Build Coastguard Worker 		count++;
845*cc4ad7daSAndroid Build Coastguard Worker 	}
846*cc4ad7daSAndroid Build Coastguard Worker 
847*cc4ad7daSAndroid Build Coastguard Worker 	if (count == 0)
848*cc4ad7daSAndroid Build Coastguard Worker 		goto fallback;
849*cc4ad7daSAndroid Build Coastguard Worker 
850*cc4ad7daSAndroid Build Coastguard Worker 	*array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
851*cc4ad7daSAndroid Build Coastguard Worker 	if (*array == NULL)
852*cc4ad7daSAndroid Build Coastguard Worker 		return -errno;
853*cc4ad7daSAndroid Build Coastguard Worker 
854*cc4ad7daSAndroid Build Coastguard Worker 	itr = (char *)(a + count);
855*cc4ad7daSAndroid Build Coastguard Worker 	count = 0;
856*cc4ad7daSAndroid Build Coastguard Worker 	str_off = (const uint8_t *)strtab - elf->memory;
857*cc4ad7daSAndroid Build Coastguard Worker 	sym_off = (const uint8_t *)symtab - elf->memory + symlen;
858*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 1; i < symcount; i++, sym_off += symlen) {
859*cc4ad7daSAndroid Build Coastguard Worker 		const char *name;
860*cc4ad7daSAndroid Build Coastguard Worker 		uint32_t name_off;
861*cc4ad7daSAndroid Build Coastguard Worker 		uint64_t crc;
862*cc4ad7daSAndroid Build Coastguard Worker 		uint8_t info, bind;
863*cc4ad7daSAndroid Build Coastguard Worker 		uint16_t shndx;
864*cc4ad7daSAndroid Build Coastguard Worker 
865*cc4ad7daSAndroid Build Coastguard Worker #define READV(field)							\
866*cc4ad7daSAndroid Build Coastguard Worker 		elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
867*cc4ad7daSAndroid Build Coastguard Worker 			     sizeof(s->field))
868*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->class & KMOD_ELF_32) {
869*cc4ad7daSAndroid Build Coastguard Worker 			Elf32_Sym *s;
870*cc4ad7daSAndroid Build Coastguard Worker 			name_off = READV(st_name);
871*cc4ad7daSAndroid Build Coastguard Worker 			crc = READV(st_value);
872*cc4ad7daSAndroid Build Coastguard Worker 			info = READV(st_info);
873*cc4ad7daSAndroid Build Coastguard Worker 			shndx = READV(st_shndx);
874*cc4ad7daSAndroid Build Coastguard Worker 		} else {
875*cc4ad7daSAndroid Build Coastguard Worker 			Elf64_Sym *s;
876*cc4ad7daSAndroid Build Coastguard Worker 			name_off = READV(st_name);
877*cc4ad7daSAndroid Build Coastguard Worker 			crc = READV(st_value);
878*cc4ad7daSAndroid Build Coastguard Worker 			info = READV(st_info);
879*cc4ad7daSAndroid Build Coastguard Worker 			shndx = READV(st_shndx);
880*cc4ad7daSAndroid Build Coastguard Worker 		}
881*cc4ad7daSAndroid Build Coastguard Worker #undef READV
882*cc4ad7daSAndroid Build Coastguard Worker 		name = elf_get_mem(elf, str_off + name_off);
883*cc4ad7daSAndroid Build Coastguard Worker 		if (strncmp(name, crc_str, crc_strlen) != 0)
884*cc4ad7daSAndroid Build Coastguard Worker 			continue;
885*cc4ad7daSAndroid Build Coastguard Worker 		name += crc_strlen;
886*cc4ad7daSAndroid Build Coastguard Worker 
887*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->class & KMOD_ELF_32)
888*cc4ad7daSAndroid Build Coastguard Worker 			bind = ELF32_ST_BIND(info);
889*cc4ad7daSAndroid Build Coastguard Worker 		else
890*cc4ad7daSAndroid Build Coastguard Worker 			bind = ELF64_ST_BIND(info);
891*cc4ad7daSAndroid Build Coastguard Worker 
892*cc4ad7daSAndroid Build Coastguard Worker 		a[count].crc = kmod_elf_resolve_crc(elf, crc, shndx);
893*cc4ad7daSAndroid Build Coastguard Worker 		a[count].bind = kmod_symbol_bind_from_elf(bind);
894*cc4ad7daSAndroid Build Coastguard Worker 		a[count].symbol = itr;
895*cc4ad7daSAndroid Build Coastguard Worker 		slen = strlen(name);
896*cc4ad7daSAndroid Build Coastguard Worker 		memcpy(itr, name, slen);
897*cc4ad7daSAndroid Build Coastguard Worker 		itr[slen] = '\0';
898*cc4ad7daSAndroid Build Coastguard Worker 		itr += slen + 1;
899*cc4ad7daSAndroid Build Coastguard Worker 		count++;
900*cc4ad7daSAndroid Build Coastguard Worker 	}
901*cc4ad7daSAndroid Build Coastguard Worker 	return count;
902*cc4ad7daSAndroid Build Coastguard Worker 
903*cc4ad7daSAndroid Build Coastguard Worker fallback:
904*cc4ad7daSAndroid Build Coastguard Worker 	ELFDBG(elf, "Falling back to __ksymtab_strings!\n");
905*cc4ad7daSAndroid Build Coastguard Worker 	return kmod_elf_get_symbols_symtab(elf, array);
906*cc4ad7daSAndroid Build Coastguard Worker }
907*cc4ad7daSAndroid Build Coastguard Worker 
kmod_elf_crc_find(const struct kmod_elf * elf,const void * versions,uint64_t versionslen,const char * name,uint64_t * crc)908*cc4ad7daSAndroid Build Coastguard Worker static int kmod_elf_crc_find(const struct kmod_elf *elf, const void *versions, uint64_t versionslen, const char *name, uint64_t *crc)
909*cc4ad7daSAndroid Build Coastguard Worker {
910*cc4ad7daSAndroid Build Coastguard Worker 	size_t verlen, crclen, off;
911*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t i;
912*cc4ad7daSAndroid Build Coastguard Worker 
913*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_32) {
914*cc4ad7daSAndroid Build Coastguard Worker 		struct kmod_modversion32 *mv;
915*cc4ad7daSAndroid Build Coastguard Worker 		verlen = sizeof(*mv);
916*cc4ad7daSAndroid Build Coastguard Worker 		crclen = sizeof(mv->crc);
917*cc4ad7daSAndroid Build Coastguard Worker 	} else {
918*cc4ad7daSAndroid Build Coastguard Worker 		struct kmod_modversion64 *mv;
919*cc4ad7daSAndroid Build Coastguard Worker 		verlen = sizeof(*mv);
920*cc4ad7daSAndroid Build Coastguard Worker 		crclen = sizeof(mv->crc);
921*cc4ad7daSAndroid Build Coastguard Worker 	}
922*cc4ad7daSAndroid Build Coastguard Worker 
923*cc4ad7daSAndroid Build Coastguard Worker 	off = (const uint8_t *)versions - elf->memory;
924*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0; i < versionslen; i += verlen) {
925*cc4ad7daSAndroid Build Coastguard Worker 		const char *symbol = elf_get_mem(elf, off + i + crclen);
926*cc4ad7daSAndroid Build Coastguard Worker 		if (!streq(name, symbol))
927*cc4ad7daSAndroid Build Coastguard Worker 			continue;
928*cc4ad7daSAndroid Build Coastguard Worker 		*crc = elf_get_uint(elf, off + i, crclen);
929*cc4ad7daSAndroid Build Coastguard Worker 		return i / verlen;
930*cc4ad7daSAndroid Build Coastguard Worker 	}
931*cc4ad7daSAndroid Build Coastguard Worker 
932*cc4ad7daSAndroid Build Coastguard Worker 	ELFDBG(elf, "could not find crc for symbol '%s'\n", name);
933*cc4ad7daSAndroid Build Coastguard Worker 	*crc = 0;
934*cc4ad7daSAndroid Build Coastguard Worker 	return -1;
935*cc4ad7daSAndroid Build Coastguard Worker }
936*cc4ad7daSAndroid Build Coastguard Worker 
937*cc4ad7daSAndroid Build Coastguard Worker /* from module-init-tools:elfops_core.c */
938*cc4ad7daSAndroid Build Coastguard Worker #ifndef STT_REGISTER
939*cc4ad7daSAndroid Build Coastguard Worker #define STT_REGISTER    13              /* Global register reserved to app. */
940*cc4ad7daSAndroid Build Coastguard Worker #endif
941*cc4ad7daSAndroid Build Coastguard Worker 
942*cc4ad7daSAndroid Build Coastguard Worker /* array will be allocated with strings in a single malloc, just free *array */
kmod_elf_get_dependency_symbols(const struct kmod_elf * elf,struct kmod_modversion ** array)943*cc4ad7daSAndroid Build Coastguard Worker int kmod_elf_get_dependency_symbols(const struct kmod_elf *elf, struct kmod_modversion **array)
944*cc4ad7daSAndroid Build Coastguard Worker {
945*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t versionslen, strtablen, symtablen, str_off, sym_off, ver_off;
946*cc4ad7daSAndroid Build Coastguard Worker 	const void *versions, *strtab, *symtab;
947*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_modversion *a;
948*cc4ad7daSAndroid Build Coastguard Worker 	char *itr;
949*cc4ad7daSAndroid Build Coastguard Worker 	size_t slen, verlen, symlen, crclen;
950*cc4ad7daSAndroid Build Coastguard Worker 	int i, count, symcount, vercount, err;
951*cc4ad7daSAndroid Build Coastguard Worker 	bool handle_register_symbols;
952*cc4ad7daSAndroid Build Coastguard Worker 	uint8_t *visited_versions;
953*cc4ad7daSAndroid Build Coastguard Worker 	uint64_t *symcrcs;
954*cc4ad7daSAndroid Build Coastguard Worker 
955*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, "__versions", &versions, &versionslen);
956*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0) {
957*cc4ad7daSAndroid Build Coastguard Worker 		versions = NULL;
958*cc4ad7daSAndroid Build Coastguard Worker 		versionslen = 0;
959*cc4ad7daSAndroid Build Coastguard Worker 		verlen = 0;
960*cc4ad7daSAndroid Build Coastguard Worker 		crclen = 0;
961*cc4ad7daSAndroid Build Coastguard Worker 	} else {
962*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->class & KMOD_ELF_32) {
963*cc4ad7daSAndroid Build Coastguard Worker 			struct kmod_modversion32 *mv;
964*cc4ad7daSAndroid Build Coastguard Worker 			verlen = sizeof(*mv);
965*cc4ad7daSAndroid Build Coastguard Worker 			crclen = sizeof(mv->crc);
966*cc4ad7daSAndroid Build Coastguard Worker 		} else {
967*cc4ad7daSAndroid Build Coastguard Worker 			struct kmod_modversion64 *mv;
968*cc4ad7daSAndroid Build Coastguard Worker 			verlen = sizeof(*mv);
969*cc4ad7daSAndroid Build Coastguard Worker 			crclen = sizeof(mv->crc);
970*cc4ad7daSAndroid Build Coastguard Worker 		}
971*cc4ad7daSAndroid Build Coastguard Worker 		if (versionslen % verlen != 0) {
972*cc4ad7daSAndroid Build Coastguard Worker 			ELFDBG(elf, "unexpected __versions of length %"PRIu64", not multiple of %zd as expected.\n", versionslen, verlen);
973*cc4ad7daSAndroid Build Coastguard Worker 			versions = NULL;
974*cc4ad7daSAndroid Build Coastguard Worker 			versionslen = 0;
975*cc4ad7daSAndroid Build Coastguard Worker 		}
976*cc4ad7daSAndroid Build Coastguard Worker 	}
977*cc4ad7daSAndroid Build Coastguard Worker 
978*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, ".strtab", &strtab, &strtablen);
979*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0) {
980*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "no .strtab found.\n");
981*cc4ad7daSAndroid Build Coastguard Worker 		return -EINVAL;
982*cc4ad7daSAndroid Build Coastguard Worker 	}
983*cc4ad7daSAndroid Build Coastguard Worker 
984*cc4ad7daSAndroid Build Coastguard Worker 	err = kmod_elf_get_section(elf, ".symtab", &symtab, &symtablen);
985*cc4ad7daSAndroid Build Coastguard Worker 	if (err < 0) {
986*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "no .symtab found.\n");
987*cc4ad7daSAndroid Build Coastguard Worker 		return -EINVAL;
988*cc4ad7daSAndroid Build Coastguard Worker 	}
989*cc4ad7daSAndroid Build Coastguard Worker 
990*cc4ad7daSAndroid Build Coastguard Worker 	if (elf->class & KMOD_ELF_32)
991*cc4ad7daSAndroid Build Coastguard Worker 		symlen = sizeof(Elf32_Sym);
992*cc4ad7daSAndroid Build Coastguard Worker 	else
993*cc4ad7daSAndroid Build Coastguard Worker 		symlen = sizeof(Elf64_Sym);
994*cc4ad7daSAndroid Build Coastguard Worker 
995*cc4ad7daSAndroid Build Coastguard Worker 	if (symtablen % symlen != 0) {
996*cc4ad7daSAndroid Build Coastguard Worker 		ELFDBG(elf, "unexpected .symtab of length %"PRIu64", not multiple of %"PRIu64" as expected.\n", symtablen, symlen);
997*cc4ad7daSAndroid Build Coastguard Worker 		return -EINVAL;
998*cc4ad7daSAndroid Build Coastguard Worker 	}
999*cc4ad7daSAndroid Build Coastguard Worker 
1000*cc4ad7daSAndroid Build Coastguard Worker 	if (versionslen == 0) {
1001*cc4ad7daSAndroid Build Coastguard Worker 		vercount = 0;
1002*cc4ad7daSAndroid Build Coastguard Worker 		visited_versions = NULL;
1003*cc4ad7daSAndroid Build Coastguard Worker 	} else {
1004*cc4ad7daSAndroid Build Coastguard Worker 		vercount = versionslen / verlen;
1005*cc4ad7daSAndroid Build Coastguard Worker 		visited_versions = calloc(vercount, sizeof(uint8_t));
1006*cc4ad7daSAndroid Build Coastguard Worker 		if (visited_versions == NULL)
1007*cc4ad7daSAndroid Build Coastguard Worker 			return -ENOMEM;
1008*cc4ad7daSAndroid Build Coastguard Worker 	}
1009*cc4ad7daSAndroid Build Coastguard Worker 
1010*cc4ad7daSAndroid Build Coastguard Worker 	handle_register_symbols = (elf->header.machine == EM_SPARC ||
1011*cc4ad7daSAndroid Build Coastguard Worker 				   elf->header.machine == EM_SPARCV9);
1012*cc4ad7daSAndroid Build Coastguard Worker 
1013*cc4ad7daSAndroid Build Coastguard Worker 	symcount = symtablen / symlen;
1014*cc4ad7daSAndroid Build Coastguard Worker 	count = 0;
1015*cc4ad7daSAndroid Build Coastguard Worker 	slen = 0;
1016*cc4ad7daSAndroid Build Coastguard Worker 	str_off = (const uint8_t *)strtab - elf->memory;
1017*cc4ad7daSAndroid Build Coastguard Worker 	sym_off = (const uint8_t *)symtab - elf->memory + symlen;
1018*cc4ad7daSAndroid Build Coastguard Worker 
1019*cc4ad7daSAndroid Build Coastguard Worker 	symcrcs = calloc(symcount, sizeof(uint64_t));
1020*cc4ad7daSAndroid Build Coastguard Worker 	if (symcrcs == NULL) {
1021*cc4ad7daSAndroid Build Coastguard Worker 		free(visited_versions);
1022*cc4ad7daSAndroid Build Coastguard Worker 		return -ENOMEM;
1023*cc4ad7daSAndroid Build Coastguard Worker 	}
1024*cc4ad7daSAndroid Build Coastguard Worker 
1025*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 1; i < symcount; i++, sym_off += symlen) {
1026*cc4ad7daSAndroid Build Coastguard Worker 		const char *name;
1027*cc4ad7daSAndroid Build Coastguard Worker 		uint64_t crc;
1028*cc4ad7daSAndroid Build Coastguard Worker 		uint32_t name_off;
1029*cc4ad7daSAndroid Build Coastguard Worker 		uint16_t secidx;
1030*cc4ad7daSAndroid Build Coastguard Worker 		uint8_t info;
1031*cc4ad7daSAndroid Build Coastguard Worker 		int idx;
1032*cc4ad7daSAndroid Build Coastguard Worker 
1033*cc4ad7daSAndroid Build Coastguard Worker #define READV(field)							\
1034*cc4ad7daSAndroid Build Coastguard Worker 		elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1035*cc4ad7daSAndroid Build Coastguard Worker 			     sizeof(s->field))
1036*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->class & KMOD_ELF_32) {
1037*cc4ad7daSAndroid Build Coastguard Worker 			Elf32_Sym *s;
1038*cc4ad7daSAndroid Build Coastguard Worker 			name_off = READV(st_name);
1039*cc4ad7daSAndroid Build Coastguard Worker 			secidx = READV(st_shndx);
1040*cc4ad7daSAndroid Build Coastguard Worker 			info = READV(st_info);
1041*cc4ad7daSAndroid Build Coastguard Worker 		} else {
1042*cc4ad7daSAndroid Build Coastguard Worker 			Elf64_Sym *s;
1043*cc4ad7daSAndroid Build Coastguard Worker 			name_off = READV(st_name);
1044*cc4ad7daSAndroid Build Coastguard Worker 			secidx = READV(st_shndx);
1045*cc4ad7daSAndroid Build Coastguard Worker 			info = READV(st_info);
1046*cc4ad7daSAndroid Build Coastguard Worker 		}
1047*cc4ad7daSAndroid Build Coastguard Worker #undef READV
1048*cc4ad7daSAndroid Build Coastguard Worker 		if (secidx != SHN_UNDEF)
1049*cc4ad7daSAndroid Build Coastguard Worker 			continue;
1050*cc4ad7daSAndroid Build Coastguard Worker 
1051*cc4ad7daSAndroid Build Coastguard Worker 		if (handle_register_symbols) {
1052*cc4ad7daSAndroid Build Coastguard Worker 			uint8_t type;
1053*cc4ad7daSAndroid Build Coastguard Worker 			if (elf->class & KMOD_ELF_32)
1054*cc4ad7daSAndroid Build Coastguard Worker 				type = ELF32_ST_TYPE(info);
1055*cc4ad7daSAndroid Build Coastguard Worker 			else
1056*cc4ad7daSAndroid Build Coastguard Worker 				type = ELF64_ST_TYPE(info);
1057*cc4ad7daSAndroid Build Coastguard Worker 
1058*cc4ad7daSAndroid Build Coastguard Worker 			/* Not really undefined: sparc gcc 3.3 creates
1059*cc4ad7daSAndroid Build Coastguard Worker 			 * U references when you have global asm
1060*cc4ad7daSAndroid Build Coastguard Worker 			 * variables, to avoid anyone else misusing
1061*cc4ad7daSAndroid Build Coastguard Worker 			 * them.
1062*cc4ad7daSAndroid Build Coastguard Worker 			 */
1063*cc4ad7daSAndroid Build Coastguard Worker 			if (type == STT_REGISTER)
1064*cc4ad7daSAndroid Build Coastguard Worker 				continue;
1065*cc4ad7daSAndroid Build Coastguard Worker 		}
1066*cc4ad7daSAndroid Build Coastguard Worker 
1067*cc4ad7daSAndroid Build Coastguard Worker 		if (name_off >= strtablen) {
1068*cc4ad7daSAndroid Build Coastguard Worker 			ELFDBG(elf, ".strtab is %"PRIu64" bytes, but .symtab entry %d wants to access offset %"PRIu32".\n", strtablen, i, name_off);
1069*cc4ad7daSAndroid Build Coastguard Worker 			free(visited_versions);
1070*cc4ad7daSAndroid Build Coastguard Worker 			free(symcrcs);
1071*cc4ad7daSAndroid Build Coastguard Worker 			return -EINVAL;
1072*cc4ad7daSAndroid Build Coastguard Worker 		}
1073*cc4ad7daSAndroid Build Coastguard Worker 
1074*cc4ad7daSAndroid Build Coastguard Worker 		name = elf_get_mem(elf, str_off + name_off);
1075*cc4ad7daSAndroid Build Coastguard Worker 		if (name[0] == '\0') {
1076*cc4ad7daSAndroid Build Coastguard Worker 			ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1077*cc4ad7daSAndroid Build Coastguard Worker 			continue;
1078*cc4ad7daSAndroid Build Coastguard Worker 		}
1079*cc4ad7daSAndroid Build Coastguard Worker 
1080*cc4ad7daSAndroid Build Coastguard Worker 		slen += strlen(name) + 1;
1081*cc4ad7daSAndroid Build Coastguard Worker 		count++;
1082*cc4ad7daSAndroid Build Coastguard Worker 
1083*cc4ad7daSAndroid Build Coastguard Worker 		idx = kmod_elf_crc_find(elf, versions, versionslen, name, &crc);
1084*cc4ad7daSAndroid Build Coastguard Worker 		if (idx >= 0 && visited_versions != NULL)
1085*cc4ad7daSAndroid Build Coastguard Worker 			visited_versions[idx] = 1;
1086*cc4ad7daSAndroid Build Coastguard Worker 		symcrcs[i] = crc;
1087*cc4ad7daSAndroid Build Coastguard Worker 	}
1088*cc4ad7daSAndroid Build Coastguard Worker 
1089*cc4ad7daSAndroid Build Coastguard Worker 	if (visited_versions != NULL) {
1090*cc4ad7daSAndroid Build Coastguard Worker 		/* module_layout/struct_module are not visited, but needed */
1091*cc4ad7daSAndroid Build Coastguard Worker 		ver_off = (const uint8_t *)versions - elf->memory;
1092*cc4ad7daSAndroid Build Coastguard Worker 		for (i = 0; i < vercount; i++) {
1093*cc4ad7daSAndroid Build Coastguard Worker 			if (visited_versions[i] == 0) {
1094*cc4ad7daSAndroid Build Coastguard Worker 				const char *name;
1095*cc4ad7daSAndroid Build Coastguard Worker 				name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1096*cc4ad7daSAndroid Build Coastguard Worker 				slen += strlen(name) + 1;
1097*cc4ad7daSAndroid Build Coastguard Worker 
1098*cc4ad7daSAndroid Build Coastguard Worker 				count++;
1099*cc4ad7daSAndroid Build Coastguard Worker 			}
1100*cc4ad7daSAndroid Build Coastguard Worker 		}
1101*cc4ad7daSAndroid Build Coastguard Worker 	}
1102*cc4ad7daSAndroid Build Coastguard Worker 
1103*cc4ad7daSAndroid Build Coastguard Worker 	if (count == 0) {
1104*cc4ad7daSAndroid Build Coastguard Worker 		free(visited_versions);
1105*cc4ad7daSAndroid Build Coastguard Worker 		free(symcrcs);
1106*cc4ad7daSAndroid Build Coastguard Worker 		*array = NULL;
1107*cc4ad7daSAndroid Build Coastguard Worker 		return 0;
1108*cc4ad7daSAndroid Build Coastguard Worker 	}
1109*cc4ad7daSAndroid Build Coastguard Worker 
1110*cc4ad7daSAndroid Build Coastguard Worker 	*array = a = malloc(sizeof(struct kmod_modversion) * count + slen);
1111*cc4ad7daSAndroid Build Coastguard Worker 	if (*array == NULL) {
1112*cc4ad7daSAndroid Build Coastguard Worker 		free(visited_versions);
1113*cc4ad7daSAndroid Build Coastguard Worker 		free(symcrcs);
1114*cc4ad7daSAndroid Build Coastguard Worker 		return -errno;
1115*cc4ad7daSAndroid Build Coastguard Worker 	}
1116*cc4ad7daSAndroid Build Coastguard Worker 
1117*cc4ad7daSAndroid Build Coastguard Worker 	itr = (char *)(a + count);
1118*cc4ad7daSAndroid Build Coastguard Worker 	count = 0;
1119*cc4ad7daSAndroid Build Coastguard Worker 	str_off = (const uint8_t *)strtab - elf->memory;
1120*cc4ad7daSAndroid Build Coastguard Worker 	sym_off = (const uint8_t *)symtab - elf->memory + symlen;
1121*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 1; i < symcount; i++, sym_off += symlen) {
1122*cc4ad7daSAndroid Build Coastguard Worker 		const char *name;
1123*cc4ad7daSAndroid Build Coastguard Worker 		uint64_t crc;
1124*cc4ad7daSAndroid Build Coastguard Worker 		uint32_t name_off;
1125*cc4ad7daSAndroid Build Coastguard Worker 		uint16_t secidx;
1126*cc4ad7daSAndroid Build Coastguard Worker 		uint8_t info, bind;
1127*cc4ad7daSAndroid Build Coastguard Worker 
1128*cc4ad7daSAndroid Build Coastguard Worker #define READV(field)							\
1129*cc4ad7daSAndroid Build Coastguard Worker 		elf_get_uint(elf, sym_off + offsetof(typeof(*s), field),\
1130*cc4ad7daSAndroid Build Coastguard Worker 			     sizeof(s->field))
1131*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->class & KMOD_ELF_32) {
1132*cc4ad7daSAndroid Build Coastguard Worker 			Elf32_Sym *s;
1133*cc4ad7daSAndroid Build Coastguard Worker 			name_off = READV(st_name);
1134*cc4ad7daSAndroid Build Coastguard Worker 			secidx = READV(st_shndx);
1135*cc4ad7daSAndroid Build Coastguard Worker 			info = READV(st_info);
1136*cc4ad7daSAndroid Build Coastguard Worker 		} else {
1137*cc4ad7daSAndroid Build Coastguard Worker 			Elf64_Sym *s;
1138*cc4ad7daSAndroid Build Coastguard Worker 			name_off = READV(st_name);
1139*cc4ad7daSAndroid Build Coastguard Worker 			secidx = READV(st_shndx);
1140*cc4ad7daSAndroid Build Coastguard Worker 			info = READV(st_info);
1141*cc4ad7daSAndroid Build Coastguard Worker 		}
1142*cc4ad7daSAndroid Build Coastguard Worker #undef READV
1143*cc4ad7daSAndroid Build Coastguard Worker 		if (secidx != SHN_UNDEF)
1144*cc4ad7daSAndroid Build Coastguard Worker 			continue;
1145*cc4ad7daSAndroid Build Coastguard Worker 
1146*cc4ad7daSAndroid Build Coastguard Worker 		if (handle_register_symbols) {
1147*cc4ad7daSAndroid Build Coastguard Worker 			uint8_t type;
1148*cc4ad7daSAndroid Build Coastguard Worker 			if (elf->class & KMOD_ELF_32)
1149*cc4ad7daSAndroid Build Coastguard Worker 				type = ELF32_ST_TYPE(info);
1150*cc4ad7daSAndroid Build Coastguard Worker 			else
1151*cc4ad7daSAndroid Build Coastguard Worker 				type = ELF64_ST_TYPE(info);
1152*cc4ad7daSAndroid Build Coastguard Worker 
1153*cc4ad7daSAndroid Build Coastguard Worker 			/* Not really undefined: sparc gcc 3.3 creates
1154*cc4ad7daSAndroid Build Coastguard Worker 			 * U references when you have global asm
1155*cc4ad7daSAndroid Build Coastguard Worker 			 * variables, to avoid anyone else misusing
1156*cc4ad7daSAndroid Build Coastguard Worker 			 * them.
1157*cc4ad7daSAndroid Build Coastguard Worker 			 */
1158*cc4ad7daSAndroid Build Coastguard Worker 			if (type == STT_REGISTER)
1159*cc4ad7daSAndroid Build Coastguard Worker 				continue;
1160*cc4ad7daSAndroid Build Coastguard Worker 		}
1161*cc4ad7daSAndroid Build Coastguard Worker 
1162*cc4ad7daSAndroid Build Coastguard Worker 		name = elf_get_mem(elf, str_off + name_off);
1163*cc4ad7daSAndroid Build Coastguard Worker 		if (name[0] == '\0') {
1164*cc4ad7daSAndroid Build Coastguard Worker 			ELFDBG(elf, "empty symbol name at index %"PRIu64"\n", i);
1165*cc4ad7daSAndroid Build Coastguard Worker 			continue;
1166*cc4ad7daSAndroid Build Coastguard Worker 		}
1167*cc4ad7daSAndroid Build Coastguard Worker 
1168*cc4ad7daSAndroid Build Coastguard Worker 		if (elf->class & KMOD_ELF_32)
1169*cc4ad7daSAndroid Build Coastguard Worker 			bind = ELF32_ST_BIND(info);
1170*cc4ad7daSAndroid Build Coastguard Worker 		else
1171*cc4ad7daSAndroid Build Coastguard Worker 			bind = ELF64_ST_BIND(info);
1172*cc4ad7daSAndroid Build Coastguard Worker 		if (bind == STB_WEAK)
1173*cc4ad7daSAndroid Build Coastguard Worker 			bind = KMOD_SYMBOL_WEAK;
1174*cc4ad7daSAndroid Build Coastguard Worker 		else
1175*cc4ad7daSAndroid Build Coastguard Worker 			bind = KMOD_SYMBOL_UNDEF;
1176*cc4ad7daSAndroid Build Coastguard Worker 
1177*cc4ad7daSAndroid Build Coastguard Worker 		slen = strlen(name);
1178*cc4ad7daSAndroid Build Coastguard Worker 		crc = symcrcs[i];
1179*cc4ad7daSAndroid Build Coastguard Worker 
1180*cc4ad7daSAndroid Build Coastguard Worker 		a[count].crc = crc;
1181*cc4ad7daSAndroid Build Coastguard Worker 		a[count].bind = bind;
1182*cc4ad7daSAndroid Build Coastguard Worker 		a[count].symbol = itr;
1183*cc4ad7daSAndroid Build Coastguard Worker 		memcpy(itr, name, slen);
1184*cc4ad7daSAndroid Build Coastguard Worker 		itr[slen] = '\0';
1185*cc4ad7daSAndroid Build Coastguard Worker 		itr += slen + 1;
1186*cc4ad7daSAndroid Build Coastguard Worker 
1187*cc4ad7daSAndroid Build Coastguard Worker 		count++;
1188*cc4ad7daSAndroid Build Coastguard Worker 	}
1189*cc4ad7daSAndroid Build Coastguard Worker 
1190*cc4ad7daSAndroid Build Coastguard Worker 	free(symcrcs);
1191*cc4ad7daSAndroid Build Coastguard Worker 
1192*cc4ad7daSAndroid Build Coastguard Worker 	if (visited_versions == NULL)
1193*cc4ad7daSAndroid Build Coastguard Worker 		return count;
1194*cc4ad7daSAndroid Build Coastguard Worker 
1195*cc4ad7daSAndroid Build Coastguard Worker 	/* add unvisited (module_layout/struct_module) */
1196*cc4ad7daSAndroid Build Coastguard Worker 	ver_off = (const uint8_t *)versions - elf->memory;
1197*cc4ad7daSAndroid Build Coastguard Worker 	for (i = 0; i < vercount; i++) {
1198*cc4ad7daSAndroid Build Coastguard Worker 		const char *name;
1199*cc4ad7daSAndroid Build Coastguard Worker 		uint64_t crc;
1200*cc4ad7daSAndroid Build Coastguard Worker 
1201*cc4ad7daSAndroid Build Coastguard Worker 		if (visited_versions[i] != 0)
1202*cc4ad7daSAndroid Build Coastguard Worker 			continue;
1203*cc4ad7daSAndroid Build Coastguard Worker 
1204*cc4ad7daSAndroid Build Coastguard Worker 		name = elf_get_mem(elf, ver_off + i * verlen + crclen);
1205*cc4ad7daSAndroid Build Coastguard Worker 		slen = strlen(name);
1206*cc4ad7daSAndroid Build Coastguard Worker 		crc = elf_get_uint(elf, ver_off + i * verlen, crclen);
1207*cc4ad7daSAndroid Build Coastguard Worker 
1208*cc4ad7daSAndroid Build Coastguard Worker 		a[count].crc = crc;
1209*cc4ad7daSAndroid Build Coastguard Worker 		a[count].bind = KMOD_SYMBOL_UNDEF;
1210*cc4ad7daSAndroid Build Coastguard Worker 		a[count].symbol = itr;
1211*cc4ad7daSAndroid Build Coastguard Worker 		memcpy(itr, name, slen);
1212*cc4ad7daSAndroid Build Coastguard Worker 		itr[slen] = '\0';
1213*cc4ad7daSAndroid Build Coastguard Worker 		itr += slen + 1;
1214*cc4ad7daSAndroid Build Coastguard Worker 
1215*cc4ad7daSAndroid Build Coastguard Worker 		count++;
1216*cc4ad7daSAndroid Build Coastguard Worker 	}
1217*cc4ad7daSAndroid Build Coastguard Worker 	free(visited_versions);
1218*cc4ad7daSAndroid Build Coastguard Worker 	return count;
1219*cc4ad7daSAndroid Build Coastguard Worker }
1220