xref: /freebsd/contrib/elftoolchain/elfcopy/ascii.c (revision cddbc3b40812213ff00041f79174cac0be360a2a)
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 3487 2016-08-24 18:12:08Z 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 		sz = 0;
255 		if (line[0] == '\r' || line[0] == '\n')
256 			continue;
257 		if (line[0] == '$' && line[1] == '$') {
258 			ecp->flags |= SYMTAB_EXIST;
259 			while ((rlt = fgets(line, _LINE_BUFSZ, ifp)) != NULL) {
260 				if (line[0] == '$' && line[1] == '$')
261 					break;
262 			}
263 			if (rlt == NULL)
264 				break;
265 			continue;
266 		}
267 		if (line[0] != 'S' || line[1] < '0' || line[1] > '9') {
268 			warnx("Invalid srec record");
269 			continue;
270 		}
271 		if (srec_read(line, &type, &addr, data, &sz) < 0) {
272 			warnx("Invalid srec record or mismatched checksum");
273 			continue;
274 		}
275 		switch (type) {
276 		case '1':
277 		case '2':
278 		case '3':
279 			if (sz == 0)
280 				break;
281 			if (first || sec_addr != addr) {
282 				if (s != NULL)
283 					finalize_data_section(s);
284 				s = new_data_section(ecp, sec_index, off,
285 				    addr);
286 				if (s == NULL) {
287 					warnx("new_data_section failed");
288 					break;
289 				}
290 				sec_index++;
291 				sec_addr = addr;
292 				first = 0;
293 			}
294 			append_data(s, data, sz);
295 			off += sz;
296 			sec_addr += sz;
297 			break;
298 		case '7':
299 		case '8':
300 		case '9':
301 			entry = addr;
302 			break;
303 		default:
304 			break;
305 		}
306 	}
307 	if (s != NULL)
308 		finalize_data_section(s);
309 	if (ferror(ifp))
310 		warn("fgets failed");
311 
312 	/* Insert .shstrtab after data sections. */
313 	if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
314 		errx(EXIT_FAILURE, "elf_newscn failed: %s",
315 		    elf_errmsg(-1));
316 	insert_to_sec_list(ecp, ecp->shstrtab, 1);
317 
318 	/* Insert section header table here. */
319 	shtab = insert_shtab(ecp, 1);
320 
321 	/*
322 	 * Rescan and create symbol table if we found '$$' section in
323 	 * the first scan.
324 	 */
325 	symtab_created = 0;
326 	in_symtab = 0;
327 	if (ecp->flags & SYMTAB_EXIST) {
328 		if (fseek(ifp, 0, SEEK_SET) < 0) {
329 			warn("fseek failed");
330 			ecp->flags &= ~SYMTAB_EXIST;
331 			goto done;
332 		}
333 		while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
334 			if (in_symtab) {
335 				if (line[0] == '$' && line[1] == '$') {
336 					in_symtab = 0;
337 					continue;
338 				}
339 				if (sscanf(line, "%s $%jx", name,
340 				    &st_value) != 2) {
341 					warnx("Invalid symbolsrec record");
342 					continue;
343 				}
344 				if (!symtab_created) {
345 					create_external_symtab(ecp);
346 					symtab_created = 1;
347 				}
348 				add_to_symtab(ecp, name, st_value, 0, SHN_ABS,
349 				    ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
350 			}
351 			if (line[0] == '$' && line[1] == '$') {
352 				in_symtab = 1;
353 				continue;
354 			}
355 		}
356 	}
357 	if (ferror(ifp))
358 		warn("fgets failed");
359 	if (symtab_created) {
360 		finalize_external_symtab(ecp);
361 		create_symtab_data(ecp);
362 		/* Count in .symtab and .strtab section headers.  */
363 		shtab->sz += gelf_fsize(ecp->eout, ELF_T_SHDR, 2, EV_CURRENT);
364 	} else
365 		ecp->flags &= ~SYMTAB_EXIST;
366 
367 done:
368 	fclose(ifp);
369 
370 	/* Set entry point. */
371 	oeh.e_entry = entry;
372 
373 	/*
374 	 * Write the underlying ehdr. Note that it should be called
375 	 * before elf_setshstrndx() since it will overwrite e->e_shstrndx.
376 	 */
377 	if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
378 		errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
379 		    elf_errmsg(-1));
380 
381 	/* Generate section name string table (.shstrtab). */
382 	set_shstrtab(ecp);
383 
384 	/* Update sh_name pointer for each section header entry. */
385 	update_shdr(ecp, 0);
386 
387 	/* Renew oeh to get the updated e_shstrndx. */
388 	if (gelf_getehdr(ecp->eout, &oeh) == NULL)
389 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
390 		    elf_errmsg(-1));
391 
392 	/* Resync section offsets. */
393 	resync_sections(ecp);
394 
395 	/* Store SHDR offset in EHDR. */
396 	oeh.e_shoff = shtab->off;
397 
398 	/* Update ehdr since we modified e_shoff. */
399 	if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
400 		errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
401 		    elf_errmsg(-1));
402 
403 	/* Write out the output elf object. */
404 	if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
405 		errx(EXIT_FAILURE, "elf_update() failed: %s",
406 		    elf_errmsg(-1));
407 
408 	/* Release allocated resource. */
409 	free_elf(ecp);
410 }
411 
412 void
413 create_ihex(int ifd, int ofd)
414 {
415 	Elf *e;
416 	Elf_Scn *scn;
417 	Elf_Data *d;
418 	GElf_Ehdr eh;
419 	GElf_Shdr sh;
420 	int elferr;
421 	uint16_t addr_hi, old_addr_hi;
422 
423 	if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
424 		errx(EXIT_FAILURE, "elf_begin() failed: %s",
425 		    elf_errmsg(-1));
426 
427 	old_addr_hi = 0;
428 	scn = NULL;
429 	while ((scn = elf_nextscn(e, scn)) != NULL) {
430 		if (gelf_getshdr(scn, &sh) == NULL) {
431 			warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
432 			(void) elf_errno();
433 			continue;
434 		}
435 		if ((sh.sh_flags & SHF_ALLOC) == 0 ||
436 		    sh.sh_type == SHT_NOBITS ||
437 		    sh.sh_size == 0)
438 			continue;
439 		if (sh.sh_addr > 0xFFFFFFFF) {
440 			warnx("address space too big for Intel Hex file");
441 			continue;
442 		}
443 		(void) elf_errno();
444 		if ((d = elf_getdata(scn, NULL)) == NULL) {
445 			elferr = elf_errno();
446 			if (elferr != 0)
447 				warnx("elf_getdata failed: %s", elf_errmsg(-1));
448 			continue;
449 		}
450 		if (d->d_buf == NULL || d->d_size == 0)
451 			continue;
452 		addr_hi = (sh.sh_addr >> 16) & 0xFFFF;
453 		if (addr_hi > 0 && addr_hi != old_addr_hi) {
454 			/* Write 04 record if addr_hi is new. */
455 			old_addr_hi = addr_hi;
456 			ihex_write_04(ofd, addr_hi);
457 		}
458 		ihex_write_00(ofd, sh.sh_addr, d->d_buf, d->d_size);
459 	}
460 	elferr = elf_errno();
461 	if (elferr != 0)
462 		warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
463 
464 	if (gelf_getehdr(e, &eh) == NULL)
465 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
466 		    elf_errmsg(-1));
467 	ihex_write_05(ofd, eh.e_entry);
468 	ihex_write_01(ofd);
469 }
470 
471 void
472 create_elf_from_ihex(struct elfcopy *ecp, int ifd)
473 {
474 	char line[_LINE_BUFSZ];
475 	uint8_t data[_DATA_BUFSZ];
476 	GElf_Ehdr oeh;
477 	struct section *s, *shtab;
478 	FILE *ifp;
479 	uint64_t addr, addr_base, entry, num, off, rec_addr, sec_addr;
480 	size_t sz;
481 	int _ifd, first, sec_index;
482 	char type;
483 
484 	if ((_ifd = dup(ifd)) < 0)
485 		err(EXIT_FAILURE, "dup failed");
486 	if ((ifp = fdopen(_ifd, "r")) == NULL)
487 		err(EXIT_FAILURE, "fdopen failed");
488 
489 	/* Create EHDR for output .o file. */
490 	if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
491 		errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
492 		    elf_errmsg(-1));
493 	if (gelf_getehdr(ecp->eout, &oeh) == NULL)
494 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
495 		    elf_errmsg(-1));
496 
497 	/* Initialise e_ident fields. */
498 	oeh.e_ident[EI_CLASS] = ecp->oec;
499 	oeh.e_ident[EI_DATA] = ecp->oed;
500 	/*
501 	 * TODO: Set OSABI according to the OS platform where elfcopy(1)
502 	 * was build. (probably)
503 	 */
504 	oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
505 	oeh.e_machine = ecp->oem;
506 	oeh.e_type = ET_REL;
507 	oeh.e_entry = 0;
508 
509 	ecp->flags |= RELOCATABLE;
510 
511 	/* Create .shstrtab section */
512 	init_shstrtab(ecp);
513 	ecp->shstrtab->off = 0;
514 
515 	/* Data sections are inserted after EHDR. */
516 	off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
517 	if (off == 0)
518 		errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
519 
520 	/* Create data sections. */
521 	s = NULL;
522 	first = 1;
523 	sec_index = 1;
524 	addr_base = rec_addr = sec_addr = entry = 0;
525 	while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
526 		if (line[0] == '\r' || line[0] == '\n')
527 			continue;
528 		if (line[0] != ':') {
529 			warnx("Invalid ihex record");
530 			continue;
531 		}
532 		if (ihex_read(line, &type, &addr, &num, data, &sz) < 0) {
533 			warnx("Invalid ihex record or mismatched checksum");
534 			continue;
535 		}
536 		switch (type) {
537 		case '0':
538 			/* Data record. */
539 			if (sz == 0)
540 				break;
541 			rec_addr = addr_base + addr;
542 			if (first || sec_addr != rec_addr) {
543 				if (s != NULL)
544 					finalize_data_section(s);
545 				s = new_data_section(ecp, sec_index, off,
546 				    rec_addr);
547 				if (s == NULL) {
548 					warnx("new_data_section failed");
549 					break;
550 				}
551 				sec_index++;
552 				sec_addr = rec_addr;
553 				first = 0;
554 			}
555 			append_data(s, data, sz);
556 			off += sz;
557 			sec_addr += sz;
558 			break;
559 		case '1':
560 			/* End of file record. */
561 			goto done;
562 		case '2':
563 			/* Extended segment address record. */
564 			addr_base = addr << 4;
565 			break;
566 		case '3':
567 			/* Start segment address record (CS:IP). Ignored. */
568 			break;
569 		case '4':
570 			/* Extended linear address record. */
571 			addr_base = num << 16;
572 			break;
573 		case '5':
574 			/* Start linear address record. */
575 			entry = num;
576 			break;
577 		default:
578 			break;
579 		}
580 	}
581 done:
582 	if (s != NULL)
583 		finalize_data_section(s);
584 	if (ferror(ifp))
585 		warn("fgets failed");
586 	fclose(ifp);
587 
588 	/* Insert .shstrtab after data sections. */
589 	if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
590 		errx(EXIT_FAILURE, "elf_newscn failed: %s",
591 		    elf_errmsg(-1));
592 	insert_to_sec_list(ecp, ecp->shstrtab, 1);
593 
594 	/* Insert section header table here. */
595 	shtab = insert_shtab(ecp, 1);
596 
597 	/* Set entry point. */
598 	oeh.e_entry = entry;
599 
600 	/*
601 	 * Write the underlying ehdr. Note that it should be called
602 	 * before elf_setshstrndx() since it will overwrite e->e_shstrndx.
603 	 */
604 	if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
605 		errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
606 		    elf_errmsg(-1));
607 
608 	/* Generate section name string table (.shstrtab). */
609 	set_shstrtab(ecp);
610 
611 	/* Update sh_name pointer for each section header entry. */
612 	update_shdr(ecp, 0);
613 
614 	/* Renew oeh to get the updated e_shstrndx. */
615 	if (gelf_getehdr(ecp->eout, &oeh) == NULL)
616 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
617 		    elf_errmsg(-1));
618 
619 	/* Resync section offsets. */
620 	resync_sections(ecp);
621 
622 	/* Store SHDR offset in EHDR. */
623 	oeh.e_shoff = shtab->off;
624 
625 	/* Update ehdr since we modified e_shoff. */
626 	if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
627 		errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
628 		    elf_errmsg(-1));
629 
630 	/* Write out the output elf object. */
631 	if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
632 		errx(EXIT_FAILURE, "elf_update() failed: %s",
633 		    elf_errmsg(-1));
634 
635 	/* Release allocated resource. */
636 	free_elf(ecp);
637 }
638 
639 #define	_SEC_NAMESZ	64
640 #define	_SEC_INIT_CAP	1024
641 
642 static struct section *
643 new_data_section(struct elfcopy *ecp, int sec_index, uint64_t off,
644     uint64_t addr)
645 {
646 	char *name;
647 
648 	if ((name = malloc(_SEC_NAMESZ)) == NULL)
649 		errx(EXIT_FAILURE, "malloc failed");
650 	snprintf(name, _SEC_NAMESZ, ".sec%d", sec_index);
651 
652 	return (create_external_section(ecp, name, name, NULL, 0, off,
653 		SHT_PROGBITS, ELF_T_BYTE, SHF_ALLOC | SHF_WRITE, 1, addr, 0));
654 }
655 
656 static void
657 finalize_data_section(struct section *s)
658 {
659 	Elf_Data *od;
660 
661 	if ((od = elf_newdata(s->os)) == NULL)
662 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
663 		    elf_errmsg(-1));
664 	od->d_align = s->align;
665 	od->d_off = 0;
666 	od->d_buf = s->buf;
667 	od->d_size = s->sz;
668 	od->d_version = EV_CURRENT;
669 }
670 
671 static void
672 append_data(struct section *s, const void *buf, size_t sz)
673 {
674 	uint8_t *p;
675 
676 	if (s->buf == NULL) {
677 		s->sz = 0;
678 		s->cap = _SEC_INIT_CAP;
679 		if ((s->buf = malloc(s->cap)) == NULL)
680 			err(EXIT_FAILURE, "malloc failed");
681 	}
682 
683 	while (sz + s->sz > s->cap) {
684 		s->cap *= 2;
685 		if ((s->buf = realloc(s->buf, s->cap)) == NULL)
686 			err(EXIT_FAILURE, "realloc failed");
687 	}
688 
689 	p = s->buf;
690 	memcpy(&p[s->sz], buf, sz);
691 	s->sz += sz;
692 }
693 
694 static int
695 srec_read(const char *line, char *type, uint64_t *addr, uint8_t *data,
696     size_t *sz)
697 {
698 	uint64_t count, _checksum, num;
699 	size_t addr_sz;
700 	int checksum, i, len;
701 
702 	checksum = 0;
703 	len = 2;
704 	if (read_num(line, &len, &count, 1, &checksum) < 0)
705 		return (-1);
706 	*type = line[1];
707 	switch (*type) {
708 	case '0':
709 	case '1':
710 	case '5':
711 	case '9':
712 		addr_sz = 2;
713 		break;
714 	case '2':
715 	case '8':
716 		addr_sz = 3;
717 		break;
718 	case '3':
719 	case '7':
720 		addr_sz = 4;
721 		break;
722 	default:
723 		return (-1);
724 	}
725 
726 	if (read_num(line, &len, addr, addr_sz, &checksum) < 0)
727 		return (-1);
728 
729 	count -= addr_sz + 1;
730 	if (*type >= '0' && *type <= '3') {
731 		for (i = 0; (uint64_t) i < count; i++) {
732 			if (read_num(line, &len, &num, 1, &checksum) < 0)
733 				return -1;
734 			data[i] = (uint8_t) num;
735 		}
736 		*sz = count;
737 	} else
738 		*sz = 0;
739 
740 	if (read_num(line, &len, &_checksum, 1, NULL) < 0)
741 		return (-1);
742 
743 	if ((int) _checksum != (~checksum & 0xFF))
744 		return (-1);
745 
746 	return (0);
747 }
748 
749 static void
750 srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn, GElf_Shdr *sh)
751 {
752 	char line[_LINE_BUFSZ];
753 	GElf_Sym sym;
754 	Elf_Data *d;
755 	const char *name;
756 	size_t sc;
757 	int elferr, i;
758 
759 #define _WRITE_LINE do {						\
760 	if (write(ofd, line, strlen(line)) != (ssize_t) strlen(line)) 	\
761 		errx(EXIT_FAILURE, "write failed");				\
762 	} while (0)
763 
764 
765 	(void) elf_errno();
766 	if ((d = elf_getdata(scn, NULL)) == NULL) {
767 		elferr = elf_errno();
768 		if (elferr != 0)
769 			warnx("elf_getdata failed: %s",
770 			    elf_errmsg(-1));
771 		return;
772 	}
773 	if (d->d_buf == NULL || d->d_size == 0)
774 		return;
775 
776 	snprintf(line, sizeof(line), "$$ %s\r\n", ofn);
777 	_WRITE_LINE;
778 	sc = d->d_size / sh->sh_entsize;
779 	for (i = 1; (size_t) i < sc; i++) {
780 		if (gelf_getsym(d, i, &sym) != &sym) {
781 			warnx("gelf_getsym failed: %s", elf_errmsg(-1));
782 			continue;
783 		}
784 		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION ||
785 		    GELF_ST_TYPE(sym.st_info) == STT_FILE)
786 			continue;
787 		if ((name = elf_strptr(e, sh->sh_link, sym.st_name)) == NULL) {
788 			warnx("elf_strptr failed: %s", elf_errmsg(-1));
789 			continue;
790 		}
791 		snprintf(line, sizeof(line), "  %s $%jx\r\n", name,
792 		    (uintmax_t) sym.st_value);
793 		_WRITE_LINE;
794 	}
795 	snprintf(line, sizeof(line), "$$ \r\n");
796 	_WRITE_LINE;
797 
798 #undef	_WRITE_LINE
799 }
800 
801 static void
802 srec_write_S0(int ofd, const char *ofn)
803 {
804 
805 	srec_write(ofd, '0', 0, ofn, strlen(ofn));
806 }
807 
808 static void
809 srec_write_Sd(int ofd, char dr, uint64_t addr, const void *buf, size_t sz,
810     size_t rlen)
811 {
812 	const uint8_t *p, *pe;
813 
814 	p = buf;
815 	pe = p + sz;
816 	while (pe - p >= (int) rlen) {
817 		srec_write(ofd, dr, addr, p, rlen);
818 		addr += rlen;
819 		p += rlen;
820 	}
821 	if (pe - p > 0)
822 		srec_write(ofd, dr, addr, p, pe - p);
823 }
824 
825 static void
826 srec_write_Se(int ofd, uint64_t e_entry, int forceS3)
827 {
828 	char er;
829 
830 	if (e_entry > 0xFFFFFFFF) {
831 		warnx("address space too big for S-Record file");
832 		return;
833 	}
834 
835 	if (forceS3)
836 		er = '7';
837 	else {
838 		if (e_entry <= 0xFFFF)
839 			er = '9';
840 		else if (e_entry <= 0xFFFFFF)
841 			er = '8';
842 		else
843 			er = '7';
844 	}
845 
846 	srec_write(ofd, er, e_entry, NULL, 0);
847 }
848 
849 static void
850 srec_write(int ofd, char type, uint64_t addr, const void *buf, size_t sz)
851 {
852 	char line[_LINE_BUFSZ];
853 	const uint8_t *p, *pe;
854 	int len, addr_sz, checksum;
855 
856 	if (type == '0' || type == '1' || type == '5' || type == '9')
857 		addr_sz = 2;
858 	else if (type == '2' || type == '8')
859 		addr_sz = 3;
860 	else
861 		addr_sz = 4;
862 
863 	checksum = 0;
864 	line[0] = 'S';
865 	line[1] = type;
866 	len = 2;
867 	write_num(line, &len, addr_sz + sz + 1, 1, &checksum);
868 	write_num(line, &len, addr, addr_sz, &checksum);
869 	for (p = buf, pe = p + sz; p < pe; p++)
870 		write_num(line, &len, *p, 1, &checksum);
871 	write_num(line, &len, ~checksum & 0xFF, 1, NULL);
872 	line[len++] = '\r';
873 	line[len++] = '\n';
874 	if (write(ofd, line, len) != (ssize_t) len)
875 		err(EXIT_FAILURE, "write failed");
876 }
877 
878 static void
879 ihex_write_00(int ofd, uint64_t addr, const void *buf, size_t sz)
880 {
881 	uint16_t addr_hi, old_addr_hi;
882 	const uint8_t *p, *pe;
883 
884 	old_addr_hi = (addr >> 16) & 0xFFFF;
885 	p = buf;
886 	pe = p + sz;
887 	while (pe - p >= 16) {
888 		ihex_write(ofd, 0, addr, 0, p, 16);
889 		addr += 16;
890 		p += 16;
891 		addr_hi = (addr >> 16) & 0xFFFF;
892 		if (addr_hi != old_addr_hi) {
893 			old_addr_hi = addr_hi;
894 			ihex_write_04(ofd, addr_hi);
895 		}
896 	}
897 	if (pe - p > 0)
898 		ihex_write(ofd, 0, addr, 0, p, pe - p);
899 }
900 
901 static int
902 ihex_read(const char *line, char *type, uint64_t *addr, uint64_t *num,
903     uint8_t *data, size_t *sz)
904 {
905 	uint64_t count, _checksum;
906 	int checksum, i, len;
907 
908 	*sz = 0;
909 	checksum = 0;
910 	len = 1;
911 	if (read_num(line, &len, &count, 1, &checksum) < 0)
912 		return (-1);
913 	if (read_num(line, &len, addr, 2, &checksum) < 0)
914 		return (-1);
915 	if (line[len++] != '0')
916 		return (-1);
917 	*type = line[len++];
918 	checksum += *type - '0';
919 	switch (*type) {
920 	case '0':
921 		for (i = 0; (uint64_t) i < count; i++) {
922 			if (read_num(line, &len, num, 1, &checksum) < 0)
923 				return (-1);
924 			data[i] = (uint8_t) *num;
925 		}
926 		*sz = count;
927 		break;
928 	case '1':
929 		if (count != 0)
930 			return (-1);
931 		break;
932 	case '2':
933 	case '4':
934 		if (count != 2)
935 			return (-1);
936 		if (read_num(line, &len, num, 2, &checksum) < 0)
937 			return (-1);
938 		break;
939 	case '3':
940 	case '5':
941 		if (count != 4)
942 			return (-1);
943 		if (read_num(line, &len, num, 4, &checksum) < 0)
944 			return (-1);
945 		break;
946 	default:
947 		return (-1);
948 	}
949 
950 	if (read_num(line, &len, &_checksum, 1, &checksum) < 0)
951 		return (-1);
952 
953 	if ((checksum & 0xFF) != 0) {
954 		return (-1);
955 	}
956 
957 	return (0);
958 }
959 
960 static void
961 ihex_write_01(int ofd)
962 {
963 
964 	ihex_write(ofd, 1, 0, 0, NULL, 0);
965 }
966 
967 static void
968 ihex_write_04(int ofd, uint16_t addr)
969 {
970 
971 	ihex_write(ofd, 4, 0, addr, NULL, 2);
972 }
973 
974 static void
975 ihex_write_05(int ofd, uint64_t e_entry)
976 {
977 
978 	if (e_entry > 0xFFFFFFFF) {
979 		warnx("address space too big for Intel Hex file");
980 		return;
981 	}
982 
983 	ihex_write(ofd, 5, 0, e_entry, NULL, 4);
984 }
985 
986 static void
987 ihex_write(int ofd, int type, uint64_t addr, uint64_t num, const void *buf,
988     size_t sz)
989 {
990 	char line[_LINE_BUFSZ];
991 	const uint8_t *p, *pe;
992 	int len, checksum;
993 
994 	if (sz > 16)
995 		errx(EXIT_FAILURE, "Internal: ihex_write() sz too big");
996 	checksum = 0;
997 	line[0] = ':';
998 	len = 1;
999 	write_num(line, &len, sz, 1, &checksum);
1000 	write_num(line, &len, addr, 2, &checksum);
1001 	write_num(line, &len, type, 1, &checksum);
1002 	if (sz > 0) {
1003 		if (buf != NULL) {
1004 			for (p = buf, pe = p + sz; p < pe; p++)
1005 				write_num(line, &len, *p, 1, &checksum);
1006 		} else
1007 			write_num(line, &len, num, sz, &checksum);
1008 	}
1009 	write_num(line, &len, (~checksum + 1) & 0xFF, 1, NULL);
1010 	line[len++] = '\r';
1011 	line[len++] = '\n';
1012 	if (write(ofd, line, len) != (ssize_t) len)
1013 		err(EXIT_FAILURE, "write failed");
1014 }
1015 
1016 static int
1017 read_num(const char *line, int *len, uint64_t *num, size_t sz, int *checksum)
1018 {
1019 	uint8_t b;
1020 
1021 	*num = 0;
1022 	for (; sz > 0; sz--) {
1023 		if (!ishexdigit(line[*len]) || !ishexdigit(line[*len + 1]))
1024 			return (-1);
1025 		b = (hex_value(line[*len]) << 4) | hex_value(line[*len + 1]);
1026 		*num = (*num << 8) | b;
1027 		*len += 2;
1028 		if (checksum != NULL)
1029 			*checksum = (*checksum + b) & 0xFF;
1030 	}
1031 
1032 	return (0);
1033 }
1034 
1035 static void
1036 write_num(char *line, int *len, uint64_t num, size_t sz, int *checksum)
1037 {
1038 	uint8_t b;
1039 
1040 	for (; sz > 0; sz--) {
1041 		b = (num >> ((sz - 1) * 8)) & 0xFF;
1042 		line[*len] = hex_digit((b >> 4) & 0xF);
1043 		line[*len + 1] = hex_digit(b & 0xF);
1044 		*len += 2;
1045 		if (checksum != NULL)
1046 			*checksum = (*checksum + b) & 0xFF;
1047 	}
1048 }
1049 
1050 static char
1051 hex_digit(uint8_t n)
1052 {
1053 
1054 	return ((n < 10) ? '0' + n : 'A' + (n - 10));
1055 }
1056 
1057 static int
1058 hex_value(int x)
1059 {
1060 
1061 	if (isdigit(x))
1062 		return (x - '0');
1063 	else if (x >= 'a' && x <= 'f')
1064 		return (x - 'a' + 10);
1065 	else
1066 		return (x - 'A' + 10);
1067 }
1068 
1069 static int
1070 ishexdigit(int x)
1071 {
1072 
1073 	if (isdigit(x))
1074 		return (1);
1075 	if ((x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F'))
1076 		return (1);
1077 
1078 	return (0);
1079 }
1080