1 | #include <assert.h> |
2 | #include <dlfcn.h> |
3 | #include <errno.h> |
4 | #include <error.h> |
5 | #include <mcheck.h> |
6 | #include <stdio.h> |
7 | #include <stdlib.h> |
8 | #include <string.h> |
9 | |
10 | |
11 | /* How many load/unload operations do we do. */ |
12 | #define TEST_ROUNDS 1000 |
13 | |
14 | |
15 | static struct |
16 | { |
17 | /* Name of the module. */ |
18 | const char *name; |
19 | /* The handle. */ |
20 | void *handle; |
21 | } testobjs[] = |
22 | { |
23 | { "testobj1.so" , NULL }, |
24 | { "testobj2.so" , NULL }, |
25 | { "testobj3.so" , NULL }, |
26 | { "testobj4.so" , NULL }, |
27 | { "testobj5.so" , NULL }, |
28 | { "testobj6.so" , NULL }, |
29 | }; |
30 | #define NOBJS (sizeof (testobjs) / sizeof (testobjs[0])) |
31 | |
32 | |
33 | static const struct |
34 | { |
35 | /* Name of a function to call. */ |
36 | const char *fname; |
37 | /* Index in status and handle array. */ |
38 | int index; |
39 | /* Options while loading the module. */ |
40 | int options; |
41 | } tests[] = |
42 | { |
43 | { "obj1func2" , 0, RTLD_LAZY }, |
44 | { "obj1func1" , 0, RTLD_LAZY | RTLD_GLOBAL }, |
45 | { "obj1func1" , 0, RTLD_NOW, }, |
46 | { "obj1func2" , 0, RTLD_NOW | RTLD_GLOBAL }, |
47 | { "obj2func2" , 1, RTLD_LAZY }, |
48 | { "obj2func1" , 1, RTLD_LAZY | RTLD_GLOBAL, }, |
49 | { "obj2func1" , 1, RTLD_NOW, }, |
50 | { "obj2func2" , 1, RTLD_NOW | RTLD_GLOBAL }, |
51 | { "obj3func2" , 2, RTLD_LAZY }, |
52 | { "obj3func1" , 2, RTLD_LAZY | RTLD_GLOBAL }, |
53 | { "obj3func1" , 2, RTLD_NOW }, |
54 | { "obj3func2" , 2, RTLD_NOW | RTLD_GLOBAL }, |
55 | { "obj4func2" , 3, RTLD_LAZY }, |
56 | { "obj4func1" , 3, RTLD_LAZY | RTLD_GLOBAL }, |
57 | { "obj4func1" , 3, RTLD_NOW }, |
58 | { "obj4func2" , 3, RTLD_NOW | RTLD_GLOBAL }, |
59 | { "obj5func2" , 4, RTLD_LAZY }, |
60 | { "obj5func1" , 4, RTLD_LAZY | RTLD_GLOBAL }, |
61 | { "obj5func1" , 4, RTLD_NOW }, |
62 | { "obj5func2" , 4, RTLD_NOW | RTLD_GLOBAL }, |
63 | { "obj6func2" , 5, RTLD_LAZY }, |
64 | { "obj6func1" , 5, RTLD_LAZY | RTLD_GLOBAL }, |
65 | { "obj6func1" , 5, RTLD_NOW }, |
66 | { "obj6func2" , 5, RTLD_NOW | RTLD_GLOBAL }, |
67 | }; |
68 | #define NTESTS (sizeof (tests) / sizeof (tests[0])) |
69 | |
70 | |
71 | #include <include/link.h> |
72 | |
73 | #define MAPS ((struct link_map *) _r_debug.r_map) |
74 | |
75 | #define OUT \ |
76 | do \ |
77 | { \ |
78 | for (map = MAPS; map != NULL; map = map->l_next) \ |
79 | if (map->l_type == lt_loaded) \ |
80 | printf ("name = \"%s\", direct_opencount = %d\n", \ |
81 | map->l_name, (int) map->l_direct_opencount); \ |
82 | fflush (stdout); \ |
83 | } \ |
84 | while (0) |
85 | |
86 | |
87 | int |
88 | main (int argc, char *argv[]) |
89 | { |
90 | int debug = argc > 1 && argv[1][0] != '\0'; |
91 | int count = TEST_ROUNDS; |
92 | int result = 0; |
93 | struct link_map *map; |
94 | |
95 | mtrace (); |
96 | |
97 | /* Just a seed. */ |
98 | srandom (TEST_ROUNDS); |
99 | |
100 | if (debug) |
101 | { |
102 | puts (s: "in the beginning" ); |
103 | OUT; |
104 | } |
105 | |
106 | while (count--) |
107 | { |
108 | int nr = random () % NTESTS; |
109 | int index = tests[nr].index; |
110 | |
111 | printf (format: "%4d: %4d: " , count + 1, nr); |
112 | fflush (stdout); |
113 | |
114 | if (testobjs[index].handle == NULL) |
115 | { |
116 | int (*fct) (int); |
117 | |
118 | /* Load the object. */ |
119 | testobjs[index].handle = dlopen (file: testobjs[index].name, |
120 | mode: tests[nr].options); |
121 | if (testobjs[index].handle == NULL) |
122 | error (EXIT_FAILURE, errnum: 0, format: "cannot load `%s': %s" , |
123 | testobjs[index].name, dlerror ()); |
124 | |
125 | /* Test the function call. */ |
126 | fct = dlsym (handle: testobjs[index].handle, name: tests[nr].fname); |
127 | if (fct == NULL) |
128 | error (EXIT_FAILURE, errnum: 0, |
129 | format: "cannot get function `%s' from shared object `%s': %s" , |
130 | tests[nr].fname, testobjs[index].name, dlerror ()); |
131 | |
132 | fct (10); |
133 | |
134 | printf (format: "successfully loaded `%s', handle %p\n" , |
135 | testobjs[index].name, testobjs[index].handle); |
136 | } |
137 | else |
138 | { |
139 | if (dlclose (handle: testobjs[index].handle) != 0) |
140 | { |
141 | printf (format: "failed to close %s\n" , testobjs[index].name); |
142 | result = 1; |
143 | } |
144 | else |
145 | printf (format: "successfully unloaded `%s', handle %p\n" , |
146 | testobjs[index].name, testobjs[index].handle); |
147 | |
148 | testobjs[index].handle = NULL; |
149 | |
150 | if (testobjs[0].handle == NULL |
151 | && testobjs[1].handle == NULL |
152 | && testobjs[5].handle == NULL) |
153 | { |
154 | /* In this case none of the objects above should be |
155 | present. */ |
156 | for (map = MAPS; map != NULL; map = map->l_next) |
157 | if (map->l_type == lt_loaded |
158 | && (strstr (haystack: map->l_name, needle: testobjs[0].name) != NULL |
159 | || strstr (haystack: map->l_name, needle: testobjs[1].name) != NULL |
160 | || strstr (haystack: map->l_name, needle: testobjs[5].name) != NULL)) |
161 | { |
162 | printf (format: "`%s' is still loaded\n" , map->l_name); |
163 | result = 1; |
164 | } |
165 | } |
166 | } |
167 | |
168 | if (debug) |
169 | OUT; |
170 | } |
171 | |
172 | /* Unload all loaded modules. */ |
173 | for (count = 0; count < (int) NOBJS; ++count) |
174 | if (testobjs[count].handle != NULL) |
175 | { |
176 | printf (format: "\nclose: %s: l_initfini = %p, l_versions = %p\n" , |
177 | testobjs[count].name, |
178 | ((struct link_map *) testobjs[count].handle)->l_initfini, |
179 | ((struct link_map *) testobjs[count].handle)->l_versions); |
180 | |
181 | if (dlclose (handle: testobjs[count].handle) != 0) |
182 | { |
183 | printf (format: "failed to close %s\n" , testobjs[count].name); |
184 | result = 1; |
185 | } |
186 | } |
187 | |
188 | /* Check whether all files are unloaded. */ |
189 | for (map = MAPS; map != NULL; map = map->l_next) |
190 | if (map->l_type == lt_loaded) |
191 | { |
192 | printf (format: "name = \"%s\", direct_opencount = %d\n" , |
193 | map->l_name, (int) map->l_direct_opencount); |
194 | result = 1; |
195 | } |
196 | |
197 | return result; |
198 | } |
199 | |
200 | |
201 | extern int foo (int a); |
202 | int |
203 | foo (int a) |
204 | { |
205 | return a - 1; |
206 | } |
207 | |