]>
Commit | Line | Data |
---|---|---|
5d28a896 | 1 | /* Locating objects in the process image. ld.so implementation. |
581c785b | 2 | Copyright (C) 2021-2022 Free Software Foundation, Inc. |
5d28a896 FW |
3 | This file is part of the GNU C Library. |
4 | ||
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. | |
9 | ||
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. | |
14 | ||
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/>. */ | |
18 | ||
19 | #ifndef _DL_FIND_EH_FRAME_H | |
20 | #define _DL_FIND_EH_FRAME_H | |
21 | ||
22 | #include <assert.h> | |
acbaad31 | 23 | #include <atomic.h> |
5d28a896 FW |
24 | #include <dlfcn.h> |
25 | #include <ldsodefs.h> | |
26 | #include <stdbool.h> | |
27 | #include <stdint.h> | |
28 | ||
29 | /* Internal version of struct dl_find_object. Does not include the | |
30 | (yet unused) flags member. We need to make a copy of data also in | |
31 | struct link_map to support non-contiguous mappings, and to support | |
32 | software transactional memory (the link map is not covered by | |
33 | transactions). */ | |
34 | struct dl_find_object_internal | |
35 | { | |
36 | uintptr_t map_start; | |
37 | uintptr_t map_end; /* Set to map_start by dlclose. */ | |
38 | struct link_map *map; /* Set to NULL by dlclose. */ | |
39 | void *eh_frame; | |
40 | #if DLFO_STRUCT_HAS_EH_DBASE | |
41 | void *eh_dbase; | |
42 | #endif | |
43 | #if DLFO_STRUCT_HAS_EH_COUNT | |
44 | int eh_count; | |
45 | #endif | |
46 | }; | |
47 | ||
acbaad31 FW |
48 | /* Create a copy of *SOURCE in *COPY using relaxed MO loads and |
49 | stores. */ | |
50 | static inline void | |
51 | _dl_find_object_internal_copy (const struct dl_find_object_internal *source, | |
52 | struct dl_find_object_internal *copy) | |
53 | { | |
54 | atomic_store_relaxed (©->map_start, | |
55 | atomic_load_relaxed (&source->map_start)); | |
56 | atomic_store_relaxed (©->map_end, | |
57 | atomic_load_relaxed (&source->map_end)); | |
58 | atomic_store_relaxed (©->map, | |
59 | atomic_load_relaxed (&source->map)); | |
60 | atomic_store_relaxed (©->eh_frame, | |
61 | atomic_load_relaxed (&source->eh_frame)); | |
62 | #if DLFO_STRUCT_HAS_EH_DBASE | |
63 | atomic_store_relaxed (©->eh_dbase, | |
64 | atomic_load_relaxed (&source->eh_dbase)); | |
65 | #endif | |
66 | #if DLFO_STRUCT_HAS_EH_COUNT | |
67 | atomic_store_relaxed (©->eh_count, | |
68 | atomic_load_relaxed (&source->eh_count)); | |
69 | #endif | |
70 | } | |
71 | ||
5d28a896 FW |
72 | static inline void |
73 | _dl_find_object_to_external (struct dl_find_object_internal *internal, | |
74 | struct dl_find_object *external) | |
75 | { | |
76 | external->dlfo_flags = 0; | |
77 | external->dlfo_map_start = (void *) internal->map_start; | |
78 | external->dlfo_map_end = (void *) internal->map_end; | |
79 | external->dlfo_link_map = internal->map; | |
80 | external->dlfo_eh_frame = internal->eh_frame; | |
81 | # if DLFO_STRUCT_HAS_EH_DBASE | |
82 | external->dlfo_eh_dbase = internal->eh_dbase; | |
83 | # endif | |
84 | # if DLFO_STRUCT_HAS_EH_COUNT | |
85 | external->dlfo_eh_count = internal->eh_count; | |
86 | # endif | |
87 | } | |
88 | ||
89 | /* Extract the object location data from a link map and writes it to | |
acbaad31 | 90 | *RESULT using relaxed MO stores. */ |
5d28a896 FW |
91 | static void __attribute__ ((unused)) |
92 | _dl_find_object_from_map (struct link_map *l, | |
93 | struct dl_find_object_internal *result) | |
94 | { | |
acbaad31 FW |
95 | atomic_store_relaxed (&result->map_start, (uintptr_t) l->l_map_start); |
96 | atomic_store_relaxed (&result->map_end, (uintptr_t) l->l_map_end); | |
97 | atomic_store_relaxed (&result->map, l); | |
5d28a896 FW |
98 | |
99 | #if DLFO_STRUCT_HAS_EH_DBASE | |
acbaad31 | 100 | atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]); |
5d28a896 FW |
101 | #endif |
102 | ||
103 | for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum; | |
104 | ph < ph_end; ++ph) | |
105 | if (ph->p_type == DLFO_EH_SEGMENT_TYPE) | |
106 | { | |
acbaad31 FW |
107 | atomic_store_relaxed (&result->eh_frame, |
108 | (void *) (ph->p_vaddr + l->l_addr)); | |
5d28a896 | 109 | #if DLFO_STRUCT_HAS_EH_COUNT |
acbaad31 | 110 | atomic_store_relaxed (&result->eh_count, ph->p_memsz / 8); |
5d28a896 FW |
111 | #endif |
112 | return; | |
113 | } | |
114 | ||
115 | /* Object has no exception handling segment. */ | |
acbaad31 | 116 | atomic_store_relaxed (&result->eh_frame, NULL); |
5d28a896 | 117 | #if DLFO_STRUCT_HAS_EH_COUNT |
acbaad31 | 118 | atomic_store_relaxed (&result->eh_count, 0); |
5d28a896 FW |
119 | #endif |
120 | } | |
121 | ||
122 | /* Called by the dynamic linker to set up the data structures for the | |
123 | initially loaded objects. This creates a few persistent | |
124 | allocations, so it should be called with the minimal malloc. */ | |
125 | void _dl_find_object_init (void) attribute_hidden; | |
126 | ||
127 | /* Called by dlopen/dlmopen to add new objects to the DWARF EH frame | |
128 | data structures. NEW_MAP is the dlopen'ed link map. Link maps on | |
129 | the l_next list are added if l_object_processed is 0. Needs to | |
130 | be protected by loader write lock. Returns true on success, false | |
131 | on malloc failure. */ | |
132 | bool _dl_find_object_update (struct link_map *new_map) attribute_hidden; | |
133 | ||
134 | /* Called by dlclose to remove the link map from the DWARF EH frame | |
135 | data structures. Needs to be protected by loader write lock. */ | |
136 | void _dl_find_object_dlclose (struct link_map *l) attribute_hidden; | |
137 | ||
138 | /* Called from __libc_freeres to deallocate malloc'ed memory. */ | |
139 | void _dl_find_object_freeres (void) attribute_hidden; | |
140 | ||
141 | #endif /* _DL_FIND_OBJECT_H */ |