aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-05-25 03:16:40 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-05-25 03:16:40 -0400
commit8a37f520523df971bd3f926d8bd45ead37e857e8 (patch)
tree762b79bb60c55ef320ec72fdf7c079fa14cb765b /arch
parente1f42ff4f06e5feaa57a22556ad977ef62164e14 (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/sh/kernel/dwarf.c19
-rw-r--r--arch/sh/kernel/return_address.c2
2 files changed, 19 insertions, 2 deletions
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);
49 49
50static struct dwarf_cie *cached_cie; 50static struct dwarf_cie *cached_cie;
51 51
52static unsigned int dwarf_unwinder_ready;
53
52/** 54/**
53 * dwarf_frame_alloc_reg - allocate memory for a DWARF register 55 * dwarf_frame_alloc_reg - allocate memory for a DWARF register
54 * @frame: the DWARF frame whose list of registers we insert on 56 * @frame: the DWARF frame whose list of registers we insert on
@@ -582,6 +584,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
582 unsigned long addr; 584 unsigned long addr;
583 585
584 /* 586 /*
587 * If we've been called in to before initialization has
588 * completed, bail out immediately.
589 */
590 if (!dwarf_unwinder_ready)
591 return NULL;
592
593 /*
585 * If we're starting at the top of the stack we need get the 594 * If we're starting at the top of the stack we need get the
586 * contents of a physical register to get the CFA in order to 595 * contents of a physical register to get the CFA in order to
587 * begin the virtual unwinding of the stack. 596 * begin the virtual unwinding of the stack.
@@ -1167,7 +1176,7 @@ void module_dwarf_cleanup(struct module *mod)
1167 */ 1176 */
1168static int __init dwarf_unwinder_init(void) 1177static int __init dwarf_unwinder_init(void)
1169{ 1178{
1170 int err; 1179 int err = -ENOMEM;
1171 1180
1172 dwarf_frame_cachep = kmem_cache_create("dwarf_frames", 1181 dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
1173 sizeof(struct dwarf_frame), 0, 1182 sizeof(struct dwarf_frame), 0,
@@ -1181,11 +1190,15 @@ static int __init dwarf_unwinder_init(void)
1181 mempool_alloc_slab, 1190 mempool_alloc_slab,
1182 mempool_free_slab, 1191 mempool_free_slab,
1183 dwarf_frame_cachep); 1192 dwarf_frame_cachep);
1193 if (!dwarf_frame_pool)
1194 goto out;
1184 1195
1185 dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, 1196 dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
1186 mempool_alloc_slab, 1197 mempool_alloc_slab,
1187 mempool_free_slab, 1198 mempool_free_slab,
1188 dwarf_reg_cachep); 1199 dwarf_reg_cachep);
1200 if (!dwarf_reg_pool)
1201 goto out;
1189 1202
1190 err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL); 1203 err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
1191 if (err) 1204 if (err)
@@ -1195,11 +1208,13 @@ static int __init dwarf_unwinder_init(void)
1195 if (err) 1208 if (err)
1196 goto out; 1209 goto out;
1197 1210
1211 dwarf_unwinder_ready = 1;
1212
1198 return 0; 1213 return 0;
1199 1214
1200out: 1215out:
1201 printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err); 1216 printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err);
1202 dwarf_unwinder_cleanup(); 1217 dwarf_unwinder_cleanup();
1203 return -EINVAL; 1218 return err;
1204} 1219}
1205early_initcall(dwarf_unwinder_init); 1220early_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)
24 struct dwarf_frame *tmp; 24 struct dwarf_frame *tmp;
25 25
26 tmp = dwarf_unwind_stack(ra, frame); 26 tmp = dwarf_unwind_stack(ra, frame);
27 if (!tmp)
28 return NULL;
27 29
28 if (frame) 30 if (frame)
29 dwarf_free_frame(frame); 31 dwarf_free_frame(frame);