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