(root)/
glibc-2.38/
dlfcn/
tst-dlinfo-phdr.c
       1  /* Test for dlinfo (RTLD_DI_PHDR).
       2     Copyright (C) 2022-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 <dlfcn.h>
      20  #include <link.h>
      21  #include <stdbool.h>
      22  #include <stdio.h>
      23  #include <string.h>
      24  #include <sys/auxv.h>
      25  
      26  #include <support/check.h>
      27  #include <support/xdlfcn.h>
      28  
      29  /* Used to verify that the program header array appears as expected
      30     among the dl_iterate_phdr callback invocations.  */
      31  
      32  struct dlip_callback_args
      33  {
      34    struct link_map *l;           /* l->l_addr is used to find the object.  */
      35    const ElfW(Phdr) *phdr;       /* Expected program header pointed.  */
      36    int phnum;                    /* Expected program header count.  */
      37    bool found;                   /* True if l->l_addr has been found.  */
      38  };
      39  
      40  static int
      41  dlip_callback (struct dl_phdr_info *dlpi, size_t size, void *closure)
      42  {
      43    TEST_COMPARE (sizeof (*dlpi), size);
      44    struct dlip_callback_args *args = closure;
      45  
      46    if (dlpi->dlpi_addr == args->l->l_addr)
      47      {
      48        TEST_VERIFY (!args->found);
      49        args->found = true;
      50        TEST_VERIFY (args->phdr == dlpi->dlpi_phdr);
      51        TEST_COMPARE (args->phnum, dlpi->dlpi_phnum);
      52      }
      53  
      54    return 0;
      55  }
      56  
      57  static int
      58  do_test (void)
      59  {
      60    /* Avoid a copy relocation.  */
      61    struct r_debug *debug = xdlsym (RTLD_DEFAULT, "_r_debug");
      62    struct link_map *l = (struct link_map *) debug->r_map;
      63    TEST_VERIFY_EXIT (l != NULL);
      64  
      65    do
      66      {
      67        printf ("info: checking link map %p (%p) for \"%s\"\n",
      68                l, l->l_phdr, l->l_name);
      69  
      70        /* Cause dlerror () to return an error message.  */
      71        dlsym (RTLD_DEFAULT, "does-not-exist");
      72  
      73        /* Use the extension that link maps are valid dlopen handles.  */
      74        const ElfW(Phdr) *phdr;
      75        int phnum = dlinfo (l, RTLD_DI_PHDR, &phdr);
      76        TEST_VERIFY (phnum >= 0);
      77        /* Verify that the error message has been cleared.  */
      78        TEST_COMPARE_STRING (dlerror (), NULL);
      79  
      80        TEST_VERIFY (phdr == l->l_phdr);
      81        TEST_COMPARE (phnum, l->l_phnum);
      82  
      83        /* Check that we can find PT_DYNAMIC among the array.  */
      84        {
      85          bool dynamic_found = false;
      86          for (int i = 0; i < phnum; ++i)
      87            if (phdr[i].p_type == PT_DYNAMIC)
      88              {
      89                dynamic_found = true;
      90                TEST_COMPARE ((ElfW(Addr)) l->l_ld, l->l_addr + phdr[i].p_vaddr);
      91              }
      92          TEST_VERIFY (dynamic_found);
      93        }
      94  
      95        /* Check that dl_iterate_phdr finds the link map with the same
      96           program headers.  */
      97        {
      98          struct dlip_callback_args args =
      99            {
     100              .l =  l,
     101              .phdr = phdr,
     102              .phnum = phnum,
     103              .found = false,
     104            };
     105          TEST_COMPARE (dl_iterate_phdr (dlip_callback, &args), 0);
     106          TEST_VERIFY (args.found);
     107        }
     108  
     109        if (l->l_prev == NULL)
     110          {
     111            /* This is the executable, so the information is also
     112               available via getauxval.  */
     113            TEST_COMPARE_STRING (l->l_name, "");
     114            TEST_VERIFY (phdr == (const ElfW(Phdr) *) getauxval (AT_PHDR));
     115            TEST_COMPARE (phnum, getauxval (AT_PHNUM));
     116          }
     117  
     118        l = l->l_next;
     119      }
     120    while (l != NULL);
     121  
     122    return 0;
     123  }
     124  
     125  #include <support/test-driver.c>