| /* Copyright (C) 2004-2016 Free Software Foundation, Inc. | 
 |    This file is part of the GNU C Library. | 
 |    Contributed by David Mosberger <davidm@hpl.hp.com>, 2004. | 
 |  | 
 |    The GNU C Library is free software; you can redistribute it and/or | 
 |    modify it under the terms of the GNU Lesser General Public | 
 |    License as published by the Free Software Foundation; either | 
 |    version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |    The GNU C Library is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |    Lesser General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU Lesser General Public | 
 |    License along with the GNU C Library; if not, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include <link.h> | 
 | #include <stddef.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 |  | 
 | #define SET	0 | 
 | #define ADD	1 | 
 | #define REMOVE	2 | 
 |  | 
 | #define leq(l,r)	(((r) - (l)) <= ~0ULL / 2) | 
 |  | 
 | static int | 
 | callback (struct dl_phdr_info *info, size_t size, void *ptr) | 
 | { | 
 |   static int last_adds = 0, last_subs = 0; | 
 |   intptr_t cmd = (intptr_t) ptr; | 
 |  | 
 |   printf ("  size = %Zu\n", size); | 
 |   if (size < (offsetof (struct dl_phdr_info, dlpi_subs) | 
 | 	      + sizeof (info->dlpi_subs))) | 
 |     { | 
 |       fprintf (stderr, "dl_iterate_phdr failed to pass dlpi_adds/dlpi_subs\n"); | 
 |       exit (5); | 
 |     } | 
 |  | 
 |   printf ("  dlpi_adds = %Lu dlpi_subs = %Lu\n", | 
 | 	  info->dlpi_adds, info->dlpi_subs); | 
 |  | 
 |   switch (cmd) | 
 |     { | 
 |     case SET: | 
 |       break; | 
 |  | 
 |     case ADD: | 
 |       if (leq (info->dlpi_adds, last_adds)) | 
 | 	{ | 
 | 	  fprintf (stderr, "dlpi_adds failed to get incremented!\n"); | 
 | 	  exit (3); | 
 | 	} | 
 |       break; | 
 |  | 
 |     case REMOVE: | 
 |       if (leq (info->dlpi_subs, last_subs)) | 
 | 	{ | 
 | 	  fprintf (stderr, "dlpi_subs failed to get incremented!\n"); | 
 | 	  exit (4); | 
 | 	} | 
 |       break; | 
 |     } | 
 |   last_adds = info->dlpi_adds; | 
 |   last_subs = info->dlpi_subs; | 
 |   return -1; | 
 | } | 
 |  | 
 | static void * | 
 | load (const char *path) | 
 | { | 
 |   void *handle; | 
 |  | 
 |   printf ("loading `%s'\n", path); | 
 |   handle = dlopen (path, RTLD_LAZY); | 
 |   if (!handle) | 
 |     exit (1); | 
 |   dl_iterate_phdr (callback, (void *)(intptr_t) ADD); | 
 |   return handle; | 
 | } | 
 |  | 
 | static void | 
 | unload (const char *path, void *handle) | 
 | { | 
 |   printf ("unloading `%s'\n", path); | 
 |   if (dlclose (handle) < 0) | 
 |     exit (2); | 
 |   dl_iterate_phdr (callback, (void *)(intptr_t) REMOVE); | 
 | } | 
 |  | 
 | static int | 
 | do_test (void) | 
 | { | 
 |   void *handle1, *handle2; | 
 |  | 
 |   dl_iterate_phdr (callback, (void *)(intptr_t) SET); | 
 |   handle1 = load ("firstobj.so"); | 
 |   handle2 = load ("globalmod1.so"); | 
 |   unload ("firstobj.so", handle1); | 
 |   unload ("globalmod1.so", handle2); | 
 |   return 0; | 
 | } | 
 |  | 
 | #define TEST_FUNCTION do_test () | 
 | #include "../test-skeleton.c" |