linux/arch/x86/kernel/perf_regs.c
<<
>>
Prefs
   1#include <linux/errno.h>
   2#include <linux/kernel.h>
   3#include <linux/sched.h>
   4#include <linux/sched/task_stack.h>
   5#include <linux/perf_event.h>
   6#include <linux/bug.h>
   7#include <linux/stddef.h>
   8#include <asm/perf_regs.h>
   9#include <asm/ptrace.h>
  10
  11#ifdef CONFIG_X86_32
  12#define PERF_REG_X86_MAX PERF_REG_X86_32_MAX
  13#else
  14#define PERF_REG_X86_MAX PERF_REG_X86_64_MAX
  15#endif
  16
  17#define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r)
  18
  19static unsigned int pt_regs_offset[PERF_REG_X86_MAX] = {
  20        PT_REGS_OFFSET(PERF_REG_X86_AX, ax),
  21        PT_REGS_OFFSET(PERF_REG_X86_BX, bx),
  22        PT_REGS_OFFSET(PERF_REG_X86_CX, cx),
  23        PT_REGS_OFFSET(PERF_REG_X86_DX, dx),
  24        PT_REGS_OFFSET(PERF_REG_X86_SI, si),
  25        PT_REGS_OFFSET(PERF_REG_X86_DI, di),
  26        PT_REGS_OFFSET(PERF_REG_X86_BP, bp),
  27        PT_REGS_OFFSET(PERF_REG_X86_SP, sp),
  28        PT_REGS_OFFSET(PERF_REG_X86_IP, ip),
  29        PT_REGS_OFFSET(PERF_REG_X86_FLAGS, flags),
  30        PT_REGS_OFFSET(PERF_REG_X86_CS, cs),
  31        PT_REGS_OFFSET(PERF_REG_X86_SS, ss),
  32#ifdef CONFIG_X86_32
  33        PT_REGS_OFFSET(PERF_REG_X86_DS, ds),
  34        PT_REGS_OFFSET(PERF_REG_X86_ES, es),
  35        PT_REGS_OFFSET(PERF_REG_X86_FS, fs),
  36        PT_REGS_OFFSET(PERF_REG_X86_GS, gs),
  37#else
  38        /*
  39         * The pt_regs struct does not store
  40         * ds, es, fs, gs in 64 bit mode.
  41         */
  42        (unsigned int) -1,
  43        (unsigned int) -1,
  44        (unsigned int) -1,
  45        (unsigned int) -1,
  46#endif
  47#ifdef CONFIG_X86_64
  48        PT_REGS_OFFSET(PERF_REG_X86_R8, r8),
  49        PT_REGS_OFFSET(PERF_REG_X86_R9, r9),
  50        PT_REGS_OFFSET(PERF_REG_X86_R10, r10),
  51        PT_REGS_OFFSET(PERF_REG_X86_R11, r11),
  52        PT_REGS_OFFSET(PERF_REG_X86_R12, r12),
  53        PT_REGS_OFFSET(PERF_REG_X86_R13, r13),
  54        PT_REGS_OFFSET(PERF_REG_X86_R14, r14),
  55        PT_REGS_OFFSET(PERF_REG_X86_R15, r15),
  56#endif
  57};
  58
  59u64 perf_reg_value(struct pt_regs *regs, int idx)
  60{
  61        if (WARN_ON_ONCE(idx >= ARRAY_SIZE(pt_regs_offset)))
  62                return 0;
  63
  64        return regs_get_register(regs, pt_regs_offset[idx]);
  65}
  66
  67#define REG_RESERVED (~((1ULL << PERF_REG_X86_MAX) - 1ULL))
  68
  69#ifdef CONFIG_X86_32
  70int perf_reg_validate(u64 mask)
  71{
  72        if (!mask || mask & REG_RESERVED)
  73                return -EINVAL;
  74
  75        return 0;
  76}
  77
  78u64 perf_reg_abi(struct task_struct *task)
  79{
  80        return PERF_SAMPLE_REGS_ABI_32;
  81}
  82
  83void perf_get_regs_user(struct perf_regs *regs_user,
  84                        struct pt_regs *regs,
  85                        struct pt_regs *regs_user_copy)
  86{
  87        regs_user->regs = task_pt_regs(current);
  88        regs_user->abi = perf_reg_abi(current);
  89}
  90#else /* CONFIG_X86_64 */
  91#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
  92                       (1ULL << PERF_REG_X86_ES) | \
  93                       (1ULL << PERF_REG_X86_FS) | \
  94                       (1ULL << PERF_REG_X86_GS))
  95
  96int perf_reg_validate(u64 mask)
  97{
  98        if (!mask || mask & REG_RESERVED)
  99                return -EINVAL;
 100
 101        if (mask & REG_NOSUPPORT)
 102                return -EINVAL;
 103
 104        return 0;
 105}
 106
 107u64 perf_reg_abi(struct task_struct *task)
 108{
 109        if (test_tsk_thread_flag(task, TIF_IA32))
 110                return PERF_SAMPLE_REGS_ABI_32;
 111        else
 112                return PERF_SAMPLE_REGS_ABI_64;
 113}
 114
 115void perf_get_regs_user(struct perf_regs *regs_user,
 116                        struct pt_regs *regs,
 117                        struct pt_regs *regs_user_copy)
 118{
 119        struct pt_regs *user_regs = task_pt_regs(current);
 120
 121        /*
 122         * If we're in an NMI that interrupted task_pt_regs setup, then
 123         * we can't sample user regs at all.  This check isn't really
 124         * sufficient, though, as we could be in an NMI inside an interrupt
 125         * that happened during task_pt_regs setup.
 126         */
 127        if (regs->sp > (unsigned long)&user_regs->r11 &&
 128            regs->sp <= (unsigned long)(user_regs + 1)) {
 129                regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
 130                regs_user->regs = NULL;
 131                return;
 132        }
 133
 134        /*
 135         * These registers are always saved on 64-bit syscall entry.
 136         * On 32-bit entry points, they are saved too except r8..r11.
 137         */
 138        regs_user_copy->ip = user_regs->ip;
 139        regs_user_copy->ax = user_regs->ax;
 140        regs_user_copy->cx = user_regs->cx;
 141        regs_user_copy->dx = user_regs->dx;
 142        regs_user_copy->si = user_regs->si;
 143        regs_user_copy->di = user_regs->di;
 144        regs_user_copy->r8 = user_regs->r8;
 145        regs_user_copy->r9 = user_regs->r9;
 146        regs_user_copy->r10 = user_regs->r10;
 147        regs_user_copy->r11 = user_regs->r11;
 148        regs_user_copy->orig_ax = user_regs->orig_ax;
 149        regs_user_copy->flags = user_regs->flags;
 150        regs_user_copy->sp = user_regs->sp;
 151        regs_user_copy->cs = user_regs->cs;
 152        regs_user_copy->ss = user_regs->ss;
 153
 154        /*
 155         * Most system calls don't save these registers, don't report them.
 156         */
 157        regs_user_copy->bx = -1;
 158        regs_user_copy->bp = -1;
 159        regs_user_copy->r12 = -1;
 160        regs_user_copy->r13 = -1;
 161        regs_user_copy->r14 = -1;
 162        regs_user_copy->r15 = -1;
 163
 164        /*
 165         * For this to be at all useful, we need a reasonable guess for
 166         * the ABI.  Be careful: we're in NMI context, and we're
 167         * considering current to be the current task, so we should
 168         * be careful not to look at any other percpu variables that might
 169         * change during context switches.
 170         */
 171        regs_user->abi = user_64bit_mode(user_regs) ?
 172                PERF_SAMPLE_REGS_ABI_64 : PERF_SAMPLE_REGS_ABI_32;
 173
 174        regs_user->regs = regs_user_copy;
 175}
 176#endif /* CONFIG_X86_32 */
 177