linux/tools/perf/util/genelf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * genelf.c
   4 * Copyright (C) 2014, Google, Inc
   5 *
   6 * Contributed by:
   7 *      Stephane Eranian <eranian@gmail.com>
   8 */
   9
  10#include <sys/types.h>
  11#include <stddef.h>
  12#include <libelf.h>
  13#include <string.h>
  14#include <stdlib.h>
  15#include <unistd.h>
  16#include <inttypes.h>
  17#include <fcntl.h>
  18#include <err.h>
  19#ifdef HAVE_DWARF_SUPPORT
  20#include <dwarf.h>
  21#endif
  22
  23#include "genelf.h"
  24#include "../util/jitdump.h"
  25#include <linux/compiler.h>
  26
  27#ifndef NT_GNU_BUILD_ID
  28#define NT_GNU_BUILD_ID 3
  29#endif
  30
  31#define BUILD_ID_URANDOM /* different uuid for each run */
  32
  33#ifdef HAVE_LIBCRYPTO
  34
  35#define BUILD_ID_MD5
  36#undef BUILD_ID_SHA     /* does not seem to work well when linked with Java */
  37#undef BUILD_ID_URANDOM /* different uuid for each run */
  38
  39#ifdef BUILD_ID_SHA
  40#include <openssl/sha.h>
  41#endif
  42
  43#ifdef BUILD_ID_MD5
  44#include <openssl/md5.h>
  45#endif
  46#endif
  47
  48
  49typedef struct {
  50  unsigned int namesz;  /* Size of entry's owner string */
  51  unsigned int descsz;  /* Size of the note descriptor */
  52  unsigned int type;    /* Interpretation of the descriptor */
  53  char         name[0]; /* Start of the name+desc data */
  54} Elf_Note;
  55
  56struct options {
  57        char *output;
  58        int fd;
  59};
  60
  61static char shd_string_table[] = {
  62        0,
  63        '.', 't', 'e', 'x', 't', 0,                     /*  1 */
  64        '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /*  7 */
  65        '.', 's', 'y', 'm', 't', 'a', 'b', 0,           /* 17 */
  66        '.', 's', 't', 'r', 't', 'a', 'b', 0,           /* 25 */
  67        '.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */
  68        '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
  69        '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
  70        '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
  71        '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', '_', 'h', 'd', 'r', 0, /* 90 */
  72        '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0, /* 104 */
  73};
  74
  75static struct buildid_note {
  76        Elf_Note desc;          /* descsz: size of build-id, must be multiple of 4 */
  77        char     name[4];       /* GNU\0 */
  78        char     build_id[20];
  79} bnote;
  80
  81static Elf_Sym symtab[]={
  82        /* symbol 0 MUST be the undefined symbol */
  83        { .st_name  = 0, /* index in sym_string table */
  84          .st_info  = ELF_ST_TYPE(STT_NOTYPE),
  85          .st_shndx = 0, /* for now */
  86          .st_value = 0x0,
  87          .st_other = ELF_ST_VIS(STV_DEFAULT),
  88          .st_size  = 0,
  89        },
  90        { .st_name  = 1, /* index in sym_string table */
  91          .st_info  = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
  92          .st_shndx = 1,
  93          .st_value = 0, /* for now */
  94          .st_other = ELF_ST_VIS(STV_DEFAULT),
  95          .st_size  = 0, /* for now */
  96        }
  97};
  98
  99#ifdef BUILD_ID_URANDOM
 100static void
 101gen_build_id(struct buildid_note *note,
 102             unsigned long load_addr __maybe_unused,
 103             const void *code __maybe_unused,
 104             size_t csize __maybe_unused)
 105{
 106        int fd;
 107        size_t sz = sizeof(note->build_id);
 108        ssize_t sret;
 109
 110        fd = open("/dev/urandom", O_RDONLY);
 111        if (fd == -1)
 112                err(1, "cannot access /dev/urandom for buildid");
 113
 114        sret = read(fd, note->build_id, sz);
 115
 116        close(fd);
 117
 118        if (sret != (ssize_t)sz)
 119                memset(note->build_id, 0, sz);
 120}
 121#endif
 122
 123#ifdef BUILD_ID_SHA
 124static void
 125gen_build_id(struct buildid_note *note,
 126             unsigned long load_addr __maybe_unused,
 127             const void *code,
 128             size_t csize)
 129{
 130        if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
 131                errx(1, "build_id too small for SHA1");
 132
 133        SHA1(code, csize, (unsigned char *)note->build_id);
 134}
 135#endif
 136
 137#ifdef BUILD_ID_MD5
 138static void
 139gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
 140{
 141        MD5_CTX context;
 142
 143        if (sizeof(note->build_id) < 16)
 144                errx(1, "build_id too small for MD5");
 145
 146        MD5_Init(&context);
 147        MD5_Update(&context, &load_addr, sizeof(load_addr));
 148        MD5_Update(&context, code, csize);
 149        MD5_Final((unsigned char *)note->build_id, &context);
 150}
 151#endif
 152
 153static int
 154jit_add_eh_frame_info(Elf *e, void* unwinding, uint64_t unwinding_header_size,
 155                      uint64_t unwinding_size, uint64_t base_offset)
 156{
 157        Elf_Data *d;
 158        Elf_Scn *scn;
 159        Elf_Shdr *shdr;
 160        uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
 161
 162        /*
 163         * setup eh_frame section
 164         */
 165        scn = elf_newscn(e);
 166        if (!scn) {
 167                warnx("cannot create section");
 168                return -1;
 169        }
 170
 171        d = elf_newdata(scn);
 172        if (!d) {
 173                warnx("cannot get new data");
 174                return -1;
 175        }
 176
 177        d->d_align = 8;
 178        d->d_off = 0LL;
 179        d->d_buf = unwinding;
 180        d->d_type = ELF_T_BYTE;
 181        d->d_size = unwinding_table_size;
 182        d->d_version = EV_CURRENT;
 183
 184        shdr = elf_getshdr(scn);
 185        if (!shdr) {
 186                warnx("cannot get section header");
 187                return -1;
 188        }
 189
 190        shdr->sh_name = 104;
 191        shdr->sh_type = SHT_PROGBITS;
 192        shdr->sh_addr = base_offset;
 193        shdr->sh_flags = SHF_ALLOC;
 194        shdr->sh_entsize = 0;
 195
 196        /*
 197         * setup eh_frame_hdr section
 198         */
 199        scn = elf_newscn(e);
 200        if (!scn) {
 201                warnx("cannot create section");
 202                return -1;
 203        }
 204
 205        d = elf_newdata(scn);
 206        if (!d) {
 207                warnx("cannot get new data");
 208                return -1;
 209        }
 210
 211        d->d_align = 4;
 212        d->d_off = 0LL;
 213        d->d_buf = unwinding + unwinding_table_size;
 214        d->d_type = ELF_T_BYTE;
 215        d->d_size = unwinding_header_size;
 216        d->d_version = EV_CURRENT;
 217
 218        shdr = elf_getshdr(scn);
 219        if (!shdr) {
 220                warnx("cannot get section header");
 221                return -1;
 222        }
 223
 224        shdr->sh_name = 90;
 225        shdr->sh_type = SHT_PROGBITS;
 226        shdr->sh_addr = base_offset + unwinding_table_size;
 227        shdr->sh_flags = SHF_ALLOC;
 228        shdr->sh_entsize = 0;
 229
 230        return 0;
 231}
 232
 233/*
 234 * fd: file descriptor open for writing for the output file
 235 * load_addr: code load address (could be zero, just used for buildid)
 236 * sym: function name (for native code - used as the symbol)
 237 * code: the native code
 238 * csize: the code size in bytes
 239 */
 240int
 241jit_write_elf(int fd, uint64_t load_addr, const char *sym,
 242              const void *code, int csize,
 243              void *debug __maybe_unused, int nr_debug_entries __maybe_unused,
 244              void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size)
 245{
 246        Elf *e;
 247        Elf_Data *d;
 248        Elf_Scn *scn;
 249        Elf_Ehdr *ehdr;
 250        Elf_Shdr *shdr;
 251        uint64_t eh_frame_base_offset;
 252        char *strsym = NULL;
 253        int symlen;
 254        int retval = -1;
 255
 256        if (elf_version(EV_CURRENT) == EV_NONE) {
 257                warnx("ELF initialization failed");
 258                return -1;
 259        }
 260
 261        e = elf_begin(fd, ELF_C_WRITE, NULL);
 262        if (!e) {
 263                warnx("elf_begin failed");
 264                goto error;
 265        }
 266
 267        /*
 268         * setup ELF header
 269         */
 270        ehdr = elf_newehdr(e);
 271        if (!ehdr) {
 272                warnx("cannot get ehdr");
 273                goto error;
 274        }
 275
 276        ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
 277        ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
 278        ehdr->e_machine = GEN_ELF_ARCH;
 279        ehdr->e_type = ET_DYN;
 280        ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
 281        ehdr->e_version = EV_CURRENT;
 282        ehdr->e_shstrndx= unwinding ? 4 : 2; /* shdr index for section name */
 283
 284        /*
 285         * setup text section
 286         */
 287        scn = elf_newscn(e);
 288        if (!scn) {
 289                warnx("cannot create section");
 290                goto error;
 291        }
 292
 293        d = elf_newdata(scn);
 294        if (!d) {
 295                warnx("cannot get new data");
 296                goto error;
 297        }
 298
 299        d->d_align = 16;
 300        d->d_off = 0LL;
 301        d->d_buf = (void *)code;
 302        d->d_type = ELF_T_BYTE;
 303        d->d_size = csize;
 304        d->d_version = EV_CURRENT;
 305
 306        shdr = elf_getshdr(scn);
 307        if (!shdr) {
 308                warnx("cannot get section header");
 309                goto error;
 310        }
 311
 312        shdr->sh_name = 1;
 313        shdr->sh_type = SHT_PROGBITS;
 314        shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
 315        shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
 316        shdr->sh_entsize = 0;
 317
 318        /*
 319         * Setup .eh_frame_hdr and .eh_frame
 320         */
 321        if (unwinding) {
 322                eh_frame_base_offset = ALIGN_8(GEN_ELF_TEXT_OFFSET + csize);
 323                retval = jit_add_eh_frame_info(e, unwinding,
 324                                               unwinding_header_size, unwinding_size,
 325                                               eh_frame_base_offset);
 326                if (retval)
 327                        goto error;
 328        }
 329
 330        /*
 331         * setup section headers string table
 332         */
 333        scn = elf_newscn(e);
 334        if (!scn) {
 335                warnx("cannot create section");
 336                goto error;
 337        }
 338
 339        d = elf_newdata(scn);
 340        if (!d) {
 341                warnx("cannot get new data");
 342                goto error;
 343        }
 344
 345        d->d_align = 1;
 346        d->d_off = 0LL;
 347        d->d_buf = shd_string_table;
 348        d->d_type = ELF_T_BYTE;
 349        d->d_size = sizeof(shd_string_table);
 350        d->d_version = EV_CURRENT;
 351
 352        shdr = elf_getshdr(scn);
 353        if (!shdr) {
 354                warnx("cannot get section header");
 355                goto error;
 356        }
 357
 358        shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
 359        shdr->sh_type = SHT_STRTAB;
 360        shdr->sh_flags = 0;
 361        shdr->sh_entsize = 0;
 362
 363        /*
 364         * setup symtab section
 365         */
 366        symtab[1].st_size  = csize;
 367        symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
 368
 369        scn = elf_newscn(e);
 370        if (!scn) {
 371                warnx("cannot create section");
 372                goto error;
 373        }
 374
 375        d = elf_newdata(scn);
 376        if (!d) {
 377                warnx("cannot get new data");
 378                goto error;
 379        }
 380
 381        d->d_align = 8;
 382        d->d_off = 0LL;
 383        d->d_buf = symtab;
 384        d->d_type = ELF_T_SYM;
 385        d->d_size = sizeof(symtab);
 386        d->d_version = EV_CURRENT;
 387
 388        shdr = elf_getshdr(scn);
 389        if (!shdr) {
 390                warnx("cannot get section header");
 391                goto error;
 392        }
 393
 394        shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
 395        shdr->sh_type = SHT_SYMTAB;
 396        shdr->sh_flags = 0;
 397        shdr->sh_entsize = sizeof(Elf_Sym);
 398        shdr->sh_link = unwinding ? 6 : 4; /* index of .strtab section */
 399
 400        /*
 401         * setup symbols string table
 402         * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
 403         */
 404        symlen = 2 + strlen(sym);
 405        strsym = calloc(1, symlen);
 406        if (!strsym) {
 407                warnx("cannot allocate strsym");
 408                goto error;
 409        }
 410        strcpy(strsym + 1, sym);
 411
 412        scn = elf_newscn(e);
 413        if (!scn) {
 414                warnx("cannot create section");
 415                goto error;
 416        }
 417
 418        d = elf_newdata(scn);
 419        if (!d) {
 420                warnx("cannot get new data");
 421                goto error;
 422        }
 423
 424        d->d_align = 1;
 425        d->d_off = 0LL;
 426        d->d_buf = strsym;
 427        d->d_type = ELF_T_BYTE;
 428        d->d_size = symlen;
 429        d->d_version = EV_CURRENT;
 430
 431        shdr = elf_getshdr(scn);
 432        if (!shdr) {
 433                warnx("cannot get section header");
 434                goto error;
 435        }
 436
 437        shdr->sh_name = 25; /* offset in shd_string_table */
 438        shdr->sh_type = SHT_STRTAB;
 439        shdr->sh_flags = 0;
 440        shdr->sh_entsize = 0;
 441
 442        /*
 443         * setup build-id section
 444         */
 445        scn = elf_newscn(e);
 446        if (!scn) {
 447                warnx("cannot create section");
 448                goto error;
 449        }
 450
 451        d = elf_newdata(scn);
 452        if (!d) {
 453                warnx("cannot get new data");
 454                goto error;
 455        }
 456
 457        /*
 458         * build-id generation
 459         */
 460        gen_build_id(&bnote, load_addr, code, csize);
 461        bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
 462        bnote.desc.descsz = sizeof(bnote.build_id);
 463        bnote.desc.type   = NT_GNU_BUILD_ID;
 464        strcpy(bnote.name, "GNU");
 465
 466        d->d_align = 4;
 467        d->d_off = 0LL;
 468        d->d_buf = &bnote;
 469        d->d_type = ELF_T_BYTE;
 470        d->d_size = sizeof(bnote);
 471        d->d_version = EV_CURRENT;
 472
 473        shdr = elf_getshdr(scn);
 474        if (!shdr) {
 475                warnx("cannot get section header");
 476                goto error;
 477        }
 478
 479        shdr->sh_name = 33; /* offset in shd_string_table */
 480        shdr->sh_type = SHT_NOTE;
 481        shdr->sh_addr = 0x0;
 482        shdr->sh_flags = SHF_ALLOC;
 483        shdr->sh_size = sizeof(bnote);
 484        shdr->sh_entsize = 0;
 485
 486#ifdef HAVE_DWARF_SUPPORT
 487        if (debug && nr_debug_entries) {
 488                retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
 489                if (retval)
 490                        goto error;
 491        } else
 492#endif
 493        {
 494                if (elf_update(e, ELF_C_WRITE) < 0) {
 495                        warnx("elf_update 4 failed");
 496                        goto error;
 497                }
 498        }
 499
 500        retval = 0;
 501error:
 502        (void)elf_end(e);
 503
 504        free(strsym);
 505
 506
 507        return retval;
 508}
 509