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