1 /*-
2 * Copyright (c) 2010,2011 Kai Wang
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/param.h>
28 #include <ctype.h>
29 #include <err.h>
30 #include <gelf.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include "elfcopy.h"
38
39 ELFTC_VCSID("$Id: ascii.c 3177 2015-03-30 18:19:41Z emaste $");
40
41 static void append_data(struct section *s, const void *buf, size_t sz);
42 static char hex_digit(uint8_t n);
43 static int hex_value(int x);
44 static void finalize_data_section(struct section *s);
45 static int ishexdigit(int x);
46 static int ihex_read(const char *line, char *type, uint64_t *addr,
47 uint64_t *num, uint8_t *data, size_t *sz);
48 static void ihex_write(int ofd, int type, uint64_t addr, uint64_t num,
49 const void *buf, size_t sz);
50 static void ihex_write_00(int ofd, uint64_t addr, const void *buf, size_t sz);
51 static void ihex_write_01(int ofd);
52 static void ihex_write_04(int ofd, uint16_t addr);
53 static void ihex_write_05(int ofd, uint64_t e_entry);
54 static struct section *new_data_section(struct elfcopy *ecp, int sec_index,
55 uint64_t off, uint64_t addr);
56 static int read_num(const char *line, int *len, uint64_t *num, size_t sz,
57 int *checksum);
58 static int srec_read(const char *line, char *type, uint64_t *addr,
59 uint8_t *data, size_t *sz);
60 static void srec_write(int ofd, char type, uint64_t addr, const void *buf,
61 size_t sz);
62 static void srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn,
63 GElf_Shdr *sh);
64 static void srec_write_S0(int ofd, const char *ofn);
65 static void srec_write_Sd(int ofd, char dr, uint64_t addr, const void *buf,
66 size_t sz, size_t rlen);
67 static void srec_write_Se(int ofd, uint64_t e_entry, int forceS3);
68 static void write_num(char *line, int *len, uint64_t num, size_t sz,
69 int *checksum);
70
71 #define _LINE_BUFSZ 1024
72 #define _DATA_BUFSZ 256
73
74 /*
75 * Convert ELF object to S-Record.
76 */
77 void
create_srec(struct elfcopy * ecp,int ifd,int ofd,const char * ofn)78 create_srec(struct elfcopy *ecp, int ifd, int ofd, const char *ofn)
79 {
80 Elf *e;
81 Elf_Scn *scn;
82 Elf_Data *d;
83 GElf_Ehdr eh;
84 GElf_Shdr sh;
85 uint64_t max_addr;
86 size_t rlen;
87 int elferr, addr_sz;
88 char dr;
89
90 if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
91 errx(EXIT_FAILURE, "elf_begin() failed: %s",
92 elf_errmsg(-1));
93
94 /* Output a symbol table for `symbolsrec' target. */
95 if (!strncmp(ecp->otgt, "symbolsrec", strlen("symbolsrec"))) {
96 scn = NULL;
97 while ((scn = elf_nextscn(e, scn)) != NULL) {
98 if (gelf_getshdr(scn, &sh) == NULL) {
99 warnx("gelf_getshdr failed: %s",
100 elf_errmsg(-1));
101 (void) elf_errno();
102 continue;
103 }
104 if (sh.sh_type != SHT_SYMTAB)
105 continue;
106 srec_write_symtab(ofd, ofn, e, scn, &sh);
107 break;
108 }
109 }
110
111 if (ecp->flags & SREC_FORCE_S3)
112 dr = '3';
113 else {
114 /*
115 * Find maximum address size in the first iteration.
116 */
117 max_addr = 0;
118 scn = NULL;
119 while ((scn = elf_nextscn(e, scn)) != NULL) {
120 if (gelf_getshdr(scn, &sh) == NULL) {
121 warnx("gelf_getshdr failed: %s",
122 elf_errmsg(-1));
123 (void) elf_errno();
124 continue;
125 }
126 if ((sh.sh_flags & SHF_ALLOC) == 0 ||
127 sh.sh_type == SHT_NOBITS ||
128 sh.sh_size == 0)
129 continue;
130 if ((uint64_t) sh.sh_addr > max_addr)
131 max_addr = sh.sh_addr;
132 }
133 elferr = elf_errno();
134 if (elferr != 0)
135 warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
136
137 if (max_addr <= 0xFFFF)
138 dr = '1';
139 else if (max_addr <= 0xFFFFFF)
140 dr = '2';
141 else
142 dr = '3';
143 }
144
145 if (ecp->flags & SREC_FORCE_LEN) {
146 addr_sz = dr - '0' + 1;
147 if (ecp->srec_len < 1)
148 rlen = 1;
149 else if (ecp->srec_len + addr_sz + 1 > 255)
150 rlen = 255 - (addr_sz + 1);
151 else
152 rlen = ecp->srec_len;
153 } else
154 rlen = 16;
155
156 /* Generate S0 record which contains the output filename. */
157 srec_write_S0(ofd, ofn);
158
159 /* Generate S{1,2,3} data records for section data. */
160 scn = NULL;
161 while ((scn = elf_nextscn(e, scn)) != NULL) {
162 if (gelf_getshdr(scn, &sh) == NULL) {
163 warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
164 (void) elf_errno();
165 continue;
166 }
167 if ((sh.sh_flags & SHF_ALLOC) == 0 ||
168 sh.sh_type == SHT_NOBITS ||
169 sh.sh_size == 0)
170 continue;
171 if (sh.sh_addr > 0xFFFFFFFF) {
172 warnx("address space too big for S-Record file");
173 continue;
174 }
175 (void) elf_errno();
176 if ((d = elf_getdata(scn, NULL)) == NULL) {
177 elferr = elf_errno();
178 if (elferr != 0)
179 warnx("elf_getdata failed: %s", elf_errmsg(-1));
180 continue;
181 }
182 if (d->d_buf == NULL || d->d_size == 0)
183 continue;
184 srec_write_Sd(ofd, dr, sh.sh_addr, d->d_buf, d->d_size, rlen);
185 }
186 elferr = elf_errno();
187 if (elferr != 0)
188 warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
189
190 /* Generate S{7,8,9} end of block recrod. */
191 if (gelf_getehdr(e, &eh) == NULL)
192 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
193 elf_errmsg(-1));
194 srec_write_Se(ofd, eh.e_entry, ecp->flags & SREC_FORCE_S3);
195 }
196
197 void
create_elf_from_srec(struct elfcopy * ecp,int ifd)198 create_elf_from_srec(struct elfcopy *ecp, int ifd)
199 {
200 char line[_LINE_BUFSZ], name[_LINE_BUFSZ];
201 uint8_t data[_DATA_BUFSZ];
202 GElf_Ehdr oeh;
203 struct section *s, *shtab;
204 FILE *ifp;
205 uint64_t addr, entry, off, sec_addr;
206 uintmax_t st_value;
207 size_t sz;
208 int _ifd, first, sec_index, in_symtab, symtab_created;
209 char *rlt;
210 char type;
211
212 if ((_ifd = dup(ifd)) < 0)
213 err(EXIT_FAILURE, "dup failed");
214 if ((ifp = fdopen(_ifd, "r")) == NULL)
215 err(EXIT_FAILURE, "fdopen failed");
216
217 /* Create EHDR for output .o file. */
218 if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
219 errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
220 elf_errmsg(-1));
221 if (gelf_getehdr(ecp->eout, &oeh) == NULL)
222 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
223 elf_errmsg(-1));
224
225 /* Initialise e_ident fields. */
226 oeh.e_ident[EI_CLASS] = ecp->oec;
227 oeh.e_ident[EI_DATA] = ecp->oed;
228 /*
229 * TODO: Set OSABI according to the OS platform where elfcopy(1)
230 * was build. (probably)
231 */
232 oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
233 oeh.e_machine = ecp->oem;
234 oeh.e_type = ET_REL;
235 oeh.e_entry = 0;
236
237 ecp->flags |= RELOCATABLE;
238
239 /* Create .shstrtab section */
240 init_shstrtab(ecp);
241 ecp->shstrtab->off = 0;
242
243 /* Data sections are inserted after EHDR. */
244 off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
245 if (off == 0)
246 errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
247
248 /* Create data sections. */
249 s = NULL;
250 first = 1;
251 sec_index = 1;
252 sec_addr = entry = 0;
253 while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
254 if (line[0] == '\r' || line[0] == '\n')
255 continue;
256 if (line[0] == '$' && line[1] == '$') {
257 ecp->flags |= SYMTAB_EXIST;
258 while ((rlt = fgets(line, _LINE_BUFSZ, ifp)) != NULL) {
259 if (line[0] == '$' && line[1] == '$')
260 break;
261 }
262 if (rlt == NULL)
263 break;
264 continue;
265 }
266 if (line[0] != 'S' || line[1] < '0' || line[1] > '9') {
267 warnx("Invalid srec record");
268 continue;
269 }
270 if (srec_read(line, &type, &addr, data, &sz) < 0) {
271 warnx("Invalid srec record or mismatched checksum");
272 continue;
273 }
274 switch (type) {
275 case '1':
276 case '2':
277 case '3':
278 if (sz == 0)
279 break;
280 if (first || sec_addr != addr) {
281 if (s != NULL)
282 finalize_data_section(s);
283 s = new_data_section(ecp, sec_index, off,
284 addr);
285 if (s == NULL) {
286 warnx("new_data_section failed");
287 break;
288 }
289 sec_index++;
290 sec_addr = addr;
291 first = 0;
292 }
293 append_data(s, data, sz);
294 off += sz;
295 sec_addr += sz;
296 break;
297 case '7':
298 case '8':
299 case '9':
300 entry = addr;
301 break;
302 default:
303 break;
304 }
305 }
306 if (s != NULL)
307 finalize_data_section(s);
308 if (ferror(ifp))
309 warn("fgets failed");
310
311 /* Insert .shstrtab after data sections. */
312 if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
313 errx(EXIT_FAILURE, "elf_newscn failed: %s",
314 elf_errmsg(-1));
315 insert_to_sec_list(ecp, ecp->shstrtab, 1);
316
317 /* Insert section header table here. */
318 shtab = insert_shtab(ecp, 1);
319
320 /*
321 * Rescan and create symbol table if we found '$$' section in
322 * the first scan.
323 */
324 symtab_created = 0;
325 in_symtab = 0;
326 if (ecp->flags & SYMTAB_EXIST) {
327 if (fseek(ifp, 0, SEEK_SET) < 0) {
328 warn("fseek failed");
329 ecp->flags &= ~SYMTAB_EXIST;
330 goto done;
331 }
332 while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
333 if (in_symtab) {
334 if (line[0] == '$' && line[1] == '$') {
335 in_symtab = 0;
336 continue;
337 }
338 if (sscanf(line, "%s $%jx", name,
339 &st_value) != 2) {
340 warnx("Invalid symbolsrec record");
341 continue;
342 }
343 if (!symtab_created) {
344 create_external_symtab(ecp);
345 symtab_created = 1;
346 }
347 add_to_symtab(ecp, name, st_value, 0, SHN_ABS,
348 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
349 }
350 if (line[0] == '$' && line[1] == '$') {
351 in_symtab = 1;
352 continue;
353 }
354 }
355 }
356 if (ferror(ifp))
357 warn("fgets failed");
358 if (symtab_created) {
359 finalize_external_symtab(ecp);
360 create_symtab_data(ecp);
361 /* Count in .symtab and .strtab section headers. */
362 shtab->sz += gelf_fsize(ecp->eout, ELF_T_SHDR, 2, EV_CURRENT);
363 } else
364 ecp->flags &= ~SYMTAB_EXIST;
365
366 done:
367 fclose(ifp);
368
369 /* Set entry point. */
370 oeh.e_entry = entry;
371
372 /*
373 * Write the underlying ehdr. Note that it should be called
374 * before elf_setshstrndx() since it will overwrite e->e_shstrndx.
375 */
376 if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
377 errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
378 elf_errmsg(-1));
379
380 /* Generate section name string table (.shstrtab). */
381 set_shstrtab(ecp);
382
383 /* Update sh_name pointer for each section header entry. */
384 update_shdr(ecp, 0);
385
386 /* Renew oeh to get the updated e_shstrndx. */
387 if (gelf_getehdr(ecp->eout, &oeh) == NULL)
388 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
389 elf_errmsg(-1));
390
391 /* Resync section offsets. */
392 resync_sections(ecp);
393
394 /* Store SHDR offset in EHDR. */
395 oeh.e_shoff = shtab->off;
396
397 /* Update ehdr since we modified e_shoff. */
398 if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
399 errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
400 elf_errmsg(-1));
401
402 /* Write out the output elf object. */
403 if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
404 errx(EXIT_FAILURE, "elf_update() failed: %s",
405 elf_errmsg(-1));
406
407 /* Release allocated resource. */
408 free_elf(ecp);
409 }
410
411 void
create_ihex(int ifd,int ofd)412 create_ihex(int ifd, int ofd)
413 {
414 Elf *e;
415 Elf_Scn *scn;
416 Elf_Data *d;
417 GElf_Ehdr eh;
418 GElf_Shdr sh;
419 int elferr;
420 uint16_t addr_hi, old_addr_hi;
421
422 if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
423 errx(EXIT_FAILURE, "elf_begin() failed: %s",
424 elf_errmsg(-1));
425
426 old_addr_hi = 0;
427 scn = NULL;
428 while ((scn = elf_nextscn(e, scn)) != NULL) {
429 if (gelf_getshdr(scn, &sh) == NULL) {
430 warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
431 (void) elf_errno();
432 continue;
433 }
434 if ((sh.sh_flags & SHF_ALLOC) == 0 ||
435 sh.sh_type == SHT_NOBITS ||
436 sh.sh_size == 0)
437 continue;
438 if (sh.sh_addr > 0xFFFFFFFF) {
439 warnx("address space too big for Intel Hex file");
440 continue;
441 }
442 (void) elf_errno();
443 if ((d = elf_getdata(scn, NULL)) == NULL) {
444 elferr = elf_errno();
445 if (elferr != 0)
446 warnx("elf_getdata failed: %s", elf_errmsg(-1));
447 continue;
448 }
449 if (d->d_buf == NULL || d->d_size == 0)
450 continue;
451 addr_hi = (sh.sh_addr >> 16) & 0xFFFF;
452 if (addr_hi > 0 && addr_hi != old_addr_hi) {
453 /* Write 04 record if addr_hi is new. */
454 old_addr_hi = addr_hi;
455 ihex_write_04(ofd, addr_hi);
456 }
457 ihex_write_00(ofd, sh.sh_addr, d->d_buf, d->d_size);
458 }
459 elferr = elf_errno();
460 if (elferr != 0)
461 warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
462
463 if (gelf_getehdr(e, &eh) == NULL)
464 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
465 elf_errmsg(-1));
466 ihex_write_05(ofd, eh.e_entry);
467 ihex_write_01(ofd);
468 }
469
470 void
create_elf_from_ihex(struct elfcopy * ecp,int ifd)471 create_elf_from_ihex(struct elfcopy *ecp, int ifd)
472 {
473 char line[_LINE_BUFSZ];
474 uint8_t data[_DATA_BUFSZ];
475 GElf_Ehdr oeh;
476 struct section *s, *shtab;
477 FILE *ifp;
478 uint64_t addr, addr_base, entry, num, off, rec_addr, sec_addr;
479 size_t sz;
480 int _ifd, first, sec_index;
481 char type;
482
483 if ((_ifd = dup(ifd)) < 0)
484 err(EXIT_FAILURE, "dup failed");
485 if ((ifp = fdopen(_ifd, "r")) == NULL)
486 err(EXIT_FAILURE, "fdopen failed");
487
488 /* Create EHDR for output .o file. */
489 if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
490 errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
491 elf_errmsg(-1));
492 if (gelf_getehdr(ecp->eout, &oeh) == NULL)
493 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
494 elf_errmsg(-1));
495
496 /* Initialise e_ident fields. */
497 oeh.e_ident[EI_CLASS] = ecp->oec;
498 oeh.e_ident[EI_DATA] = ecp->oed;
499 /*
500 * TODO: Set OSABI according to the OS platform where elfcopy(1)
501 * was build. (probably)
502 */
503 oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
504 oeh.e_machine = ecp->oem;
505 oeh.e_type = ET_REL;
506 oeh.e_entry = 0;
507
508 ecp->flags |= RELOCATABLE;
509
510 /* Create .shstrtab section */
511 init_shstrtab(ecp);
512 ecp->shstrtab->off = 0;
513
514 /* Data sections are inserted after EHDR. */
515 off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
516 if (off == 0)
517 errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
518
519 /* Create data sections. */
520 s = NULL;
521 first = 1;
522 sec_index = 1;
523 addr_base = rec_addr = sec_addr = entry = 0;
524 while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
525 if (line[0] == '\r' || line[0] == '\n')
526 continue;
527 if (line[0] != ':') {
528 warnx("Invalid ihex record");
529 continue;
530 }
531 if (ihex_read(line, &type, &addr, &num, data, &sz) < 0) {
532 warnx("Invalid ihex record or mismatched checksum");
533 continue;
534 }
535 switch (type) {
536 case '0':
537 /* Data record. */
538 if (sz == 0)
539 break;
540 rec_addr = addr_base + addr;
541 if (first || sec_addr != rec_addr) {
542 if (s != NULL)
543 finalize_data_section(s);
544 s = new_data_section(ecp, sec_index, off,
545 rec_addr);
546 if (s == NULL) {
547 warnx("new_data_section failed");
548 break;
549 }
550 sec_index++;
551 sec_addr = rec_addr;
552 first = 0;
553 }
554 append_data(s, data, sz);
555 off += sz;
556 sec_addr += sz;
557 break;
558 case '1':
559 /* End of file record. */
560 goto done;
561 case '2':
562 /* Extended segment address record. */
563 addr_base = addr << 4;
564 break;
565 case '3':
566 /* Start segment address record (CS:IP). Ignored. */
567 break;
568 case '4':
569 /* Extended linear address record. */
570 addr_base = num << 16;
571 break;
572 case '5':
573 /* Start linear address record. */
574 entry = num;
575 break;
576 default:
577 break;
578 }
579 }
580 done:
581 if (s != NULL)
582 finalize_data_section(s);
583 if (ferror(ifp))
584 warn("fgets failed");
585 fclose(ifp);
586
587 /* Insert .shstrtab after data sections. */
588 if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
589 errx(EXIT_FAILURE, "elf_newscn failed: %s",
590 elf_errmsg(-1));
591 insert_to_sec_list(ecp, ecp->shstrtab, 1);
592
593 /* Insert section header table here. */
594 shtab = insert_shtab(ecp, 1);
595
596 /* Set entry point. */
597 oeh.e_entry = entry;
598
599 /*
600 * Write the underlying ehdr. Note that it should be called
601 * before elf_setshstrndx() since it will overwrite e->e_shstrndx.
602 */
603 if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
604 errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
605 elf_errmsg(-1));
606
607 /* Generate section name string table (.shstrtab). */
608 set_shstrtab(ecp);
609
610 /* Update sh_name pointer for each section header entry. */
611 update_shdr(ecp, 0);
612
613 /* Renew oeh to get the updated e_shstrndx. */
614 if (gelf_getehdr(ecp->eout, &oeh) == NULL)
615 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
616 elf_errmsg(-1));
617
618 /* Resync section offsets. */
619 resync_sections(ecp);
620
621 /* Store SHDR offset in EHDR. */
622 oeh.e_shoff = shtab->off;
623
624 /* Update ehdr since we modified e_shoff. */
625 if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
626 errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
627 elf_errmsg(-1));
628
629 /* Write out the output elf object. */
630 if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
631 errx(EXIT_FAILURE, "elf_update() failed: %s",
632 elf_errmsg(-1));
633
634 /* Release allocated resource. */
635 free_elf(ecp);
636 }
637
638 #define _SEC_NAMESZ 64
639 #define _SEC_INIT_CAP 1024
640
641 static struct section *
new_data_section(struct elfcopy * ecp,int sec_index,uint64_t off,uint64_t addr)642 new_data_section(struct elfcopy *ecp, int sec_index, uint64_t off,
643 uint64_t addr)
644 {
645 char *name;
646
647 if ((name = malloc(_SEC_NAMESZ)) == NULL)
648 errx(EXIT_FAILURE, "malloc failed");
649 snprintf(name, _SEC_NAMESZ, ".sec%d", sec_index);
650
651 return (create_external_section(ecp, name, name, NULL, 0, off,
652 SHT_PROGBITS, ELF_T_BYTE, SHF_ALLOC | SHF_WRITE, 1, addr, 0));
653 }
654
655 static void
finalize_data_section(struct section * s)656 finalize_data_section(struct section *s)
657 {
658 Elf_Data *od;
659
660 if ((od = elf_newdata(s->os)) == NULL)
661 errx(EXIT_FAILURE, "elf_newdata() failed: %s",
662 elf_errmsg(-1));
663 od->d_align = s->align;
664 od->d_off = 0;
665 od->d_buf = s->buf;
666 od->d_size = s->sz;
667 od->d_version = EV_CURRENT;
668 }
669
670 static void
append_data(struct section * s,const void * buf,size_t sz)671 append_data(struct section *s, const void *buf, size_t sz)
672 {
673 uint8_t *p;
674
675 if (s->buf == NULL) {
676 s->sz = 0;
677 s->cap = _SEC_INIT_CAP;
678 if ((s->buf = malloc(s->cap)) == NULL)
679 err(EXIT_FAILURE, "malloc failed");
680 }
681
682 while (sz + s->sz > s->cap) {
683 s->cap *= 2;
684 if ((s->buf = realloc(s->buf, s->cap)) == NULL)
685 err(EXIT_FAILURE, "realloc failed");
686 }
687
688 p = s->buf;
689 memcpy(&p[s->sz], buf, sz);
690 s->sz += sz;
691 }
692
693 static int
srec_read(const char * line,char * type,uint64_t * addr,uint8_t * data,size_t * sz)694 srec_read(const char *line, char *type, uint64_t *addr, uint8_t *data,
695 size_t *sz)
696 {
697 uint64_t count, _checksum, num;
698 size_t addr_sz;
699 int checksum, i, len;
700
701 checksum = 0;
702 len = 2;
703 if (read_num(line, &len, &count, 1, &checksum) < 0)
704 return (-1);
705 *type = line[1];
706 switch (*type) {
707 case '0':
708 case '1':
709 case '5':
710 case '9':
711 addr_sz = 2;
712 break;
713 case '2':
714 case '8':
715 addr_sz = 3;
716 break;
717 case '3':
718 case '7':
719 addr_sz = 4;
720 break;
721 default:
722 return (-1);
723 }
724
725 if (read_num(line, &len, addr, addr_sz, &checksum) < 0)
726 return (-1);
727
728 count -= addr_sz + 1;
729 if (*type >= '0' && *type <= '3') {
730 for (i = 0; (uint64_t) i < count; i++) {
731 if (read_num(line, &len, &num, 1, &checksum) < 0)
732 return -1;
733 data[i] = (uint8_t) num;
734 }
735 *sz = count;
736 } else
737 *sz = 0;
738
739 if (read_num(line, &len, &_checksum, 1, NULL) < 0)
740 return (-1);
741
742 if ((int) _checksum != (~checksum & 0xFF))
743 return (-1);
744
745 return (0);
746 }
747
748 static void
srec_write_symtab(int ofd,const char * ofn,Elf * e,Elf_Scn * scn,GElf_Shdr * sh)749 srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn, GElf_Shdr *sh)
750 {
751 char line[_LINE_BUFSZ];
752 GElf_Sym sym;
753 Elf_Data *d;
754 const char *name;
755 size_t sc;
756 int elferr, i;
757
758 #define _WRITE_LINE do { \
759 if (write(ofd, line, strlen(line)) != (ssize_t) strlen(line)) \
760 errx(EXIT_FAILURE, "write failed"); \
761 } while (0)
762
763
764 (void) elf_errno();
765 if ((d = elf_getdata(scn, NULL)) == NULL) {
766 elferr = elf_errno();
767 if (elferr != 0)
768 warnx("elf_getdata failed: %s",
769 elf_errmsg(-1));
770 return;
771 }
772 if (d->d_buf == NULL || d->d_size == 0)
773 return;
774
775 snprintf(line, sizeof(line), "$$ %s\r\n", ofn);
776 _WRITE_LINE;
777 sc = d->d_size / sh->sh_entsize;
778 for (i = 1; (size_t) i < sc; i++) {
779 if (gelf_getsym(d, i, &sym) != &sym) {
780 warnx("gelf_getsym failed: %s", elf_errmsg(-1));
781 continue;
782 }
783 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION ||
784 GELF_ST_TYPE(sym.st_info) == STT_FILE)
785 continue;
786 if ((name = elf_strptr(e, sh->sh_link, sym.st_name)) == NULL) {
787 warnx("elf_strptr failed: %s", elf_errmsg(-1));
788 continue;
789 }
790 snprintf(line, sizeof(line), " %s $%jx\r\n", name,
791 (uintmax_t) sym.st_value);
792 _WRITE_LINE;
793 }
794 snprintf(line, sizeof(line), "$$ \r\n");
795 _WRITE_LINE;
796
797 #undef _WRITE_LINE
798 }
799
800 static void
srec_write_S0(int ofd,const char * ofn)801 srec_write_S0(int ofd, const char *ofn)
802 {
803
804 srec_write(ofd, '0', 0, ofn, strlen(ofn));
805 }
806
807 static void
srec_write_Sd(int ofd,char dr,uint64_t addr,const void * buf,size_t sz,size_t rlen)808 srec_write_Sd(int ofd, char dr, uint64_t addr, const void *buf, size_t sz,
809 size_t rlen)
810 {
811 const uint8_t *p, *pe;
812
813 p = buf;
814 pe = p + sz;
815 while (pe - p >= (int) rlen) {
816 srec_write(ofd, dr, addr, p, rlen);
817 addr += rlen;
818 p += rlen;
819 }
820 if (pe - p > 0)
821 srec_write(ofd, dr, addr, p, pe - p);
822 }
823
824 static void
srec_write_Se(int ofd,uint64_t e_entry,int forceS3)825 srec_write_Se(int ofd, uint64_t e_entry, int forceS3)
826 {
827 char er;
828
829 if (e_entry > 0xFFFFFFFF) {
830 warnx("address space too big for S-Record file");
831 return;
832 }
833
834 if (forceS3)
835 er = '7';
836 else {
837 if (e_entry <= 0xFFFF)
838 er = '9';
839 else if (e_entry <= 0xFFFFFF)
840 er = '8';
841 else
842 er = '7';
843 }
844
845 srec_write(ofd, er, e_entry, NULL, 0);
846 }
847
848 static void
srec_write(int ofd,char type,uint64_t addr,const void * buf,size_t sz)849 srec_write(int ofd, char type, uint64_t addr, const void *buf, size_t sz)
850 {
851 char line[_LINE_BUFSZ];
852 const uint8_t *p, *pe;
853 int len, addr_sz, checksum;
854
855 if (type == '0' || type == '1' || type == '5' || type == '9')
856 addr_sz = 2;
857 else if (type == '2' || type == '8')
858 addr_sz = 3;
859 else
860 addr_sz = 4;
861
862 checksum = 0;
863 line[0] = 'S';
864 line[1] = type;
865 len = 2;
866 write_num(line, &len, addr_sz + sz + 1, 1, &checksum);
867 write_num(line, &len, addr, addr_sz, &checksum);
868 for (p = buf, pe = p + sz; p < pe; p++)
869 write_num(line, &len, *p, 1, &checksum);
870 write_num(line, &len, ~checksum & 0xFF, 1, NULL);
871 line[len++] = '\r';
872 line[len++] = '\n';
873 if (write(ofd, line, len) != (ssize_t) len)
874 err(EXIT_FAILURE, "write failed");
875 }
876
877 static void
ihex_write_00(int ofd,uint64_t addr,const void * buf,size_t sz)878 ihex_write_00(int ofd, uint64_t addr, const void *buf, size_t sz)
879 {
880 uint16_t addr_hi, old_addr_hi;
881 const uint8_t *p, *pe;
882
883 old_addr_hi = (addr >> 16) & 0xFFFF;
884 p = buf;
885 pe = p + sz;
886 while (pe - p >= 16) {
887 ihex_write(ofd, 0, addr, 0, p, 16);
888 addr += 16;
889 p += 16;
890 addr_hi = (addr >> 16) & 0xFFFF;
891 if (addr_hi != old_addr_hi) {
892 old_addr_hi = addr_hi;
893 ihex_write_04(ofd, addr_hi);
894 }
895 }
896 if (pe - p > 0)
897 ihex_write(ofd, 0, addr, 0, p, pe - p);
898 }
899
900 static int
ihex_read(const char * line,char * type,uint64_t * addr,uint64_t * num,uint8_t * data,size_t * sz)901 ihex_read(const char *line, char *type, uint64_t *addr, uint64_t *num,
902 uint8_t *data, size_t *sz)
903 {
904 uint64_t count, _checksum;
905 int checksum, i, len;
906
907 *sz = 0;
908 checksum = 0;
909 len = 1;
910 if (read_num(line, &len, &count, 1, &checksum) < 0)
911 return (-1);
912 if (read_num(line, &len, addr, 2, &checksum) < 0)
913 return (-1);
914 if (line[len++] != '0')
915 return (-1);
916 *type = line[len++];
917 checksum += *type - '0';
918 switch (*type) {
919 case '0':
920 for (i = 0; (uint64_t) i < count; i++) {
921 if (read_num(line, &len, num, 1, &checksum) < 0)
922 return (-1);
923 data[i] = (uint8_t) *num;
924 }
925 *sz = count;
926 break;
927 case '1':
928 if (count != 0)
929 return (-1);
930 break;
931 case '2':
932 case '4':
933 if (count != 2)
934 return (-1);
935 if (read_num(line, &len, num, 2, &checksum) < 0)
936 return (-1);
937 break;
938 case '3':
939 case '5':
940 if (count != 4)
941 return (-1);
942 if (read_num(line, &len, num, 4, &checksum) < 0)
943 return (-1);
944 break;
945 default:
946 return (-1);
947 }
948
949 if (read_num(line, &len, &_checksum, 1, &checksum) < 0)
950 return (-1);
951
952 if ((checksum & 0xFF) != 0) {
953 return (-1);
954 }
955
956 return (0);
957 }
958
959 static void
ihex_write_01(int ofd)960 ihex_write_01(int ofd)
961 {
962
963 ihex_write(ofd, 1, 0, 0, NULL, 0);
964 }
965
966 static void
ihex_write_04(int ofd,uint16_t addr)967 ihex_write_04(int ofd, uint16_t addr)
968 {
969
970 ihex_write(ofd, 4, 0, addr, NULL, 2);
971 }
972
973 static void
ihex_write_05(int ofd,uint64_t e_entry)974 ihex_write_05(int ofd, uint64_t e_entry)
975 {
976
977 if (e_entry > 0xFFFFFFFF) {
978 warnx("address space too big for Intel Hex file");
979 return;
980 }
981
982 ihex_write(ofd, 5, 0, e_entry, NULL, 4);
983 }
984
985 static void
ihex_write(int ofd,int type,uint64_t addr,uint64_t num,const void * buf,size_t sz)986 ihex_write(int ofd, int type, uint64_t addr, uint64_t num, const void *buf,
987 size_t sz)
988 {
989 char line[_LINE_BUFSZ];
990 const uint8_t *p, *pe;
991 int len, checksum;
992
993 if (sz > 16)
994 errx(EXIT_FAILURE, "Internal: ihex_write() sz too big");
995 checksum = 0;
996 line[0] = ':';
997 len = 1;
998 write_num(line, &len, sz, 1, &checksum);
999 write_num(line, &len, addr, 2, &checksum);
1000 write_num(line, &len, type, 1, &checksum);
1001 if (sz > 0) {
1002 if (buf != NULL) {
1003 for (p = buf, pe = p + sz; p < pe; p++)
1004 write_num(line, &len, *p, 1, &checksum);
1005 } else
1006 write_num(line, &len, num, sz, &checksum);
1007 }
1008 write_num(line, &len, (~checksum + 1) & 0xFF, 1, NULL);
1009 line[len++] = '\r';
1010 line[len++] = '\n';
1011 if (write(ofd, line, len) != (ssize_t) len)
1012 err(EXIT_FAILURE, "write failed");
1013 }
1014
1015 static int
read_num(const char * line,int * len,uint64_t * num,size_t sz,int * checksum)1016 read_num(const char *line, int *len, uint64_t *num, size_t sz, int *checksum)
1017 {
1018 uint8_t b;
1019
1020 *num = 0;
1021 for (; sz > 0; sz--) {
1022 if (!ishexdigit(line[*len]) || !ishexdigit(line[*len + 1]))
1023 return (-1);
1024 b = (hex_value(line[*len]) << 4) | hex_value(line[*len + 1]);
1025 *num = (*num << 8) | b;
1026 *len += 2;
1027 if (checksum != NULL)
1028 *checksum = (*checksum + b) & 0xFF;
1029 }
1030
1031 return (0);
1032 }
1033
1034 static void
write_num(char * line,int * len,uint64_t num,size_t sz,int * checksum)1035 write_num(char *line, int *len, uint64_t num, size_t sz, int *checksum)
1036 {
1037 uint8_t b;
1038
1039 for (; sz > 0; sz--) {
1040 b = (num >> ((sz - 1) * 8)) & 0xFF;
1041 line[*len] = hex_digit((b >> 4) & 0xF);
1042 line[*len + 1] = hex_digit(b & 0xF);
1043 *len += 2;
1044 if (checksum != NULL)
1045 *checksum = (*checksum + b) & 0xFF;
1046 }
1047 }
1048
1049 static char
hex_digit(uint8_t n)1050 hex_digit(uint8_t n)
1051 {
1052
1053 return ((n < 10) ? '0' + n : 'A' + (n - 10));
1054 }
1055
1056 static int
hex_value(int x)1057 hex_value(int x)
1058 {
1059
1060 if (isdigit(x))
1061 return (x - '0');
1062 else if (x >= 'a' && x <= 'f')
1063 return (x - 'a' + 10);
1064 else
1065 return (x - 'A' + 10);
1066 }
1067
1068 static int
ishexdigit(int x)1069 ishexdigit(int x)
1070 {
1071
1072 if (isdigit(x))
1073 return (1);
1074 if ((x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F'))
1075 return (1);
1076
1077 return (0);
1078 }
1079