X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fparisc%2Fkernel%2Funwind.c;h=cc1c1afc31878cb2845677b64a21e58a497f99d3;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=5e1e1152008220c3aa9adf7a306218b43b0e91ef;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index 5e1e11520..cc1c1afc3 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c @@ -35,9 +35,8 @@ static spinlock_t unwind_lock; * we can call unwind_init as early in the bootup process as * possible (before the slab allocator is initialized) */ -static struct unwind_table kernel_unwind_table; -static struct unwind_table *unwind_tables, *unwind_tables_end; - +static struct unwind_table kernel_unwind_table __read_mostly; +static LIST_HEAD(unwind_tables); static inline const struct unwind_table_entry * find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr) @@ -65,14 +64,14 @@ find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr) static const struct unwind_table_entry * find_unwind_entry(unsigned long addr) { - struct unwind_table *table = unwind_tables; + struct unwind_table *table; const struct unwind_table_entry *e = NULL; if (addr >= kernel_unwind_table.start && addr <= kernel_unwind_table.end) e = find_unwind_entry_in_table(&kernel_unwind_table, addr); - else - for (; table; table = table->next) { + else + list_for_each_entry(table, &unwind_tables, list) { if (addr >= table->start && addr <= table->end) e = find_unwind_entry_in_table(table, addr); @@ -99,7 +98,7 @@ unwind_table_init(struct unwind_table *table, const char *name, table->end = base_addr + end->region_end; table->table = (struct unwind_table_entry *)table_start; table->length = end - start + 1; - table->next = NULL; + INIT_LIST_HEAD(&table->list); for (; start <= end; start++) { if (start < end && @@ -112,33 +111,60 @@ unwind_table_init(struct unwind_table *table, const char *name, } } -void * +static void +unwind_table_sort(struct unwind_table_entry *start, + struct unwind_table_entry *finish) +{ + struct unwind_table_entry el, *p, *q; + + for (p = start + 1; p < finish; ++p) { + if (p[0].region_start < p[-1].region_start) { + el = *p; + q = p; + do { + q[0] = q[-1]; + --q; + } while (q > start && + el.region_start < q[-1].region_start); + *q = el; + } + } +} + +struct unwind_table * unwind_table_add(const char *name, unsigned long base_addr, unsigned long gp, void *start, void *end) { struct unwind_table *table; unsigned long flags; + struct unwind_table_entry *s = (struct unwind_table_entry *)start; + struct unwind_table_entry *e = (struct unwind_table_entry *)end; + + unwind_table_sort(s, e); table = kmalloc(sizeof(struct unwind_table), GFP_USER); if (table == NULL) return NULL; unwind_table_init(table, name, base_addr, gp, start, end); spin_lock_irqsave(&unwind_lock, flags); - if (unwind_tables) - { - unwind_tables_end->next = table; - unwind_tables_end = table; - } - else - { - unwind_tables = unwind_tables_end = table; - } + list_add_tail(&table->list, &unwind_tables); spin_unlock_irqrestore(&unwind_lock, flags); return table; } +void unwind_table_remove(struct unwind_table *table) +{ + unsigned long flags; + + spin_lock_irqsave(&unwind_lock, flags); + list_del(&table->list); + spin_unlock_irqrestore(&unwind_lock, flags); + + kfree(table); +} + /* Called from setup_arch to import the kernel unwind info */ static int unwind_init(void) { @@ -148,6 +174,8 @@ static int unwind_init(void) start = (long)&__start___unwind[0]; stop = (long)&__stop___unwind[0]; + spin_lock_init(&unwind_lock); + printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n", start, stop, (stop - start) / sizeof(struct unwind_table_entry)); @@ -239,9 +267,9 @@ static void unwind_frame_regs(struct unwind_frame_info *info) info->prev_sp, info->prev_ip); } else { dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, " - "Save_RP = %d size = %u\n", e->region_start, - e->region_end, e->Save_SP, e->Save_RP, - e->Total_frame_size); + "Save_RP = %d, Millicode = %d size = %u\n", + e->region_start, e->region_end, e->Save_SP, e->Save_RP, + e->Millicode, e->Total_frame_size); looking_for_rp = e->Save_RP; @@ -284,7 +312,9 @@ static void unwind_frame_regs(struct unwind_frame_info *info) } info->prev_sp = info->sp - frame_size; - if (rpoffset) + if (e->Millicode) + info->rp = info->r31; + else if (rpoffset) info->rp = *(unsigned long *)(info->prev_sp - rpoffset); info->prev_ip = info->rp; info->rp = 0; @@ -296,13 +326,14 @@ static void unwind_frame_regs(struct unwind_frame_info *info) } void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, - unsigned long sp, unsigned long ip, unsigned long rp) + struct pt_regs *regs) { memset(info, 0, sizeof(struct unwind_frame_info)); info->t = t; - info->sp = sp; - info->ip = ip; - info->rp = rp; + info->sp = regs->gr[30]; + info->ip = regs->iaoq[0]; + info->rp = regs->gr[2]; + info->r31 = regs->gr[31]; dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", t ? (int)t->pid : -1, info->sp, info->ip); @@ -310,14 +341,22 @@ void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t) { - struct pt_regs *regs = &t->thread.regs; - unwind_frame_init(info, t, regs->ksp, regs->kpc, 0); + struct pt_regs *r = &t->thread.regs; + struct pt_regs *r2; + + r2 = (struct pt_regs *)kmalloc(sizeof(struct pt_regs), GFP_KERNEL); + if (!r2) + return; + *r2 = *r; + r2->gr[30] = r->ksp; + r2->iaoq[0] = r->kpc; + unwind_frame_init(info, t, r2); + kfree(r2); } void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs) { - unwind_frame_init(info, current, regs->gr[30], regs->iaoq[0], - regs->gr[2]); + unwind_frame_init(info, current, regs); } int unwind_once(struct unwind_frame_info *next_frame)