Commit d2d8b146 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'trace-v5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing updates from Steven Rostedt:
 "The major changes in this tracing update includes:

   - Removal of non-DYNAMIC_FTRACE from 32bit x86

   - Removal of mcount support from x86

   - Emulating a call from int3 on x86_64, fixes live kernel patching

   - Consolidated Tracing Error logs file

  Minor updates:

   - Removal of klp_check_compiler_support()

   - kdb ftrace dumping output changes

   - Accessing and creating ftrace instances from inside the kernel

   - Clean up of #define if macro

   - Introduction of TRACE_EVENT_NOP() to disable trace events based on
     config options

  And other minor fixes and clean ups"

* tag 'trace-v5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (44 commits)
  x86: Hide the int3_emulate_call/jmp functions from UML
  livepatch: Remove klp_check_compiler_support()
  ftrace/x86: Remove mcount support
  ftrace/x86_32: Remove support for non DYNAMIC_FTRACE
  tracing: Simplify "if" macro code
  tracing: Fix documentation about disabling options using trace_options
  tracing: Replace kzalloc with kcalloc
  tracing: Fix partial reading of trace event's id file
  tracing: Allow RCU to run between postponed startup tests
  tracing: Fix white space issues in parse_pred() function
  tracing: Eliminate const char[] auto variables
  ring-buffer: Fix mispelling of Calculate
  tracing: probeevent: Fix to make the type of $comm string
  tracing: probeevent: Do not accumulate on ret variable
  tracing: uprobes: Re-enable $comm support for uprobe events
  ftrace/x86_64: Emulate call function while updating in breakpoint handler
  x86_64: Allow breakpoints to emulate call instructions
  x86_64: Add gap to int3 to allow for call emulation
  tracing: kdb: Allow ftdump to skip all but the last few entries
  tracing: Add trace_total_entries() / trace_total_entries_cpu()
  ...
