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