mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	LoongArch: Add USER_STACKTRACE support
To get the best stacktrace output, you can compile your userspace
programs with frame pointers (at least glibc + the app you are tracing).
1, export "CC = gcc -fno-omit-frame-pointer";
2, compile your programs with "CC";
3, use uprobe to get stacktrace output.
...
     echo 'p:malloc /usr/lib64/libc.so.6:0x0a4704 size=%r4:u64' > uprobe_events
     echo 'p:free /usr/lib64/libc.so.6:0x0a4d50 ptr=%r4:x64' >> uprobe_events
     echo 'comm == "demo"' > ./events/uprobes/malloc/filter
     echo 'comm == "demo"' > ./events/uprobes/free/filter
     echo 1 > ./options/userstacktrace
     echo 1 > ./options/sym-userobj
...
Signed-off-by: Qing Zhang <zhangqing@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
			
			
This commit is contained in:
		
							parent
							
								
									93a4fa622e
								
							
						
					
					
						commit
						4d7bf939df
					
				
					 3 changed files with 47 additions and 0 deletions
				
			
		| 
						 | 
					@ -119,6 +119,7 @@ config LOONGARCH
 | 
				
			||||||
	select SWIOTLB
 | 
						select SWIOTLB
 | 
				
			||||||
	select TRACE_IRQFLAGS_SUPPORT
 | 
						select TRACE_IRQFLAGS_SUPPORT
 | 
				
			||||||
	select USE_PERCPU_NUMA_NODE_ID
 | 
						select USE_PERCPU_NUMA_NODE_ID
 | 
				
			||||||
 | 
						select USER_STACKTRACE_SUPPORT
 | 
				
			||||||
	select ZONE_DMA32
 | 
						select ZONE_DMA32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config 32BIT
 | 
					config 32BIT
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,11 @@ struct stack_info {
 | 
				
			||||||
	unsigned long begin, end, next_sp;
 | 
						unsigned long begin, end, next_sp;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct stack_frame {
 | 
				
			||||||
 | 
						unsigned long	fp;
 | 
				
			||||||
 | 
						unsigned long	ra;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool in_irq_stack(unsigned long stack, struct stack_info *info);
 | 
					bool in_irq_stack(unsigned long stack, struct stack_info *info);
 | 
				
			||||||
bool in_task_stack(unsigned long stack, struct task_struct *task, struct stack_info *info);
 | 
					bool in_task_stack(unsigned long stack, struct task_struct *task, struct stack_info *info);
 | 
				
			||||||
int get_stack_info(unsigned long stack, struct task_struct *task, struct stack_info *info);
 | 
					int get_stack_info(unsigned long stack, struct task_struct *task, struct stack_info *info);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
#include <linux/stacktrace.h>
 | 
					#include <linux/stacktrace.h>
 | 
				
			||||||
 | 
					#include <linux/uaccess.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/stacktrace.h>
 | 
					#include <asm/stacktrace.h>
 | 
				
			||||||
#include <asm/unwind.h>
 | 
					#include <asm/unwind.h>
 | 
				
			||||||
| 
						 | 
					@ -35,3 +36,43 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					copy_stack_frame(unsigned long fp, struct stack_frame *frame)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret = 1;
 | 
				
			||||||
 | 
						unsigned long err;
 | 
				
			||||||
 | 
						unsigned long __user *user_frame_tail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user_frame_tail = (unsigned long *)(fp - sizeof(struct stack_frame));
 | 
				
			||||||
 | 
						if (!access_ok(user_frame_tail, sizeof(*frame)))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pagefault_disable();
 | 
				
			||||||
 | 
						err = (__copy_from_user_inatomic(frame, user_frame_tail, sizeof(*frame)));
 | 
				
			||||||
 | 
						if (err || (unsigned long)user_frame_tail >= frame->fp)
 | 
				
			||||||
 | 
							ret = 0;
 | 
				
			||||||
 | 
						pagefault_enable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
 | 
				
			||||||
 | 
								  const struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long fp = regs->regs[22];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (fp && !((unsigned long)fp & 0xf)) {
 | 
				
			||||||
 | 
							struct stack_frame frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							frame.fp = 0;
 | 
				
			||||||
 | 
							frame.ra = 0;
 | 
				
			||||||
 | 
							if (!copy_stack_frame(fp, &frame))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (!frame.ra)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (!consume_entry(cookie, frame.ra))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							fp = frame.fp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue