orc_dump.c 3.1 KB

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