aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2009-08-27 17:36:59 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2009-08-27 17:36:59 +0000
commitf613e8217080c49a8fbf89b40bbc4a0737a7b67c (patch)
tree3dcca9f4b33a8ec7790d3ef7e2823de99a2a9213
parent9d16faa36bea51e414201da64ff4c9fd6ff51c2b (diff)
Notes
-rw-r--r--sys/amd64/amd64/elf_machdep.c17
-rw-r--r--sys/amd64/amd64/trap.c16
-rw-r--r--sys/amd64/linux32/linux32_sysvec.c35
-rw-r--r--sys/compat/ia32/ia32_sysvec.c15
-rw-r--r--sys/i386/i386/elf_machdep.c16
-rw-r--r--sys/i386/i386/trap.c7
-rw-r--r--sys/i386/linux/linux_sysvec.c35
-rw-r--r--sys/kern/imgact_elf.c60
-rw-r--r--sys/sys/imgact_elf.h6
9 files changed, 188 insertions, 19 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index 2f33303e041b..a2d967079ce1 100644
--- a/sys/amd64/amd64/elf_machdep.c
+++ b/sys/amd64/amd64/elf_machdep.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/syscall.h>
+#include <sys/sysent.h>
#include <sys/signalvar.h>
#include <sys/vnode.h>
@@ -107,6 +108,22 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
(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,
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 8107864e51c7..16f8157e1d4b 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
*/
#include "opt_clock.h"
+#include "opt_compat.h"
#include "opt_cpu.h"
#include "opt_hwpmc_hooks.h"
#include "opt_isa.h"
@@ -115,6 +116,13 @@ dtrace_doubletrap_func_t dtrace_doubletrap_func;
systrace_probe_func_t systrace_probe_func;
#endif
+/* Defined in amd64/amd64/elf_machdep.c. */
+extern struct sysentvec elf64_freebsd_sysvec;
+#ifdef COMPAT_IA32
+/* Defined in compat/ia32/ia32_sysvec.c. */
+extern struct sysentvec ia32_freebsd_sysvec;
+#endif
+
extern void trap(struct trapframe *frame);
extern void syscall(struct trapframe *frame);
void dblfault_handler(struct trapframe *frame);
@@ -359,7 +367,13 @@ trap(struct trapframe *frame)
* This check also covers the images
* without the ABI-tag ELF note.
*/
- if (p->p_osrel >= 700004) {
+ if ((curproc->p_sysent ==
+ &elf64_freebsd_sysvec
+#ifdef COMPAT_IA32
+ || curproc->p_sysent ==
+ &ia32_freebsd_sysvec
+#endif
+ ) && p->p_osrel >= 700004) {
i = SIGSEGV;
ucode = SEGV_ACCERR;
} else {
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index 86d4bbd2bd23..5338da4a848c 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -126,6 +126,7 @@ static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
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;
@@ -1055,14 +1056,38 @@ struct sysentvec elf_linux_sysvec = {
.sv_maxssiz = &linux32_maxssiz,
};
-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 = {
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index 644dba6918ee..a44431a79e4a 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -171,6 +171,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,
diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c
index 6df39f7353d9..42779595ff89 100644
--- a/sys/i386/i386/elf_machdep.c
+++ b/sys/i386/i386/elf_machdep.c
@@ -107,6 +107,22 @@ SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
(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,
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 3d7633c74e78..fddad06a4e13 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -123,6 +123,9 @@ dtrace_doubletrap_func_t dtrace_doubletrap_func;
systrace_probe_func_t systrace_probe_func;
#endif
+/* Defined in i386/i386/elf_machdep.c. */
+extern struct sysentvec elf32_freebsd_sysvec;
+
extern void trap(struct trapframe *frame);
extern void syscall(struct trapframe *frame);
@@ -423,7 +426,9 @@ trap(struct trapframe *frame)
* This check also covers the images
* without the ABI-tag ELF note.
*/
- if (p->p_osrel >= 700004) {
+ if (curproc->p_sysent ==
+ &elf32_freebsd_sysvec &&
+ p->p_osrel >= 700004) {
i = SIGSEGV;
ucode = SEGV_ACCERR;
} else {
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index 8f43df3a4c66..522b8339ac68 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -107,6 +107,7 @@ static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
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;
@@ -1025,14 +1026,38 @@ struct sysentvec elf_linux_sysvec = {
.sv_maxssiz = NULL
};
-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 = {
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 5e6dc0e6f0f8..817a8ee40f46 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -86,6 +86,9 @@ static int __elfN(load_section)(struct vmspace *vmspace, vm_object_t object,
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);
@@ -119,9 +122,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: <major><two digit minor>Rxx) in the LSB way.
+ */
+ *osrel = desc[1] * 100000 + desc[2] * 1000 + desc[3];
+
+ return (TRUE);
+}
+
int
__elfN(insert_brand_entry)(Elf_Brandinfo *entry)
{
@@ -1382,11 +1432,9 @@ __elfN(check_note)(struct image_params *imgp, Elf_Brandnote *checknote,
* 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:
diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h
index c0410cb16416..7a9283946f21 100644
--- a/sys/sys/imgact_elf.h
+++ b/sys/sys/imgact_elf.h
@@ -59,7 +59,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 {
@@ -92,6 +95,7 @@ void __elfN(dump_thread)(struct thread *, void *, size_t *);
extern int __elfN(fallback_brand);
extern Elf_Brandnote __elfN(freebsd_brandnote);
+extern Elf_Brandnote __elfN(kfreebsd_brandnote);
#endif /* _KERNEL */
#endif /* !_SYS_IMGACT_ELF_H_ */