xref: /kernel/linux/linux-5.10/tools/perf/util/genelf.c (revision 8c2ecf20)
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 <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_SUPPORT
20#include <dwarf.h>
21#endif
22
23#include "genelf.h"
24#include "../util/jitdump.h"
25#include <linux/compiler.h>
26
27#ifndef NT_GNU_BUILD_ID
28#define NT_GNU_BUILD_ID 3
29#endif
30
31#define BUILD_ID_URANDOM /* different uuid for each run */
32
33// FIXME, remove this and fix the deprecation warnings before its removed and
34// We'll break for good here...
35#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
36
37#ifdef HAVE_LIBCRYPTO_SUPPORT
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_Phdr *phdr;
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 program header
291	 */
292	phdr = elf_newphdr(e, 1);
293	phdr[0].p_type = PT_LOAD;
294	phdr[0].p_offset = GEN_ELF_TEXT_OFFSET;
295	phdr[0].p_vaddr = GEN_ELF_TEXT_OFFSET;
296	phdr[0].p_paddr = GEN_ELF_TEXT_OFFSET;
297	phdr[0].p_filesz = csize;
298	phdr[0].p_memsz = csize;
299	phdr[0].p_flags = PF_X | PF_R;
300	phdr[0].p_align = 8;
301
302	/*
303	 * setup text section
304	 */
305	scn = elf_newscn(e);
306	if (!scn) {
307		warnx("cannot create section");
308		goto error;
309	}
310
311	d = elf_newdata(scn);
312	if (!d) {
313		warnx("cannot get new data");
314		goto error;
315	}
316
317	d->d_align = 16;
318	d->d_off = 0LL;
319	d->d_buf = (void *)code;
320	d->d_type = ELF_T_BYTE;
321	d->d_size = csize;
322	d->d_version = EV_CURRENT;
323
324	shdr = elf_getshdr(scn);
325	if (!shdr) {
326		warnx("cannot get section header");
327		goto error;
328	}
329
330	shdr->sh_name = 1;
331	shdr->sh_type = SHT_PROGBITS;
332	shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
333	shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
334	shdr->sh_entsize = 0;
335
336	/*
337	 * Setup .eh_frame_hdr and .eh_frame
338	 */
339	if (unwinding) {
340		eh_frame_base_offset = ALIGN_8(GEN_ELF_TEXT_OFFSET + csize);
341		retval = jit_add_eh_frame_info(e, unwinding,
342					       unwinding_header_size, unwinding_size,
343					       eh_frame_base_offset);
344		if (retval)
345			goto error;
346	}
347
348	/*
349	 * setup section headers string table
350	 */
351	scn = elf_newscn(e);
352	if (!scn) {
353		warnx("cannot create section");
354		goto error;
355	}
356
357	d = elf_newdata(scn);
358	if (!d) {
359		warnx("cannot get new data");
360		goto error;
361	}
362
363	d->d_align = 1;
364	d->d_off = 0LL;
365	d->d_buf = shd_string_table;
366	d->d_type = ELF_T_BYTE;
367	d->d_size = sizeof(shd_string_table);
368	d->d_version = EV_CURRENT;
369
370	shdr = elf_getshdr(scn);
371	if (!shdr) {
372		warnx("cannot get section header");
373		goto error;
374	}
375
376	shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
377	shdr->sh_type = SHT_STRTAB;
378	shdr->sh_flags = 0;
379	shdr->sh_entsize = 0;
380
381	/*
382	 * setup symtab section
383	 */
384	symtab[1].st_size  = csize;
385	symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
386
387	scn = elf_newscn(e);
388	if (!scn) {
389		warnx("cannot create section");
390		goto error;
391	}
392
393	d = elf_newdata(scn);
394	if (!d) {
395		warnx("cannot get new data");
396		goto error;
397	}
398
399	d->d_align = 8;
400	d->d_off = 0LL;
401	d->d_buf = symtab;
402	d->d_type = ELF_T_SYM;
403	d->d_size = sizeof(symtab);
404	d->d_version = EV_CURRENT;
405
406	shdr = elf_getshdr(scn);
407	if (!shdr) {
408		warnx("cannot get section header");
409		goto error;
410	}
411
412	shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
413	shdr->sh_type = SHT_SYMTAB;
414	shdr->sh_flags = 0;
415	shdr->sh_entsize = sizeof(Elf_Sym);
416	shdr->sh_link = unwinding ? 6 : 4; /* index of .strtab section */
417
418	/*
419	 * setup symbols string table
420	 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
421	 */
422	symlen = 2 + strlen(sym);
423	strsym = calloc(1, symlen);
424	if (!strsym) {
425		warnx("cannot allocate strsym");
426		goto error;
427	}
428	strcpy(strsym + 1, sym);
429
430	scn = elf_newscn(e);
431	if (!scn) {
432		warnx("cannot create section");
433		goto error;
434	}
435
436	d = elf_newdata(scn);
437	if (!d) {
438		warnx("cannot get new data");
439		goto error;
440	}
441
442	d->d_align = 1;
443	d->d_off = 0LL;
444	d->d_buf = strsym;
445	d->d_type = ELF_T_BYTE;
446	d->d_size = symlen;
447	d->d_version = EV_CURRENT;
448
449	shdr = elf_getshdr(scn);
450	if (!shdr) {
451		warnx("cannot get section header");
452		goto error;
453	}
454
455	shdr->sh_name = 25; /* offset in shd_string_table */
456	shdr->sh_type = SHT_STRTAB;
457	shdr->sh_flags = 0;
458	shdr->sh_entsize = 0;
459
460	/*
461	 * setup build-id section
462	 */
463	scn = elf_newscn(e);
464	if (!scn) {
465		warnx("cannot create section");
466		goto error;
467	}
468
469	d = elf_newdata(scn);
470	if (!d) {
471		warnx("cannot get new data");
472		goto error;
473	}
474
475	/*
476	 * build-id generation
477	 */
478	gen_build_id(&bnote, load_addr, code, csize);
479	bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
480	bnote.desc.descsz = sizeof(bnote.build_id);
481	bnote.desc.type   = NT_GNU_BUILD_ID;
482	strcpy(bnote.name, "GNU");
483
484	d->d_align = 4;
485	d->d_off = 0LL;
486	d->d_buf = &bnote;
487	d->d_type = ELF_T_BYTE;
488	d->d_size = sizeof(bnote);
489	d->d_version = EV_CURRENT;
490
491	shdr = elf_getshdr(scn);
492	if (!shdr) {
493		warnx("cannot get section header");
494		goto error;
495	}
496
497	shdr->sh_name = 33; /* offset in shd_string_table */
498	shdr->sh_type = SHT_NOTE;
499	shdr->sh_addr = 0x0;
500	shdr->sh_flags = SHF_ALLOC;
501	shdr->sh_size = sizeof(bnote);
502	shdr->sh_entsize = 0;
503
504#ifdef HAVE_DWARF_SUPPORT
505	if (debug && nr_debug_entries) {
506		retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
507		if (retval)
508			goto error;
509	} else
510#endif
511	{
512		if (elf_update(e, ELF_C_WRITE) < 0) {
513			warnx("elf_update 4 failed");
514			goto error;
515		}
516	}
517
518	retval = 0;
519error:
520	(void)elf_end(e);
521
522	free(strsym);
523
524
525	return retval;
526}
527