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