This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Make Stap compatible with Android


Hi folks,

it's been a long time since my first approach to submit my Android patch
set.
I re-worked my code 'a bit' and stripped it down to the bare essentials.
The result is attached to this mail. The patch is based on release-3.2.
It basically adds a new configure options: --with-android. This option
makes the configure libelf check optional and disables some parts of
stap{run,io} which depend on libelf.
The result is two binaries, staprun and stapio, which can be executed on
Android.

What do you think about these changes?

Regards,
Alex

-- 
Technische Universität Dortmund
Alexander Lochmann                PGP key: 0xBC3EF6FD
Otto-Hahn-Str. 16                 phone:  +49.231.7556141
D-44227 Dortmund                  fax:    +49.231.7556116
http://ess.cs.tu-dortmund.de/Staff/al
From 04579cae1833d3889279ea0eb6ecc53c7dbe79cb Mon Sep 17 00:00:00 2001
From: Alexander Lochmann <info@alexander-lochmann.de>
Date: Mon, 2 Apr 2018 20:02:46 +0200
Subject: [PATCH] Make SystemTap compatible with Android

Introduced a new configure option '--with-android' which disables
configure's libelf checks. It disables all libelf-related code in
stap{run,io} as well.
---
 build_android.sh        | 64 +++++++++++++++++++++++++++++++++++++++++
 configure.ac            | 21 ++++++++++----
 staprun/Makefile.am     | 12 ++++++++
 staprun/staprun.c       |  2 ++
 staprun/staprun_funcs.c | 30 +++++++++++++++++++
 5 files changed, 124 insertions(+), 5 deletions(-)
 create mode 100755 build_android.sh

diff --git a/build_android.sh b/build_android.sh
new file mode 100755
index 000000000..ce25c83c9
--- /dev/null
+++ b/build_android.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+BUILD_PREFIX="/data/data/com.systemtap.android/stap/"
+OUTPUT_DIR="android_binaries"
+STAPIO_BIN="staprun/stapio"
+STAPRUN_BIN="staprun/staprun"
+ARCH=${ARCH:-ARM}
+
+case ${ARCH} in
+ARM)
+	COMPILER_PREFIX_LIST=("arm-none-linux-gnueabi" "arm-unknown-linux-gnueabi")
+	;;
+AARCH64)
+	COMPILER_PREFIX_LIST=("aarch64-linux-gnu")
+	;;
+esac
+
+function checkCompiler()
+{
+	for cur_compiler_prefix in ${COMPILER_PREFIX_LIST[@]}
+	do
+		RET=`${cur_compiler_prefix}-gcc --version 2>&1`
+		if [ $? -eq 0 ];
+		then
+			COMPILER_PREFIX=${cur_compiler_prefix}
+			return
+		fi
+	done;
+
+	echo "No suitable compiler found. Check your PATH" >&2
+	exit 1
+}
+
+checkCompiler
+
+STAP_ANDROID_PREFIX="/data/data/com.systemtap.android/"
+# A bit of manually tuning of bindir and libexecdir.
+# This way stap{run,io} can both be stored in ${STAP_ANDROID_PREFIX}, and be executed *without* setting the environment variables SYSTEMTAP_STAP{IO,RUN}.
+./configure --prefix=${STAP_ANDROID_PREFIX} --bindir=${STAP_ANDROID_PREFIX}/systemtap --libexecdir=${STAP_ANDROID_PREFIX} --host=arm-none-linux-gnueabi --disable-translator --disable-docs --disable-refdocs --disable-grapher --without-rpm --without-nss --with-android
+
+if [ $? -ne 0 ]; then
+	echo "Error configuring the workspace" >&2
+	exit 1
+fi
+
+make 
+
+if [ $? -ne 0 ]; then
+	echo "Error building stap{run,io}" >&2
+	exit 1
+fi
+
+if [ -e $STAPRUN_BIN ] &&  [ -e $STAPIO_RUN ]; then
+	if [ ! -d $OUTPUT_DIR ]; then
+		mkdir $OUTPUT_DIR
+	fi
+	cp $STAPRUN_BIN $OUTPUT_DIR
+	cp $STAPIO_BIN $OUTPUT_DIR
+else
+	rm ${OUTPUT_DIR}/${STAPRUN_BIN}
+	rm ${OUTPUT_DIR}/${STAPIO_BIN}
+	echo "Some binaries were not created."
+	exit 1
+fi
diff --git a/configure.ac b/configure.ac
index b4dd4afea..5c381b138 100644
--- a/configure.ac
+++ b/configure.ac
@@ -531,7 +531,14 @@ AS_IF([test "x$with_python3" = "xyes"],
       [AS_IF([test "x$PYTHON" = "x:"],
              [AC_MSG_ERROR([python version 2 is required])],
 	     [AC_SUBST(preferred_python,[$PYTHON])])])
