1/* Basic tests for _dl_find_object.
2 Copyright (C) 2021-2022 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, result: &internal);
39 _dl_find_object_to_external (internal: &internal, external: 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: address, result: &actual);
49 if (expected == NULL)
50 {
51 if (ret != -1)
52 {
53 support_record_failure ();
54 printf (format: "%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 (format: "%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 (format: "%s:%d: error: %p: flags is %llu, expected %llu\n",
71 __FILE__, line, address,
72 actual.dlfo_flags, expected->dlfo_flags);
73 }
74 if (expected->dlfo_link_map->l_contiguous)
75 {
76 /* If the mappings are not contiguous, the actual and execpted
77 mappings may differ, so this subtest will not work. */
78 if (actual.dlfo_flags != expected->dlfo_flags)
79 {
80 support_record_failure ();
81 printf (format: "%s:%d: error: %p: map start is %p, expected %p\n",
82 __FILE__, line,
83 address, actual.dlfo_map_start, expected->dlfo_map_start);
84 }
85 if (actual.dlfo_map_end != expected->dlfo_map_end)
86 {
87 support_record_failure ();
88 printf (format: "%s:%d: error: %p: map end is %p, expected %p\n",
89 __FILE__, line,
90 address, actual.dlfo_map_end, expected->dlfo_map_end);
91 }
92 }
93 if (actual.dlfo_link_map != expected->dlfo_link_map)
94 {
95 support_record_failure ();
96 printf (format: "%s:%d: error: %p: link map is %p, expected %p\n",
97 __FILE__, line,
98 address, actual.dlfo_link_map, expected->dlfo_link_map);
99 }
100 if (actual.dlfo_eh_frame != expected->dlfo_eh_frame)
101 {
102 support_record_failure ();
103 printf (format: "%s:%d: error: %p: EH frame is %p, expected %p\n",
104 __FILE__, line,
105 address, actual.dlfo_eh_frame, expected->dlfo_eh_frame);
106 }
107#if DLFO_STRUCT_HAS_EH_DBASE
108 if (actual.dlfo_eh_dbase != expected->dlfo_eh_dbase)
109 {
110 support_record_failure ();
111 printf ("%s:%d: error: %p: data base is %p, expected %p\n",
112 __FILE__, line,
113 address, actual.dlfo_eh_dbase, expected->dlfo_eh_dbase);
114 }
115#endif
116#if DLFO_STRUCT_HAS_EH_COUNT
117 if (actual.dlfo_eh_count != expected->dlfo_eh_count)
118 {
119 support_record_failure ();
120 printf ("%s:%d: error: %p: count is %d, expected %d\n",
121 __FILE__, line,
122 address, actual.dlfo_eh_count, expected->dlfo_eh_count);
123 }
124#endif
125}
126
127/* Check that unwind data for the main executable and the dynamic
128 linker can be found. */
129static void
130check_initial (void)
131{
132#ifndef FOR_STATIC
133 /* Avoid direct reference, which could lead to copy relocations. */
134 struct r_debug *debug = xdlsym (NULL, "_r_debug");
135 TEST_VERIFY_EXIT (debug != NULL);
136 char **tzname = xdlsym (NULL, "tzname");
137
138 /* The main executable has an unnamed link map. */
139 struct link_map *main_map = (struct link_map *) debug->r_map;
140 TEST_COMPARE_STRING (main_map->l_name, "");
141
142 /* The link map of the dynamic linker. */
143 struct link_map *rtld_map = xdlopen (LD_SO, RTLD_LAZY | RTLD_NOLOAD);
144 TEST_VERIFY_EXIT (rtld_map != NULL);
145
146 /* The link map of libc.so. */
147 struct link_map *libc_map = xdlopen (LIBC_SO, RTLD_LAZY | RTLD_NOLOAD);
148 TEST_VERIFY_EXIT (libc_map != NULL);
149
150 struct dl_find_object expected;
151
152 /* Data in the main program. */
153 from_map (main_map, &expected);
154 check (&main_program_data, &expected, __LINE__);
155 /* Corner cases for the mapping. */
156 check ((void *) main_map->l_map_start, &expected, __LINE__);
157 check ((void *) (main_map->l_map_end - 1), &expected, __LINE__);
158
159 /* Data in the dynamic loader. */
160 from_map (rtld_map, &expected);
161 check (debug, &expected, __LINE__);
162 check ((void *) rtld_map->l_map_start, &expected, __LINE__);
163 check ((void *) (rtld_map->l_map_end - 1), &expected, __LINE__);
164
165 /* Data in libc. */
166 from_map (libc_map, &expected);
167 check (tzname, &expected, __LINE__);
168 check ((void *) libc_map->l_map_start, &expected, __LINE__);
169 check ((void *) (libc_map->l_map_end - 1), &expected, __LINE__);
170#endif
171}
172
173static int
174do_test (void)
175{
176 {
177 struct dl_find_object dlfo = { };
178 int ret = _dl_find_object (address: &main_program_data, result: &dlfo);
179 printf (format: "info: main program unwind data: %p (%d)\n",
180 dlfo.dlfo_eh_frame, ret);
181 TEST_COMPARE (ret, 0);
182 TEST_VERIFY (dlfo.dlfo_eh_frame != NULL);
183 }
184
185 check_initial ();
186
187 /* dlopen-based test. First an object that can be dlclosed. */
188 struct link_map *mod1 = xdlopen (filename: "tst-dl_find_object-mod1.so", RTLD_NOW);
189 void *mod1_data = xdlsym (handle: mod1, symbol: "mod1_data");
190 void *map_start = (void *) mod1->l_map_start;
191 void *map_end = (void *) (mod1->l_map_end - 1);
192 check_initial ();
193
194 struct dl_find_object expected;
195 from_map (l: mod1, expected: &expected);
196 check (address: mod1_data, expected: &expected, __LINE__);
197 check (address: map_start, expected: &expected, __LINE__);
198 check (address: map_end, expected: &expected, __LINE__);
199
200 /* Unloading must make the data unavailable. */
201 xdlclose (handle: mod1);
202 check_initial ();
203 check (address: mod1_data, NULL, __LINE__);
204 check (address: map_start, NULL, __LINE__);
205 check (address: map_end, NULL, __LINE__);
206
207 /* Now try a NODELETE load. */
208 struct link_map *mod2 = xdlopen (filename: "tst-dl_find_object-mod2.so", RTLD_NOW);
209 void *mod2_data = xdlsym (handle: mod2, symbol: "mod2_data");
210 map_start = (void *) mod2->l_map_start;
211 map_end = (void *) (mod2->l_map_end - 1);
212 check_initial ();
213 from_map (l: mod2, expected: &expected);
214 check (address: mod2_data, expected: &expected, __LINE__);
215 check (address: map_start, expected: &expected, __LINE__);
216 check (address: map_end, expected: &expected, __LINE__);
217 dlclose (handle: mod2); /* Does nothing due to NODELETE. */
218 check_initial ();
219 check (address: mod2_data, expected: &expected, __LINE__);
220 check (address: map_start, expected: &expected, __LINE__);
221 check (address: map_end, expected: &expected, __LINE__);
222
223 /* Now load again the first module. */
224 mod1 = xdlopen (filename: "tst-dl_find_object-mod1.so", RTLD_NOW);
225 mod1_data = xdlsym (handle: mod1, symbol: "mod1_data");
226 map_start = (void *) mod1->l_map_start;
227 map_end = (void *) (mod1->l_map_end - 1);
228 check_initial ();
229 from_map (l: mod1, expected: &expected);
230 check (address: mod1_data, expected: &expected, __LINE__);
231 check (address: map_start, expected: &expected, __LINE__);
232 check (address: map_end, expected: &expected, __LINE__);
233
234 /* Check that _dl_find_object works from a shared object (mostly for
235 static dlopen). */
236 __typeof (_dl_find_object) *find_object
237 = *(void **) xdlsym (handle: mod2, symbol: "find_object");
238 struct dl_find_object actual;
239 TEST_COMPARE (find_object (&main_program_data, &actual), 0);
240 check (address: &main_program_data, expected: &actual, __LINE__); /* Reversed check. */
241
242 return 0;
243}
244
245#include <support/test-driver.c>
246

source code of glibc/elf/tst-dl_find_object.c