Module Name:    src
Committed By:   christos
Date:           Sun Jul  8 17:58:39 UTC 2018

Modified Files:
        src/sys/compat/linux/common: linux_exec_elf32.c

Log Message:
Enable executing linux go binaries by using a special probe function for them.


To generate a diff of this commit:
cvs rdiff -u -r1.94 -r1.95 src/sys/compat/linux/common/linux_exec_elf32.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/compat/linux/common/linux_exec_elf32.c
diff -u src/sys/compat/linux/common/linux_exec_elf32.c:1.94 src/sys/compat/linux/common/linux_exec_elf32.c:1.95
--- src/sys/compat/linux/common/linux_exec_elf32.c:1.94	Mon Feb  6 18:45:49 2017
+++ src/sys/compat/linux/common/linux_exec_elf32.c	Sun Jul  8 13:58:39 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: linux_exec_elf32.c,v 1.94 2017/02/06 23:45:49 uwe Exp $	*/
+/*	$NetBSD: linux_exec_elf32.c,v 1.95 2018/07/08 17:58:39 christos Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1998, 2000, 2001 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.94 2017/02/06 23:45:49 uwe Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_exec_elf32.c,v 1.95 2018/07/08 17:58:39 christos Exp $");
 
 #ifndef ELFSIZE
 /* XXX should die */
@@ -73,6 +73,8 @@ __KERNEL_RCSID(0, "$NetBSD: linux_exec_e
 #include <compat/linux/linux_syscallargs.h>
 #include <compat/linux/linux_syscall.h>
 
+#define LINUX_GO_RT0_SIGNATURE
+
 #ifdef DEBUG_LINUX
 #define DPRINTF(a)	uprintf a
 #else
@@ -264,6 +266,93 @@ out:
 }
 #endif
 
+#ifdef LINUX_GO_RT0_SIGNATURE
+/*
+ * Look for a .gopclntab, specific to go binaries
+ * in it look for a symbol called _rt0_<cpu>_linux
+ */
+static int
+ELFNAME2(linux,go_rt0_signature)(struct lwp *l, struct exec_package *epp, Elf_Ehdr *eh)
+{
+	Elf_Shdr *sh;
+	size_t shsize;
+	u_int shstrndx;
+	size_t i;
+	static const char signature[] = ".gopclntab";
+	const size_t sigsz = sizeof(signature);
+	char tbuf[sizeof(signature)], *tmp = NULL;
+	char mbuf[64];
+	const char *m;
+	int mlen;
+	int error;
+
+	/* Load the section header table. */
+	shsize = eh->e_shnum * sizeof(Elf_Shdr);
+	sh = malloc(shsize, M_TEMP, M_WAITOK);
+	error = exec_read_from(l, epp->ep_vp, eh->e_shoff, sh, shsize);
+	if (error)
+		goto out;
+
+	/* Now let's find the string table. If it does not exist, give up. */
+	shstrndx = eh->e_shstrndx;
+	if (shstrndx == SHN_UNDEF || shstrndx >= eh->e_shnum) {
+		error = ENOEXEC;
+		goto out;
+	}
+
+	/* Check if any section has the name we're looking for. */
+	const off_t stroff = sh[shstrndx].sh_offset;
+	for (i = 0; i < eh->e_shnum; i++) {
+		Elf_Shdr *s = &sh[i];
+
+		if (s->sh_name + sigsz > sh[shstrndx].sh_size)
+			continue;
+
+		error = exec_read_from(l, epp->ep_vp, stroff + s->sh_name, tbuf,
+		    sigsz);
+		if (error)
+			goto out;
+		if (!memcmp(tbuf, signature, sigsz)) {
+			DPRINTF(("linux_goplcntab_sig=%s\n", tbuf);
+			break;
+		}
+	}
+
+	if (i == eh->e_shnum) {
+		error = ENOEXEC;
+		goto out;
+	}
+
+	if (sh[i].sh_size > 1024 * 1014)
+		sh[i].sh_size = 1014 * 1014;
+
+	tmp = malloc(sh[i].sh_size, M_TEMP, M_WAITOK);
+	error = exec_read_from(l, epp->ep_vp, sh[i].sh_offset, tmp,
+	    sh[i].sh_size);
+	if (error)
+		goto out;
+
+#if (ELFSIZE == 32)
+	if (strcmp(machine, "amd64") == 0)
+		m = "i386";
+	else
+		m = machine;
+#else
+	m = machine;
+#endif
+	mlen = snprintf(mbuf, sizeof(mbuf), "_rt0_%s_linux", m);
+	if (memmem(tmp, sh[i].sh_size, mbuf, mlen) == NULL)
+		error = ENOEXEC;
+	else
+		DPRINTF(("linux_rt0_sig=%s\n", mbuf));
+out:
+	if (tmp)
+		free(tmp, M_TEMP);
+	free(sh, M_TEMP);
+	return error;
+}
+#endif
+
 int
 ELFNAME2(linux,signature)(struct lwp *l, struct exec_package *epp, Elf_Ehdr *eh, char *itp)
 {
@@ -356,6 +445,9 @@ ELFNAME2(linux,probe)(struct lwp *l, str
 #ifdef LINUX_DEBUGLINK_SIGNATURE
 	    ((error = ELFNAME2(linux,debuglink_signature)(l, epp, eh)) != 0) &&
 #endif
+#ifdef LINUX_GO_RT0_SIGNATURE
+	    ((error = ELFNAME2(linux,go_rt0_signature)(l, epp, eh)) != 0) &&
+#endif
 	    1) {
 			DPRINTF(("linux_probe: returning %d\n", error));
 			return error;

Reply via email to