]> git.karo-electronics.de Git - linux-beck.git/commitdiff
sh: handle early calls to return_address() when using dwarf unwinder.
authorPaul Mundt <lethal@linux-sh.org>
Tue, 25 May 2010 07:16:40 +0000 (16:16 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Tue, 25 May 2010 07:16:40 +0000 (16:16 +0900)
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>
arch/sh/kernel/dwarf.c
arch/sh/kernel/return_address.c

index 886d7d83ace38912aa4966da50159d43686b0fde..49c09c7d5b77ce76b3351bf2174251756c7b9b41 100644 (file)
@@ -49,6 +49,8 @@ static DEFINE_SPINLOCK(dwarf_fde_lock);
 
 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
@@ -581,6 +583,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
        struct dwarf_reg *reg;
        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
@@ -1167,7 +1176,7 @@ void module_dwarf_cleanup(struct module *mod)
  */
 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 @@ static int __init dwarf_unwinder_init(void)
                                          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 @@ static int __init dwarf_unwinder_init(void)
        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);
index cbf1dd5372b2d223f399ab884fd46bfbd83246d1..5124aeb28c3f333d9b7ff7755d8f01e738a044d1 100644 (file)
@@ -24,6 +24,8 @@ void *return_address(unsigned int depth)
                struct dwarf_frame *tmp;
 
                tmp = dwarf_unwind_stack(ra, frame);
+               if (!tmp)
+                       return NULL;
 
                if (frame)
                        dwarf_free_frame(frame);