2010-04-20 16:58:32 +10:00
/*
* dwarf - regs . c : Mapping of DWARF debug register numbers into register names .
* Extracted from probe - finder . c
*
* Written by Masami Hiramatsu < mhiramat @ redhat . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*
*/
2013-03-14 15:27:51 -07:00
# include <stddef.h>
2015-09-06 07:13:35 +00:00
# include <errno.h> /* for EINVAL */
# include <string.h> /* for strcmp */
# include <linux/ptrace.h> /* for struct pt_regs */
# include <linux/kernel.h> /* for offsetof */
2010-04-20 16:58:32 +10:00
# include <dwarf-regs.h>
/*
2015-09-06 07:13:35 +00:00
* See arch / x86 / kernel / ptrace . c .
* Different from it :
*
* - Since struct pt_regs is defined differently for user and kernel ,
* but we want to use ' ax , bx ' instead of ' rax , rbx ' ( which is struct
* field name of user ' s pt_regs ) , we make REG_OFFSET_NAME to accept
* both string name and reg field name .
*
* - Since accessing x86_32 ' s pt_regs from x86_64 building is difficult
* and vise versa , we simply fill offset with - 1 , so
* get_arch_regstr ( ) still works but regs_query_register_offset ( )
* returns error .
* The only inconvenience caused by it now is that we are not allowed
* to generate BPF prologue for a x86_64 kernel if perf is built for
* x86_32 . This is really a rare usecase .
*
* - Order is different from kernel ' s ptrace . c for get_arch_regstr ( ) . Use
* the order defined by dwarf .
2010-04-20 16:58:32 +10:00
*/
2015-09-06 07:13:35 +00:00
struct pt_regs_offset {
const char * name ;
int offset ;
} ;
# define REG_OFFSET_END {.name = NULL, .offset = 0}
# ifdef __x86_64__
# define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)}
# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = -1}
# else
# define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = -1}
# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)}
# endif
2016-04-08 12:04:29 -03:00
/* TODO: switching by dwarf address size */
# ifndef __x86_64__
2015-09-06 07:13:35 +00:00
static const struct pt_regs_offset x86_32_regoffset_table [ ] = {
REG_OFFSET_NAME_32 ( " %ax " , eax ) ,
REG_OFFSET_NAME_32 ( " %cx " , ecx ) ,
REG_OFFSET_NAME_32 ( " %dx " , edx ) ,
REG_OFFSET_NAME_32 ( " %bx " , ebx ) ,
REG_OFFSET_NAME_32 ( " $stack " , esp ) , /* Stack address instead of %sp */
REG_OFFSET_NAME_32 ( " %bp " , ebp ) ,
REG_OFFSET_NAME_32 ( " %si " , esi ) ,
REG_OFFSET_NAME_32 ( " %di " , edi ) ,
REG_OFFSET_END ,
2010-04-20 16:58:32 +10:00
} ;
2016-04-08 12:04:29 -03:00
# define regoffset_table x86_32_regoffset_table
# else
2015-09-06 07:13:35 +00:00
static const struct pt_regs_offset x86_64_regoffset_table [ ] = {
REG_OFFSET_NAME_64 ( " %ax " , rax ) ,
REG_OFFSET_NAME_64 ( " %dx " , rdx ) ,
REG_OFFSET_NAME_64 ( " %cx " , rcx ) ,
REG_OFFSET_NAME_64 ( " %bx " , rbx ) ,
REG_OFFSET_NAME_64 ( " %si " , rsi ) ,
REG_OFFSET_NAME_64 ( " %di " , rdi ) ,
REG_OFFSET_NAME_64 ( " %bp " , rbp ) ,
REG_OFFSET_NAME_64 ( " %sp " , rsp ) ,
REG_OFFSET_NAME_64 ( " %r8 " , r8 ) ,
REG_OFFSET_NAME_64 ( " %r9 " , r9 ) ,
REG_OFFSET_NAME_64 ( " %r10 " , r10 ) ,
REG_OFFSET_NAME_64 ( " %r11 " , r11 ) ,
REG_OFFSET_NAME_64 ( " %r12 " , r12 ) ,
REG_OFFSET_NAME_64 ( " %r13 " , r13 ) ,
REG_OFFSET_NAME_64 ( " %r14 " , r14 ) ,
REG_OFFSET_NAME_64 ( " %r15 " , r15 ) ,
REG_OFFSET_END ,
2010-04-20 16:58:32 +10:00
} ;
2015-09-06 07:13:35 +00:00
# define regoffset_table x86_64_regoffset_table
2010-04-20 16:58:32 +10:00
# endif
2015-09-06 07:13:35 +00:00
/* Minus 1 for the ending REG_OFFSET_END */
# define ARCH_MAX_REGS ((sizeof(regoffset_table) / sizeof(regoffset_table[0])) - 1)
2010-04-20 16:58:32 +10:00
/* Return architecture dependent register string (for kprobe-tracer) */
const char * get_arch_regstr ( unsigned int n )
{
2015-09-06 07:13:35 +00:00
return ( n < ARCH_MAX_REGS ) ? regoffset_table [ n ] . name : NULL ;
}
/* Reuse code from arch/x86/kernel/ptrace.c */
/**
* regs_query_register_offset ( ) - query register offset from its name
* @ name : the name of a register
*
* regs_query_register_offset ( ) returns the offset of a register in struct
* pt_regs from its name . If the name is invalid , this returns - EINVAL ;
*/
int regs_query_register_offset ( const char * name )
{
const struct pt_regs_offset * roff ;
for ( roff = regoffset_table ; roff - > name ! = NULL ; roff + + )
if ( ! strcmp ( roff - > name , name ) )
return roff - > offset ;
return - EINVAL ;
2010-04-20 16:58:32 +10:00
}