- Rework of the kprobe/uprobe and synthetic events to consolidate all
the dynamic event code. This will make changes in the future easier.
- Partial rewrite of the function graph tracing infrastructure.
This will allow for multiple users of hooking onto functions
to get the callback (return) of the function. This is the ground
work for having kprobes and function graph tracer using one code base.
- Clean up of the histogram code that will facilitate adding more
features to the histograms in the future.
- Addition of str_has_prefix() and a few use cases. There currently
is a similar function strstart() that is used in a few places, but
only returns a bool and not a length. These instances will be
removed in the future to use str_has_prefix() instead.
- A few other various clean ups as well.
-----BEGIN PGP SIGNATURE-----
iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCXCawlBQccm9zdGVkdEBn
b29kbWlzLm9yZwAKCRAp5XQQmuv6qhbcAQCFeT0fWWTUxofBQz5jqsHaRnVg21+9
X4sTldYRYEn4YgEAmWOyiwq7zvrsAu4ZwkNBMeqxn3tVymYHiGOGe3Y4BAw=
=u96o
-----END PGP SIGNATURE-----
Merge tag 'trace-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing updates from Steven Rostedt:
- Rework of the kprobe/uprobe and synthetic events to consolidate all
the dynamic event code. This will make changes in the future easier.
- Partial rewrite of the function graph tracing infrastructure. This
will allow for multiple users of hooking onto functions to get the
callback (return) of the function. This is the ground work for having
kprobes and function graph tracer using one code base.
- Clean up of the histogram code that will facilitate adding more
features to the histograms in the future.
- Addition of str_has_prefix() and a few use cases. There currently is
a similar function strstart() that is used in a few places, but only
returns a bool and not a length. These instances will be removed in
the future to use str_has_prefix() instead.
- A few other various clean ups as well.
* tag 'trace-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (57 commits)
tracing: Use the return of str_has_prefix() to remove open coded numbers
tracing: Have the historgram use the result of str_has_prefix() for len of prefix
tracing: Use str_has_prefix() instead of using fixed sizes
tracing: Use str_has_prefix() helper for histogram code
string.h: Add str_has_prefix() helper function
tracing: Make function ‘ftrace_exports’ static
tracing: Simplify printf'ing in seq_print_sym
tracing: Avoid -Wformat-nonliteral warning
tracing: Merge seq_print_sym_short() and seq_print_sym_offset()
tracing: Add hist trigger comments for variable-related fields
tracing: Remove hist trigger synth_var_refs
tracing: Use hist trigger's var_ref array to destroy var_refs
tracing: Remove open-coding of hist trigger var_ref management
tracing: Use var_refs[] for hist trigger reference checking
tracing: Change strlen to sizeof for hist trigger static strings
tracing: Remove unnecessary hist trigger struct field
tracing: Fix ftrace_graph_get_ret_stack() to use task and not current
seq_buf: Use size_t for len in seq_buf_puts()
seq_buf: Make seq_buf_puts() null-terminate the buffer
arm64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
...
163 lines
3.4 KiB
C
163 lines
3.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
|
|
* Copyright (C) 2009 Matt Fleming
|
|
* Copyright (C) 2002 - 2012 Paul Mundt
|
|
*/
|
|
#include <linux/kallsyms.h>
|
|
#include <linux/ftrace.h>
|
|
#include <linux/debug_locks.h>
|
|
#include <linux/sched/debug.h>
|
|
#include <linux/sched/task_stack.h>
|
|
#include <linux/kdebug.h>
|
|
#include <linux/export.h>
|
|
#include <linux/uaccess.h>
|
|
#include <asm/unwinder.h>
|
|
#include <asm/stacktrace.h>
|
|
|
|
void dump_mem(const char *str, unsigned long bottom, unsigned long top)
|
|
{
|
|
unsigned long p;
|
|
int i;
|
|
|
|
printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
|
|
|
|
for (p = bottom & ~31; p < top; ) {
|
|
printk("%04lx: ", p & 0xffff);
|
|
|
|
for (i = 0; i < 8; i++, p += 4) {
|
|
unsigned int val;
|
|
|
|
if (p < bottom || p >= top)
|
|
printk(" ");
|
|
else {
|
|
if (__get_user(val, (unsigned int __user *)p)) {
|
|
printk("\n");
|
|
return;
|
|
}
|
|
printk("%08x ", val);
|
|
}
|
|
}
|
|
printk("\n");
|
|
}
|
|
}
|
|
|
|
void printk_address(unsigned long address, int reliable)
|
|
{
|
|
printk(" [<%p>] %s%pS\n", (void *) address,
|
|
reliable ? "" : "? ", (void *) address);
|
|
}
|
|
|
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
|
static void
|
|
print_ftrace_graph_addr(unsigned long addr, void *data,
|
|
const struct stacktrace_ops *ops,
|
|
struct thread_info *tinfo, int *graph)
|
|
{
|
|
struct task_struct *task = tinfo->task;
|
|
struct ftrace_ret_stack *ret_stack;
|
|
unsigned long ret_addr;
|
|
|
|
if (addr != (unsigned long)return_to_handler)
|
|
return;
|
|
|
|
if (!task->ret_stack)
|
|
return;
|
|
|
|
ret_stack = ftrace_graph_get_ret_stack(task, *graph);
|
|
if (!ret_stack)
|
|
return;
|
|
|
|
ret_addr = ret_stack->ret;
|
|
|
|
ops->address(data, ret_addr, 1);
|
|
|
|
(*graph)++;
|
|
}
|
|
#else
|
|
static inline void
|
|
print_ftrace_graph_addr(unsigned long addr, void *data,
|
|
const struct stacktrace_ops *ops,
|
|
struct thread_info *tinfo, int *graph)
|
|
{ }
|
|
#endif
|
|
|
|
void
|
|
stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
|
|
unsigned long *sp, const struct stacktrace_ops *ops,
|
|
void *data)
|
|
{
|
|
struct thread_info *context;
|
|
int graph = 0;
|
|
|
|
context = (struct thread_info *)
|
|
((unsigned long)sp & (~(THREAD_SIZE - 1)));
|
|
|
|
while (!kstack_end(sp)) {
|
|
unsigned long addr = *sp++;
|
|
|
|
if (__kernel_text_address(addr)) {
|
|
ops->address(data, addr, 1);
|
|
|
|
print_ftrace_graph_addr(addr, data, ops,
|
|
context, &graph);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int print_trace_stack(void *data, char *name)
|
|
{
|
|
printk("%s <%s> ", (char *)data, name);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Print one address/symbol entries per line.
|
|
*/
|
|
static void print_trace_address(void *data, unsigned long addr, int reliable)
|
|
{
|
|
printk("%s", (char *)data);
|
|
printk_address(addr, reliable);
|
|
}
|
|
|
|
static const struct stacktrace_ops print_trace_ops = {
|
|
.stack = print_trace_stack,
|
|
.address = print_trace_address,
|
|
};
|
|
|
|
void show_trace(struct task_struct *tsk, unsigned long *sp,
|
|
struct pt_regs *regs)
|
|
{
|
|
if (regs && user_mode(regs))
|
|
return;
|
|
|
|
printk("\nCall trace:\n");
|
|
|
|
unwind_stack(tsk, regs, sp, &print_trace_ops, "");
|
|
|
|
printk("\n");
|
|
|
|
if (!tsk)
|
|
tsk = current;
|
|
|
|
debug_show_held_locks(tsk);
|
|
}
|
|
|
|
void show_stack(struct task_struct *tsk, unsigned long *sp)
|
|
{
|
|
unsigned long stack;
|
|
|
|
if (!tsk)
|
|
tsk = current;
|
|
if (tsk == current)
|
|
sp = (unsigned long *)current_stack_pointer;
|
|
else
|
|
sp = (unsigned long *)tsk->thread.sp;
|
|
|
|
stack = (unsigned long)sp;
|
|
dump_mem("Stack: ", stack, THREAD_SIZE +
|
|
(unsigned long)task_stack_page(tsk));
|
|
show_trace(tsk, sp, NULL);
|
|
}
|