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