1 /* 2 * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. 3 * Extracted from probe-finder.c 4 * 5 * Written by Masami Hiramatsu <mhiramat@redhat.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 * 21 */ 22 23 #include <stddef.h> 24 #include <errno.h> /* for EINVAL */ 25 #include <string.h> /* for strcmp */ 26 #include <linux/ptrace.h> /* for struct pt_regs */ 27 #include <linux/kernel.h> /* for offsetof */ 28 #include <dwarf-regs.h> 29 30 /* 31 * See arch/x86/kernel/ptrace.c. 32 * Different from it: 33 * 34 * - Since struct pt_regs is defined differently for user and kernel, 35 * but we want to use 'ax, bx' instead of 'rax, rbx' (which is struct 36 * field name of user's pt_regs), we make REG_OFFSET_NAME to accept 37 * both string name and reg field name. 38 * 39 * - Since accessing x86_32's pt_regs from x86_64 building is difficult 40 * and vise versa, we simply fill offset with -1, so 41 * get_arch_regstr() still works but regs_query_register_offset() 42 * returns error. 43 * The only inconvenience caused by it now is that we are not allowed 44 * to generate BPF prologue for a x86_64 kernel if perf is built for 45 * x86_32. This is really a rare usecase. 46 * 47 * - Order is different from kernel's ptrace.c for get_arch_regstr(). Use 48 * the order defined by dwarf. 49 */ 50 51 struct pt_regs_offset { 52 const char *name; 53 int offset; 54 }; 55 56 #define REG_OFFSET_END {.name = NULL, .offset = 0} 57 58 #ifdef __x86_64__ 59 # define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} 60 # define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = -1} 61 #else 62 # define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = -1} 63 # define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} 64 #endif 65 66 /* TODO: switching by dwarf address size */ 67 #ifndef __x86_64__ 68 static const struct pt_regs_offset x86_32_regoffset_table[] = { 69 REG_OFFSET_NAME_32("%ax", eax), 70 REG_OFFSET_NAME_32("%cx", ecx), 71 REG_OFFSET_NAME_32("%dx", edx), 72 REG_OFFSET_NAME_32("%bx", ebx), 73 REG_OFFSET_NAME_32("$stack", esp), /* Stack address instead of %sp */ 74 REG_OFFSET_NAME_32("%bp", ebp), 75 REG_OFFSET_NAME_32("%si", esi), 76 REG_OFFSET_NAME_32("%di", edi), 77 REG_OFFSET_END, 78 }; 79 80 #define regoffset_table x86_32_regoffset_table 81 #else 82 static const struct pt_regs_offset x86_64_regoffset_table[] = { 83 REG_OFFSET_NAME_64("%ax", rax), 84 REG_OFFSET_NAME_64("%dx", rdx), 85 REG_OFFSET_NAME_64("%cx", rcx), 86 REG_OFFSET_NAME_64("%bx", rbx), 87 REG_OFFSET_NAME_64("%si", rsi), 88 REG_OFFSET_NAME_64("%di", rdi), 89 REG_OFFSET_NAME_64("%bp", rbp), 90 REG_OFFSET_NAME_64("%sp", rsp), 91 REG_OFFSET_NAME_64("%r8", r8), 92 REG_OFFSET_NAME_64("%r9", r9), 93 REG_OFFSET_NAME_64("%r10", r10), 94 REG_OFFSET_NAME_64("%r11", r11), 95 REG_OFFSET_NAME_64("%r12", r12), 96 REG_OFFSET_NAME_64("%r13", r13), 97 REG_OFFSET_NAME_64("%r14", r14), 98 REG_OFFSET_NAME_64("%r15", r15), 99 REG_OFFSET_END, 100 }; 101 102 #define regoffset_table x86_64_regoffset_table 103 #endif 104 105 /* Minus 1 for the ending REG_OFFSET_END */ 106 #define ARCH_MAX_REGS ((sizeof(regoffset_table) / sizeof(regoffset_table[0])) - 1) 107 108 /* Return architecture dependent register string (for kprobe-tracer) */ 109 const char *get_arch_regstr(unsigned int n) 110 { 111 return (n < ARCH_MAX_REGS) ? regoffset_table[n].name : NULL; 112 } 113 114 /* Reuse code from arch/x86/kernel/ptrace.c */ 115 /** 116 * regs_query_register_offset() - query register offset from its name 117 * @name: the name of a register 118 * 119 * regs_query_register_offset() returns the offset of a register in struct 120 * pt_regs from its name. If the name is invalid, this returns -EINVAL; 121 */ 122 int regs_query_register_offset(const char *name) 123 { 124 const struct pt_regs_offset *roff; 125 for (roff = regoffset_table; roff->name != NULL; roff++) 126 if (!strcmp(roff->name, name)) 127 return roff->offset; 128 return -EINVAL; 129 } 130