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