Pass read/write CRx registers to userspace
[freebsd-src/fkvm-freebsd.git] / libexec / rtld-elf / libmap.c
blob773456b1f74de359473a04a0c478d6ca5512ee65
1 /*
2 * $FreeBSD$
3 */
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <sys/queue.h>
10 #include <sys/param.h>
12 #include "debug.h"
13 #include "rtld.h"
14 #include "libmap.h"
16 #ifndef _PATH_LIBMAP_CONF
17 #define _PATH_LIBMAP_CONF "/etc/libmap.conf"
18 #endif
20 #ifdef COMPAT_32BIT
21 #undef _PATH_LIBMAP_CONF
22 #define _PATH_LIBMAP_CONF "/etc/libmap32.conf"
23 #endif
25 TAILQ_HEAD(lm_list, lm);
26 struct lm {
27 char *f;
28 char *t;
30 TAILQ_ENTRY(lm) lm_link;
33 TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head);
34 struct lmp {
35 char *p;
36 enum { T_EXACT=0, T_BASENAME, T_DIRECTORY } type;
37 struct lm_list lml;
38 TAILQ_ENTRY(lmp) lmp_link;
41 static int lm_count;
43 static void lmc_parse (FILE *);
44 static void lm_add (const char *, const char *, const char *);
45 static void lm_free (struct lm_list *);
46 static char * lml_find (struct lm_list *, const char *);
47 static struct lm_list * lmp_find (const char *);
48 static struct lm_list * lmp_init (char *);
49 static const char * quickbasename (const char *);
50 static int readstrfn (void * cookie, char *buf, int len);
51 static int closestrfn (void * cookie);
53 #define iseol(c) (((c) == '#') || ((c) == '\0') || \
54 ((c) == '\n') || ((c) == '\r'))
56 int
57 lm_init (char *libmap_override)
59 FILE *fp;
61 dbg("%s(\"%s\")", __func__, libmap_override);
63 TAILQ_INIT(&lmp_head);
65 fp = fopen(_PATH_LIBMAP_CONF, "r");
66 if (fp) {
67 lmc_parse(fp);
68 fclose(fp);
71 if (libmap_override) {
72 char *p;
73 /* do some character replacement to make $LIBMAP look like a
74 text file, then "open" it with funopen */
75 libmap_override = xstrdup(libmap_override);
77 for (p = libmap_override; *p; p++) {
78 switch (*p) {
79 case '=':
80 *p = ' '; break;
81 case ',':
82 *p = '\n'; break;
85 fp = funopen(libmap_override, readstrfn, NULL, NULL, closestrfn);
86 if (fp) {
87 lmc_parse(fp);
88 fclose(fp);
92 return (lm_count == 0);
95 static void
96 lmc_parse (FILE *fp)
98 char *cp;
99 char *f, *t, *c, *p;
100 char prog[MAXPATHLEN];
101 char line[MAXPATHLEN + 2];
103 dbg("%s(%p)", __func__, fp);
105 p = NULL;
106 while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) {
107 t = f = c = NULL;
109 /* Skip over leading space */
110 while (isspace(*cp)) cp++;
112 /* Found a comment or EOL */
113 if (iseol(*cp)) continue;
115 /* Found a constraint selector */
116 if (*cp == '[') {
117 cp++;
119 /* Skip leading space */
120 while (isspace(*cp)) cp++;
122 /* Found comment, EOL or end of selector */
123 if (iseol(*cp) || *cp == ']')
124 continue;
126 c = cp++;
127 /* Skip to end of word */
128 while (!isspace(*cp) && !iseol(*cp) && *cp != ']')
129 cp++;
131 /* Skip and zero out trailing space */
132 while (isspace(*cp)) *cp++ = '\0';
134 /* Check if there is a closing brace */
135 if (*cp != ']') continue;
137 /* Terminate string if there was no trailing space */
138 *cp++ = '\0';
141 * There should be nothing except whitespace or comment
142 from this point to the end of the line.
144 while(isspace(*cp)) cp++;
145 if (!iseol(*cp)) continue;
147 strcpy(prog, c);
148 p = prog;
149 continue;
152 /* Parse the 'from' candidate. */
153 f = cp++;
154 while (!isspace(*cp) && !iseol(*cp)) cp++;
156 /* Skip and zero out the trailing whitespace */
157 while (isspace(*cp)) *cp++ = '\0';
159 /* Found a comment or EOL */
160 if (iseol(*cp)) continue;
162 /* Parse 'to' mapping */
163 t = cp++;
164 while (!isspace(*cp) && !iseol(*cp)) cp++;
166 /* Skip and zero out the trailing whitespace */
167 while (isspace(*cp)) *cp++ = '\0';
169 /* Should be no extra tokens at this point */
170 if (!iseol(*cp)) continue;
172 *cp = '\0';
173 lm_add(p, f, t);
177 static void
178 lm_free (struct lm_list *lml)
180 struct lm *lm;
182 dbg("%s(%p)", __func__, lml);
184 while (!TAILQ_EMPTY(lml)) {
185 lm = TAILQ_FIRST(lml);
186 TAILQ_REMOVE(lml, lm, lm_link);
187 free(lm->f);
188 free(lm->t);
189 free(lm);
191 return;
194 void
195 lm_fini (void)
197 struct lmp *lmp;
199 dbg("%s()", __func__);
201 while (!TAILQ_EMPTY(&lmp_head)) {
202 lmp = TAILQ_FIRST(&lmp_head);
203 TAILQ_REMOVE(&lmp_head, lmp, lmp_link);
204 free(lmp->p);
205 lm_free(&lmp->lml);
206 free(lmp);
208 return;
211 static void
212 lm_add (const char *p, const char *f, const char *t)
214 struct lm_list *lml;
215 struct lm *lm;
217 if (p == NULL)
218 p = "$DEFAULT$";
220 dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t);
222 if ((lml = lmp_find(p)) == NULL)
223 lml = lmp_init(xstrdup(p));
225 lm = xmalloc(sizeof(struct lm));
226 lm->f = xstrdup(f);
227 lm->t = xstrdup(t);
228 TAILQ_INSERT_HEAD(lml, lm, lm_link);
229 lm_count++;
232 char *
233 lm_find (const char *p, const char *f)
235 struct lm_list *lml;
236 char *t;
238 dbg("%s(\"%s\", \"%s\")", __func__, p, f);
240 if (p != NULL && (lml = lmp_find(p)) != NULL) {
241 t = lml_find(lml, f);
242 if (t != NULL) {
244 * Add a global mapping if we have
245 * a successful constrained match.
247 lm_add(NULL, f, t);
248 return (t);
251 lml = lmp_find("$DEFAULT$");
252 if (lml != NULL)
253 return (lml_find(lml, f));
254 else
255 return (NULL);
258 /* Given a libmap translation list and a library name, return the
259 replacement library, or NULL */
260 #ifdef COMPAT_32BIT
261 char *
262 lm_findn (const char *p, const char *f, const int n)
264 char pathbuf[64], *s, *t;
266 if (n < sizeof(pathbuf) - 1)
267 s = pathbuf;
268 else
269 s = xmalloc(n + 1);
270 memcpy(s, f, n);
271 s[n] = '\0';
272 t = lm_find(p, s);
273 if (s != pathbuf)
274 free(s);
275 return (t);
277 #endif
279 static char *
280 lml_find (struct lm_list *lmh, const char *f)
282 struct lm *lm;
284 dbg("%s(%p, \"%s\")", __func__, lmh, f);
286 TAILQ_FOREACH(lm, lmh, lm_link)
287 if (strcmp(f, lm->f) == 0)
288 return (lm->t);
289 return (NULL);
292 /* Given an executable name, return a pointer to the translation list or
293 NULL if no matches */
294 static struct lm_list *
295 lmp_find (const char *n)
297 struct lmp *lmp;
299 dbg("%s(\"%s\")", __func__, n);
301 TAILQ_FOREACH(lmp, &lmp_head, lmp_link)
302 if ((lmp->type == T_EXACT && strcmp(n, lmp->p) == 0) ||
303 (lmp->type == T_DIRECTORY && strncmp(n, lmp->p, strlen(lmp->p)) == 0) ||
304 (lmp->type == T_BASENAME && strcmp(quickbasename(n), lmp->p) == 0))
305 return (&lmp->lml);
306 return (NULL);
309 static struct lm_list *
310 lmp_init (char *n)
312 struct lmp *lmp;
314 dbg("%s(\"%s\")", __func__, n);
316 lmp = xmalloc(sizeof(struct lmp));
317 lmp->p = n;
318 if (n[strlen(n)-1] == '/')
319 lmp->type = T_DIRECTORY;
320 else if (strchr(n,'/') == NULL)
321 lmp->type = T_BASENAME;
322 else
323 lmp->type = T_EXACT;
324 TAILQ_INIT(&lmp->lml);
325 TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link);
327 return (&lmp->lml);
330 /* libc basename is overkill. Return a pointer to the character after the
331 last /, or the original string if there are no slashes. */
332 static const char *
333 quickbasename (const char *path)
335 const char *p = path;
336 for (; *path; path++) {
337 if (*path == '/')
338 p = path+1;
340 return (p);
343 static int
344 readstrfn(void * cookie, char *buf, int len)
346 static char *current;
347 static int left;
348 int copied;
350 copied = 0;
351 if (!current) {
352 current = cookie;
353 left = strlen(cookie);
355 while (*current && left && len) {
356 *buf++ = *current++;
357 left--;
358 len--;
359 copied++;
361 return copied;
364 static int
365 closestrfn(void * cookie)
367 free(cookie);
368 return 0;