]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/tst-dl_find_object.c
elf: Add _dl_find_object function
[thirdparty/glibc.git] / elf / tst-dl_find_object.c
CommitLineData
5d28a896
FW
1/* Basic tests for _dl_find_object.
2 Copyright (C) 2021 Free Software Foundation, Inc.
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#include <dl-find_object.h>
20#include <dlfcn.h>
21#include <gnu/lib-names.h>
22#include <ldsodefs.h>
23#include <link.h>
24#include <stdio.h>
25#include <support/check.h>
26#include <support/xdlfcn.h>
27
28/* Use data objects for testing, so that it is not necessary to decode
29 function descriptors on architectures that have them. */
30static char main_program_data;
31
32/* Computes the expected _dl_find_object result directly from the
33 map. */
34static void
35from_map (struct link_map *l, struct dl_find_object *expected)
36{
37 struct dl_find_object_internal internal;
38 _dl_find_object_from_map (l, &internal);
39 _dl_find_object_to_external (&internal, expected);
40}
41
42/* Compare _dl_find_object result at ADDRESS with *EXPECTED. */
43static void
44check (void *address,
45 struct dl_find_object *expected, int line)
46{
47 struct dl_find_object actual;
48 int ret = _dl_find_object (address, &actual);
49 if (expected == NULL)
50 {
51 if (ret != -1)
52 {
53 support_record_failure ();
54 printf ("%s:%d: unexpected success for %p\n",
55 __FILE__, line, address);
56 }
57 return;
58 }
59 if (ret != 0)
60 {
61 support_record_failure ();
62 printf ("%s:%d: unexpected failure for %p\n",
63 __FILE__, line, address);
64 return;
65 }
66
67 if (actual.dlfo_flags != expected->dlfo_flags)
68 {
69 support_record_failure ();
70 printf ("%s:%d: error: %p: flags is %llu, expected %llu\n",
71 __FILE__, line, address,
72 actual.dlfo_flags, expected->dlfo_flags);
73 }
74 if (actual.dlfo_flags != expected->dlfo_flags)
75 {
76 support_record_failure ();
77 printf ("%s:%d: error: %p: map start is %p, expected %p\n",
78 __FILE__, line,
79 address, actual.dlfo_map_start, expected->dlfo_map_start);
80 }
81 if (actual.dlfo_map_end != expected->dlfo_map_end)
82 {
83 support_record_failure ();
84 printf ("%s:%d: error: %p: map end is %p, expected %p\n",
85 __FILE__, line,
86 address, actual.dlfo_map_end, expected->dlfo_map_end);
87 }
88 if (actual.dlfo_link_map != expected->dlfo_link_map)
89 {
90 support_record_failure ();
91 printf ("%s:%d: error: %p: link map is %p, expected %p\n",
92 __FILE__, line,
93 address, actual.dlfo_link_map, expected->dlfo_link_map);
94 }
95 if (actual.dlfo_eh_frame != expected->dlfo_eh_frame)
96 {
97 support_record_failure ();
98 printf ("%s:%d: error: %p: EH frame is %p, expected %p\n",
99 __FILE__, line,
100 address, actual.dlfo_eh_frame, expected->dlfo_eh_frame);
101 }
102#if DLFO_STRUCT_HAS_EH_DBASE
103 if (actual.dlfo_eh_dbase != expected->dlfo_eh_dbase)
104 {
105 support_record_failure ();
106 printf ("%s:%d: error: %p: data base is %p, expected %p\n",
107 __FILE__, line,
108 address, actual.dlfo_eh_dbase, expected->dlfo_eh_dbase);
109 }
110#endif
111#if DLFO_STRUCT_HAS_EH_COUNT
112 if (actual.dlfo_eh_count != expected->dlfo_eh_count)
113 {
114 support_record_failure ();
115 printf ("%s:%d: error: %p: count is %d, expected %d\n",
116 __FILE__, line,
117 address, actual.dlfo_eh_count, expected->dlfo_eh_count);
118 }
119#endif
120}
121
122/* Check that unwind data for the main executable and the dynamic
123 linker can be found. */
124static void
125check_initial (void)
126{
127#ifndef FOR_STATIC
128 /* Avoid direct reference, which could lead to copy relocations. */
129 struct r_debug *debug = xdlsym (NULL, "_r_debug");
130 TEST_VERIFY_EXIT (debug != NULL);
131 char **tzname = xdlsym (NULL, "tzname");
132
133 /* The main executable has an unnamed link map. */
134 struct link_map *main_map = (struct link_map *) debug->r_map;
135 TEST_COMPARE_STRING (main_map->l_name, "");
136
137 /* The link map of the dynamic linker. */
138 struct link_map *rtld_map = xdlopen (LD_SO, RTLD_LAZY | RTLD_NOLOAD);
139 TEST_VERIFY_EXIT (rtld_map != NULL);
140
141 /* The link map of libc.so. */
142 struct link_map *libc_map = xdlopen (LIBC_SO, RTLD_LAZY | RTLD_NOLOAD);
143 TEST_VERIFY_EXIT (libc_map != NULL);
144
145 struct dl_find_object expected;
146
147 /* Data in the main program. */
148 from_map (main_map, &expected);
149 check (&main_program_data, &expected, __LINE__);
150 /* Corner cases for the mapping. */
151 check ((void *) main_map->l_map_start, &expected, __LINE__);
152 check ((void *) (main_map->l_map_end - 1), &expected, __LINE__);
153
154 /* Data in the dynamic loader. */
155 from_map (rtld_map, &expected);
156 check (debug, &expected, __LINE__);
157 check ((void *) rtld_map->l_map_start, &expected, __LINE__);
158 check ((void *) (rtld_map->l_map_end - 1), &expected, __LINE__);
159
160 /* Data in libc. */
161 from_map (libc_map, &expected);
162 check (tzname, &expected, __LINE__);
163 check ((void *) libc_map->l_map_start, &expected, __LINE__);
164 check ((void *) (libc_map->l_map_end - 1), &expected, __LINE__);
165#endif
166}
167
168static int
169do_test (void)
170{
171 {
172 struct dl_find_object dlfo = { };
173 int ret = _dl_find_object (&main_program_data, &dlfo);
174 printf ("info: main program unwind data: %p (%d)\n",
175 dlfo.dlfo_eh_frame, ret);
176 TEST_COMPARE (ret, 0);
177 TEST_VERIFY (dlfo.dlfo_eh_frame != NULL);
178 }
179
180 check_initial ();
181
182 /* dlopen-based test. First an object that can be dlclosed. */
183 struct link_map *mod1 = xdlopen ("tst-dl_find_object-mod1.so", RTLD_NOW);
184 void *mod1_data = xdlsym (mod1, "mod1_data");
185 void *map_start = (void *) mod1->l_map_start;
186 void *map_end = (void *) (mod1->l_map_end - 1);
187 check_initial ();
188
189 struct dl_find_object expected;
190 from_map (mod1, &expected);
191 check (mod1_data, &expected, __LINE__);
192 check (map_start, &expected, __LINE__);
193 check (map_end, &expected, __LINE__);
194
195 /* Unloading must make the data unavailable. */
196 xdlclose (mod1);
197 check_initial ();
198 check (mod1_data, NULL, __LINE__);
199 check (map_start, NULL, __LINE__);
200 check (map_end, NULL, __LINE__);
201
202 /* Now try a NODELETE load. */
203 struct link_map *mod2 = xdlopen ("tst-dl_find_object-mod2.so", RTLD_NOW);
204 void *mod2_data = xdlsym (mod1, "mod2_data");
205 map_start = (void *) mod2->l_map_start;
206 map_end = (void *) (mod2->l_map_end - 1);
207 check_initial ();
208 from_map (mod2, &expected);
209 check (mod2_data, &expected, __LINE__);
210 check (map_start, &expected, __LINE__);
211 check (map_end, &expected, __LINE__);
212 dlclose (mod2); /* Does nothing due to NODELETE. */
213 check_initial ();
214 check (mod2_data, &expected, __LINE__);
215 check (map_start, &expected, __LINE__);
216 check (map_end, &expected, __LINE__);
217
218 /* Now load again the first module. */
219 mod1 = xdlopen ("tst-dl_find_object-mod1.so", RTLD_NOW);
220 mod1_data = xdlsym (mod1, "mod1_data");
221 map_start = (void *) mod1->l_map_start;
222 map_end = (void *) (mod1->l_map_end - 1);
223 check_initial ();
224 from_map (mod1, &expected);
225 check (mod1_data, &expected, __LINE__);
226 check (map_start, &expected, __LINE__);
227 check (map_end, &expected, __LINE__);
228
229 /* Check that _dl_find_object works from a shared object (mostly for
230 static dlopen). */
231 __typeof (_dl_find_object) *find_object
232 = *(void **) xdlsym (mod2, "find_object");
233 struct dl_find_object actual;
234 TEST_COMPARE (find_object (&main_program_data, &actual), 0);
235 check (&main_program_data, &actual, __LINE__); /* Reversed check. */
236
237 return 0;
238}
239
240#include <support/test-driver.c>