Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 121185
b: refs/heads/master
c: 02b6751
h: refs/heads/master
i:
  121183: 36c8940
v: v3
  • Loading branch information
Török Edwin authored and Ingo Molnar committed Nov 23, 2008
1 parent 3f4d65e commit 5e8555c
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 69 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 033601a32b2012b6948e80e739cca40bff4de4a0
refs/heads/master: 02b67518e2b1c490787dac7f35e1204e74fe21ba
5 changes: 4 additions & 1 deletion trunk/Documentation/ftrace.txt
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ output. To see what is available, simply cat the file:

cat /debug/tracing/trace_options
print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \
noblock nostacktrace nosched-tree
noblock nostacktrace nosched-tree nouserstacktrace

To disable one of the options, echo in the option prepended with "no".

Expand Down Expand Up @@ -378,6 +378,9 @@ Here are the available options:
When a trace is recorded, so is the stack of functions.
This allows for back traces of trace sites.

userstacktrace - This option changes the trace.
It records a stacktrace of the current userspace thread.

sched-tree - TBD (any users??)


Expand Down
57 changes: 57 additions & 0 deletions trunk/arch/x86/kernel/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <linux/sched.h>
#include <linux/stacktrace.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <asm/stacktrace.h>

static void save_stack_warning(void *data, char *msg)
Expand Down Expand Up @@ -83,3 +84,59 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);

/* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */

struct stack_frame {
const void __user *next_fp;
unsigned long return_address;
};

static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
{
int ret;

if (!access_ok(VERIFY_READ, fp, sizeof(*frame)))
return 0;

ret = 1;
pagefault_disable();
if (__copy_from_user_inatomic(frame, fp, sizeof(*frame)))
ret = 0;
pagefault_enable();

return ret;
}

void save_stack_trace_user(struct stack_trace *trace)
{
/*
* Trace user stack if we are not a kernel thread
*/
if (current->mm) {
const struct pt_regs *regs = task_pt_regs(current);
const void __user *fp = (const void __user *)regs->bp;

if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = regs->ip;

while (trace->nr_entries < trace->max_entries) {
struct stack_frame frame;
frame.next_fp = NULL;
frame.return_address = 0;
if (!copy_stack_frame(fp, &frame))
break;
if ((unsigned long)fp < regs->sp)
break;
if (frame.return_address)
trace->entries[trace->nr_entries++] =
frame.return_address;
if (fp == frame.next_fp)
break;
fp = frame.next_fp;
}
}
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}

1 change: 0 additions & 1 deletion trunk/include/linux/ring_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ void ring_buffer_normalize_time_stamp(int cpu, u64 *ts);

void tracing_on(void);
void tracing_off(void);
void tracing_off_permanent(void);

