From owner-svn-src-all@FreeBSD.ORG Mon Aug 24 16:19:47 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id AFA54106564A; Mon, 24 Aug 2009 16:19:47 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 9C5DD8FC12; Mon, 24 Aug 2009 16:19:47 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n7OGJlvD099886; Mon, 24 Aug 2009 16:19:47 GMT (envelope-from bz@svn.freebsd.org) Received: (from bz@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n7OGJlvq099876; Mon, 24 Aug 2009 16:19:47 GMT (envelope-from bz@svn.freebsd.org) Message-Id: <200908241619.n7OGJlvq099876@svn.freebsd.org> From: "Bjoern A. Zeeb" Date: Mon, 24 Aug 2009 16:19:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r196512 - in head/sys: amd64/amd64 amd64/linux32 compat/ia32 i386/i386 i386/linux kern sys X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 24 Aug 2009 16:19:47 -0000 Author: bz Date: Mon Aug 24 16:19:47 2009 New Revision: 196512 URL: http://svn.freebsd.org/changeset/base/196512 Log: Fix handling of .note.ABI-tag section for GNU systems [1]. Handle GNU/Linux according to LSB Core Specification 4.0, Chapter 11. Object Format, 11.8. ABI note tag. Also check the first word of desc, not only name, according to glibc abi-tags specification to distinguish between Linux and kFreeBSD. Add explicit handling for Debian GNU/kFreeBSD, which runs on our kernels as well [2]. In {amd64,i386}/trap.c, when checking osrel of the current process, also check the ABI to not change the signal behaviour for Linux binary processes, now that we save an osrel version for all three from the lists above in struct proc [2]. These changes make it possible to run FreeBSD, Debian GNU/kFreeBSD and Linux binaries on the same machine again for at least i386 and amd64, and no longer break kFreeBSD which was detected as GNU(/Linux). PR: kern/135468 Submitted by: dchagin [1] (initial patch) Suggested by: kib [2] Tested by: Petr Salinger (Petr.Salinger seznam.cz) for kFreeBSD Reviewed by: kib MFC after: 3 days Modified: head/sys/amd64/amd64/elf_machdep.c head/sys/amd64/amd64/trap.c head/sys/amd64/linux32/linux32_sysvec.c head/sys/compat/ia32/ia32_sysvec.c head/sys/i386/i386/elf_machdep.c head/sys/i386/i386/trap.c head/sys/i386/linux/linux_sysvec.c head/sys/kern/imgact_elf.c head/sys/sys/imgact_elf.h Modified: head/sys/amd64/amd64/elf_machdep.c ============================================================================== --- head/sys/amd64/amd64/elf_machdep.c Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/amd64/amd64/elf_machdep.c Mon Aug 24 16:19:47 2009 (r196512) @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -108,6 +109,22 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_AN (sysinit_cfunc_t) elf64_insert_brand_entry, &freebsd_brand_oinfo); +static Elf64_Brandinfo kfreebsd_brand_info = { + .brand = ELFOSABI_FREEBSD, + .machine = EM_X86_64, + .compat_3_brand = "FreeBSD", + .emul_path = NULL, + .interp_path = "/lib/ld-kfreebsd-x86-64.so.1", + .sysvec = &elf64_freebsd_sysvec, + .interp_newpath = NULL, + .brand_note = &elf64_kfreebsd_brandnote, + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE +}; + +SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t) elf64_insert_brand_entry, + &kfreebsd_brand_info); + void elf64_dump_thread(struct thread *td __unused, void *dst __unused, Modified: head/sys/amd64/amd64/trap.c ============================================================================== --- head/sys/amd64/amd64/trap.c Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/amd64/amd64/trap.c Mon Aug 24 16:19:47 2009 (r196512) @@ -409,7 +409,9 @@ trap(struct trapframe *frame) * This check also covers the images * without the ABI-tag ELF note. */ - if (p->p_osrel >= 700004) { + if (SV_CURPROC_ABI() == + SV_ABI_FREEBSD && + p->p_osrel >= 700004) { i = SIGSEGV; ucode = SEGV_ACCERR; } else { Modified: head/sys/amd64/linux32/linux32_sysvec.c ============================================================================== --- head/sys/amd64/linux32/linux32_sysvec.c Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/amd64/linux32/linux32_sysvec.c Mon Aug 24 16:19:47 2009 (r196512) @@ -127,6 +127,7 @@ static void linux_sendsig(sig_t catc static void exec_linux_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings); static void linux32_fixlimit(struct rlimit *rl, int which); +static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); static eventhandler_tag linux_exit_tag; static eventhandler_tag linux_schedtail_tag; @@ -1066,14 +1067,38 @@ struct sysentvec elf_linux_sysvec = { .sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32 }; -static char GNULINUX_ABI_VENDOR[] = "GNU"; +static char GNU_ABI_VENDOR[] = "GNU"; +static int GNULINUX_ABI_DESC = 0; + +static boolean_t +linux32_trans_osrel(const Elf_Note *note, int32_t *osrel) +{ + const Elf32_Word *desc; + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + + desc = (const Elf32_Word *)p; + if (desc[0] != GNULINUX_ABI_DESC) + return (FALSE); + + /* + * For linux we encode osrel as follows (see linux_mib.c): + * VVVMMMIII (version, major, minor), see linux_mib.c. + */ + *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; + + return (TRUE); +} static Elf_Brandnote linux32_brandnote = { - .hdr.n_namesz = sizeof(GNULINUX_ABI_VENDOR), - .hdr.n_descsz = 16, + .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), + .hdr.n_descsz = 16, /* XXX at least 16 */ .hdr.n_type = 1, - .vendor = GNULINUX_ABI_VENDOR, - .flags = 0 + .vendor = GNU_ABI_VENDOR, + .flags = BN_TRANSLATE_OSREL, + .trans_osrel = linux32_trans_osrel }; static Elf32_Brandinfo linux_brand = { Modified: head/sys/compat/ia32/ia32_sysvec.c ============================================================================== --- head/sys/compat/ia32/ia32_sysvec.c Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/compat/ia32/ia32_sysvec.c Mon Aug 24 16:19:47 2009 (r196512) @@ -172,6 +172,21 @@ SYSINIT(oia32, SI_SUB_EXEC, SI_ORDER_ANY (sysinit_cfunc_t) elf32_insert_brand_entry, &ia32_brand_oinfo); +static Elf32_Brandinfo kia32_brand_info = { + .brand = ELFOSABI_FREEBSD, + .machine = EM_386, + .compat_3_brand = "FreeBSD", + .emul_path = NULL, + .interp_path = "/lib/ld.so.1", + .sysvec = &ia32_freebsd_sysvec, + .brand_note = &elf32_kfreebsd_brandnote, + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE +}; + +SYSINIT(kia32, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t) elf32_insert_brand_entry, + &kia32_brand_info); + void elf32_dump_thread(struct thread *td __unused, void *dst __unused, Modified: head/sys/i386/i386/elf_machdep.c ============================================================================== --- head/sys/i386/i386/elf_machdep.c Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/i386/i386/elf_machdep.c Mon Aug 24 16:19:47 2009 (r196512) @@ -108,6 +108,22 @@ SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_AN (sysinit_cfunc_t) elf32_insert_brand_entry, &freebsd_brand_oinfo); +static Elf32_Brandinfo kfreebsd_brand_info = { + .brand = ELFOSABI_FREEBSD, + .machine = EM_386, + .compat_3_brand = "FreeBSD", + .emul_path = NULL, + .interp_path = "/lib/ld.so.1", + .sysvec = &elf32_freebsd_sysvec, + .interp_newpath = NULL, + .brand_note = &elf32_kfreebsd_brandnote, + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE +}; + +SYSINIT(kelf32, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t) elf32_insert_brand_entry, + &kfreebsd_brand_info); + void elf32_dump_thread(struct thread *td __unused, void *dst __unused, Modified: head/sys/i386/i386/trap.c ============================================================================== --- head/sys/i386/i386/trap.c Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/i386/i386/trap.c Mon Aug 24 16:19:47 2009 (r196512) @@ -423,7 +423,9 @@ trap(struct trapframe *frame) * This check also covers the images * without the ABI-tag ELF note. */ - if (p->p_osrel >= 700004) { + if (SV_CURPROC_ABI() == + SV_ABI_FREEBSD && + p->p_osrel >= 700004) { i = SIGSEGV; ucode = SEGV_ACCERR; } else { Modified: head/sys/i386/linux/linux_sysvec.c ============================================================================== --- head/sys/i386/linux/linux_sysvec.c Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/i386/linux/linux_sysvec.c Mon Aug 24 16:19:47 2009 (r196512) @@ -108,6 +108,7 @@ static void linux_sendsig(sig_t catc static void exec_linux_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings); static register_t *linux_copyout_strings(struct image_params *imgp); +static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel); static int linux_szplatform; const char *linux_platform; @@ -1027,14 +1028,38 @@ struct sysentvec elf_linux_sysvec = { .sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32 }; -static char GNULINUX_ABI_VENDOR[] = "GNU"; +static char GNU_ABI_VENDOR[] = "GNU"; +static int GNULINUX_ABI_DESC = 0; + +static boolean_t +linux_trans_osrel(const Elf_Note *note, int32_t *osrel) +{ + const Elf32_Word *desc; + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + + desc = (const Elf32_Word *)p; + if (desc[0] != GNULINUX_ABI_DESC) + return (FALSE); + + /* + * For linux we encode osrel as follows (see linux_mib.c): + * VVVMMMIII (version, major, minor), see linux_mib.c. + */ + *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; + + return (TRUE); +} static Elf_Brandnote linux_brandnote = { - .hdr.n_namesz = sizeof(GNULINUX_ABI_VENDOR), - .hdr.n_descsz = 16, + .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), + .hdr.n_descsz = 16, /* XXX at least 16 */ .hdr.n_type = 1, - .vendor = GNULINUX_ABI_VENDOR, - .flags = 0 + .vendor = GNU_ABI_VENDOR, + .flags = BN_TRANSLATE_OSREL, + .trans_osrel = linux_trans_osrel }; static Elf32_Brandinfo linux_brand = { Modified: head/sys/kern/imgact_elf.c ============================================================================== --- head/sys/kern/imgact_elf.c Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/kern/imgact_elf.c Mon Aug 24 16:19:47 2009 (r196512) @@ -86,6 +86,9 @@ static int __elfN(load_section)(struct v vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot, size_t pagesize); static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp); +static boolean_t __elfN(freebsd_trans_osrel)(const Elf_Note *note, + int32_t *osrel); +static boolean_t kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel); static boolean_t __elfN(check_note)(struct image_params *imgp, Elf_Brandnote *checknote, int32_t *osrel); @@ -116,9 +119,56 @@ Elf_Brandnote __elfN(freebsd_brandnote) .hdr.n_descsz = sizeof(int32_t), .hdr.n_type = 1, .vendor = FREEBSD_ABI_VENDOR, - .flags = BN_CAN_FETCH_OSREL + .flags = BN_TRANSLATE_OSREL, + .trans_osrel = __elfN(freebsd_trans_osrel) }; +static boolean_t +__elfN(freebsd_trans_osrel)(const Elf_Note *note, int32_t *osrel) +{ + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + *osrel = *(const int32_t *)(p); + + return (TRUE); +} + +static const char GNU_ABI_VENDOR[] = "GNU"; +static int GNU_KFREEBSD_ABI_DESC = 3; + +Elf_Brandnote __elfN(kfreebsd_brandnote) = { + .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), + .hdr.n_descsz = 16, /* XXX at least 16 */ + .hdr.n_type = 1, + .vendor = GNU_ABI_VENDOR, + .flags = BN_TRANSLATE_OSREL, + .trans_osrel = kfreebsd_trans_osrel +}; + +static boolean_t +kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel) +{ + const Elf32_Word *desc; + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + + desc = (const Elf32_Word *)p; + if (desc[0] != GNU_KFREEBSD_ABI_DESC) + return (FALSE); + + /* + * Debian GNU/kFreeBSD embed the earliest compatible kernel version + * (__FreeBSD_version: Rxx) in the LSB way. + */ + *osrel = desc[1] * 100000 + desc[2] * 1000 + desc[3]; + + return (TRUE); +} + int __elfN(insert_brand_entry)(Elf_Brandinfo *entry) { @@ -1371,11 +1421,9 @@ __elfN(check_note)(struct image_params * * Fetch the osreldate for binary * from the ELF OSABI-note if necessary. */ - if ((checknote->flags & BN_CAN_FETCH_OSREL) != 0 && - osrel != NULL) - *osrel = *(const int32_t *) (note_name + - roundup2(checknote->hdr.n_namesz, - sizeof(Elf32_Addr))); + if ((checknote->flags & BN_TRANSLATE_OSREL) != 0 && + checknote->trans_osrel != NULL) + return (checknote->trans_osrel(note, osrel)); return (TRUE); nextnote: Modified: head/sys/sys/imgact_elf.h ============================================================================== --- head/sys/sys/imgact_elf.h Mon Aug 24 13:10:55 2009 (r196511) +++ head/sys/sys/imgact_elf.h Mon Aug 24 16:19:47 2009 (r196512) @@ -58,7 +58,10 @@ typedef struct { Elf_Note hdr; const char * vendor; int flags; -#define BN_CAN_FETCH_OSREL 0x0001 + boolean_t (*trans_osrel)(const Elf_Note *, int32_t *); +#define BN_CAN_FETCH_OSREL 0x0001 /* Deprecated. */ +#define BN_TRANSLATE_OSREL 0x0002 /* Use trans_osrel fetch osrel after */ + /* checking ABI contraint if needed. */ } Elf_Brandnote; typedef struct { @@ -91,6 +94,7 @@ void __elfN(dump_thread)(struct thread * extern int __elfN(fallback_brand); extern Elf_Brandnote __elfN(freebsd_brandnote); +extern Elf_Brandnote __elfN(kfreebsd_brandnote); #endif /* _KERNEL */ #endif /* !_SYS_IMGACT_ELF_H_ */