1 /* Copyright (C) 2001-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 /* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF
20 segment and dl_iterate_phdr to avoid register/deregister calls at
24 # include <shlib-compat.h>
27 #if !defined _LIBC || SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2_5)
32 #define _Unwind_Find_FDE _Unwind_Find_registered_FDE
34 #include <unwind-dw2-fde.c>
36 #undef _Unwind_Find_FDE
38 extern fde
* _Unwind_Find_registered_FDE (void *pc
,
39 struct dwarf_eh_bases
*bases
);
40 extern fde
* _Unwind_Find_FDE (void *, struct dwarf_eh_bases
*);
42 struct unw_eh_callback_data
51 struct unw_eh_frame_hdr
53 unsigned char version
;
54 unsigned char eh_frame_ptr_enc
;
55 unsigned char fde_count_enc
;
56 unsigned char table_enc
;
59 /* Like base_of_encoded_value, but take the base from a struct object
60 instead of an _Unwind_Context. */
63 base_from_cb_data (unsigned char encoding
, struct unw_eh_callback_data
*data
)
65 if (encoding
== DW_EH_PE_omit
)
68 switch (encoding
& 0x70)
72 case DW_EH_PE_aligned
:
75 case DW_EH_PE_textrel
:
76 return (_Unwind_Ptr
) data
->tbase
;
77 case DW_EH_PE_datarel
:
78 return (_Unwind_Ptr
) data
->dbase
;
84 _Unwind_IteratePhdrCallback (struct dl_phdr_info
*info
, size_t size
, void *ptr
)
86 struct unw_eh_callback_data
*data
= (struct unw_eh_callback_data
*) ptr
;
87 const ElfW(Phdr
) *phdr
, *p_eh_frame_hdr
;
88 const ElfW(Phdr
) *p_dynamic
__attribute__ ((unused
));
90 _Unwind_Ptr load_base
;
91 const unsigned char *p
;
92 const struct unw_eh_frame_hdr
*hdr
;
96 /* Make sure struct dl_phdr_info is at least as big as we need. */
97 if (size
< offsetof (struct dl_phdr_info
, dlpi_phnum
)
98 + sizeof (info
->dlpi_phnum
))
102 phdr
= info
->dlpi_phdr
;
103 load_base
= info
->dlpi_addr
;
104 p_eh_frame_hdr
= NULL
;
107 /* See if PC falls into one of the loaded segments. Find the eh_frame
108 segment at the same time. */
109 for (n
= info
->dlpi_phnum
; --n
>= 0; phdr
++)
111 if (phdr
->p_type
== PT_LOAD
)
113 _Unwind_Ptr vaddr
= phdr
->p_vaddr
+ load_base
;
114 if (data
->pc
>= vaddr
&& data
->pc
< vaddr
+ phdr
->p_memsz
)
117 else if (phdr
->p_type
== PT_GNU_EH_FRAME
)
118 p_eh_frame_hdr
= phdr
;
119 else if (phdr
->p_type
== PT_DYNAMIC
)
122 if (!match
|| !p_eh_frame_hdr
)
125 /* Read .eh_frame_hdr header. */
126 hdr
= (const struct unw_eh_frame_hdr
*)
127 (p_eh_frame_hdr
->p_vaddr
+ load_base
);
128 if (hdr
->version
!= 1)
131 #ifdef CRT_GET_RFIB_DATA
136 /* For dynamicly linked executables and shared libraries,
137 DT_PLTGOT is the gp value for that object. */
138 ElfW(Dyn
) *dyn
= (ElfW(Dyn
) *)(p_dynamic
->p_vaddr
+ load_base
);
139 for (; dyn
->d_tag
!= DT_NULL
; dyn
++)
140 if (dyn
->d_tag
== DT_PLTGOT
)
142 /* On IA-32, _DYNAMIC is writable and GLIBC has relocated it. */
143 data
->dbase
= (void *) dyn
->d_un
.d_ptr
;
148 # error What is DW_EH_PE_datarel base on this platform?
151 #ifdef CRT_GET_RFIB_TEXT
152 # error What is DW_EH_PE_textrel base on this platform?
155 p
= read_encoded_value_with_base (hdr
->eh_frame_ptr_enc
,
156 base_from_cb_data (hdr
->eh_frame_ptr_enc
,
158 (const unsigned char *) (hdr
+ 1),
161 /* We require here specific table encoding to speed things up.
162 Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
163 as base, not the processor specific DW_EH_PE_datarel. */
164 if (hdr
->fde_count_enc
!= DW_EH_PE_omit
165 && hdr
->table_enc
== (DW_EH_PE_datarel
| DW_EH_PE_sdata4
))
167 _Unwind_Ptr fde_count
;
169 p
= read_encoded_value_with_base (hdr
->fde_count_enc
,
170 base_from_cb_data (hdr
->fde_count_enc
,
173 /* Shouldn't happen. */
176 if ((((_Unwind_Ptr
) p
) & 3) == 0)
179 signed initial_loc
__attribute__ ((mode (SI
)));
180 signed fde
__attribute__ ((mode (SI
)));
182 const struct fde_table
*table
= (const struct fde_table
*) p
;
184 _Unwind_Ptr data_base
= (_Unwind_Ptr
) hdr
;
186 unsigned int f_enc
, f_enc_size
;
190 if (data
->pc
< table
[0].initial_loc
+ data_base
)
192 else if (data
->pc
< table
[mid
].initial_loc
+ data_base
)
200 if (data
->pc
< table
[mid
].initial_loc
+ data_base
)
202 else if (data
->pc
>= table
[mid
+ 1].initial_loc
+ data_base
)
212 f
= (fde
*) (table
[mid
].fde
+ data_base
);
213 f_enc
= get_fde_encoding (f
);
214 f_enc_size
= size_of_encoded_value (f_enc
);
215 read_encoded_value_with_base (f_enc
& 0x0f, 0,
216 &f
->pc_begin
[f_enc_size
], &range
);
217 if (data
->pc
< table
[mid
].initial_loc
+ data_base
+ range
)
219 data
->func
= (void *) (table
[mid
].initial_loc
+ data_base
);
224 /* We have no sorted search table, so need to go the slow way.
225 As soon as GLIBC will provide API so to notify that a library has been
226 removed, we could cache this (and thus use search_object). */
228 ob
.tbase
= data
->tbase
;
229 ob
.dbase
= data
->dbase
;
230 ob
.u
.single
= (fde
*) eh_frame
;
232 ob
.s
.b
.mixed_encoding
= 1; /* Need to assume worst case. */
233 data
->ret
= linear_search_fdes (&ob
, (fde
*) eh_frame
, (void *) data
->pc
);
234 if (data
->ret
!= NULL
)
236 unsigned int encoding
= get_fde_encoding (data
->ret
);
238 read_encoded_value_with_base (encoding
,
239 base_from_cb_data (encoding
, data
),
240 data
->ret
->pc_begin
, &func
);
241 data
->func
= (void *) 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
;