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