GNU Linux-libre 4.9.328-gnu1
[releases.git] / tools / perf / util / genelf.c
1 /*
2  * genelf.c
3  * Copyright (C) 2014, Google, Inc
4  *
5  * Contributed by:
6  *      Stephane Eranian <eranian@gmail.com>
7  *
8  * Released under the GPL v2. (and only v2, not any later version)
9  */
10
11 #include <sys/types.h>
12 #include <stdio.h>
13 #include <getopt.h>
14 #include <stddef.h>
15 #include <libelf.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <inttypes.h>
19 #include <limits.h>
20 #include <fcntl.h>
21 #include <err.h>
22 #ifdef HAVE_DWARF_SUPPORT
23 #include <dwarf.h>
24 #endif
25
26 #include "perf.h"
27 #include "genelf.h"
28 #include "../util/jitdump.h"
29
30 #define JVMTI
31
32 #define BUILD_ID_URANDOM /* different uuid for each run */
33
34 #ifdef HAVE_LIBCRYPTO
35
36 #define BUILD_ID_MD5
37 #undef BUILD_ID_SHA     /* does not seem to work well when linked with Java */
38 #undef BUILD_ID_URANDOM /* different uuid for each run */
39
40 #ifdef BUILD_ID_SHA
41 #include <openssl/sha.h>
42 #endif
43
44 #ifdef BUILD_ID_MD5
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 struct options {
58         char *output;
59         int fd;
60 };
61
62 static char shd_string_table[] = {
63         0,
64         '.', 't', 'e', 'x', 't', 0,                     /*  1 */
65         '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /*  7 */
66         '.', 's', 'y', 'm', 't', 'a', 'b', 0,           /* 17 */
67         '.', 's', 't', 'r', 't', 'a', 'b', 0,           /* 25 */
68         '.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */
69         '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
70         '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
71         '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
72 };
73
74 static struct buildid_note {
75         Elf_Note desc;          /* descsz: size of build-id, must be multiple of 4 */
76         char     name[4];       /* GNU\0 */
77         char     build_id[20];
78 } bnote;
79
80 static Elf_Sym symtab[]={
81         /* symbol 0 MUST be the undefined symbol */
82         { .st_name  = 0, /* index in sym_string table */
83           .st_info  = ELF_ST_TYPE(STT_NOTYPE),
84           .st_shndx = 0, /* for now */
85           .st_value = 0x0,
86           .st_other = ELF_ST_VIS(STV_DEFAULT),
87           .st_size  = 0,
88         },
89         { .st_name  = 1, /* index in sym_string table */
90           .st_info  = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
91           .st_shndx = 1,
92           .st_value = 0, /* for now */
93           .st_other = ELF_ST_VIS(STV_DEFAULT),
94           .st_size  = 0, /* for now */
95         }
96 };
97
98 #ifdef BUILD_ID_URANDOM
99 static void
100 gen_build_id(struct buildid_note *note,
101              unsigned long load_addr __maybe_unused,
102              const void *code __maybe_unused,
103              size_t csize __maybe_unused)
104 {
105         int fd;
106         size_t sz = sizeof(note->build_id);
107         ssize_t sret;
108
109         fd = open("/dev/urandom", O_RDONLY);
110         if (fd == -1)
111                 err(1, "cannot access /dev/urandom for builid");
112
113         sret = read(fd, note->build_id, sz);
114
115         close(fd);
116
117         if (sret != (ssize_t)sz)
118                 memset(note->build_id, 0, sz);
119 }
120 #endif
121
122 #ifdef BUILD_ID_SHA
123 static void
124 gen_build_id(struct buildid_note *note,
125              unsigned long load_addr __maybe_unused,
126              const void *code,
127              size_t csize)
128 {
129         if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
130                 errx(1, "build_id too small for SHA1");
131
132         SHA1(code, csize, (unsigned char *)note->build_id);
133 }
134 #endif
135
136 #ifdef BUILD_ID_MD5
137 static void
138 gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
139 {
140         MD5_CTX context;
141
142         if (sizeof(note->build_id) < 16)
143                 errx(1, "build_id too small for MD5");
144
145         MD5_Init(&context);
146         MD5_Update(&context, &load_addr, sizeof(load_addr));
147         MD5_Update(&context, code, csize);
148         MD5_Final((unsigned char *)note->build_id, &context);
149 }
150 #endif
151
152 /*
153  * fd: file descriptor open for writing for the output file
154  * load_addr: code load address (could be zero, just used for buildid)
155  * sym: function name (for native code - used as the symbol)
156  * code: the native code
157  * csize: the code size in bytes
158  */
159 int
160 jit_write_elf(int fd, uint64_t load_addr, const char *sym,
161               const void *code, int csize,
162               void *debug __maybe_unused, int nr_debug_entries __maybe_unused)
163 {
164         Elf *e;
165         Elf_Data *d;
166         Elf_Scn *scn;
167         Elf_Ehdr *ehdr;
168         Elf_Shdr *shdr;
169         char *strsym = NULL;
170         int symlen;
171         int retval = -1;
172
173         if (elf_version(EV_CURRENT) == EV_NONE) {
174                 warnx("ELF initialization failed");
175                 return -1;
176         }
177
178         e = elf_begin(fd, ELF_C_WRITE, NULL);
179         if (!e) {
180                 warnx("elf_begin failed");
181                 goto error;
182         }
183
184         /*
185          * setup ELF header
186          */
187         ehdr = elf_newehdr(e);
188         if (!ehdr) {
189                 warnx("cannot get ehdr");
190                 goto error;
191         }
192
193         ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
194         ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
195         ehdr->e_machine = GEN_ELF_ARCH;
196         ehdr->e_type = ET_DYN;
197         ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
198         ehdr->e_version = EV_CURRENT;
199         ehdr->e_shstrndx= 2; /* shdr index for section name */
200
201         /*
202          * setup text section
203          */
204         scn = elf_newscn(e);
205         if (!scn) {
206                 warnx("cannot create section");
207                 goto error;
208         }
209
210         d = elf_newdata(scn);
211         if (!d) {
212                 warnx("cannot get new data");
213                 goto error;
214         }
215
216         d->d_align = 16;
217         d->d_off = 0LL;
218         d->d_buf = (void *)code;
219         d->d_type = ELF_T_BYTE;
220         d->d_size = csize;
221         d->d_version = EV_CURRENT;
222
223         shdr = elf_getshdr(scn);
224         if (!shdr) {
225                 warnx("cannot get section header");
226                 goto error;
227         }
228
229         shdr->sh_name = 1;
230         shdr->sh_type = SHT_PROGBITS;
231         shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
232         shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
233         shdr->sh_entsize = 0;
234
235         /*
236          * setup section headers string table
237          */
238         scn = elf_newscn(e);
239         if (!scn) {
240                 warnx("cannot create section");
241                 goto error;
242         }
243
244         d = elf_newdata(scn);
245         if (!d) {
246                 warnx("cannot get new data");
247                 goto error;
248         }
249
250         d->d_align = 1;
251         d->d_off = 0LL;
252         d->d_buf = shd_string_table;
253         d->d_type = ELF_T_BYTE;
254         d->d_size = sizeof(shd_string_table);
255         d->d_version = EV_CURRENT;
256
257         shdr = elf_getshdr(scn);
258         if (!shdr) {
259                 warnx("cannot get section header");
260                 goto error;
261         }
262
263         shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
264         shdr->sh_type = SHT_STRTAB;
265         shdr->sh_flags = 0;
266         shdr->sh_entsize = 0;
267
268         /*
269          * setup symtab section
270          */
271         symtab[1].st_size  = csize;
272         symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
273
274         scn = elf_newscn(e);
275         if (!scn) {
276                 warnx("cannot create section");
277                 goto error;
278         }
279
280         d = elf_newdata(scn);
281         if (!d) {
282                 warnx("cannot get new data");
283                 goto error;
284         }
285
286         d->d_align = 8;
287         d->d_off = 0LL;
288         d->d_buf = symtab;
289         d->d_type = ELF_T_SYM;
290         d->d_size = sizeof(symtab);
291         d->d_version = EV_CURRENT;
292
293         shdr = elf_getshdr(scn);
294         if (!shdr) {
295                 warnx("cannot get section header");
296                 goto error;
297         }
298
299         shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
300         shdr->sh_type = SHT_SYMTAB;
301         shdr->sh_flags = 0;
302         shdr->sh_entsize = sizeof(Elf_Sym);
303         shdr->sh_link = 4; /* index of .strtab section */
304
305         /*
306          * setup symbols string table
307          * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
308          */
309         symlen = 2 + strlen(sym);
310         strsym = calloc(1, symlen);
311         if (!strsym) {
312                 warnx("cannot allocate strsym");
313                 goto error;
314         }
315         strcpy(strsym + 1, sym);
316
317         scn = elf_newscn(e);
318         if (!scn) {
319                 warnx("cannot create section");
320                 goto error;
321         }
322
323         d = elf_newdata(scn);
324         if (!d) {
325                 warnx("cannot get new data");
326                 goto error;
327         }
328
329         d->d_align = 1;
330         d->d_off = 0LL;
331         d->d_buf = strsym;
332         d->d_type = ELF_T_BYTE;
333         d->d_size = symlen;
334         d->d_version = EV_CURRENT;
335
336         shdr = elf_getshdr(scn);
337         if (!shdr) {
338                 warnx("cannot get section header");
339                 goto error;
340         }
341
342         shdr->sh_name = 25; /* offset in shd_string_table */
343         shdr->sh_type = SHT_STRTAB;
344         shdr->sh_flags = 0;
345         shdr->sh_entsize = 0;
346
347         /*
348          * setup build-id section
349          */
350         scn = elf_newscn(e);
351         if (!scn) {
352                 warnx("cannot create section");
353                 goto error;
354         }
355
356         d = elf_newdata(scn);
357         if (!d) {
358                 warnx("cannot get new data");
359                 goto error;
360         }
361
362         /*
363          * build-id generation
364          */
365         gen_build_id(&bnote, load_addr, code, csize);
366         bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
367         bnote.desc.descsz = sizeof(bnote.build_id);
368         bnote.desc.type   = NT_GNU_BUILD_ID;
369         strcpy(bnote.name, "GNU");
370
371         d->d_align = 4;
372         d->d_off = 0LL;
373         d->d_buf = &bnote;
374         d->d_type = ELF_T_BYTE;
375         d->d_size = sizeof(bnote);
376         d->d_version = EV_CURRENT;
377
378         shdr = elf_getshdr(scn);
379         if (!shdr) {
380                 warnx("cannot get section header");
381                 goto error;
382         }
383
384         shdr->sh_name = 33; /* offset in shd_string_table */
385         shdr->sh_type = SHT_NOTE;
386         shdr->sh_addr = 0x0;
387         shdr->sh_flags = SHF_ALLOC;
388         shdr->sh_size = sizeof(bnote);
389         shdr->sh_entsize = 0;
390
391 #ifdef HAVE_DWARF_SUPPORT
392         if (debug && nr_debug_entries) {
393                 retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
394                 if (retval)
395                         goto error;
396         } else
397 #endif
398         {
399                 if (elf_update(e, ELF_C_WRITE) < 0) {
400                         warnx("elf_update 4 failed");
401                         goto error;
402                 }
403         }
404
405         retval = 0;
406 error:
407         (void)elf_end(e);
408
409         free(strsym);
410
411
412         return retval;
413 }
414
415 #ifndef JVMTI
416
417 static unsigned char x86_code[] = {
418     0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */
419     0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */
420     0xCD, 0x80            /* int $0x80 */
421 };
422
423 static struct options options;
424
425 int main(int argc, char **argv)
426 {
427         int c, fd, ret;
428
429         while ((c = getopt(argc, argv, "o:h")) != -1) {
430                 switch (c) {
431                 case 'o':
432                         options.output = optarg;
433                         break;
434                 case 'h':
435                         printf("Usage: genelf -o output_file [-h]\n");
436                         return 0;
437                 default:
438                         errx(1, "unknown option");
439                 }
440         }
441
442         fd = open(options.output, O_CREAT|O_TRUNC|O_RDWR, 0666);
443         if (fd == -1)
444                 err(1, "cannot create file %s", options.output);
445
446         ret = jit_write_elf(fd, "main", x86_code, sizeof(x86_code));
447         close(fd);
448
449         if (ret != 0)
450                 unlink(options.output);
451
452         return ret;
453 }
454 #endif