aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/Makefile1
-rw-r--r--arch/um/kernel/physmem.c32
-rw-r--r--arch/um/kernel/ptrace.c3
-rw-r--r--arch/um/kernel/stacktrace.c80
-rw-r--r--arch/um/kernel/sysrq.c69
-rw-r--r--arch/um/kernel/um_arch.c7
6 files changed, 106 insertions, 86 deletions
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index d8b78a03855c..2d840a070c8b 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o
obj-$(CONFIG_GCOV) += gmon_syms.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
USER_OBJS := config.o
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 30fdd5d0067b..549ecf3f5857 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -22,39 +22,19 @@ EXPORT_SYMBOL(high_physmem);
extern unsigned long long physmem_size;
-int __init init_maps(unsigned long physmem, unsigned long iomem,
+void __init mem_total_pages(unsigned long physmem, unsigned long iomem,
unsigned long highmem)
{
- struct page *p, *map;
- unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
- unsigned long iomem_len, iomem_pages, total_len, total_pages;
- int i;
-
- phys_pages = physmem >> PAGE_SHIFT;
- phys_len = phys_pages * sizeof(struct page);
-
- iomem_pages = iomem >> PAGE_SHIFT;
- iomem_len = iomem_pages * sizeof(struct page);
+ unsigned long phys_pages, highmem_pages;
+ unsigned long iomem_pages, total_pages;
+ phys_pages = physmem >> PAGE_SHIFT;
+ iomem_pages = iomem >> PAGE_SHIFT;
highmem_pages = highmem >> PAGE_SHIFT;
- highmem_len = highmem_pages * sizeof(struct page);
-
- total_pages = phys_pages + iomem_pages + highmem_pages;
- total_len = phys_len + iomem_len + highmem_len;
- map = alloc_bootmem_low_pages(total_len);
- if (map == NULL)
- return -ENOMEM;
-
- for (i = 0; i < total_pages; i++) {
- p = &map[i];
- memset(p, 0, sizeof(struct page));
- SetPageReserved(p);
- INIT_LIST_HEAD(&p->lru);
- }
+ total_pages = phys_pages + iomem_pages + highmem_pages;
max_mapnr = total_pages;
- return 0;
}
void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index 694d551c8899..62435ef003d9 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -165,8 +165,7 @@ static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs,
*/
void syscall_trace_enter(struct pt_regs *regs)
{
- audit_syscall_entry(HOST_AUDIT_ARCH,
- UPT_SYSCALL_NR(&regs->regs),
+ audit_syscall_entry(UPT_SYSCALL_NR(&regs->regs),
UPT_SYSCALL_ARG1(&regs->regs),
UPT_SYSCALL_ARG2(&regs->regs),
UPT_SYSCALL_ARG3(&regs->regs),
diff --git a/arch/um/kernel/stacktrace.c b/arch/um/kernel/stacktrace.c
new file mode 100644
index 000000000000..ebe7bcf62684
--- /dev/null
+++ b/arch/um/kernel/stacktrace.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2013 Richard Weinberger <richard@nod.at>
+ * Copyright (C) 2014 Google Inc., Author: Daniel Walter <dwalter@google.com>
+ *
+ * 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);
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index 799d7e413bf5..894c8d303cda 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -12,57 +12,20 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/sysrq.h>
+#include <asm/stacktrace.h>
#include <os.h>
-struct stack_frame {
- struct stack_frame *next_frame;
- unsigned long return_address;
-};
-
-static void do_stack_trace(unsigned long *sp, unsigned long bp)
+static void _print_addr(void *data, unsigned long address, int reliable)
{
- int reliable;
- unsigned long addr;
- struct stack_frame *frame = (struct stack_frame *)bp;
-
- printk(KERN_INFO "Call Trace:\n");
- 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;
- }
-
- printk(KERN_INFO " [<%08lx>]", addr);
- printk(KERN_CONT " %s", reliable ? "" : "? ");
- print_symbol(KERN_CONT "%s", addr);
- printk(KERN_CONT "\n");
- }
- sp++;
- }
- printk(KERN_INFO "\n");
+ pr_info(" [<%08lx>]", address);
+ pr_cont(" %s", reliable ? "" : "? ");
+ print_symbol("%s", address);
+ pr_cont("\n");
}
-static 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();
- else
- return KSTK_EBP(task);
-}
-
-static 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();
- else
- return (unsigned long *)KSTK_ESP(task);
-}
+static const struct stacktrace_ops stackops = {
+ .address = _print_addr
+};
void show_stack(struct task_struct *task, unsigned long *stack)
{
@@ -71,7 +34,7 @@ void show_stack(struct task_struct *task, unsigned long *stack)
int i;
if (!segv_regs && os_is_signal_stack()) {
- printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler,"
+ pr_err("Received SIGSEGV in SIGSEGV handler,"
" aborting stack trace!\n");
return;
}
@@ -83,16 +46,18 @@ void show_stack(struct task_struct *task, unsigned long *stack)
if (!stack)
sp = get_stack_pointer(task, segv_regs);
- printk(KERN_INFO "Stack:\n");
+ pr_info("Stack:\n");
stack = sp;
for (i = 0; i < 3 * STACKSLOTS_PER_LINE; i++) {
if (kstack_end(stack))
break;
if (i && ((i % STACKSLOTS_PER_LINE) == 0))
- printk(KERN_CONT "\n");
- printk(KERN_CONT " %08lx", *stack++);
+ pr_cont("\n");
+ pr_cont(" %08lx", *stack++);
}
- printk(KERN_CONT "\n");
+ pr_cont("\n");
- do_stack_trace(sp, bp);
+ pr_info("Call Trace:\n");
+ dump_trace(current, &stackops, NULL);
+ pr_info("\n");
}
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 016adf0985d5..9274eae6ae7b 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -348,12 +348,7 @@ int __init linux_main(int argc, char **argv)
start_vm = VMALLOC_START;
setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
- if (init_maps(physmem_size, iomem_size, highmem)) {
- printf("Failed to allocate mem_map for %Lu bytes of physical "
- "memory and %Lu bytes of highmem\n", physmem_size,
- highmem);
- exit(1);
- }
+ mem_total_pages(physmem_size, iomem_size, highmem);
virtmem_size = physmem_size;
stack = (unsigned long) argv;