Line data Source code
1 : /*-
2 : * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
3 : * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : * 1. Redistributions of source code must retain the above copyright
10 : * notice, this list of conditions and the following disclaimer
11 : * in this position and unchanged.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 :
28 : #ifdef HAVE_CONFIG_H
29 : #include "pkg_config.h"
30 : #endif
31 :
32 : #ifdef HAVE_SYS_ENDIAN_H
33 : #include <sys/endian.h>
34 : #elif HAVE_ENDIAN_H
35 : #include <endian.h>
36 : #elif HAVE_MACHINE_ENDIAN_H
37 : #include <machine/endian.h>
38 : #endif
39 : #include <sys/types.h>
40 : #if defined(HAVE_SYS_ELF_COMMON_H) && !defined(__DragonFly__)
41 : #include <sys/elf_common.h>
42 : #endif
43 : #include <sys/stat.h>
44 :
45 : #include <assert.h>
46 : #include <ctype.h>
47 : #include <dlfcn.h>
48 : #include <fcntl.h>
49 : #include <gelf.h>
50 : #include <libgen.h>
51 : #if defined(HAVE_LINK_H) && !defined(__DragonFly__) && defined(HAVE_LIBELF)
52 : #include <link.h>
53 : #endif
54 : #include <paths.h>
55 : #include <stdbool.h>
56 : #include <string.h>
57 : #include <unistd.h>
58 : #ifdef HAVE_LIBELF
59 : #include <libelf.h>
60 : #endif
61 :
62 : #include <bsd_compat.h>
63 :
64 : #include "pkg.h"
65 : #include "private/pkg.h"
66 : #include "private/event.h"
67 : #include "private/elf_tables.h"
68 : #include "private/ldconfig.h"
69 :
70 : #ifndef NT_ABI_TAG
71 : #define NT_ABI_TAG 1
72 : #endif
73 :
74 : /* FFR: when we support installing a 32bit package on a 64bit host */
75 : #define _PATH_ELF32_HINTS "/var/run/ld-elf32.so.hints"
76 :
77 : #ifndef roundup2
78 : #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
79 : #endif
80 :
81 : static const char * elf_corres_to_string(const struct _elf_corres* m, int e);
82 : static int elf_string_to_corres(const struct _elf_corres* m, const char *s);
83 :
84 : static int
85 0 : filter_system_shlibs(const char *name, char *path, size_t pathlen)
86 : {
87 : const char *shlib_path;
88 :
89 0 : shlib_path = shlib_list_find_by_name(name);
90 0 : if (shlib_path == NULL) {
91 : /* dynamic linker could not resolve */
92 0 : return (EPKG_FATAL);
93 : }
94 :
95 : /* match /lib, /lib32, /usr/lib and /usr/lib32 */
96 0 : if (strncmp(shlib_path, "/lib", 4) == 0 ||
97 0 : strncmp(shlib_path, "/usr/lib", 8) == 0)
98 0 : return (EPKG_END); /* ignore libs from base */
99 :
100 0 : if (path != NULL)
101 0 : strncpy(path, shlib_path, pathlen);
102 :
103 0 : return (EPKG_OK);
104 : }
105 :
106 : /* ARGSUSED */
107 : static int
108 0 : add_shlibs_to_pkg(struct pkg *pkg, const char *fpath, const char *name,
109 : bool is_shlib)
110 : {
111 0 : struct pkg_file *file = NULL;
112 : const char *filepath;
113 :
114 0 : switch(filter_system_shlibs(name, NULL, 0)) {
115 : case EPKG_OK: /* A non-system library */
116 0 : pkg_addshlib_required(pkg, name);
117 0 : return (EPKG_OK);
118 : case EPKG_END: /* A system library */
119 0 : return (EPKG_OK);
120 : default:
121 : /* Ignore link resolution errors if we're analysing a
122 : shared library. */
123 0 : if (is_shlib)
124 0 : return (EPKG_OK);
125 :
126 0 : while (pkg_files(pkg, &file) == EPKG_OK) {
127 0 : filepath = file->path;
128 0 : if (strcmp(&filepath[strlen(filepath) - strlen(name)], name) == 0) {
129 0 : pkg_addshlib_required(pkg, name);
130 0 : return (EPKG_OK);
131 : }
132 : }
133 :
134 0 : pkg_emit_notice("(%s-%s) %s - required shared library %s not "
135 : "found", pkg->name, pkg->version, fpath, name);
136 :
137 0 : return (EPKG_FATAL);
138 : }
139 : }
140 :
141 : static bool
142 0 : shlib_valid_abi(const char *fpath, GElf_Ehdr *hdr, const char *abi)
143 : {
144 : int semicolon;
145 : const char *p, *t;
146 : char arch[64], wordsize[64];
147 : int wclass;
148 : const char *shlib_arch;
149 :
150 : /*
151 : * ABI string is in format:
152 : * <osname>:<osversion>:<arch>:<wordsize>[.other]
153 : * We need here arch and wordsize only
154 : */
155 0 : arch[0] = '\0';
156 0 : wordsize[0] = '\0';
157 0 : p = abi;
158 0 : for(semicolon = 0; semicolon < 3 && p != NULL; semicolon ++, p ++) {
159 0 : p = strchr(p, ':');
160 0 : if (p != NULL) {
161 0 : switch(semicolon) {
162 : case 1:
163 : /* We have arch here */
164 0 : t = strchr(p + 1, ':');
165 : /* Abi line is likely invalid */
166 0 : if (t == NULL)
167 0 : return (true);
168 0 : strlcpy(arch, p + 1, MIN((long)sizeof(arch), t - p));
169 0 : break;
170 : case 2:
171 0 : t = strchr(p + 1, ':');
172 0 : if (t == NULL)
173 0 : strlcpy(wordsize, p + 1, sizeof(wordsize));
174 : else
175 0 : strlcpy(wordsize, p + 1, MIN((long)sizeof(wordsize), t - p));
176 0 : break;
177 : }
178 : }
179 : }
180 : /* Invalid ABI line */
181 0 : if (arch[0] == '\0' || wordsize[0] == '\0')
182 0 : return (true);
183 :
184 0 : shlib_arch = elf_corres_to_string(mach_corres, (int)hdr->e_machine);
185 0 : if (shlib_arch == NULL)
186 0 : return (true);
187 :
188 0 : wclass = elf_string_to_corres(wordsize_corres, wordsize);
189 0 : if (wclass == -1)
190 0 : return (true);
191 :
192 :
193 : /*
194 : * Compare wordsize first as the arch for amd64/i386 is an abmiguous
195 : * 'x86'
196 : */
197 0 : if ((int)hdr->e_ident[EI_CLASS] != wclass) {
198 0 : pkg_debug(1, "not valid elf class for shlib: %s: %s",
199 : elf_corres_to_string(wordsize_corres,
200 0 : (int)hdr->e_ident[EI_CLASS]),
201 : fpath);
202 0 : return (false);
203 : }
204 :
205 0 : if (strcmp(shlib_arch, arch) != 0) {
206 0 : pkg_debug(1, "not valid abi for shlib: %s: %s", shlib_arch,
207 : fpath);
208 0 : return (false);
209 : }
210 :
211 0 : return (true);
212 : }
213 :
214 : static int
215 64 : analyse_elf(struct pkg *pkg, const char *fpath)
216 : {
217 64 : Elf *e = NULL;
218 : GElf_Ehdr elfhdr;
219 64 : Elf_Scn *scn = NULL;
220 64 : Elf_Scn *note = NULL;
221 64 : Elf_Scn *dynamic = NULL;
222 : GElf_Shdr shdr;
223 : Elf_Data *data;
224 : GElf_Dyn *dyn, dyn_mem;
225 : struct stat sb;
226 64 : int ret = EPKG_OK;
227 :
228 64 : size_t numdyn = 0;
229 64 : size_t sh_link = 0;
230 : size_t dynidx;
231 : const char *osname;
232 : const char *myarch;
233 : const char *shlib;
234 :
235 64 : bool is_shlib = false;
236 :
237 64 : myarch = pkg_object_string(pkg_config_get("ABI"));
238 :
239 : int fd;
240 :
241 64 : if (lstat(fpath, &sb) != 0)
242 0 : pkg_emit_errno("fstat() failed for", fpath);
243 : /* ignore empty files and non regular files */
244 64 : if (sb.st_size == 0 || !S_ISREG(sb.st_mode))
245 62 : return (EPKG_END); /* Empty file or sym-link: no results */
246 :
247 2 : if ((fd = open(fpath, O_RDONLY, 0)) < 0) {
248 0 : return (EPKG_FATAL);
249 : }
250 :
251 2 : if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
252 0 : ret = EPKG_FATAL;
253 0 : pkg_emit_error("elf_begin() for %s failed: %s", fpath,
254 : elf_errmsg(-1));
255 0 : goto cleanup;
256 : }
257 :
258 2 : if (elf_kind(e) != ELF_K_ELF) {
259 : /* Not an elf file: no results */
260 2 : ret = EPKG_END;
261 2 : goto cleanup;
262 : }
263 :
264 0 : if (developer_mode)
265 0 : pkg->flags |= PKG_CONTAINS_ELF_OBJECTS;
266 :
267 0 : if (gelf_getehdr(e, &elfhdr) == NULL) {
268 0 : ret = EPKG_FATAL;
269 0 : pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1));
270 0 : goto cleanup;
271 : }
272 :
273 0 : if (elfhdr.e_type != ET_DYN && elfhdr.e_type != ET_EXEC &&
274 0 : elfhdr.e_type != ET_REL) {
275 0 : ret = EPKG_END;
276 0 : goto cleanup;
277 : }
278 :
279 : /* Elf file has sections header */
280 0 : while ((scn = elf_nextscn(e, scn)) != NULL) {
281 0 : if (gelf_getshdr(scn, &shdr) != &shdr) {
282 0 : ret = EPKG_FATAL;
283 0 : pkg_emit_error("getshdr() for %s failed: %s", fpath,
284 : elf_errmsg(-1));
285 0 : goto cleanup;
286 : }
287 0 : switch (shdr.sh_type) {
288 : case SHT_NOTE:
289 0 : if ((data = elf_getdata(scn, NULL)) == NULL) {
290 0 : ret = EPKG_END; /* Some error occurred, ignore this file */
291 0 : goto cleanup;
292 : }
293 0 : else if (data->d_buf != NULL) {
294 0 : Elf_Note *en = (Elf_Note *)data->d_buf;
295 0 : if (en->n_type == NT_ABI_TAG)
296 0 : note = scn;
297 : }
298 0 : break;
299 : case SHT_DYNAMIC:
300 0 : dynamic = scn;
301 0 : sh_link = shdr.sh_link;
302 0 : numdyn = shdr.sh_size / shdr.sh_entsize;
303 0 : break;
304 : }
305 :
306 0 : if (note != NULL && dynamic != NULL)
307 0 : break;
308 : }
309 :
310 : /*
311 : * note == NULL usually means a shared object for use with dlopen(3)
312 : * dynamic == NULL means not a dynamically linked elf
313 : */
314 0 : if (dynamic == NULL) {
315 0 : ret = EPKG_END;
316 0 : goto cleanup; /* not a dynamically linked elf: no results */
317 : }
318 :
319 0 : if (!shlib_valid_abi(fpath, &elfhdr, myarch)) {
320 0 : ret = EPKG_END;
321 0 : goto cleanup; /* Invalid ABI */
322 : }
323 :
324 0 : if (note != NULL) {
325 0 : if ((data = elf_getdata(note, NULL)) == NULL) {
326 0 : ret = EPKG_END; /* Some error occurred, ignore this file */
327 0 : goto cleanup;
328 : }
329 0 : if (data->d_buf == NULL) {
330 0 : ret = EPKG_END; /* No osname available */
331 0 : goto cleanup;
332 : }
333 0 : osname = (const char *) data->d_buf + sizeof(Elf_Note);
334 0 : if (strncasecmp(osname, "freebsd", sizeof("freebsd")) != 0 &&
335 0 : strncasecmp(osname, "dragonfly", sizeof("dragonfly")) != 0) {
336 0 : ret = EPKG_END; /* Foreign (probably linux) ELF object */
337 0 : goto cleanup;
338 : }
339 : } else {
340 0 : if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD) {
341 0 : ret = EPKG_END;
342 0 : goto cleanup;
343 : }
344 : }
345 :
346 0 : if ((data = elf_getdata(dynamic, NULL)) == NULL) {
347 0 : ret = EPKG_END; /* Some error occurred, ignore this file */
348 0 : goto cleanup;
349 : }
350 :
351 : /* First, scan through the data from the .dynamic section to
352 : find any RPATH or RUNPATH settings. These are colon
353 : separated paths to prepend to the ld.so search paths from
354 : the ELF hints file. These always seem to come right after
355 : the NEEDED shared library entries.
356 :
357 : NEEDED entries should resolve to a filename for installed
358 : executables, but need not resolve for installed shared
359 : libraries -- additional info from the apps that link
360 : against them would be required. Shared libraries are
361 : distinguished by a DT_SONAME tag */
362 :
363 0 : rpath_list_init();
364 0 : for (dynidx = 0; dynidx < numdyn; dynidx++) {
365 0 : if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
366 0 : ret = EPKG_FATAL;
367 0 : pkg_emit_error("getdyn() failed for %s: %s", fpath,
368 : elf_errmsg(-1));
369 0 : goto cleanup;
370 : }
371 :
372 0 : if (dyn->d_tag == DT_SONAME) {
373 0 : is_shlib = true;
374 :
375 : /* The file being scanned is a shared library
376 : *provided* by the package. Record this if
377 : appropriate */
378 :
379 0 : pkg_addshlib_provided(pkg, elf_strptr(e, sh_link, dyn->d_un.d_val));
380 : }
381 :
382 0 : if (dyn->d_tag != DT_RPATH && dyn->d_tag != DT_RUNPATH)
383 0 : continue;
384 :
385 0 : shlib_list_from_rpath(elf_strptr(e, sh_link, dyn->d_un.d_val),
386 0 : bsd_dirname(fpath));
387 0 : break;
388 : }
389 :
390 : /* Now find all of the NEEDED shared libraries. */
391 :
392 0 : for (dynidx = 0; dynidx < numdyn; dynidx++) {
393 0 : if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
394 0 : ret = EPKG_FATAL;
395 0 : pkg_emit_error("getdyn() failed for %s: %s", fpath,
396 : elf_errmsg(-1));
397 0 : goto cleanup;
398 : }
399 :
400 0 : if (dyn->d_tag != DT_NEEDED)
401 0 : continue;
402 :
403 0 : shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);
404 :
405 0 : add_shlibs_to_pkg(pkg, fpath, shlib, is_shlib);
406 : }
407 :
408 : cleanup:
409 2 : rpath_list_free();
410 :
411 2 : if (e != NULL)
412 2 : elf_end(e);
413 2 : close(fd);
414 :
415 2 : return (ret);
416 : }
417 :
418 : static int
419 0 : analyse_fpath(struct pkg *pkg, const char *fpath)
420 : {
421 : const char *dot;
422 :
423 0 : dot = strrchr(fpath, '.');
424 :
425 0 : if (dot == NULL) /* No extension */
426 0 : return (EPKG_OK);
427 :
428 0 : if (dot[1] == 'a' && dot[2] == '\0')
429 0 : pkg->flags |= PKG_CONTAINS_STATIC_LIBS;
430 :
431 0 : if ((dot[1] == 'l' && dot[2] == 'a' && dot[3] == '\0') ||
432 0 : (dot[1] == 'h' && dot[2] == '\0'))
433 0 : pkg->flags |= PKG_CONTAINS_H_OR_LA;
434 :
435 0 : return (EPKG_OK);
436 : }
437 :
438 : int
439 71 : pkg_analyse_files(struct pkgdb *db, struct pkg *pkg, const char *stage)
440 : {
441 71 : struct pkg_file *file = NULL;
442 : char *sh;
443 : khint_t k;
444 71 : int ret = EPKG_OK;
445 : char fpath[MAXPATHLEN];
446 : const char *lib;
447 71 : bool failures = false;
448 :
449 71 : if (kh_count(pkg->shlibs_required) != 0)
450 0 : pkg_list_free(pkg, PKG_SHLIBS_REQUIRED);
451 71 : if (kh_count(pkg->shlibs_provided) != 0)
452 2 : pkg_list_free(pkg, PKG_SHLIBS_PROVIDED);
453 :
454 71 : if (elf_version(EV_CURRENT) == EV_NONE)
455 0 : return (EPKG_FATAL);
456 :
457 71 : shlib_list_init();
458 :
459 71 : ret = shlib_list_from_elf_hints(_PATH_ELF_HINTS);
460 71 : if (ret != EPKG_OK)
461 0 : goto cleanup;
462 :
463 : /* Assume no architecture dependence, for contradiction */
464 71 : if (developer_mode)
465 3 : pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS |
466 : PKG_CONTAINS_STATIC_LIBS |
467 : PKG_CONTAINS_H_OR_LA);
468 :
469 206 : while (pkg_files(pkg, &file) == EPKG_OK) {
470 64 : if (stage != NULL)
471 14 : snprintf(fpath, sizeof(fpath), "%s/%s", stage, file->path);
472 : else
473 50 : strlcpy(fpath, file->path, sizeof(fpath));
474 :
475 64 : ret = analyse_elf(pkg, fpath);
476 64 : if (developer_mode) {
477 0 : if (ret != EPKG_OK && ret != EPKG_END) {
478 0 : failures = true;
479 0 : continue;
480 : }
481 0 : analyse_fpath(pkg, fpath);
482 : }
483 : }
484 :
485 : /*
486 : * Do not depend on libraries that a package provides itself
487 : */
488 71 : kh_each_value(pkg->shlibs_required, sh, {
489 : if (kh_contains(strings, pkg->shlibs_provided, sh)) {
490 : pkg_debug(2, "remove %s from required shlibs as the "
491 : "package %s provides this library itself",
492 : sh, pkg->name);
493 : k = kh_get_strings(pkg->shlibs_required, sh);
494 : kh_del_strings(pkg->shlibs_required, k);
495 : continue;
496 : }
497 : file = NULL;
498 : while (pkg_files(pkg, &file) == EPKG_OK) {
499 : if ((lib = strstr(file->path, sh)) != NULL &&
500 : strlen(lib) == strlen(sh) && lib[-1] == '/') {
501 : pkg_debug(2, "remove %s from required shlibs as "
502 : "the package %s provides this library itself",
503 : sh, pkg->name);
504 : k = kh_get_strings(pkg->shlibs_required, sh);
505 : kh_del_strings(pkg->shlibs_required, k);
506 : break;
507 : }
508 : }
509 : });
510 :
511 : /*
512 : * if the package is not supposed to provide share libraries then
513 : * drop the provided one
514 : */
515 71 : if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL)
516 0 : kh_free(strings, pkg->shlibs_provided, char, free);
517 :
518 71 : if (failures)
519 0 : goto cleanup;
520 :
521 71 : ret = EPKG_OK;
522 :
523 : cleanup:
524 71 : shlib_list_free();
525 :
526 71 : return (ret);
527 : }
528 :
529 : static const char *
530 876 : elf_corres_to_string(const struct _elf_corres* m, int e)
531 : {
532 876 : int i = 0;
533 :
534 1752 : for (i = 0; m[i].string != NULL; i++)
535 1752 : if (m[i].elf_nb == e)
536 876 : return (m[i].string);
537 :
538 0 : return ("unknown");
539 : }
540 :
541 : static int
542 0 : elf_string_to_corres(const struct _elf_corres* m, const char *s)
543 : {
544 0 : int i = 0;
545 :
546 0 : for (i = 0; m[i].string != NULL; i++)
547 0 : if (strcmp(m[i].string, s) == 0)
548 0 : return (m[i].elf_nb);
549 :
550 0 : return (-1);
551 : }
552 :
553 : static const char *
554 0 : aeabi_parse_arm_attributes(void *data, size_t length)
555 : {
556 : uint32_t sect_len;
557 0 : uint8_t *section = data;
558 :
559 : #define MOVE(len) do { \
560 : assert(length >= (len)); \
561 : section += (len); \
562 : length -= (len); \
563 : } while (0)
564 :
565 0 : if (length == 0 || *section != 'A')
566 0 : return (NULL);
567 0 : MOVE(1);
568 :
569 : /* Read the section length */
570 0 : if (length < sizeof(sect_len))
571 0 : return (NULL);
572 0 : memcpy(§_len, section, sizeof(sect_len));
573 :
574 : /*
575 : * The section length should be no longer than the section it is within
576 : */
577 0 : if (sect_len > length)
578 0 : return (NULL);
579 :
580 0 : MOVE(sizeof(sect_len));
581 :
582 : /* Skip the vendor name */
583 0 : while (length != 0) {
584 0 : if (*section == '\0')
585 0 : break;
586 0 : MOVE(1);
587 : }
588 0 : if (length == 0)
589 0 : return (NULL);
590 0 : MOVE(1);
591 :
592 0 : while (length != 0) {
593 : uint32_t tag_length;
594 :
595 0 : switch(*section) {
596 : case 1: /* Tag_File */
597 0 : MOVE(1);
598 0 : if (length < sizeof(tag_length))
599 0 : return (NULL);
600 0 : memcpy(&tag_length, section, sizeof(tag_length));
601 0 : break;
602 : case 2: /* Tag_Section */
603 : case 3: /* Tag_Symbol */
604 : default:
605 0 : return (NULL);
606 : }
607 : /* At least space for the tag and size */
608 0 : if (tag_length <= 5)
609 0 : return (NULL);
610 0 : tag_length--;
611 : /* Check the tag fits */
612 0 : if (tag_length > length)
613 0 : return (NULL);
614 :
615 : #define MOVE_TAG(len) do { \
616 : assert(tag_length >= (len)); \
617 : MOVE(len); \
618 : tag_length -= (len); \
619 : } while(0)
620 :
621 0 : MOVE(sizeof(tag_length));
622 0 : tag_length -= sizeof(tag_length);
623 :
624 0 : while (tag_length != 0) {
625 : uint8_t tag;
626 :
627 0 : assert(tag_length >= length);
628 :
629 0 : tag = *section;
630 0 : MOVE_TAG(1);
631 :
632 : /*
633 : * These tag values come from:
634 : *
635 : * Addenda to, and Errata in, the ABI for the
636 : * ARM Architecture. Release 2.08, section 2.3.
637 : */
638 0 : if (tag == 6) { /* == Tag_CPU_arch */
639 : uint8_t val;
640 :
641 0 : val = *section;
642 : /*
643 : * We don't support values that require
644 : * more than one byte.
645 : */
646 0 : if (val & (1 << 7))
647 0 : return (NULL);
648 :
649 : /* We have an ARMv4 or ARMv5 */
650 0 : if (val <= 5)
651 0 : return ("arm");
652 : else /* We have an ARMv6+ */
653 0 : return ("armv6");
654 0 : } else if (tag == 4 || tag == 5 || tag == 32 ||
655 0 : tag == 65 || tag == 67) {
656 0 : while (*section != '\0' && length != 0)
657 0 : MOVE_TAG(1);
658 0 : if (tag_length == 0)
659 0 : return (NULL);
660 : /* Skip the last byte */
661 0 : MOVE_TAG(1);
662 0 : } else if ((tag >= 7 && tag <= 31) || tag == 34 ||
663 0 : tag == 36 || tag == 38 || tag == 42 || tag == 44 ||
664 0 : tag == 64 || tag == 66 || tag == 68 || tag == 70) {
665 : /* Skip the uleb128 data */
666 0 : while (*section & (1 << 7) && length != 0)
667 0 : MOVE_TAG(1);
668 0 : if (tag_length == 0)
669 0 : return (NULL);
670 : /* Skip the last byte */
671 0 : MOVE_TAG(1);
672 : } else
673 0 : return (NULL);
674 : #undef MOVE_TAG
675 : }
676 :
677 0 : break;
678 : }
679 0 : return (NULL);
680 : #undef MOVE
681 : }
682 :
683 : static int
684 438 : pkg_get_myarch_elfparse(char *dest, size_t sz)
685 : {
686 438 : Elf *elf = NULL;
687 : GElf_Ehdr elfhdr;
688 : GElf_Shdr shdr;
689 : Elf_Data *data;
690 : Elf_Note note;
691 438 : Elf_Scn *scn = NULL;
692 : int fd;
693 438 : char *src = NULL;
694 : char *osname;
695 438 : uint32_t version = 0;
696 438 : int ret = EPKG_OK;
697 : const char *arch, *abi, *endian_corres_str, *wordsize_corres_str, *fpu;
698 : const char *path;
699 :
700 438 : path = getenv("ABI_FILE");
701 438 : if (path == NULL)
702 438 : path = _PATH_BSHELL;
703 :
704 438 : if (elf_version(EV_CURRENT) == EV_NONE) {
705 0 : pkg_emit_error("ELF library initialization failed: %s",
706 : elf_errmsg(-1));
707 0 : return (EPKG_FATAL);
708 : }
709 :
710 438 : if ((fd = open(path, O_RDONLY)) < 0) {
711 0 : pkg_emit_errno("open", _PATH_BSHELL);
712 0 : snprintf(dest, sz, "%s", "unknown");
713 0 : return (EPKG_FATAL);
714 : }
715 :
716 438 : if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
717 0 : ret = EPKG_FATAL;
718 0 : pkg_emit_error("elf_begin() failed: %s.", elf_errmsg(-1));
719 0 : goto cleanup;
720 : }
721 :
722 438 : if (gelf_getehdr(elf, &elfhdr) == NULL) {
723 0 : ret = EPKG_FATAL;
724 0 : pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1));
725 0 : goto cleanup;
726 : }
727 :
728 :
729 1314 : while ((scn = elf_nextscn(elf, scn)) != NULL) {
730 876 : if (gelf_getshdr(scn, &shdr) != &shdr) {
731 0 : ret = EPKG_FATAL;
732 0 : pkg_emit_error("getshdr() failed: %s.", elf_errmsg(-1));
733 0 : goto cleanup;
734 : }
735 :
736 876 : if (shdr.sh_type == SHT_NOTE)
737 438 : break;
738 : }
739 :
740 438 : if (scn == NULL) {
741 0 : ret = EPKG_FATAL;
742 0 : pkg_emit_error("failed to get the note section");
743 0 : goto cleanup;
744 : }
745 :
746 438 : data = elf_getdata(scn, NULL);
747 438 : src = data->d_buf;
748 876 : while ((uintptr_t)src < ((uintptr_t)data->d_buf + data->d_size)) {
749 438 : memcpy(¬e, src, sizeof(Elf_Note));
750 438 : src += sizeof(Elf_Note);
751 438 : if (note.n_type == NT_VERSION)
752 438 : break;
753 0 : src += roundup2(note.n_namesz + note.n_descsz, 4);
754 : }
755 438 : if ((uintptr_t)src >= ((uintptr_t)data->d_buf + data->d_size)) {
756 0 : ret = EPKG_FATAL;
757 0 : pkg_emit_error("failed to find the version elf note");
758 0 : goto cleanup;
759 : }
760 438 : osname = src;
761 438 : src += roundup2(note.n_namesz, 4);
762 438 : if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB)
763 0 : version = be32dec(src);
764 : else
765 438 : version = le32dec(src);
766 :
767 438 : wordsize_corres_str = elf_corres_to_string(wordsize_corres,
768 438 : (int)elfhdr.e_ident[EI_CLASS]);
769 :
770 438 : arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine);
771 : #if defined(__DragonFly__)
772 : snprintf(dest, sz, "%s:%d.%d",
773 : osname, version / 100000, (((version / 100 % 1000)+1)/2)*2);
774 : #else
775 438 : snprintf(dest, sz, "%s:%d", osname, version / 100000);
776 : #endif
777 :
778 438 : switch (elfhdr.e_machine) {
779 : case EM_ARM:
780 0 : endian_corres_str = elf_corres_to_string(endian_corres,
781 0 : (int)elfhdr.e_ident[EI_DATA]);
782 :
783 : /* FreeBSD doesn't support the hard-float ABI yet */
784 0 : fpu = "softfp";
785 0 : if ((elfhdr.e_flags & 0xFF000000) != 0) {
786 0 : const char *sh_name = NULL;
787 : size_t shstrndx;
788 :
789 : /* This is an EABI file, the conformance level is set */
790 0 : abi = "eabi";
791 :
792 : /* Find which TARGET_ARCH we are building for. */
793 0 : elf_getshdrstrndx(elf, &shstrndx);
794 0 : while ((scn = elf_nextscn(elf, scn)) != NULL) {
795 0 : sh_name = NULL;
796 0 : if (gelf_getshdr(scn, &shdr) != &shdr) {
797 0 : scn = NULL;
798 0 : break;
799 : }
800 :
801 0 : sh_name = elf_strptr(elf, shstrndx,
802 0 : shdr.sh_name);
803 0 : if (sh_name == NULL)
804 0 : continue;
805 0 : if (strcmp(".ARM.attributes", sh_name) == 0)
806 0 : break;
807 : }
808 0 : if (scn != NULL && sh_name != NULL) {
809 0 : data = elf_getdata(scn, NULL);
810 : /*
811 : * Prior to FreeBSD 10.0 libelf would return
812 : * NULL from elf_getdata on the .ARM.attributes
813 : * section. As this was the first release to
814 : * get armv6 support assume a NULL value means
815 : * arm.
816 : *
817 : * This assumption can be removed when 9.x
818 : * is unsupported.
819 : */
820 0 : if (data != NULL) {
821 0 : arch = aeabi_parse_arm_attributes(
822 : data->d_buf, data->d_size);
823 0 : if (arch == NULL) {
824 0 : ret = EPKG_FATAL;
825 0 : pkg_emit_error(
826 : "unknown ARM ARCH");
827 0 : goto cleanup;
828 : }
829 : }
830 : } else {
831 0 : ret = EPKG_FATAL;
832 0 : pkg_emit_error("Unable to find the "
833 : ".ARM.attributes section");
834 0 : goto cleanup;
835 : }
836 :
837 0 : } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) {
838 : /*
839 : * EABI executables all have this field set to
840 : * ELFOSABI_NONE, therefore it must be an oabi file.
841 : */
842 0 : abi = "oabi";
843 : } else {
844 : /*
845 : * We may have failed to positively detect the ABI,
846 : * set the ABI to unknown. If we end up here one of
847 : * the above cases should be fixed for the binary.
848 : */
849 0 : ret = EPKG_FATAL;
850 0 : pkg_emit_error("unknown ARM ABI");
851 0 : goto cleanup;
852 : }
853 0 : snprintf(dest + strlen(dest), sz - strlen(dest),
854 : ":%s:%s:%s:%s:%s", arch, wordsize_corres_str,
855 : endian_corres_str, abi, fpu);
856 0 : break;
857 : case EM_MIPS:
858 : /*
859 : * this is taken from binutils sources:
860 : * include/elf/mips.h
861 : * mapping is figured out from binutils:
862 : * gas/config/tc-mips.c
863 : */
864 0 : switch (elfhdr.e_flags & EF_MIPS_ABI) {
865 : case E_MIPS_ABI_O32:
866 0 : abi = "o32";
867 0 : break;
868 : case E_MIPS_ABI_N32:
869 0 : abi = "n32";
870 0 : break;
871 : default:
872 0 : if (elfhdr.e_ident[EI_DATA] == ELFCLASS32)
873 0 : abi = "o32";
874 0 : else if (elfhdr.e_ident[EI_DATA] == ELFCLASS64)
875 0 : abi = "n64";
876 : else
877 0 : abi = "unknown";
878 0 : break;
879 : }
880 0 : endian_corres_str = elf_corres_to_string(endian_corres,
881 0 : (int)elfhdr.e_ident[EI_DATA]);
882 :
883 0 : snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s",
884 : arch, wordsize_corres_str, endian_corres_str, abi);
885 0 : break;
886 : default:
887 438 : snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s",
888 : arch, wordsize_corres_str);
889 438 : break;
890 : }
891 :
892 : cleanup:
893 438 : if (elf != NULL)
894 438 : elf_end(elf);
895 :
896 438 : close(fd);
897 438 : return (ret);
898 : }
899 :
900 : int
901 305 : pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
902 : {
903 305 : int i = 0;
904 : struct arch_trans *arch_trans;
905 :
906 305 : bzero(dest, sz);
907 : /* Lower case the OS */
908 2211 : while (arch[i] != ':' && arch[i] != '\0') {
909 1601 : dest[i] = tolower(arch[i]);
910 1601 : i++;
911 : }
912 305 : if (arch[i] == '\0')
913 89 : return (0);
914 :
915 216 : dest[i++] = ':';
916 :
917 : /* Copy the version */
918 864 : while (arch[i] != ':' && arch[i] != '\0') {
919 432 : dest[i] = arch[i];
920 432 : i++;
921 : }
922 216 : if (arch[i] == '\0')
923 0 : return (0);
924 :
925 216 : dest[i++] = ':';
926 :
927 648 : for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL;
928 216 : arch_trans++) {
929 432 : if (strcmp(arch + i, arch_trans->archid) == 0) {
930 216 : strlcpy(dest + i, arch_trans->elftype,
931 216 : sz - (arch + i - dest));
932 216 : return (0);
933 : }
934 : }
935 0 : strlcpy(dest + i, arch + i, sz - (arch + i - dest));
936 :
937 0 : return (0);
938 : }
939 :
940 : int
941 200 : pkg_get_myarch_legacy(char *dest, size_t sz)
942 : {
943 : int i, err;
944 :
945 200 : err = pkg_get_myarch_elfparse(dest, sz);
946 200 : if (err)
947 0 : return (err);
948 :
949 3600 : for (i = 0; i < strlen(dest); i++)
950 3400 : dest[i] = tolower(dest[i]);
951 :
952 200 : return (0);
953 : }
954 :
955 : #ifndef __DragonFly__
956 : int
957 238 : pkg_get_myarch(char *dest, size_t sz)
958 : {
959 : struct arch_trans *arch_trans;
960 : char *arch_tweak;
961 :
962 : int err;
963 238 : err = pkg_get_myarch_elfparse(dest, sz);
964 238 : if (err)
965 0 : return (err);
966 :
967 : /* Translate architecture string back to regular OS one */
968 238 : arch_tweak = strchr(dest, ':');
969 238 : if (arch_tweak == NULL)
970 0 : return (0);
971 238 : arch_tweak++;
972 238 : arch_tweak = strchr(arch_tweak, ':');
973 238 : if (arch_tweak == NULL)
974 0 : return (0);
975 238 : arch_tweak++;
976 714 : for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL;
977 238 : arch_trans++) {
978 476 : if (strcmp(arch_tweak, arch_trans->elftype) == 0) {
979 238 : strlcpy(arch_tweak, arch_trans->archid,
980 238 : sz - (arch_tweak - dest));
981 238 : break;
982 : }
983 : }
984 :
985 238 : return (0);
986 : }
987 : #endif
988 :
|