enum ring_buffer_flags {
RB_FL_OVERWRITE = 1 << 0,
Expand Down
8 changes: 8 additions & 0 deletions trunk/include/linux/stacktrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,17 @@ extern void save_stack_trace_tsk(struct task_struct *tsk,
struct stack_trace *trace);

extern void print_stack_trace(struct stack_trace *trace, int spaces);

#ifdef CONFIG_X86
extern void save_stack_trace_user(struct stack_trace *trace);
#else
# define save_stack_trace_user(trace) do { } while (0)
#endif

#else
# define save_stack_trace(trace) do { } while (0)
# define save_stack_trace_tsk(tsk, trace) do { } while (0)
# define save_stack_trace_user(trace) do { } while (0)
# define print_stack_trace(trace, spaces) do { } while (0)
#endif

Expand Down
79 changes: 13 additions & 66 deletions trunk/kernel/trace/ring_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,8 @@

#include "trace.h"

/*
* A fast way to enable or disable all ring buffers is to
* call tracing_on or tracing_off. Turning off the ring buffers
* prevents all ring buffers from being recorded to.
* Turning this switch on, makes it OK to write to the
* ring buffer, if the ring buffer is enabled itself.
*
* There's three layers that must be on in order to write
* to the ring buffer.
*
* 1) This global flag must be set.
* 2) The ring buffer must be enabled for recording.
* 3) The per cpu buffer must be enabled for recording.
*
* In case of an anomaly, this global flag has a bit set that
* will permantly disable all ring buffers.
*/

/*
* Global flag to disable all recording to ring buffers
* This has two bits: ON, DISABLED
*
* ON DISABLED
* ---- ----------
* 0 0 : ring buffers are off
* 1 0 : ring buffers are on
* X 1 : ring buffers are permanently disabled
*/

enum {
RB_BUFFERS_ON_BIT = 0,
RB_BUFFERS_DISABLED_BIT = 1,
};

enum {
RB_BUFFERS_ON = 1 << RB_BUFFERS_ON_BIT,
RB_BUFFERS_DISABLED = 1 << RB_BUFFERS_DISABLED_BIT,
};

static long ring_buffer_flags __read_mostly = RB_BUFFERS_ON;
/* Global flag to disable all recording to ring buffers */
static int ring_buffers_off __read_mostly;

/**
* tracing_on - enable all tracing buffers
Expand All @@ -67,7 +29,7 @@ static long ring_buffer_flags __read_mostly = RB_BUFFERS_ON;
*/
void tracing_on(void)
{
set_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags);
ring_buffers_off = 0;
}

/**
Expand All @@ -80,18 +42,7 @@ void tracing_on(void)
*/
void tracing_off(void)
{
clear_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags);
}

/**
* tracing_off_permanent - permanently disable ring buffers
*
* This function, once called, will disable all ring buffers
* permanenty.
*/
void tracing_off_permanent(void)
{
set_bit(RB_BUFFERS_DISABLED_BIT, &ring_buffer_flags);
ring_buffers_off = 1;
}

#include "trace.h"
Expand Down Expand Up @@ -1234,7 +1185,7 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer,
struct ring_buffer_event *event;
int cpu, resched;

if (ring_buffer_flags != RB_BUFFERS_ON)
if (ring_buffers_off)
return NULL;

if (atomic_read(&buffer->record_disabled))
Expand Down Expand Up @@ -1346,7 +1297,7 @@ int ring_buffer_write(struct ring_buffer *buffer,
int ret = -EBUSY;
int cpu, resched;

if (ring_buffer_flags != RB_BUFFERS_ON)
if (ring_buffers_off)
return -EBUSY;

if (atomic_read(&buffer->record_disabled))
Expand Down Expand Up @@ -2227,14 +2178,12 @@ static ssize_t
rb_simple_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
long *p = filp->private_data;
int *p = filp->private_data;
char buf[64];
int r;

if (test_bit(RB_BUFFERS_DISABLED_BIT, p))
r = sprintf(buf, "permanently disabled\n");
else
r = sprintf(buf, "%d\n", test_bit(RB_BUFFERS_ON_BIT, p));
/* !ring_buffers_off == tracing_on */
r = sprintf(buf, "%d\n", !*p);

return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}
Expand All @@ -2243,7 +2192,7 @@ static ssize_t
rb_simple_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
long *p = filp->private_data;
int *p = filp->private_data;
char buf[64];
long val;
int ret;
Expand All @@ -2260,10 +2209,8 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
if (ret < 0)
return ret;

if (val)
set_bit(RB_BUFFERS_ON_BIT, p);
else
clear_bit(RB_BUFFERS_ON_BIT, p);
/* !ring_buffers_off == tracing_on */
*p = !val;

(*ppos)++;

Expand All @@ -2285,7 +2232,7 @@ static __init int rb_init_debugfs(void)
d_tracer = tracing_init_dentry();

entry = debugfs_create_file("tracing_on", 0644, d_tracer,
&ring_buffer_flags, &rb_simple_fops);
&ring_buffers_off, &rb_simple_fops);
if (!entry)
pr_warning("Could not create debugfs 'tracing_on' entry\n");

Expand Down
Loading

0 comments on commit 5e8555c

Please sign in to comment.