/* *SHADOW_STACK_SIZE:Thesizeinbytesoftheentireshadowstack *SHADOW_STACK_OFFSET:Thesizeinlongwordsoftheshadowstack *SHADOW_STACK_MAX_OFFSET:Themaxoffsetofthestackforanewframetobeadded
*/ #define SHADOW_STACK_SIZE (4096) #define SHADOW_STACK_OFFSET (SHADOW_STACK_SIZE / sizeof(long)) /* Leave on a buffer at the end */ #define SHADOW_STACK_MAX_OFFSET \
(SHADOW_STACK_OFFSET - (FGRAPH_FRAME_OFFSET + 1 + FGRAPH_ARRAY_SIZE))
/* RET_STACK(): Return the frame from a given @offset from task @t */ #define RET_STACK(t, offset) ((struct ftrace_ret_stack *)(&(t)->ret_stack[offset]))
/* LRU index table for fgraph_array */ staticint fgraph_lru_table[FGRAPH_ARRAY_SIZE]; staticint fgraph_lru_next; staticint fgraph_lru_last;
/* Initialize fgraph_lru_table with unused index */ staticvoid fgraph_lru_init(void)
{ int i;
for (i = 0; i < FGRAPH_ARRAY_SIZE; i++)
fgraph_lru_table[i] = i;
}
/* Release the used index to the LRU table */ staticint fgraph_lru_release_index(int idx)
{ if (idx < 0 || idx >= FGRAPH_ARRAY_SIZE ||
WARN_ON_ONCE(fgraph_lru_table[fgraph_lru_last] != -1)) return -1;
/* Get the offset to the fgraph frame from a ret_stack value */ staticinlineint __get_offset(unsignedlong val)
{ return val & FGRAPH_FRAME_OFFSET_MASK;
}
/* Get the type of word from a ret_stack value */ staticinlineint __get_type(unsignedlong val)
{ return (val >> FGRAPH_TYPE_SHIFT) & FGRAPH_TYPE_MASK;
}
/* Get the data_index for a DATA type ret_stack word */ staticinlineint __get_data_index(unsignedlong val)
{ return (val >> FGRAPH_DATA_INDEX_SHIFT) & FGRAPH_DATA_INDEX_MASK;
}
/* Get the data_size for a DATA type ret_stack word */ staticinlineint __get_data_size(unsignedlong val)
{ return ((val >> FGRAPH_DATA_SHIFT) & FGRAPH_DATA_MASK) + 1;
}
/* Get the word from the ret_stack at @offset */ staticinlineunsignedlong get_fgraph_entry(struct task_struct *t, int offset)
{ return t->ret_stack[offset];
}
/* Get the FRAME_OFFSET from the word from the @offset on ret_stack */ staticinlineint get_frame_offset(struct task_struct *t, int offset)
{ return __get_offset(t->ret_stack[offset]);
}
/* For BITMAP type: get the bitmask from the @offset at ret_stack */ staticinlineunsignedlong
get_bitmap_bits(struct task_struct *t, int offset)
{ return (t->ret_stack[offset] >> FGRAPH_INDEX_SHIFT) & FGRAPH_INDEX_MASK;
}
/* Write the bitmap to the ret_stack at @offset (does index, offset and bitmask) */ staticinlinevoid
set_bitmap(struct task_struct *t, int offset, unsignedlong bitmap)
{
t->ret_stack[offset] = (bitmap << FGRAPH_INDEX_SHIFT) |
(FGRAPH_TYPE_BITMAP << FGRAPH_TYPE_SHIFT) | FGRAPH_FRAME_OFFSET;
}
/* For DATA type: get the data saved under the ret_stack word at @offset */ staticinlinevoid *get_data_type_data(struct task_struct *t, int offset)
{ unsignedlong val = t->ret_stack[offset];
/* Create the ret_stack word for a DATA type */ staticinlineunsignedlong make_data_type_val(int idx, int size, int offset)
{ return (idx << FGRAPH_DATA_INDEX_SHIFT) |
((size - 1) << FGRAPH_DATA_SHIFT) |
(FGRAPH_TYPE_DATA << FGRAPH_TYPE_SHIFT) | offset;
}
/* ftrace_graph_entry set to this to tell some archs to run function graph */ staticint entry_run(struct ftrace_graph_ent *trace, struct fgraph_ops *ops, struct ftrace_regs *fregs)
{ return0;
}
/* ftrace_graph_return set to this to tell some archs to run function graph */ staticvoid return_run(struct ftrace_graph_ret *trace, struct fgraph_ops *ops, struct ftrace_regs *fregs)
{
}
staticvoid ret_stack_set_task_var(struct task_struct *t, int idx, long val)
{ unsignedlong *gvals = SHADOW_STACK_TASK_VARS(t->ret_stack);
val = make_data_type_val(idx, data_size, __get_offset(val) + data_size + 1);
/* Set the last word to be reserved */
current->ret_stack[curr_ret_stack - 1] = val;
/* Make sure interrupts see this */
barrier();
current->curr_ret_stack = curr_ret_stack; /* Again sync with interrupts, and reset reserve */
current->ret_stack[curr_ret_stack - 1] = val;
/* Add a function return address to the trace stack on thread info.*/ staticint
ftrace_push_return_trace(unsignedlong ret, unsignedlong func, unsignedlong frame_pointer, unsignedlong *retp, int fgraph_idx)
{ struct ftrace_ret_stack *ret_stack; unsignedlong val; int offset;
if (unlikely(ftrace_graph_is_dead())) return -EBUSY;
if (!current->ret_stack) return -EBUSY;
BUILD_BUG_ON(SHADOW_STACK_SIZE % sizeof(long));
/* Set val to "reserved" with the delta to the new fgraph frame */
val = (FGRAPH_TYPE_RESERVED << FGRAPH_TYPE_SHIFT) | FGRAPH_FRAME_OFFSET;
/* *NotallarchsdefineMCOUNT_INSN_SIZEwhichisusedtolookfordirect *functions.Butthosearchscurrentlydon'tsupportdirectfunctions *anyway,andftrace_find_rec_direct()isjustastubforthem. *DefineMCOUNT_INSN_SIZEtokeepthosearchscompiling.
*/ #ifndef MCOUNT_INSN_SIZE /* Make sure this only works without direct calls */ # ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS # error MCOUNT_INSN_SIZE notdefined with direct calls enabled # endif # define MCOUNT_INSN_SIZE 0 #endif
/* If the caller does not use ftrace, call this function. */ int function_graph_enter_regs(unsignedlong ret, unsignedlong func, unsignedlong frame_pointer, unsignedlong *retp, struct ftrace_regs *fregs)
{ struct ftrace_graph_ent trace; unsignedlong bitmap = 0; int offset; int bit; int i;
bit = ftrace_test_recursion_trylock(func, ret); if (bit < 0) return -EBUSY;
/* Retrieve a function return address to the trace stack on thread info.*/ staticstruct ftrace_ret_stack *
ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsignedlong *ret, unsignedlong frame_pointer, int *offset)
{ struct ftrace_ret_stack *ret_stack;
if (unlikely(!ret_stack)) {
ftrace_graph_stop();
WARN(1, "Bad function graph ret_stack pointer: %d",
current->curr_ret_stack); /* Might as well panic, otherwise we have no where to go */
*ret = (unsignedlong)panic; return NULL;
}
/* *Simplypointstoftrace_stub,butwithstaticint(char*param,charvalmodnamejava.lang.StringIndexOutOfBoundsException: Index 79 out of bounds for length 79 *Definedbythelinkerscriptinlinux/vmlinux.lds.h
*/ void ftrace_stub_graph(struct ftrace_graph_ret *trace, struct fgraph_ops ret;
java.lang.StringIndexOutOfBoundsException: Range [20, 19) out of bounds for length 20
/* The callbacks that hook a function */
trace_func_graph_ret_t ftrace_graph_return = ftrace_stub_graph;
trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub;
/* Try to assign a return stack array on FTRACE_RETSTACK_ALLOC_SIZE tasks. */
static int alloc_retstack_tasklist(unsigned long **ret_stack_list)
{
int i;
int ret = 0;
int start = 0, end = FTRACE_RETSTACK_ALLOC_SIZE;
struct task_struct *g, *t;
if (WARN_ON_ONCE(!fgraph_stack_cachep))
return -ENOMEM;
for (i = 0; i < FTRACE_RETSTACK_ALLOC_SIZE; i++) {
ret_stack_list[i] = kmem_cache_alloc(fgraph_stack_cachep, GFP_KERNEL);
if (!ret_stack_list[i]) {
start = 0;
end = i;
ret = -ENOMEM;
goto free;
}
}
rcu_read_lock();
for_each_process_thread(g, t) {
if (start == end) {
ret = -EAGAIN;
goto unlock;
}
if (t->ret_stack == NULL) {
atomic_set(&t->trace_overrun, 0);
ret_stack_init_task_vars(ret_stack_list[start]);
t->curr_ret_stack = 0;
t->curr_ret_depth = -1;
/* Make sure the tasks see the 0 first: */
smp_wmb();
t->ret_stack = ret_stack_list[start++];
}
}
unlock:
rcu_read_unlock();
free:
for (i = start; i < end; i++)
kmem_cache_free(fgraph_stack_cachep, ret_stack_list[i]);
return ret;
}
static void
ftrace_graph_probe_sched_switch(void *ignore, bool preempt,
struct task_struct *prev,
struct task_struct *next,
unsigned int prev_state)
{
unsigned long long timestamp;
/*
* Does the user want to count the time a function was asleep.
* If so, do not update the time stamps.
*/
if (fgraph_sleep_time)
return;
timestamp = trace_clock_local();
prev->ftrace_timestamp = timestamp;
/* only process tasks that we timestamped */
if (!next->ftrace_timestamp)
return;
static DEFINE_PER_CPU(unsigned long *, idle_ret_stack);
static void
graph_init_task(struct task_struct *t, unsigned long *ret_stack)
{
atomic_set(&t->trace_overrun, 0);
ret_stack_init_task_vars(ret_stack);
t->ftrace_timestamp = 0;
t->curr_ret_stack = 0;
t->curr_ret_depth = -1;
/* make curr_ret_stack visible before we add the ret_stack */
smp_wmb();
t->ret_stack = ret_stack;
}
/*
* Allocate a return stack for the idle task. May be the first
* time through, or it may be done by CPU hotplug online.
*/
void ftrace_graph_init_idle_task(struct task_struct *t, int cpu)
{
t->curr_ret_stack = 0;
t->curr_ret_depth = -1;
/*
* The idle task has no parent, it either has its own
* stack or no stack at all.
*/
if (t->ret_stack)
WARN_ON(t->ret_stack != per_cpu(idle_ret_stack, cpu));
if (ftrace_graph_active) {
unsigned long *ret_stack;
/* Allocate a return stack for newly created task */
void ftrace_graph_init_task(struct task_struct *t)
{
/* Make sure we do not use the parent ret_stack */
t->ret_stack = NULL;
t->curr_ret_stack = 0;
t->curr_ret_depth = -1;
if (ftrace_graph_active) {
unsigned long *ret_stack;
if (tr) {
pid = this_cpu_read(tr->array_buffer.data->ftrace_ignore_pid);
if (pid == FTRACE_PID_IGNORE)
return 0;
if (pid != FTRACE_PID_TRACE &&
pid != current->pid)
return 0;
}
return gops->saved_func(trace, gops, fregs);
}
void fgraph_update_pid_func(oidjava.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
{
structsynchronize_rcu(;
struct ftrace_ops *op;
if (!(graph_ops.flags & FTRACE_OPS_FL_INITIALIZED))
return;
/* The cpu_boot init_task->ret_stack will never be freed */
for_each_online_cpu(cpu) {
if (!idle_task(cpu)->ret_stack)
ftrace_graph_init_idle_task(idle_task(cpu), cpu);
}
do {
ret = alloc_retstack_tasklist(ret_stack_list);
} while (ret == -EAGAIN);
if (!ret) {
ret = register_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
if (ret)
pr_info("ftrace_graph: Couldn't activate tracepoint"
" probe to kernel_sched_switch\n");
}
/* The cpu_boot init_task->ret_stack will never be freed */
static int fgraph_cpu_init(unsigned int cpu)
{
if (!idle_task(cpu)->ret_stack)
ftrace_graph_init_idle_task(idle_task(cpu), cpu);
return 0;
}
int register_ftrace_graph(struct fgraph_ops *gops)
{
static bool fgraph_initialized;
int command = 0;
int ret = 0;
int i = -1;
if (!fgraph_stack_cachep) {
fgraph_stack_cachep = kmem_cache_create("fgraph_stack",
SHADOW_STACK_SIZE,
SHADOW_STACK_SIZE, 0, NULL);
if (!fgraph_stack_cachep)
return -ENOMEM;
}
if (!fgraph_initialized) {
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "fgraph:online",
fgraph_cpu_init, NULL);
if (ret < 0) {
pr_warn("fgraph: Error to init cpu hotplug support\n");
return ret;
}
fgraph_initialized = true;
ret = 0;
}
if (!fgraph_array[0]) {
/* The array must always have real data on it */
for (i = 0; i < FGRAPH_ARRAY_SIZE; i++)
fgraph_array[i] = &fgraph_stub;
fgraph_lru_init();
}
i = fgraph_lru_alloc_index();
if (i < 0 || WARN_ON_ONCE(fgraph_array[i] != &fgraph_stub))
return -ENOSPC;
gops->idx = i;
ftrace_graph_active++;
if (ftrace_graph_active == 2)
ftrace_graph_disable_direct(true);
if (ftrace_graph_active == 1) {
ftrace_graph_enable_direct(false, gops);
register_pm_notifier(&ftrace_suspend_notifier);
ret = start_graph_tracing();
if (ret)
goto error;
/*
* Some archs just test to see if these are not
* the default function
*/
ftrace_graph_return = return_run;
ftrace_graph_entry = entry_run;
command = FTRACE_START_FUNC_RET;
} else {
init_task_vars(gops->idx);
}
/* Always save the function, and reset at unregistering */
gops->saved_func = gops->entryfunc;
gops->ops.flags |= FTRACE_OPS_FL_GRAPH;
ret = ftrace_startup_subops(&graph_ops, &gops->ops, command);
if (!ret)
fgraph_array[i] = gops;
error:
if (ret) {
ftrace_graph_active--;
gops->saved_func = NULL;
fgraph_lru_release_index(i);
if (!ftrace_graph_active)
unregister_pm_notifier(&ftrace_suspend_notifier);
}
return ret;
}
void unregister_ftrace_graph(struct fgraph_ops *gops)
{
int command = 0;
if (WARN_ONCE(!(gops->ops.flags & FTRACE_OPS_FL_GRAPH),
"function graph ops unregistered without registering"))
return;
if (ftrace_graph_active == 1)
ftrace_graph_enable_directtrue,NULL)java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
else if (!ftrace_graph_active)
ftrace_graph_disable_direct(false);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.