191007045SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29b07e27fSStephane Eranian /* 39b07e27fSStephane Eranian * genelf.c 49b07e27fSStephane Eranian * Copyright (C) 2014, Google, Inc 59b07e27fSStephane Eranian * 69b07e27fSStephane Eranian * Contributed by: 79b07e27fSStephane Eranian * Stephane Eranian <eranian@gmail.com> 89b07e27fSStephane Eranian */ 99b07e27fSStephane Eranian 109b07e27fSStephane Eranian #include <sys/types.h> 119b07e27fSStephane Eranian #include <stddef.h> 129b07e27fSStephane Eranian #include <libelf.h> 139b07e27fSStephane Eranian #include <string.h> 149b07e27fSStephane Eranian #include <stdlib.h> 1591854f9aSArnaldo Carvalho de Melo #include <unistd.h> 169b07e27fSStephane Eranian #include <inttypes.h> 179b07e27fSStephane Eranian #include <fcntl.h> 189b07e27fSStephane Eranian #include <err.h> 19621cb4e7SMaciej Debski #ifdef HAVE_DWARF_SUPPORT 209b07e27fSStephane Eranian #include <dwarf.h> 21621cb4e7SMaciej Debski #endif 229b07e27fSStephane Eranian 239b07e27fSStephane Eranian #include "genelf.h" 249b07e27fSStephane Eranian #include "../util/jitdump.h" 2591854f9aSArnaldo Carvalho de Melo #include <linux/compiler.h> 269b07e27fSStephane Eranian 275fef5f3fSArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 285fef5f3fSArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 295fef5f3fSArnaldo Carvalho de Melo #endif 305fef5f3fSArnaldo Carvalho de Melo 319b07e27fSStephane Eranian #define BUILD_ID_URANDOM /* different uuid for each run */ 329b07e27fSStephane Eranian 3391cea6beSArnaldo Carvalho de Melo #ifdef HAVE_LIBCRYPTO_SUPPORT 349b07e27fSStephane Eranian 359b07e27fSStephane Eranian #define BUILD_ID_MD5 369b07e27fSStephane Eranian #undef BUILD_ID_SHA /* does not seem to work well when linked with Java */ 379b07e27fSStephane Eranian #undef BUILD_ID_URANDOM /* different uuid for each run */ 389b07e27fSStephane Eranian 399b07e27fSStephane Eranian #ifdef BUILD_ID_SHA 409b07e27fSStephane Eranian #include <openssl/sha.h> 419b07e27fSStephane Eranian #endif 429b07e27fSStephane Eranian 439b07e27fSStephane Eranian #ifdef BUILD_ID_MD5 446ea9da51SZixuan Tan #include <openssl/evp.h> 459b07e27fSStephane Eranian #include <openssl/md5.h> 469b07e27fSStephane Eranian #endif 479b07e27fSStephane Eranian #endif 489b07e27fSStephane Eranian 499b07e27fSStephane Eranian 509b07e27fSStephane Eranian typedef struct { 519b07e27fSStephane Eranian unsigned int namesz; /* Size of entry's owner string */ 529b07e27fSStephane Eranian unsigned int descsz; /* Size of the note descriptor */ 539b07e27fSStephane Eranian unsigned int type; /* Interpretation of the descriptor */ 549b07e27fSStephane Eranian char name[0]; /* Start of the name+desc data */ 559b07e27fSStephane Eranian } Elf_Note; 569b07e27fSStephane Eranian 579b07e27fSStephane Eranian struct options { 589b07e27fSStephane Eranian char *output; 599b07e27fSStephane Eranian int fd; 609b07e27fSStephane Eranian }; 619b07e27fSStephane Eranian 629b07e27fSStephane Eranian static char shd_string_table[] = { 639b07e27fSStephane Eranian 0, 649b07e27fSStephane Eranian '.', 't', 'e', 'x', 't', 0, /* 1 */ 659b07e27fSStephane Eranian '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /* 7 */ 669b07e27fSStephane Eranian '.', 's', 'y', 'm', 't', 'a', 'b', 0, /* 17 */ 679b07e27fSStephane Eranian '.', 's', 't', 'r', 't', 'a', 'b', 0, /* 25 */ 689b07e27fSStephane Eranian '.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */ 699b07e27fSStephane Eranian '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */ 709b07e27fSStephane Eranian '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */ 719b07e27fSStephane Eranian '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */ 72086f9f3dSStefano Sanfilippo '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', '_', 'h', 'd', 'r', 0, /* 90 */ 73086f9f3dSStefano Sanfilippo '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0, /* 104 */ 749b07e27fSStephane Eranian }; 759b07e27fSStephane Eranian 769b07e27fSStephane Eranian static struct buildid_note { 779b07e27fSStephane Eranian Elf_Note desc; /* descsz: size of build-id, must be multiple of 4 */ 789b07e27fSStephane Eranian char name[4]; /* GNU\0 */ 799b07e27fSStephane Eranian char build_id[20]; 809b07e27fSStephane Eranian } bnote; 819b07e27fSStephane Eranian 829b07e27fSStephane Eranian static Elf_Sym symtab[]={ 839b07e27fSStephane Eranian /* symbol 0 MUST be the undefined symbol */ 849b07e27fSStephane Eranian { .st_name = 0, /* index in sym_string table */ 859b07e27fSStephane Eranian .st_info = ELF_ST_TYPE(STT_NOTYPE), 869b07e27fSStephane Eranian .st_shndx = 0, /* for now */ 879b07e27fSStephane Eranian .st_value = 0x0, 889b07e27fSStephane Eranian .st_other = ELF_ST_VIS(STV_DEFAULT), 899b07e27fSStephane Eranian .st_size = 0, 909b07e27fSStephane Eranian }, 919b07e27fSStephane Eranian { .st_name = 1, /* index in sym_string table */ 929b07e27fSStephane Eranian .st_info = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC), 939b07e27fSStephane Eranian .st_shndx = 1, 949b07e27fSStephane Eranian .st_value = 0, /* for now */ 959b07e27fSStephane Eranian .st_other = ELF_ST_VIS(STV_DEFAULT), 969b07e27fSStephane Eranian .st_size = 0, /* for now */ 979b07e27fSStephane Eranian } 989b07e27fSStephane Eranian }; 999b07e27fSStephane Eranian 1009b07e27fSStephane Eranian #ifdef BUILD_ID_URANDOM 1019b07e27fSStephane Eranian static void 1029b07e27fSStephane Eranian gen_build_id(struct buildid_note *note, 1039b07e27fSStephane Eranian unsigned long load_addr __maybe_unused, 1049b07e27fSStephane Eranian const void *code __maybe_unused, 1059b07e27fSStephane Eranian size_t csize __maybe_unused) 1069b07e27fSStephane Eranian { 1079b07e27fSStephane Eranian int fd; 1089b07e27fSStephane Eranian size_t sz = sizeof(note->build_id); 1099b07e27fSStephane Eranian ssize_t sret; 1109b07e27fSStephane Eranian 1119b07e27fSStephane Eranian fd = open("/dev/urandom", O_RDONLY); 1129b07e27fSStephane Eranian if (fd == -1) 11324690761SColin Ian King err(1, "cannot access /dev/urandom for buildid"); 1149b07e27fSStephane Eranian 1159b07e27fSStephane Eranian sret = read(fd, note->build_id, sz); 1169b07e27fSStephane Eranian 1179b07e27fSStephane Eranian close(fd); 1189b07e27fSStephane Eranian 1199b07e27fSStephane Eranian if (sret != (ssize_t)sz) 1209b07e27fSStephane Eranian memset(note->build_id, 0, sz); 1219b07e27fSStephane Eranian } 1229b07e27fSStephane Eranian #endif 1239b07e27fSStephane Eranian 1249b07e27fSStephane Eranian #ifdef BUILD_ID_SHA 1259b07e27fSStephane Eranian static void 1269b07e27fSStephane Eranian gen_build_id(struct buildid_note *note, 1279b07e27fSStephane Eranian unsigned long load_addr __maybe_unused, 1289b07e27fSStephane Eranian const void *code, 1299b07e27fSStephane Eranian size_t csize) 1309b07e27fSStephane Eranian { 1319b07e27fSStephane Eranian if (sizeof(note->build_id) < SHA_DIGEST_LENGTH) 1329b07e27fSStephane Eranian errx(1, "build_id too small for SHA1"); 1339b07e27fSStephane Eranian 1349b07e27fSStephane Eranian SHA1(code, csize, (unsigned char *)note->build_id); 1359b07e27fSStephane Eranian } 1369b07e27fSStephane Eranian #endif 1379b07e27fSStephane Eranian 1389b07e27fSStephane Eranian #ifdef BUILD_ID_MD5 1399b07e27fSStephane Eranian static void 1409b07e27fSStephane Eranian gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize) 1419b07e27fSStephane Eranian { 1426ea9da51SZixuan Tan EVP_MD_CTX *mdctx; 1439b07e27fSStephane Eranian 1449b07e27fSStephane Eranian if (sizeof(note->build_id) < 16) 1459b07e27fSStephane Eranian errx(1, "build_id too small for MD5"); 1469b07e27fSStephane Eranian 1476ea9da51SZixuan Tan mdctx = EVP_MD_CTX_new(); 1486ea9da51SZixuan Tan if (!mdctx) 1496ea9da51SZixuan Tan errx(2, "failed to create EVP_MD_CTX"); 1506ea9da51SZixuan Tan 1516ea9da51SZixuan Tan EVP_DigestInit_ex(mdctx, EVP_md5(), NULL); 1526ea9da51SZixuan Tan EVP_DigestUpdate(mdctx, &load_addr, sizeof(load_addr)); 1536ea9da51SZixuan Tan EVP_DigestUpdate(mdctx, code, csize); 1546ea9da51SZixuan Tan EVP_DigestFinal_ex(mdctx, (unsigned char *)note->build_id, NULL); 1556ea9da51SZixuan Tan EVP_MD_CTX_free(mdctx); 1569b07e27fSStephane Eranian } 1579b07e27fSStephane Eranian #endif 1589b07e27fSStephane Eranian 159086f9f3dSStefano Sanfilippo static int 160086f9f3dSStefano Sanfilippo jit_add_eh_frame_info(Elf *e, void* unwinding, uint64_t unwinding_header_size, 161086f9f3dSStefano Sanfilippo uint64_t unwinding_size, uint64_t base_offset) 162086f9f3dSStefano Sanfilippo { 163086f9f3dSStefano Sanfilippo Elf_Data *d; 164086f9f3dSStefano Sanfilippo Elf_Scn *scn; 165086f9f3dSStefano Sanfilippo Elf_Shdr *shdr; 166086f9f3dSStefano Sanfilippo uint64_t unwinding_table_size = unwinding_size - unwinding_header_size; 167086f9f3dSStefano Sanfilippo 168086f9f3dSStefano Sanfilippo /* 169086f9f3dSStefano Sanfilippo * setup eh_frame section 170086f9f3dSStefano Sanfilippo */ 171086f9f3dSStefano Sanfilippo scn = elf_newscn(e); 172086f9f3dSStefano Sanfilippo if (!scn) { 173086f9f3dSStefano Sanfilippo warnx("cannot create section"); 174086f9f3dSStefano Sanfilippo return -1; 175086f9f3dSStefano Sanfilippo } 176086f9f3dSStefano Sanfilippo 177086f9f3dSStefano Sanfilippo d = elf_newdata(scn); 178086f9f3dSStefano Sanfilippo if (!d) { 179086f9f3dSStefano Sanfilippo warnx("cannot get new data"); 180086f9f3dSStefano Sanfilippo return -1; 181086f9f3dSStefano Sanfilippo } 182086f9f3dSStefano Sanfilippo 183086f9f3dSStefano Sanfilippo d->d_align = 8; 184086f9f3dSStefano Sanfilippo d->d_off = 0LL; 185086f9f3dSStefano Sanfilippo d->d_buf = unwinding; 186086f9f3dSStefano Sanfilippo d->d_type = ELF_T_BYTE; 187086f9f3dSStefano Sanfilippo d->d_size = unwinding_table_size; 188086f9f3dSStefano Sanfilippo d->d_version = EV_CURRENT; 189086f9f3dSStefano Sanfilippo 190086f9f3dSStefano Sanfilippo shdr = elf_getshdr(scn); 191086f9f3dSStefano Sanfilippo if (!shdr) { 192086f9f3dSStefano Sanfilippo warnx("cannot get section header"); 193086f9f3dSStefano Sanfilippo return -1; 194086f9f3dSStefano Sanfilippo } 195086f9f3dSStefano Sanfilippo 196086f9f3dSStefano Sanfilippo shdr->sh_name = 104; 197086f9f3dSStefano Sanfilippo shdr->sh_type = SHT_PROGBITS; 198086f9f3dSStefano Sanfilippo shdr->sh_addr = base_offset; 199086f9f3dSStefano Sanfilippo shdr->sh_flags = SHF_ALLOC; 200086f9f3dSStefano Sanfilippo shdr->sh_entsize = 0; 201086f9f3dSStefano Sanfilippo 202086f9f3dSStefano Sanfilippo /* 203086f9f3dSStefano Sanfilippo * setup eh_frame_hdr section 204086f9f3dSStefano Sanfilippo */ 205086f9f3dSStefano Sanfilippo scn = elf_newscn(e); 206086f9f3dSStefano Sanfilippo if (!scn) { 207086f9f3dSStefano Sanfilippo warnx("cannot create section"); 208086f9f3dSStefano Sanfilippo return -1; 209086f9f3dSStefano Sanfilippo } 210086f9f3dSStefano Sanfilippo 211086f9f3dSStefano Sanfilippo d = elf_newdata(scn); 212086f9f3dSStefano Sanfilippo if (!d) { 213086f9f3dSStefano Sanfilippo warnx("cannot get new data"); 214086f9f3dSStefano Sanfilippo return -1; 215086f9f3dSStefano Sanfilippo } 216086f9f3dSStefano Sanfilippo 217086f9f3dSStefano Sanfilippo d->d_align = 4; 218086f9f3dSStefano Sanfilippo d->d_off = 0LL; 219086f9f3dSStefano Sanfilippo d->d_buf = unwinding + unwinding_table_size; 220086f9f3dSStefano Sanfilippo d->d_type = ELF_T_BYTE; 221086f9f3dSStefano Sanfilippo d->d_size = unwinding_header_size; 222086f9f3dSStefano Sanfilippo d->d_version = EV_CURRENT; 223086f9f3dSStefano Sanfilippo 224086f9f3dSStefano Sanfilippo shdr = elf_getshdr(scn); 225086f9f3dSStefano Sanfilippo if (!shdr) { 226086f9f3dSStefano Sanfilippo warnx("cannot get section header"); 227086f9f3dSStefano Sanfilippo return -1; 228086f9f3dSStefano Sanfilippo } 229086f9f3dSStefano Sanfilippo 230086f9f3dSStefano Sanfilippo shdr->sh_name = 90; 231086f9f3dSStefano Sanfilippo shdr->sh_type = SHT_PROGBITS; 232086f9f3dSStefano Sanfilippo shdr->sh_addr = base_offset + unwinding_table_size; 233086f9f3dSStefano Sanfilippo shdr->sh_flags = SHF_ALLOC; 234086f9f3dSStefano Sanfilippo shdr->sh_entsize = 0; 235086f9f3dSStefano Sanfilippo 236086f9f3dSStefano Sanfilippo return 0; 237086f9f3dSStefano Sanfilippo } 238086f9f3dSStefano Sanfilippo 2399b07e27fSStephane Eranian /* 2409b07e27fSStephane Eranian * fd: file descriptor open for writing for the output file 2419b07e27fSStephane Eranian * load_addr: code load address (could be zero, just used for buildid) 2429b07e27fSStephane Eranian * sym: function name (for native code - used as the symbol) 2439b07e27fSStephane Eranian * code: the native code 2449b07e27fSStephane Eranian * csize: the code size in bytes 2459b07e27fSStephane Eranian */ 2469b07e27fSStephane Eranian int 2479b07e27fSStephane Eranian jit_write_elf(int fd, uint64_t load_addr, const char *sym, 248598b7c69SStephane Eranian const void *code, int csize, 249086f9f3dSStefano Sanfilippo void *debug __maybe_unused, int nr_debug_entries __maybe_unused, 250086f9f3dSStefano Sanfilippo void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size) 2519b07e27fSStephane Eranian { 2529b07e27fSStephane Eranian Elf *e; 2539b07e27fSStephane Eranian Elf_Data *d; 2549b07e27fSStephane Eranian Elf_Scn *scn; 2559b07e27fSStephane Eranian Elf_Ehdr *ehdr; 256babd0438SLieven Hey Elf_Phdr *phdr; 2579b07e27fSStephane Eranian Elf_Shdr *shdr; 258086f9f3dSStefano Sanfilippo uint64_t eh_frame_base_offset; 2599b07e27fSStephane Eranian char *strsym = NULL; 2609b07e27fSStephane Eranian int symlen; 2619b07e27fSStephane Eranian int retval = -1; 2629b07e27fSStephane Eranian 2639b07e27fSStephane Eranian if (elf_version(EV_CURRENT) == EV_NONE) { 2649b07e27fSStephane Eranian warnx("ELF initialization failed"); 2659b07e27fSStephane Eranian return -1; 2669b07e27fSStephane Eranian } 2679b07e27fSStephane Eranian 2689b07e27fSStephane Eranian e = elf_begin(fd, ELF_C_WRITE, NULL); 2699b07e27fSStephane Eranian if (!e) { 2709b07e27fSStephane Eranian warnx("elf_begin failed"); 2719b07e27fSStephane Eranian goto error; 2729b07e27fSStephane Eranian } 2739b07e27fSStephane Eranian 2749b07e27fSStephane Eranian /* 2759b07e27fSStephane Eranian * setup ELF header 2769b07e27fSStephane Eranian */ 2779b07e27fSStephane Eranian ehdr = elf_newehdr(e); 2789b07e27fSStephane Eranian if (!ehdr) { 2799b07e27fSStephane Eranian warnx("cannot get ehdr"); 2809b07e27fSStephane Eranian goto error; 2819b07e27fSStephane Eranian } 2829b07e27fSStephane Eranian 2839b07e27fSStephane Eranian ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN; 2849b07e27fSStephane Eranian ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS; 2859b07e27fSStephane Eranian ehdr->e_machine = GEN_ELF_ARCH; 2869b07e27fSStephane Eranian ehdr->e_type = ET_DYN; 2879b07e27fSStephane Eranian ehdr->e_entry = GEN_ELF_TEXT_OFFSET; 2889b07e27fSStephane Eranian ehdr->e_version = EV_CURRENT; 289086f9f3dSStefano Sanfilippo ehdr->e_shstrndx= unwinding ? 4 : 2; /* shdr index for section name */ 2909b07e27fSStephane Eranian 2919b07e27fSStephane Eranian /* 292babd0438SLieven Hey * setup program header 293babd0438SLieven Hey */ 294babd0438SLieven Hey phdr = elf_newphdr(e, 1); 295babd0438SLieven Hey phdr[0].p_type = PT_LOAD; 296babd0438SLieven Hey phdr[0].p_offset = 0; 297babd0438SLieven Hey phdr[0].p_vaddr = 0; 298babd0438SLieven Hey phdr[0].p_paddr = 0; 299babd0438SLieven Hey phdr[0].p_filesz = csize; 300babd0438SLieven Hey phdr[0].p_memsz = csize; 301babd0438SLieven Hey phdr[0].p_flags = PF_X | PF_R; 302babd0438SLieven Hey phdr[0].p_align = 8; 303babd0438SLieven Hey 304babd0438SLieven Hey /* 3059b07e27fSStephane Eranian * setup text section 3069b07e27fSStephane Eranian */ 3079b07e27fSStephane Eranian scn = elf_newscn(e); 3089b07e27fSStephane Eranian if (!scn) { 3099b07e27fSStephane Eranian warnx("cannot create section"); 3109b07e27fSStephane Eranian goto error; 3119b07e27fSStephane Eranian } 3129b07e27fSStephane Eranian 3139b07e27fSStephane Eranian d = elf_newdata(scn); 3149b07e27fSStephane Eranian if (!d) { 3159b07e27fSStephane Eranian warnx("cannot get new data"); 3169b07e27fSStephane Eranian goto error; 3179b07e27fSStephane Eranian } 3189b07e27fSStephane Eranian 3199b07e27fSStephane Eranian d->d_align = 16; 3209b07e27fSStephane Eranian d->d_off = 0LL; 3219b07e27fSStephane Eranian d->d_buf = (void *)code; 3229b07e27fSStephane Eranian d->d_type = ELF_T_BYTE; 3239b07e27fSStephane Eranian d->d_size = csize; 3249b07e27fSStephane Eranian d->d_version = EV_CURRENT; 3259b07e27fSStephane Eranian 3269b07e27fSStephane Eranian shdr = elf_getshdr(scn); 3279b07e27fSStephane Eranian if (!shdr) { 3289b07e27fSStephane Eranian warnx("cannot get section header"); 3299b07e27fSStephane Eranian goto error; 3309b07e27fSStephane Eranian } 3319b07e27fSStephane Eranian 3329b07e27fSStephane Eranian shdr->sh_name = 1; 3339b07e27fSStephane Eranian shdr->sh_type = SHT_PROGBITS; 3349b07e27fSStephane Eranian shdr->sh_addr = GEN_ELF_TEXT_OFFSET; 3359b07e27fSStephane Eranian shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC; 3369b07e27fSStephane Eranian shdr->sh_entsize = 0; 3379b07e27fSStephane Eranian 3389b07e27fSStephane Eranian /* 339086f9f3dSStefano Sanfilippo * Setup .eh_frame_hdr and .eh_frame 340086f9f3dSStefano Sanfilippo */ 341086f9f3dSStefano Sanfilippo if (unwinding) { 342086f9f3dSStefano Sanfilippo eh_frame_base_offset = ALIGN_8(GEN_ELF_TEXT_OFFSET + csize); 343086f9f3dSStefano Sanfilippo retval = jit_add_eh_frame_info(e, unwinding, 344086f9f3dSStefano Sanfilippo unwinding_header_size, unwinding_size, 345086f9f3dSStefano Sanfilippo eh_frame_base_offset); 346086f9f3dSStefano Sanfilippo if (retval) 347086f9f3dSStefano Sanfilippo goto error; 348*e8a6430fSShang XiaoJing retval = -1; 349086f9f3dSStefano Sanfilippo } 350086f9f3dSStefano Sanfilippo 351086f9f3dSStefano Sanfilippo /* 3529b07e27fSStephane Eranian * setup section headers string table 3539b07e27fSStephane Eranian */ 3549b07e27fSStephane Eranian scn = elf_newscn(e); 3559b07e27fSStephane Eranian if (!scn) { 3569b07e27fSStephane Eranian warnx("cannot create section"); 3579b07e27fSStephane Eranian goto error; 3589b07e27fSStephane Eranian } 3599b07e27fSStephane Eranian 3609b07e27fSStephane Eranian d = elf_newdata(scn); 3619b07e27fSStephane Eranian if (!d) { 3629b07e27fSStephane Eranian warnx("cannot get new data"); 3639b07e27fSStephane Eranian goto error; 3649b07e27fSStephane Eranian } 3659b07e27fSStephane Eranian 3669b07e27fSStephane Eranian d->d_align = 1; 3679b07e27fSStephane Eranian d->d_off = 0LL; 3689b07e27fSStephane Eranian d->d_buf = shd_string_table; 3699b07e27fSStephane Eranian d->d_type = ELF_T_BYTE; 3709b07e27fSStephane Eranian d->d_size = sizeof(shd_string_table); 3719b07e27fSStephane Eranian d->d_version = EV_CURRENT; 3729b07e27fSStephane Eranian 3739b07e27fSStephane Eranian shdr = elf_getshdr(scn); 3749b07e27fSStephane Eranian if (!shdr) { 3759b07e27fSStephane Eranian warnx("cannot get section header"); 3769b07e27fSStephane Eranian goto error; 3779b07e27fSStephane Eranian } 3789b07e27fSStephane Eranian 3799b07e27fSStephane Eranian shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */ 3809b07e27fSStephane Eranian shdr->sh_type = SHT_STRTAB; 3819b07e27fSStephane Eranian shdr->sh_flags = 0; 3829b07e27fSStephane Eranian shdr->sh_entsize = 0; 3839b07e27fSStephane Eranian 3849b07e27fSStephane Eranian /* 3859b07e27fSStephane Eranian * setup symtab section 3869b07e27fSStephane Eranian */ 3879b07e27fSStephane Eranian symtab[1].st_size = csize; 3889b07e27fSStephane Eranian symtab[1].st_value = GEN_ELF_TEXT_OFFSET; 3899b07e27fSStephane Eranian 3909b07e27fSStephane Eranian scn = elf_newscn(e); 3919b07e27fSStephane Eranian if (!scn) { 3929b07e27fSStephane Eranian warnx("cannot create section"); 3939b07e27fSStephane Eranian goto error; 3949b07e27fSStephane Eranian } 3959b07e27fSStephane Eranian 3969b07e27fSStephane Eranian d = elf_newdata(scn); 3979b07e27fSStephane Eranian if (!d) { 3989b07e27fSStephane Eranian warnx("cannot get new data"); 3999b07e27fSStephane Eranian goto error; 4009b07e27fSStephane Eranian } 4019b07e27fSStephane Eranian 4029b07e27fSStephane Eranian d->d_align = 8; 4039b07e27fSStephane Eranian d->d_off = 0LL; 4049b07e27fSStephane Eranian d->d_buf = symtab; 4059b07e27fSStephane Eranian d->d_type = ELF_T_SYM; 4069b07e27fSStephane Eranian d->d_size = sizeof(symtab); 4079b07e27fSStephane Eranian d->d_version = EV_CURRENT; 4089b07e27fSStephane Eranian 4099b07e27fSStephane Eranian shdr = elf_getshdr(scn); 4109b07e27fSStephane Eranian if (!shdr) { 4119b07e27fSStephane Eranian warnx("cannot get section header"); 4129b07e27fSStephane Eranian goto error; 4139b07e27fSStephane Eranian } 4149b07e27fSStephane Eranian 4159b07e27fSStephane Eranian shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */ 4169b07e27fSStephane Eranian shdr->sh_type = SHT_SYMTAB; 4179b07e27fSStephane Eranian shdr->sh_flags = 0; 4189b07e27fSStephane Eranian shdr->sh_entsize = sizeof(Elf_Sym); 419086f9f3dSStefano Sanfilippo shdr->sh_link = unwinding ? 6 : 4; /* index of .strtab section */ 4209b07e27fSStephane Eranian 4219b07e27fSStephane Eranian /* 4229b07e27fSStephane Eranian * setup symbols string table 4239b07e27fSStephane Eranian * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry 4249b07e27fSStephane Eranian */ 4259b07e27fSStephane Eranian symlen = 2 + strlen(sym); 4269b07e27fSStephane Eranian strsym = calloc(1, symlen); 4279b07e27fSStephane Eranian if (!strsym) { 4289b07e27fSStephane Eranian warnx("cannot allocate strsym"); 4299b07e27fSStephane Eranian goto error; 4309b07e27fSStephane Eranian } 4319b07e27fSStephane Eranian strcpy(strsym + 1, sym); 4329b07e27fSStephane Eranian 4339b07e27fSStephane Eranian scn = elf_newscn(e); 4349b07e27fSStephane Eranian if (!scn) { 4359b07e27fSStephane Eranian warnx("cannot create section"); 4369b07e27fSStephane Eranian goto error; 4379b07e27fSStephane Eranian } 4389b07e27fSStephane Eranian 4399b07e27fSStephane Eranian d = elf_newdata(scn); 4409b07e27fSStephane Eranian if (!d) { 4419b07e27fSStephane Eranian warnx("cannot get new data"); 4429b07e27fSStephane Eranian goto error; 4439b07e27fSStephane Eranian } 4449b07e27fSStephane Eranian 4459b07e27fSStephane Eranian d->d_align = 1; 4469b07e27fSStephane Eranian d->d_off = 0LL; 4479b07e27fSStephane Eranian d->d_buf = strsym; 4489b07e27fSStephane Eranian d->d_type = ELF_T_BYTE; 4499b07e27fSStephane Eranian d->d_size = symlen; 4509b07e27fSStephane Eranian d->d_version = EV_CURRENT; 4519b07e27fSStephane Eranian 4529b07e27fSStephane Eranian shdr = elf_getshdr(scn); 4539b07e27fSStephane Eranian if (!shdr) { 4549b07e27fSStephane Eranian warnx("cannot get section header"); 4559b07e27fSStephane Eranian goto error; 4569b07e27fSStephane Eranian } 4579b07e27fSStephane Eranian 4589b07e27fSStephane Eranian shdr->sh_name = 25; /* offset in shd_string_table */ 4599b07e27fSStephane Eranian shdr->sh_type = SHT_STRTAB; 4609b07e27fSStephane Eranian shdr->sh_flags = 0; 4619b07e27fSStephane Eranian shdr->sh_entsize = 0; 4629b07e27fSStephane Eranian 4639b07e27fSStephane Eranian /* 4649b07e27fSStephane Eranian * setup build-id section 4659b07e27fSStephane Eranian */ 4669b07e27fSStephane Eranian scn = elf_newscn(e); 4679b07e27fSStephane Eranian if (!scn) { 4689b07e27fSStephane Eranian warnx("cannot create section"); 4699b07e27fSStephane Eranian goto error; 4709b07e27fSStephane Eranian } 4719b07e27fSStephane Eranian 4729b07e27fSStephane Eranian d = elf_newdata(scn); 4739b07e27fSStephane Eranian if (!d) { 4749b07e27fSStephane Eranian warnx("cannot get new data"); 4759b07e27fSStephane Eranian goto error; 4769b07e27fSStephane Eranian } 4779b07e27fSStephane Eranian 4789b07e27fSStephane Eranian /* 4799b07e27fSStephane Eranian * build-id generation 4809b07e27fSStephane Eranian */ 4819b07e27fSStephane Eranian gen_build_id(&bnote, load_addr, code, csize); 4829b07e27fSStephane Eranian bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */ 4839b07e27fSStephane Eranian bnote.desc.descsz = sizeof(bnote.build_id); 4849b07e27fSStephane Eranian bnote.desc.type = NT_GNU_BUILD_ID; 4859b07e27fSStephane Eranian strcpy(bnote.name, "GNU"); 4869b07e27fSStephane Eranian 4879b07e27fSStephane Eranian d->d_align = 4; 4889b07e27fSStephane Eranian d->d_off = 0LL; 4899b07e27fSStephane Eranian d->d_buf = &bnote; 4909b07e27fSStephane Eranian d->d_type = ELF_T_BYTE; 4919b07e27fSStephane Eranian d->d_size = sizeof(bnote); 4929b07e27fSStephane Eranian d->d_version = EV_CURRENT; 4939b07e27fSStephane Eranian 4949b07e27fSStephane Eranian shdr = elf_getshdr(scn); 4959b07e27fSStephane Eranian if (!shdr) { 4969b07e27fSStephane Eranian warnx("cannot get section header"); 4979b07e27fSStephane Eranian goto error; 4989b07e27fSStephane Eranian } 4999b07e27fSStephane Eranian 5009b07e27fSStephane Eranian shdr->sh_name = 33; /* offset in shd_string_table */ 5019b07e27fSStephane Eranian shdr->sh_type = SHT_NOTE; 5029b07e27fSStephane Eranian shdr->sh_addr = 0x0; 5039b07e27fSStephane Eranian shdr->sh_flags = SHF_ALLOC; 5049b07e27fSStephane Eranian shdr->sh_size = sizeof(bnote); 5059b07e27fSStephane Eranian shdr->sh_entsize = 0; 5069b07e27fSStephane Eranian 507621cb4e7SMaciej Debski #ifdef HAVE_DWARF_SUPPORT 508598b7c69SStephane Eranian if (debug && nr_debug_entries) { 509598b7c69SStephane Eranian retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries); 510598b7c69SStephane Eranian if (retval) 511598b7c69SStephane Eranian goto error; 512621cb4e7SMaciej Debski } else 513621cb4e7SMaciej Debski #endif 514621cb4e7SMaciej Debski { 5159b07e27fSStephane Eranian if (elf_update(e, ELF_C_WRITE) < 0) { 5169b07e27fSStephane Eranian warnx("elf_update 4 failed"); 5179b07e27fSStephane Eranian goto error; 5189b07e27fSStephane Eranian } 519598b7c69SStephane Eranian } 5209b07e27fSStephane Eranian 5219b07e27fSStephane Eranian retval = 0; 5229b07e27fSStephane Eranian error: 5239b07e27fSStephane Eranian (void)elf_end(e); 5249b07e27fSStephane Eranian 5259b07e27fSStephane Eranian free(strsym); 5269b07e27fSStephane Eranian 5279b07e27fSStephane Eranian 5289b07e27fSStephane Eranian return retval; 5299b07e27fSStephane Eranian } 530