1 /* Basic tests for _dl_find_object.
2 Copyright (C) 2021-2024 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 #include <dl-find_object.h>
21 #include <gnu/lib-names.h>
25 #include <support/check.h>
26 #include <support/xdlfcn.h>
28 /* Use data objects for testing, so that it is not necessary to decode
29 function descriptors on architectures that have them. */
30 static char main_program_data
;
32 /* Computes the expected _dl_find_object result directly from the
35 from_map (struct link_map
*l
, struct dl_find_object
*expected
)
37 struct dl_find_object_internal internal
;
38 _dl_find_object_from_map (l
, &internal
);
39 _dl_find_object_to_external (&internal
, expected
);
42 /* Compare _dl_find_object result at ADDRESS with *EXPECTED. */
45 struct dl_find_object
*expected
, int line
)
47 struct dl_find_object actual
;
48 int ret
= _dl_find_object (address
, &actual
);
53 support_record_failure ();
54 printf ("%s:%d: unexpected success for %p\n",
55 __FILE__
, line
, address
);
61 support_record_failure ();
62 printf ("%s:%d: unexpected failure for %p\n",
63 __FILE__
, line
, address
);
67 if (actual
.dlfo_flags
!= expected
->dlfo_flags
)
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
);
74 if (expected
->dlfo_link_map
->l_contiguous
)
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
)
80 support_record_failure ();
81 printf ("%s:%d: error: %p: map start is %p, expected %p\n",
83 address
, actual
.dlfo_map_start
, expected
->dlfo_map_start
);
85 if (actual
.dlfo_map_end
!= expected
->dlfo_map_end
)
87 support_record_failure ();
88 printf ("%s:%d: error: %p: map end is %p, expected %p\n",
90 address
, actual
.dlfo_map_end
, expected
->dlfo_map_end
);
93 if (actual
.dlfo_link_map
!= expected
->dlfo_link_map
)
95 support_record_failure ();
96 printf ("%s:%d: error: %p: link map is %p, expected %p\n",
98 address
, actual
.dlfo_link_map
, expected
->dlfo_link_map
);
100 if (actual
.dlfo_eh_frame
!= expected
->dlfo_eh_frame
)
102 support_record_failure ();
103 printf ("%s:%d: error: %p: EH frame is %p, expected %p\n",
105 address
, actual
.dlfo_eh_frame
, expected
->dlfo_eh_frame
);
107 #if DLFO_STRUCT_HAS_EH_DBASE
108 if (actual
.dlfo_eh_dbase
!= expected
->dlfo_eh_dbase
)
110 support_record_failure ();
111 printf ("%s:%d: error: %p: data base is %p, expected %p\n",
113 address
, actual
.dlfo_eh_dbase
, expected
->dlfo_eh_dbase
);
116 #if DLFO_STRUCT_HAS_EH_COUNT
117 if (actual
.dlfo_eh_count
!= expected
->dlfo_eh_count
)
119 support_record_failure ();
120 printf ("%s:%d: error: %p: count is %d, expected %d\n",
122 address
, actual
.dlfo_eh_count
, expected
->dlfo_eh_count
);
127 /* Check that unwind data for the main executable and the dynamic
128 linker can be found. */
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");
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
, "");
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
);
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
);
150 struct dl_find_object expected
;
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__
);
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__
);
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__
);
177 struct dl_find_object dlfo
= { };
178 int ret
= _dl_find_object (&main_program_data
, &dlfo
);
179 printf ("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
);
187 /* dlopen-based test. First an object that can be dlclosed. */
188 struct link_map
*mod1
= xdlopen ("tst-dl_find_object-mod1.so", RTLD_NOW
);
189 void *mod1_data
= xdlsym (mod1
, "mod1_data");
190 void *map_start
= (void *) mod1
->l_map_start
;
191 void *map_end
= (void *) (mod1
->l_map_end
- 1);
194 struct dl_find_object expected
;
195 from_map (mod1
, &expected
);
196 check (mod1_data
, &expected
, __LINE__
);
197 check (map_start
, &expected
, __LINE__
);
198 check (map_end
, &expected
, __LINE__
);
200 /* Unloading must make the data unavailable. */
203 check (mod1_data
, NULL
, __LINE__
);
204 check (map_start
, NULL
, __LINE__
);
205 check (map_end
, NULL
, __LINE__
);
207 /* Now try a NODELETE load. */
208 struct link_map
*mod2
= xdlopen ("tst-dl_find_object-mod2.so", RTLD_NOW
);
209 void *mod2_data
= xdlsym (mod2
, "mod2_data");
210 map_start
= (void *) mod2
->l_map_start
;
211 map_end
= (void *) (mod2
->l_map_end
- 1);
213 from_map (mod2
, &expected
);
214 check (mod2_data
, &expected
, __LINE__
);
215 check (map_start
, &expected
, __LINE__
);
216 check (map_end
, &expected
, __LINE__
);
217 dlclose (mod2
); /* Does nothing due to NODELETE. */
219 check (mod2_data
, &expected
, __LINE__
);
220 check (map_start
, &expected
, __LINE__
);
221 check (map_end
, &expected
, __LINE__
);
223 /* Now load again the first module. */
224 mod1
= xdlopen ("tst-dl_find_object-mod1.so", RTLD_NOW
);
225 mod1_data
= xdlsym (mod1
, "mod1_data");
226 map_start
= (void *) mod1
->l_map_start
;
227 map_end
= (void *) (mod1
->l_map_end
- 1);
229 from_map (mod1
, &expected
);
230 check (mod1_data
, &expected
, __LINE__
);
231 check (map_start
, &expected
, __LINE__
);
232 check (map_end
, &expected
, __LINE__
);
234 /* Check that _dl_find_object works from a shared object (mostly for
236 __typeof (_dl_find_object
) *find_object
237 = *(void **) xdlsym (mod2
, "find_object");
238 struct dl_find_object actual
;
239 TEST_COMPARE (find_object (&main_program_data
, &actual
), 0);
240 check (&main_program_data
, &actual
, __LINE__
); /* Reversed check. */
245 #include <support/test-driver.c>