hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// SPDX-License-Identifier: GPL-2.0
/*
 * linux/arch/sparc/mm/extable.c
 */
 
#include <linux/module.h>
#include <linux/extable.h>
#include <linux/uaccess.h>
 
void sort_extable(struct exception_table_entry *start,
         struct exception_table_entry *finish)
{
}
 
/* Caller knows they are in a range if ret->fixup == 0 */
const struct exception_table_entry *
search_extable(const struct exception_table_entry *base,
          const size_t num,
          unsigned long value)
{
   int i;
 
   /* Single insn entries are encoded as:
    *    word 1:    insn address
    *    word 2:    fixup code address
    *
    * Range entries are encoded as:
    *    word 1: first insn address
    *    word 2: 0
    *    word 3: last insn address + 4 bytes
    *    word 4: fixup code address
    *
    * Deleted entries are encoded as:
    *    word 1: unused
    *    word 2: -1
    *
    * See asm/uaccess.h for more details.
    */
 
   /* 1. Try to find an exact match. */
   for (i = 0; i < num; i++) {
       if (base[i].fixup == 0) {
           /* A range entry, skip both parts. */
           i++;
           continue;
       }
 
       /* A deleted entry; see trim_init_extable */
       if (base[i].fixup == -1)
           continue;
 
       if (base[i].insn == value)
           return &base[i];
   }
 
   /* 2. Try to find a range match. */
   for (i = 0; i < (num - 1); i++) {
       if (base[i].fixup)
           continue;
 
       if (base[i].insn <= value && base[i + 1].insn > value)
           return &base[i];
 
       i++;
   }
 
        return NULL;
}
 
#ifdef CONFIG_MODULES
/* We could memmove them around; easier to mark the trimmed ones. */
void trim_init_extable(struct module *m)
{
   unsigned int i;
   bool range;
 
   for (i = 0; i < m->num_exentries; i += range ? 2 : 1) {
       range = m->extable[i].fixup == 0;
 
       if (within_module_init(m->extable[i].insn, m)) {
           m->extable[i].fixup = -1;
           if (range)
               m->extable[i+1].fixup = -1;
       }
       if (range)
           i++;
   }
}
#endif /* CONFIG_MODULES */
 
/* Special extable search, which handles ranges.  Returns fixup */
unsigned long search_extables_range(unsigned long addr, unsigned long *g2)
{
   const struct exception_table_entry *entry;
 
   entry = search_exception_tables(addr);
   if (!entry)
       return 0;
 
   /* Inside range?  Fix g2 and return correct fixup */
   if (!entry->fixup) {
       *g2 = (addr - entry->insn) / 4;
       return (entry + 1)->fixup;
   }
 
   return entry->fixup;
}