VirtualBox

source: kBuild/trunk/src/kmk/load.c@ 3387

Last change on this file since 3387 was 3140, checked in by bird, 6 years ago

kmk: Merged in changes from GNU make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6 / https://git.savannah.gnu.org/git/make.git).

  • Property svn:eol-style set to native
File size: 6.8 KB
Line 
1/* Loading dynamic objects for GNU Make.
2Copyright (C) 2012-2016 Free Software Foundation, Inc.
3This file is part of GNU Make.
4
5GNU Make is free software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the Free Software
7Foundation; either version 3 of the License, or (at your option) any later
8version.
9
10GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "makeint.h"
18
19#if MAKE_LOAD
20
21#include <string.h>
22#include <ctype.h>
23#include <stdlib.h>
24#include <dlfcn.h>
25#include <errno.h>
26
27#define SYMBOL_EXTENSION "_gmk_setup"
28
29#include "debug.h"
30#include "filedef.h"
31#include "variable.h"
32
33/* Tru64 V4.0 does not have this flag */
34#ifndef RTLD_GLOBAL
35# define RTLD_GLOBAL 0
36#endif
37
38struct load_list
39 {
40 struct load_list *next;
41 const char *name;
42 void *dlp;
43 };
44
45static struct load_list *loaded_syms = NULL;
46
47static load_func_t
48load_object (const floc *flocp, int noerror, const char *ldname,
49 const char *symname)
50{
51 static void *global_dl = NULL;
52 load_func_t symp;
53
54 if (! global_dl)
55 {
56 global_dl = dlopen (NULL, RTLD_NOW|RTLD_GLOBAL);
57 if (! global_dl)
58 {
59 const char *err = dlerror ();
60 OS (fatal, flocp, _("Failed to open global symbol table: %s"), err);
61 }
62 }
63
64 symp = (load_func_t) dlsym (global_dl, symname);
65 if (! symp)
66 {
67 struct load_list *new;
68 void *dlp = NULL;
69
70 /* If the path has no "/", try the current directory first. */
71 if (! strchr (ldname, '/')
72#ifdef HAVE_DOS_PATHS
73 && ! strchr (ldname, '\\')
74#endif
75 )
76 dlp = dlopen (concat (2, "./", ldname), RTLD_LAZY|RTLD_GLOBAL);
77
78 /* If we haven't opened it yet, try the default search path. */
79 if (! dlp)
80 dlp = dlopen (ldname, RTLD_LAZY|RTLD_GLOBAL);
81
82 /* Still no? Then fail. */
83 if (! dlp)
84 {
85 const char *err = dlerror ();
86 if (noerror)
87 DB (DB_BASIC, ("%s", err));
88 else
89 OS (error, flocp, "%s", err);
90 return NULL;
91 }
92
93 /* Assert that the GPL license symbol is defined. */
94 symp = (load_func_t) dlsym (dlp, "plugin_is_GPL_compatible");
95 if (! symp)
96 OS (fatal, flocp,
97 _("Loaded object %s is not declared to be GPL compatible"),
98 ldname);
99
100 symp = (load_func_t) dlsym (dlp, symname);
101 if (! symp)
102 {
103 const char *err = dlerror ();
104 OSSS (fatal, flocp, _("Failed to load symbol %s from %s: %s"),
105 symname, ldname, err);
106 }
107
108 /* Add this symbol to a trivial lookup table. This is not efficient but
109 it's highly unlikely we'll be loading lots of objects, and we only
110 need it to look them up on unload, if we rebuild them. */
111 new = xmalloc (sizeof (struct load_list));
112 new->name = xstrdup (ldname);
113 new->dlp = dlp;
114 new->next = loaded_syms;
115 loaded_syms = new;
116 }
117
118 return symp;
119}
120
121int
122load_file (const floc *flocp, const char **ldname, int noerror)
123{
124 int nmlen = strlen (*ldname);
125 char *new = alloca (nmlen + CSTRLEN (SYMBOL_EXTENSION) + 1);
126 char *symname = NULL;
127 char *loaded;
128 const char *fp;
129 int r;
130 load_func_t symp;
131
132 /* Break the input into an object file name and a symbol name. If no symbol
133 name was provided, compute one from the object file name. */
134 fp = strchr (*ldname, '(');
135 if (fp)
136 {
137 const char *ep;
138
139 /* There's an open paren, so see if there's a close paren: if so use
140 that as the symbol name. We can't have whitespace: it would have
141 been chopped up before this function is called. */
142 ep = strchr (fp+1, ')');
143 if (ep && ep[1] == '\0')
144 {
145 int l = fp - *ldname;;
146
147 ++fp;
148 if (fp == ep)
149 OS (fatal, flocp, _("Empty symbol name for load: %s"), *ldname);
150
151 /* Make a copy of the ldname part. */
152 memcpy (new, *ldname, l);
153 new[l] = '\0';
154 *ldname = new;
155 nmlen = l;
156
157 /* Make a copy of the symbol name part. */
158 symname = new + l + 1;
159 memcpy (symname, fp, ep - fp);
160 symname[ep - fp] = '\0';
161 }
162 }
163
164 /* Add this name to the string cache so it can be reused later. */
165 *ldname = strcache_add (*ldname);
166
167 /* If this object has been loaded, we're done. */
168 loaded = allocated_variable_expand ("$(.LOADED)");
169 fp = strstr (loaded, *ldname);
170 r = fp && (fp==loaded || fp[-1]==' ') && (fp[nmlen]=='\0' || fp[nmlen]==' ');
171 if (r)
172 goto exit;
173
174 /* If we didn't find a symbol name yet, construct it from the ldname. */
175 if (! symname)
176 {
177 char *p = new;
178
179 fp = strrchr (*ldname, '/');
180#ifdef HAVE_DOS_PATHS
181 if (fp)
182 {
183 const char *fp2 = strchr (fp, '\\');
184
185 if (fp2 > fp)
186 fp = fp2;
187 }
188 else
189 fp = strrchr (*ldname, '\\');
190 /* The (improbable) case of d:foo. */
191 if (fp && *fp && fp[1] == ':')
192 fp++;
193#endif
194 if (!fp)
195 fp = *ldname;
196 else
197 ++fp;
198 while (isalnum (*fp) || *fp == '_')
199 *(p++) = *(fp++);
200 strcpy (p, SYMBOL_EXTENSION);
201 symname = new;
202 }
203
204 DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, *ldname));
205
206 /* Load it! */
207 symp = load_object (flocp, noerror, *ldname, symname);
208 if (! symp)
209 return 0;
210
211 /* Invoke the symbol. */
212 r = (*symp) (flocp);
213
214 /* If it succeeded, add the load file to the loaded variable. */
215 if (r > 0)
216 {
217 size_t loadlen = strlen (loaded);
218 char *newval = alloca (loadlen + strlen (*ldname) + 2);
219 /* Don't add a space if it's empty. */
220 if (loadlen)
221 {
222 memcpy (newval, loaded, loadlen);
223 newval[loadlen++] = ' ';
224 }
225 strcpy (&newval[loadlen], *ldname);
226 do_variable_definition (flocp, ".LOADED", newval, o_default, f_simple, 0);
227 }
228
229 exit:
230 free (loaded);
231 return r;
232}
233
234void
235unload_file (const char *name)
236{
237 struct load_list *d;
238
239 for (d = loaded_syms; d != NULL; d = d->next)
240 if (streq (d->name, name) && d->dlp)
241 {
242 if (dlclose (d->dlp))
243 perror_with_name ("dlclose", d->name);
244 d->dlp = NULL;
245 break;
246 }
247}
248
249#else
250
251int
252load_file (const floc *flocp, const char **ldname UNUSED, int noerror)
253{
254 if (! noerror)
255 O (fatal, flocp,
256 _("The 'load' operation is not supported on this platform."));
257
258 return 0;
259}
260
261void
262unload_file (const char *name UNUSED)
263{
264 O (fatal, NILF, "INTERNAL: Cannot unload when load is not supported!");
265}
266
267#endif /* MAKE_LOAD */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use