sh: handle early calls to return_address() when using dwarf unwinder.

The dwarf unwinder ties in to an early initcall, but it's possible that
return_address() calls will be made prior to that. This implements some
additional error handling in to the dwarf unwinder as well as an exit
path in the return_address() case to bail out if the unwinder hasn't come
up yet.

This fixes a NULL pointer deref in early boot when mempool_alloc() blows
up on the not-yet-ready mempool via dwarf_unwind_stack().

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c
index 886d7d8..49c09c7 100644
--- a/arch/sh/kernel/dwarf.c
+++ b/arch/sh/kernel/dwarf.c
@@ -49,6 +49,8 @@
 
 static struct dwarf_cie *cached_cie;
 
+static unsigned int dwarf_unwinder_ready;
+
 /**
  *	dwarf_frame_alloc_reg - allocate memory for a DWARF register
  *	@frame: the DWARF frame whose list of registers we insert on
@@ -582,6 +584,13 @@
 	unsigned long addr;
 
 	/*
+	 * If we've been called in to before initialization has
+	 * completed, bail out immediately.
+	 */
+	if (!dwarf_unwinder_ready)
+		return NULL;
+
+	/*
 	 * If we're starting at the top of the stack we need get the
 	 * contents of a physical register to get the CFA in order to
 	 * begin the virtual unwinding of the stack.
@@ -1167,7 +1176,7 @@
  */
 static int __init dwarf_unwinder_init(void)
 {
-	int err;
+	int err = -ENOMEM;
 
 	dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
 			sizeof(struct dwarf_frame), 0,
@@ -1181,11 +1190,15 @@
 					  mempool_alloc_slab,
 					  mempool_free_slab,
 					  dwarf_frame_cachep);
+	if (!dwarf_frame_pool)
+		goto out;
 
 	dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
 					 mempool_alloc_slab,
 					 mempool_free_slab,
 					 dwarf_reg_cachep);
+	if (!dwarf_reg_pool)
+		goto out;
 
 	err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
 	if (err)
@@ -1195,11 +1208,13 @@
 	if (err)
 		goto out;
 
+	dwarf_unwinder_ready = 1;
+
 	return 0;
 
 out:
 	printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err);
 	dwarf_unwinder_cleanup();
-	return -EINVAL;
+	return err;
 }
 early_initcall(dwarf_unwinder_init);
diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c
index cbf1dd5..5124aeb 100644
--- a/arch/sh/kernel/return_address.c
+++ b/arch/sh/kernel/return_address.c
@@ -24,6 +24,8 @@
 		struct dwarf_frame *tmp;
 
 		tmp = dwarf_unwind_stack(ra, frame);
+		if (!tmp)
+			return NULL;
 
 		if (frame)
 			dwarf_free_frame(frame);