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