Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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);