genelf.c 9.2 KB

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