00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef _GNU_SOURCE
00033 #define _GNU_SOURCE 1
00034 #endif
00035
00036 #include "tconfig.h"
00037 #include "tsystem.h"
00038 #ifndef inhibit_libc
00039 #include <link.h>
00040 #endif
00041 #include "coretypes.h"
00042 #include "tm.h"
00043 #include "dwarf2.h"
00044 #include "unwind.h"
00045 #define NO_BASE_OF_ENCODED_VALUE
00046 #include "unwind-pe.h"
00047 #include "unwind-dw2-fde.h"
00048 #include "unwind-compat.h"
00049 #include "gthr.h"
00050
00051 #if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \
00052 && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
00053 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
00054
00055 #ifndef __RELOC_POINTER
00056 # define __RELOC_POINTER(ptr, base) ((ptr) + (base))
00057 #endif
00058
00059 static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases);
00060
00061 #define _Unwind_Find_FDE _Unwind_Find_registered_FDE
00062 #include "unwind-dw2-fde.c"
00063 #undef _Unwind_Find_FDE
00064
00065 #ifndef PT_GNU_EH_FRAME
00066 #define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
00067 #endif
00068
00069 struct unw_eh_callback_data
00070 {
00071 _Unwind_Ptr pc;
00072 void *tbase;
00073 void *dbase;
00074 void *func;
00075 const fde *ret;
00076 int check_cache;
00077 };
00078
00079 struct unw_eh_frame_hdr
00080 {
00081 unsigned char version;
00082 unsigned char eh_frame_ptr_enc;
00083 unsigned char fde_count_enc;
00084 unsigned char table_enc;
00085 };
00086
00087 #define FRAME_HDR_CACHE_SIZE 8
00088
00089 static struct frame_hdr_cache_element
00090 {
00091 _Unwind_Ptr pc_low;
00092 _Unwind_Ptr pc_high;
00093 _Unwind_Ptr load_base;
00094 const ElfW(Phdr) *p_eh_frame_hdr;
00095 const ElfW(Phdr) *p_dynamic;
00096 struct frame_hdr_cache_element *link;
00097 } frame_hdr_cache[FRAME_HDR_CACHE_SIZE];
00098
00099 static struct frame_hdr_cache_element *frame_hdr_cache_head;
00100
00101
00102
00103
00104 static _Unwind_Ptr
00105 base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
00106 {
00107 if (encoding == DW_EH_PE_omit)
00108 return 0;
00109
00110 switch (encoding & 0x70)
00111 {
00112 case DW_EH_PE_absptr:
00113 case DW_EH_PE_pcrel:
00114 case DW_EH_PE_aligned:
00115 return 0;
00116
00117 case DW_EH_PE_textrel:
00118 return (_Unwind_Ptr) data->tbase;
00119 case DW_EH_PE_datarel:
00120 return (_Unwind_Ptr) data->dbase;
00121 default:
00122 gcc_unreachable ();
00123 }
00124 }
00125
00126 static int
00127 _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
00128 {
00129 struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr;
00130 const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic;
00131 long n, match;
00132 #ifdef __FRV_FDPIC__
00133 struct elf32_fdpic_loadaddr load_base;
00134 #else
00135 _Unwind_Ptr load_base;
00136 #endif
00137 const unsigned char *p;
00138 const struct unw_eh_frame_hdr *hdr;
00139 _Unwind_Ptr eh_frame;
00140 struct object ob;
00141
00142 struct ext_dl_phdr_info
00143 {
00144 ElfW(Addr) dlpi_addr;
00145 const char *dlpi_name;
00146 const ElfW(Phdr) *dlpi_phdr;
00147 ElfW(Half) dlpi_phnum;
00148 unsigned long long int dlpi_adds;
00149 unsigned long long int dlpi_subs;
00150 };
00151
00152 match = 0;
00153 phdr = info->dlpi_phdr;
00154 load_base = info->dlpi_addr;
00155 p_eh_frame_hdr = NULL;
00156 p_dynamic = NULL;
00157
00158 struct frame_hdr_cache_element *prev_cache_entry = NULL,
00159 *last_cache_entry = NULL;
00160
00161 if (data->check_cache && size >= sizeof (struct ext_dl_phdr_info))
00162 {
00163 static unsigned long long adds = -1ULL, subs;
00164 struct ext_dl_phdr_info *einfo = (struct ext_dl_phdr_info *) info;
00165
00166
00167
00168
00169
00170 if (einfo->dlpi_adds == adds && einfo->dlpi_subs == subs)
00171 {
00172
00173
00174
00175
00176
00177 struct frame_hdr_cache_element *cache_entry;
00178
00179 for (cache_entry = frame_hdr_cache_head;
00180 cache_entry;
00181 cache_entry = cache_entry->link)
00182 {
00183 if (data->pc >= cache_entry->pc_low
00184 && data->pc < cache_entry->pc_high)
00185 {
00186 load_base = cache_entry->load_base;
00187 p_eh_frame_hdr = cache_entry->p_eh_frame_hdr;
00188 p_dynamic = cache_entry->p_dynamic;
00189
00190
00191 if (cache_entry != frame_hdr_cache_head)
00192 {
00193 prev_cache_entry->link = cache_entry->link;
00194 cache_entry->link = frame_hdr_cache_head;
00195 frame_hdr_cache_head = cache_entry;
00196 }
00197 goto found;
00198 }
00199
00200 last_cache_entry = cache_entry;
00201
00202 if ((cache_entry->pc_low | cache_entry->pc_high) == 0)
00203 break;
00204 if (cache_entry->link != NULL)
00205 prev_cache_entry = cache_entry;
00206 }
00207 }
00208 else
00209 {
00210 adds = einfo->dlpi_adds;
00211 subs = einfo->dlpi_subs;
00212
00213
00214 int i;
00215 for (i = 0; i < FRAME_HDR_CACHE_SIZE; i++)
00216 {
00217 frame_hdr_cache[i].pc_low = 0;
00218 frame_hdr_cache[i].pc_high = 0;
00219 frame_hdr_cache[i].link = &frame_hdr_cache[i+1];
00220 }
00221 frame_hdr_cache[i-1].link = NULL;
00222 frame_hdr_cache_head = &frame_hdr_cache[0];
00223 data->check_cache = 0;
00224 }
00225 }
00226
00227
00228 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
00229 + sizeof (info->dlpi_phnum))
00230 return -1;
00231
00232 _Unwind_Ptr pc_low = 0, pc_high = 0;
00233
00234
00235
00236 for (n = info->dlpi_phnum; --n >= 0; phdr++)
00237 {
00238 if (phdr->p_type == PT_LOAD)
00239 {
00240 _Unwind_Ptr vaddr = (_Unwind_Ptr)
00241 __RELOC_POINTER (phdr->p_vaddr, load_base);
00242 if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
00243 {
00244 match = 1;
00245 pc_low = vaddr;
00246 pc_high = vaddr + phdr->p_memsz;
00247 }
00248 }
00249 else if (phdr->p_type == PT_GNU_EH_FRAME)
00250 p_eh_frame_hdr = phdr;
00251 else if (phdr->p_type == PT_DYNAMIC)
00252 p_dynamic = phdr;
00253 }
00254
00255 if (!match)
00256 return 0;
00257
00258 if (size >= sizeof (struct ext_dl_phdr_info))
00259 {
00260
00261
00262
00263 if (last_cache_entry != NULL && prev_cache_entry != NULL)
00264 {
00265 prev_cache_entry->link = last_cache_entry->link;
00266 last_cache_entry->link = frame_hdr_cache_head;
00267 frame_hdr_cache_head = last_cache_entry;
00268 }
00269
00270 frame_hdr_cache_head->load_base = load_base;
00271 frame_hdr_cache_head->p_eh_frame_hdr = p_eh_frame_hdr;
00272 frame_hdr_cache_head->p_dynamic = p_dynamic;
00273 frame_hdr_cache_head->pc_low = pc_low;
00274 frame_hdr_cache_head->pc_high = pc_high;
00275 }
00276
00277 found:
00278
00279 if (!p_eh_frame_hdr)
00280 return 0;
00281
00282
00283 hdr = (const struct unw_eh_frame_hdr *)
00284 __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base);
00285 if (hdr->version != 1)
00286 return 1;
00287
00288 #ifdef CRT_GET_RFIB_DATA
00289 # ifdef __i386__
00290 data->dbase = NULL;
00291 if (p_dynamic)
00292 {
00293
00294
00295 ElfW(Dyn) *dyn = (ElfW(Dyn) *)
00296 __RELOC_POINTER (p_dynamic->p_vaddr, load_base);
00297 for (; dyn->d_tag != DT_NULL ; dyn++)
00298 if (dyn->d_tag == DT_PLTGOT)
00299 {
00300
00301 data->dbase = (void *) dyn->d_un.d_ptr;
00302 break;
00303 }
00304 }
00305 # elif defined __FRV_FDPIC__ && defined __linux__
00306 data->dbase = load_base.got_value;
00307 # else
00308 # error What is DW_EH_PE_datarel base on this platform?
00309 # endif
00310 #endif
00311
00312 p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
00313 base_from_cb_data (hdr->eh_frame_ptr_enc,
00314 data),
00315 (const unsigned char *) (hdr + 1),
00316 &eh_frame);
00317
00318
00319
00320
00321 if (hdr->fde_count_enc != DW_EH_PE_omit
00322 && hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4))
00323 {
00324 _Unwind_Ptr fde_count;
00325
00326 p = read_encoded_value_with_base (hdr->fde_count_enc,
00327 base_from_cb_data (hdr->fde_count_enc,
00328 data),
00329 p, &fde_count);
00330
00331 if (fde_count == 0)
00332 return 1;
00333 if ((((_Unwind_Ptr) p) & 3) == 0)
00334 {
00335 struct fde_table {
00336 signed initial_loc __attribute__ ((mode (SI)));
00337 signed fde __attribute__ ((mode (SI)));
00338 };
00339 const struct fde_table *table = (const struct fde_table *) p;
00340 size_t lo, hi, mid;
00341 _Unwind_Ptr data_base = (_Unwind_Ptr) hdr;
00342 fde *f;
00343 unsigned int f_enc, f_enc_size;
00344 _Unwind_Ptr range;
00345
00346 mid = fde_count - 1;
00347 if (data->pc < table[0].initial_loc + data_base)
00348 return 1;
00349 else if (data->pc < table[mid].initial_loc + data_base)
00350 {
00351 lo = 0;
00352 hi = mid;
00353
00354 while (lo < hi)
00355 {
00356 mid = (lo + hi) / 2;
00357 if (data->pc < table[mid].initial_loc + data_base)
00358 hi = mid;
00359 else if (data->pc >= table[mid + 1].initial_loc + data_base)
00360 lo = mid + 1;
00361 else
00362 break;
00363 }
00364
00365 gcc_assert (lo < hi);
00366 }
00367
00368 f = (fde *) (table[mid].fde + data_base);
00369 f_enc = get_fde_encoding (f);
00370 f_enc_size = size_of_encoded_value (f_enc);
00371 read_encoded_value_with_base (f_enc & 0x0f, 0,
00372 &f->pc_begin[f_enc_size], &range);
00373 if (data->pc < table[mid].initial_loc + data_base + range)
00374 data->ret = f;
00375 data->func = (void *) (table[mid].initial_loc + data_base);
00376 return 1;
00377 }
00378 }
00379
00380
00381
00382
00383 ob.pc_begin = NULL;
00384 ob.tbase = data->tbase;
00385 ob.dbase = data->dbase;
00386 ob.u.single = (fde *) eh_frame;
00387 ob.s.i = 0;
00388 ob.s.b.mixed_encoding = 1;
00389 data->ret = linear_search_fdes (&ob, (fde *) eh_frame, (void *) data->pc);
00390 if (data->ret != NULL)
00391 {
00392 _Unwind_Ptr func;
00393 unsigned int encoding = get_fde_encoding (data->ret);
00394
00395 read_encoded_value_with_base (encoding,
00396 base_from_cb_data (encoding, data),
00397 data->ret->pc_begin, &func);
00398 data->func = (void *) func;
00399 }
00400 return 1;
00401 }
00402
00403 const fde *
00404 _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
00405 {
00406 struct unw_eh_callback_data data;
00407 const fde *ret;
00408
00409 ret = _Unwind_Find_registered_FDE (pc, bases);
00410 if (ret != NULL)
00411 return ret;
00412
00413 data.pc = (_Unwind_Ptr) pc;
00414 data.tbase = NULL;
00415 data.dbase = NULL;
00416 data.func = NULL;
00417 data.ret = NULL;
00418 data.check_cache = 1;
00419
00420 if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
00421 return NULL;
00422
00423 if (data.ret)
00424 {
00425 bases->tbase = data.tbase;
00426 bases->dbase = data.dbase;
00427 bases->func = data.func;
00428 }
00429 return data.ret;
00430 }
00431
00432 #else
00433
00434 #define _Unwind_Find_FDE _Unwind_Find_FDE
00435 #include "unwind-dw2-fde.c"
00436 #endif
00437
00438 #if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
00439 alias (_Unwind_Find_FDE);
00440 #endif