X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fia64%2Fkernel%2Funwind.c;h=69e095abedf6f6d53be7c5510792ef8722cdc20d;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=6a715d84106538205482324902261e1a528b818f;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 6a715d841..69e095abe 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2003 Hewlett-Packard Co + * Copyright (C) 1999-2004 Hewlett-Packard Co * David Mosberger-Tang * Copyright (C) 2003 Fenghua Yu * - Change pt_regs_off() to make it less dependant on pt_regs structure. @@ -47,7 +47,6 @@ #include "entry.h" #include "unwind_i.h" -#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define p5 5 #define UNW_LOG_CACHE_SIZE 7 /* each unw_script is ~256 bytes in size */ @@ -89,6 +88,8 @@ static struct { /* list of unwind tables (one per load-module) */ struct unw_table *tables; + unsigned long r0; /* constant 0 for r0 */ + /* table of registers that prologues can save (and order in which they're saved): */ const unsigned char save_order[8]; @@ -239,7 +240,11 @@ static struct { #endif }; -/* Unwind accessors. */ +static inline int +read_only (void *addr) +{ + return (unsigned long) ((char *) addr - (char *) &unw.r0) < sizeof(unw.r0); +} /* * Returns offset of rREG in struct pt_regs. @@ -274,6 +279,8 @@ get_scratch_regs (struct unw_frame_info *info) return (struct pt_regs *) info->pt; } +/* Unwind accessors. */ + int unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write) { @@ -377,11 +384,16 @@ unw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char } if (write) { - *addr = *val; - if (*nat) - *nat_addr |= nat_mask; - else - *nat_addr &= ~nat_mask; + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else { + *addr = *val; + if (*nat) + *nat_addr |= nat_mask; + else + *nat_addr &= ~nat_mask; + } } else { if ((*nat_addr & nat_mask) == 0) { *val = *addr; @@ -420,7 +432,11 @@ unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int return -1; } if (write) - *addr = *val; + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else + *addr = *val; else *val = *addr; return 0; @@ -430,7 +446,7 @@ EXPORT_SYMBOL(unw_access_br); int unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, int write) { - struct ia64_fpreg *addr = 0; + struct ia64_fpreg *addr = NULL; struct pt_regs *pt; if ((unsigned) (regnum - 2) >= 126) { @@ -465,7 +481,11 @@ unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, } if (write) - *addr = *val; + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else + *addr = *val; else *val = *addr; return 0; @@ -557,9 +577,13 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int return -1; } - if (write) - *addr = *val; - else + if (write) { + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else + *addr = *val; + } else *val = *addr; return 0; } @@ -574,9 +598,13 @@ unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write) if (!addr) addr = &info->sw->pr; - if (write) - *addr = *val; - else + if (write) { + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else + *addr = *val; + } else *val = *addr; return 0; } @@ -814,7 +842,7 @@ desc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave } sr->gr_save_loc = grsave; sr->any_spills = 0; - sr->imask = 0; + sr->imask = NULL; sr->spill_offset = 0x10; /* default to psp+16 */ } } @@ -934,13 +962,13 @@ static inline void desc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr) { set_reg(sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE, - sr->region_start + MIN((int)t, sr->region_len - 1), 16*size); + sr->region_start + min_t(int, t, sr->region_len - 1), 16*size); } static inline void desc_mem_stack_v (unw_word t, struct unw_state_record *sr) { - sr->curr.reg[UNW_REG_PSP].when = sr->region_start + MIN((int)t, sr->region_len - 1); + sr->curr.reg[UNW_REG_PSP].when = sr->region_start + min_t(int, t, sr->region_len - 1); } static inline void @@ -976,7 +1004,7 @@ desc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr) if (reg->where == UNW_WHERE_NONE) reg->where = UNW_WHERE_GR_SAVE; - reg->when = sr->region_start + MIN((int)t, sr->region_len - 1); + reg->when = sr->region_start + min_t(int, t, sr->region_len - 1); } static inline void @@ -1044,7 +1072,7 @@ desc_label_state (unw_word label, struct unw_state_record *sr) static inline int desc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr) { - if (sr->when_target <= sr->region_start + MIN((int)t, sr->region_len - 1)) + if (sr->when_target <= sr->region_start + min_t(int, t, sr->region_len - 1)) return 0; if (qp > 0) { if ((sr->pr_val & (1UL << qp)) == 0) @@ -1085,7 +1113,7 @@ desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg, unsigned ch r = sr->curr.reg + decode_abreg(abreg, 0); r->where = where; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = (ytreg & 0x7f); } @@ -1100,7 +1128,7 @@ desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word r = sr->curr.reg + decode_abreg(abreg, 1); r->where = UNW_WHERE_PSPREL; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = 0x10 - 4*pspoff; } @@ -1115,7 +1143,7 @@ desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word r = sr->curr.reg + decode_abreg(abreg, 1); r->where = UNW_WHERE_SPREL; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->when = sr->region_start + min_t(int, t, sr->region_len - 1); r->val = 4*spoff; } @@ -1177,7 +1205,7 @@ desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word static inline unw_hash_index_t hash (unsigned long ip) { -# define hashmagic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */ +# define hashmagic 0x9e3779b97f4a7c16UL /* based on (sqrt(5)/2-1)*2^64 */ return (ip >> 4)*hashmagic >> (64 - UNW_LOG_HASH_SIZE); #undef hashmagic @@ -1202,7 +1230,7 @@ script_lookup (struct unw_frame_info *info) unsigned long ip, pr; if (UNW_DEBUG_ON(0)) - return 0; /* Always regenerate scripts in debug mode */ + return NULL; /* Always regenerate scripts in debug mode */ STAT(++unw.stat.cache.lookups); @@ -1216,7 +1244,7 @@ script_lookup (struct unw_frame_info *info) index = unw.hash[hash(ip)]; if (index >= UNW_CACHE_SIZE) - return 0; + return NULL; script = unw.cache + index; while (1) { @@ -1227,7 +1255,7 @@ script_lookup (struct unw_frame_info *info) return script; } if (script->coll_chain >= UNW_HASH_SIZE) - return 0; + return NULL; script = unw.cache + script->coll_chain; STAT(++unw.stat.cache.collision_chain_traversals); } @@ -1277,7 +1305,7 @@ script_new (unsigned long ip) if (script->ip) { index = hash(script->ip); tmp = unw.cache + unw.hash[index]; - prev = 0; + prev = NULL; while (1) { if (tmp == script) { if (prev) @@ -1407,6 +1435,9 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) need_nat_info = 0; } val = unw.preg_index[UNW_REG_R4 + (rval - 4)]; + } else if (rval == 0) { + opc = UNW_INSN_MOVE_CONST; + val = 0; } else { /* register got spilled to a scratch register */ opc = UNW_INSN_MOVE_SCRATCH; @@ -1479,7 +1510,7 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) static inline const struct unw_table_entry * lookup (struct unw_table *table, unsigned long rel_ip) { - const struct unw_table_entry *e = 0; + const struct unw_table_entry *e = NULL; unsigned long lo, hi, mid; /* do a binary search for right entry: */ @@ -1505,8 +1536,8 @@ lookup (struct unw_table *table, unsigned long rel_ip) static inline struct unw_script * build_script (struct unw_frame_info *info) { - const struct unw_table_entry *e = 0; - struct unw_script *script = 0; + const struct unw_table_entry *e = NULL; + struct unw_script *script = NULL; struct unw_labeled_state *ls, *next; unsigned long ip = info->ip; struct unw_state_record sr; @@ -1531,7 +1562,7 @@ build_script (struct unw_frame_info *info) if (!script) { UNW_DPRINT(0, "unwind.%s: failed to create unwind script\n", __FUNCTION__); STAT(unw.stat.script.build_time += ia64_get_itc() - start); - return 0; + return NULL; } unw.cache[info->prev_script].hint = script - unw.cache; @@ -1729,6 +1760,17 @@ run_script (struct unw_script *script, struct unw_frame_info *state) } break; + case UNW_INSN_MOVE_CONST: + if (val == 0) + s[dst] = (unsigned long) &unw.r0; + else { + s[dst] = 0; + UNW_DPRINT(0, "unwind.%s: UNW_INSN_MOVE_CONST bad val=%ld\n", + __FUNCTION__, val); + } + break; + + case UNW_INSN_MOVE_STACKED: s[dst] = (unsigned long) ia64_rse_skip_regs((unsigned long *)state->bsp, val); @@ -1793,7 +1835,7 @@ find_save_locs (struct unw_frame_info *info) /* don't let obviously bad addresses pollute the cache */ /* FIXME: should really be level 0 but it occurs too often. KAO */ UNW_DPRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip); - info->rp_loc = 0; + info->rp_loc = NULL; return -1; } @@ -2050,12 +2092,12 @@ unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned lon if (end - start <= 0) { UNW_DPRINT(0, "unwind.%s: ignoring attempt to insert empty unwind table\n", __FUNCTION__); - return 0; + return NULL; } table = kmalloc(sizeof(*table), GFP_USER); if (!table) - return 0; + return NULL; init_unwind_table(table, name, segment_base, gp, table_start, table_end); @@ -2257,7 +2299,7 @@ unw_init (void) * EFAULT BUF points outside your accessible address space. */ asmlinkage long -sys_getunwind (void *buf, size_t buf_size) +sys_getunwind (void __user *buf, size_t buf_size) { if (buf && buf_size >= unw.gate_table_size) if (copy_to_user(buf, unw.gate_table, unw.gate_table_size) != 0)