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