1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
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 | |
13 | int 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 | |