1 /* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 /* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF
22 segment and dl_iterate_phdr to avoid register/deregister calls at
26 # include <shlib-compat.h>
29 #if !defined _LIBC || SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2_5)
34 #define _Unwind_Find_FDE _Unwind_Find_registered_FDE
36 #include <unwind-dw2-fde.c>
38 #undef _Unwind_Find_FDE
40 extern fde
* _Unwind_Find_registered_FDE (void *pc
,
41 struct dwarf_eh_bases
*bases
);
42 extern fde
* _Unwind_Find_FDE (void *, struct dwarf_eh_bases
*);
44 struct unw_eh_callback_data
53 struct unw_eh_frame_hdr
55 unsigned char version
;
56 unsigned char eh_frame_ptr_enc
;
57 unsigned char fde_count_enc
;
58 unsigned char table_enc
;
61 /* Like base_of_encoded_value, but take the base from a struct object
62 instead of an _Unwind_Context. */
65 base_from_cb_data (unsigned char encoding
, struct unw_eh_callback_data
*data
)
67 if (encoding
== DW_EH_PE_omit
)
70 switch (encoding
& 0x70)
74 case DW_EH_PE_aligned
:
77 case DW_EH_PE_textrel
:
78 return (_Unwind_Ptr
) data
->tbase
;
79 case DW_EH_PE_datarel
:
80 return (_Unwind_Ptr
) data
->dbase
;
86 _Unwind_IteratePhdrCallback (struct dl_phdr_info
*info
, size_t size
, void *ptr
)
88 struct unw_eh_callback_data
*data
= (struct unw_eh_callback_data
*) ptr
;
89 const ElfW(Phdr
) *phdr
, *p_eh_frame_hdr
, *p_dynamic
;
91 _Unwind_Ptr load_base
;
92 const unsigned char *p
;
93 const struct unw_eh_frame_hdr
*hdr
;
97 /* Make sure struct dl_phdr_info is at least as big as we need. */
98 if (size
< offsetof (struct dl_phdr_info
, dlpi_phnum
)
99 + sizeof (info
->dlpi_phnum
))
103 phdr
= info
->dlpi_phdr
;
104 load_base
= info
->dlpi_addr
;
105 p_eh_frame_hdr
= NULL
;
108 /* See if PC falls into one of the loaded segments. Find the eh_frame
109 segment at the same time. */
110 for (n
= info
->dlpi_phnum
; --n
>= 0; phdr
++)
112 if (phdr
->p_type
== PT_LOAD
)
114 _Unwind_Ptr vaddr
= phdr
->p_vaddr
+ load_base
;
115 if (data
->pc
>= vaddr
&& data
->pc
< vaddr
+ phdr
->p_memsz
)
118 else if (phdr
->p_type
== PT_GNU_EH_FRAME
)
119 p_eh_frame_hdr
= phdr
;
120 else if (phdr
->p_type
== PT_DYNAMIC
)
123 if (!match
|| !p_eh_frame_hdr
)
126 /* Read .eh_frame_hdr header. */
127 hdr
= (const struct unw_eh_frame_hdr
*)
128 (p_eh_frame_hdr
->p_vaddr
+ load_base
);
129 if (hdr
->version
!= 1)
132 #ifdef CRT_GET_RFIB_DATA
137 /* For dynamicly linked executables and shared libraries,
138 DT_PLTGOT is the gp value for that object. */
139 ElfW(Dyn
) *dyn
= (ElfW(Dyn
) *)(p_dynamic
->p_vaddr
+ load_base
);
140 for (; dyn
->d_tag
!= DT_NULL
; dyn
++)
141 if (dyn
->d_tag
== DT_PLTGOT
)
143 /* On IA-32, _DYNAMIC is writable and GLIBC has relocated it. */
144 data
->dbase
= (void *) dyn
->d_un
.d_ptr
;
149 # error What is DW_EH_PE_datarel base on this platform?
152 #ifdef CRT_GET_RFIB_TEXT
153 # error What is DW_EH_PE_textrel base on this platform?
156 p
= read_encoded_value_with_base (hdr
->eh_frame_ptr_enc
,
157 base_from_cb_data (hdr
->eh_frame_ptr_enc
,
159 (const unsigned char *) (hdr
+ 1),
162 /* We require here specific table encoding to speed things up.
163 Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
164 as base, not the processor specific DW_EH_PE_datarel. */
165 if (hdr
->fde_count_enc
!= DW_EH_PE_omit
166 && hdr
->table_enc
== (DW_EH_PE_datarel
| DW_EH_PE_sdata4
))
168 _Unwind_Ptr fde_count
;
170 p
= read_encoded_value_with_base (hdr
->fde_count_enc
,
171 base_from_cb_data (hdr
->fde_count_enc
,
174 /* Shouldn't happen. */
177 if ((((_Unwind_Ptr
) p
) & 3) == 0)
180 signed initial_loc
__attribute__ ((mode (SI
)));
181 signed fde
__attribute__ ((mode (SI
)));
183 const struct fde_table
*table
= (const struct fde_table
*) p
;
185 _Unwind_Ptr data_base
= (_Unwind_Ptr
) hdr
;
187 unsigned int f_enc
, f_enc_size
;
191 if (data
->pc
< table
[0].initial_loc
+ data_base
)
193 else if (data
->pc
< table
[mid
].initial_loc
+ data_base
)
201 if (data
->pc
< table
[mid
].initial_loc
+ data_base
)
203 else if (data
->pc
>= table
[mid
+ 1].initial_loc
+ data_base
)
213 f
= (fde
*) (table
[mid
].fde
+ data_base
);
214 f_enc
= get_fde_encoding (f
);
215 f_enc_size
= size_of_encoded_value (f_enc
);
216 read_encoded_value_with_base (f_enc
& 0x0f, 0,
217 &f
->pc_begin
[f_enc_size
], &range
);
218 if (data
->pc
< table
[mid
].initial_loc
+ data_base
+ range
)
220 data
->func
= (void *) (table
[mid
].initial_loc
+ data_base
);
225 /* We have no sorted search table, so need to go the slow way.
226 As soon as GLIBC will provide API so to notify that a library has been
227 removed, we could cache this (and thus use search_object). */
229 ob
.tbase
= data
->tbase
;
230 ob
.dbase
= data
->dbase
;
231 ob
.u
.single
= (fde
*) eh_frame
;
233 ob
.s
.b
.mixed_encoding
= 1; /* Need to assume worst case. */
234 data
->ret
= linear_search_fdes (&ob
, (fde
*) eh_frame
, (void *) data
->pc
);
235 if (data
->ret
!= NULL
)
237 unsigned int encoding
= get_fde_encoding (data
->ret
);
238 read_encoded_value_with_base (encoding
,
239 base_from_cb_data (encoding
, data
),
241 (_Unwind_Ptr
*)&data
->func
);
247 # define dl_iterate_phdr __dl_iterate_phdr
251 _Unwind_Find_FDE (void *pc
, struct dwarf_eh_bases
*bases
)
253 struct unw_eh_callback_data data
;
256 ret
= _Unwind_Find_registered_FDE (pc
, bases
);
260 data
.pc
= (_Unwind_Ptr
) pc
;
266 if (dl_iterate_phdr (_Unwind_IteratePhdrCallback
, &data
) < 0)
271 bases
->tbase
= data
.tbase
;
272 bases
->dbase
= data
.dbase
;
273 bases
->func
= data
.func
;