qemu/include/hw/elf_ops.h
<<
>>
Prefs
   1static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
   2{
   3    bswap16s(&ehdr->e_type);      /* Object file type */
   4    bswap16s(&ehdr->e_machine);   /* Architecture */
   5    bswap32s(&ehdr->e_version);   /* Object file version */
   6    bswapSZs(&ehdr->e_entry);     /* Entry point virtual address */
   7    bswapSZs(&ehdr->e_phoff);     /* Program header table file offset */
   8    bswapSZs(&ehdr->e_shoff);     /* Section header table file offset */
   9    bswap32s(&ehdr->e_flags);     /* Processor-specific flags */
  10    bswap16s(&ehdr->e_ehsize);    /* ELF header size in bytes */
  11    bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
  12    bswap16s(&ehdr->e_phnum);     /* Program header table entry count */
  13    bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
  14    bswap16s(&ehdr->e_shnum);     /* Section header table entry count */
  15    bswap16s(&ehdr->e_shstrndx);  /* Section header string table index */
  16}
  17
  18static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
  19{
  20    bswap32s(&phdr->p_type);   /* Segment type */
  21    bswapSZs(&phdr->p_offset); /* Segment file offset */
  22    bswapSZs(&phdr->p_vaddr);  /* Segment virtual address */
  23    bswapSZs(&phdr->p_paddr);  /* Segment physical address */
  24    bswapSZs(&phdr->p_filesz); /* Segment size in file */
  25    bswapSZs(&phdr->p_memsz);  /* Segment size in memory */
  26    bswap32s(&phdr->p_flags);  /* Segment flags */
  27    bswapSZs(&phdr->p_align);  /* Segment alignment */
  28}
  29
  30static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
  31{
  32    bswap32s(&shdr->sh_name);
  33    bswap32s(&shdr->sh_type);
  34    bswapSZs(&shdr->sh_flags);
  35    bswapSZs(&shdr->sh_addr);
  36    bswapSZs(&shdr->sh_offset);
  37    bswapSZs(&shdr->sh_size);
  38    bswap32s(&shdr->sh_link);
  39    bswap32s(&shdr->sh_info);
  40    bswapSZs(&shdr->sh_addralign);
  41    bswapSZs(&shdr->sh_entsize);
  42}
  43
  44static void glue(bswap_sym, SZ)(struct elf_sym *sym)
  45{
  46    bswap32s(&sym->st_name);
  47    bswapSZs(&sym->st_value);
  48    bswapSZs(&sym->st_size);
  49    bswap16s(&sym->st_shndx);
  50}
  51
  52static void glue(bswap_rela, SZ)(struct elf_rela *rela)
  53{
  54    bswapSZs(&rela->r_offset);
  55    bswapSZs(&rela->r_info);
  56    bswapSZs((elf_word *)&rela->r_addend);
  57}
  58
  59static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
  60                                               int n, int type)
  61{
  62    int i;
  63    for(i=0;i<n;i++) {
  64        if (shdr_table[i].sh_type == type)
  65            return shdr_table + i;
  66    }
  67    return NULL;
  68}
  69
  70static int glue(symfind, SZ)(const void *s0, const void *s1)
  71{
  72    hwaddr addr = *(hwaddr *)s0;
  73    struct elf_sym *sym = (struct elf_sym *)s1;
  74    int result = 0;
  75    if (addr < sym->st_value) {
  76        result = -1;
  77    } else if (addr >= sym->st_value + sym->st_size) {
  78        result = 1;
  79    }
  80    return result;
  81}
  82
  83static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
  84                                           hwaddr orig_addr)
  85{
  86    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
  87    struct elf_sym *sym;
  88
  89    sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms),
  90                  glue(symfind, SZ));
  91    if (sym != NULL) {
  92        return s->disas_strtab + sym->st_name;
  93    }
  94
  95    return "";
  96}
  97
  98static int glue(symcmp, SZ)(const void *s0, const void *s1)
  99{
 100    struct elf_sym *sym0 = (struct elf_sym *)s0;
 101    struct elf_sym *sym1 = (struct elf_sym *)s1;
 102    return (sym0->st_value < sym1->st_value)
 103        ? -1
 104        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
 105}
 106
 107static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
 108                                   int clear_lsb, symbol_fn_t sym_cb)
 109{
 110    struct elf_shdr *symtab, *strtab;
 111    g_autofree struct elf_shdr *shdr_table = NULL;
 112    g_autofree struct elf_sym *syms = NULL;
 113    g_autofree char *str = NULL;
 114    struct syminfo *s;
 115    int nsyms, i;
 116
 117    shdr_table = load_at(fd, ehdr->e_shoff,
 118                         sizeof(struct elf_shdr) * ehdr->e_shnum);
 119    if (!shdr_table) {
 120        return;
 121    }
 122
 123    if (must_swab) {
 124        for (i = 0; i < ehdr->e_shnum; i++) {
 125            glue(bswap_shdr, SZ)(shdr_table + i);
 126        }
 127    }
 128
 129    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
 130    if (!symtab) {
 131        return;
 132    }
 133    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
 134    if (!syms) {
 135        return;
 136    }
 137
 138    nsyms = symtab->sh_size / sizeof(struct elf_sym);
 139
 140    /* String table */
 141    if (symtab->sh_link >= ehdr->e_shnum) {
 142        return;
 143    }
 144    strtab = &shdr_table[symtab->sh_link];
 145
 146    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
 147    if (!str) {
 148        return;
 149    }
 150
 151    i = 0;
 152    while (i < nsyms) {
 153        if (must_swab) {
 154            glue(bswap_sym, SZ)(&syms[i]);
 155        }
 156        if (sym_cb) {
 157            sym_cb(str + syms[i].st_name, syms[i].st_info,
 158                   syms[i].st_value, syms[i].st_size);
 159        }
 160        /* We are only interested in function symbols.
 161           Throw everything else away.  */
 162        if (syms[i].st_shndx == SHN_UNDEF ||
 163                syms[i].st_shndx >= SHN_LORESERVE ||
 164                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
 165            nsyms--;
 166            if (i < nsyms) {
 167                syms[i] = syms[nsyms];
 168            }
 169            continue;
 170        }
 171        if (clear_lsb) {
 172            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
 173            syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
 174        }
 175        i++;
 176    }
 177
 178    /* check we have symbols left */
 179    if (nsyms == 0) {
 180        return;
 181    }
 182
 183    syms = g_realloc(syms, nsyms * sizeof(*syms));
 184    qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
 185    for (i = 0; i < nsyms - 1; i++) {
 186        if (syms[i].st_size == 0) {
 187            syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
 188        }
 189    }
 190
 191    /* Commit */
 192    s = g_malloc0(sizeof(*s));
 193    s->lookup_symbol = glue(lookup_symbol, SZ);
 194    glue(s->disas_symtab.elf, SZ) = g_steal_pointer(&syms);
 195    s->disas_num_syms = nsyms;
 196    s->disas_strtab = g_steal_pointer(&str);
 197    s->next = syminfos;
 198    syminfos = s;
 199}
 200
 201static int glue(elf_reloc, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
 202                               uint64_t (*translate_fn)(void *, uint64_t),
 203                               void *translate_opaque, uint8_t *data,
 204                               struct elf_phdr *ph, int elf_machine)
 205{
 206    struct elf_shdr *reltab, *shdr_table = NULL;
 207    struct elf_rela *rels = NULL;
 208    int nrels, i, ret = -1;
 209    elf_word wordval;
 210    void *addr;
 211
 212    shdr_table = load_at(fd, ehdr->e_shoff,
 213                         sizeof(struct elf_shdr) * ehdr->e_shnum);
 214    if (!shdr_table) {
 215        return -1;
 216    }
 217    if (must_swab) {
 218        for (i = 0; i < ehdr->e_shnum; i++) {
 219            glue(bswap_shdr, SZ)(&shdr_table[i]);
 220        }
 221    }
 222
 223    reltab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_RELA);
 224    if (!reltab) {
 225        goto fail;
 226    }
 227    rels = load_at(fd, reltab->sh_offset, reltab->sh_size);
 228    if (!rels) {
 229        goto fail;
 230    }
 231    nrels = reltab->sh_size / sizeof(struct elf_rela);
 232
 233    for (i = 0; i < nrels; i++) {
 234        if (must_swab) {
 235            glue(bswap_rela, SZ)(&rels[i]);
 236        }
 237        if (rels[i].r_offset < ph->p_vaddr ||
 238            rels[i].r_offset >= ph->p_vaddr + ph->p_filesz) {
 239            continue;
 240        }
 241        addr = &data[rels[i].r_offset - ph->p_vaddr];
 242        switch (elf_machine) {
 243        case EM_S390:
 244            switch (rels[i].r_info) {
 245            case R_390_RELATIVE:
 246                wordval = *(elf_word *)addr;
 247                if (must_swab) {
 248                    bswapSZs(&wordval);
 249                }
 250                wordval = translate_fn(translate_opaque, wordval);
 251                if (must_swab) {
 252                    bswapSZs(&wordval);
 253                }
 254                *(elf_word *)addr = wordval;
 255                break;
 256            default:
 257                fprintf(stderr, "Unsupported relocation type %i!\n",
 258                        (int)rels[i].r_info);
 259            }
 260        }
 261    }
 262
 263    ret = 0;
 264fail:
 265    g_free(rels);
 266    g_free(shdr_table);
 267    return ret;
 268}
 269
 270/*
 271 * Given 'nhdr', a pointer to a range of ELF Notes, search through them
 272 * for a note matching type 'elf_note_type' and return a pointer to
 273 * the matching ELF note.
 274 */
 275static struct elf_note *glue(get_elf_note_type, SZ)(struct elf_note *nhdr,
 276                                                    elf_word note_size,
 277                                                    elf_word phdr_align,
 278                                                    elf_word elf_note_type)
 279{
 280    elf_word nhdr_size = sizeof(struct elf_note);
 281    elf_word elf_note_entry_offset = 0;
 282    elf_word note_type;
 283    elf_word nhdr_namesz;
 284    elf_word nhdr_descsz;
 285
 286    if (nhdr == NULL) {
 287        return NULL;
 288    }
 289
 290    note_type = nhdr->n_type;
 291    while (note_type != elf_note_type) {
 292        nhdr_namesz = nhdr->n_namesz;
 293        nhdr_descsz = nhdr->n_descsz;
 294
 295        elf_note_entry_offset = nhdr_size +
 296            QEMU_ALIGN_UP(nhdr_namesz, phdr_align) +
 297            QEMU_ALIGN_UP(nhdr_descsz, phdr_align);
 298
 299        /*
 300         * If the offset calculated in this iteration exceeds the
 301         * supplied size, we are done and no matching note was found.
 302         */
 303        if (elf_note_entry_offset > note_size) {
 304            return NULL;
 305        }
 306
 307        /* skip to the next ELF Note entry */
 308        nhdr = (void *)nhdr + elf_note_entry_offset;
 309        note_type = nhdr->n_type;
 310    }
 311
 312    return nhdr;
 313}
 314
 315static ssize_t glue(load_elf, SZ)(const char *name, int fd,
 316                                  uint64_t (*elf_note_fn)(void *, void *, bool),
 317                                  uint64_t (*translate_fn)(void *, uint64_t),
 318                                  void *translate_opaque,
 319                                  int must_swab, uint64_t *pentry,
 320                                  uint64_t *lowaddr, uint64_t *highaddr,
 321                                  uint32_t *pflags, int elf_machine,
 322                                  int clear_lsb, int data_swab,
 323                                  AddressSpace *as, bool load_rom,
 324                                  symbol_fn_t sym_cb)
 325{
 326    struct elfhdr ehdr;
 327    struct elf_phdr *phdr = NULL, *ph;
 328    int size, i;
 329    ssize_t total_size;
 330    elf_word mem_size, file_size, data_offset;
 331    uint64_t addr, low = (uint64_t)-1, high = 0;
 332    GMappedFile *mapped_file = NULL;
 333    uint8_t *data = NULL;
 334    ssize_t ret = ELF_LOAD_FAILED;
 335
 336    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
 337        goto fail;
 338    if (must_swab) {
 339        glue(bswap_ehdr, SZ)(&ehdr);
 340    }
 341
 342    if (elf_machine <= EM_NONE) {
 343        /* The caller didn't specify an ARCH, we can figure it out */
 344        elf_machine = ehdr.e_machine;
 345    }
 346
 347    switch (elf_machine) {
 348        case EM_PPC64:
 349            if (ehdr.e_machine != EM_PPC64) {
 350                if (ehdr.e_machine != EM_PPC) {
 351                    ret = ELF_LOAD_WRONG_ARCH;
 352                    goto fail;
 353                }
 354            }
 355            break;
 356        case EM_X86_64:
 357            if (ehdr.e_machine != EM_X86_64) {
 358                if (ehdr.e_machine != EM_386) {
 359                    ret = ELF_LOAD_WRONG_ARCH;
 360                    goto fail;
 361                }
 362            }
 363            break;
 364        case EM_MICROBLAZE:
 365            if (ehdr.e_machine != EM_MICROBLAZE) {
 366                if (ehdr.e_machine != EM_MICROBLAZE_OLD) {
 367                    ret = ELF_LOAD_WRONG_ARCH;
 368                    goto fail;
 369                }
 370            }
 371            break;
 372        case EM_MIPS:
 373        case EM_NANOMIPS:
 374            if ((ehdr.e_machine != EM_MIPS) &&
 375                (ehdr.e_machine != EM_NANOMIPS)) {
 376                ret = ELF_LOAD_WRONG_ARCH;
 377                goto fail;
 378            }
 379            break;
 380        default:
 381            if (elf_machine != ehdr.e_machine) {
 382                ret = ELF_LOAD_WRONG_ARCH;
 383                goto fail;
 384            }
 385    }
 386
 387    if (pflags) {
 388        *pflags = (elf_word)ehdr.e_flags;
 389    }
 390    if (pentry)
 391        *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
 392
 393    glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb, sym_cb);
 394
 395    size = ehdr.e_phnum * sizeof(phdr[0]);
 396    if (lseek(fd, ehdr.e_phoff, SEEK_SET) != ehdr.e_phoff) {
 397        goto fail;
 398    }
 399    phdr = g_malloc0(size);
 400    if (!phdr)
 401        goto fail;
 402    if (read(fd, phdr, size) != size)
 403        goto fail;
 404    if (must_swab) {
 405        for(i = 0; i < ehdr.e_phnum; i++) {
 406            ph = &phdr[i];
 407            glue(bswap_phdr, SZ)(ph);
 408        }
 409    }
 410
 411    /*
 412     * Since we want to be able to modify the mapped buffer, we set the
 413     * 'writable' parameter to 'true'. Modifications to the buffer are not
 414     * written back to the file.
 415     */
 416    mapped_file = g_mapped_file_new_from_fd(fd, true, NULL);
 417    if (!mapped_file) {
 418        goto fail;
 419    }
 420
 421    total_size = 0;
 422    for(i = 0; i < ehdr.e_phnum; i++) {
 423        ph = &phdr[i];
 424        if (ph->p_type == PT_LOAD) {
 425            mem_size = ph->p_memsz; /* Size of the ROM */
 426            file_size = ph->p_filesz; /* Size of the allocated data */
 427            data_offset = ph->p_offset; /* Offset where the data is located */
 428
 429            if (file_size > 0) {
 430                if (g_mapped_file_get_length(mapped_file) <
 431                    file_size + data_offset) {
 432                    goto fail;
 433                }
 434
 435                data = (uint8_t *)g_mapped_file_get_contents(mapped_file);
 436                data += data_offset;
 437            }
 438
 439            /* The ELF spec is somewhat vague about the purpose of the
 440             * physical address field. One common use in the embedded world
 441             * is that physical address field specifies the load address
 442             * and the virtual address field specifies the execution address.
 443             * Segments are packed into ROM or flash, and the relocation
 444             * and zero-initialization of data is done at runtime. This
 445             * means that the memsz header represents the runtime size of the
 446             * segment, but the filesz represents the loadtime size. If
 447             * we try to honour the memsz value for an ELF file like this
 448             * we will end up with overlapping segments (which the
 449             * loader.c code will later reject).
 450             * We support ELF files using this scheme by by checking whether
 451             * paddr + memsz for this segment would overlap with any other
 452             * segment. If so, then we assume it's using this scheme and
 453             * truncate the loaded segment to the filesz size.
 454             * If the segment considered as being memsz size doesn't overlap
 455             * then we use memsz for the segment length, to handle ELF files
 456             * which assume that the loader will do the zero-initialization.
 457             */
 458            if (mem_size > file_size) {
 459                /* If this segment's zero-init portion overlaps another
 460                 * segment's data or zero-init portion, then truncate this one.
 461                 * Invalid ELF files where the segments overlap even when
 462                 * only file_size bytes are loaded will be rejected by
 463                 * the ROM overlap check in loader.c, so we don't try to
 464                 * explicitly detect those here.
 465                 */
 466                int j;
 467                elf_word zero_start = ph->p_paddr + file_size;
 468                elf_word zero_end = ph->p_paddr + mem_size;
 469
 470                for (j = 0; j < ehdr.e_phnum; j++) {
 471                    struct elf_phdr *jph = &phdr[j];
 472
 473                    if (i != j && jph->p_type == PT_LOAD) {
 474                        elf_word other_start = jph->p_paddr;
 475                        elf_word other_end = jph->p_paddr + jph->p_memsz;
 476
 477                        if (!(other_start >= zero_end ||
 478                              zero_start >= other_end)) {
 479                            mem_size = file_size;
 480                            break;
 481                        }
 482                    }
 483                }
 484            }
 485
 486            if (mem_size > SSIZE_MAX - total_size) {
 487                ret = ELF_LOAD_TOO_BIG;
 488                goto fail;
 489            }
 490
 491            /* address_offset is hack for kernel images that are
 492               linked at the wrong physical address.  */
 493            if (translate_fn) {
 494                addr = translate_fn(translate_opaque, ph->p_paddr);
 495                glue(elf_reloc, SZ)(&ehdr, fd, must_swab,  translate_fn,
 496                                    translate_opaque, data, ph, elf_machine);
 497            } else {
 498                addr = ph->p_paddr;
 499            }
 500
 501            if (data_swab) {
 502                int j;
 503                for (j = 0; j < file_size; j += (1 << data_swab)) {
 504                    uint8_t *dp = data + j;
 505                    switch (data_swab) {
 506                    case (1):
 507                        *(uint16_t *)dp = bswap16(*(uint16_t *)dp);
 508                        break;
 509                    case (2):
 510                        *(uint32_t *)dp = bswap32(*(uint32_t *)dp);
 511                        break;
 512                    case (3):
 513                        *(uint64_t *)dp = bswap64(*(uint64_t *)dp);
 514                        break;
 515                    default:
 516                        g_assert_not_reached();
 517                    }
 518                }
 519            }
 520
 521            /* the entry pointer in the ELF header is a virtual
 522             * address, if the text segments paddr and vaddr differ
 523             * we need to adjust the entry */
 524            if (pentry && !translate_fn &&
 525                    ph->p_vaddr != ph->p_paddr &&
 526                    ehdr.e_entry >= ph->p_vaddr &&
 527                    ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
 528                    ph->p_flags & PF_X) {
 529                *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
 530            }
 531
 532            /* Some ELF files really do have segments of zero size;
 533             * just ignore them rather than trying to create empty
 534             * ROM blobs, because the zero-length blob can falsely
 535             * trigger the overlapping-ROM-blobs check.
 536             */
 537            if (mem_size != 0) {
 538                if (load_rom) {
 539                    g_autofree char *label =
 540                        g_strdup_printf("%s ELF program header segment %d",
 541                                        name, i);
 542
 543                    /*
 544                     * rom_add_elf_program() takes its own reference to
 545                     * 'mapped_file'.
 546                     */
 547                    rom_add_elf_program(label, mapped_file, data, file_size,
 548                                        mem_size, addr, as);
 549                } else {
 550                    MemTxResult res;
 551
 552                    res = address_space_write(as ? as : &address_space_memory,
 553                                              addr, MEMTXATTRS_UNSPECIFIED,
 554                                              data, file_size);
 555                    if (res != MEMTX_OK) {
 556                        goto fail;
 557                    }
 558                    /*
 559                     * We need to zero'ify the space that is not copied
 560                     * from file
 561                     */
 562                    if (file_size < mem_size) {
 563                        res = address_space_set(as ? as : &address_space_memory,
 564                                                addr + file_size, 0,
 565                                                mem_size - file_size,
 566                                                MEMTXATTRS_UNSPECIFIED);
 567                        if (res != MEMTX_OK) {
 568                            goto fail;
 569                        }
 570                    }
 571                }
 572            }
 573
 574            total_size += mem_size;
 575            if (addr < low)
 576                low = addr;
 577            if ((addr + mem_size) > high)
 578                high = addr + mem_size;
 579
 580            data = NULL;
 581
 582        } else if (ph->p_type == PT_NOTE && elf_note_fn) {
 583            struct elf_note *nhdr = NULL;
 584
 585            file_size = ph->p_filesz; /* Size of the range of ELF notes */
 586            data_offset = ph->p_offset; /* Offset where the notes are located */
 587
 588            if (file_size > 0) {
 589                if (g_mapped_file_get_length(mapped_file) <
 590                    file_size + data_offset) {
 591                    goto fail;
 592                }
 593
 594                data = (uint8_t *)g_mapped_file_get_contents(mapped_file);
 595                data += data_offset;
 596            }
 597
 598            /*
 599             * Search the ELF notes to find one with a type matching the
 600             * value passed in via 'translate_opaque'
 601             */
 602            nhdr = (struct elf_note *)data;
 603            assert(translate_opaque != NULL);
 604            nhdr = glue(get_elf_note_type, SZ)(nhdr, file_size, ph->p_align,
 605                                               *(uint64_t *)translate_opaque);
 606            if (nhdr != NULL) {
 607                elf_note_fn((void *)nhdr, (void *)&ph->p_align, SZ == 64);
 608            }
 609            data = NULL;
 610        }
 611    }
 612
 613    if (lowaddr)
 614        *lowaddr = (uint64_t)(elf_sword)low;
 615    if (highaddr)
 616        *highaddr = (uint64_t)(elf_sword)high;
 617    ret = total_size;
 618 fail:
 619    if (mapped_file) {
 620        g_mapped_file_unref(mapped_file);
 621    }
 622    g_free(phdr);
 623    return ret;
 624}
 625