~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/util/genelf.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #ifdef HAVE_LIBCRYPTO_SUPPORT
 34 
 35 #define BUILD_ID_MD5
 36 #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_SHA
 40 #include <openssl/sha.h>
 41 #endif
 42 
 43 #ifdef BUILD_ID_MD5
 44 #include <openssl/evp.h>
 45 #include <openssl/md5.h>
 46 #endif
 47 #endif
 48 
 49 
 50 typedef 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 
 57 static 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 
 71 static 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 
 77 static 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_URANDOM
 96 static void
 97 gen_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 #endif
118 
119 #ifdef BUILD_ID_SHA
120 static void
121 gen_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 #endif
132 
133 #ifdef BUILD_ID_MD5
134 static void
135 gen_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 #endif
153 
154 static int
155 jit_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 section
165          */
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 section
199          */
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 file
236  * 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 code
239  * csize: the code size in bytes
240  */
241 int
242 jit_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 header
271          */
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 header
288          */
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 section
301          */
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_frame
335          */
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 table
348          */
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 section
381          */
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 table
418          * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
419          */
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 section
460          */
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 generation
475          */
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_SUPPORT
503         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         } else
508 #endif
509         {
510                 if (elf_update(e, ELF_C_WRITE) < 0) {
511                         warnx("elf_update 4 failed");
512                         goto error;
513                 }
514         }
515 
516         retval = 0;
517 error:
518         (void)elf_end(e);
519 
520         free(strsym);
521 
522 
523         return retval;
524 }
525 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php