linux/tools/objtool/elf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * elf.c - ELF access library
   4 *
   5 * Adapted from kpatch (https://github.com/dynup/kpatch):
   6 * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com>
   7 * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
   8 */
   9
  10#include <sys/types.h>
  11#include <sys/stat.h>
  12#include <fcntl.h>
  13#include <stdio.h>
  14#include <stdlib.h>
  15#include <string.h>
  16#include <unistd.h>
  17#include <errno.h>
  18
  19#include "elf.h"
  20#include "warn.h"
  21
  22#define MAX_NAME_LEN 128
  23
  24struct section *find_section_by_name(struct elf *elf, const char *name)
  25{
  26        struct section *sec;
  27
  28        list_for_each_entry(sec, &elf->sections, list)
  29                if (!strcmp(sec->name, name))
  30                        return sec;
  31
  32        return NULL;
  33}
  34
  35static struct section *find_section_by_index(struct elf *elf,
  36                                             unsigned int idx)
  37{
  38        struct section *sec;
  39
  40        list_for_each_entry(sec, &elf->sections, list)
  41                if (sec->idx == idx)
  42                        return sec;
  43
  44        return NULL;
  45}
  46
  47static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
  48{
  49        struct section *sec;
  50        struct symbol *sym;
  51
  52        list_for_each_entry(sec, &elf->sections, list)
  53                hash_for_each_possible(sec->symbol_hash, sym, hash, idx)
  54                        if (sym->idx == idx)
  55                                return sym;
  56
  57        return NULL;
  58}
  59
  60struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)
  61{
  62        struct symbol *sym;
  63
  64        list_for_each_entry(sym, &sec->symbol_list, list)
  65                if (sym->type != STT_SECTION &&
  66                    sym->offset == offset)
  67                        return sym;
  68
  69        return NULL;
  70}
  71
  72struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
  73{
  74        struct section *sec;
  75        struct symbol *sym;
  76
  77        list_for_each_entry(sec, &elf->sections, list)
  78                list_for_each_entry(sym, &sec->symbol_list, list)
  79                        if (!strcmp(sym->name, name))
  80                                return sym;
  81
  82        return NULL;
  83}
  84
  85struct symbol *find_symbol_containing(struct section *sec, unsigned long offset)
  86{
  87        struct symbol *sym;
  88
  89        list_for_each_entry(sym, &sec->symbol_list, list)
  90                if (sym->type != STT_SECTION &&
  91                    offset >= sym->offset && offset < sym->offset + sym->len)
  92                        return sym;
  93
  94        return NULL;
  95}
  96
  97struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
  98                                     unsigned int len)
  99{
 100        struct rela *rela;
 101        unsigned long o;
 102
 103        if (!sec->rela)
 104                return NULL;
 105
 106        for (o = offset; o < offset + len; o++)
 107                hash_for_each_possible(sec->rela->rela_hash, rela, hash, o)
 108                        if (rela->offset == o)
 109                                return rela;
 110
 111        return NULL;
 112}
 113
 114struct rela *find_rela_by_dest(struct section *sec, unsigned long offset)
 115{
 116        return find_rela_by_dest_range(sec, offset, 1);
 117}
 118
 119struct symbol *find_containing_func(struct section *sec, unsigned long offset)
 120{
 121        struct symbol *func;
 122
 123        list_for_each_entry(func, &sec->symbol_list, list)
 124                if (func->type == STT_FUNC && offset >= func->offset &&
 125                    offset < func->offset + func->len)
 126                        return func;
 127
 128        return NULL;
 129}
 130
 131static int read_sections(struct elf *elf)
 132{
 133        Elf_Scn *s = NULL;
 134        struct section *sec;
 135        size_t shstrndx, sections_nr;
 136        int i;
 137
 138        if (elf_getshdrnum(elf->elf, &sections_nr)) {
 139                WARN_ELF("elf_getshdrnum");
 140                return -1;
 141        }
 142
 143        if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
 144                WARN_ELF("elf_getshdrstrndx");
 145                return -1;
 146        }
 147
 148        for (i = 0; i < sections_nr; i++) {
 149                sec = malloc(sizeof(*sec));
 150                if (!sec) {
 151                        perror("malloc");
 152                        return -1;
 153                }
 154                memset(sec, 0, sizeof(*sec));
 155
 156                INIT_LIST_HEAD(&sec->symbol_list);
 157                INIT_LIST_HEAD(&sec->rela_list);
 158                hash_init(sec->rela_hash);
 159                hash_init(sec->symbol_hash);
 160
 161                list_add_tail(&sec->list, &elf->sections);
 162
 163                s = elf_getscn(elf->elf, i);
 164                if (!s) {
 165                        WARN_ELF("elf_getscn");
 166                        return -1;
 167                }
 168
 169                sec->idx = elf_ndxscn(s);
 170
 171                if (!gelf_getshdr(s, &sec->sh)) {
 172                        WARN_ELF("gelf_getshdr");
 173                        return -1;
 174                }
 175
 176                sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
 177                if (!sec->name) {
 178                        WARN_ELF("elf_strptr");
 179                        return -1;
 180                }
 181
 182                if (sec->sh.sh_size != 0) {
 183                        sec->data = elf_getdata(s, NULL);
 184                        if (!sec->data) {
 185                                WARN_ELF("elf_getdata");
 186                                return -1;
 187                        }
 188                        if (sec->data->d_off != 0 ||
 189                            sec->data->d_size != sec->sh.sh_size) {
 190                                WARN("unexpected data attributes for %s",
 191                                     sec->name);
 192                                return -1;
 193                        }
 194                }
 195                sec->len = sec->sh.sh_size;
 196        }
 197
 198        /* sanity check, one more call to elf_nextscn() should return NULL */
 199        if (elf_nextscn(elf->elf, s)) {
 200                WARN("section entry mismatch");
 201                return -1;
 202        }
 203
 204        return 0;
 205}
 206
 207static int read_symbols(struct elf *elf)
 208{
 209        struct section *symtab, *sec;
 210        struct symbol *sym, *pfunc, *alias;
 211        struct list_head *entry, *tmp;
 212        int symbols_nr, i;
 213        char *coldstr;
 214
 215        symtab = find_section_by_name(elf, ".symtab");
 216        if (!symtab) {
 217                WARN("missing symbol table");
 218                return -1;
 219        }
 220
 221        symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
 222
 223        for (i = 0; i < symbols_nr; i++) {
 224                sym = malloc(sizeof(*sym));
 225                if (!sym) {
 226                        perror("malloc");
 227                        return -1;
 228                }
 229                memset(sym, 0, sizeof(*sym));
 230                alias = sym;
 231
 232                sym->idx = i;
 233
 234                if (!gelf_getsym(symtab->data, i, &sym->sym)) {
 235                        WARN_ELF("gelf_getsym");
 236                        goto err;
 237                }
 238
 239                sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
 240                                       sym->sym.st_name);
 241                if (!sym->name) {
 242                        WARN_ELF("elf_strptr");
 243                        goto err;
 244                }
 245
 246                sym->type = GELF_ST_TYPE(sym->sym.st_info);
 247                sym->bind = GELF_ST_BIND(sym->sym.st_info);
 248
 249                if (sym->sym.st_shndx > SHN_UNDEF &&
 250                    sym->sym.st_shndx < SHN_LORESERVE) {
 251                        sym->sec = find_section_by_index(elf,
 252                                                         sym->sym.st_shndx);
 253                        if (!sym->sec) {
 254                                WARN("couldn't find section for symbol %s",
 255                                     sym->name);
 256                                goto err;
 257                        }
 258                        if (sym->type == STT_SECTION) {
 259                                sym->name = sym->sec->name;
 260                                sym->sec->sym = sym;
 261                        }
 262                } else
 263                        sym->sec = find_section_by_index(elf, 0);
 264
 265                sym->offset = sym->sym.st_value;
 266                sym->len = sym->sym.st_size;
 267
 268                /* sorted insert into a per-section list */
 269                entry = &sym->sec->symbol_list;
 270                list_for_each_prev(tmp, &sym->sec->symbol_list) {
 271                        struct symbol *s;
 272
 273                        s = list_entry(tmp, struct symbol, list);
 274
 275                        if (sym->offset > s->offset) {
 276                                entry = tmp;
 277                                break;
 278                        }
 279
 280                        if (sym->offset == s->offset) {
 281                                if (sym->len && sym->len == s->len && alias == sym)
 282                                        alias = s;
 283
 284                                if (sym->len >= s->len) {
 285                                        entry = tmp;
 286                                        break;
 287                                }
 288                        }
 289                }
 290                sym->alias = alias;
 291                list_add(&sym->list, entry);
 292                hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx);
 293        }
 294
 295        /* Create parent/child links for any cold subfunctions */
 296        list_for_each_entry(sec, &elf->sections, list) {
 297                list_for_each_entry(sym, &sec->symbol_list, list) {
 298                        char pname[MAX_NAME_LEN + 1];
 299                        size_t pnamelen;
 300                        if (sym->type != STT_FUNC)
 301                                continue;
 302                        sym->pfunc = sym->cfunc = sym;
 303                        coldstr = strstr(sym->name, ".cold");
 304                        if (!coldstr)
 305                                continue;
 306
 307                        pnamelen = coldstr - sym->name;
 308                        if (pnamelen > MAX_NAME_LEN) {
 309                                WARN("%s(): parent function name exceeds maximum length of %d characters",
 310                                     sym->name, MAX_NAME_LEN);
 311                                return -1;
 312                        }
 313
 314                        strncpy(pname, sym->name, pnamelen);
 315                        pname[pnamelen] = '\0';
 316                        pfunc = find_symbol_by_name(elf, pname);
 317
 318                        if (!pfunc) {
 319                                WARN("%s(): can't find parent function",
 320                                     sym->name);
 321                                return -1;
 322                        }
 323
 324                        sym->pfunc = pfunc;
 325                        pfunc->cfunc = sym;
 326
 327                        /*
 328                         * Unfortunately, -fnoreorder-functions puts the child
 329                         * inside the parent.  Remove the overlap so we can
 330                         * have sane assumptions.
 331                         *
 332                         * Note that pfunc->len now no longer matches
 333                         * pfunc->sym.st_size.
 334                         */
 335                        if (sym->sec == pfunc->sec &&
 336                            sym->offset >= pfunc->offset &&
 337                            sym->offset + sym->len == pfunc->offset + pfunc->len) {
 338                                pfunc->len -= sym->len;
 339                        }
 340                }
 341        }
 342
 343        return 0;
 344
 345err:
 346        free(sym);
 347        return -1;
 348}
 349
 350static int read_relas(struct elf *elf)
 351{
 352        struct section *sec;
 353        struct rela *rela;
 354        int i;
 355        unsigned int symndx;
 356
 357        list_for_each_entry(sec, &elf->sections, list) {
 358                if (sec->sh.sh_type != SHT_RELA)
 359                        continue;
 360
 361                sec->base = find_section_by_name(elf, sec->name + 5);
 362                if (!sec->base) {
 363                        WARN("can't find base section for rela section %s",
 364                             sec->name);
 365                        return -1;
 366                }
 367
 368                sec->base->rela = sec;
 369
 370                for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
 371                        rela = malloc(sizeof(*rela));
 372                        if (!rela) {
 373                                perror("malloc");
 374                                return -1;
 375                        }
 376                        memset(rela, 0, sizeof(*rela));
 377
 378                        if (!gelf_getrela(sec->data, i, &rela->rela)) {
 379                                WARN_ELF("gelf_getrela");
 380                                return -1;
 381                        }
 382
 383                        rela->type = GELF_R_TYPE(rela->rela.r_info);
 384                        rela->addend = rela->rela.r_addend;
 385                        rela->offset = rela->rela.r_offset;
 386                        symndx = GELF_R_SYM(rela->rela.r_info);
 387                        rela->sym = find_symbol_by_index(elf, symndx);
 388                        rela->sec = sec;
 389                        if (!rela->sym) {
 390                                WARN("can't find rela entry symbol %d for %s",
 391                                     symndx, sec->name);
 392                                return -1;
 393                        }
 394
 395                        list_add_tail(&rela->list, &sec->rela_list);
 396                        hash_add(sec->rela_hash, &rela->hash, rela->offset);
 397
 398                }
 399        }
 400
 401        return 0;
 402}
 403
 404struct elf *elf_read(const char *name, int flags)
 405{
 406        struct elf *elf;
 407        Elf_Cmd cmd;
 408
 409        elf_version(EV_CURRENT);
 410
 411        elf = malloc(sizeof(*elf));
 412        if (!elf) {
 413                perror("malloc");
 414                return NULL;
 415        }
 416        memset(elf, 0, sizeof(*elf));
 417
 418        INIT_LIST_HEAD(&elf->sections);
 419
 420        elf->fd = open(name, flags);
 421        if (elf->fd == -1) {
 422                fprintf(stderr, "objtool: Can't open '%s': %s\n",
 423                        name, strerror(errno));
 424                goto err;
 425        }
 426
 427        if ((flags & O_ACCMODE) == O_RDONLY)
 428                cmd = ELF_C_READ_MMAP;
 429        else if ((flags & O_ACCMODE) == O_RDWR)
 430                cmd = ELF_C_RDWR;
 431        else /* O_WRONLY */
 432                cmd = ELF_C_WRITE;
 433
 434        elf->elf = elf_begin(elf->fd, cmd, NULL);
 435        if (!elf->elf) {
 436                WARN_ELF("elf_begin");
 437                goto err;
 438        }
 439
 440        if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
 441                WARN_ELF("gelf_getehdr");
 442                goto err;
 443        }
 444
 445        if (read_sections(elf))
 446                goto err;
 447
 448        if (read_symbols(elf))
 449                goto err;
 450
 451        if (read_relas(elf))
 452                goto err;
 453
 454        return elf;
 455
 456err:
 457        elf_close(elf);
 458        return NULL;
 459}
 460
 461struct section *elf_create_section(struct elf *elf, const char *name,
 462                                   size_t entsize, int nr)
 463{
 464        struct section *sec, *shstrtab;
 465        size_t size = entsize * nr;
 466        Elf_Scn *s;
 467        Elf_Data *data;
 468
 469        sec = malloc(sizeof(*sec));
 470        if (!sec) {
 471                perror("malloc");
 472                return NULL;
 473        }
 474        memset(sec, 0, sizeof(*sec));
 475
 476        INIT_LIST_HEAD(&sec->symbol_list);
 477        INIT_LIST_HEAD(&sec->rela_list);
 478        hash_init(sec->rela_hash);
 479        hash_init(sec->symbol_hash);
 480
 481        list_add_tail(&sec->list, &elf->sections);
 482
 483        s = elf_newscn(elf->elf);
 484        if (!s) {
 485                WARN_ELF("elf_newscn");
 486                return NULL;
 487        }
 488
 489        sec->name = strdup(name);
 490        if (!sec->name) {
 491                perror("strdup");
 492                return NULL;
 493        }
 494
 495        sec->idx = elf_ndxscn(s);
 496        sec->len = size;
 497        sec->changed = true;
 498
 499        sec->data = elf_newdata(s);
 500        if (!sec->data) {
 501                WARN_ELF("elf_newdata");
 502                return NULL;
 503        }
 504
 505        sec->data->d_size = size;
 506        sec->data->d_align = 1;
 507
 508        if (size) {
 509                sec->data->d_buf = malloc(size);
 510                if (!sec->data->d_buf) {
 511                        perror("malloc");
 512                        return NULL;
 513                }
 514                memset(sec->data->d_buf, 0, size);
 515        }
 516
 517        if (!gelf_getshdr(s, &sec->sh)) {
 518                WARN_ELF("gelf_getshdr");
 519                return NULL;
 520        }
 521
 522        sec->sh.sh_size = size;
 523        sec->sh.sh_entsize = entsize;
 524        sec->sh.sh_type = SHT_PROGBITS;
 525        sec->sh.sh_addralign = 1;
 526        sec->sh.sh_flags = SHF_ALLOC;
 527
 528
 529        /* Add section name to .shstrtab (or .strtab for Clang) */
 530        shstrtab = find_section_by_name(elf, ".shstrtab");
 531        if (!shstrtab)
 532                shstrtab = find_section_by_name(elf, ".strtab");
 533        if (!shstrtab) {
 534                WARN("can't find .shstrtab or .strtab section");
 535                return NULL;
 536        }
 537
 538        s = elf_getscn(elf->elf, shstrtab->idx);
 539        if (!s) {
 540                WARN_ELF("elf_getscn");
 541                return NULL;
 542        }
 543
 544        data = elf_newdata(s);
 545        if (!data) {
 546                WARN_ELF("elf_newdata");
 547                return NULL;
 548        }
 549
 550        data->d_buf = sec->name;
 551        data->d_size = strlen(name) + 1;
 552        data->d_align = 1;
 553
 554        sec->sh.sh_name = shstrtab->len;
 555
 556        shstrtab->len += strlen(name) + 1;
 557        shstrtab->changed = true;
 558
 559        return sec;
 560}
 561
 562struct section *elf_create_rela_section(struct elf *elf, struct section *base)
 563{
 564        char *relaname;
 565        struct section *sec;
 566
 567        relaname = malloc(strlen(base->name) + strlen(".rela") + 1);
 568        if (!relaname) {
 569                perror("malloc");
 570                return NULL;
 571        }
 572        strcpy(relaname, ".rela");
 573        strcat(relaname, base->name);
 574
 575        sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0);
 576        free(relaname);
 577        if (!sec)
 578                return NULL;
 579
 580        base->rela = sec;
 581        sec->base = base;
 582
 583        sec->sh.sh_type = SHT_RELA;
 584        sec->sh.sh_addralign = 8;
 585        sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
 586        sec->sh.sh_info = base->idx;
 587        sec->sh.sh_flags = SHF_INFO_LINK;
 588
 589        return sec;
 590}
 591
 592int elf_rebuild_rela_section(struct section *sec)
 593{
 594        struct rela *rela;
 595        int nr, idx = 0, size;
 596        GElf_Rela *relas;
 597
 598        nr = 0;
 599        list_for_each_entry(rela, &sec->rela_list, list)
 600                nr++;
 601
 602        size = nr * sizeof(*relas);
 603        relas = malloc(size);
 604        if (!relas) {
 605                perror("malloc");
 606                return -1;
 607        }
 608
 609        sec->data->d_buf = relas;
 610        sec->data->d_size = size;
 611
 612        sec->sh.sh_size = size;
 613
 614        idx = 0;
 615        list_for_each_entry(rela, &sec->rela_list, list) {
 616                relas[idx].r_offset = rela->offset;
 617                relas[idx].r_addend = rela->addend;
 618                relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type);
 619                idx++;
 620        }
 621
 622        return 0;
 623}
 624
 625int elf_write(struct elf *elf)
 626{
 627        struct section *sec;
 628        Elf_Scn *s;
 629
 630        /* Update section headers for changed sections: */
 631        list_for_each_entry(sec, &elf->sections, list) {
 632                if (sec->changed) {
 633                        s = elf_getscn(elf->elf, sec->idx);
 634                        if (!s) {
 635                                WARN_ELF("elf_getscn");
 636                                return -1;
 637                        }
 638                        if (!gelf_update_shdr(s, &sec->sh)) {
 639                                WARN_ELF("gelf_update_shdr");
 640                                return -1;
 641                        }
 642                }
 643        }
 644
 645        /* Make sure the new section header entries get updated properly. */
 646        elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY);
 647
 648        /* Write all changes to the file. */
 649        if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
 650                WARN_ELF("elf_update");
 651                return -1;
 652        }
 653
 654        return 0;
 655}
 656
 657void elf_close(struct elf *elf)
 658{
 659        struct section *sec, *tmpsec;
 660        struct symbol *sym, *tmpsym;
 661        struct rela *rela, *tmprela;
 662
 663        if (elf->elf)
 664                elf_end(elf->elf);
 665
 666        if (elf->fd > 0)
 667                close(elf->fd);
 668
 669        list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
 670                list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
 671                        list_del(&sym->list);
 672                        hash_del(&sym->hash);
 673                        free(sym);
 674                }
 675                list_for_each_entry_safe(rela, tmprela, &sec->rela_list, list) {
 676                        list_del(&rela->list);
 677                        hash_del(&rela->hash);
 678                        free(rela);
 679                }
 680                list_del(&sec->list);
 681                free(sec);
 682        }
 683
 684        free(elf);
 685}
 686