orc_dump.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <unistd.h>
  18. #include "orc.h"
  19. #include "warn.h"
  20. static const char *reg_name(unsigned int reg)
  21. {
  22. switch (reg) {
  23. case ORC_REG_PREV_SP:
  24. return "prevsp";
  25. case ORC_REG_DX:
  26. return "dx";
  27. case ORC_REG_DI:
  28. return "di";
  29. case ORC_REG_BP:
  30. return "bp";
  31. case ORC_REG_SP:
  32. return "sp";
  33. case ORC_REG_R10:
  34. return "r10";
  35. case ORC_REG_R13:
  36. return "r13";
  37. case ORC_REG_BP_INDIRECT:
  38. return "bp(ind)";
  39. case ORC_REG_SP_INDIRECT:
  40. return "sp(ind)";
  41. default:
  42. return "?";
  43. }
  44. }
  45. static const char *orc_type_name(unsigned int type)
  46. {
  47. switch (type) {
  48. case ORC_TYPE_CALL:
  49. return "call";
  50. case ORC_TYPE_REGS:
  51. return "regs";
  52. case ORC_TYPE_REGS_IRET:
  53. return "iret";
  54. default:
  55. return "?";
  56. }
  57. }
  58. static void print_reg(unsigned int reg, int offset)
  59. {
  60. if (reg == ORC_REG_BP_INDIRECT)
  61. printf("(bp%+d)", offset);
  62. else if (reg == ORC_REG_SP_INDIRECT)
  63. printf("(sp%+d)", offset);
  64. else if (reg == ORC_REG_UNDEFINED)
  65. printf("(und)");
  66. else
  67. printf("%s%+d", reg_name(reg), offset);
  68. }
  69. int orc_dump(const char *_objname)
  70. {
  71. int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
  72. struct orc_entry *orc = NULL;
  73. char *name;
  74. size_t nr_sections;
  75. Elf64_Addr orc_ip_addr = 0;
  76. size_t shstrtab_idx;
  77. Elf *elf;
  78. Elf_Scn *scn;
  79. GElf_Shdr sh;
  80. GElf_Rela rela;
  81. GElf_Sym sym;
  82. Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL;
  83. objname = _objname;
  84. elf_version(EV_CURRENT);
  85. fd = open(objname, O_RDONLY);
  86. if (fd == -1) {
  87. perror("open");
  88. return -1;
  89. }
  90. elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
  91. if (!elf) {
  92. WARN_ELF("elf_begin");
  93. return -1;
  94. }
  95. if (elf_getshdrnum(elf, &nr_sections)) {
  96. WARN_ELF("elf_getshdrnum");
  97. return -1;
  98. }
  99. if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
  100. WARN_ELF("elf_getshdrstrndx");
  101. return -1;
  102. }
  103. for (i = 0; i < nr_sections; i++) {
  104. scn = elf_getscn(elf, i);
  105. if (!scn) {
  106. WARN_ELF("elf_getscn");
  107. return -1;
  108. }
  109. if (!gelf_getshdr(scn, &sh)) {
  110. WARN_ELF("gelf_getshdr");
  111. return -1;
  112. }
  113. name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
  114. if (!name) {
  115. WARN_ELF("elf_strptr");
  116. return -1;
  117. }
  118. data = elf_getdata(scn, NULL);
  119. if (!data) {
  120. WARN_ELF("elf_getdata");
  121. return -1;
  122. }
  123. if (!strcmp(name, ".symtab")) {
  124. symtab = data;
  125. } else if (!strcmp(name, ".orc_unwind")) {
  126. orc = data->d_buf;
  127. orc_size = sh.sh_size;
  128. } else if (!strcmp(name, ".orc_unwind_ip")) {
  129. orc_ip = data->d_buf;
  130. orc_ip_addr = sh.sh_addr;
  131. } else if (!strcmp(name, ".rela.orc_unwind_ip")) {
  132. rela_orc_ip = data;
  133. }
  134. }
  135. if (!symtab || !orc || !orc_ip)
  136. return 0;
  137. if (orc_size % sizeof(*orc) != 0) {
  138. WARN("bad .orc_unwind section size");
  139. return -1;
  140. }
  141. nr_entries = orc_size / sizeof(*orc);
  142. for (i = 0; i < nr_entries; i++) {
  143. if (rela_orc_ip) {
  144. if (!gelf_getrela(rela_orc_ip, i, &rela)) {
  145. WARN_ELF("gelf_getrela");
  146. return -1;
  147. }
  148. if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
  149. WARN_ELF("gelf_getsym");
  150. return -1;
  151. }
  152. scn = elf_getscn(elf, sym.st_shndx);
  153. if (!scn) {
  154. WARN_ELF("elf_getscn");
  155. return -1;
  156. }
  157. if (!gelf_getshdr(scn, &sh)) {
  158. WARN_ELF("gelf_getshdr");
  159. return -1;
  160. }
  161. name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
  162. if (!name || !*name) {
  163. WARN_ELF("elf_strptr");
  164. return -1;
  165. }
  166. printf("%s+%llx:", name, (unsigned long long)rela.r_addend);
  167. } else {
  168. printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i]));
  169. }
  170. printf(" sp:");
  171. print_reg(orc[i].sp_reg, orc[i].sp_offset);
  172. printf(" bp:");
  173. print_reg(orc[i].bp_reg, orc[i].bp_offset);
  174. printf(" type:%s end:%d\n",
  175. orc_type_name(orc[i].type), orc[i].end);
  176. }
  177. elf_end(elf);
  178. close(fd);
  179. return 0;
  180. }