2006-07-03 00:24:40 -07:00
/*
* Stack trace management functions
*
2009-01-31 02:03:42 +01:00
* Copyright ( C ) 2006 - 2009 Red Hat , Inc . , Ingo Molnar < mingo @ redhat . com >
2006-07-03 00:24:40 -07:00
*/
# include <linux/sched.h>
2017-02-08 18:51:35 +01:00
# include <linux/sched/debug.h>
2017-02-08 18:51:37 +01:00
# include <linux/sched/task_stack.h>
2006-07-03 00:24:40 -07:00
# include <linux/stacktrace.h>
2016-07-13 20:18:56 -04:00
# include <linux/export.h>
2008-11-22 13:28:47 +02:00
# include <linux/uaccess.h>
2006-09-26 10:52:34 +02:00
# include <asm/stacktrace.h>
2016-09-16 14:18:14 -05:00
# include <asm/unwind.h>
2006-07-03 00:24:40 -07:00
2019-04-25 11:45:22 +02:00
void arch_stack_walk ( stack_trace_consume_fn consume_entry , void * cookie ,
struct task_struct * task , struct pt_regs * regs )
2008-01-25 21:08:34 +01:00
{
2016-09-16 14:18:14 -05:00
struct unwind_state state ;
unsigned long addr ;
2008-01-25 21:08:34 +01:00
2020-09-14 16:34:07 +01:00
if ( regs & & ! consume_entry ( cookie , regs - > ip ) )
2019-04-25 11:45:22 +02:00
return ;
2006-07-03 00:24:40 -07:00
2016-09-16 14:18:14 -05:00
for ( unwind_start ( & state , task , regs , NULL ) ; ! unwind_done ( & state ) ;
unwind_next_frame ( & state ) ) {
addr = unwind_get_return_address ( & state ) ;
2020-09-14 16:34:07 +01:00
if ( ! addr | | ! consume_entry ( cookie , addr ) )
2016-09-16 14:18:14 -05:00
break ;
}
}
2008-01-25 21:08:34 +01:00
2019-04-25 11:45:22 +02:00
int arch_stack_walk_reliable ( stack_trace_consume_fn consume_entry ,
void * cookie , struct task_struct * task )
2017-02-13 19:42:28 -06:00
{
struct unwind_state state ;
struct pt_regs * regs ;
unsigned long addr ;
2018-05-18 08:47:10 +02:00
for ( unwind_start ( & state , task , NULL , NULL ) ;
! unwind_done ( & state ) & & ! unwind_error ( & state ) ;
2017-02-13 19:42:28 -06:00
unwind_next_frame ( & state ) ) {
2017-12-31 10:18:06 -06:00
regs = unwind_get_entry_regs ( & state , NULL ) ;
2017-02-13 19:42:28 -06:00
if ( regs ) {
2018-05-18 08:47:10 +02:00
/* Success path for user tasks */
if ( user_mode ( regs ) )
2019-04-10 12:27:56 +02:00
return 0 ;
2018-05-18 08:47:10 +02:00
2017-02-13 19:42:28 -06:00
/*
* Kernel mode registers on the stack indicate an
* in - kernel interrupt or exception ( e . g . , preemption
* or a page fault ) , which can make frame pointers
* unreliable .
*/
2018-05-18 08:47:11 +02:00
if ( IS_ENABLED ( CONFIG_FRAME_POINTER ) )
return - EINVAL ;
2017-02-13 19:42:28 -06:00
}
addr = unwind_get_return_address ( & state ) ;
/*
* A NULL or invalid return address probably means there ' s some
* generated code which __kernel_text_address ( ) doesn ' t know
* about .
*/
2018-05-18 08:47:09 +02:00
if ( ! addr )
2017-02-13 19:42:28 -06:00
return - EINVAL ;
2020-09-14 16:34:07 +01:00
if ( ! consume_entry ( cookie , addr ) )
2017-02-13 19:42:28 -06:00
return - EINVAL ;
}
/* Check for stack corruption */
2018-05-18 08:47:09 +02:00
if ( unwind_error ( & state ) )
2017-02-13 19:42:28 -06:00
return - EINVAL ;
return 0 ;
}
2008-11-22 13:28:47 +02:00
/* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */
2010-05-19 21:35:17 +02:00
struct stack_frame_user {
2008-11-22 13:28:47 +02:00
const void __user * next_fp ;
2008-11-23 12:39:06 +02:00
unsigned long ret_addr ;
2008-11-22 13:28:47 +02:00
} ;
2010-05-19 21:35:17 +02:00
static int
2020-02-15 11:28:09 -05:00
copy_stack_frame ( const struct stack_frame_user __user * fp ,
struct stack_frame_user * frame )
2008-11-22 13:28:47 +02:00
{
int ret ;
2022-02-15 09:15:57 +01:00
if ( ! __access_ok ( fp , sizeof ( * frame ) ) )
2008-11-22 13:28:47 +02:00
return 0 ;
ret = 1 ;
pagefault_disable ( ) ;
2020-02-15 11:28:09 -05:00
if ( __get_user ( frame - > next_fp , & fp - > next_fp ) | |
__get_user ( frame - > ret_addr , & fp - > ret_addr ) )
2008-11-22 13:28:47 +02:00
ret = 0 ;
pagefault_enable ( ) ;
return ret ;
}
2019-04-25 11:45:22 +02:00
void arch_stack_walk_user ( stack_trace_consume_fn consume_entry , void * cookie ,
const struct pt_regs * regs )
2008-11-23 12:39:06 +02:00
{
const void __user * fp = ( const void __user * ) regs - > bp ;
2020-09-14 16:34:07 +01:00
if ( ! consume_entry ( cookie , regs - > ip ) )
2019-04-25 11:45:22 +02:00
return ;
2008-11-23 12:39:06 +02:00
2019-04-25 11:45:22 +02:00
while ( 1 ) {
2010-05-19 21:35:17 +02:00
struct stack_frame_user frame ;
2008-11-23 12:39:06 +02:00
frame . next_fp = NULL ;
frame . ret_addr = 0 ;
if ( ! copy_stack_frame ( fp , & frame ) )
break ;
if ( ( unsigned long ) fp < regs - > sp )
break ;
2019-07-11 11:35:01 +09:00
if ( ! frame . ret_addr )
break ;
2020-09-14 16:34:07 +01:00
if ( ! consume_entry ( cookie , frame . ret_addr ) )
2008-11-23 12:39:06 +02:00
break ;
fp = frame . next_fp ;
}
}