if (frame_count++ == max_frames) break; if (state.reliable && !addr) {
kunit_err(current_test, "unwind state reliable but addr is 0\n");
ret = -EINVAL; break;
}
sprint_symbol(sym, addr); if (bt_pos < BT_BUF_SIZE) {
bt_pos += snprintf(bt + bt_pos, BT_BUF_SIZE - bt_pos,
state.reliable ? " [%-7s%px] %pSR\n" : "([%-7s%px] %pSR)\n",
stack_type_name(state.stack_info.type),
(void *)state.sp, (void *)state.ip); if (bt_pos >= BT_BUF_SIZE)
kunit_err(current_test, "backtrace buffer is too small\n");
}
frame_count += 1; if (prev_is_func2 && str_has_prefix(sym, "unwindme_func1"))
seen_func2_func1 = 1;
prev_is_func2 = str_has_prefix(sym, "unwindme_func2"); if (str_has_prefix(sym, "arch_rethook_trampoline+0x0/"))
seen_arch_rethook_trampoline = 1;
}
/* Check the results. */ if (unwind_error(&state)) {
kunit_err(current_test, "unwind error\n");
ret = -EINVAL;
} if (!seen_func2_func1) {
kunit_err(current_test, "unwindme_func2 and unwindme_func1 not found\n");
ret = -EINVAL;
} if (frame_count == max_frames) {
kunit_err(current_test, "Maximum number of frames exceeded\n");
ret = -EINVAL;
} if (seen_arch_rethook_trampoline) {
kunit_err(current_test, "arch_rethook_trampoline+0x0 in unwinding results\n");
ret = -EINVAL;
} if (ret || force_bt)
print_backtrace(bt);
kfree(bt); return ret;
}
/* State of the task being unwound. */ struct unwindme { int flags; int ret; struct task_struct *task; struct completion task_ready;
wait_queue_head_t task_wq; unsignedlong sp;
};
staticstruct unwindme *unwindme;
/* Values of unwindme.flags. */ #define UWM_DEFAULT 0x0 #define UWM_THREAD 0x1 /* Unwind a separate task. */ #define UWM_REGS 0x2 /* Pass regs to test_unwind(). */ #define UWM_SP 0x4 /* Pass sp to test_unwind(). */ #define UWM_CALLER 0x8 /* Unwind starting from caller. */ #define UWM_SWITCH_STACK 0x10 /* Use call_on_stack. */ #define UWM_IRQ 0x20 /* Unwind from irq context. */ #define UWM_PGM 0x40 /* Unwind from program check handler */ #define UWM_KPROBE_ON_FTRACE 0x80 /* Unwind from kprobe handler called via ftrace. */ #define UWM_FTRACE 0x100 /* Unwind from ftrace handler. */ #define UWM_KRETPROBE 0x200 /* Unwind through kretprobed function. */ #define UWM_KRETPROBE_HANDLER 0x400 /* Unwind from kretprobe handler. */
ret = ftrace_set_filter_ip(fops, (unsignedlong)test_unwind_ftraced_func, 0, 0); if (ret) {
kunit_err(current_test, "failed to set ftrace filter (%d)\n", ret); return -1;
}
ret = register_ftrace_function(fops); if (!ret) {
ret = test_unwind_ftraced_func(u);
unregister_ftrace_function(fops);
} else {
kunit_err(current_test, "failed to register ftrace handler (%d)\n", ret);
}
/* This function may or may not appear in the backtrace. */ static noinline int unwindme_func3(struct unwindme *u)
{
u->sp = current_frame_address(); return unwindme_func4(u);
}
/* This function must appear in the backtrace. */ static noinline int unwindme_func2(struct unwindme *u)
{ unsignedlong flags, mflags; int rc;
/* This function must follow unwindme_func2 in the backtrace. */ static noinline int unwindme_func1(void *u)
{ return unwindme_func2((struct unwindme *)u);
}
/* * Start the task and wait until it reaches unwindme_func4() and sleeps * in (task_ready, unwind_done] range.
*/
task = kthread_run(unwindme_func1, u, "%s", __func__); if (IS_ERR(task)) {
kunit_err(current_test, "kthread_run() failed\n"); return PTR_ERR(task);
} /* * Make sure task reaches unwindme_func4 before parking it, * we might park it before kthread function has been executed otherwise
*/
wait_for_completion(&u->task_ready);
kthread_park(task); /* Unwind. */
ret = test_unwind(task, NULL, (u->flags & UWM_SP) ? u->sp : 0);
kthread_stop(task); return ret;
}
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.