2 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
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.
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.
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/>.
22 static const char *reg_name(unsigned int reg
)
39 case ORC_REG_BP_INDIRECT
:
41 case ORC_REG_SP_INDIRECT
:
48 static const char *orc_type_name(unsigned int type
)
55 case ORC_TYPE_REGS_IRET
:
62 static void print_reg(unsigned int reg
, int offset
)
64 if (reg
== ORC_REG_BP_INDIRECT
)
65 printf("(bp%+d)", offset
);
66 else if (reg
== ORC_REG_SP_INDIRECT
)
67 printf("(sp%+d)", offset
);
68 else if (reg
== ORC_REG_UNDEFINED
)
71 printf("%s%+d", reg_name(reg
), offset
);
74 int orc_dump(const char *_objname
)
76 int fd
, nr_entries
, i
, *orc_ip
= NULL
, orc_size
= 0;
77 struct orc_entry
*orc
= NULL
;
79 unsigned long nr_sections
, orc_ip_addr
= 0;
86 Elf_Data
*data
, *symtab
= NULL
, *rela_orc_ip
= NULL
;
91 elf_version(EV_CURRENT
);
93 fd
= open(objname
, O_RDONLY
);
99 elf
= elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
101 WARN_ELF("elf_begin");
105 if (elf_getshdrnum(elf
, &nr_sections
)) {
106 WARN_ELF("elf_getshdrnum");
110 if (elf_getshdrstrndx(elf
, &shstrtab_idx
)) {
111 WARN_ELF("elf_getshdrstrndx");
115 for (i
= 0; i
< nr_sections
; i
++) {
116 scn
= elf_getscn(elf
, i
);
118 WARN_ELF("elf_getscn");
122 if (!gelf_getshdr(scn
, &sh
)) {
123 WARN_ELF("gelf_getshdr");
127 name
= elf_strptr(elf
, shstrtab_idx
, sh
.sh_name
);
129 WARN_ELF("elf_strptr");
133 data
= elf_getdata(scn
, NULL
);
135 WARN_ELF("elf_getdata");
139 if (!strcmp(name
, ".symtab")) {
141 } else if (!strcmp(name
, ".orc_unwind")) {
143 orc_size
= sh
.sh_size
;
144 } else if (!strcmp(name
, ".orc_unwind_ip")) {
145 orc_ip
= data
->d_buf
;
146 orc_ip_addr
= sh
.sh_addr
;
147 } else if (!strcmp(name
, ".rela.orc_unwind_ip")) {
152 if (!symtab
|| !orc
|| !orc_ip
)
155 if (orc_size
% sizeof(*orc
) != 0) {
156 WARN("bad .orc_unwind section size");
160 nr_entries
= orc_size
/ sizeof(*orc
);
161 for (i
= 0; i
< nr_entries
; i
++) {
163 if (!gelf_getrela(rela_orc_ip
, i
, &rela
)) {
164 WARN_ELF("gelf_getrela");
168 if (!gelf_getsym(symtab
, GELF_R_SYM(rela
.r_info
), &sym
)) {
169 WARN_ELF("gelf_getsym");
173 scn
= elf_getscn(elf
, sym
.st_shndx
);
175 WARN_ELF("elf_getscn");
179 if (!gelf_getshdr(scn
, &sh
)) {
180 WARN_ELF("gelf_getshdr");
184 name
= elf_strptr(elf
, shstrtab_idx
, sh
.sh_name
);
185 if (!name
|| !*name
) {
186 WARN_ELF("elf_strptr");
190 printf("%s+%lx:", name
, rela
.r_addend
);
193 printf("%lx:", orc_ip_addr
+ (i
* sizeof(int)) + orc_ip
[i
]);
199 print_reg(orc
[i
].sp_reg
, orc
[i
].sp_offset
);
203 print_reg(orc
[i
].bp_reg
, orc
[i
].bp_offset
);
205 printf(" type:%s\n", orc_type_name(orc
[i
].type
));