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