1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
7 #include <linux/objtool.h>
8 #include <asm/orc_types.h>
12 static const char *reg_name(unsigned int reg
)
29 case ORC_REG_BP_INDIRECT
:
31 case ORC_REG_SP_INDIRECT
:
38 static const char *orc_type_name(unsigned int type
)
41 case UNWIND_HINT_TYPE_CALL
:
43 case UNWIND_HINT_TYPE_REGS
:
45 case UNWIND_HINT_TYPE_REGS_PARTIAL
:
46 return "regs (partial)";
52 static void print_reg(unsigned int reg
, int offset
)
54 if (reg
== ORC_REG_BP_INDIRECT
)
55 printf("(bp%+d)", offset
);
56 else if (reg
== ORC_REG_SP_INDIRECT
)
57 printf("(sp%+d)", offset
);
58 else if (reg
== ORC_REG_UNDEFINED
)
61 printf("%s%+d", reg_name(reg
), offset
);
64 int orc_dump(const char *_objname
)
66 int fd
, nr_entries
, i
, *orc_ip
= NULL
, orc_size
= 0;
67 struct orc_entry
*orc
= NULL
;
70 Elf64_Addr orc_ip_addr
= 0;
71 size_t shstrtab_idx
, strtab_idx
= 0;
77 Elf_Data
*data
, *symtab
= NULL
, *rela_orc_ip
= NULL
;
82 elf_version(EV_CURRENT
);
84 fd
= open(objname
, O_RDONLY
);
90 elf
= elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
92 WARN_ELF("elf_begin");
96 if (elf_getshdrnum(elf
, &nr_sections
)) {
97 WARN_ELF("elf_getshdrnum");
101 if (elf_getshdrstrndx(elf
, &shstrtab_idx
)) {
102 WARN_ELF("elf_getshdrstrndx");
106 for (i
= 0; i
< nr_sections
; i
++) {
107 scn
= elf_getscn(elf
, i
);
109 WARN_ELF("elf_getscn");
113 if (!gelf_getshdr(scn
, &sh
)) {
114 WARN_ELF("gelf_getshdr");
118 name
= elf_strptr(elf
, shstrtab_idx
, sh
.sh_name
);
120 WARN_ELF("elf_strptr");
124 data
= elf_getdata(scn
, NULL
);
126 WARN_ELF("elf_getdata");
130 if (!strcmp(name
, ".symtab")) {
132 } else if (!strcmp(name
, ".strtab")) {
134 } else if (!strcmp(name
, ".orc_unwind")) {
136 orc_size
= sh
.sh_size
;
137 } else if (!strcmp(name
, ".orc_unwind_ip")) {
138 orc_ip
= data
->d_buf
;
139 orc_ip_addr
= sh
.sh_addr
;
140 } else if (!strcmp(name
, ".rela.orc_unwind_ip")) {
145 if (!symtab
|| !strtab_idx
|| !orc
|| !orc_ip
)
148 if (orc_size
% sizeof(*orc
) != 0) {
149 WARN("bad .orc_unwind section size");
153 nr_entries
= orc_size
/ sizeof(*orc
);
154 for (i
= 0; i
< nr_entries
; i
++) {
156 if (!gelf_getrela(rela_orc_ip
, i
, &rela
)) {
157 WARN_ELF("gelf_getrela");
161 if (!gelf_getsym(symtab
, GELF_R_SYM(rela
.r_info
), &sym
)) {
162 WARN_ELF("gelf_getsym");
166 if (GELF_ST_TYPE(sym
.st_info
) == STT_SECTION
) {
167 scn
= elf_getscn(elf
, sym
.st_shndx
);
169 WARN_ELF("elf_getscn");
173 if (!gelf_getshdr(scn
, &sh
)) {
174 WARN_ELF("gelf_getshdr");
178 name
= elf_strptr(elf
, shstrtab_idx
, sh
.sh_name
);
180 WARN_ELF("elf_strptr");
184 name
= elf_strptr(elf
, strtab_idx
, sym
.st_name
);
186 WARN_ELF("elf_strptr");
191 printf("%s+%llx:", name
, (unsigned long long)rela
.r_addend
);
194 printf("%llx:", (unsigned long long)(orc_ip_addr
+ (i
* sizeof(int)) + orc_ip
[i
]));
200 print_reg(orc
[i
].sp_reg
, orc
[i
].sp_offset
);
204 print_reg(orc
[i
].bp_reg
, orc
[i
].bp_offset
);
206 printf(" type:%s end:%d\n",
207 orc_type_name(orc
[i
].type
), orc
[i
].end
);