1*627fce14SJosh Poimboeuf /* 2*627fce14SJosh Poimboeuf * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> 3*627fce14SJosh Poimboeuf * 4*627fce14SJosh Poimboeuf * This program is free software; you can redistribute it and/or 5*627fce14SJosh Poimboeuf * modify it under the terms of the GNU General Public License 6*627fce14SJosh Poimboeuf * as published by the Free Software Foundation; either version 2 7*627fce14SJosh Poimboeuf * of the License, or (at your option) any later version. 8*627fce14SJosh Poimboeuf * 9*627fce14SJosh Poimboeuf * This program is distributed in the hope that it will be useful, 10*627fce14SJosh Poimboeuf * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*627fce14SJosh Poimboeuf * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*627fce14SJosh Poimboeuf * GNU General Public License for more details. 13*627fce14SJosh Poimboeuf * 14*627fce14SJosh Poimboeuf * You should have received a copy of the GNU General Public License 15*627fce14SJosh Poimboeuf * along with this program; if not, see <http://www.gnu.org/licenses/>. 16*627fce14SJosh Poimboeuf */ 17*627fce14SJosh Poimboeuf 18*627fce14SJosh Poimboeuf #include <unistd.h> 19*627fce14SJosh Poimboeuf #include "orc.h" 20*627fce14SJosh Poimboeuf #include "warn.h" 21*627fce14SJosh Poimboeuf 22*627fce14SJosh Poimboeuf static const char *reg_name(unsigned int reg) 23*627fce14SJosh Poimboeuf { 24*627fce14SJosh Poimboeuf switch (reg) { 25*627fce14SJosh Poimboeuf case ORC_REG_PREV_SP: 26*627fce14SJosh Poimboeuf return "prevsp"; 27*627fce14SJosh Poimboeuf case ORC_REG_DX: 28*627fce14SJosh Poimboeuf return "dx"; 29*627fce14SJosh Poimboeuf case ORC_REG_DI: 30*627fce14SJosh Poimboeuf return "di"; 31*627fce14SJosh Poimboeuf case ORC_REG_BP: 32*627fce14SJosh Poimboeuf return "bp"; 33*627fce14SJosh Poimboeuf case ORC_REG_SP: 34*627fce14SJosh Poimboeuf return "sp"; 35*627fce14SJosh Poimboeuf case ORC_REG_R10: 36*627fce14SJosh Poimboeuf return "r10"; 37*627fce14SJosh Poimboeuf case ORC_REG_R13: 38*627fce14SJosh Poimboeuf return "r13"; 39*627fce14SJosh Poimboeuf case ORC_REG_BP_INDIRECT: 40*627fce14SJosh Poimboeuf return "bp(ind)"; 41*627fce14SJosh Poimboeuf case ORC_REG_SP_INDIRECT: 42*627fce14SJosh Poimboeuf return "sp(ind)"; 43*627fce14SJosh Poimboeuf default: 44*627fce14SJosh Poimboeuf return "?"; 45*627fce14SJosh Poimboeuf } 46*627fce14SJosh Poimboeuf } 47*627fce14SJosh Poimboeuf 48*627fce14SJosh Poimboeuf static const char *orc_type_name(unsigned int type) 49*627fce14SJosh Poimboeuf { 50*627fce14SJosh Poimboeuf switch (type) { 51*627fce14SJosh Poimboeuf case ORC_TYPE_CALL: 52*627fce14SJosh Poimboeuf return "call"; 53*627fce14SJosh Poimboeuf case ORC_TYPE_REGS: 54*627fce14SJosh Poimboeuf return "regs"; 55*627fce14SJosh Poimboeuf case ORC_TYPE_REGS_IRET: 56*627fce14SJosh Poimboeuf return "iret"; 57*627fce14SJosh Poimboeuf default: 58*627fce14SJosh Poimboeuf return "?"; 59*627fce14SJosh Poimboeuf } 60*627fce14SJosh Poimboeuf } 61*627fce14SJosh Poimboeuf 62*627fce14SJosh Poimboeuf static void print_reg(unsigned int reg, int offset) 63*627fce14SJosh Poimboeuf { 64*627fce14SJosh Poimboeuf if (reg == ORC_REG_BP_INDIRECT) 65*627fce14SJosh Poimboeuf printf("(bp%+d)", offset); 66*627fce14SJosh Poimboeuf else if (reg == ORC_REG_SP_INDIRECT) 67*627fce14SJosh Poimboeuf printf("(sp%+d)", offset); 68*627fce14SJosh Poimboeuf else if (reg == ORC_REG_UNDEFINED) 69*627fce14SJosh Poimboeuf printf("(und)"); 70*627fce14SJosh Poimboeuf else 71*627fce14SJosh Poimboeuf printf("%s%+d", reg_name(reg), offset); 72*627fce14SJosh Poimboeuf } 73*627fce14SJosh Poimboeuf 74*627fce14SJosh Poimboeuf int orc_dump(const char *_objname) 75*627fce14SJosh Poimboeuf { 76*627fce14SJosh Poimboeuf int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0; 77*627fce14SJosh Poimboeuf struct orc_entry *orc = NULL; 78*627fce14SJosh Poimboeuf char *name; 79*627fce14SJosh Poimboeuf unsigned long nr_sections, orc_ip_addr = 0; 80*627fce14SJosh Poimboeuf size_t shstrtab_idx; 81*627fce14SJosh Poimboeuf Elf *elf; 82*627fce14SJosh Poimboeuf Elf_Scn *scn; 83*627fce14SJosh Poimboeuf GElf_Shdr sh; 84*627fce14SJosh Poimboeuf GElf_Rela rela; 85*627fce14SJosh Poimboeuf GElf_Sym sym; 86*627fce14SJosh Poimboeuf Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL; 87*627fce14SJosh Poimboeuf 88*627fce14SJosh Poimboeuf 89*627fce14SJosh Poimboeuf objname = _objname; 90*627fce14SJosh Poimboeuf 91*627fce14SJosh Poimboeuf elf_version(EV_CURRENT); 92*627fce14SJosh Poimboeuf 93*627fce14SJosh Poimboeuf fd = open(objname, O_RDONLY); 94*627fce14SJosh Poimboeuf if (fd == -1) { 95*627fce14SJosh Poimboeuf perror("open"); 96*627fce14SJosh Poimboeuf return -1; 97*627fce14SJosh Poimboeuf } 98*627fce14SJosh Poimboeuf 99*627fce14SJosh Poimboeuf elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 100*627fce14SJosh Poimboeuf if (!elf) { 101*627fce14SJosh Poimboeuf WARN_ELF("elf_begin"); 102*627fce14SJosh Poimboeuf return -1; 103*627fce14SJosh Poimboeuf } 104*627fce14SJosh Poimboeuf 105*627fce14SJosh Poimboeuf if (elf_getshdrnum(elf, &nr_sections)) { 106*627fce14SJosh Poimboeuf WARN_ELF("elf_getshdrnum"); 107*627fce14SJosh Poimboeuf return -1; 108*627fce14SJosh Poimboeuf } 109*627fce14SJosh Poimboeuf 110*627fce14SJosh Poimboeuf if (elf_getshdrstrndx(elf, &shstrtab_idx)) { 111*627fce14SJosh Poimboeuf WARN_ELF("elf_getshdrstrndx"); 112*627fce14SJosh Poimboeuf return -1; 113*627fce14SJosh Poimboeuf } 114*627fce14SJosh Poimboeuf 115*627fce14SJosh Poimboeuf for (i = 0; i < nr_sections; i++) { 116*627fce14SJosh Poimboeuf scn = elf_getscn(elf, i); 117*627fce14SJosh Poimboeuf if (!scn) { 118*627fce14SJosh Poimboeuf WARN_ELF("elf_getscn"); 119*627fce14SJosh Poimboeuf return -1; 120*627fce14SJosh Poimboeuf } 121*627fce14SJosh Poimboeuf 122*627fce14SJosh Poimboeuf if (!gelf_getshdr(scn, &sh)) { 123*627fce14SJosh Poimboeuf WARN_ELF("gelf_getshdr"); 124*627fce14SJosh Poimboeuf return -1; 125*627fce14SJosh Poimboeuf } 126*627fce14SJosh Poimboeuf 127*627fce14SJosh Poimboeuf name = elf_strptr(elf, shstrtab_idx, sh.sh_name); 128*627fce14SJosh Poimboeuf if (!name) { 129*627fce14SJosh Poimboeuf WARN_ELF("elf_strptr"); 130*627fce14SJosh Poimboeuf return -1; 131*627fce14SJosh Poimboeuf } 132*627fce14SJosh Poimboeuf 133*627fce14SJosh Poimboeuf data = elf_getdata(scn, NULL); 134*627fce14SJosh Poimboeuf if (!data) { 135*627fce14SJosh Poimboeuf WARN_ELF("elf_getdata"); 136*627fce14SJosh Poimboeuf return -1; 137*627fce14SJosh Poimboeuf } 138*627fce14SJosh Poimboeuf 139*627fce14SJosh Poimboeuf if (!strcmp(name, ".symtab")) { 140*627fce14SJosh Poimboeuf symtab = data; 141*627fce14SJosh Poimboeuf } else if (!strcmp(name, ".orc_unwind")) { 142*627fce14SJosh Poimboeuf orc = data->d_buf; 143*627fce14SJosh Poimboeuf orc_size = sh.sh_size; 144*627fce14SJosh Poimboeuf } else if (!strcmp(name, ".orc_unwind_ip")) { 145*627fce14SJosh Poimboeuf orc_ip = data->d_buf; 146*627fce14SJosh Poimboeuf orc_ip_addr = sh.sh_addr; 147*627fce14SJosh Poimboeuf } else if (!strcmp(name, ".rela.orc_unwind_ip")) { 148*627fce14SJosh Poimboeuf rela_orc_ip = data; 149*627fce14SJosh Poimboeuf } 150*627fce14SJosh Poimboeuf } 151*627fce14SJosh Poimboeuf 152*627fce14SJosh Poimboeuf if (!symtab || !orc || !orc_ip) 153*627fce14SJosh Poimboeuf return 0; 154*627fce14SJosh Poimboeuf 155*627fce14SJosh Poimboeuf if (orc_size % sizeof(*orc) != 0) { 156*627fce14SJosh Poimboeuf WARN("bad .orc_unwind section size"); 157*627fce14SJosh Poimboeuf return -1; 158*627fce14SJosh Poimboeuf } 159*627fce14SJosh Poimboeuf 160*627fce14SJosh Poimboeuf nr_entries = orc_size / sizeof(*orc); 161*627fce14SJosh Poimboeuf for (i = 0; i < nr_entries; i++) { 162*627fce14SJosh Poimboeuf if (rela_orc_ip) { 163*627fce14SJosh Poimboeuf if (!gelf_getrela(rela_orc_ip, i, &rela)) { 164*627fce14SJosh Poimboeuf WARN_ELF("gelf_getrela"); 165*627fce14SJosh Poimboeuf return -1; 166*627fce14SJosh Poimboeuf } 167*627fce14SJosh Poimboeuf 168*627fce14SJosh Poimboeuf if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) { 169*627fce14SJosh Poimboeuf WARN_ELF("gelf_getsym"); 170*627fce14SJosh Poimboeuf return -1; 171*627fce14SJosh Poimboeuf } 172*627fce14SJosh Poimboeuf 173*627fce14SJosh Poimboeuf scn = elf_getscn(elf, sym.st_shndx); 174*627fce14SJosh Poimboeuf if (!scn) { 175*627fce14SJosh Poimboeuf WARN_ELF("elf_getscn"); 176*627fce14SJosh Poimboeuf return -1; 177*627fce14SJosh Poimboeuf } 178*627fce14SJosh Poimboeuf 179*627fce14SJosh Poimboeuf if (!gelf_getshdr(scn, &sh)) { 180*627fce14SJosh Poimboeuf WARN_ELF("gelf_getshdr"); 181*627fce14SJosh Poimboeuf return -1; 182*627fce14SJosh Poimboeuf } 183*627fce14SJosh Poimboeuf 184*627fce14SJosh Poimboeuf name = elf_strptr(elf, shstrtab_idx, sh.sh_name); 185*627fce14SJosh Poimboeuf if (!name || !*name) { 186*627fce14SJosh Poimboeuf WARN_ELF("elf_strptr"); 187*627fce14SJosh Poimboeuf return -1; 188*627fce14SJosh Poimboeuf } 189*627fce14SJosh Poimboeuf 190*627fce14SJosh Poimboeuf printf("%s+%lx:", name, rela.r_addend); 191*627fce14SJosh Poimboeuf 192*627fce14SJosh Poimboeuf } else { 193*627fce14SJosh Poimboeuf printf("%lx:", orc_ip_addr + (i * sizeof(int)) + orc_ip[i]); 194*627fce14SJosh Poimboeuf } 195*627fce14SJosh Poimboeuf 196*627fce14SJosh Poimboeuf 197*627fce14SJosh Poimboeuf printf(" sp:"); 198*627fce14SJosh Poimboeuf 199*627fce14SJosh Poimboeuf print_reg(orc[i].sp_reg, orc[i].sp_offset); 200*627fce14SJosh Poimboeuf 201*627fce14SJosh Poimboeuf printf(" bp:"); 202*627fce14SJosh Poimboeuf 203*627fce14SJosh Poimboeuf print_reg(orc[i].bp_reg, orc[i].bp_offset); 204*627fce14SJosh Poimboeuf 205*627fce14SJosh Poimboeuf printf(" type:%s\n", orc_type_name(orc[i].type)); 206*627fce14SJosh Poimboeuf } 207*627fce14SJosh Poimboeuf 208*627fce14SJosh Poimboeuf elf_end(elf); 209*627fce14SJosh Poimboeuf close(fd); 210*627fce14SJosh Poimboeuf 211*627fce14SJosh Poimboeuf return 0; 212*627fce14SJosh Poimboeuf } 213