0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <sys/types.h>
0011 #include <stddef.h>
0012 #include <libelf.h>
0013 #include <string.h>
0014 #include <stdlib.h>
0015 #include <unistd.h>
0016 #include <inttypes.h>
0017 #include <fcntl.h>
0018 #include <err.h>
0019 #ifdef HAVE_DWARF_SUPPORT
0020 #include <dwarf.h>
0021 #endif
0022
0023 #include "genelf.h"
0024 #include "../util/jitdump.h"
0025 #include <linux/compiler.h>
0026
0027 #ifndef NT_GNU_BUILD_ID
0028 #define NT_GNU_BUILD_ID 3
0029 #endif
0030
0031 #define BUILD_ID_URANDOM
0032
0033 #ifdef HAVE_LIBCRYPTO_SUPPORT
0034
0035 #define BUILD_ID_MD5
0036 #undef BUILD_ID_SHA
0037 #undef BUILD_ID_URANDOM
0038
0039 #ifdef BUILD_ID_SHA
0040 #include <openssl/sha.h>
0041 #endif
0042
0043 #ifdef BUILD_ID_MD5
0044 #include <openssl/evp.h>
0045 #include <openssl/md5.h>
0046 #endif
0047 #endif
0048
0049
0050 typedef struct {
0051 unsigned int namesz;
0052 unsigned int descsz;
0053 unsigned int type;
0054 char name[0];
0055 } Elf_Note;
0056
0057 struct options {
0058 char *output;
0059 int fd;
0060 };
0061
0062 static char shd_string_table[] = {
0063 0,
0064 '.', 't', 'e', 'x', 't', 0,
0065 '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0,
0066 '.', 's', 'y', 'm', 't', 'a', 'b', 0,
0067 '.', 's', 't', 'r', 't', 'a', 'b', 0,
0068 '.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0,
0069 '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0,
0070 '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0,
0071 '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0,
0072 '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', '_', 'h', 'd', 'r', 0,
0073 '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0,
0074 };
0075
0076 static struct buildid_note {
0077 Elf_Note desc;
0078 char name[4];
0079 char build_id[20];
0080 } bnote;
0081
0082 static Elf_Sym symtab[]={
0083
0084 { .st_name = 0,
0085 .st_info = ELF_ST_TYPE(STT_NOTYPE),
0086 .st_shndx = 0,
0087 .st_value = 0x0,
0088 .st_other = ELF_ST_VIS(STV_DEFAULT),
0089 .st_size = 0,
0090 },
0091 { .st_name = 1,
0092 .st_info = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
0093 .st_shndx = 1,
0094 .st_value = 0,
0095 .st_other = ELF_ST_VIS(STV_DEFAULT),
0096 .st_size = 0,
0097 }
0098 };
0099
0100 #ifdef BUILD_ID_URANDOM
0101 static void
0102 gen_build_id(struct buildid_note *note,
0103 unsigned long load_addr __maybe_unused,
0104 const void *code __maybe_unused,
0105 size_t csize __maybe_unused)
0106 {
0107 int fd;
0108 size_t sz = sizeof(note->build_id);
0109 ssize_t sret;
0110
0111 fd = open("/dev/urandom", O_RDONLY);
0112 if (fd == -1)
0113 err(1, "cannot access /dev/urandom for buildid");
0114
0115 sret = read(fd, note->build_id, sz);
0116
0117 close(fd);
0118
0119 if (sret != (ssize_t)sz)
0120 memset(note->build_id, 0, sz);
0121 }
0122 #endif
0123
0124 #ifdef BUILD_ID_SHA
0125 static void
0126 gen_build_id(struct buildid_note *note,
0127 unsigned long load_addr __maybe_unused,
0128 const void *code,
0129 size_t csize)
0130 {
0131 if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
0132 errx(1, "build_id too small for SHA1");
0133
0134 SHA1(code, csize, (unsigned char *)note->build_id);
0135 }
0136 #endif
0137
0138 #ifdef BUILD_ID_MD5
0139 static void
0140 gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
0141 {
0142 EVP_MD_CTX *mdctx;
0143
0144 if (sizeof(note->build_id) < 16)
0145 errx(1, "build_id too small for MD5");
0146
0147 mdctx = EVP_MD_CTX_new();
0148 if (!mdctx)
0149 errx(2, "failed to create EVP_MD_CTX");
0150
0151 EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
0152 EVP_DigestUpdate(mdctx, &load_addr, sizeof(load_addr));
0153 EVP_DigestUpdate(mdctx, code, csize);
0154 EVP_DigestFinal_ex(mdctx, (unsigned char *)note->build_id, NULL);
0155 EVP_MD_CTX_free(mdctx);
0156 }
0157 #endif
0158
0159 static int
0160 jit_add_eh_frame_info(Elf *e, void* unwinding, uint64_t unwinding_header_size,
0161 uint64_t unwinding_size, uint64_t base_offset)
0162 {
0163 Elf_Data *d;
0164 Elf_Scn *scn;
0165 Elf_Shdr *shdr;
0166 uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;
0167
0168
0169
0170
0171 scn = elf_newscn(e);
0172 if (!scn) {
0173 warnx("cannot create section");
0174 return -1;
0175 }
0176
0177 d = elf_newdata(scn);
0178 if (!d) {
0179 warnx("cannot get new data");
0180 return -1;
0181 }
0182
0183 d->d_align = 8;
0184 d->d_off = 0LL;
0185 d->d_buf = unwinding;
0186 d->d_type = ELF_T_BYTE;
0187 d->d_size = unwinding_table_size;
0188 d->d_version = EV_CURRENT;
0189
0190 shdr = elf_getshdr(scn);
0191 if (!shdr) {
0192 warnx("cannot get section header");
0193 return -1;
0194 }
0195
0196 shdr->sh_name = 104;
0197 shdr->sh_type = SHT_PROGBITS;
0198 shdr->sh_addr = base_offset;
0199 shdr->sh_flags = SHF_ALLOC;
0200 shdr->sh_entsize = 0;
0201
0202
0203
0204
0205 scn = elf_newscn(e);
0206 if (!scn) {
0207 warnx("cannot create section");
0208 return -1;
0209 }
0210
0211 d = elf_newdata(scn);
0212 if (!d) {
0213 warnx("cannot get new data");
0214 return -1;
0215 }
0216
0217 d->d_align = 4;
0218 d->d_off = 0LL;
0219 d->d_buf = unwinding + unwinding_table_size;
0220 d->d_type = ELF_T_BYTE;
0221 d->d_size = unwinding_header_size;
0222 d->d_version = EV_CURRENT;
0223
0224 shdr = elf_getshdr(scn);
0225 if (!shdr) {
0226 warnx("cannot get section header");
0227 return -1;
0228 }
0229
0230 shdr->sh_name = 90;
0231 shdr->sh_type = SHT_PROGBITS;
0232 shdr->sh_addr = base_offset + unwinding_table_size;
0233 shdr->sh_flags = SHF_ALLOC;
0234 shdr->sh_entsize = 0;
0235
0236 return 0;
0237 }
0238
0239
0240
0241
0242
0243
0244
0245
0246 int
0247 jit_write_elf(int fd, uint64_t load_addr, const char *sym,
0248 const void *code, int csize,
0249 void *debug __maybe_unused, int nr_debug_entries __maybe_unused,
0250 void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size)
0251 {
0252 Elf *e;
0253 Elf_Data *d;
0254 Elf_Scn *scn;
0255 Elf_Ehdr *ehdr;
0256 Elf_Phdr *phdr;
0257 Elf_Shdr *shdr;
0258 uint64_t eh_frame_base_offset;
0259 char *strsym = NULL;
0260 int symlen;
0261 int retval = -1;
0262
0263 if (elf_version(EV_CURRENT) == EV_NONE) {
0264 warnx("ELF initialization failed");
0265 return -1;
0266 }
0267
0268 e = elf_begin(fd, ELF_C_WRITE, NULL);
0269 if (!e) {
0270 warnx("elf_begin failed");
0271 goto error;
0272 }
0273
0274
0275
0276
0277 ehdr = elf_newehdr(e);
0278 if (!ehdr) {
0279 warnx("cannot get ehdr");
0280 goto error;
0281 }
0282
0283 ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
0284 ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
0285 ehdr->e_machine = GEN_ELF_ARCH;
0286 ehdr->e_type = ET_DYN;
0287 ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
0288 ehdr->e_version = EV_CURRENT;
0289 ehdr->e_shstrndx= unwinding ? 4 : 2;
0290
0291
0292
0293
0294 phdr = elf_newphdr(e, 1);
0295 phdr[0].p_type = PT_LOAD;
0296 phdr[0].p_offset = 0;
0297 phdr[0].p_vaddr = 0;
0298 phdr[0].p_paddr = 0;
0299 phdr[0].p_filesz = csize;
0300 phdr[0].p_memsz = csize;
0301 phdr[0].p_flags = PF_X | PF_R;
0302 phdr[0].p_align = 8;
0303
0304
0305
0306
0307 scn = elf_newscn(e);
0308 if (!scn) {
0309 warnx("cannot create section");
0310 goto error;
0311 }
0312
0313 d = elf_newdata(scn);
0314 if (!d) {
0315 warnx("cannot get new data");
0316 goto error;
0317 }
0318
0319 d->d_align = 16;
0320 d->d_off = 0LL;
0321 d->d_buf = (void *)code;
0322 d->d_type = ELF_T_BYTE;
0323 d->d_size = csize;
0324 d->d_version = EV_CURRENT;
0325
0326 shdr = elf_getshdr(scn);
0327 if (!shdr) {
0328 warnx("cannot get section header");
0329 goto error;
0330 }
0331
0332 shdr->sh_name = 1;
0333 shdr->sh_type = SHT_PROGBITS;
0334 shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
0335 shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
0336 shdr->sh_entsize = 0;
0337
0338
0339
0340
0341 if (unwinding) {
0342 eh_frame_base_offset = ALIGN_8(GEN_ELF_TEXT_OFFSET + csize);
0343 retval = jit_add_eh_frame_info(e, unwinding,
0344 unwinding_header_size, unwinding_size,
0345 eh_frame_base_offset);
0346 if (retval)
0347 goto error;
0348 }
0349
0350
0351
0352
0353 scn = elf_newscn(e);
0354 if (!scn) {
0355 warnx("cannot create section");
0356 goto error;
0357 }
0358
0359 d = elf_newdata(scn);
0360 if (!d) {
0361 warnx("cannot get new data");
0362 goto error;
0363 }
0364
0365 d->d_align = 1;
0366 d->d_off = 0LL;
0367 d->d_buf = shd_string_table;
0368 d->d_type = ELF_T_BYTE;
0369 d->d_size = sizeof(shd_string_table);
0370 d->d_version = EV_CURRENT;
0371
0372 shdr = elf_getshdr(scn);
0373 if (!shdr) {
0374 warnx("cannot get section header");
0375 goto error;
0376 }
0377
0378 shdr->sh_name = 7;
0379 shdr->sh_type = SHT_STRTAB;
0380 shdr->sh_flags = 0;
0381 shdr->sh_entsize = 0;
0382
0383
0384
0385
0386 symtab[1].st_size = csize;
0387 symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
0388
0389 scn = elf_newscn(e);
0390 if (!scn) {
0391 warnx("cannot create section");
0392 goto error;
0393 }
0394
0395 d = elf_newdata(scn);
0396 if (!d) {
0397 warnx("cannot get new data");
0398 goto error;
0399 }
0400
0401 d->d_align = 8;
0402 d->d_off = 0LL;
0403 d->d_buf = symtab;
0404 d->d_type = ELF_T_SYM;
0405 d->d_size = sizeof(symtab);
0406 d->d_version = EV_CURRENT;
0407
0408 shdr = elf_getshdr(scn);
0409 if (!shdr) {
0410 warnx("cannot get section header");
0411 goto error;
0412 }
0413
0414 shdr->sh_name = 17;
0415 shdr->sh_type = SHT_SYMTAB;
0416 shdr->sh_flags = 0;
0417 shdr->sh_entsize = sizeof(Elf_Sym);
0418 shdr->sh_link = unwinding ? 6 : 4;
0419
0420
0421
0422
0423
0424 symlen = 2 + strlen(sym);
0425 strsym = calloc(1, symlen);
0426 if (!strsym) {
0427 warnx("cannot allocate strsym");
0428 goto error;
0429 }
0430 strcpy(strsym + 1, sym);
0431
0432 scn = elf_newscn(e);
0433 if (!scn) {
0434 warnx("cannot create section");
0435 goto error;
0436 }
0437
0438 d = elf_newdata(scn);
0439 if (!d) {
0440 warnx("cannot get new data");
0441 goto error;
0442 }
0443
0444 d->d_align = 1;
0445 d->d_off = 0LL;
0446 d->d_buf = strsym;
0447 d->d_type = ELF_T_BYTE;
0448 d->d_size = symlen;
0449 d->d_version = EV_CURRENT;
0450
0451 shdr = elf_getshdr(scn);
0452 if (!shdr) {
0453 warnx("cannot get section header");
0454 goto error;
0455 }
0456
0457 shdr->sh_name = 25;
0458 shdr->sh_type = SHT_STRTAB;
0459 shdr->sh_flags = 0;
0460 shdr->sh_entsize = 0;
0461
0462
0463
0464
0465 scn = elf_newscn(e);
0466 if (!scn) {
0467 warnx("cannot create section");
0468 goto error;
0469 }
0470
0471 d = elf_newdata(scn);
0472 if (!d) {
0473 warnx("cannot get new data");
0474 goto error;
0475 }
0476
0477
0478
0479
0480 gen_build_id(&bnote, load_addr, code, csize);
0481 bnote.desc.namesz = sizeof(bnote.name);
0482 bnote.desc.descsz = sizeof(bnote.build_id);
0483 bnote.desc.type = NT_GNU_BUILD_ID;
0484 strcpy(bnote.name, "GNU");
0485
0486 d->d_align = 4;
0487 d->d_off = 0LL;
0488 d->d_buf = &bnote;
0489 d->d_type = ELF_T_BYTE;
0490 d->d_size = sizeof(bnote);
0491 d->d_version = EV_CURRENT;
0492
0493 shdr = elf_getshdr(scn);
0494 if (!shdr) {
0495 warnx("cannot get section header");
0496 goto error;
0497 }
0498
0499 shdr->sh_name = 33;
0500 shdr->sh_type = SHT_NOTE;
0501 shdr->sh_addr = 0x0;
0502 shdr->sh_flags = SHF_ALLOC;
0503 shdr->sh_size = sizeof(bnote);
0504 shdr->sh_entsize = 0;
0505
0506 #ifdef HAVE_DWARF_SUPPORT
0507 if (debug && nr_debug_entries) {
0508 retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
0509 if (retval)
0510 goto error;
0511 } else
0512 #endif
0513 {
0514 if (elf_update(e, ELF_C_WRITE) < 0) {
0515 warnx("elf_update 4 failed");
0516 goto error;
0517 }
0518 }
0519
0520 retval = 0;
0521 error:
0522 (void)elf_end(e);
0523
0524 free(strsym);
0525
0526
0527 return retval;
0528 }