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