xref: /freebsd/contrib/elftoolchain/elfcopy/ascii.c (revision 907b59d76938e654f0d040a888e8dfca3de1e222)
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 3446 2016-05-03 01:31:17Z 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
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 record. */
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
960 ihex_write_01(int ofd)
961 {
962 
963 	ihex_write(ofd, 1, 0, 0, NULL, 0);
964 }
965 
966 static void
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
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
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
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
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
1050 hex_digit(uint8_t n)
1051 {
1052 
1053 	return ((n < 10) ? '0' + n : 'A' + (n - 10));
1054 }
1055 
1056 static int
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
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