1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2020 Intel Corporation. All rights reserved.
4  *
5  * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6  *         Keyon Jie <yang.jie@linux.intel.com>
7  *         Karol Trzcinski <karolx.trzcinski@linux.intel.com>
8  */
9 
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include "elf_defs.h"
15 #include "elf.h"
16 
elf_read_sections(struct elf_module * module,bool verbose)17 static int elf_read_sections(struct elf_module *module, bool verbose)
18 {
19 	Elf32_Ehdr *hdr = &module->hdr;
20 	Elf32_Shdr *section = module->section;
21 	size_t count;
22 	int i, ret;
23 	uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
24 
25 	/* read in section header */
26 	ret = fseek(module->fd, hdr->shoff, SEEK_SET);
27 	if (ret < 0) {
28 		fprintf(stderr, "error: can't seek to %s section header %d\n",
29 			module->elf_file, ret);
30 		return ret;
31 	}
32 
33 	/* allocate space for each section header */
34 	section = calloc(sizeof(Elf32_Shdr), hdr->shnum);
35 	if (!section)
36 		return -ENOMEM;
37 	module->section = section;
38 
39 	/* read in sections */
40 	count = fread(section, sizeof(Elf32_Shdr), hdr->shnum, module->fd);
41 	if (count != hdr->shnum) {
42 		fprintf(stderr, "error: failed to read %s section header %d\n",
43 			module->elf_file, -errno);
44 		return -errno;
45 	}
46 
47 	/* read in strings */
48 	module->strings = calloc(1, section[hdr->shstrndx].size);
49 	if (!module->strings) {
50 		fprintf(stderr, "error: failed %s to read ELF strings for %d\n",
51 			module->elf_file, -errno);
52 			return -errno;
53 	}
54 
55 	ret = fseek(module->fd, section[hdr->shstrndx].off, SEEK_SET);
56 	if (ret < 0) {
57 		fprintf(stderr, "error: can't seek to %s stringss %d\n",
58 			module->elf_file, ret);
59 		return ret;
60 	}
61 
62 	count = fread(module->strings, 1, section[hdr->shstrndx].size,
63 		      module->fd);
64 	if (count != section[hdr->shstrndx].size) {
65 		fprintf(stderr, "error: failed to read %s strings %d\n",
66 			module->elf_file, -errno);
67 		return -errno;
68 	}
69 
70 	module->bss_index = elf_find_section(module, ".bss");
71 	if (module->bss_index < 0) {
72 		fprintf(stderr, "Can't find .bss section in %s",
73 		module->elf_file);
74 		return -EINVAL;
75 	}
76 
77 	/* parse each section */
78 	for (i = 0; i < hdr->shnum; i++) {
79 		/* only write valid sections */
80 		if (!(section[i].flags & valid))
81 			continue;
82 
83 		switch (section[i].type) {
84 		case SHT_NOBITS:
85 			/* bss */
86 			module->bss_size += section[i].size;
87 			module->num_bss++;
88 			break;
89 		case SHT_PROGBITS:
90 			/* text or data */
91 			module->fw_size += section[i].size;
92 
93 			if (section[i].flags & SHF_EXECINSTR)
94 				module->text_size += section[i].size;
95 			else
96 				module->data_size += section[i].size;
97 			break;
98 		default:
99 			continue;
100 		}
101 
102 		module->num_sections++;
103 
104 		if (!verbose)
105 			continue;
106 
107 		fprintf(stdout, " %s section-%d: \tname\t %s\n",
108 			module->elf_file, i, module->strings + section[i].name);
109 		fprintf(stdout, " %s section-%d: \ttype\t 0x%8.8x\n",
110 			module->elf_file, i, section[i].type);
111 		fprintf(stdout, " %s section-%d: \tflags\t 0x%8.8x\n",
112 			module->elf_file, i, section[i].flags);
113 		fprintf(stdout, " %s section-%d: \taddr\t 0x%8.8x\n",
114 			module->elf_file, i, section[i].vaddr);
115 		fprintf(stdout, " %s section-%d: \toffset\t 0x%8.8x\n",
116 			module->elf_file, i, section[i].off);
117 		fprintf(stdout, " %s section-%d: \tsize\t 0x%8.8x\n",
118 			module->elf_file, i, section[i].size);
119 		fprintf(stdout, " %s section-%d: \tlink\t 0x%8.8x\n",
120 			module->elf_file, i, section[i].link);
121 		fprintf(stdout, " %s section-%d: \tinfo\t 0x%8.8x\n\n",
122 			module->elf_file, i, section[i].info);
123 	}
124 
125 	return 0;
126 }
127 
elf_read_programs(struct elf_module * module,bool verbose)128 static int elf_read_programs(struct elf_module *module, bool verbose)
129 {
130 	Elf32_Ehdr *hdr = &module->hdr;
131 	Elf32_Phdr *prg = module->prg;
132 	size_t count;
133 	int i, ret;
134 
135 	/* read in program header */
136 	ret = fseek(module->fd, hdr->phoff, SEEK_SET);
137 	if (ret < 0) {
138 		fprintf(stderr, "error: cant seek to %s program header %d\n",
139 			module->elf_file, ret);
140 		return ret;
141 	}
142 
143 	/* allocate space for programs */
144 	prg = calloc(sizeof(Elf32_Phdr), hdr->phnum);
145 	if (!prg)
146 		return -ENOMEM;
147 	module->prg = prg;
148 
149 	/* read in programs */
150 	count = fread(prg, sizeof(Elf32_Phdr), hdr->phnum, module->fd);
151 	if (count != hdr->phnum) {
152 		fprintf(stderr, "error: failed to read %s program header %d\n",
153 			module->elf_file, -errno);
154 		return -errno;
155 	}
156 
157 	/* check each program */
158 	for (i = 0; i < hdr->phnum; i++) {
159 		if (prg[i].filesz == 0)
160 			continue;
161 
162 		if (!verbose)
163 			continue;
164 
165 		fprintf(stdout, "%s program-%d: \ttype\t 0x%8.8x\n",
166 			module->elf_file, i, prg[i].type);
167 		fprintf(stdout, "%s program-%d: \toffset\t 0x%8.8x\n",
168 			module->elf_file, i, prg[i].off);
169 		fprintf(stdout, "%s program-%d: \tvaddr\t 0x%8.8x\n",
170 			module->elf_file, i, prg[i].vaddr);
171 		fprintf(stdout, "%s program-%d: \tpaddr\t 0x%8.8x\n",
172 			module->elf_file, i, prg[i].paddr);
173 		fprintf(stdout, "%s program-%d: \tfsize\t 0x%8.8x\n",
174 			module->elf_file, i, prg[i].filesz);
175 		fprintf(stdout, "%s program-%d: \tmsize\t 0x%8.8x\n",
176 			module->elf_file, i, prg[i].memsz);
177 		fprintf(stdout, "%s program-%d: \tflags\t 0x%8.8x\n\n",
178 			module->elf_file, i, prg[i].flags);
179 	}
180 
181 	return 0;
182 }
183 
elf_read_hdr(struct elf_module * module,bool verbose)184 static int elf_read_hdr(struct elf_module *module, bool verbose)
185 {
186 	Elf32_Ehdr *hdr = &module->hdr;
187 	size_t count;
188 
189 	/* read in elf header */
190 	count = fread(hdr, sizeof(*hdr), 1, module->fd);
191 	if (count != 1) {
192 		fprintf(stderr, "error: failed to read %s elf header %d\n",
193 			module->elf_file, -errno);
194 		return -errno;
195 	}
196 
197 	if (!verbose)
198 		return 0;
199 
200 	fprintf(stdout, "%s elf: \tentry point\t 0x%8.8x\n",
201 		module->elf_file, hdr->entry);
202 	fprintf(stdout, "%s elf: \tprogram offset\t 0x%8.8x\n",
203 		module->elf_file, hdr->phoff);
204 	fprintf(stdout, "%s elf: \tsection offset\t 0x%8.8x\n",
205 		module->elf_file, hdr->shoff);
206 	fprintf(stdout, "%s elf: \tprogram size\t 0x%8.8x\n",
207 		module->elf_file, hdr->phentsize);
208 	fprintf(stdout, "%s elf: \tprogram count\t 0x%8.8x\n",
209 		module->elf_file, hdr->phnum);
210 	fprintf(stdout, "%s elf: \tsection size\t 0x%8.8x\n",
211 		module->elf_file, hdr->shentsize);
212 	fprintf(stdout, "%s elf: \tsection count\t 0x%8.8x\n",
213 		module->elf_file, hdr->shnum);
214 	fprintf(stdout, "%s elf: \tstring index\t 0x%8.8x\n\n",
215 		module->elf_file, hdr->shstrndx);
216 
217 	return 0;
218 }
219 
elf_module_size(struct elf_module * module,Elf32_Shdr * section,int index)220 static void elf_module_size(struct elf_module *module, Elf32_Shdr *section,
221 			    int index)
222 {
223 	switch (section->type) {
224 	case SHT_PROGBITS:
225 		/* text or data */
226 		if (section->flags & SHF_EXECINSTR) {
227 			/* text */
228 			if (module->text_start > section->vaddr)
229 				module->text_start = section->vaddr;
230 			if (module->text_end < section->vaddr + section->size)
231 				module->text_end = section->vaddr +
232 					section->size;
233 
234 			fprintf(stdout, "\tTEXT\t");
235 		} else {
236 			/* initialized data, also calc the writable sections */
237 			if (module->data_start > section->vaddr)
238 				module->data_start = section->vaddr;
239 			if (module->data_end < section->vaddr + section->size)
240 				module->data_end = section->vaddr +
241 					section->size;
242 
243 			fprintf(stdout, "\tDATA\t");
244 		}
245 		break;
246 	case SHT_NOBITS:
247 		/* bss */
248 		if (index == module->bss_index) {
249 			/* updated the .bss segment */
250 			module->bss_start = section->vaddr;
251 			module->bss_end = section->vaddr + section->size;
252 			fprintf(stdout, "\tBSS\t");
253 		} else {
254 			fprintf(stdout, "\tHEAP\t");
255 		}
256 		break;
257 	case SHT_NOTE:
258 		fprintf(stdout, "\tNOTE\t");
259 		break;
260 	default:
261 		break;
262 	}
263 }
264 
elf_module_limits(struct elf_module * module)265 static void elf_module_limits(struct elf_module *module)
266 {
267 	Elf32_Shdr *section;
268 	int i;
269 
270 	module->text_start = 0xffffffff;
271 	module->data_start = 0xffffffff;
272 	module->bss_start = 0;
273 	module->text_end = 0;
274 	module->data_end = 0;
275 	module->bss_end = 0;
276 
277 	fprintf(stdout, "  Found %d sections, listing valid sections......\n",
278 		module->hdr.shnum);
279 
280 	fprintf(stdout, "\tNo\tStart\t\tEnd\t\tSize\tType\tName\n");
281 
282 	/* iterate all sections and get size of segments */
283 	for (i = 0; i < module->hdr.shnum; i++) {
284 		section = &module->section[i];
285 
286 		/* module bss can sometimes be missed */
287 		if (i != module->bss_index) {
288 			if (section->vaddr == 0)
289 				continue;
290 
291 			if (section->size == 0)
292 				continue;
293 		}
294 
295 		fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%x", i,
296 			section->vaddr, section->vaddr + section->size,
297 			section->size);
298 
299 		/* text or data section */
300 		elf_module_size(module, section, i);
301 
302 		/* section name */
303 		fprintf(stdout, "%s\n", module->strings + section->name);
304 	}
305 
306 	fprintf(stdout, "\n");
307 }
308 
309 /* make sure no section overlap */
elf_validate_section(struct elf_module * module,Elf32_Shdr * section,int index)310 static int elf_validate_section(struct elf_module *module,
311 				Elf32_Shdr *section, int index)
312 {
313 	Elf32_Shdr *s;
314 	uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
315 	int i;
316 
317 	/* for each section */
318 	for (i = 0; i < module->hdr.shnum; i++) {
319 		s = &module->section[i];
320 
321 		if (s == section)
322 			continue;
323 
324 		/* only check valid sections */
325 		if (!(s->flags & valid))
326 			continue;
327 
328 		if (s->size == 0)
329 			continue;
330 
331 		/* is section start non overlapping ? */
332 		if (section->vaddr >= s->vaddr &&
333 		    section->vaddr < s->vaddr + s->size) {
334 			goto err;
335 		}
336 
337 		/* is section end non overlapping ? */
338 		if (section->vaddr + section->size > s->vaddr &&
339 		    section->vaddr + section->size <= s->vaddr + s->size) {
340 			goto err;
341 		}
342 	}
343 
344 	return 0;
345 
346 err:
347 	fprintf(stderr, "error: section overlap between %s:%d and %s:%d\n",
348 		module->elf_file, index, module->elf_file, i);
349 	fprintf(stderr, "     [0x%x : 0x%x] overlaps with [0x%x :0x%x]\n",
350 		section->vaddr, section->vaddr + section->size,
351 		s->vaddr, s->vaddr + s->size);
352 	return -EINVAL;
353 }
354 
355 /* make sure no section overlaps from any modules */
elf_validate_module(struct elf_module * module)356 static int elf_validate_module(struct elf_module *module)
357 {
358 	Elf32_Shdr *section;
359 	uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
360 	int i, ret;
361 
362 	/* for each section */
363 	for (i = 0; i < module->hdr.shnum; i++) {
364 		section = &module->section[i];
365 
366 		/* only check valid sections */
367 		if (!(section->flags & valid))
368 			continue;
369 
370 		if (section->size == 0)
371 			continue;
372 
373 		/* is section non overlapping ? */
374 		ret = elf_validate_section(module, section, i);
375 		if (ret < 0)
376 			return ret;
377 	}
378 
379 	return 0;
380 }
381 
elf_find_section(const struct elf_module * module,const char * name)382 int elf_find_section(const struct elf_module *module, const char *name)
383 {
384 	const Elf32_Ehdr *hdr = &module->hdr;
385 	const Elf32_Shdr *section, *s;
386 	char *buffer;
387 	size_t count;
388 	int ret, i;
389 
390 	section = &module->section[hdr->shstrndx];
391 
392 	/* alloc data data */
393 	buffer = calloc(1, section->size);
394 	if (!buffer)
395 		return -ENOMEM;
396 
397 	/* read in section string data */
398 	ret = fseek(module->fd, section->off, SEEK_SET);
399 	if (ret < 0) {
400 		fprintf(stderr, "error: cant seek to string section %d\n", ret);
401 		goto out;
402 	}
403 
404 	count = fread(buffer, 1, section->size, module->fd);
405 	if (count != section->size) {
406 		fprintf(stderr, "error: can't read string section %d\n",
407 			-errno);
408 		ret = -errno;
409 		goto out;
410 	}
411 
412 	/* find section with name */
413 	for (i = 0; i < hdr->shnum; i++) {
414 		s = &module->section[i];
415 		if (!strcmp(name, buffer + s->name)) {
416 			ret = i;
417 			goto out;
418 		}
419 	}
420 
421 	fprintf(stderr, "warning: can't find section %s in module %s\n", name,
422 		module->elf_file);
423 	ret = -EINVAL;
424 
425 out:
426 	free(buffer);
427 	return ret;
428 }
429 
elf_read_section(const struct elf_module * module,const char * section_name,const Elf32_Shdr ** dst_section,void ** dst_buff)430 int elf_read_section(const struct elf_module *module, const char *section_name,
431 		     const Elf32_Shdr **dst_section, void **dst_buff)
432 {
433 	const Elf32_Shdr *section;
434 	int section_index = -1;
435 	int read;
436 
437 	section_index = elf_find_section(module, section_name);
438 	if (section_index < 0) {
439 		fprintf(stderr, "error: section %s can't be found\n",
440 			section_name);
441 		return -EINVAL;
442 	}
443 
444 	section = &module->section[section_index];
445 	if (dst_section)
446 		*dst_section = section;
447 
448 	/* alloc buffer for section content */
449 	*dst_buff = calloc(1, section->size);
450 	if (!*dst_buff)
451 		return -ENOMEM;
452 
453 	/* fill buffer with section content */
454 	fseek(module->fd, section->off, SEEK_SET);
455 	read = fread(*dst_buff, 1, section->size, module->fd);
456 	if (read != section->size) {
457 		fprintf(stderr,
458 			"error: can't read %s section %d\n", section_name,
459 			-errno);
460 		free(*dst_buff);
461 		return -errno;
462 	}
463 
464 	return section->size;
465 }
466 
elf_read_module(struct elf_module * module,const char * name,bool verbose)467 int elf_read_module(struct elf_module *module, const char *name, bool verbose)
468 {
469 	int ret = 0;
470 
471 	/* open the elf input file */
472 	module->fd = fopen(name, "rb");
473 	if (!module->fd) {
474 		fprintf(stderr, "error: unable to open %s for reading: %s\n",
475 			name, strerror(errno));
476 		return -EINVAL;
477 	}
478 	module->elf_file = name;
479 
480 	/* get file size */
481 	ret = fseek(module->fd, 0, SEEK_END);
482 	if (ret < 0)
483 		goto hdr_err;
484 	module->file_size = ftell(module->fd);
485 	ret = fseek(module->fd, 0, SEEK_SET);
486 	if (ret < 0)
487 		goto hdr_err;
488 
489 	/* read in elf header */
490 	ret = elf_read_hdr(module, verbose);
491 	if (ret < 0)
492 		goto hdr_err;
493 
494 	/* read in programs */
495 	ret = elf_read_programs(module, verbose);
496 	if (ret < 0) {
497 		fprintf(stderr, "error: failed to read program sections %d\n",
498 			ret);
499 		goto hdr_err;
500 	}
501 
502 	/* read sections */
503 	ret = elf_read_sections(module, verbose);
504 	if (ret < 0) {
505 		fprintf(stderr, "error: failed to read base sections %d\n",
506 			ret);
507 		goto sec_err;
508 	}
509 
510 	elf_module_limits(module);
511 	elf_find_section(module, "");
512 
513 	fprintf(stdout, " module: input size %d (0x%x) bytes %d sections\n",
514 		module->fw_size, module->fw_size, module->num_sections);
515 	fprintf(stdout, " module: text %d (0x%x) bytes\n"
516 			"    data %d (0x%x) bytes\n"
517 			"    bss  %d (0x%x) bytes\n\n",
518 		module->text_size, module->text_size,
519 		module->data_size, module->data_size,
520 		module->bss_size, module->bss_size);
521 
522 	elf_validate_module(module);
523 
524 	return 0;
525 
526 sec_err:
527 	free(module->prg);
528 hdr_err:
529 	fclose(module->fd);
530 
531 	return ret;
532 }
533 
elf_free_module(struct elf_module * module)534 void elf_free_module(struct elf_module *module)
535 {
536 	free(module->prg);
537 	free(module->section);
538 	free(module->strings);
539 	if (module->fd)
540 		fclose(module->fd);
541 }
542