orc_dump.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
  4. */
  5. #include <unistd.h>
  6. #include <asm/orc_types.h>
  7. #include <objtool/objtool.h>
  8. #include <objtool/orc.h>
  9. #include <objtool/warn.h>
  10. #include <objtool/endianness.h>
  11. int orc_dump(const char *_objname)
  12. {
  13. int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
  14. struct orc_entry *orc = NULL;
  15. char *name;
  16. size_t nr_sections;
  17. Elf64_Addr orc_ip_addr = 0;
  18. size_t shstrtab_idx, strtab_idx = 0;
  19. Elf *elf;
  20. Elf_Scn *scn;
  21. GElf_Shdr sh;
  22. GElf_Rela rela;
  23. GElf_Sym sym;
  24. Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL;
  25. struct elf dummy_elf = {};
  26. objname = _objname;
  27. elf_version(EV_CURRENT);
  28. fd = open(objname, O_RDONLY);
  29. if (fd == -1) {
  30. perror("open");
  31. return -1;
  32. }
  33. elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
  34. if (!elf) {
  35. WARN_ELF("elf_begin");
  36. return -1;
  37. }
  38. if (!elf64_getehdr(elf)) {
  39. WARN_ELF("elf64_getehdr");
  40. return -1;
  41. }
  42. memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr));
  43. if (elf_getshdrnum(elf, &nr_sections)) {
  44. WARN_ELF("elf_getshdrnum");
  45. return -1;
  46. }
  47. if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
  48. WARN_ELF("elf_getshdrstrndx");
  49. return -1;
  50. }
  51. for (i = 0; i < nr_sections; i++) {
  52. scn = elf_getscn(elf, i);
  53. if (!scn) {
  54. WARN_ELF("elf_getscn");
  55. return -1;
  56. }
  57. if (!gelf_getshdr(scn, &sh)) {
  58. WARN_ELF("gelf_getshdr");
  59. return -1;
  60. }
  61. name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
  62. if (!name) {
  63. WARN_ELF("elf_strptr");
  64. return -1;
  65. }
  66. data = elf_getdata(scn, NULL);
  67. if (!data) {
  68. WARN_ELF("elf_getdata");
  69. return -1;
  70. }
  71. if (!strcmp(name, ".symtab")) {
  72. symtab = data;
  73. } else if (!strcmp(name, ".strtab")) {
  74. strtab_idx = i;
  75. } else if (!strcmp(name, ".orc_unwind")) {
  76. orc = data->d_buf;
  77. orc_size = sh.sh_size;
  78. } else if (!strcmp(name, ".orc_unwind_ip")) {
  79. orc_ip = data->d_buf;
  80. orc_ip_addr = sh.sh_addr;
  81. } else if (!strcmp(name, ".rela.orc_unwind_ip")) {
  82. rela_orc_ip = data;
  83. }
  84. }
  85. if (!symtab || !strtab_idx || !orc || !orc_ip)
  86. return 0;
  87. if (orc_size % sizeof(*orc) != 0) {
  88. WARN("bad .orc_unwind section size");
  89. return -1;
  90. }
  91. nr_entries = orc_size / sizeof(*orc);
  92. for (i = 0; i < nr_entries; i++) {
  93. if (rela_orc_ip) {
  94. if (!gelf_getrela(rela_orc_ip, i, &rela)) {
  95. WARN_ELF("gelf_getrela");
  96. return -1;
  97. }
  98. if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
  99. WARN_ELF("gelf_getsym");
  100. return -1;
  101. }
  102. if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
  103. scn = elf_getscn(elf, sym.st_shndx);
  104. if (!scn) {
  105. WARN_ELF("elf_getscn");
  106. return -1;
  107. }
  108. if (!gelf_getshdr(scn, &sh)) {
  109. WARN_ELF("gelf_getshdr");
  110. return -1;
  111. }
  112. name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
  113. if (!name) {
  114. WARN_ELF("elf_strptr");
  115. return -1;
  116. }
  117. } else {
  118. name = elf_strptr(elf, strtab_idx, sym.st_name);
  119. if (!name) {
  120. WARN_ELF("elf_strptr");
  121. return -1;
  122. }
  123. }
  124. printf("%s+%llx:", name, (unsigned long long)rela.r_addend);
  125. } else {
  126. printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i]));
  127. }
  128. orc_print_dump(&dummy_elf, orc, i);
  129. }
  130. elf_end(elf);
  131. close(fd);
  132. return 0;
  133. }