forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
um: Add support for CONFIG_STACKTRACE
Add stacktrace support for User Mode Linux Signed-off-by: Daniel Walter <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
- Loading branch information
1 parent
2a23612
commit 970e51f
Showing
5 changed files
with
142 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#ifndef _ASM_UML_STACKTRACE_H | ||
#define _ASM_UML_STACKTRACE_H | ||
|
||
#include <linux/uaccess.h> | ||
#include <linux/ptrace.h> | ||
|
||
struct stack_frame { | ||
struct stack_frame *next_frame; | ||
unsigned long return_address; | ||
}; | ||
|
||
struct stacktrace_ops { | ||
void (*address)(void *data, unsigned long address, int reliable); | ||
}; | ||
|
||
#ifdef CONFIG_FRAME_POINTER | ||
static inline unsigned long | ||
get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs) | ||
{ | ||
if (!task || task == current) | ||
return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); | ||
return KSTK_EBP(task); | ||
} | ||
#else | ||
static inline unsigned long | ||
get_frame_pointer(struct task_struct *task, struct pt_regs *segv_regs) | ||
{ | ||
return 0; | ||
} | ||
#endif | ||
|
||
static inline unsigned long | ||
*get_stack_pointer(struct task_struct *task, struct pt_regs *segv_regs) | ||
{ | ||
if (!task || task == current) | ||
return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); | ||
return (unsigned long *)KSTK_ESP(task); | ||
} | ||
|
||
void dump_trace(struct task_struct *tsk, const struct stacktrace_ops *ops, void *data); | ||
|
||
#endif /* _ASM_UML_STACKTRACE_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
* Copyright (C) 2013 Richard Weinberger <[email protected]> | ||
* Copyright (C) 2014 Google Inc., Author: Daniel Walter <[email protected]> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/kallsyms.h> | ||
#include <linux/kernel.h> | ||
#include <linux/sched.h> | ||
#include <linux/stacktrace.h> | ||
#include <linux/module.h> | ||
#include <linux/uaccess.h> | ||
#include <asm/stacktrace.h> | ||
|
||
void dump_trace(struct task_struct *tsk, | ||
const struct stacktrace_ops *ops, | ||
void *data) | ||
{ | ||
int reliable = 0; | ||
unsigned long *sp, bp, addr; | ||
struct pt_regs *segv_regs = tsk->thread.segv_regs; | ||
struct stack_frame *frame; | ||
|
||
bp = get_frame_pointer(tsk, segv_regs); | ||
sp = get_stack_pointer(tsk, segv_regs); | ||
|
||
frame = (struct stack_frame *)bp; | ||
while (((long) sp & (THREAD_SIZE-1)) != 0) { | ||
addr = *sp; | ||
if (__kernel_text_address(addr)) { | ||
reliable = 0; | ||
if ((unsigned long) sp == bp + sizeof(long)) { | ||
frame = frame ? frame->next_frame : NULL; | ||
bp = (unsigned long)frame; | ||
reliable = 1; | ||
} | ||
ops->address(data, addr, reliable); | ||
} | ||
sp++; | ||
} | ||
} | ||
|
||
static void save_addr(void *data, unsigned long address, int reliable) | ||
{ | ||
struct stack_trace *trace = data; | ||
|
||
if (!reliable) | ||
return; | ||
if (trace->nr_entries >= trace->max_entries) | ||
return; | ||
|
||
trace->entries[trace->nr_entries++] = address; | ||
} | ||
|
||
static const struct stacktrace_ops dump_ops = { | ||
.address = save_addr | ||
}; | ||
|
||
static void __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace) | ||
{ | ||
dump_trace(tsk, &dump_ops, trace); | ||
if (trace->nr_entries < trace->max_entries) | ||
trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
} | ||
|
||
void save_stack_trace(struct stack_trace *trace) | ||
{ | ||
__save_stack_trace(current, trace); | ||
} | ||
EXPORT_SYMBOL_GPL(save_stack_trace); | ||
|
||
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | ||
{ | ||
__save_stack_trace(tsk, trace); | ||
} | ||
EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters