From: Paul Mundt Date: Tue, 25 May 2010 07:16:40 +0000 (+0900) Subject: sh: handle early calls to return_address() when using dwarf unwinder. X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=8a37f520523df971bd3f926d8bd45ead37e857e8;p=linux-beck.git 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 --- diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 886d7d83ace3..49c09c7d5b77 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c @@ -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); diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c index cbf1dd5372b2..5124aeb28c3f 100644 --- a/arch/sh/kernel/return_address.c +++ b/arch/sh/kernel/return_address.c @@ -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);