app: build fake auxv

Some Android systems cannot read from /proc/self/auxv. Work around
this by creating a minimal fake auxv for the Go runtime.

Fixes #9229

Change-Id: Id2d743f43d91be23006aac708a5b5b5cd60a6dca
Reviewed-on: https://go-review.googlesource.com/1284
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
David Crawshaw
2014-12-10 17:26:16 +00:00
parent 7b659348a5
commit 32030f7750
4 changed files with 87 additions and 26 deletions
+3 -26
View File
@@ -48,41 +48,18 @@ static void* init_go_runtime(void* unused) {
// Defensively heap-allocate argv0, for setenv.
char* argv0 = strdup("gojni");
// Build argv, including the ELF auxiliary vector, which is loaded
// from /proc/self/auxv. While there does not appear to be any
// spec for this format, there are some notes in
//
// Phrack, V. 0x0b, Issue 0x3a, P. 0x05.
// http://phrack.org/issues/58/5.html
//
// For our needs, we don't need to know the format beyond the fact
// that argv is followed by a meaningless envp, then a series of
// NUL terminated bytes that make up auxv.
// Build argv, including the ELF auxiliary vector.
struct {
char* argv[2];
char* envp[2];
char* auxv[1024];
uint32_t auxv[64];
} x;
x.argv[0] = argv0;
x.argv[1] = NULL;
x.envp[0] = argv0;
x.envp[1] = NULL;
int fd = open("/proc/self/auxv", O_RDONLY, 0);
if (fd == -1) {
__android_log_print(ANDROID_LOG_FATAL, "Go", "cannot open /proc/self/auxv: %s", strerror(errno));
}
int n = read(fd, &x.auxv, sizeof x.auxv - 1);
if (n < 0) {
__android_log_print(ANDROID_LOG_FATAL, "Go", "error reading /proc/self/auxv: %s", strerror(errno));
}
if (n == sizeof x.auxv - 1) { // x.auxv should be more than plenty.
__android_log_print(ANDROID_LOG_FATAL, "Go", "/proc/self/auxv too big");
}
close(fd);
x.auxv[n / sizeof(char*)] = NULL;
build_auxv(x.auxv, sizeof(x.auxv)/sizeof(uint32_t));
int32_t argc = 1;
_rt0_arm_linux1(argc, x.argv);
return NULL;
+15
View File
@@ -33,6 +33,21 @@ int go_started;
// OpenJDK there is JNI_GetCreatedJavaVMs, but this is not available
// on android.
JavaVM* current_vm;
// build_auxv builds an ELF auxiliary vector for initializing the Go
// runtime. While there does not appear to be any spec for this
// format, there are some notes in
//
// Phrack, V. 0x0b, Issue 0x3a, P. 0x05.
// http://phrack.org/issues/58/5.html
//
// Much of the time on linux the real auxv can be read from the file
// /proc/self/auxv, however there are several conditions under which
// Android apps cannot read this file (see a note to this effect in
// sources/android/cpufeatures/cpu-features.c). So we construct a
// fake one, working backwards from what the Go runtime wants to see
// as defined by the code in src/runtime/os_linux_GOARCH.c.
void build_auxv(uint32_t *auxv, size_t len);
*/
import "C"
import (
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build android,arm
#include <android/log.h>
#include <stdint.h>
#include <string.h>
#include "_cgo_export.h"
#define AT_PLATFORM 15
#define AT_HWCAP 16
#define HWCAP_VFP (1 << 6)
#define HWCAP_VFPv3 (1 << 13)
void build_auxv(uint32_t *auxv, size_t len) {
// Minimum auxv required by runtime/os_linux_arm.go.
int i;
if (len < 5) {
__android_log_print(ANDROID_LOG_FATAL, "Go", "auxv len %d too small", len);
}
auxv[0] = AT_PLATFORM;
*(char**)&auxv[1] = strdup("v7l");
auxv[2] = AT_HWCAP;
auxv[3] = HWCAP_VFP | HWCAP_VFPv3;
for (i = 4; i < len; i++) {
auxv[i] = 0;
}
}
+38
View File
@@ -0,0 +1,38 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build android,x86
#include <android/log.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "_cgo_export.h"
void build_auxv(uint32_t *xauxv, size_t xauxv_len) {
char* auxv = (char*)xauxv;
size_t auxv_len = xauxv_len*sizeof(uint32_t);
// TODO(crawshaw): determine if we can read /proc/self/auxv on
// x86 android release builds.
int fd = open("/proc/self/auxv", O_RDONLY, 0);
if (fd == -1) {
__android_log_print(ANDROID_LOG_FATAL, "Go", "cannot open /proc/self/auxv: %s", strerror(errno));
}
int n = read(fd, &auxv, auxv_len);
if (n < 0) {
__android_log_print(ANDROID_LOG_FATAL, "Go", "error reading /proc/self/auxv: %s", strerror(errno));
}
if (n == auxv_len) { // auxv should be more than plenty.
__android_log_print(ANDROID_LOG_FATAL, "Go", "/proc/self/auxv too big");
}
close(fd);
for (; n < auxv_len; n++) {
auxv[n] = 0;
}
}