source: libcfa/src/lsda.h @ 71f3d45

Last change on this file since 71f3d45 was bf71cfd, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

Moved up many directories in source

  • Property mode set to 100644
File size: 6.8 KB
Line 
1//This code was stolen from gcc to read exception tables
2
3
4/* If using C++, references to abort have to be qualified with std::.  */
5#if __cplusplus
6#define __gxx_abort std::abort
7#else
8#define __gxx_abort abort
9#endif
10
11/* Pointer encodings, from dwarf2.h.  */
12#define DW_EH_PE_absptr         0x00
13#define DW_EH_PE_omit           0xff
14
15#define DW_EH_PE_uleb128        0x01
16#define DW_EH_PE_udata2         0x02
17#define DW_EH_PE_udata4         0x03
18#define DW_EH_PE_udata8         0x04
19#define DW_EH_PE_sleb128        0x09
20#define DW_EH_PE_sdata2         0x0A
21#define DW_EH_PE_sdata4         0x0B
22#define DW_EH_PE_sdata8         0x0C
23#define DW_EH_PE_signed         0x08
24
25#define DW_EH_PE_pcrel          0x10
26#define DW_EH_PE_textrel        0x20
27#define DW_EH_PE_datarel        0x30
28#define DW_EH_PE_funcrel        0x40
29#define DW_EH_PE_aligned        0x50
30
31#define DW_EH_PE_indirect       0x80
32
33
34int handler_found = 0;
35
36/* Given an encoding, return the number of bytes the format occupies.
37This is only defined for fixed-size encodings, and so does not
38include leb128.  */
39static unsigned int size_of_encoded_value (unsigned char encoding) __attribute__ ((unused));
40
41static unsigned int size_of_encoded_value (unsigned char encoding)
42{
43        if (encoding == DW_EH_PE_omit) return 0;
44
45        switch (encoding & 0x07) {
46                case DW_EH_PE_absptr: return sizeof (void *);
47                case DW_EH_PE_udata2: return 2;
48                case DW_EH_PE_udata4: return 4;
49                case DW_EH_PE_udata8: return 8;
50        }
51        __gxx_abort ();
52}
53
54/* Given an encoding and an _Unwind_Context, return the base to which
55the encoding is relative.  This base may then be passed to
56read_encoded_value_with_base for use when the _Unwind_Context is
57not available.  */
58static _Unwind_Ptr base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
59{
60        if (encoding == DW_EH_PE_omit) return 0;
61
62        switch (encoding & 0x70) {
63                case DW_EH_PE_absptr:
64                case DW_EH_PE_pcrel:
65                case DW_EH_PE_aligned:
66                        return 0;
67                case DW_EH_PE_textrel:
68                        return _Unwind_GetTextRelBase (context);
69                case DW_EH_PE_datarel:
70                        return _Unwind_GetDataRelBase (context);
71                case DW_EH_PE_funcrel:
72                        return _Unwind_GetRegionStart (context);
73        }
74        __gxx_abort ();
75}
76
77/* Read an unsigned leb128 value from P, store the value in VAL, return
78P incremented past the value.  We assume that a word is large enough to
79hold any value so encoded; if it is smaller than a pointer on some target,
80pointers should not be leb128 encoded on that target.  */
81static const unsigned char * read_uleb128 (const unsigned char *p, _uleb128_t *val)
82{
83        unsigned int shift = 0;
84        unsigned char byte;
85        _uleb128_t result;
86
87        result = 0;
88        do
89        {
90                byte = *p++;
91                result |= ((_uleb128_t)byte & 0x7f) << shift;
92                shift += 7;
93        }
94        while (byte & 0x80);
95
96        *val = result;
97        return p;
98}
99
100/* Similar, but read a signed leb128 value.  */
101static const unsigned char * read_sleb128 (const unsigned char *p, _sleb128_t *val)
102{
103        unsigned int shift = 0;
104        unsigned char byte;
105        _uleb128_t result;
106
107        result = 0;
108        do
109        {
110                byte = *p++;
111                result |= ((_uleb128_t)byte & 0x7f) << shift;
112                shift += 7;
113        }
114        while (byte & 0x80);
115
116        /* Sign-extend a negative value.  */
117        if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) result |= -(((_uleb128_t)1L) << shift);
118
119        *val = (_sleb128_t) result;
120        return p;
121}
122
123/* Load an encoded value from memory at P.  The value is returned in VAL;
124The function returns P incremented past the value.  BASE is as given
125by base_of_encoded_value for this encoding in the appropriate context.  */
126
127static const unsigned char * read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, const unsigned char *p, _Unwind_Ptr *val)
128{
129        union unaligned
130        {
131                void *ptr;
132                unsigned u2 __attribute__ ((mode (HI)));
133                unsigned u4 __attribute__ ((mode (SI)));
134                unsigned u8 __attribute__ ((mode (DI)));
135                signed s2 __attribute__ ((mode (HI)));
136                signed s4 __attribute__ ((mode (SI)));
137                signed s8 __attribute__ ((mode (DI)));
138        } __attribute__((__packed__));
139
140        const union unaligned *u = (const union unaligned *) p;
141        _Unwind_Internal_Ptr result;
142
143        if (encoding == DW_EH_PE_aligned)
144        {
145                _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
146                a = (a + sizeof (void *) - 1) & - sizeof(void *);
147                result = *(_Unwind_Internal_Ptr *) a;
148                p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *));
149        }
150        else
151        {
152                switch (encoding & 0x0f)
153                {
154                        case DW_EH_PE_absptr:
155                                result = (_Unwind_Internal_Ptr) u->ptr;
156                                p += sizeof (void *);
157                                break;
158                        case DW_EH_PE_uleb128:
159                        {
160                                _uleb128_t tmp;
161                                p = read_uleb128 (p, &tmp);
162                                result = (_Unwind_Internal_Ptr) tmp;
163                        }
164                        break;
165
166                        case DW_EH_PE_sleb128:
167                        {
168                                _sleb128_t tmp;
169                                p = read_sleb128 (p, &tmp);
170                                result = (_Unwind_Internal_Ptr) tmp;
171                        }
172                        break;
173
174                        case DW_EH_PE_udata2:
175                                result = u->u2;
176                                p += 2;
177                                break;
178                        case DW_EH_PE_udata4:
179                                result = u->u4;
180                                p += 4;
181                                break;
182                        case DW_EH_PE_udata8:
183                                result = u->u8;
184                                p += 8;
185                                break;
186                        case DW_EH_PE_sdata2:
187                                result = u->s2;
188                                p += 2;
189                                break;
190                        case DW_EH_PE_sdata4:
191                                result = u->s4;
192                                p += 4;
193                                break;
194                        case DW_EH_PE_sdata8:
195                                result = u->s8;
196                                p += 8;
197                                break;
198                        default:
199                                __gxx_abort();
200                }
201
202                if (result != 0)
203                {
204                        result += ((encoding & 0x70) == DW_EH_PE_pcrel ? (_Unwind_Internal_Ptr) u : base);
205                       
206                        if (encoding & DW_EH_PE_indirect) result = *(_Unwind_Internal_Ptr *) result;
207                }
208        }
209
210        *val = result;
211        return p;
212}
213
214/* Like read_encoded_value_with_base, but get the base from the context
215rather than providing it directly.  */
216static inline const unsigned char * read_encoded_value (struct _Unwind_Context *context, unsigned char encoding, const unsigned char *p, _Unwind_Ptr *val)
217{
218        return read_encoded_value_with_base (encoding, base_of_encoded_value (encoding, context), p, val);
219}
220
221typedef struct
222{
223        _Unwind_Ptr Start;
224        _Unwind_Ptr LPStart;
225        _Unwind_Ptr ttype_base;
226        const unsigned char *TType;
227        const unsigned char *action_table;
228        unsigned char ttype_encoding;
229        unsigned char call_site_encoding;
230} lsda_header_info;
231
232static const unsigned char * parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, lsda_header_info *info)
233{
234        _uleb128_t tmp;
235        unsigned char lpstart_encoding;
236
237        info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
238
239        /* Find @LPStart, the base to which landing pad offsets are relative.  */
240        lpstart_encoding = *p++;
241        if (lpstart_encoding != DW_EH_PE_omit) p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
242
243        else info->LPStart = info->Start;
244
245        /* Find @TType, the base of the handler and exception spec type data.  */
246        info->ttype_encoding = *p++;
247        if (info->ttype_encoding != DW_EH_PE_omit)
248        {
249                p = read_uleb128 (p, &tmp);
250                info->TType = p + tmp;
251        }
252        else info->TType = 0;
253
254        /* The encoding and length of the call-site table; the action table
255        immediately follows.  */
256        info->call_site_encoding = *p++;
257        p = read_uleb128 (p, &tmp);
258        info->action_table = p + tmp;
259
260        return p;
261}
Note: See TracBrowser for help on using the repository browser.