root/tools/perf/util/genelf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gen_build_id
  2. gen_build_id
  3. gen_build_id
  4. jit_add_eh_frame_info
  5. jit_write_elf
  6. main

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

/* [<][>][^][v][top][bottom][index][help] */