linux-old/arch/alpha/mm/extable.c
<<
>>
Prefs
   1/*
   2 * linux/arch/alpha/mm/extable.c
   3 */
   4
   5#include <linux/config.h>
   6#include <linux/module.h>
   7#include <asm/uaccess.h>
   8
   9extern const struct exception_table_entry __start___ex_table[];
  10extern const struct exception_table_entry __stop___ex_table[];
  11
  12static inline unsigned
  13search_one_table(const struct exception_table_entry *first,
  14                 const struct exception_table_entry *last,
  15                 signed long value)
  16{
  17        /* Abort early if the search value is out of range.  */
  18        if (value != (signed int)value)
  19                return 0;
  20
  21        while (first <= last) {
  22                const struct exception_table_entry *mid;
  23                long diff;
  24
  25                mid = (last - first) / 2 + first;
  26                diff = mid->insn - value;
  27                if (diff == 0)
  28                        return mid->fixup.unit;
  29                else if (diff < 0)
  30                        first = mid+1;
  31                else
  32                        last = mid-1;
  33        }
  34        return 0;
  35}
  36
  37register unsigned long gp __asm__("$29");
  38
  39static unsigned
  40search_exception_table_without_gp(unsigned long addr)
  41{
  42        unsigned ret;
  43
  44#ifndef CONFIG_MODULES
  45        /* There is only the kernel to search.  */
  46        ret = search_one_table(__start___ex_table, __stop___ex_table - 1,
  47                               addr - gp);
  48#else
  49        extern spinlock_t modlist_lock;
  50        unsigned long flags;
  51        /* The kernel is the last "module" -- no need to treat it special. */
  52        struct module *mp;
  53
  54        ret = 0;
  55        spin_lock_irqsave(&modlist_lock, flags);
  56        for (mp = module_list; mp ; mp = mp->next) {
  57                if (!mp->ex_table_start || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
  58                        continue;
  59                ret = search_one_table(mp->ex_table_start,
  60                                       mp->ex_table_end - 1, addr - mp->gp);
  61                if (ret)
  62                        break;
  63        }
  64        spin_unlock_irqrestore(&modlist_lock, flags);
  65#endif
  66
  67        return ret;
  68}
  69
  70unsigned
  71search_exception_table(unsigned long addr, unsigned long exc_gp)
  72{
  73        unsigned ret;
  74
  75#ifndef CONFIG_MODULES
  76        ret = search_one_table(__start___ex_table, __stop___ex_table - 1,
  77                               addr - exc_gp);
  78        if (ret) return ret;
  79#else
  80        extern spinlock_t modlist_lock;
  81        unsigned long flags;
  82        /* The kernel is the last "module" -- no need to treat it special. */
  83        struct module *mp;
  84
  85        ret = 0;
  86        spin_lock_irqsave(&modlist_lock, flags);
  87        for (mp = module_list; mp ; mp = mp->next) {
  88                if (!mp->ex_table_start || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
  89                        continue;
  90                ret = search_one_table(mp->ex_table_start,
  91                                       mp->ex_table_end - 1, addr - exc_gp);
  92                if (ret)
  93                        break;
  94        }
  95        spin_unlock_irqrestore(&modlist_lock, flags);
  96        if (ret) return ret;
  97#endif
  98
  99        /*
 100         * The search failed with the exception gp. To be safe, try the
 101         * old method before giving up.
 102         */
 103        ret = search_exception_table_without_gp(addr);
 104        if (ret) {
 105                printk(KERN_ALERT "%s: [%lx] EX_TABLE search fail with"
 106                       "exc frame GP, success with raw GP\n",
 107                       current->comm, addr);
 108                return ret;
 109        }
 110
 111        return 0;
 112}
 113
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.