elf_ops.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
  2. {
  3. bswap16s(&ehdr->e_type); /* Object file type */
  4. bswap16s(&ehdr->e_machine); /* Architecture */
  5. bswap32s(&ehdr->e_version); /* Object file version */
  6. bswapSZs(&ehdr->e_entry); /* Entry point virtual address */
  7. bswapSZs(&ehdr->e_phoff); /* Program header table file offset */
  8. bswapSZs(&ehdr->e_shoff); /* Section header table file offset */
  9. bswap32s(&ehdr->e_flags); /* Processor-specific flags */
  10. bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
  11. bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
  12. bswap16s(&ehdr->e_phnum); /* Program header table entry count */
  13. bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
  14. bswap16s(&ehdr->e_shnum); /* Section header table entry count */
  15. bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
  16. }
  17. static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
  18. {
  19. bswap32s(&phdr->p_type); /* Segment type */
  20. bswapSZs(&phdr->p_offset); /* Segment file offset */
  21. bswapSZs(&phdr->p_vaddr); /* Segment virtual address */
  22. bswapSZs(&phdr->p_paddr); /* Segment physical address */
  23. bswapSZs(&phdr->p_filesz); /* Segment size in file */
  24. bswapSZs(&phdr->p_memsz); /* Segment size in memory */
  25. bswap32s(&phdr->p_flags); /* Segment flags */
  26. bswapSZs(&phdr->p_align); /* Segment alignment */
  27. }
  28. static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
  29. {
  30. bswap32s(&shdr->sh_name);
  31. bswap32s(&shdr->sh_type);
  32. bswapSZs(&shdr->sh_flags);
  33. bswapSZs(&shdr->sh_addr);
  34. bswapSZs(&shdr->sh_offset);
  35. bswapSZs(&shdr->sh_size);
  36. bswap32s(&shdr->sh_link);
  37. bswap32s(&shdr->sh_info);
  38. bswapSZs(&shdr->sh_addralign);
  39. bswapSZs(&shdr->sh_entsize);
  40. }
  41. static void glue(bswap_sym, SZ)(struct elf_sym *sym)
  42. {
  43. bswap32s(&sym->st_name);
  44. bswapSZs(&sym->st_value);
  45. bswapSZs(&sym->st_size);
  46. bswap16s(&sym->st_shndx);
  47. }
  48. static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
  49. int n, int type)
  50. {
  51. int i;
  52. for(i=0;i<n;i++) {
  53. if (shdr_table[i].sh_type == type)
  54. return shdr_table + i;
  55. }
  56. return NULL;
  57. }
  58. static int glue(symfind, SZ)(const void *s0, const void *s1)
  59. {
  60. hwaddr addr = *(hwaddr *)s0;
  61. struct elf_sym *sym = (struct elf_sym *)s1;
  62. int result = 0;
  63. if (addr < sym->st_value) {
  64. result = -1;
  65. } else if (addr >= sym->st_value + sym->st_size) {
  66. result = 1;
  67. }
  68. return result;
  69. }
  70. static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
  71. hwaddr orig_addr)
  72. {
  73. struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
  74. struct elf_sym *sym;
  75. sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms),
  76. glue(symfind, SZ));
  77. if (sym != NULL) {
  78. return s->disas_strtab + sym->st_name;
  79. }
  80. return "";
  81. }
  82. static int glue(symcmp, SZ)(const void *s0, const void *s1)
  83. {
  84. struct elf_sym *sym0 = (struct elf_sym *)s0;
  85. struct elf_sym *sym1 = (struct elf_sym *)s1;
  86. return (sym0->st_value < sym1->st_value)
  87. ? -1
  88. : ((sym0->st_value > sym1->st_value) ? 1 : 0);
  89. }
  90. static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
  91. int clear_lsb)
  92. {
  93. struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
  94. struct elf_sym *syms = NULL;
  95. struct syminfo *s;
  96. int nsyms, i;
  97. char *str = NULL;
  98. shdr_table = load_at(fd, ehdr->e_shoff,
  99. sizeof(struct elf_shdr) * ehdr->e_shnum);
  100. if (!shdr_table)
  101. return -1;
  102. if (must_swab) {
  103. for (i = 0; i < ehdr->e_shnum; i++) {
  104. glue(bswap_shdr, SZ)(shdr_table + i);
  105. }
  106. }
  107. symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
  108. if (!symtab)
  109. goto fail;
  110. syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
  111. if (!syms)
  112. goto fail;
  113. nsyms = symtab->sh_size / sizeof(struct elf_sym);
  114. i = 0;
  115. while (i < nsyms) {
  116. if (must_swab)
  117. glue(bswap_sym, SZ)(&syms[i]);
  118. /* We are only interested in function symbols.
  119. Throw everything else away. */
  120. if (syms[i].st_shndx == SHN_UNDEF ||
  121. syms[i].st_shndx >= SHN_LORESERVE ||
  122. ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
  123. nsyms--;
  124. if (i < nsyms) {
  125. syms[i] = syms[nsyms];
  126. }
  127. continue;
  128. }
  129. if (clear_lsb) {
  130. /* The bottom address bit marks a Thumb or MIPS16 symbol. */
  131. syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
  132. }
  133. i++;
  134. }
  135. if (nsyms) {
  136. syms = g_realloc(syms, nsyms * sizeof(*syms));
  137. qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
  138. for (i = 0; i < nsyms - 1; i++) {
  139. if (syms[i].st_size == 0) {
  140. syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
  141. }
  142. }
  143. } else {
  144. g_free(syms);
  145. syms = NULL;
  146. }
  147. /* String table */
  148. if (symtab->sh_link >= ehdr->e_shnum)
  149. goto fail;
  150. strtab = &shdr_table[symtab->sh_link];
  151. str = load_at(fd, strtab->sh_offset, strtab->sh_size);
  152. if (!str)
  153. goto fail;
  154. /* Commit */
  155. s = g_malloc0(sizeof(*s));
  156. s->lookup_symbol = glue(lookup_symbol, SZ);
  157. glue(s->disas_symtab.elf, SZ) = syms;
  158. s->disas_num_syms = nsyms;
  159. s->disas_strtab = str;
  160. s->next = syminfos;
  161. syminfos = s;
  162. g_free(shdr_table);
  163. return 0;
  164. fail:
  165. g_free(syms);
  166. g_free(str);
  167. g_free(shdr_table);
  168. return -1;
  169. }
  170. static int glue(load_elf, SZ)(const char *name, int fd,
  171. uint64_t (*translate_fn)(void *, uint64_t),
  172. void *translate_opaque,
  173. int must_swab, uint64_t *pentry,
  174. uint64_t *lowaddr, uint64_t *highaddr,
  175. int elf_machine, int clear_lsb)
  176. {
  177. struct elfhdr ehdr;
  178. struct elf_phdr *phdr = NULL, *ph;
  179. int size, i, total_size;
  180. elf_word mem_size;
  181. uint64_t addr, low = (uint64_t)-1, high = 0;
  182. uint8_t *data = NULL;
  183. char label[128];
  184. if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
  185. goto fail;
  186. if (must_swab) {
  187. glue(bswap_ehdr, SZ)(&ehdr);
  188. }
  189. switch (elf_machine) {
  190. case EM_PPC64:
  191. if (EM_PPC64 != ehdr.e_machine)
  192. if (EM_PPC != ehdr.e_machine)
  193. goto fail;
  194. break;
  195. case EM_X86_64:
  196. if (EM_X86_64 != ehdr.e_machine)
  197. if (EM_386 != ehdr.e_machine)
  198. goto fail;
  199. break;
  200. case EM_MICROBLAZE:
  201. if (EM_MICROBLAZE != ehdr.e_machine)
  202. if (EM_MICROBLAZE_OLD != ehdr.e_machine)
  203. goto fail;
  204. break;
  205. default:
  206. if (elf_machine != ehdr.e_machine)
  207. goto fail;
  208. }
  209. if (pentry)
  210. *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
  211. glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb);
  212. size = ehdr.e_phnum * sizeof(phdr[0]);
  213. lseek(fd, ehdr.e_phoff, SEEK_SET);
  214. phdr = g_malloc0(size);
  215. if (!phdr)
  216. goto fail;
  217. if (read(fd, phdr, size) != size)
  218. goto fail;
  219. if (must_swab) {
  220. for(i = 0; i < ehdr.e_phnum; i++) {
  221. ph = &phdr[i];
  222. glue(bswap_phdr, SZ)(ph);
  223. }
  224. }
  225. total_size = 0;
  226. for(i = 0; i < ehdr.e_phnum; i++) {
  227. ph = &phdr[i];
  228. if (ph->p_type == PT_LOAD) {
  229. mem_size = ph->p_memsz;
  230. /* XXX: avoid allocating */
  231. data = g_malloc0(mem_size);
  232. if (ph->p_filesz > 0) {
  233. if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
  234. goto fail;
  235. if (read(fd, data, ph->p_filesz) != ph->p_filesz)
  236. goto fail;
  237. }
  238. /* address_offset is hack for kernel images that are
  239. linked at the wrong physical address. */
  240. if (translate_fn) {
  241. addr = translate_fn(translate_opaque, ph->p_paddr);
  242. } else {
  243. addr = ph->p_paddr;
  244. }
  245. /* the entry pointer in the ELF header is a virtual
  246. * address, if the text segments paddr and vaddr differ
  247. * we need to adjust the entry */
  248. if (pentry && !translate_fn &&
  249. ph->p_vaddr != ph->p_paddr &&
  250. ehdr.e_entry >= ph->p_vaddr &&
  251. ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
  252. ph->p_flags & PF_X) {
  253. *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
  254. }
  255. snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
  256. rom_add_blob_fixed(label, data, mem_size, addr);
  257. total_size += mem_size;
  258. if (addr < low)
  259. low = addr;
  260. if ((addr + mem_size) > high)
  261. high = addr + mem_size;
  262. g_free(data);
  263. data = NULL;
  264. }
  265. }
  266. g_free(phdr);
  267. if (lowaddr)
  268. *lowaddr = (uint64_t)(elf_sword)low;
  269. if (highaddr)
  270. *highaddr = (uint64_t)(elf_sword)high;
  271. return total_size;
  272. fail:
  273. g_free(data);
  274. g_free(phdr);
  275. return -1;
  276. }