-      
+
+AC_ARG_WITH([android],
+  AS_HELP_STRING([--with-android],[]))
+AS_IF([test "x$with_android" = "xyes"],
+     [have_android=yes AC_DEFINE([HAVE_ANDROID], [1], [Define to 1 if you compile for Android.])],
+     [have_android=no])
+AM_CONDITIONAL([HAVE_ANDROID], [test "${have_android}" == "yes"])
+
 dnl Handle elfutils.  If '--with-elfutils=DIR' wasn't specified, used
 dnl the system's elfutils.
 build_elfutils=no
@@ -580,10 +587,14 @@ AC_MSG_NOTICE([stap will link $stap_LIBS])
 if test $build_elfutils = no; then
   save_LIBS="$LIBS"
   dnl this will only succeed with elfutils 0.142+
-  AC_CHECK_LIB(elf,elf_getshdrstrndx,[],[
-    AC_MSG_FAILURE([libelf too old, need 0.142+])])
-  staprun_LIBS="$staprun_LIBS -lelf"
-  stapbpf_LIBS="$stapbpf_LIBS -lelf"
+  if test "${have_android}" == "bo"; then
+	AC_CHECK_LIB(elf,elf_getshdrstrndx,
+	[staprun_LIBS="$staprun_LIBS -lelf"
+	LIBS="$save_LIBS"],
+	[AC_MSG_FAILURE([libelf too old, need 0.142+])])
+	staprun_LIBS="$staprun_LIBS -lelf"
+	stapbpf_LIBS="$stapbpf_LIBS -lelf"
+  fi
   LIBS="$save_LIBS"
 else
   # We built our own and staprun_LDFLAGS points at the install.
diff --git a/staprun/Makefile.am b/staprun/Makefile.am
index 4073aa01c..9dfe4fb8a 100644
--- a/staprun/Makefile.am
+++ b/staprun/Makefile.am
@@ -29,6 +29,9 @@ staprun_CXXFLAGS = $(AM_CXXFLAGS) -DSINGLE_THREADED
 staprun_CPPFLAGS = $(AM_CPPFLAGS)
 staprun_LDADD = libstrfloctime.a $(staprun_LIBS)
 staprun_LDFLAGS =  $(AM_LDFLAGS)
+if HAVE_ANDROID
+staprun_LDFLAGS += -static
+endif
 if BUILD_ELFUTILS
 staprun_CPPFLAGS += -I../include-elfutils
 staprun_LDFLAGS += -L../lib-elfutils -Wl,-rpath-link,lib-elfutils \
@@ -43,6 +46,9 @@ staprun_LDADD += $(nss_LIBS)
 endif
 
 stapio_SOURCES = stapio.c mainloop.c common.c ctl.c relay.c relay_old.c monitor.c
+if HAVE_ANDROID
+stapio_LDFLAGS = -static
+endif
 stapio_LDADD = libstrfloctime.a -lpthread
 
 if HAVE_MONITOR_LIBS
@@ -54,11 +60,17 @@ man_MANS = staprun.8
 stap_merge_SOURCES = stap_merge.c
 stap_merge_CFLAGS = $(AM_CFLAGS)
 stap_merge_LDFLAGS = $(AM_LDFLAGS)
