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