parents 2bbacd1a 693713cb
......@@ -765,6 +765,37 @@ Here is the list of current tracers that may be configured.
tracers from tracing simply echo "nop" into
current_tracer.
Error conditions
----------------
For most ftrace commands, failure modes are obvious and communicated
using standard return codes.
For other more involved commands, extended error information may be
available via the tracing/error_log file. For the commands that
support it, reading the tracing/error_log file after an error will
display more detailed information about what went wrong, if
information is available. The tracing/error_log file is a circular
error log displaying a small number (currently, 8) of ftrace errors
for the last (8) failed commands.
The extended error information and usage takes the form shown in
this example::
# echo xxx > /sys/kernel/debug/tracing/events/sched/sched_wakeup/trigger
echo: write error: Invalid argument
# cat /sys/kernel/debug/tracing/error_log
[ 5348.887237] location: error: Couldn't yyy: zzz
Command: xxx
^
[ 7517.023364] location: error: Bad rrr: sss
Command: ppp qqq
^
To clear the error log, echo the empty string into it::
# echo > /sys/kernel/debug/tracing/error_log
Examples of using the tracer
----------------------------
......
......@@ -199,20 +199,8 @@ Extended error information
For some error conditions encountered when invoking a hist trigger
command, extended error information is available via the
corresponding event's 'hist' file. Reading the hist file after an
error will display more detailed information about what went wrong,
if information is available. This extended error information will
be available until the next hist trigger command for that event.
If available for a given error condition, the extended error
information and usage takes the following form::
# echo xxx > /sys/kernel/debug/tracing/events/sched/sched_wakeup/trigger
echo: write error: Invalid argument
# cat /sys/kernel/debug/tracing/events/sched/sched_wakeup/hist
ERROR: Couldn't yyy: zzz
Last command: xxx
tracing/error_log file. See Error Conditions in
:file:`Documentation/trace/ftrace.rst` for details.
6.2 'hist' trigger examples
---------------------------
......
......@@ -7,7 +7,6 @@
#ifndef CONFIG_DYNAMIC_FTRACE
extern void (*ftrace_trace_function)(unsigned long, unsigned long,
struct ftrace_ops*, struct pt_regs*);
extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
extern void ftrace_graph_caller(void);
noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip,
......
......@@ -51,7 +51,6 @@ void notrace __hot ftrace_function_trampoline(unsigned long parent,
unsigned long org_sp_gr3)
{
extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */
extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
if (ftrace_trace_function != ftrace_stub) {
/* struct ftrace_ops *op, struct pt_regs *regs); */
......
......@@ -24,11 +24,6 @@
#include <linux/sched/task_stack.h>
#ifdef CONFIG_LIVEPATCH
static inline int klp_check_compiler_support(void)
{
return 0;
}
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->nip = ip;
......
......@@ -13,11 +13,6 @@
#include <asm/ptrace.h>
static inline int klp_check_compiler_support(void)
{
return 0;
}
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->psw.addr = ip;
......
......@@ -31,6 +31,17 @@ config X86_64
select SWIOTLB
select ARCH_HAS_SYSCALL_WRAPPER
config FORCE_DYNAMIC_FTRACE
def_bool y
depends on X86_32
depends on FUNCTION_TRACER
select DYNAMIC_FTRACE
help
We keep the static function tracing (!DYNAMIC_FTRACE) around
in order to test the non static function tracing in the
generic code, as other architectures still use it. But we
only need to keep it around for x86_64. No need to keep it
for x86_32. For x86_32, force DYNAMIC_FTRACE.
#
# Arch settings
#
......
......@@ -878,7 +878,7 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt
* @paranoid == 2 is special: the stub will never switch stacks. This is for
* #DF: if the thread stack is somehow unusable, we'll still get a useful OOPS.
*/
.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ist_offset=0
.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 ist_offset=0 create_gap=0
ENTRY(\sym)
UNWIND_HINT_IRET_REGS offset=\has_error_code*8
......@@ -898,6 +898,20 @@ ENTRY(\sym)
jnz .Lfrom_usermode_switch_stack_\@
.endif
.if \create_gap == 1
/*
* If coming from kernel space, create a 6-word gap to allow the
* int3 handler to emulate a call instruction.
*/
testb $3, CS-ORIG_RAX(%rsp)
jnz .Lfrom_usermode_no_gap_\@
.rept 6
pushq 5*8(%rsp)
.endr
UNWIND_HINT_IRET_REGS offset=8
.Lfrom_usermode_no_gap_\@:
.endif
.if \paranoid
call paranoid_entry
.else
......@@ -1129,7 +1143,7 @@ apicinterrupt3 HYPERV_STIMER0_VECTOR \
#endif /* CONFIG_HYPERV */
idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=IST_INDEX_DB ist_offset=DB_STACK_OFFSET
idtentry int3 do_int3 has_error_code=0
idtentry int3 do_int3 has_error_code=0 create_gap=1
idtentry stack_segment do_stack_segment has_error_code=1
#ifdef CONFIG_XEN_PV
......
......@@ -3,12 +3,10 @@
#define _ASM_X86_FTRACE_H
#ifdef CONFIG_FUNCTION_TRACER
#ifdef CC_USING_FENTRY
# define MCOUNT_ADDR ((unsigned long)(__fentry__))
#else
# define MCOUNT_ADDR ((unsigned long)(mcount))
# define HAVE_FUNCTION_GRAPH_FP_TEST
#ifndef CC_USING_FENTRY
# error Compiler does not support fentry?
#endif
# define MCOUNT_ADDR ((unsigned long)(__fentry__))
#define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */
#ifdef CONFIG_DYNAMIC_FTRACE
......
......@@ -24,14 +24,6 @@
#include <asm/setup.h>
#include <linux/ftrace.h>
static inline int klp_check_compiler_support(void)
{
#ifndef CC_USING_FENTRY
return 1;
#endif
return 0;
}
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->ip = ip;
......
......@@ -42,4 +42,34 @@ extern int after_bootmem;
extern __ro_after_init struct mm_struct *poking_mm;
extern __ro_after_init unsigned long poking_addr;
#ifndef CONFIG_UML_X86
static inline void int3_emulate_jmp(struct pt_regs *regs, unsigned long ip)
{
regs->ip = ip;
}
#define INT3_INSN_SIZE 1
#define CALL_INSN_SIZE 5
#ifdef CONFIG_X86_64
static inline void int3_emulate_push(struct pt_regs *regs, unsigned long val)
{
/*
* The int3 handler in entry_64.S adds a gap between the
* stack where the break point happened, and the saving of
* pt_regs. We can extend the original stack because of
* this gap. See the idtentry macro's create_gap option.
*/
regs->sp -= sizeof(unsigned long);
*(unsigned long *)regs->sp = val;
}
static inline void int3_emulate_call(struct pt_regs *regs, unsigned long func)
{
int3_emulate_push(regs, regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE);
int3_emulate_jmp(regs, func);
}
#endif /* CONFIG_X86_64 */
#endif /* !CONFIG_UML_X86 */
#endif /* _ASM_X86_TEXT_PATCHING_H */
......@@ -29,6 +29,7 @@
#include <asm/kprobes.h>
#include <asm/ftrace.h>
#include <asm/nops.h>
#include <asm/text-patching.h>
#ifdef CONFIG_DYNAMIC_FTRACE
......@@ -231,6 +232,7 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
}
static unsigned long ftrace_update_func;
static unsigned long ftrace_update_func_call;
static int update_ftrace_func(unsigned long ip, void *new)
{
......@@ -259,6 +261,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
unsigned char *new;
int ret;
ftrace_update_func_call = (unsigned long)func;
new = ftrace_call_replace(ip, (unsigned long)func);
ret = update_ftrace_func(ip, new);
......@@ -294,13 +298,28 @@ int ftrace_int3_handler(struct pt_regs *regs)
if (WARN_ON_ONCE(!regs))
return 0;
ip = regs->ip - 1;
if (!ftrace_location(ip) && !is_ftrace_caller(ip))
return 0;
ip = regs->ip - INT3_INSN_SIZE;
regs->ip += MCOUNT_INSN_SIZE - 1;
#ifdef CONFIG_X86_64
if (ftrace_location(ip)) {
int3_emulate_call(regs, (unsigned long)ftrace_regs_caller);
return 1;
} else if (is_ftrace_caller(ip)) {
if (!ftrace_update_func_call) {
int3_emulate_jmp(regs, ip + CALL_INSN_SIZE);
return 1;
}
int3_emulate_call(regs, ftrace_update_func_call);
return 1;
}
#else
if (ftrace_location(ip) || is_ftrace_caller(ip)) {
int3_emulate_jmp(regs, ip + CALL_INSN_SIZE);
return 1;
}
#endif
return 1;
return 0;
}
NOKPROBE_SYMBOL(ftrace_int3_handler);
......@@ -865,6 +884,8 @@ void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
func = ftrace_ops_get_func(ops);
ftrace_update_func_call = (unsigned long)func;
/* Do a safe modify in case the trampoline is executing */
new = ftrace_call_replace(ip, (unsigned long)func);
ret = update_ftrace_func(ip, new);
......@@ -966,6 +987,7 @@ static int ftrace_mod_jmp(unsigned long ip, void *func)
{
unsigned char *new;
ftrace_update_func_call = 0UL;
new = ftrace_jmp_replace(ip, (unsigned long)func);
return update_ftrace_func(ip, new);
......
......@@ -10,22 +10,10 @@
#include <asm/ftrace.h>
#include <asm/nospec-branch.h>
#ifdef CC_USING_FENTRY
# define function_hook __fentry__
EXPORT_SYMBOL(__fentry__)
#else
# define function_hook mcount
EXPORT_SYMBOL(mcount)
#endif
#ifdef CONFIG_DYNAMIC_FTRACE
/* mcount uses a frame pointer even if CONFIG_FRAME_POINTER is not set */
#if !defined(CC_USING_FENTRY) || defined(CONFIG_FRAME_POINTER)
# define USING_FRAME_POINTER
#endif
#ifdef USING_FRAME_POINTER
#ifdef CONFIG_FRAME_POINTER
# define MCOUNT_FRAME 1 /* using frame = true */
#else
# define MCOUNT_FRAME 0 /* using frame = false */
......@@ -37,8 +25,7 @@ END(function_hook)
ENTRY(ftrace_caller)
#ifdef USING_FRAME_POINTER
# ifdef CC_USING_FENTRY
#ifdef CONFIG_FRAME_POINTER
/*
* Frame pointers are of ip followed by bp.
* Since fentry is an immediate jump, we are left with
......@@ -49,7 +36,7 @@ ENTRY(ftrace_caller)
pushl %ebp
movl %esp, %ebp
pushl 2*4(%esp) /* function ip */
# endif
/* For mcount, the function ip is directly above */
pushl %ebp
movl %esp, %ebp
......@@ -59,7 +46,7 @@ ENTRY(ftrace_caller)
pushl %edx
pushl $0 /* Pass NULL as regs pointer */
#ifdef USING_FRAME_POINTER
#ifdef CONFIG_FRAME_POINTER
/* Load parent ebp into edx */
movl 4*4(%esp), %edx
#else
......@@ -82,13 +69,11 @@ ftrace_call:
popl %edx
popl %ecx
popl %eax
#ifdef USING_FRAME_POINTER
#ifdef CONFIG_FRAME_POINTER
popl %ebp
# ifdef CC_USING_FENTRY
addl $4,%esp /* skip function ip */
popl %ebp /* this is the orig bp */
addl $4, %esp /* skip parent ip */
# endif
#endif
.Lftrace_ret:
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
......@@ -133,11 +118,7 @@ ENTRY(ftrace_regs_caller)
movl 12*4(%esp), %eax /* Load ip (1st parameter) */
subl $MCOUNT_INSN_SIZE, %eax /* Adjust ip */
#ifdef CC_USING_FENTRY
movl 15*4(%esp), %edx /* Load parent ip (2nd parameter) */
#else
movl 0x4(%ebp), %edx /* Load parent ip (2nd parameter) */
#endif
movl function_trace_op, %ecx /* Save ftrace_pos in 3rd parameter */
pushl %esp /* Save pt_regs as 4th parameter */
......@@ -170,43 +151,6 @@ GLOBAL(ftrace_regs_call)
lea 3*4(%esp), %esp /* Skip orig_ax, ip and cs */
jmp .Lftrace_ret
#else /* ! CONFIG_DYNAMIC_FTRACE */
ENTRY(function_hook)
cmpl $__PAGE_OFFSET, %esp
jb ftrace_stub /* Paging not enabled yet? */
cmpl $ftrace_stub, ftrace_trace_function
jnz .Ltrace
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
cmpl $ftrace_stub, ftrace_graph_return
jnz ftrace_graph_caller
cmpl $ftrace_graph_entry_stub, ftrace_graph_entry
jnz ftrace_graph_caller
#endif
.globl ftrace_stub
ftrace_stub:
ret
/* taken from glibc */
.Ltrace:
pushl %eax
pushl %ecx
pushl %edx
movl 0xc(%esp), %eax
movl 0x4(%ebp), %edx
subl $MCOUNT_INSN_SIZE, %eax
movl ftrace_trace_function, %ecx
CALL_NOSPEC %ecx
popl %edx
popl %ecx
popl %eax
jmp ftrace_stub
END(function_hook)
#endif /* CONFIG_DYNAMIC_FTRACE */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(ftrace_graph_caller)
......@@ -215,13 +159,8 @@ ENTRY(ftrace_graph_caller)
pushl %edx
movl 3*4(%esp), %eax
/* Even with frame pointers, fentry doesn't have one here */
#ifdef CC_USING_FENTRY
lea 4*4(%esp), %edx
movl $0, %ecx
#else
lea 0x4(%ebp), %edx
movl (%ebp), %ecx
#endif
subl $MCOUNT_INSN_SIZE, %eax
call prepare_ftrace_return
popl %edx
......@@ -234,11 +173,7 @@ END(ftrace_graph_caller)
return_to_handler:
pushl %eax
pushl %edx
#ifdef CC_USING_FENTRY
movl $0, %eax
#else
movl %ebp, %eax
#endif
call ftrace_return_to_handler
movl %eax, %ecx
popl %edx
......
......@@ -13,22 +13,12 @@
.code64
.section .entry.text, "ax"
#ifdef CC_USING_FENTRY
# define function_hook __fentry__
EXPORT_SYMBOL(__fentry__)
#else
# define function_hook mcount
EXPORT_SYMBOL(mcount)
#endif
#ifdef CONFIG_FRAME_POINTER
# ifdef CC_USING_FENTRY
/* Save parent and function stack frames (rip and rbp) */
# define MCOUNT_FRAME_SIZE (8+16*2)
# else
/* Save just function stack frame (rip and rbp) */
# define MCOUNT_FRAME_SIZE (8+16)
# endif
#else
/* No need to save a stack frame */
# define MCOUNT_FRAME_SIZE 0
......@@ -75,17 +65,13 @@ EXPORT_SYMBOL(mcount)
* fentry is called before the stack frame is set up, where as mcount
* is called afterward.
*/
#ifdef CC_USING_FENTRY
/* Save the parent pointer (skip orig rbp and our return address) */
pushq \added+8*2(%rsp)
pushq %rbp
movq %rsp, %rbp
/* Save the return address (now skip orig rbp, rbp and parent) */
pushq \added+8*3(%rsp)
#else
/* Can't assume that rip is before this (unless added was zero) */
pushq \added+8(%rsp)
#endif
pushq %rbp
movq %rsp, %rbp
#endif /* CONFIG_FRAME_POINTER */
......@@ -113,12 +99,7 @@ EXPORT_SYMBOL(mcount)
movq %rdx, RBP(%rsp)
/* Copy the parent address into %rsi (second parameter) */
#ifdef CC_USING_FENTRY
movq MCOUNT_REG_SIZE+8+\added(%rsp), %rsi
#else
/* %rdx contains original %rbp */
movq 8(%rdx), %rsi
#endif
/* Move RIP to its proper location */
movq MCOUNT_REG_SIZE+\added(%rsp), %rdi
......@@ -303,15 +284,8 @@ ENTRY(ftrace_graph_caller)
/* Saves rbp into %rdx and fills first parameter */
save_mcount_regs
#ifdef CC_USING_FENTRY
leaq MCOUNT_REG_SIZE+8(%rsp), %rsi
movq $0, %rdx /* No framepointers needed */
#else
/* Save address of the return address of traced function */
leaq 8(%rdx), %rsi
/* ftrace does sanity checks against frame pointers */
movq (%rdx), %rdx
#endif
call prepare_ftrace_return
restore_mcount_regs
......
......@@ -53,23 +53,24 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
* "Define 'is'", Bill Clinton
* "Define 'if'", Steven Rostedt
*/
#define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
#define __trace_if(cond) \
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
({ \
int ______r; \
static struct ftrace_branch_data \
__aligned(4) \
__section("_ftrace_branch") \
______f = { \
.func = __func__, \
.file = __FILE__, \
.line = __LINE__, \
}; \
______r = !!(cond); \
______r ? ______f.miss_hit[1]++ : ______f.miss_hit[0]++;\
______r; \
}))
#define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
#define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
#define __trace_if_value(cond) ({ \
static struct ftrace_branch_data \
__aligned(4) \
__section("_ftrace_branch") \
__if_trace = { \
.func = __func__, \
.file = __FILE__, \
.line = __LINE__, \
}; \
(cond) ? \
(__if_trace.miss_hit[1]++,1) : \
(__if_trace.miss_hit[0]++,0); \
})
#endif /* CONFIG_PROFILE_ALL_BRANCHES */
#else
......
......@@ -741,6 +741,8 @@ struct ftrace_graph_ret {
typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); /* return */
typedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *); /* entry */
extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
struct fgraph_ops {
......
......@@ -548,4 +548,19 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
#define TRACE_EVENT_PERF_PERM(event, expr...)
#define DECLARE_EVENT_NOP(name, proto, args) \
static inline void trace_##name(proto) \
{ } \
static inline bool trace_##name##_enabled(void) \
{ \
return false; \
}
#define TRACE_EVENT_NOP(name, proto, args, struct, assign, print) \
DECLARE_EVENT_NOP(name, PARAMS(proto), PARAMS(args))
#define DECLARE_EVENT_CLASS_NOP(name, proto, args, tstruct, assign, print)
#define DEFINE_EVENT_NOP(template, name, proto, args) \
DECLARE_EVENT_NOP(name, PARAMS(proto), PARAMS(args))
#endif /* ifdef TRACE_EVENT (see note above) */
......@@ -46,6 +46,12 @@
assign, print, reg, unreg) \
DEFINE_TRACE_FN(name, reg, unreg)
#undef TRACE_EVENT_NOP
#define TRACE_EVENT_NOP(name, proto, args, struct, assign, print)
#undef DEFINE_EVENT_NOP
#define DEFINE_EVENT_NOP(template, name, proto, args)
#undef DEFINE_EVENT
#define DEFINE_EVENT(template, name, proto, args) \
DEFINE_TRACE(name)
......@@ -102,6 +108,8 @@
#undef TRACE_EVENT_FN
#undef TRACE_EVENT_FN_COND
#undef TRACE_EVENT_CONDITION
#undef TRACE_EVENT_NOP
#undef DEFINE_EVENT_NOP
#undef DECLARE_EVENT_CLASS
#undef DEFINE_EVENT
#undef DEFINE_EVENT_FN
......
......@@ -7,6 +7,12 @@
#include <linux/tracepoint.h>
#ifdef CONFIG_RCU_TRACE
#define TRACE_EVENT_RCU TRACE_EVENT
#else
#define TRACE_EVENT_RCU TRACE_EVENT_NOP
#endif
/*
* Tracepoint for start/end markers used for utilization calculations.
* By convention, the string is of the following forms:
......@@ -35,8 +41,6 @@ TRACE_EVENT(rcu_utilization,
TP_printk("%s", __entry->s)
);
#ifdef CONFIG_RCU_TRACE
#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
/*
......@@ -62,7 +66,7 @@ TRACE_EVENT(rcu_utilization,
* "end": End a grace period.
* "cpuend": CPU first notices a grace-period end.
*/
TRACE_EVENT(rcu_grace_period,
TRACE_EVENT_RCU(rcu_grace_period,
TP_PROTO(const char *rcuname, unsigned long gp_seq, const char *gpevent),
......@@ -101,7 +105,7 @@ TRACE_EVENT(rcu_grace_period,
* "Cleanup": Clean up rcu_node structure after previous GP.
* "CleanupMore": Clean up, and another GP is needed.
*/
TRACE_EVENT(rcu_future_grace_period,
TRACE_EVENT_RCU(rcu_future_grace_period,
TP_PROTO(const char *rcuname, unsigned long gp_seq,
unsigned long gp_seq_req, u8 level, int grplo, int grphi,
......@@ -141,7 +145,7 @@ TRACE_EVENT(rcu_future_grace_period,
* rcu_node structure, and the mask of CPUs that will be waited for.
* All but the type of RCU are extracted from the rcu_node structure.
*/
TRACE_EVENT(rcu_grace_period_init,
TRACE_EVENT_RCU(rcu_grace_period_init,
TP_PROTO(const char *rcuname, unsigned long gp_seq, u8 level,
int grplo, int grphi, unsigned long qsmask),
......@@ -186,7 +190,7 @@ TRACE_EVENT(rcu_grace_period_init,
* "endwake": Woke piggybackers up.
* "done": Someone else did the expedited grace period for us.
*/
TRACE_EVENT(rcu_exp_grace_period,
TRACE_EVENT_RCU(rcu_exp_grace_period,
TP_PROTO(const char *rcuname, unsigned long gpseq, const char *gpevent),
......@@ -218,7 +222,7 @@ TRACE_EVENT(rcu_exp_grace_period,
* "nxtlvl": Advance to next level of rcu_node funnel
* "wait": Wait for someone else to do expedited GP
*/
TRACE_EVENT(rcu_exp_funnel_lock,
TRACE_EVENT_RCU(rcu_exp_funnel_lock,
TP_PROTO(const char *rcuname, u8 level, int grplo, int grphi,
const char *gpevent),
......@@ -269,7 +273,7 @@ TRACE_EVENT(rcu_exp_funnel_lock,
* "WaitQueue": Enqueue partially done, timed wait for it to complete.
* "WokeQueue": Partial enqueue now complete.
*/
TRACE_EVENT(rcu_nocb_wake,
TRACE_EVENT_RCU(rcu_nocb_wake,
TP_PROTO(const char *rcuname, int cpu, const char *reason),
......@@ -297,7 +301,7 @@ TRACE_EVENT(rcu_nocb_wake,
* include SRCU), the grace-period number that the task is blocking
* (the current or the next), and the task's PID.
*/
TRACE_EVENT(rcu_preempt_task,
TRACE_EVENT_RCU(rcu_preempt_task,
TP_PROTO(const char *rcuname, int pid, unsigned long gp_seq),
......@@ -324,7 +328,7 @@ TRACE_EVENT(rcu_preempt_task,
* read-side critical section exiting that critical section. Track the
* type of RCU (which one day might include SRCU) and the task's PID.
*/
TRACE_EVENT(rcu_unlock_preempted_task,
TRACE_EVENT_RCU(rcu_unlock_preempted_task,
TP_PROTO(const char *rcuname, unsigned long gp_seq, int pid),
......@@ -353,7 +357,7 @@ TRACE_EVENT(rcu_unlock_preempted_task,
* whether there are any blocked tasks blocking the current grace period.
* All but the type of RCU are extracted from the rcu_node structure.
*/
TRACE_EVENT(rcu_quiescent_state_report,
TRACE_EVENT_RCU(rcu_quiescent_state_report,
TP_PROTO(const char *rcuname, unsigned long gp_seq,
unsigned long mask, unsigned long qsmask,
......@@ -396,7 +400,7 @@ TRACE_EVENT(rcu_quiescent_state_report,
* state, which can be "dti" for dyntick-idle mode or "kick" when kicking
* a CPU that has been in dyntick-idle mode for too long.
*/
TRACE_EVENT(rcu_fqs,
TRACE_EVENT_RCU(rcu_fqs,
TP_PROTO(const char *rcuname, unsigned long gp_seq, int cpu, const char *qsevent),
......@@ -436,7 +440,7 @@ TRACE_EVENT(rcu_fqs,
* events use two separate counters, and that the "++=" and "--=" events
* for irq/NMI will change the counter by two, otherwise by one.
*/
TRACE_EVENT(rcu_dyntick,
TRACE_EVENT_RCU(rcu_dyntick,
TP_PROTO(const char *polarity, long oldnesting, long newnesting, atomic_t dynticks),
......@@ -468,7 +472,7 @@ TRACE_EVENT(rcu_dyntick,
* number of lazy callbacks queued, and the fourth element is the
* total number of callbacks queued.
*/
TRACE_EVENT(rcu_callback,
TRACE_EVENT_RCU(rcu_callback,
TP_PROTO(const char *rcuname, struct rcu_head *rhp, long qlen_lazy,
long qlen),
......@@ -504,7 +508,7 @@ TRACE_EVENT(rcu_callback,
* the fourth argument is the number of lazy callbacks queued, and the
* fifth argument is the total number of callbacks queued.
*/
TRACE_EVENT(rcu_kfree_callback,
TRACE_EVENT_RCU(rcu_kfree_callback,
TP_PROTO(const char *rcuname, struct rcu_head *rhp, unsigned long offset,
long qlen_lazy, long qlen),
......@@ -539,7 +543,7 @@ TRACE_EVENT(rcu_kfree_callback,
* the total number of callbacks queued, and the fourth argument is
* the current RCU-callback batch limit.
*/
TRACE_EVENT(rcu_batch_start,
TRACE_EVENT_RCU(rcu_batch_start,
TP_PROTO(const char *rcuname, long qlen_lazy, long qlen, long blimit),
......@@ -569,7 +573,7 @@ TRACE_EVENT(rcu_batch_start,
* The first argument is the type of RCU, and the second argument is
* a pointer to the RCU callback itself.
*/
TRACE_EVENT(rcu_invoke_callback,
TRACE_EVENT_RCU(rcu_invoke_callback,
TP_PROTO(const char *rcuname, struct rcu_head *rhp),
......@@ -598,7 +602,7 @@ TRACE_EVENT(rcu_invoke_callback,
* is the offset of the callback within the enclosing RCU-protected
* data structure.
*/
TRACE_EVENT(rcu_invoke_kfree_callback,
TRACE_EVENT_RCU(rcu_invoke_kfree_callback,
TP_PROTO(const char *rcuname, struct rcu_head *rhp, unsigned long offset),
......@@ -631,7 +635,7 @@ TRACE_EVENT(rcu_invoke_kfree_callback,
* and the sixth argument (risk) is the return value from
* rcu_is_callbacks_kthread().
*/
TRACE_EVENT(rcu_batch_end,
TRACE_EVENT_RCU(rcu_batch_end,
TP_PROTO(const char *rcuname, int callbacks_invoked,
char cb, char nr, char iit, char risk),
......@@ -673,7 +677,7 @@ TRACE_EVENT(rcu_batch_end,
* callback address can be NULL.
*/
#define RCUTORTURENAME_LEN 8
TRACE_EVENT(rcu_torture_read,
TRACE_EVENT_RCU(rcu_torture_read,
TP_PROTO(const char *rcutorturename, struct rcu_head *rhp,
unsigned long secs, unsigned long c_old, unsigned long c),
......@@ -721,7 +725,7 @@ TRACE_EVENT(rcu_torture_read,
* The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument
* is the count of remaining callbacks, and "done" is the piggybacking count.
*/
TRACE_EVENT(rcu_barrier,
TRACE_EVENT_RCU(rcu_barrier,
TP_PROTO(const char *rcuname, const char *s, int cpu, int cnt, unsigned long done),
......@@ -748,41 +752,6 @@ TRACE_EVENT(rcu_barrier,
__entry->done)
);
#else /* #ifdef CONFIG_RCU_TRACE */
#define trace_rcu_grace_period(rcuname, gp_seq, gpevent) do { } while (0)
#define trace_rcu_future_grace_period(rcuname, gp_seq, gp_seq_req, \
level, grplo, grphi, event) \
do { } while (0)
#define trace_rcu_grace_period_init(rcuname, gp_seq, level, grplo, grphi, \
qsmask) do { } while (0)
#define trace_rcu_exp_grace_period(rcuname, gqseq, gpevent) \
do { } while (0)
#define trace_rcu_exp_funnel_lock(rcuname, level, grplo, grphi, gpevent) \
do { } while (0)
#define trace_rcu_nocb_wake(rcuname, cpu, reason) do { } while (0)
#define trace_rcu_preempt_task(rcuname, pid, gp_seq) do { } while (0)
#define trace_rcu_unlock_preempted_task(rcuname, gp_seq, pid) do { } while (0)
#define trace_rcu_quiescent_state_report(rcuname, gp_seq, mask, qsmask, level, \
grplo, grphi, gp_tasks) do { } \
while (0)
#define trace_rcu_fqs(rcuname, gp_seq, cpu, qsevent) do { } while (0)
#define trace_rcu_dyntick(polarity, oldnesting, newnesting, dyntick) do { } while (0)
#define trace_rcu_callback(rcuname, rhp, qlen_lazy, qlen) do { } while (0)
#define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen_lazy, qlen) \
do { } while (0)
#define trace_rcu_batch_start(rcuname, qlen_lazy, qlen, blimit) \
do { } while (0)
#define trace_rcu_invoke_callback(rcuname, rhp) do { } while (0)
#define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0)
#define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \
do { } while (0)
#define trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
do { } while (0)
#define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0)
#endif /* #else #ifdef CONFIG_RCU_TRACE */
#endif /* _TRACE_RCU_H */
/* This part must be outside protection */
......
......@@ -241,7 +241,6 @@ DECLARE_EVENT_CLASS(sched_process_template,
DEFINE_EVENT(sched_process_template, sched_process_free,
TP_PROTO(struct task_struct *p),
TP_ARGS(p));
/*
* Tracepoint for a task exiting:
......@@ -336,11 +335,20 @@ TRACE_EVENT(sched_process_exec,
__entry->pid, __entry->old_pid)
);
#ifdef CONFIG_SCHEDSTATS
#define DEFINE_EVENT_SCHEDSTAT DEFINE_EVENT
#define DECLARE_EVENT_CLASS_SCHEDSTAT DECLARE_EVENT_CLASS
#else
#define DEFINE_EVENT_SCHEDSTAT DEFINE_EVENT_NOP
#define DECLARE_EVENT_CLASS_SCHEDSTAT DECLARE_EVENT_CLASS_NOP
#endif
/*
* XXX the below sched_stat tracepoints only apply to SCHED_OTHER/BATCH/IDLE
* adding sched_stat support to SCHED_FIFO/RR would be welcome.
*/
DECLARE_EVENT_CLASS(sched_stat_template,
DECLARE_EVENT_CLASS_SCHEDSTAT(sched_stat_template,
TP_PROTO(struct task_struct *tsk, u64 delay),
......@@ -363,12 +371,11 @@ DECLARE_EVENT_CLASS(sched_stat_template,
(unsigned long long)__entry->delay)
);
/*
* Tracepoint for accounting wait time (time the task is runnable
* but not actually running due to scheduler contention).
*/
DEFINE_EVENT(sched_stat_template, sched_stat_wait,
DEFINE_EVENT_SCHEDSTAT(sched_stat_template, sched_stat_wait,
TP_PROTO(struct task_struct *tsk, u64 delay),
TP_ARGS(tsk, delay));
......@@ -376,7 +383,7 @@ DEFINE_EVENT(sched_stat_template, sched_stat_wait,
* Tracepoint for accounting sleep time (time the task is not runnable,
* including iowait, see below).
*/
DEFINE_EVENT(sched_stat_template, sched_stat_sleep,
DEFINE_EVENT_SCHEDSTAT(sched_stat_template, sched_stat_sleep,
TP_PROTO(struct task_struct *tsk, u64 delay),
TP_ARGS(tsk, delay));
......@@ -384,14 +391,14 @@ DEFINE_EVENT(sched_stat_template, sched_stat_sleep,
* Tracepoint for accounting iowait time (time the task is not runnable
* due to waiting on IO to complete).
*/
DEFINE_EVENT(sched_stat_template, sched_stat_iowait,
DEFINE_EVENT_SCHEDSTAT(sched_stat_template, sched_stat_iowait,
TP_PROTO(struct task_struct *tsk, u64 delay),
TP_ARGS(tsk, delay));
/*
* Tracepoint for accounting blocked time (time the task is in uninterruptible).
*/
DEFINE_EVENT(sched_stat_template, sched_stat_blocked,
DEFINE_EVENT_SCHEDSTAT(sched_stat_template, sched_stat_blocked,
TP_PROTO(struct task_struct *tsk, u64 delay),
TP_ARGS(tsk, delay));
......
......@@ -1208,14 +1208,6 @@ void klp_module_going(struct module *mod)
static int __init klp_init(void)
{
int ret;
ret = klp_check_compiler_support();
if (ret) {
pr_info("Your compiler is too old; turning off.\n");
return -EINVAL;
}
klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
if (!klp_root_kobj)
return -ENOMEM;
......
......@@ -11,11 +11,6 @@
#define __LINUX_RCU_H
#include <trace/events/rcu.h>
#ifdef CONFIG_RCU_TRACE
#define RCU_TRACE(stmt) stmt
#else /* #ifdef CONFIG_RCU_TRACE */
#define RCU_TRACE(stmt)
#endif /* #else #ifdef CONFIG_RCU_TRACE */
/* Offset to allow distinguishing irq vs. task-based idle entry/exit. */
#define DYNTICK_IRQ_NONIDLE ((LONG_MAX / 2) + 1)
......@@ -216,12 +211,12 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head)
rcu_lock_acquire(&rcu_callback_map);
if (__is_kfree_rcu_offset(offset)) {
RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset);)
trace_rcu_invoke_kfree_callback(rn, head, offset);
kfree((void *)head - offset);
rcu_lock_release(&rcu_callback_map);
return true;
} else {
RCU_TRACE(trace_rcu_invoke_callback(rn, head);)
trace_rcu_invoke_callback(rn, head);
f = head->func;
WRITE_ONCE(head->func, (rcu_callback_t)0L);
f(head);
......
......@@ -1969,14 +1969,14 @@ rcu_check_quiescent_state(struct rcu_data *rdp)
*/
int rcutree_dying_cpu(unsigned int cpu)
{
RCU_TRACE(bool blkd;)
RCU_TRACE(struct rcu_data *rdp = this_cpu_ptr(&rcu_data);)
RCU_TRACE(struct rcu_node *rnp = rdp->mynode;)
bool blkd;
struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
struct rcu_node *rnp = rdp->mynode;
if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
return 0;
RCU_TRACE(blkd = !!(rnp->qsmask & rdp->grpmask);)
blkd = !!(rnp->qsmask & rdp->grpmask);
trace_rcu_grace_period(rcu_state.name, rnp->gp_seq,
blkd ? TPS("cpuofl") : TPS("cpuofl-bgp"));
return 0;
......
......@@ -70,12 +70,8 @@
#define INIT_OPS_HASH(opsname) \
.func_hash = &opsname.local_hash, \
.local_hash.regex_lock = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock),
#define ASSIGN_OPS_HASH(opsname, val) \
.func_hash = val, \
.local_hash.regex_lock = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock),
#else
#define INIT_OPS_HASH(opsname)
#define ASSIGN_OPS_HASH(opsname, val)
#endif
enum {
......@@ -3880,7 +3876,7 @@ static int ftrace_hash_move_and_update_ops(struct ftrace_ops *ops,
static bool module_exists(const char *module)
{
/* All modules have the symbol __this_module */
const char this_mod[] = "__this_module";
static const char this_mod[] = "__this_module";
char modname[MAX_PARAM_PREFIX_LEN + sizeof(this_mod) + 2];
unsigned long val;
int n;
......@@ -6265,6 +6261,9 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
preempt_disable_notrace();
do_for_each_ftrace_op(op, ftrace_ops_list) {
/* Stub functions don't need to be called nor tested */
if (op->flags & FTRACE_OPS_FL_STUB)
continue;
/*
* Check the following for each ops before calling their func:
* if RCU flag is set, then rcu_is_watching() must be true
......
......@@ -4979,7 +4979,7 @@ static __init int rb_write_something(struct rb_test_data *data, bool nested)
cnt = data->cnt + (nested ? 27 : 0);
/* Multiply cnt by ~e, to make some unique increment */
size = (data->cnt * 68 / 25) % (sizeof(rb_string) - 1);
size = (cnt * 68 / 25) % (sizeof(rb_string) - 1);
len = size + sizeof(struct rb_item);
......
......@@ -362,7 +362,7 @@ static void ring_buffer_producer(void)
hit--; /* make it non zero */
}
/* Caculate the average time in nanosecs */
/* Calculate the average time in nanosecs */
avg = NSEC_PER_MSEC / (hit + missed);
trace_printk("%ld ns per entry\n", avg);
}
......
This diff is collapsed.
......@@ -293,11 +293,13 @@ struct trace_array {
int nr_topts;
bool clear_trace;
int buffer_percent;
unsigned int n_err_log_entries;
struct tracer *current_trace;
unsigned int trace_flags;
unsigned char trace_flags_index[TRACE_FLAGS_MAX_SIZE];
unsigned int flags;
raw_spinlock_t start_lock;
struct list_head err_log;
struct dentry *dir;
struct dentry *options;
struct dentry *percpu_dir;
......@@ -719,6 +721,9 @@ void trace_init_global_iter(struct trace_iterator *iter);
void tracing_iter_reset(struct trace_iterator *iter, int cpu);
unsigned long trace_total_entries_cpu(struct trace_array *tr, int cpu);
unsigned long trace_total_entries(struct trace_array *tr);
void trace_function(struct trace_array *tr,
unsigned long ip,
unsigned long parent_ip,
......@@ -1545,7 +1550,8 @@ extern int apply_subsystem_event_filter(struct trace_subsystem_dir *dir,
extern void print_subsystem_event_filter(struct event_subsystem *system,
struct trace_seq *s);
extern int filter_assign_type(const char *type);
extern int create_event_filter(struct trace_event_call *call,
extern int create_event_filter(struct trace_array *tr,
struct trace_event_call *call,
char *filter_str, bool set_str,
struct event_filter **filterp);
extern void free_event_filter(struct event_filter *filter);
......@@ -1876,6 +1882,11 @@ extern ssize_t trace_parse_run_command(struct file *file,
const char __user *buffer, size_t count, loff_t *ppos,
int (*createfn)(int, char**));
extern unsigned int err_pos(char *cmd, const char *str);
extern void tracing_log_err(struct trace_array *tr,
const char *loc, const char *cmd,
const char **errs, u8 type, u8 pos);
/*
* Normal trace_printk() and friends allocates special buffers
* to do the manipulation, as well as saves the print formats
......
......@@ -832,6 +832,7 @@ static int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set)
return ret;
}
EXPORT_SYMBOL_GPL(ftrace_set_clr_event);
/**
* trace_set_clr_event - enable or disable an event
......@@ -1318,9 +1319,6 @@ event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
char buf[32];
int len;
if (*ppos)
return 0;
if (unlikely(!id))
return -ENODEV;
......
......@@ -66,7 +66,8 @@ static const char * ops[] = { OPS };
C(INVALID_FILTER, "Meaningless filter expression"), \
C(IP_FIELD_ONLY, "Only 'ip' field is supported for function trace"), \
C(INVALID_VALUE, "Invalid value (did you forget quotes)?"), \
C(NO_FILTER, "No filter found"),
C(ERRNO, "Error"), \
C(NO_FILTER, "No filter found")
#undef C
#define C(a, b) FILT_ERR_##a
......@@ -76,7 +77,7 @@ enum { ERRORS };
#undef C
#define C(a, b) b
static char *err_text[] = { ERRORS };
static const char *err_text[] = { ERRORS };
/* Called after a '!' character but "!=" and "!~" are not "not"s */
static bool is_not(const char *str)
......@@ -919,7 +920,8 @@ static void remove_filter_string(struct event_filter *filter)
filter->filter_string = NULL;
}
static void append_filter_err(struct filter_parse_error *pe,
static void append_filter_err(struct trace_array *tr,
struct filter_parse_error *pe,
struct event_filter *filter)
{
struct trace_seq *s;
......@@ -947,8 +949,14 @@ static void append_filter_err(struct filter_parse_error *pe,
if (pe->lasterr > 0) {
trace_seq_printf(s, "\n%*s", pos, "^");
trace_seq_printf(s, "\nparse_error: %s\n", err_text[pe->lasterr]);
tracing_log_err(tr, "event filter parse error",
filter->filter_string, err_text,
pe->lasterr, pe->lasterr_pos);
} else {
trace_seq_printf(s, "\nError: (%d)\n", pe->lasterr);
tracing_log_err(tr, "event filter parse error",
filter->filter_string, err_text,
FILT_ERR_ERRNO, 0);
}
trace_seq_putc(s, 0);
buf = kmemdup_nul(s->buffer, s->seq.len, GFP_KERNEL);
......@@ -1214,30 +1222,30 @@ static int parse_pred(const char *str, void *data,
* (perf doesn't use it) and grab everything.
*/
if (strcmp(field->name, "ip") != 0) {
parse_error(pe, FILT_ERR_IP_FIELD_ONLY, pos + i);
goto err_free;
}
pred->fn = filter_pred_none;
/*
* Quotes are not required, but if they exist then we need
* to read them till we hit a matching one.
*/
if (str[i] == '\'' || str[i] == '"')
q = str[i];
else
q = 0;
for (i++; str[i]; i++) {
if (q && str[i] == q)
break;
if (!q && (str[i] == ')' || str[i] == '&' ||
str[i] == '|'))
break;
}
/* Skip quotes */
if (q)
s++;
parse_error(pe, FILT_ERR_IP_FIELD_ONLY, pos + i);
goto err_free;
}
pred->fn = filter_pred_none;
/*
* Quotes are not required, but if they exist then we need
* to read them till we hit a matching one.
*/
if (str[i] == '\'' || str[i] == '"')
q = str[i];
else
q = 0;
for (i++; str[i]; i++) {
if (q && str[i] == q)
break;
if (!q && (str[i] == ')' || str[i] == '&' ||
str[i] == '|'))
break;
}
/* Skip quotes */
if (q)
s++;
len = i - s;
if (len >= MAX_FILTER_STR_VAL) {
parse_error(pe, FILT_ERR_OPERAND_TOO_LONG, pos + i);
......@@ -1600,7 +1608,7 @@ static int process_system_preds(struct trace_subsystem_dir *dir,
if (err) {
filter_disable(file);
parse_error(pe, FILT_ERR_BAD_SUBSYS_FILTER, 0);
append_filter_err(pe, filter);
append_filter_err(tr, pe, filter);
} else
event_set_filtered_flag(file);
......@@ -1712,7 +1720,8 @@ static void create_filter_finish(struct filter_parse_error *pe)
* information if @set_str is %true and the caller is responsible for
* freeing it.
*/
static int create_filter(struct trace_event_call *call,
static int create_filter(struct trace_array *tr,
struct trace_event_call *call,
char *filter_string, bool set_str,
struct event_filter **filterp)
{
......@@ -1729,17 +1738,18 @@ static int create_filter(struct trace_event_call *call,
err = process_preds(call, filter_string, *filterp, pe);
if (err && set_str)
append_filter_err(pe, *filterp);
append_filter_err(tr, pe, *filterp);
create_filter_finish(pe);
return err;
}
int create_event_filter(struct trace_event_call *call,
int create_event_filter(struct trace_array *tr,
struct trace_event_call *call,
char *filter_str, bool set_str,
struct event_filter **filterp)
{
return create_filter(call, filter_str, set_str, filterp);
return create_filter(tr, call, filter_str, set_str, filterp);
}
/**
......@@ -1766,7 +1776,7 @@ static int create_system_filter(struct trace_subsystem_dir *dir,
kfree((*filterp)->filter_string);
(*filterp)->filter_string = NULL;
} else {
append_filter_err(pe, *filterp);
append_filter_err(tr, pe, *filterp);
}
}
create_filter_finish(pe);
......@@ -1797,7 +1807,7 @@ int apply_event_filter(struct trace_event_file *file, char *filter_string)
return 0;
}
err = create_filter(call, filter_string, true, &filter);
err = create_filter(file->tr, call, filter_string, true, &filter);
/*
* Always swap the call filter with the new filter
......@@ -2053,7 +2063,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
if (event->filter)
goto out_unlock;
err = create_filter(call, filter_str, false, &filter);
err = create_filter(NULL, call, filter_str, false, &filter);
if (err)
goto free_filter;
......@@ -2202,8 +2212,8 @@ static __init int ftrace_test_event_filter(void)
struct test_filter_data_t *d = &test_filter_data[i];
int err;
err = create_filter(&event_ftrace_test_filter, d->filter,
false, &filter);
err = create_filter(NULL, &event_ftrace_test_filter,
d->filter, false, &filter);
if (err) {
printk(KERN_INFO
"Failed to get filter for '%s', err %d\n",
......
This diff is collapsed.
......@@ -731,7 +731,8 @@ int set_trigger_filter(char *filter_str,
goto out;
/* The filter is for the 'trigger' event, not the triggered event */
ret = create_event_filter(file->event_call, filter_str, false, &filter);
ret = create_event_filter(file->tr, file->event_call,
filter_str, false, &filter);
/*
* If create_event_filter() fails, filter still needs to be freed.
* Which the calling code will do with data->filter.
......
......@@ -17,29 +17,25 @@
#include "trace.h"
#include "trace_output.h"
static void ftrace_dump_buf(int skip_lines, long cpu_file)
static struct trace_iterator iter;
static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS];
static void ftrace_dump_buf(int skip_entries, long cpu_file)
{
/* use static because iter can be a bit big for the stack */
static struct trace_iterator iter;
static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS];
struct trace_array *tr;
unsigned int old_userobj;
int cnt = 0, cpu;
trace_init_global_iter(&iter);
iter.buffer_iter = buffer_iter;
tr = iter.tr;
for_each_tracing_cpu(cpu) {
atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
}
old_userobj = tr->trace_flags;
/* don't look at user memory in panic mode */
tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
kdb_printf("Dumping ftrace buffer:\n");
if (skip_entries)
kdb_printf("(skipping %d entries)\n", skip_entries);
/* reset all but tr, trace, and overruns */
memset(&iter.seq, 0,
......@@ -70,11 +66,11 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
kdb_printf("---------------------------------\n");
cnt++;
if (!skip_lines) {
if (!skip_entries) {
print_trace_line(&iter);
trace_printk_seq(&iter.seq);
} else {
skip_lines--;
skip_entries--;
}
if (KDB_FLAG(CMD_INTERRUPT))
......@@ -89,10 +85,6 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
out:
tr->trace_flags = old_userobj;
for_each_tracing_cpu(cpu) {
atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
}
for_each_tracing_cpu(cpu) {
if (iter.buffer_iter[cpu]) {
ring_buffer_read_finish(iter.buffer_iter[cpu]);
......@@ -106,17 +98,19 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
*/
static int kdb_ftdump(int argc, const char **argv)
{
int skip_lines = 0;
int skip_entries = 0;
long cpu_file;
char *cp;
int cnt;
int cpu;
if (argc > 2)
return KDB_ARGCOUNT;
if (argc) {
skip_lines = simple_strtol(argv[1], &cp, 0);
skip_entries = simple_strtol(argv[1], &cp, 0);
if (*cp)
skip_lines = 0;
skip_entries = 0;
}
if (argc == 2) {
......@@ -129,7 +123,29 @@ static int kdb_ftdump(int argc, const char **argv)
}
kdb_trap_printk++;
ftrace_dump_buf(skip_lines, cpu_file);
trace_init_global_iter(&iter);
iter.buffer_iter = buffer_iter;
for_each_tracing_cpu(cpu) {
atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
}
/* A negative skip_entries means skip all but the last entries */
if (skip_entries < 0) {
if (cpu_file == RING_BUFFER_ALL_CPUS)
cnt = trace_total_entries(NULL);
else
cnt = trace_total_entries_cpu(NULL, cpu_file);
skip_entries = max(cnt + skip_entries, 0);
}
ftrace_dump_buf(skip_entries, cpu_file);
for_each_tracing_cpu(cpu) {
atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
}
kdb_trap_printk--;
return 0;
......@@ -137,8 +153,9 @@ static int kdb_ftdump(int argc, const char **argv)
static __init int kdb_ftrace_register(void)
{
kdb_register_flags("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
"Dump ftrace log", 0, KDB_ENABLE_ALWAYS_SAFE);
kdb_register_flags("ftdump", kdb_ftdump, "[skip_#entries] [cpu]",
"Dump ftrace log; -skip dumps last #entries", 0,
KDB_ENABLE_ALWAYS_SAFE);
return 0;
}
......
......@@ -441,13 +441,8 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
else
ret = register_kprobe(&tk->rp.kp);
if (ret == 0) {
if (ret == 0)
tk->tp.flags |= TP_FLAG_REGISTERED;
} else if (ret == -EILSEQ) {
pr_warn("Probing address(0x%p) is not an instruction boundary.\n",
tk->rp.kp.addr);
ret = -EINVAL;
}
return ret;
}
......@@ -591,7 +586,7 @@ static int trace_kprobe_create(int argc, const char *argv[])
* Type of args:
* FETCHARG:TYPE : use TYPE instead of unsigned long.
*/
struct trace_kprobe *tk;
struct trace_kprobe *tk = NULL;
int i, len, ret = 0;
bool is_return = false;
char *symbol = NULL, *tmp = NULL;
......@@ -615,44 +610,50 @@ static int trace_kprobe_create(int argc, const char *argv[])
if (argc < 2)
return -ECANCELED;
trace_probe_log_init("trace_kprobe", argc, argv);
event = strchr(&argv[0][1], ':');
if (event)
event++;
if (isdigit(argv[0][1])) {
if (!is_return) {
pr_info("Maxactive is not for kprobe");
return -EINVAL;
trace_probe_log_err(1, MAXACT_NO_KPROBE);
goto parse_error;
}
if (event)
len = event - &argv[0][1] - 1;
else
len = strlen(&argv[0][1]);
if (len > MAX_EVENT_NAME_LEN - 1)
return -E2BIG;
if (len > MAX_EVENT_NAME_LEN - 1) {
trace_probe_log_err(1, BAD_MAXACT);
goto parse_error;
}
memcpy(buf, &argv[0][1], len);
buf[len] = '\0';
ret = kstrtouint(buf, 0, &maxactive);
if (ret || !maxactive) {
pr_info("Invalid maxactive number\n");
return ret;
trace_probe_log_err(1, BAD_MAXACT);
goto parse_error;
}
/* kretprobes instances are iterated over via a list. The
* maximum should stay reasonable.
*/
if (maxactive > KRETPROBE_MAXACTIVE_MAX) {
pr_info("Maxactive is too big (%d > %d).\n",
maxactive, KRETPROBE_MAXACTIVE_MAX);
return -E2BIG;
trace_probe_log_err(1, MAXACT_TOO_BIG);
goto parse_error;
}
}
/* try to parse an address. if that fails, try to read the
* input as a symbol. */
if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) {
trace_probe_log_set_index(1);
/* Check whether uprobe event specified */
if (strchr(argv[1], '/') && strchr(argv[1], ':'))
return -ECANCELED;
if (strchr(argv[1], '/') && strchr(argv[1], ':')) {
ret = -ECANCELED;
goto error;
}
/* a symbol specified */
symbol = kstrdup(argv[1], GFP_KERNEL);
if (!symbol)
......@@ -660,23 +661,23 @@ static int trace_kprobe_create(int argc, const char *argv[])
/* TODO: support .init module functions */
ret = traceprobe_split_symbol_offset(symbol, &offset);
if (ret || offset < 0 || offset > UINT_MAX) {
pr_info("Failed to parse either an address or a symbol.\n");
goto out;
trace_probe_log_err(0, BAD_PROBE_ADDR);
goto parse_error;
}
if (kprobe_on_func_entry(NULL, symbol, offset))
flags |= TPARG_FL_FENTRY;
if (offset && is_return && !(flags & TPARG_FL_FENTRY)) {
pr_info("Given offset is not valid for return probe.\n");
ret = -EINVAL;
goto out;
trace_probe_log_err(0, BAD_RETPROBE);
goto parse_error;
}
}
argc -= 2; argv += 2;
trace_probe_log_set_index(0);
if (event) {
ret = traceprobe_parse_event_name(&event, &group, buf);
ret = traceprobe_parse_event_name(&event, &group, buf,
event - argv[0]);
if (ret)
goto out;
goto parse_error;
} else {
/* Make a new event name */
if (symbol)
......@@ -691,13 +692,14 @@ static int trace_kprobe_create(int argc, const char *argv[])
/* setup a probe */
tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
argc, is_return);
argc - 2, is_return);
if (IS_ERR(tk)) {
ret = PTR_ERR(tk);
/* This must return -ENOMEM otherwise there is a bug */
/* This must return -ENOMEM, else there is a bug */
WARN_ON_ONCE(ret != -ENOMEM);
goto out;
goto out; /* We know tk is not allocated */
}
argc -= 2; argv += 2;
/* parse arguments */
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
......@@ -707,19 +709,32 @@ static int trace_kprobe_create(int argc, const char *argv[])
goto error;
}
trace_probe_log_set_index(i + 2);
ret = traceprobe_parse_probe_arg(&tk->tp, i, tmp, flags);
kfree(tmp);
if (ret)
goto error;
goto error; /* This can be -ENOMEM */
}
ret = register_trace_kprobe(tk);
if (ret)
if (ret) {
trace_probe_log_set_index(1);
if (ret == -EILSEQ)
trace_probe_log_err(0, BAD_INSN_BNDRY);
else if (ret == -ENOENT)
trace_probe_log_err(0, BAD_PROBE_ADDR);
else if (ret != -ENOMEM)
trace_probe_log_err(0, FAIL_REG_PROBE);
goto error;
}
out:
trace_probe_log_clear();
kfree(symbol);
return ret;
parse_error:
ret = -EINVAL;
error:
free_trace_kprobe(tk);
goto out;
......
This diff is collapsed.
......@@ -124,6 +124,7 @@ struct fetch_insn {
/* fetch + deref*N + store + mod + end <= 16, this allows N=12, enough */
#define FETCH_INSN_MAX 16
#define FETCH_TOKEN_COMM (-ECOMM)
/* Fetch type information table */
struct fetch_type {
......@@ -280,8 +281,8 @@ extern int traceprobe_update_arg(struct probe_arg *arg);
extern void traceprobe_free_probe_arg(struct probe_arg *arg);
extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
extern int traceprobe_parse_event_name(const char **pevent,
const char **pgroup, char *buf);
int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
char *buf, int offset);
extern int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return);
......@@ -298,3 +299,76 @@ extern void destroy_local_trace_uprobe(struct trace_event_call *event_call);
#endif
extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
size_t offset, struct trace_probe *tp);
#undef ERRORS
#define ERRORS \
C(FILE_NOT_FOUND, "Failed to find the given file"), \
C(NO_REGULAR_FILE, "Not a regular file"), \
C(BAD_REFCNT, "Invalid reference counter offset"), \
C(REFCNT_OPEN_BRACE, "Reference counter brace is not closed"), \
C(BAD_REFCNT_SUFFIX, "Reference counter has wrong suffix"), \
C(BAD_UPROBE_OFFS, "Invalid uprobe offset"), \
C(MAXACT_NO_KPROBE, "Maxactive is not for kprobe"), \
C(BAD_MAXACT, "Invalid maxactive number"), \
C(MAXACT_TOO_BIG, "Maxactive is too big"), \
C(BAD_PROBE_ADDR, "Invalid probed address or symbol"), \
C(BAD_RETPROBE, "Retprobe address must be an function entry"), \
C(NO_GROUP_NAME, "Group name is not specified"), \
C(GROUP_TOO_LONG, "Group name is too long"), \
C(BAD_GROUP_NAME, "Group name must follow the same rules as C identifiers"), \
C(NO_EVENT_NAME, "Event name is not specified"), \
C(EVENT_TOO_LONG, "Event name is too long"), \
C(BAD_EVENT_NAME, "Event name must follow the same rules as C identifiers"), \
C(RETVAL_ON_PROBE, "$retval is not available on probe"), \
C(BAD_STACK_NUM, "Invalid stack number"), \
C(BAD_ARG_NUM, "Invalid argument number"), \
C(BAD_VAR, "Invalid $-valiable specified"), \
C(BAD_REG_NAME, "Invalid register name"), \
C(BAD_MEM_ADDR, "Invalid memory address"), \
C(FILE_ON_KPROBE, "File offset is not available with kprobe"), \
C(BAD_FILE_OFFS, "Invalid file offset value"), \
C(SYM_ON_UPROBE, "Symbol is not available with uprobe"), \
C(TOO_MANY_OPS, "Dereference is too much nested"), \
C(DEREF_NEED_BRACE, "Dereference needs a brace"), \
C(BAD_DEREF_OFFS, "Invalid dereference offset"), \
C(DEREF_OPEN_BRACE, "Dereference brace is not closed"), \
C(COMM_CANT_DEREF, "$comm can not be dereferenced"), \
C(BAD_FETCH_ARG, "Invalid fetch argument"), \
C(ARRAY_NO_CLOSE, "Array is not closed"), \
C(BAD_ARRAY_SUFFIX, "Array has wrong suffix"), \
C(BAD_ARRAY_NUM, "Invalid array size"), \
C(ARRAY_TOO_BIG, "Array number is too big"), \
C(BAD_TYPE, "Unknown type is specified"), \
C(BAD_STRING, "String accepts only memory argument"), \
C(BAD_BITFIELD, "Invalid bitfield"), \
C(ARG_NAME_TOO_LONG, "Argument name is too long"), \
C(NO_ARG_NAME, "Argument name is not specified"), \
C(BAD_ARG_NAME, "Argument name must follow the same rules as C identifiers"), \
C(USED_ARG_NAME, "This argument name is already used"), \
C(ARG_TOO_LONG, "Argument expression is too long"), \
C(NO_ARG_BODY, "No argument expression"), \
C(BAD_INSN_BNDRY, "Probe point is not an instruction boundary"),\
C(FAIL_REG_PROBE, "Failed to register probe event"),
#undef C
#define C(a, b) TP_ERR_##a
/* Define TP_ERR_ */
enum { ERRORS };
/* Error text is defined in trace_probe.c */
struct trace_probe_log {
const char *subsystem;
const char **argv;
int argc;
int index;
};
void trace_probe_log_init(const char *subsystem, int argc, const char **argv);
void trace_probe_log_set_index(int index);
void trace_probe_log_clear(void);
void __trace_probe_log_err(int offset, int err);
#define trace_probe_log_err(offs, err) \
__trace_probe_log_err(offs, TP_ERR_##err)
......@@ -88,7 +88,7 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
/* 3rd stage: store value to buffer */
if (unlikely(!dest)) {
if (code->op == FETCH_OP_ST_STRING) {
ret += fetch_store_strlen(val + code->offset);
ret = fetch_store_strlen(val + code->offset);
code++;
goto array;
} else
......
......@@ -792,7 +792,10 @@ trace_selftest_startup_function_graph(struct tracer *trace,
/* check the trace buffer */
ret = trace_test_buffer(&tr->trace_buffer, &count);
trace->reset(tr);
/* Need to also simulate the tr->reset to remove this fgraph_ops */
tracing_stop_cmdline_record();
unregister_ftrace_graph(&fgraph_ops);
tracing_start();
if (!ret && !count) {
......
......@@ -156,7 +156,10 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
if (unlikely(!maxlen))
return -ENOMEM;
ret = strncpy_from_user(dst, src, maxlen);
if (addr == FETCH_TOKEN_COMM)
ret = strlcpy(dst, current->comm, maxlen);
else
ret = strncpy_from_user(dst, src, maxlen);
if (ret >= 0) {
if (ret == maxlen)
dst[ret - 1] = '\0';
......@@ -180,7 +183,10 @@ fetch_store_strlen(unsigned long addr)
int len;
void __user *vaddr = (void __force __user *) addr;
len = strnlen_user(vaddr, MAX_STRING_SIZE);
if (addr == FETCH_TOKEN_COMM)
len = strlen(current->comm) + 1;
else
len = strnlen_user(vaddr, MAX_STRING_SIZE);
return (len > MAX_STRING_SIZE) ? 0 : len;
}
......@@ -220,6 +226,9 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
case FETCH_OP_IMM:
val = code->immediate;
break;
case FETCH_OP_COMM:
val = FETCH_TOKEN_COMM;
break;
case FETCH_OP_FOFFS:
val = translate_user_vaddr(code->immediate);
break;
......@@ -457,13 +466,19 @@ static int trace_uprobe_create(int argc, const char **argv)
return -ECANCELED;
}
trace_probe_log_init("trace_uprobe", argc, argv);
trace_probe_log_set_index(1); /* filename is the 2nd argument */
*arg++ = '\0';
ret = kern_path(filename, LOOKUP_FOLLOW, &path);
if (ret) {
trace_probe_log_err(0, FILE_NOT_FOUND);
kfree(filename);
trace_probe_log_clear();
return ret;
}
if (!d_is_reg(path.dentry)) {
trace_probe_log_err(0, NO_REGULAR_FILE);
ret = -EINVAL;
goto fail_address_parse;
}
......@@ -472,9 +487,16 @@ static int trace_uprobe_create(int argc, const char **argv)
rctr = strchr(arg, '(');
if (rctr) {
rctr_end = strchr(rctr, ')');
if (rctr > rctr_end || *(rctr_end + 1) != 0) {
if (!rctr_end) {
ret = -EINVAL;
rctr_end = rctr + strlen(rctr);
trace_probe_log_err(rctr_end - filename,
REFCNT_OPEN_BRACE);
goto fail_address_parse;
} else if (rctr_end[1] != '\0') {
ret = -EINVAL;
pr_info("Invalid reference counter offset.\n");
trace_probe_log_err(rctr_end + 1 - filename,
BAD_REFCNT_SUFFIX);
goto fail_address_parse;
}
......@@ -482,22 +504,23 @@ static int trace_uprobe_create(int argc, const char **argv)
*rctr_end = '\0';
ret = kstrtoul(rctr, 0, &ref_ctr_offset);
if (ret) {
pr_info("Invalid reference counter offset.\n");
trace_probe_log_err(rctr - filename, BAD_REFCNT);
goto fail_address_parse;
}
}
/* Parse uprobe offset. */
ret = kstrtoul(arg, 0, &offset);
if (ret)
if (ret) {
trace_probe_log_err(arg - filename, BAD_UPROBE_OFFS);
goto fail_address_parse;
argc -= 2;
argv += 2;
}
/* setup a probe */
trace_probe_log_set_index(0);
if (event) {
ret = traceprobe_parse_event_name(&event, &group, buf);
ret = traceprobe_parse_event_name(&event, &group, buf,
event - argv[0]);
if (ret)
goto fail_address_parse;
} else {
......@@ -519,6 +542,9 @@ static int trace_uprobe_create(int argc, const char **argv)
kfree(tail);
}
argc -= 2;
argv += 2;
tu = alloc_trace_uprobe(group, event, argc, is_return);
if (IS_ERR(tu)) {
ret = PTR_ERR(tu);
......@@ -539,6 +565,7 @@ static int trace_uprobe_create(int argc, const char **argv)
goto error;
}
trace_probe_log_set_index(i + 2);
ret = traceprobe_parse_probe_arg(&tu->tp, i, tmp,
is_return ? TPARG_FL_RETURN : 0);
kfree(tmp);
......@@ -547,20 +574,20 @@ static int trace_uprobe_create(int argc, const char **argv)
}
ret = register_trace_uprobe(tu);
if (ret)
goto error;
return 0;
if (!ret)
goto out;
error:
free_trace_uprobe(tu);
out:
trace_probe_log_clear();
return ret;
fail_address_parse:
trace_probe_log_clear();
path_put(&path);
kfree(filename);
pr_info("Failed to parse address or file.\n");
return ret;
}
......
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: ftrace - test tracing error log support
fail() { #msg
echo $1
exit_fail
}
# event tracing is currently the only ftrace tracer that uses the
# tracing error_log, hence this check
if [ ! -f set_event ]; then
echo "event tracing is not supported"
exit_unsupported
fi
ftrace_errlog_check 'event filter parse error' '((sig >= 10 && sig < 15) || dsig ^== 17) && comm != bash' 'events/signal/signal_generate/filter'
exit 0
......@@ -109,3 +109,15 @@ LOCALHOST=127.0.0.1
yield() {
ping $LOCALHOST -c 1 || sleep .001 || usleep 1 || sleep 1
}
ftrace_errlog_check() { # err-prefix command-with-error-pos-by-^ command-file
pos=$(echo -n "${2%^*}" | wc -c) # error position
command=$(echo "$2" | tr -d ^)
echo "Test command: $command"
echo > error_log
(! echo "$command" > "$3" ) 2> /dev/null
grep "$1: error:" -A 3 error_log
N=$(tail -n 1 error_log | wc -c)
# " Command: " and "^\n" => 13
test $(expr 13 + $pos) -eq $N
}
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Kprobe event parser error log check
[ -f kprobe_events ] || exit_unsupported # this is configurable
[ -f error_log ] || exit_unsupported
check_error() { # command-with-error-pos-by-^
ftrace_errlog_check 'trace_kprobe' "$1" 'kprobe_events'
}
if grep -q 'r\[maxactive\]' README; then
check_error 'p^100 vfs_read' # MAXACT_NO_KPROBE
check_error 'r^1a111 vfs_read' # BAD_MAXACT
check_error 'r^100000 vfs_read' # MAXACT_TOO_BIG
fi
check_error 'p ^non_exist_func' # BAD_PROBE_ADDR (enoent)
check_error 'p ^hoge-fuga' # BAD_PROBE_ADDR (bad syntax)
check_error 'p ^hoge+1000-1000' # BAD_PROBE_ADDR (bad syntax)
check_error 'r ^vfs_read+10' # BAD_RETPROBE
check_error 'p:^/bar vfs_read' # NO_GROUP_NAME
check_error 'p:^12345678901234567890123456789012345678901234567890123456789012345/bar vfs_read' # GROUP_TOO_LONG
check_error 'p:^foo.1/bar vfs_read' # BAD_GROUP_NAME
check_error 'p:foo/^ vfs_read' # NO_EVENT_NAME
check_error 'p:foo/^12345678901234567890123456789012345678901234567890123456789012345 vfs_read' # EVENT_TOO_LONG
check_error 'p:foo/^bar.1 vfs_read' # BAD_EVENT_NAME
check_error 'p vfs_read ^$retval' # RETVAL_ON_PROBE
check_error 'p vfs_read ^$stack10000' # BAD_STACK_NUM
if grep -q '$arg<N>' README; then
check_error 'p vfs_read ^$arg10000' # BAD_ARG_NUM
fi
check_error 'p vfs_read ^$none_var' # BAD_VAR
check_error 'p vfs_read ^%none_reg' # BAD_REG_NAME
check_error 'p vfs_read ^@12345678abcde' # BAD_MEM_ADDR
check_error 'p vfs_read ^@+10' # FILE_ON_KPROBE
check_error 'p vfs_read ^+0@0)' # DEREF_NEED_BRACE
check_error 'p vfs_read ^+0ab1(@0)' # BAD_DEREF_OFFS
check_error 'p vfs_read +0(+0(@0^)' # DEREF_OPEN_BRACE
if grep -A1 "fetcharg:" README | grep -q '\$comm' ; then
check_error 'p vfs_read +0(^$comm)' # COMM_CANT_DEREF
fi
check_error 'p vfs_read ^&1' # BAD_FETCH_ARG
# We've introduced this limitation with array support
if grep -q ' <type>\\\[<array-size>\\\]' README; then
check_error 'p vfs_read +0(^+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(+0(@0))))))))))))))' # TOO_MANY_OPS?
check_error 'p vfs_read +0(@11):u8[10^' # ARRAY_NO_CLOSE
check_error 'p vfs_read +0(@11):u8[10]^a' # BAD_ARRAY_SUFFIX
check_error 'p vfs_read +0(@11):u8[^10a]' # BAD_ARRAY_NUM
check_error 'p vfs_read +0(@11):u8[^256]' # ARRAY_TOO_BIG
fi
check_error 'p vfs_read @11:^unknown_type' # BAD_TYPE
check_error 'p vfs_read $stack0:^string' # BAD_STRING
check_error 'p vfs_read @11:^b10@a/16' # BAD_BITFIELD
check_error 'p vfs_read ^arg123456789012345678901234567890=@11' # ARG_NAME_TOO_LOG
check_error 'p vfs_read ^=@11' # NO_ARG_NAME
check_error 'p vfs_read ^var.1=@11' # BAD_ARG_NAME
check_error 'p vfs_read var1=@11 ^var1=@12' # USED_ARG_NAME
check_error 'p vfs_read ^+1234567(+1234567(+1234567(+1234567(+1234567(+1234567(@1234))))))' # ARG_TOO_LONG
check_error 'p vfs_read arg1=^' # NO_ARG_BODY
# instruction boundary check is valid on x86 (at this moment)
case $(uname -m) in
x86_64|i[3456]86)
echo 'p vfs_read' > kprobe_events
if grep -q FTRACE ../kprobes/list ; then
check_error 'p ^vfs_read+3' # BAD_INSN_BNDRY (only if function-tracer is enabled)
fi
;;
esac
exit 0
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Uprobe event parser error log check
[ -f uprobe_events ] || exit_unsupported # this is configurable
[ -f error_log ] || exit_unsupported
check_error() { # command-with-error-pos-by-^
ftrace_errlog_check 'trace_uprobe' "$1" 'uprobe_events'
}
check_error 'p ^/non_exist_file:100' # FILE_NOT_FOUND
check_error 'p ^/sys:100' # NO_REGULAR_FILE
check_error 'p /bin/sh:^10a' # BAD_UPROBE_OFFS
check_error 'p /bin/sh:10(^1a)' # BAD_REFCNT
check_error 'p /bin/sh:10(10^' # REFCNT_OPEN_BRACE
check_error 'p /bin/sh:10(10)^a' # BAD_REFCNT_SUFFIX
check_error 'p /bin/sh:10 ^@+ab' # BAD_FILE_OFFS
check_error 'p /bin/sh:10 ^@symbol' # SYM_ON_UPROBE
exit 0
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: event trigger - test extended error support
fail() { #msg
echo $1
exit_fail
}
if [ ! -f set_event ]; then
echo "event tracing is not supported"
exit_unsupported
fi
if [ ! -f synthetic_events ]; then
echo "synthetic event is not supported"
exit_unsupported
fi
echo "Test extended error support"
echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger
! echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_wakeup/trigger 2> /dev/null
if ! grep -q "ERROR:" events/sched/sched_wakeup/hist; then
fail "Failed to generate extended error in histogram"
fi
exit 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