+if HAVE_ANDROID
+stap_merge_LDFLAGS += -static
+endif
 stap_merge_LDADD =
 
 stapsh_SOURCES = stapsh.c
 stapsh_CFLAGS = $(AM_CFLAGS)
 stapsh_LDFLAGS = $(AM_LDFLAGS)
+if HAVE_ANDROID
+stapsh_LDFLAGS += -static
+endif
 stapsh_LDADD =
 
 BUILT_SOURCES =
diff --git a/staprun/staprun.c b/staprun/staprun.c
index 79d82f3df..26c201747 100644
--- a/staprun/staprun.c
+++ b/staprun/staprun.c
@@ -358,8 +358,10 @@ int init_staprun(void)
                 disable_kprobes_optimization();
 
 		if (insert_stap_module(& user_credentials) < 0) {
+#ifdef HAVE_ANDROID
 			if(!rename_mod && errno == EEXIST)
 				err("Rerun with staprun option '-R' to rename this module.\n");
+#endif
 			return -1;
 		}
 		rc = init_ctl_channel (modname, 0);
diff --git a/staprun/staprun_funcs.c b/staprun/staprun_funcs.c
index a938e0737..4d4c60037 100644
--- a/staprun/staprun_funcs.c
+++ b/staprun/staprun_funcs.c
@@ -19,10 +19,12 @@
 #include <pwd.h>
 #include <assert.h>
 
+#ifndef HAVE_ANDROID
 /* The module-renaming facility only works with new enough
    elfutils: 0.142+. */
 #include <libelf.h>
 #include <gelf.h>
+#endif
 
 #include <math.h>
 
@@ -206,6 +208,7 @@ int insert_module(
 	return 0;
 }
 
+#ifndef HAVE_ANDROID
 static Elf_Scn *
 find_section_in_module(const void* module_file, const __off_t st_size, const char *section_name)
 {
@@ -244,10 +247,12 @@ find_section_in_module(const void* module_file, const __off_t st_size, const cha
   	}
 	return scn;
 }
+#endif /* HAVE_ANDROID */
 
 int
 rename_module(void* module_file, const __off_t st_size)
 {
+#ifndef HAVE_ANDROID
 	int length_to_replace;
 	char newname[MODULE_NAME_LEN];
 	char *p;
@@ -305,6 +310,14 @@ rename_module(void* module_file, const __off_t st_size)
 	}
 	_err("Could not find old name to replace!\n");
 	return -1;
+#else
+        /* Old or no elfutils?  Pretend to have renamed.  This means a
+           greater likelihood for module-name collisions, but so be
+           it. */
+        (void) module_file;
+        (void) st_size;
+        return 0; 
+#endif /* HAVE_ANDROID */
 }
 
 
@@ -582,6 +595,22 @@ static privilege_t get_module_required_credentials (
   const __off_t st_size __attribute__ ((unused))
 )
 {
+#ifdef HAVE_ANDROID
+  /* Without the proper ELF support, we can't determine the credentials required to run this
+     module. However, we know that it has been correctly signed (we only check privilege
+     credentials for correctly signed modules). It is therefore either
+       a) a dual-privilege-level era module compiled with stapusr privileges enforced or,
+       b) a multi-privilege-level era module with built-in privilege level checking.
+     In either case, we can load it for stapusr level users and above. In case a, it requires
+     exactly that privilege level. In case b, the module will self check against the user's
+     actual privilege level.
+  */
+  if (verbose >= 1) {
+    err ("Unable to determine the privilege level required for the module %s. Assuming %s.\n",
+	 module_path, pr_name (pr_stapusr));
+  }
+  return pr_stapusr;
+#else
   Elf_Scn *scn = 0;
   Elf_Data *data = 0;
   GElf_Shdr shdr;
@@ -666,6 +695,7 @@ static privilege_t get_module_required_credentials (
 
   /* ALl is ok. Return the extracted privilege data. */
   return privilege;
+#endif /* HAVE_ANDROID */
 }
 
 /*
-- 
2.17.0

Attachment: signature.asc
Description: OpenPGP digital signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]