int pkg_get_myarch(char *dest, size_t sz) { Elf *elf = NULL; GElf_Ehdr elfhdr; GElf_Shdr shdr; Elf_Data *data; Elf_Note note; Elf_Scn *scn = NULL; int fd; char *src = NULL; char *osname; uint32_t version = 0; int ret = EPKG_OK; int i; const char *arch, *abi, *endian_corres_str, *wordsize_corres_str, *fpu; if (elf_version(EV_CURRENT) == EV_NONE) { pkg_emit_error("ELF library initialization failed: %s", elf_errmsg(-1)); return (EPKG_FATAL); } if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { pkg_emit_errno("open", _PATH_BSHELL); snprintf(dest, sz, "%s", "unknown"); return (EPKG_FATAL); } if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { ret = EPKG_FATAL; pkg_emit_error("elf_begin() failed: %s.", elf_errmsg(-1)); goto cleanup; } if (gelf_getehdr(elf, &elfhdr) == NULL) { ret = EPKG_FATAL; pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { ret = EPKG_FATAL; pkg_emit_error("getshdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } if (shdr.sh_type == SHT_NOTE) break; } if (scn == NULL) { ret = EPKG_FATAL; pkg_emit_error("failed to get the note section"); goto cleanup; } data = elf_getdata(scn, NULL); src = data->d_buf; while ((uintptr_t)src < ((uintptr_t)data->d_buf + data->d_size)) { memcpy(¬e, src, sizeof(Elf_Note)); src += sizeof(Elf_Note); if (note.n_type == NT_VERSION) break; src += note.n_namesz + note.n_descsz; } if ((uintptr_t)src >= ((uintptr_t)data->d_buf + data->d_size)) { ret = EPKG_FATAL; pkg_emit_error("failed to find the version elf note"); goto cleanup; } osname = src; src += roundup2(note.n_namesz, 4); if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) version = be32dec(src); else version = le32dec(src); for (i = 0; osname[i] != '\0'; i++) osname[i] = (char)tolower(osname[i]); wordsize_corres_str = elf_corres_to_string(wordsize_corres, (int)elfhdr.e_ident[EI_CLASS]); arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine); #if defined(__DragonFly__) snprintf(dest, sz, "%s:%d.%d", osname, version / 100000, (((version / 100 % 1000)+1)/2)*2); #else snprintf(dest, sz, "%s:%d", osname, version / 100000); #endif switch (elfhdr.e_machine) { case EM_ARM: endian_corres_str = elf_corres_to_string(endian_corres, (int)elfhdr.e_ident[EI_DATA]); /* FreeBSD doesn't support the hard-float ABI yet */ fpu = "softfp"; if ((elfhdr.e_flags & 0xFF000000) != 0) { const char *sh_name = NULL; size_t shstrndx; /* This is an EABI file, the conformance level is set */ abi = "eabi"; /* Find which TARGET_ARCH we are building for. */ elf_getshdrstrndx(elf, &shstrndx); while ((scn = elf_nextscn(elf, scn)) != NULL) { sh_name = NULL; if (gelf_getshdr(scn, &shdr) != &shdr) { scn = NULL; break; } sh_name = elf_strptr(elf, shstrndx, shdr.sh_name); if (sh_name == NULL) continue; if (strcmp(".ARM.attributes", sh_name) == 0) break; } if (scn != NULL && sh_name != NULL) { data = elf_getdata(scn, NULL); /* * Prior to FreeBSD 10.0 libelf would return * NULL from elf_getdata on the .ARM.attributes * section. As this was the first release to * get armv6 support assume a NULL value means * arm. * * This assumption can be removed when 9.x * is unsupported. */ if (data != NULL) { arch = aeabi_parse_arm_attributes( data->d_buf, data->d_size); if (arch == NULL) { ret = EPKG_FATAL; pkg_emit_error( "unknown ARM ARCH"); goto cleanup; } } } else { ret = EPKG_FATAL; pkg_emit_error("Unable to find the " ".ARM.attributes section"); goto cleanup; } } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) { /* * EABI executables all have this field set to * ELFOSABI_NONE, therefore it must be an oabi file. */ abi = "oabi"; } else { /* * We may have failed to positively detect the ABI, * set the ABI to unknown. If we end up here one of * the above cases should be fixed for the binary. */ ret = EPKG_FATAL; pkg_emit_error("unknown ARM ABI"); goto cleanup; } snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s:%s", arch, wordsize_corres_str, endian_corres_str, abi, fpu); break; case EM_MIPS: /* * this is taken from binutils sources: * include/elf/mips.h * mapping is figured out from binutils: * gas/config/tc-mips.c */ switch (elfhdr.e_flags & EF_MIPS_ABI) { case E_MIPS_ABI_O32: abi = "o32"; break; case E_MIPS_ABI_N32: abi = "n32"; break; default: if (elfhdr.e_ident[EI_DATA] == ELFCLASS32) abi = "o32"; else if (elfhdr.e_ident[EI_DATA] == ELFCLASS64) abi = "n64"; else abi = "unknown"; break; } endian_corres_str = elf_corres_to_string(endian_corres, (int)elfhdr.e_ident[EI_DATA]); snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s", arch, wordsize_corres_str, endian_corres_str, abi); break; default: snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", arch, wordsize_corres_str); break; } cleanup: if (elf != NULL) elf_end(elf); close(fd); return (ret); }
static int pkg_get_myabi(char *dest, size_t sz) { Elf *elf; Elf_Data *data; Elf_Note note; Elf_Scn *scn; char *src, *osname; const char *abi; GElf_Ehdr elfhdr; GElf_Shdr shdr; int fd, i, ret; uint32_t version; version = 0; ret = -1; scn = NULL; abi = NULL; if (elf_version(EV_CURRENT) == EV_NONE) { warnx("ELF library initialization failed: %s", elf_errmsg(-1)); return (-1); } if ((fd = open("/bin/sh", O_RDONLY)) < 0) { warn("open()"); return (-1); } if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { ret = -1; warnx("elf_begin() failed: %s.", elf_errmsg(-1)); goto cleanup; } if (gelf_getehdr(elf, &elfhdr) == NULL) { ret = -1; warn("getehdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { ret = -1; warn("getshdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } if (shdr.sh_type == SHT_NOTE) break; } if (scn == NULL) { ret = -1; warn("failed to get the note section"); goto cleanup; } data = elf_getdata(scn, NULL); src = data->d_buf; for (;;) { memcpy(¬e, src, sizeof(Elf_Note)); src += sizeof(Elf_Note); if (note.n_type == NT_VERSION) break; src += note.n_namesz + note.n_descsz; } osname = src; src += note.n_namesz; if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) version = be32dec(src); else version = le32dec(src); for (i = 0; osname[i] != '\0'; i++) osname[i] = (char)tolower(osname[i]); snprintf(dest, sz, "%s:%d:%s:%s", osname, version / 100000, elf_corres_to_string(mach_corres, (int)elfhdr.e_machine), elf_corres_to_string(wordsize_corres, (int)elfhdr.e_ident[EI_CLASS])); ret = 0; switch (elfhdr.e_machine) { case EM_ARM: snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s", elf_corres_to_string(endian_corres, (int)elfhdr.e_ident[EI_DATA]), (elfhdr.e_flags & EF_ARM_NEW_ABI) > 0 ? "eabi" : "oabi", (elfhdr.e_flags & EF_ARM_VFP_FLOAT) > 0 ? "softfp" : "vfp"); break; case EM_MIPS: /* * this is taken from binutils sources: * include/elf/mips.h * mapping is figured out from binutils: * gas/config/tc-mips.c */ switch (elfhdr.e_flags & EF_MIPS_ABI) { case E_MIPS_ABI_O32: abi = "o32"; break; case E_MIPS_ABI_N32: abi = "n32"; break; default: if (elfhdr.e_ident[EI_DATA] == ELFCLASS32) abi = "o32"; else if (elfhdr.e_ident[EI_DATA] == ELFCLASS64) abi = "n64"; break; } snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", elf_corres_to_string(endian_corres, (int)elfhdr.e_ident[EI_DATA]), abi); break; } cleanup: if (elf != NULL) elf_end(elf); close(fd); return (ret); }
static bool shlib_valid_abi(const char *fpath, GElf_Ehdr *hdr, const char *abi) { int semicolon; const char *p, *t; char arch[64], wordsize[64]; int wclass; const char *shlib_arch; /* * ABI string is in format: * <osname>:<osversion>:<arch>:<wordsize>[.other] * We need here arch and wordsize only */ arch[0] = '\0'; wordsize[0] = '\0'; p = abi; for(semicolon = 0; semicolon < 3 && p != NULL; semicolon ++, p ++) { p = strchr(p, ':'); if (p != NULL) { switch(semicolon) { case 1: /* We have arch here */ t = strchr(p + 1, ':'); /* Abi line is likely invalid */ if (t == NULL) return (true); strlcpy(arch, p + 1, MIN((long)sizeof(arch), t - p)); break; case 2: t = strchr(p + 1, ':'); if (t == NULL) strlcpy(wordsize, p + 1, sizeof(wordsize)); else strlcpy(wordsize, p + 1, MIN((long)sizeof(wordsize), t - p)); break; } } } /* Invalid ABI line */ if (arch[0] == '\0' || wordsize[0] == '\0') return (true); shlib_arch = elf_corres_to_string(mach_corres, (int)hdr->e_machine); if (shlib_arch == NULL) return (true); wclass = elf_string_to_corres(wordsize_corres, wordsize); if (wclass == -1) return (true); /* * Compare wordsize first as the arch for amd64/i386 is an abmiguous * 'x86' */ if ((int)hdr->e_ident[EI_CLASS] != wclass) { pkg_debug(1, "not valid elf class for shlib: %s: %s", elf_corres_to_string(wordsize_corres, (int)hdr->e_ident[EI_CLASS]), fpath); return (false); } if (strcmp(shlib_arch, arch) != 0) { pkg_debug(1, "not valid abi for shlib: %s: %s", shlib_arch, fpath); return (false); } return (true); }
int pkg_get_myarch(char *dest, size_t sz) { Elf *elf = NULL; GElf_Ehdr elfhdr; GElf_Shdr shdr; Elf_Data *data; Elf_Note note; Elf_Scn *scn = NULL; int fd; char *src = NULL; char *osname; uint32_t version = 0; int ret = EPKG_OK; int i; const char *abi, *endian_corres_str, *wordsize_corres_str; if (elf_version(EV_CURRENT) == EV_NONE) { pkg_emit_error("ELF library initialization failed: %s", elf_errmsg(-1)); return (EPKG_FATAL); } if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { pkg_emit_errno("open", _PATH_BSHELL); snprintf(dest, sz, "%s", "unknown"); return (EPKG_FATAL); } if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { ret = EPKG_FATAL; pkg_emit_error("elf_begin() failed: %s.", elf_errmsg(-1)); goto cleanup; } if (gelf_getehdr(elf, &elfhdr) == NULL) { ret = EPKG_FATAL; pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { ret = EPKG_FATAL; pkg_emit_error("getshdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } if (shdr.sh_type == SHT_NOTE) break; } if (scn == NULL) { ret = EPKG_FATAL; pkg_emit_error("fail to get the note section"); goto cleanup; } data = elf_getdata(scn, NULL); src = data->d_buf; while (1) { memcpy(¬e, src, sizeof(Elf_Note)); src += sizeof(Elf_Note); if (note.n_type == NT_VERSION) break; src += note.n_namesz + note.n_descsz; } osname = src; src += roundup2(note.n_namesz, 4); if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) version = be32dec(src); else version = le32dec(src); for (i = 0; osname[i] != '\0'; i++) osname[i] = (char)tolower(osname[i]); wordsize_corres_str = elf_corres_to_string(wordsize_corres, (int)elfhdr.e_ident[EI_CLASS]); #if defined(__DragonFly__) snprintf(dest, sz, "%s:%d.%d:%s:%s", osname, version / 100000, (((version / 100 % 1000)+1)/2)*2, #else snprintf(dest, sz, "%s:%d:%s:%s", osname, version / 100000, #endif elf_corres_to_string(mach_corres, (int) elfhdr.e_machine), wordsize_corres_str); switch (elfhdr.e_machine) { case EM_ARM: endian_corres_str = elf_corres_to_string(endian_corres, (int)elfhdr.e_ident[EI_DATA]); snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s", endian_corres_str, (elfhdr.e_flags & EF_ARM_NEW_ABI) > 0 ? "eabi" : "oabi", (elfhdr.e_flags & EF_ARM_VFP_FLOAT) > 0 ? "softfp" : "vfp"); break; case EM_MIPS: /* * this is taken from binutils sources: * include/elf/mips.h * mapping is figured out from binutils: * gas/config/tc-mips.c */ switch (elfhdr.e_flags & EF_MIPS_ABI) { case E_MIPS_ABI_O32: abi = "o32"; break; case E_MIPS_ABI_N32: abi = "n32"; break; default: if (elfhdr.e_ident[EI_DATA] == ELFCLASS32) abi = "o32"; else if (elfhdr.e_ident[EI_DATA] == ELFCLASS64) abi = "n64"; else abi = "unknown"; break; } endian_corres_str = elf_corres_to_string(endian_corres, (int)elfhdr.e_ident[EI_DATA]); snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", endian_corres_str, abi); break; default: break; } cleanup: if (elf != NULL) elf_end(elf); close(fd); return (ret); }