]>
Commit | Line | Data |
---|---|---|
d66e34cd | 1 | /* Storage management for the chain of loaded shared objects. |
bed12f78 | 2 | Copyright (C) 1995-2002, 2004 Free Software Foundation, Inc. |
afd4eb37 UD |
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 | |
41bdb6e2 AJ |
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. | |
afd4eb37 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
afd4eb37 | 14 | |
41bdb6e2 AJ |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
d66e34cd | 19 | |
a853022c | 20 | #include <errno.h> |
d66e34cd RM |
21 | #include <string.h> |
22 | #include <stdlib.h> | |
f787edde | 23 | #include <unistd.h> |
a42195db | 24 | #include <ldsodefs.h> |
d66e34cd | 25 | |
a853022c | 26 | #include <assert.h> |
d66e34cd | 27 | |
d66e34cd RM |
28 | |
29 | /* Allocate a `struct link_map' for a new object being loaded, | |
30 | and enter it into the _dl_loaded list. */ | |
31 | ||
32 | struct link_map * | |
d0fc4041 | 33 | internal_function |
be935610 | 34 | _dl_new_object (char *realname, const char *libname, int type, |
c0f62c56 | 35 | struct link_map *loader, int mode, Lmid_t nsid) |
d66e34cd | 36 | { |
be935610 UD |
37 | struct link_map *l; |
38 | int idx; | |
76156ea1 | 39 | size_t libname_len = strlen (libname) + 1; |
c4bb124a UD |
40 | struct link_map *new; |
41 | struct libname_list *newname; | |
42 | ||
a334319f UD |
43 | new = (struct link_map *) calloc (sizeof (*new) + sizeof (*newname) |
44 | + libname_len, 1); | |
11810621 | 45 | if (new == NULL) |
ba79d61b | 46 | return NULL; |
d66e34cd | 47 | |
c0f62c56 | 48 | new->l_real = new; |
a334319f | 49 | new->l_libname = newname = (struct libname_list *) (new + 1); |
c4bb124a | 50 | newname->name = (char *) memcpy (newname + 1, libname, libname_len); |
455e8060 | 51 | /* newname->next = NULL; We use calloc therefore not necessary. */ |
11810621 UD |
52 | newname->dont_free = 1; |
53 | ||
54 | new->l_name = realname; | |
d66e34cd | 55 | new->l_type = type; |
be935610 | 56 | new->l_loader = loader; |
299601a1 UD |
57 | #if defined USE_TLS && NO_TLS_OFFSET != 0 |
58 | new->l_tls_offset = NO_TLS_OFFSET; | |
59 | #endif | |
c0f62c56 | 60 | new->l_ns = nsid; |
299601a1 | 61 | |
b25d4ff0 | 62 | /* new->l_global = 0; We use calloc therefore not necessary. */ |
d66e34cd | 63 | |
5a21d307 UD |
64 | /* Use the 'l_scope_mem' array by default for the the 'l_scope' |
65 | information. If we need more entries we will allocate a large | |
66 | array dynamically. */ | |
67 | new->l_scope = new->l_scope_mem; | |
68 | new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]); | |
69 | ||
be935610 UD |
70 | /* Counter for the scopes we have to handle. */ |
71 | idx = 0; | |
72 | ||
c0f62c56 | 73 | if (GL(dl_ns)[nsid]._ns_loaded != NULL) |
d66e34cd | 74 | { |
c0f62c56 | 75 | l = GL(dl_ns)[nsid]._ns_loaded; |
7bccbc05 | 76 | while (l->l_next != NULL) |
d66e34cd RM |
77 | l = l->l_next; |
78 | new->l_prev = l; | |
49c091e5 | 79 | /* new->l_next = NULL; Would be necessary but we use calloc. */ |
d66e34cd | 80 | l->l_next = new; |
d66e34cd | 81 | |
be935610 | 82 | /* Add the global scope. */ |
c0f62c56 | 83 | new->l_scope[idx++] = &GL(dl_ns)[nsid]._ns_loaded->l_searchlist; |
be935610 | 84 | } |
e4d50917 | 85 | else |
c0f62c56 UD |
86 | GL(dl_ns)[nsid]._ns_loaded = new; |
87 | ++GL(dl_ns)[nsid]._ns_nloaded; | |
bed12f78 | 88 | ++GL(dl_load_adds); |
7bccbc05 UD |
89 | |
90 | /* If we have no loader the new object acts as it. */ | |
91 | if (loader == NULL) | |
92 | loader = new; | |
93 | else | |
94 | /* Determine the local scope. */ | |
95 | while (loader->l_loader != NULL) | |
96 | loader = loader->l_loader; | |
97 | ||
98 | /* Insert the scope if it isn't the global scope we already added. */ | |
99 | if (idx == 0 || &loader->l_searchlist != new->l_scope[0]) | |
1fc07491 UD |
100 | { |
101 | if ((mode & RTLD_DEEPBIND) != 0 && idx != 0) | |
102 | { | |
103 | new->l_scope[1] = new->l_scope[0]; | |
104 | idx = 0; | |
105 | } | |
106 | ||
107 | new->l_scope[idx] = &loader->l_searchlist; | |
108 | } | |
be935610 | 109 | |
df4d2898 | 110 | new->l_local_scope[0] = &new->l_searchlist; |
be935610 UD |
111 | |
112 | /* Don't try to find the origin for the main map which has the name "". */ | |
113 | if (realname[0] != '\0') | |
f787edde | 114 | { |
7bccbc05 | 115 | size_t realname_len = strlen (realname) + 1; |
f787edde | 116 | char *origin; |
7bccbc05 | 117 | char *cp; |
f787edde UD |
118 | |
119 | if (realname[0] == '/') | |
120 | { | |
7bccbc05 UD |
121 | /* It is an absolute path. Use it. But we have to make a |
122 | copy since we strip out the trailing slash. */ | |
123 | cp = origin = (char *) malloc (realname_len); | |
f787edde | 124 | if (origin == NULL) |
7bccbc05 UD |
125 | { |
126 | origin = (char *) -1; | |
127 | goto out; | |
128 | } | |
f787edde UD |
129 | } |
130 | else | |
131 | { | |
7bccbc05 | 132 | size_t len = realname_len; |
f787edde UD |
133 | char *result = NULL; |
134 | ||
135 | /* Get the current directory name. */ | |
7bccbc05 UD |
136 | origin = NULL; |
137 | do | |
f787edde | 138 | { |
d1dddedf UD |
139 | char *new_origin; |
140 | ||
f787edde | 141 | len += 128; |
d1dddedf UD |
142 | new_origin = (char *) realloc (origin, len); |
143 | if (new_origin == NULL) | |
144 | /* We exit the loop. Note that result == NULL. */ | |
145 | break; | |
146 | origin = new_origin; | |
f787edde | 147 | } |
d1dddedf | 148 | while ((result = __getcwd (origin, len - realname_len)) == NULL |
7bccbc05 | 149 | && errno == ERANGE); |
f787edde UD |
150 | |
151 | if (result == NULL) | |
152 | { | |
7bccbc05 UD |
153 | /* We were not able to determine the current directory. |
154 | Note that free(origin) is OK if origin == NULL. */ | |
903244ac | 155 | free (origin); |
f787edde | 156 | origin = (char *) -1; |
7bccbc05 | 157 | goto out; |
f787edde | 158 | } |
f787edde | 159 | |
9710f75d UD |
160 | /* Find the end of the path and see whether we have to add a |
161 | slash. We could use rawmemchr but this need not be | |
162 | fast. */ | |
163 | cp = (strchr) (origin, '\0'); | |
7bccbc05 UD |
164 | if (cp[-1] != '/') |
165 | *cp++ = '/'; | |
f787edde UD |
166 | } |
167 | ||
7bccbc05 | 168 | /* Add the real file name. */ |
88794e30 | 169 | cp = __mempcpy (cp, realname, realname_len); |
7bccbc05 | 170 | |
88794e30 | 171 | /* Now remove the filename and the slash. Leave the slash if |
7bccbc05 | 172 | the name is something like "/foo". */ |
88794e30 UD |
173 | do |
174 | --cp; | |
175 | while (*cp != '/'); | |
176 | ||
7bccbc05 | 177 | if (cp == origin) |
88794e30 UD |
178 | /* Keep the only slash which is the first character. */ |
179 | ++cp; | |
180 | *cp = '\0'; | |
f787edde | 181 | |
7bccbc05 | 182 | out: |
f787edde UD |
183 | new->l_origin = origin; |
184 | } | |
185 | ||
d66e34cd RM |
186 | return new; |
187 | } |