mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 20:51:03 +02:00
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>
This commit is contained in:
@@ -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,
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user