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