1 #include <dlfcn.h>
2 #include <link.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <gnu/lib-names.h>
7 #include <first-versions.h>
8 
9 int test (FILE *out, int a);
10 
11 int
test(FILE * out,int a)12 test (FILE *out, int a)
13 {
14   fputs ("in modstatic2.c (test)\n", out);
15 
16   void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY);
17   if (handle == NULL)
18     fprintf (out, "nonexistent: %s\n", dlerror ());
19   else
20     exit (1);
21 
22   handle = dlopen ("modstatic2.so", RTLD_LAZY);
23   if (handle == NULL)
24     {
25       fprintf (out, "%s\n", dlerror ());
26       exit (1);
27     }
28 
29   int (*test2) (FILE *, int);
30   test2 = dlsym (handle, "test");
31   if (test2 == NULL)
32     {
33       fprintf (out, "%s\n", dlerror ());
34       exit (1);
35     }
36   if (test2 != test)
37     {
38       fprintf (out, "test %p != test2 %p\n", test, test2);
39       exit (1);
40     }
41 
42   Dl_info info;
43   int res = dladdr (test2, &info);
44   if (res == 0)
45     {
46       fputs ("dladdr returned 0\n", out);
47       exit (1);
48     }
49   else
50     {
51       if (strstr (info.dli_fname, "modstatic2.so") == NULL
52 	  || strcmp (info.dli_sname, "test") != 0)
53 	{
54 	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
55 	  exit (1);
56 	}
57       if (info.dli_saddr != (void *) test2)
58 	{
59 	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2);
60 	  exit (1);
61 	}
62     }
63 
64   ElfW(Sym) *sym;
65   void *symp;
66   res = dladdr1 (test2, &info, &symp, RTLD_DL_SYMENT);
67   if (res == 0)
68     {
69       fputs ("dladdr1 returned 0\n", out);
70       exit (1);
71     }
72   else
73     {
74       if (strstr (info.dli_fname, "modstatic2.so") == NULL
75 	  || strcmp (info.dli_sname, "test") != 0)
76 	{
77 	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
78 	  exit (1);
79 	}
80       if (info.dli_saddr != (void *) test2)
81 	{
82 	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2);
83 	  exit (1);
84 	}
85       sym = symp;
86       if (sym == NULL)
87 	{
88 	  fputs ("sym == NULL\n", out);
89 	  exit (1);
90 	}
91       if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
92 	  || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
93 	{
94 	  fprintf (out, "bind %d visibility %d\n",
95 		   (int) ELF32_ST_BIND (sym->st_info),
96 		   (int) ELF32_ST_VISIBILITY (sym->st_other));
97 	  exit (1);
98 	}
99     }
100 
101   Lmid_t lmid;
102   res = dlinfo (handle, RTLD_DI_LMID, &lmid);
103   if (res != 0)
104     {
105       fprintf (out, "dlinfo returned %d %s\n", res, dlerror ());
106       exit (1);
107     }
108   else if (lmid != LM_ID_BASE)
109     {
110       fprintf (out, "lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE);
111       exit (1);
112     }
113 
114   void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY);
115   if (handle2 == NULL)
116     {
117       fprintf (out, "libdl.so: %s\n", dlerror ());
118       exit (1);
119     }
120 
121   /* _exit is very unlikely to receive a second symbol version.  */
122   void *exit_ptr = dlvsym (handle2, "_exit", FIRST_VERSION_libc__exit_STRING);
123   if (exit_ptr == NULL)
124     {
125       fprintf (out, "dlvsym: %s\n", dlerror ());
126       exit (1);
127     }
128   if (exit_ptr != dlsym (handle2, "_exit"))
129     {
130       fprintf (out, "dlvsym for _exit does not match dlsym\n");
131       exit (1);
132     }
133 
134   void *(*dlsymfn) (void *, const char *);
135   dlsymfn = dlsym (handle2, "dlsym");
136   if (dlsymfn == NULL)
137     {
138       fprintf (out, "dlsym \"dlsym\": %s\n", dlerror ());
139       exit (1);
140     }
141   void *test3 = dlsymfn (handle, "test");
142   if (test3 == NULL)
143     {
144       fprintf (out, "%s\n", dlerror ());
145       exit (1);
146     }
147   else if (test3 != (void *) test2)
148     {
149       fprintf (out, "test2 %p != test3 %p\n", test2, test3);
150       exit (1);
151     }
152 
153   dlclose (handle2);
154   dlclose (handle);
155 
156   handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY);
157   if (handle == NULL)
158     {
159       fprintf (out, "%s\n", dlerror ());
160       exit (1);
161     }
162   dlclose (handle);
163 
164   handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY);
165   if (handle == NULL)
166     fprintf (out, "LM_ID_NEWLM: %s\n", dlerror ());
167   else
168     {
169       fputs ("LM_ID_NEWLM unexpectedly succeeded\n", out);
170       exit (1);
171     }
172 
173   handle = dlopen ("modstatic.so", RTLD_LAZY);
174   if (handle == NULL)
175     {
176       fprintf (out, "%s\n", dlerror ());
177       exit (1);
178     }
179 
180   int (*test4) (int);
181   test4 = dlsym (handle, "test");
182   if (test4 == NULL)
183     {
184       fprintf (out, "%s\n", dlerror ());
185       exit (1);
186     }
187 
188   res = test4 (16);
189   if (res != 16 + 16)
190     {
191       fprintf (out, "modstatic.so (test) returned %d\n", res);
192       exit (1);
193     }
194 
195   res = dladdr1 (test4, &info, &symp, RTLD_DL_SYMENT);
196   if (res == 0)
197     {
198       fputs ("dladdr1 returned 0\n", out);
199       exit (1);
200     }
201   else
202     {
203       if (strstr (info.dli_fname, "modstatic.so") == NULL
204 	  || strcmp (info.dli_sname, "test") != 0)
205 	{
206 	  fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname);
207 	  exit (1);
208 	}
209       if (info.dli_saddr != (void *) test4)
210 	{
211 	  fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test4);
212 	  exit (1);
213 	}
214       sym = symp;
215       if (sym == NULL)
216 	{
217 	  fputs ("sym == NULL\n", out);
218 	  exit (1);
219 	}
220       if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL
221 	  || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT)
222 	{
223 	  fprintf (out, "bind %d visibility %d\n",
224 		   (int) ELF32_ST_BIND (sym->st_info),
225 		   (int) ELF32_ST_VISIBILITY (sym->st_other));
226 	  exit (1);
227 	}
228     }
229 
230   dlclose (handle);
231 
232   fputs ("leaving modstatic2.c (test)\n", out);
233   return a + a;
234 }
235