2018-12-28 00:32:24 -08:00
// SPDX-License-Identifier: GPL-2.0
2009-08-07 16:11:19 +01:00
/*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
* Copyright ( C ) 2000 , 2001 , 2002 Andi Kleen , SuSE Labs
* Copyright ( C ) 2009 Matt Fleming
2012-05-24 15:03:46 +09:00
* Copyright ( C ) 2002 - 2012 Paul Mundt
2009-08-07 16:11:19 +01:00
*/
# include <linux/kallsyms.h>
# include <linux/ftrace.h>
# include <linux/debug_locks.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>
2012-05-24 15:03:46 +09:00
# include <linux/kdebug.h>
# include <linux/export.h>
# include <linux/uaccess.h>
2009-08-11 22:43:20 +01:00
# include <asm/unwinder.h>
2009-08-07 16:11:19 +01:00
# include <asm/stacktrace.h>
2020-06-17 16:36:35 +02:00
void dump_mem ( const char * str , const char * loglvl , unsigned long bottom ,
unsigned long top )
2012-05-24 15:03:46 +09:00
{
unsigned long p ;
int i ;
2020-06-08 21:31:24 -07:00
printk ( " %s%s(0x%08lx to 0x%08lx) \n " , loglvl , str , bottom , top ) ;
2012-05-24 15:03:46 +09:00
for ( p = bottom & ~ 31 ; p < top ; ) {
2020-06-08 21:31:24 -07:00
printk ( " %s%04lx: " , loglvl , p & 0xffff ) ;
2012-05-24 15:03:46 +09:00
for ( i = 0 ; i < 8 ; i + + , p + = 4 ) {
unsigned int val ;
if ( p < bottom | | p > = top )
2020-06-17 16:36:35 +02:00
pr_cont ( " " ) ;
2012-05-24 15:03:46 +09:00
else {
if ( __get_user ( val , ( unsigned int __user * ) p ) ) {
2020-06-17 16:36:35 +02:00
pr_cont ( " \n " ) ;
2012-05-24 15:03:46 +09:00
return ;
}
2020-06-17 16:36:35 +02:00
pr_cont ( " %08x " , val ) ;
2012-05-24 15:03:46 +09:00
}
}
2020-06-17 16:36:35 +02:00
pr_cont ( " \n " ) ;
2012-05-24 15:03:46 +09:00
}
}
2020-06-17 16:36:32 +02:00
void printk_address ( unsigned long address , int reliable )
2009-08-07 16:11:19 +01:00
{
2020-06-17 16:36:35 +02:00
pr_cont ( " [<%px>] %s%pS \n " , ( void * ) address ,
reliable ? " " : " ? " , ( void * ) address ) ;
2009-08-07 16:11:19 +01:00
}
# 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 ;
2018-12-07 13:06:04 -05:00
struct ftrace_ret_stack * ret_stack ;
2009-08-07 16:11:19 +01:00
unsigned long ret_addr ;
if ( addr ! = ( unsigned long ) return_to_handler )
return ;
2018-12-07 13:06:04 -05:00
if ( ! task - > ret_stack )
2009-08-07 16:11:19 +01:00
return ;
2018-12-07 13:06:04 -05:00
ret_stack = ftrace_graph_get_ret_stack ( task , * graph ) ;
if ( ! ret_stack )
return ;
ret_addr = ret_stack - > ret ;
2009-08-07 16:11:19 +01:00
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
2009-08-11 22:43:20 +01:00
void
stack_reader_dump ( struct task_struct * task , struct pt_regs * regs ,
unsigned long * sp , const struct stacktrace_ops * ops ,
void * data )
2009-08-07 16:11:19 +01:00
{
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 ) ) {
2009-08-15 01:09:03 +09:00
ops - > address ( data , addr , 1 ) ;
2009-08-07 16:11:19 +01:00
print_ftrace_graph_addr ( addr , data , ops ,
context , & graph ) ;
}
}
}
/*
* Print one address / symbol entries per line .
*/
static void print_trace_address ( void * data , unsigned long addr , int reliable )
{
2020-06-17 16:36:33 +02:00
printk ( " %s " , ( char * ) data ) ;
2020-06-17 16:36:32 +02:00
printk_address ( addr , reliable ) ;
2009-08-07 16:11:19 +01:00
}
static const struct stacktrace_ops print_trace_ops = {
. address = print_trace_address ,
} ;
void show_trace ( struct task_struct * tsk , unsigned long * sp ,
2020-06-08 21:31:33 -07:00
struct pt_regs * regs , const char * loglvl )
2009-08-07 16:11:19 +01:00
{
if ( regs & & user_mode ( regs ) )
return ;
2020-06-08 21:31:33 -07:00
printk ( " %s \n Call trace: \n " , loglvl ) ;
2009-08-07 16:11:19 +01:00
2020-06-08 21:31:33 -07:00
unwind_stack ( tsk , regs , sp , & print_trace_ops , ( void * ) loglvl ) ;
2009-08-07 16:11:19 +01:00
2020-06-17 16:36:35 +02:00
pr_cont ( " \n " ) ;
2009-08-07 16:11:19 +01:00
if ( ! tsk )
tsk = current ;
debug_show_held_locks ( tsk ) ;
}
2012-05-24 15:03:46 +09:00
2020-06-08 21:32:29 -07:00
void show_stack ( struct task_struct * tsk , unsigned long * sp , const char * loglvl )
2012-05-24 15:03:46 +09:00
{
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 ;
2020-06-08 21:31:36 -07:00
dump_mem ( " Stack: " , loglvl , stack , THREAD_SIZE +
2012-05-24 15:03:46 +09:00
( unsigned long ) task_stack_page ( tsk ) ) ;
2020-06-08 21:31:36 -07:00
show_trace ( tsk , sp , NULL , loglvl ) ;
}