Commit ba62a537 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arc-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc

Pull ARC updates from Vineet Gupta:

 - Basic eBPF support (Sergey)

* tag 'arc-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc:
  ARC: bpf: define uapi for BPF_PROG_TYPE_PERF_EVENT program type
  ARC: disasm: handle ARCv2 case in kprobe get/set functions
  ARC: implement syscall tracepoints
  ARC: enable HAVE_REGS_AND_STACK_ACCESS_API feature
parents ef98f9cf 6aa98f62
...@@ -36,8 +36,10 @@ config ARC ...@@ -36,8 +36,10 @@ config ARC
select HAVE_KERNEL_LZMA select HAVE_KERNEL_LZMA
select HAVE_KPROBES select HAVE_KPROBES
select HAVE_KRETPROBES select HAVE_KRETPROBES
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_MOD_ARCH_SPECIFIC select HAVE_MOD_ARCH_SPECIFIC
select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS
select HAVE_SYSCALL_TRACEPOINTS
select IRQ_DOMAIN select IRQ_DOMAIN
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA
select OF select OF
......
...@@ -63,4 +63,8 @@ struct arc_reg_cc_build { ...@@ -63,4 +63,8 @@ struct arc_reg_cc_build {
#define PERF_COUNT_ARC_HW_MAX (PERF_COUNT_HW_MAX + 8) #define PERF_COUNT_ARC_HW_MAX (PERF_COUNT_HW_MAX + 8)
#ifdef CONFIG_PERF_EVENTS
#define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs
#endif
#endif /* __ASM_PERF_EVENT_H */ #endif /* __ASM_PERF_EVENT_H */
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define __ASM_ARC_PTRACE_H #define __ASM_ARC_PTRACE_H
#include <uapi/asm/ptrace.h> #include <uapi/asm/ptrace.h>
#include <linux/compiler.h>
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
...@@ -54,6 +55,9 @@ struct pt_regs { ...@@ -54,6 +55,9 @@ struct pt_regs {
unsigned long user_r25; unsigned long user_r25;
}; };
#define MAX_REG_OFFSET offsetof(struct pt_regs, user_r25)
#else #else
struct pt_regs { struct pt_regs {
...@@ -102,6 +106,8 @@ struct pt_regs { ...@@ -102,6 +106,8 @@ struct pt_regs {
unsigned long status32; unsigned long status32;
}; };
#define MAX_REG_OFFSET offsetof(struct pt_regs, status32)
#endif #endif
/* Callee saved registers - need to be saved only when you are scheduled out */ /* Callee saved registers - need to be saved only when you are scheduled out */
...@@ -154,6 +160,27 @@ static inline void instruction_pointer_set(struct pt_regs *regs, ...@@ -154,6 +160,27 @@ static inline void instruction_pointer_set(struct pt_regs *regs,
{ {
instruction_pointer(regs) = val; instruction_pointer(regs) = val;
} }
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
{
return regs->sp;
}
extern int regs_query_register_offset(const char *name);
extern const char *regs_query_register_name(unsigned int offset);
extern bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr);
extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
unsigned int n);
static inline unsigned long regs_get_register(struct pt_regs *regs,
unsigned int offset)
{
if (unlikely(offset > MAX_REG_OFFSET))
return 0;
return *(unsigned long *)((unsigned long)regs + offset);
}
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
#endif /* __ASM_PTRACE_H */ #endif /* __ASM_PTRACE_H */
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/ptrace.h> /* in_syscall() */ #include <asm/ptrace.h> /* in_syscall() */
extern void *sys_call_table[];
static inline long static inline long
syscall_get_nr(struct task_struct *task, struct pt_regs *regs) syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{ {
......
...@@ -78,9 +78,9 @@ static inline __attribute_const__ struct thread_info *current_thread_info(void) ...@@ -78,9 +78,9 @@ static inline __attribute_const__ struct thread_info *current_thread_info(void)
#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */ #define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */
#define TIF_NOTIFY_SIGNAL 5 /* signal notifications exist */ #define TIF_NOTIFY_SIGNAL 5 /* signal notifications exist */
#define TIF_SYSCALL_TRACE 15 /* syscall trace active */ #define TIF_SYSCALL_TRACE 15 /* syscall trace active */
/* true if poll_idle() is polling TIF_NEED_RESCHED */ /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 16 #define TIF_MEMDIE 16
#define TIF_SYSCALL_TRACEPOINT 17 /* syscall tracepoint instrumentation */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
...@@ -89,11 +89,14 @@ static inline __attribute_const__ struct thread_info *current_thread_info(void) ...@@ -89,11 +89,14 @@ static inline __attribute_const__ struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL) #define _TIF_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL)
#define _TIF_MEMDIE (1<<TIF_MEMDIE) #define _TIF_MEMDIE (1<<TIF_MEMDIE)
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
/* work to do on interrupt/exception return */ /* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_NOTIFY_SIGNAL) _TIF_NOTIFY_RESUME | _TIF_NOTIFY_SIGNAL)
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)
/* /*
* _TIF_ALLWORK_MASK includes SYSCALL_TRACE, but we don't need it. * _TIF_ALLWORK_MASK includes SYSCALL_TRACE, but we don't need it.
* SYSCALL_TRACE is anyway separately/unconditionally tested right after a * SYSCALL_TRACE is anyway separately/unconditionally tested right after a
......
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
#define _UAPI__ASM_BPF_PERF_EVENT_H__
#include <asm/ptrace.h>
typedef struct user_regs_struct bpf_user_pt_regs_t;
#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
...@@ -434,14 +434,31 @@ long __kprobes get_reg(int reg, struct pt_regs *regs, ...@@ -434,14 +434,31 @@ long __kprobes get_reg(int reg, struct pt_regs *regs,
{ {
long *p; long *p;
#if defined(CONFIG_ISA_ARCOMPACT)
if (reg <= 12) { if (reg <= 12) {
p = &regs->r0; p = &regs->r0;
return p[-reg]; return p[-reg];
} }
#else /* CONFIG_ISA_ARCV2 */
if (reg <= 11) {
p = &regs->r0;
return p[reg];
}
if (reg == 12)
return regs->r12;
if (reg == 30)
return regs->r30;
#ifdef CONFIG_ARC_HAS_ACCL_REGS
if (reg == 58)
return regs->r58;
if (reg == 59)
return regs->r59;
#endif
#endif
if (cregs && (reg <= 25)) { if (cregs && (reg <= 25)) {
p = &cregs->r13; p = &cregs->r13;
return p[13-reg]; return p[13 - reg];
} }
if (reg == 26) if (reg == 26)
...@@ -461,6 +478,7 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs, ...@@ -461,6 +478,7 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
{ {
long *p; long *p;
#if defined(CONFIG_ISA_ARCOMPACT)
switch (reg) { switch (reg) {
case 0 ... 12: case 0 ... 12:
p = &regs->r0; p = &regs->r0;
...@@ -469,7 +487,7 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs, ...@@ -469,7 +487,7 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
case 13 ... 25: case 13 ... 25:
if (cregs) { if (cregs) {
p = &cregs->r13; p = &cregs->r13;
p[13-reg] = val; p[13 - reg] = val;
} }
break; break;
case 26: case 26:
...@@ -487,6 +505,48 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs, ...@@ -487,6 +505,48 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
default: default:
break; break;
} }
#else /* CONFIG_ISA_ARCV2 */
switch (reg) {
case 0 ... 11:
p = &regs->r0;
p[reg] = val;
break;
case 12:
regs->r12 = val;
break;
case 13 ... 25:
if (cregs) {
p = &cregs->r13;
p[13 - reg] = val;
}
break;
case 26:
regs->r26 = val;
break;
case 27:
regs->fp = val;
break;
case 28:
regs->sp = val;
break;
case 30:
regs->r30 = val;
break;
case 31:
regs->blink = val;
break;
#ifdef CONFIG_ARC_HAS_ACCL_REGS
case 58:
regs->r58 = val;
break;
case 59:
regs->r59 = val;
break;
#endif
default:
break;
}
#endif
} }
/* /*
......
...@@ -29,8 +29,8 @@ ENTRY(sys_clone_wrapper) ...@@ -29,8 +29,8 @@ ENTRY(sys_clone_wrapper)
DISCARD_CALLEE_SAVED_USER DISCARD_CALLEE_SAVED_USER
GET_CURR_THR_INFO_FLAGS r10 GET_CURR_THR_INFO_FLAGS r10
btst r10, TIF_SYSCALL_TRACE and.f 0, r10, _TIF_SYSCALL_WORK
bnz tracesys_exit bnz tracesys_exit
b .Lret_from_system_call b .Lret_from_system_call
END(sys_clone_wrapper) END(sys_clone_wrapper)
...@@ -41,8 +41,8 @@ ENTRY(sys_clone3_wrapper) ...@@ -41,8 +41,8 @@ ENTRY(sys_clone3_wrapper)
DISCARD_CALLEE_SAVED_USER DISCARD_CALLEE_SAVED_USER
GET_CURR_THR_INFO_FLAGS r10 GET_CURR_THR_INFO_FLAGS r10
btst r10, TIF_SYSCALL_TRACE and.f 0, r10, _TIF_SYSCALL_WORK
bnz tracesys_exit bnz tracesys_exit
b .Lret_from_system_call b .Lret_from_system_call
END(sys_clone3_wrapper) END(sys_clone3_wrapper)
...@@ -247,8 +247,8 @@ ENTRY(EV_Trap) ...@@ -247,8 +247,8 @@ ENTRY(EV_Trap)
; If syscall tracing ongoing, invoke pre-post-hooks ; If syscall tracing ongoing, invoke pre-post-hooks
GET_CURR_THR_INFO_FLAGS r10 GET_CURR_THR_INFO_FLAGS r10
btst r10, TIF_SYSCALL_TRACE and.f 0, r10, _TIF_SYSCALL_WORK
bnz tracesys ; this never comes back bnz tracesys ; this never comes back
;============ Normal syscall case ;============ Normal syscall case
......
...@@ -9,6 +9,92 @@ ...@@ -9,6 +9,92 @@
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/elf.h> #include <linux/elf.h>
#define CREATE_TRACE_POINTS
#include <trace/events/syscalls.h>
struct pt_regs_offset {
const char *name;
int offset;
};
#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
#define REG_OFFSET_END {.name = NULL, .offset = 0}
#ifdef CONFIG_ISA_ARCOMPACT
static const struct pt_regs_offset regoffset_table[] = {
REG_OFFSET_NAME(bta),
REG_OFFSET_NAME(lp_start),
REG_OFFSET_NAME(lp_end),
REG_OFFSET_NAME(lp_count),
REG_OFFSET_NAME(status32),
REG_OFFSET_NAME(ret),
REG_OFFSET_NAME(blink),
REG_OFFSET_NAME(fp),
REG_OFFSET_NAME(r26),
REG_OFFSET_NAME(r12),
REG_OFFSET_NAME(r11),
REG_OFFSET_NAME(r10),
REG_OFFSET_NAME(r9),
REG_OFFSET_NAME(r8),
REG_OFFSET_NAME(r7),
REG_OFFSET_NAME(r6),
REG_OFFSET_NAME(r5),
REG_OFFSET_NAME(r4),
REG_OFFSET_NAME(r3),
REG_OFFSET_NAME(r2),
REG_OFFSET_NAME(r1),
REG_OFFSET_NAME(r0),
REG_OFFSET_NAME(sp),
REG_OFFSET_NAME(orig_r0),
REG_OFFSET_NAME(event),
REG_OFFSET_NAME(user_r25),
REG_OFFSET_END,
};
#else
static const struct pt_regs_offset regoffset_table[] = {
REG_OFFSET_NAME(orig_r0),
REG_OFFSET_NAME(event),
REG_OFFSET_NAME(bta),
REG_OFFSET_NAME(user_r25),
REG_OFFSET_NAME(r26),
REG_OFFSET_NAME(fp),
REG_OFFSET_NAME(sp),
REG_OFFSET_NAME(r12),
REG_OFFSET_NAME(r30),
#ifdef CONFIG_ARC_HAS_ACCL_REGS
REG_OFFSET_NAME(r58),
REG_OFFSET_NAME(r59),
#endif
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
REG_OFFSET_NAME(DSP_CTRL),
#endif
REG_OFFSET_NAME(r0),
REG_OFFSET_NAME(r1),
REG_OFFSET_NAME(r2),
REG_OFFSET_NAME(r3),
REG_OFFSET_NAME(r4),
REG_OFFSET_NAME(r5),
REG_OFFSET_NAME(r6),
REG_OFFSET_NAME(r7),
REG_OFFSET_NAME(r8),
REG_OFFSET_NAME(r9),
REG_OFFSET_NAME(r10),
REG_OFFSET_NAME(r11),
REG_OFFSET_NAME(blink),
REG_OFFSET_NAME(lp_end),
REG_OFFSET_NAME(lp_start),
REG_OFFSET_NAME(lp_count),
REG_OFFSET_NAME(ei),
REG_OFFSET_NAME(ldi),
REG_OFFSET_NAME(jli),
REG_OFFSET_NAME(ret),
REG_OFFSET_NAME(status32),
REG_OFFSET_END,
};
#endif
static struct callee_regs *task_callee_regs(struct task_struct *tsk) static struct callee_regs *task_callee_regs(struct task_struct *tsk)
{ {
struct callee_regs *tmp = (struct callee_regs *)tsk->thread.callee_reg; struct callee_regs *tmp = (struct callee_regs *)tsk->thread.callee_reg;
...@@ -257,13 +343,61 @@ long arch_ptrace(struct task_struct *child, long request, ...@@ -257,13 +343,61 @@ long arch_ptrace(struct task_struct *child, long request,
asmlinkage int syscall_trace_entry(struct pt_regs *regs) asmlinkage int syscall_trace_entry(struct pt_regs *regs)
{ {
if (ptrace_report_syscall_entry(regs)) if (test_thread_flag(TIF_SYSCALL_TRACE))
return ULONG_MAX; if (ptrace_report_syscall_entry(regs))
return ULONG_MAX;
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
trace_sys_enter(regs, syscall_get_nr(current, regs));
#endif
return regs->r8; return regs->r8;
} }
asmlinkage void syscall_trace_exit(struct pt_regs *regs) asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{ {
ptrace_report_syscall_exit(regs, 0); if (test_thread_flag(TIF_SYSCALL_TRACE))
ptrace_report_syscall_exit(regs, 0);
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
trace_sys_exit(regs, regs_return_value(regs));
#endif
}
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;
}
const char *regs_query_register_name(unsigned int offset)
{
const struct pt_regs_offset *roff;
for (roff = regoffset_table; roff->name != NULL; roff++)
if (roff->offset == offset)
return roff->name;
return NULL;
}
bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
{
return (addr & ~(THREAD_SIZE - 1)) ==
(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1));
}
unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
{
unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
addr += n;
if (regs_within_kernel_stack(regs, (unsigned long)addr))
return *addr;
else
return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment