(root)/
glibc-2.38/
elf/
tst-dl_find_object.c
       1  /* Basic tests for _dl_find_object.
       2     Copyright (C) 2021-2023 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.  */
      30  static char main_program_data;
      31  
      32  /* Computes the expected _dl_find_object result directly from the
      33     map.  */
      34  static void
      35  from_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.  */
      43  static void
      44  check (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 (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 ("%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 ("%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 ("%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 ("%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.  */
     129  static void
     130  check_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  
     173  static int
     174  do_test (void)
     175  {
     176    {
     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);
     183    }
     184  
     185    check_initial ();
     186  
     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);
     192    check_initial ();
     193  
     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__);
     199  
     200    /* Unloading must make the data unavailable.  */
     201    xdlclose (mod1);
     202    check_initial ();
     203    check (mod1_data, NULL, __LINE__);
     204    check (map_start, NULL, __LINE__);
     205    check (map_end, NULL, __LINE__);
     206  
     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);
     212    check_initial ();
     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.  */
     218    check_initial ();
     219    check (mod2_data, &expected, __LINE__);
     220    check (map_start, &expected, __LINE__);
     221    check (map_end, &expected, __LINE__);
     222  
     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);
     228    check_initial ();
     229    from_map (mod1, &expected);
     230    check (mod1_data, &expected, __LINE__);
     231    check (map_start, &expected, __LINE__);
     232    check (map_end, &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 (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.  */
     241  
     242    return 0;
     243  }
     244  
     245  #include <support/test-driver.c>