Implement handling of DL_FILTER.
[kopensolaris-gnu/glibc.git] / elf / dl-deps.c
1 /* Load the dependencies of a mapped object.
2    Copyright (C) 1996, 1997 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <link.h>
21 #include <errno.h>
22 #include <dlfcn.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 /* Whether an shared object references one or more auxiliary objects
28    is signaled by the AUXTAG entry in l_info.  */
29 #define AUXTAG  (DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM \
30                  + DT_EXTRATAGIDX (DT_AUXILIARY))
31 /* Whether an shared object references one or more auxiliary objects
32    is signaled by the AUXTAG entry in l_info.  */
33 #define FILTERTAG (DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM \
34                    + DT_EXTRATAGIDX (DT_FILTER))
35
36
37 /* When loading auxiliary objects we must ignore errors.  It's ok if
38    an object is missing.  */
39 struct openaux_args
40   {
41     /* The arguments to openaux.  */
42     struct link_map *map;
43     int trace_mode;
44     const char *strtab;
45     const ElfW(Dyn) *d;
46
47     /* The return value of openaux.  */
48     struct link_map *aux;
49   };
50
51 static void
52 openaux (void *a)
53 {
54   struct openaux_args *args = (struct openaux_args *) a;
55
56   args->aux = _dl_map_object (args->map, args->strtab + args->d->d_un.d_val,
57                               (args->map->l_type == lt_executable
58                                ? lt_library : args->map->l_type),
59                               args->trace_mode);
60 }
61
62
63
64 /* We use a very special kind of list to track the two kinds paths
65    through the list of loaded shared objects.  We have to
66
67    - produce a flat list with unique members of all involved objects
68
69    - produce a flat list of all shared objects.
70 */
71 struct list
72   {
73     int done;                   /* Nonzero if this map was processed.  */
74     struct link_map *map;       /* The data.  */
75
76     struct list *unique;        /* Elements for normal list.  */
77     struct list *dup;           /* Elements in complete list.  */
78   };
79
80
81 void
82 _dl_map_object_deps (struct link_map *map,
83                      struct link_map **preloads, unsigned int npreloads,
84                      int trace_mode)
85 {
86   struct list known[1 + npreloads + 1];
87   struct list *runp, *head, *utail, *dtail;
88   unsigned int nlist, nduplist, i;
89
90   inline void preload (struct link_map *map)
91     {
92       known[nlist].done = 0;
93       known[nlist].map = map;
94
95       known[nlist].unique = &known[nlist + 1];
96       known[nlist].dup = &known[nlist + 1];
97
98       ++nlist;
99       /* We use `l_reserved' as a mark bit to detect objects we have
100          already put in the search list and avoid adding duplicate
101          elements later in the list.  */
102       map->l_reserved = 1;
103     }
104
105   /* No loaded object so far.  */
106   nlist = 0;
107
108   /* First load MAP itself.  */
109   preload (map);
110
111   /* Add the preloaded items after MAP but before any of its dependencies.  */
112   for (i = 0; i < npreloads; ++i)
113     preload (preloads[i]);
114
115   /* Terminate the lists.  */
116   known[nlist - 1].unique = NULL;
117   known[nlist - 1].dup = NULL;
118
119   /* Pointer to the first member of the unique and duplicate list.  */
120   head = known;
121
122   /* Pointer to last unique object.  */
123   utail = &known[nlist - 1];
124   /* Pointer to last loaded object.  */
125   dtail = &known[nlist - 1];
126
127   /* Until now we have the same number of libraries in the normal and
128      the list with duplicates.  */
129   nduplist = nlist;
130
131   /* Process each element of the search list, loading each of its
132      auxiliary objects and immediate dependencies.  Auxiliary objects
133      will be added in the list before the object itself and
134      dependencies will be appended to the list as we step through it.
135      This produces a flat, ordered list that represents a
136      breadth-first search of the dependency tree.
137
138      The whole process is complicated by the fact that we better
139      should use alloca for the temporary list elements.  But using
140      alloca means we cannot use recursive function calls.  */
141   for (runp = known; runp; )
142     {
143       struct link_map *l = runp->map;
144
145       if (l->l_info[AUXTAG] || l->l_info[FILTERTAG] || l->l_info[DT_NEEDED])
146         {
147           const char *strtab = ((void *) l->l_addr
148                                 + l->l_info[DT_STRTAB]->d_un.d_ptr);
149           struct openaux_args args;
150           struct list *orig;
151           const ElfW(Dyn) *d;
152
153           /* Mark map as processed.  */
154           runp->done = 1;
155
156           args.strtab = strtab;
157           args.map = l;
158           args.trace_mode = trace_mode;
159           orig = runp;
160
161           for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
162             if (d->d_tag == DT_NEEDED)
163               {
164                 /* Map in the needed object.  */
165                 struct link_map *dep
166                   = _dl_map_object (l, strtab + d->d_un.d_val,
167                                     l->l_type == lt_executable ? lt_library :
168                                     l->l_type, trace_mode);
169                 /* Allocate new entry.  */
170                 struct list *newp = alloca (sizeof (struct list));
171
172                 /* Add it in any case to the duplicate list.  */
173                 newp->map = dep;
174                 newp->dup = NULL;
175                 dtail->dup = newp;
176                 dtail = newp;
177                 ++nduplist;
178
179                 if (dep->l_reserved)
180                   /* This object is already in the search list we are
181                      building.  Don't add a duplicate pointer.
182                      Release the reference just added by
183                      _dl_map_object.  */
184                   --dep->l_opencount;
185                 else
186                   {
187                     /* Append DEP to the unique list.  */
188                     newp->done = 0;
189                     newp->unique = NULL;
190                     utail->unique = newp;
191                     utail = newp;
192                     ++nlist;
193                     /* Set the mark bit that says it's already in the list.  */
194                     dep->l_reserved = 1;
195                   }
196               }
197             else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
198               {
199                 char *errstring;
200                 const char *objname;
201                 struct list *newp;
202
203                 if (d->d_tag == DT_AUXILIARY)
204                   {
205                     /* Store the tag in the argument structure.  */
206                     args.d = d;
207
208                     /* We must be prepared that the addressed shared
209                        object is not available.  */
210                     if (_dl_catch_error (&errstring, &objname, openaux, &args))
211                       {
212                         /* We are not interested in the error message.  */
213                         assert (errstring != NULL);
214                         free (errstring);
215
216                         /* Simply ignore this error and continue the work.  */
217                         continue;
218                       }
219                   }
220                 else
221                   /* For filter objects the dependency must be available.  */
222                   args.aux = _dl_map_object (l, strtab + d->d_un.d_val,
223                                              (l->l_type == lt_executable
224                                               ? lt_library : l->l_type),
225                                              trace_mode);
226
227                 /* The auxiliary object is actually available.
228                    Incorporate the map in all the lists.  */
229
230                 /* Allocate new entry.  This always has to be done.  */
231                 newp = alloca (sizeof (struct list));
232
233                 /* Copy the content of the current entry over.  */
234                 memcpy (newp, orig, sizeof (*newp));
235
236                 /* Initialize new entry.  */
237                 orig->done = 0;
238                 orig->map = args.aux;
239                 orig->dup = newp;
240
241                 /* We must handle two situations here: the map is new,
242                    so we must add it in all three lists.  If the map
243                    is already known, we have two further possibilities:
244                    - if the object is before the current map in the
245                    search list, we do nothing.  It is already found
246                    early
247                    - if the object is after the current one, we must
248                    move it just before the current map to make sure
249                    the symbols are found early enough
250                 */
251                 if (args.aux->l_reserved)
252                   {
253                     /* The object is already somewhere in the list.
254                        Locate it first.  */
255                     struct list *late;
256
257                     /* This object is already in the search list we
258                        are building.  Don't add a duplicate pointer.
259                        Release the reference just added by
260                        _dl_map_object.  */
261                     --args.aux->l_opencount;
262
263                     for (late = orig; late->unique; late = late->unique)
264                       if (late->unique->map == args.aux)
265                         break;
266
267                     if (late->unique)
268                       {
269                         /* The object is somewhere behind the current
270                            position in the search path.  We have to
271                            move it to this earlier position.  */
272                         orig->unique = newp;
273
274                         /* Now remove the later entry from the unique list.  */
275                         late->unique = late->unique->unique;
276
277                         /* We must move the earlier in the chain.  */
278                         if (args.aux->l_prev)
279                           args.aux->l_prev->l_next = args.aux->l_next;
280                         if (args.aux->l_next)
281                           args.aux->l_next->l_prev = args.aux->l_prev;
282
283                         args.aux->l_prev = newp->map->l_prev;
284                         newp->map->l_prev = args.aux;
285                         if (args.aux->l_prev != NULL)
286                           args.aux->l_prev->l_next = args.aux;
287                         args.aux->l_next = newp->map;
288                       }
289                     else
290                       {
291                         /* The object must be somewhere earlier in the
292                            list.  That's good, we only have to insert
293                            an entry for the duplicate list.  */
294                         orig->unique = NULL;    /* Never used.  */
295
296                         /* Now we have a problem.  The element
297                            pointing to ORIG in the unique list must
298                            point to NEWP now.  This is the only place
299                            where we need this backreference and this
300                            situation is really not that frequent.  So
301                            we don't use a double-linked list but
302                            instead search for the preceding element.  */
303                         late = head;
304                         while (late->unique != orig)
305                           late = late->unique;
306                         late->unique = newp;
307                       }
308                   }
309                 else
310                   {
311                     /* This is easy.  We just add the symbol right here.  */
312                     orig->unique = newp;
313                     ++nlist;
314                     /* Set the mark bit that says it's already in the list.  */
315                     args.aux->l_reserved = 1;
316
317                     /* The only problem is that in the double linked
318                        list of all objects we don't have this new
319                        object at the correct place.  Correct this here.  */
320                     if (args.aux->l_prev)
321                       args.aux->l_prev->l_next = args.aux->l_next;
322                     if (args.aux->l_next)
323                       args.aux->l_next->l_prev = args.aux->l_prev;
324
325                     args.aux->l_prev = newp->map->l_prev;
326                     newp->map->l_prev = args.aux;
327                     if (args.aux->l_prev != NULL)
328                       args.aux->l_prev->l_next = args.aux;
329                     args.aux->l_next = newp->map;
330                   }
331
332                 /* Move the tail pointers if necessary.  */
333                 if (orig == utail)
334                   utail = newp;
335                 if (orig == dtail)
336                   dtail = newp;
337
338                 /* Move on the insert point.  */
339                 orig = newp;
340
341                 /* We always add an entry to the duplicate list.  */
342                 ++nduplist;
343               }
344         }
345       else
346         /* Mark as processed.  */
347         runp->done = 1;
348
349       /* If we have no auxiliary objects just go on to the next map.  */
350       if (runp->done)
351         do
352           runp = runp->unique;
353         while (runp && runp->done);
354     }
355
356   /* Store the search list we built in the object.  It will be used for
357      searches in the scope of this object.  */
358   map->l_searchlist = malloc (nlist * sizeof (struct link_map *));
359   if (map->l_searchlist == NULL)
360     _dl_signal_error (ENOMEM, map->l_name,
361                       "cannot allocate symbol search list");
362   map->l_nsearchlist = nlist;
363
364   for (nlist = 0, runp = head; runp; runp = runp->unique)
365     {
366       map->l_searchlist[nlist++] = runp->map;
367
368       /* Now clear all the mark bits we set in the objects on the search list
369          to avoid duplicates, so the next call starts fresh.  */
370       runp->map->l_reserved = 0;
371     }
372
373   map->l_ndupsearchlist = nduplist;
374   if (nlist == nduplist)
375     map->l_dupsearchlist = map->l_searchlist;
376   else
377     {
378       map->l_dupsearchlist = malloc (nduplist * sizeof (struct link_map *));
379       if (map->l_dupsearchlist == NULL)
380         _dl_signal_error (ENOMEM, map->l_name,
381                           "cannot allocate symbol search list");
382
383       for (nlist = 0, runp = head; runp; runp = runp->dup)
384         map->l_dupsearchlist[nlist++] = runp->map;
385     }
386 }