ARC changes for 5.19-rc1
- Basic eBPF support (Sergey) -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEOXpuCuR6hedrdLCJadfx3eKKwl4FAmKO9fQACgkQadfx3eKK wl6qLA//UERRB3zLJf5PSzs+RYohtzBTHWJG4AfTog1hLy8pzCPXrUv/y4J58nTv UOZRJFIBGmZaOGz+sXSxKz5d3IcJXm825Z3zqdbgdBeyTV6e0UotFqw2zimqtw5K l7MjVcpOnSy6/ohkfiSjSXttdhPXXNqe30GS9+BHyrcpJUjqwHnUwR+d8cIeaRmf 3cMio8SWVaya0LY78cs8zvxZvx6SwxAHE+u5UhA9ywBPnGRg6rLOe/rnLfyfgbaG 6xufHlkmdsUrgs01RlQj21fNxax6UNbcB0THAAGmGAYXNYJi0BBigtSQXlLcOdgz a9FASeapiF63cQlrftcrA9/B7rtJqjECO5dz68ImOfWoZn1bFXOYVXOv6fTr9GWv 61n7OeVVAxnJTYFMaLD86gyTgkqyich3M7O4BZN8RhSDKH7EJ7fbYhEmGhZbgkka t/WpWM8BdyzpprGw4sh2DJ87A/S1YipK30xLkPchzP6bleqleIi2jtNaiuSHH0FA yWxn1cZDmV6akpca6Uoo6LIDlhSrWQZRuhiu9d08wRtv5kUGJLnXn1w8XT+ZxsGG Gk5j05hTqDjQBOusdXwa8T2dHsOV5cibHYytVe+kYgjm1HPpD3sj++3YaZ0csQ2G YRwl6sxJrky2xSath58Z3kYpwnTB3oZGSUSz0VroWa1VEhQr+7c= =IZht -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
ba62a537b4
@ -36,8 +36,10 @@ config ARC
|
||||
select HAVE_KERNEL_LZMA
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_REGS_AND_STACK_ACCESS_API
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_SYSCALL_TRACEPOINTS
|
||||
select IRQ_DOMAIN
|
||||
select MODULES_USE_ELF_RELA
|
||||
select OF
|
||||
|
@ -63,4 +63,8 @@ struct arc_reg_cc_build {
|
||||
|
||||
#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 */
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define __ASM_ARC_PTRACE_H
|
||||
|
||||
#include <uapi/asm/ptrace.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@ -54,6 +55,9 @@ struct pt_regs {
|
||||
|
||||
unsigned long user_r25;
|
||||
};
|
||||
|
||||
#define MAX_REG_OFFSET offsetof(struct pt_regs, user_r25)
|
||||
|
||||
#else
|
||||
|
||||
struct pt_regs {
|
||||
@ -102,6 +106,8 @@ struct pt_regs {
|
||||
unsigned long status32;
|
||||
};
|
||||
|
||||
#define MAX_REG_OFFSET offsetof(struct pt_regs, status32)
|
||||
|
||||
#endif
|
||||
|
||||
/* 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,
|
||||
{
|
||||
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 /* __ASM_PTRACE_H */
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/ptrace.h> /* in_syscall() */
|
||||
|
||||
extern void *sys_call_table[];
|
||||
|
||||
static inline long
|
||||
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)
|
||||
#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */
|
||||
#define TIF_NOTIFY_SIGNAL 5 /* signal notifications exist */
|
||||
#define TIF_SYSCALL_TRACE 15 /* syscall trace active */
|
||||
|
||||
/* true if poll_idle() is polling TIF_NEED_RESCHED */
|
||||
#define TIF_MEMDIE 16
|
||||
#define TIF_SYSCALL_TRACEPOINT 17 /* syscall tracepoint instrumentation */
|
||||
|
||||
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
|
||||
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
|
||||
@ -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_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL)
|
||||
#define _TIF_MEMDIE (1<<TIF_MEMDIE)
|
||||
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
|
||||
|
||||
/* work to do on interrupt/exception return */
|
||||
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
|
||||
_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.
|
||||
* SYSCALL_TRACE is anyway separately/unconditionally tested right after a
|
||||
|
9
arch/arc/include/uapi/asm/bpf_perf_event.h
Normal file
9
arch/arc/include/uapi/asm/bpf_perf_event.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* 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,
|
||||
{
|
||||
long *p;
|
||||
|
||||
#if defined(CONFIG_ISA_ARCOMPACT)
|
||||
if (reg <= 12) {
|
||||
p = ®s->r0;
|
||||
return p[-reg];
|
||||
}
|
||||
#else /* CONFIG_ISA_ARCV2 */
|
||||
if (reg <= 11) {
|
||||
p = ®s->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)) {
|
||||
p = &cregs->r13;
|
||||
return p[13-reg];
|
||||
return p[13 - reg];
|
||||
}
|
||||
|
||||
if (reg == 26)
|
||||
@ -461,6 +478,7 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
|
||||
{
|
||||
long *p;
|
||||
|
||||
#if defined(CONFIG_ISA_ARCOMPACT)
|
||||
switch (reg) {
|
||||
case 0 ... 12:
|
||||
p = ®s->r0;
|
||||
@ -469,7 +487,7 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
|
||||
case 13 ... 25:
|
||||
if (cregs) {
|
||||
p = &cregs->r13;
|
||||
p[13-reg] = val;
|
||||
p[13 - reg] = val;
|
||||
}
|
||||
break;
|
||||
case 26:
|
||||
@ -487,6 +505,48 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else /* CONFIG_ISA_ARCV2 */
|
||||
switch (reg) {
|
||||
case 0 ... 11:
|
||||
p = ®s->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)
|
||||
DISCARD_CALLEE_SAVED_USER
|
||||
|
||||
GET_CURR_THR_INFO_FLAGS r10
|
||||
btst r10, TIF_SYSCALL_TRACE
|
||||
bnz tracesys_exit
|
||||
and.f 0, r10, _TIF_SYSCALL_WORK
|
||||
bnz tracesys_exit
|
||||
|
||||
b .Lret_from_system_call
|
||||
END(sys_clone_wrapper)
|
||||
@ -41,8 +41,8 @@ ENTRY(sys_clone3_wrapper)
|
||||
DISCARD_CALLEE_SAVED_USER
|
||||
|
||||
GET_CURR_THR_INFO_FLAGS r10
|
||||
btst r10, TIF_SYSCALL_TRACE
|
||||
bnz tracesys_exit
|
||||
and.f 0, r10, _TIF_SYSCALL_WORK
|
||||
bnz tracesys_exit
|
||||
|
||||
b .Lret_from_system_call
|
||||
END(sys_clone3_wrapper)
|
||||
@ -247,8 +247,8 @@ ENTRY(EV_Trap)
|
||||
|
||||
; If syscall tracing ongoing, invoke pre-post-hooks
|
||||
GET_CURR_THR_INFO_FLAGS r10
|
||||
btst r10, TIF_SYSCALL_TRACE
|
||||
bnz tracesys ; this never comes back
|
||||
and.f 0, r10, _TIF_SYSCALL_WORK
|
||||
bnz tracesys ; this never comes back
|
||||
|
||||
;============ Normal syscall case
|
||||
|
||||
|
@ -9,6 +9,92 @@
|
||||
#include <linux/unistd.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)
|
||||
{
|
||||
struct callee_regs *tmp = (struct callee_regs *)tsk->thread.callee_reg;
|
||||
@ -257,13 +343,61 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
|
||||
asmlinkage int syscall_trace_entry(struct pt_regs *regs)
|
||||
{
|
||||
if (ptrace_report_syscall_entry(regs))
|
||||
return ULONG_MAX;
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user