Commit 8a37f520 authored by Paul Mundt's avatar Paul Mundt

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: default avatarPaul Mundt <lethal@linux-sh.org>
parent e1f42ff4
...@@ -49,6 +49,8 @@ static DEFINE_SPINLOCK(dwarf_fde_lock); ...@@ -49,6 +49,8 @@ static DEFINE_SPINLOCK(dwarf_fde_lock);
static struct dwarf_cie *cached_cie; static struct dwarf_cie *cached_cie;
static unsigned int dwarf_unwinder_ready;
/** /**
* dwarf_frame_alloc_reg - allocate memory for a DWARF register * dwarf_frame_alloc_reg - allocate memory for a DWARF register
* @frame: the DWARF frame whose list of registers we insert on * @frame: the DWARF frame whose list of registers we insert on
...@@ -581,6 +583,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc, ...@@ -581,6 +583,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
struct dwarf_reg *reg; struct dwarf_reg *reg;
unsigned long addr; 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 * 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 * contents of a physical register to get the CFA in order to
...@@ -1167,7 +1176,7 @@ void module_dwarf_cleanup(struct module *mod) ...@@ -1167,7 +1176,7 @@ void module_dwarf_cleanup(struct module *mod)
*/ */
static int __init dwarf_unwinder_init(void) static int __init dwarf_unwinder_init(void)
{ {
int err; int err = -ENOMEM;
dwarf_frame_cachep = kmem_cache_create("dwarf_frames", dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
sizeof(struct dwarf_frame), 0, sizeof(struct dwarf_frame), 0,
...@@ -1181,11 +1190,15 @@ static int __init dwarf_unwinder_init(void) ...@@ -1181,11 +1190,15 @@ static int __init dwarf_unwinder_init(void)
mempool_alloc_slab, mempool_alloc_slab,
mempool_free_slab, mempool_free_slab,
dwarf_frame_cachep); dwarf_frame_cachep);
if (!dwarf_frame_pool)
goto out;
dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
mempool_alloc_slab, mempool_alloc_slab,
mempool_free_slab, mempool_free_slab,
dwarf_reg_cachep); dwarf_reg_cachep);
if (!dwarf_reg_pool)
goto out;
err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL); err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
if (err) if (err)
...@@ -1195,11 +1208,13 @@ static int __init dwarf_unwinder_init(void) ...@@ -1195,11 +1208,13 @@ static int __init dwarf_unwinder_init(void)
if (err) if (err)
goto out; goto out;
dwarf_unwinder_ready = 1;
return 0; return 0;
out: out:
printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err); printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err);
dwarf_unwinder_cleanup(); dwarf_unwinder_cleanup();
return -EINVAL; return err;
} }
early_initcall(dwarf_unwinder_init); early_initcall(dwarf_unwinder_init);
...@@ -24,6 +24,8 @@ void *return_address(unsigned int depth) ...@@ -24,6 +24,8 @@ void *return_address(unsigned int depth)
struct dwarf_frame *tmp; struct dwarf_frame *tmp;
tmp = dwarf_unwind_stack(ra, frame); tmp = dwarf_unwind_stack(ra, frame);
if (!tmp)
return NULL;
if (frame) if (frame)
dwarf_free_frame(frame); dwarf_free_frame(frame);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment