Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
0004  */
0005 
0006 #include <unistd.h>
0007 #include <linux/objtool.h>
0008 #include <asm/orc_types.h>
0009 #include <objtool/objtool.h>
0010 #include <objtool/warn.h>
0011 #include <objtool/endianness.h>
0012 
0013 static const char *reg_name(unsigned int reg)
0014 {
0015     switch (reg) {
0016     case ORC_REG_PREV_SP:
0017         return "prevsp";
0018     case ORC_REG_DX:
0019         return "dx";
0020     case ORC_REG_DI:
0021         return "di";
0022     case ORC_REG_BP:
0023         return "bp";
0024     case ORC_REG_SP:
0025         return "sp";
0026     case ORC_REG_R10:
0027         return "r10";
0028     case ORC_REG_R13:
0029         return "r13";
0030     case ORC_REG_BP_INDIRECT:
0031         return "bp(ind)";
0032     case ORC_REG_SP_INDIRECT:
0033         return "sp(ind)";
0034     default:
0035         return "?";
0036     }
0037 }
0038 
0039 static const char *orc_type_name(unsigned int type)
0040 {
0041     switch (type) {
0042     case UNWIND_HINT_TYPE_CALL:
0043         return "call";
0044     case UNWIND_HINT_TYPE_REGS:
0045         return "regs";
0046     case UNWIND_HINT_TYPE_REGS_PARTIAL:
0047         return "regs (partial)";
0048     default:
0049         return "?";
0050     }
0051 }
0052 
0053 static void print_reg(unsigned int reg, int offset)
0054 {
0055     if (reg == ORC_REG_BP_INDIRECT)
0056         printf("(bp%+d)", offset);
0057     else if (reg == ORC_REG_SP_INDIRECT)
0058         printf("(sp)%+d", offset);
0059     else if (reg == ORC_REG_UNDEFINED)
0060         printf("(und)");
0061     else
0062         printf("%s%+d", reg_name(reg), offset);
0063 }
0064 
0065 int orc_dump(const char *_objname)
0066 {
0067     int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
0068     struct orc_entry *orc = NULL;
0069     char *name;
0070     size_t nr_sections;
0071     Elf64_Addr orc_ip_addr = 0;
0072     size_t shstrtab_idx, strtab_idx = 0;
0073     Elf *elf;
0074     Elf_Scn *scn;
0075     GElf_Shdr sh;
0076     GElf_Rela rela;
0077     GElf_Sym sym;
0078     Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL;
0079 
0080 
0081     objname = _objname;
0082 
0083     elf_version(EV_CURRENT);
0084 
0085     fd = open(objname, O_RDONLY);
0086     if (fd == -1) {
0087         perror("open");
0088         return -1;
0089     }
0090 
0091     elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
0092     if (!elf) {
0093         WARN_ELF("elf_begin");
0094         return -1;
0095     }
0096 
0097     if (elf_getshdrnum(elf, &nr_sections)) {
0098         WARN_ELF("elf_getshdrnum");
0099         return -1;
0100     }
0101 
0102     if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
0103         WARN_ELF("elf_getshdrstrndx");
0104         return -1;
0105     }
0106 
0107     for (i = 0; i < nr_sections; i++) {
0108         scn = elf_getscn(elf, i);
0109         if (!scn) {
0110             WARN_ELF("elf_getscn");
0111             return -1;
0112         }
0113 
0114         if (!gelf_getshdr(scn, &sh)) {
0115             WARN_ELF("gelf_getshdr");
0116             return -1;
0117         }
0118 
0119         name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
0120         if (!name) {
0121             WARN_ELF("elf_strptr");
0122             return -1;
0123         }
0124 
0125         data = elf_getdata(scn, NULL);
0126         if (!data) {
0127             WARN_ELF("elf_getdata");
0128             return -1;
0129         }
0130 
0131         if (!strcmp(name, ".symtab")) {
0132             symtab = data;
0133         } else if (!strcmp(name, ".strtab")) {
0134             strtab_idx = i;
0135         } else if (!strcmp(name, ".orc_unwind")) {
0136             orc = data->d_buf;
0137             orc_size = sh.sh_size;
0138         } else if (!strcmp(name, ".orc_unwind_ip")) {
0139             orc_ip = data->d_buf;
0140             orc_ip_addr = sh.sh_addr;
0141         } else if (!strcmp(name, ".rela.orc_unwind_ip")) {
0142             rela_orc_ip = data;
0143         }
0144     }
0145 
0146     if (!symtab || !strtab_idx || !orc || !orc_ip)
0147         return 0;
0148 
0149     if (orc_size % sizeof(*orc) != 0) {
0150         WARN("bad .orc_unwind section size");
0151         return -1;
0152     }
0153 
0154     nr_entries = orc_size / sizeof(*orc);
0155     for (i = 0; i < nr_entries; i++) {
0156         if (rela_orc_ip) {
0157             if (!gelf_getrela(rela_orc_ip, i, &rela)) {
0158                 WARN_ELF("gelf_getrela");
0159                 return -1;
0160             }
0161 
0162             if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
0163                 WARN_ELF("gelf_getsym");
0164                 return -1;
0165             }
0166 
0167             if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
0168                 scn = elf_getscn(elf, sym.st_shndx);
0169                 if (!scn) {
0170                     WARN_ELF("elf_getscn");
0171                     return -1;
0172                 }
0173 
0174                 if (!gelf_getshdr(scn, &sh)) {
0175                     WARN_ELF("gelf_getshdr");
0176                     return -1;
0177                 }
0178 
0179                 name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
0180                 if (!name) {
0181                     WARN_ELF("elf_strptr");
0182                     return -1;
0183                 }
0184             } else {
0185                 name = elf_strptr(elf, strtab_idx, sym.st_name);
0186                 if (!name) {
0187                     WARN_ELF("elf_strptr");
0188                     return -1;
0189                 }
0190             }
0191 
0192             printf("%s+%llx:", name, (unsigned long long)rela.r_addend);
0193 
0194         } else {
0195             printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i]));
0196         }
0197 
0198 
0199         printf(" sp:");
0200 
0201         print_reg(orc[i].sp_reg, bswap_if_needed(orc[i].sp_offset));
0202 
0203         printf(" bp:");
0204 
0205         print_reg(orc[i].bp_reg, bswap_if_needed(orc[i].bp_offset));
0206 
0207         printf(" type:%s end:%d\n",
0208                orc_type_name(orc[i].type), orc[i].end);
0209     }
0210 
0211     elf_end(elf);
0212     close(fd);
0213 
0214     return 0;
0215 }