brintos

brintos / linux-shallow public Read only

0
0
Text · 11.0 KiB · c8f6bee Raw
525 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * genelf.c4 * Copyright (C) 2014, Google, Inc5 *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_SUPPORT20#include <dwarf.h>21#endif22 23#include "genelf.h"24#include "../util/jitdump.h"25#include <linux/compiler.h>26 27#ifndef NT_GNU_BUILD_ID28#define NT_GNU_BUILD_ID 329#endif30 31#define BUILD_ID_URANDOM /* different uuid for each run */32 33#ifdef HAVE_LIBCRYPTO_SUPPORT34 35#define BUILD_ID_MD536#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_SHA40#include <openssl/sha.h>41#endif42 43#ifdef BUILD_ID_MD544#include <openssl/evp.h>45#include <openssl/md5.h>46#endif47#endif48 49 50typedef struct {51  unsigned int namesz;  /* Size of entry's owner string */52  unsigned int descsz;  /* Size of the note descriptor */53  unsigned int type;    /* Interpretation of the descriptor */54  char         name[0]; /* Start of the name+desc data */55} Elf_Note;56 57static char shd_string_table[] = {58	0,59	'.', 't', 'e', 'x', 't', 0,			/*  1 */60	'.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /*  7 */61	'.', 's', 'y', 'm', 't', 'a', 'b', 0,		/* 17 */62	'.', 's', 't', 'r', 't', 'a', 'b', 0,		/* 25 */63	'.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */64	'.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */65	'.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */66	'.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */67	'.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', '_', 'h', 'd', 'r', 0, /* 90 */68	'.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0, /* 104 */69};70 71static struct buildid_note {72	Elf_Note desc;		/* descsz: size of build-id, must be multiple of 4 */73	char	 name[4];	/* GNU\0 */74	char	 build_id[20];75} bnote;76 77static Elf_Sym symtab[]={78	/* symbol 0 MUST be the undefined symbol */79	{ .st_name  = 0, /* index in sym_string table */80	  .st_info  = ELF_ST_TYPE(STT_NOTYPE),81	  .st_shndx = 0, /* for now */82	  .st_value = 0x0,83	  .st_other = ELF_ST_VIS(STV_DEFAULT),84	  .st_size  = 0,85	},86	{ .st_name  = 1, /* index in sym_string table */87	  .st_info  = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),88	  .st_shndx = 1,89	  .st_value = 0, /* for now */90	  .st_other = ELF_ST_VIS(STV_DEFAULT),91	  .st_size  = 0, /* for now */92	}93};94 95#ifdef BUILD_ID_URANDOM96static void97gen_build_id(struct buildid_note *note,98	     unsigned long load_addr __maybe_unused,99	     const void *code __maybe_unused,100	     size_t csize __maybe_unused)101{102	int fd;103	size_t sz = sizeof(note->build_id);104	ssize_t sret;105 106	fd = open("/dev/urandom", O_RDONLY);107	if (fd == -1)108		err(1, "cannot access /dev/urandom for buildid");109 110	sret = read(fd, note->build_id, sz);111 112	close(fd);113 114	if (sret != (ssize_t)sz)115		memset(note->build_id, 0, sz);116}117#endif118 119#ifdef BUILD_ID_SHA120static void121gen_build_id(struct buildid_note *note,122	     unsigned long load_addr __maybe_unused,123	     const void *code,124	     size_t csize)125{126	if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)127		errx(1, "build_id too small for SHA1");128 129	SHA1(code, csize, (unsigned char *)note->build_id);130}131#endif132 133#ifdef BUILD_ID_MD5134static void135gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)136{137	EVP_MD_CTX *mdctx;138 139	if (sizeof(note->build_id) < 16)140		errx(1, "build_id too small for MD5");141 142	mdctx = EVP_MD_CTX_new();143	if (!mdctx)144		errx(2, "failed to create EVP_MD_CTX");145 146	EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);147	EVP_DigestUpdate(mdctx, &load_addr, sizeof(load_addr));148	EVP_DigestUpdate(mdctx, code, csize);149	EVP_DigestFinal_ex(mdctx, (unsigned char *)note->build_id, NULL);150	EVP_MD_CTX_free(mdctx);151}152#endif153 154static int155jit_add_eh_frame_info(Elf *e, void* unwinding, uint64_t unwinding_header_size,156		      uint64_t unwinding_size, uint64_t base_offset)157{158	Elf_Data *d;159	Elf_Scn *scn;160	Elf_Shdr *shdr;161	uint64_t unwinding_table_size = unwinding_size - unwinding_header_size;162 163	/*164	 * setup eh_frame section165	 */166	scn = elf_newscn(e);167	if (!scn) {168		warnx("cannot create section");169		return -1;170	}171 172	d = elf_newdata(scn);173	if (!d) {174		warnx("cannot get new data");175		return -1;176	}177 178	d->d_align = 8;179	d->d_off = 0LL;180	d->d_buf = unwinding;181	d->d_type = ELF_T_BYTE;182	d->d_size = unwinding_table_size;183	d->d_version = EV_CURRENT;184 185	shdr = elf_getshdr(scn);186	if (!shdr) {187		warnx("cannot get section header");188		return -1;189	}190 191	shdr->sh_name = 104;192	shdr->sh_type = SHT_PROGBITS;193	shdr->sh_addr = base_offset;194	shdr->sh_flags = SHF_ALLOC;195	shdr->sh_entsize = 0;196 197	/*198	 * setup eh_frame_hdr section199	 */200	scn = elf_newscn(e);201	if (!scn) {202		warnx("cannot create section");203		return -1;204	}205 206	d = elf_newdata(scn);207	if (!d) {208		warnx("cannot get new data");209		return -1;210	}211 212	d->d_align = 4;213	d->d_off = 0LL;214	d->d_buf = unwinding + unwinding_table_size;215	d->d_type = ELF_T_BYTE;216	d->d_size = unwinding_header_size;217	d->d_version = EV_CURRENT;218 219	shdr = elf_getshdr(scn);220	if (!shdr) {221		warnx("cannot get section header");222		return -1;223	}224 225	shdr->sh_name = 90;226	shdr->sh_type = SHT_PROGBITS;227	shdr->sh_addr = base_offset + unwinding_table_size;228	shdr->sh_flags = SHF_ALLOC;229	shdr->sh_entsize = 0;230 231	return 0;232}233 234/*235 * fd: file descriptor open for writing for the output file236 * load_addr: code load address (could be zero, just used for buildid)237 * sym: function name (for native code - used as the symbol)238 * code: the native code239 * csize: the code size in bytes240 */241int242jit_write_elf(int fd, uint64_t load_addr, const char *sym,243	      const void *code, int csize,244	      void *debug __maybe_unused, int nr_debug_entries __maybe_unused,245	      void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size)246{247	Elf *e;248	Elf_Data *d;249	Elf_Scn *scn;250	Elf_Ehdr *ehdr;251	Elf_Phdr *phdr;252	Elf_Shdr *shdr;253	uint64_t eh_frame_base_offset;254	char *strsym = NULL;255	int symlen;256	int retval = -1;257 258	if (elf_version(EV_CURRENT) == EV_NONE) {259		warnx("ELF initialization failed");260		return -1;261	}262 263	e = elf_begin(fd, ELF_C_WRITE, NULL);264	if (!e) {265		warnx("elf_begin failed");266		goto error;267	}268 269	/*270	 * setup ELF header271	 */272	ehdr = elf_newehdr(e);273	if (!ehdr) {274		warnx("cannot get ehdr");275		goto error;276	}277 278	ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;279	ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;280	ehdr->e_machine = GEN_ELF_ARCH;281	ehdr->e_type = ET_DYN;282	ehdr->e_entry = GEN_ELF_TEXT_OFFSET;283	ehdr->e_version = EV_CURRENT;284	ehdr->e_shstrndx= unwinding ? 4 : 2; /* shdr index for section name */285 286	/*287	 * setup program header288	 */289	phdr = elf_newphdr(e, 1);290	phdr[0].p_type = PT_LOAD;291	phdr[0].p_offset = GEN_ELF_TEXT_OFFSET;292	phdr[0].p_vaddr = GEN_ELF_TEXT_OFFSET;293	phdr[0].p_paddr = GEN_ELF_TEXT_OFFSET;294	phdr[0].p_filesz = csize;295	phdr[0].p_memsz = csize;296	phdr[0].p_flags = PF_X | PF_R;297	phdr[0].p_align = 8;298 299	/*300	 * setup text section301	 */302	scn = elf_newscn(e);303	if (!scn) {304		warnx("cannot create section");305		goto error;306	}307 308	d = elf_newdata(scn);309	if (!d) {310		warnx("cannot get new data");311		goto error;312	}313 314	d->d_align = 16;315	d->d_off = 0LL;316	d->d_buf = (void *)code;317	d->d_type = ELF_T_BYTE;318	d->d_size = csize;319	d->d_version = EV_CURRENT;320 321	shdr = elf_getshdr(scn);322	if (!shdr) {323		warnx("cannot get section header");324		goto error;325	}326 327	shdr->sh_name = 1;328	shdr->sh_type = SHT_PROGBITS;329	shdr->sh_addr = GEN_ELF_TEXT_OFFSET;330	shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;331	shdr->sh_entsize = 0;332 333	/*334	 * Setup .eh_frame_hdr and .eh_frame335	 */336	if (unwinding) {337		eh_frame_base_offset = ALIGN_8(GEN_ELF_TEXT_OFFSET + csize);338		retval = jit_add_eh_frame_info(e, unwinding,339					       unwinding_header_size, unwinding_size,340					       eh_frame_base_offset);341		if (retval)342			goto error;343		retval = -1;344	}345 346	/*347	 * setup section headers string table348	 */349	scn = elf_newscn(e);350	if (!scn) {351		warnx("cannot create section");352		goto error;353	}354 355	d = elf_newdata(scn);356	if (!d) {357		warnx("cannot get new data");358		goto error;359	}360 361	d->d_align = 1;362	d->d_off = 0LL;363	d->d_buf = shd_string_table;364	d->d_type = ELF_T_BYTE;365	d->d_size = sizeof(shd_string_table);366	d->d_version = EV_CURRENT;367 368	shdr = elf_getshdr(scn);369	if (!shdr) {370		warnx("cannot get section header");371		goto error;372	}373 374	shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */375	shdr->sh_type = SHT_STRTAB;376	shdr->sh_flags = 0;377	shdr->sh_entsize = 0;378 379	/*380	 * setup symtab section381	 */382	symtab[1].st_size  = csize;383	symtab[1].st_value = GEN_ELF_TEXT_OFFSET;384 385	scn = elf_newscn(e);386	if (!scn) {387		warnx("cannot create section");388		goto error;389	}390 391	d = elf_newdata(scn);392	if (!d) {393		warnx("cannot get new data");394		goto error;395	}396 397	d->d_align = 8;398	d->d_off = 0LL;399	d->d_buf = symtab;400	d->d_type = ELF_T_SYM;401	d->d_size = sizeof(symtab);402	d->d_version = EV_CURRENT;403 404	shdr = elf_getshdr(scn);405	if (!shdr) {406		warnx("cannot get section header");407		goto error;408	}409 410	shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */411	shdr->sh_type = SHT_SYMTAB;412	shdr->sh_flags = 0;413	shdr->sh_entsize = sizeof(Elf_Sym);414	shdr->sh_link = unwinding ? 6 : 4; /* index of .strtab section */415 416	/*417	 * setup symbols string table418	 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry419	 */420	symlen = 2 + strlen(sym);421	strsym = calloc(1, symlen);422	if (!strsym) {423		warnx("cannot allocate strsym");424		goto error;425	}426	strcpy(strsym + 1, sym);427 428	scn = elf_newscn(e);429	if (!scn) {430		warnx("cannot create section");431		goto error;432	}433 434	d = elf_newdata(scn);435	if (!d) {436		warnx("cannot get new data");437		goto error;438	}439 440	d->d_align = 1;441	d->d_off = 0LL;442	d->d_buf = strsym;443	d->d_type = ELF_T_BYTE;444	d->d_size = symlen;445	d->d_version = EV_CURRENT;446 447	shdr = elf_getshdr(scn);448	if (!shdr) {449		warnx("cannot get section header");450		goto error;451	}452 453	shdr->sh_name = 25; /* offset in shd_string_table */454	shdr->sh_type = SHT_STRTAB;455	shdr->sh_flags = 0;456	shdr->sh_entsize = 0;457 458	/*459	 * setup build-id section460	 */461	scn = elf_newscn(e);462	if (!scn) {463		warnx("cannot create section");464		goto error;465	}466 467	d = elf_newdata(scn);468	if (!d) {469		warnx("cannot get new data");470		goto error;471	}472 473	/*474	 * build-id generation475	 */476	gen_build_id(&bnote, load_addr, code, csize);477	bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */478	bnote.desc.descsz = sizeof(bnote.build_id);479	bnote.desc.type   = NT_GNU_BUILD_ID;480	strcpy(bnote.name, "GNU");481 482	d->d_align = 4;483	d->d_off = 0LL;484	d->d_buf = &bnote;485	d->d_type = ELF_T_BYTE;486	d->d_size = sizeof(bnote);487	d->d_version = EV_CURRENT;488 489	shdr = elf_getshdr(scn);490	if (!shdr) {491		warnx("cannot get section header");492		goto error;493	}494 495	shdr->sh_name = 33; /* offset in shd_string_table */496	shdr->sh_type = SHT_NOTE;497	shdr->sh_addr = 0x0;498	shdr->sh_flags = SHF_ALLOC;499	shdr->sh_size = sizeof(bnote);500	shdr->sh_entsize = 0;501 502#ifdef HAVE_DWARF_SUPPORT503	if (debug && nr_debug_entries) {504		retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);505		if (retval)506			goto error;507	} else508#endif509	{510		if (elf_update(e, ELF_C_WRITE) < 0) {511			warnx("elf_update 4 failed");512			goto error;513		}514	}515 516	retval = 0;517error:518	(void)elf_end(e);519 520	free(strsym);521 522 523	return retval;524}525