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