Set up Android-specific debugging

Change-Id: I293568f0d0ee42dd64ee869e3c3ba28810e4883a
Reviewed-on: https://swiftshader-review.googlesource.com/2824
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Greg Hartman <ghartman@google.com>
diff --git a/src/Common/Debug.cpp b/src/Common/Debug.cpp
index b06e98f..a122c42 100644
--- a/src/Common/Debug.cpp
+++ b/src/Common/Debug.cpp
@@ -11,38 +11,23 @@
 
 #include "Debug.hpp"
 
-#ifdef __ANDROID__
-#include <utils/String8.h>
-#include <cutils/log.h>
-#endif
-
 #include <stdio.h>
 #include <stdarg.h>
 
-#ifdef __ANDROID__
-	void trace(const char *format, ...)
+void trace(const char *format, ...)
+{
+	if(false)
 	{
-		va_list vararg;
-		va_start(vararg, format);
-		ALOGI("%s", android::String8::formatV(format, vararg).string());
-		va_end(vararg);
-	}
-#else
-	void trace(const char *format, ...)
-	{
-		if(false)
+		FILE *file = fopen("debug.txt", "a");
+
+		if(file)
 		{
-			FILE *file = fopen("debug.txt", "a");
+			va_list vararg;
+			va_start(vararg, format);
+			vfprintf(file, format, vararg);
+			va_end(vararg);
 
-			if(file)
-			{
-				va_list vararg;
-				va_start(vararg, format);
-				vfprintf(file, format, vararg);
-				va_end(vararg);
-
-				fclose(file);
-			}
+			fclose(file);
 		}
 	}
-#endif
+}
diff --git a/src/Common/Debug.hpp b/src/Common/Debug.hpp
index 9cb4952..569e9a3 100644
--- a/src/Common/Debug.hpp
+++ b/src/Common/Debug.hpp
@@ -13,8 +13,8 @@
 #define Debug_hpp

 

 #ifdef __ANDROID__

-#include <cutils/log.h>

-#endif

+#include "DebugAndroid.hpp"

+#else

 

 #include <assert.h>

 #include <stdio.h>

@@ -30,30 +30,10 @@
 	#define TRACE(...) ((void)0)

 #endif

 

-#ifdef __ANDROID__

-	// On Android Virtual Devices we heavily depend on logging, even in

-	// production builds. We do this because AVDs are components of larger

-	// systems, and may be configured in ways that are difficult to

-	// reproduce locally. For example some system run tests against

-	// third-party code that we cannot access.  Aborting (cf. assert) on

-	// unimplemented functionality creates two problems. First, it produces

-	// a service failure where none is needed. Second, it puts the

-	// customer on the critical path for notifying us of a problem.

-	// The alternative, skipping unimplemented functionality silently, is

-	// arguably worse: neither the service provider nor the customer will

-	// learn that unimplemented functionality may have compromised the test

-	// results.

-	// Logging invocations of unimplemented functionality is useful to both

-	// service provider and the customer. The service provider can learn

-	// that the functionality is needed. The customer learns that the test

-	// results may be compromised.

-	#define UNIMPLEMENTED() {ALOGE("Unimplemented: %s %s:%d", __FUNCTION__, __FILE__, __LINE__); }

+#ifndef NDEBUG

+	#define UNIMPLEMENTED() {trace("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); ASSERT(false);}

 #else

-	#ifndef NDEBUG

-		#define UNIMPLEMENTED() {trace("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); ASSERT(false);}

-	#else

-		#define UNIMPLEMENTED() ((void)0)

-	#endif

+	#define UNIMPLEMENTED() ((void)0)

 #endif

 

 #ifndef NDEBUG

@@ -62,4 +42,5 @@
 	#define ASSERT assert

 #endif

 

+#endif   // __ANDROID__

 #endif   // Debug_hpp

diff --git a/src/Common/DebugAndroid.cpp b/src/Common/DebugAndroid.cpp
new file mode 100644
index 0000000..67e63cd
--- /dev/null
+++ b/src/Common/DebugAndroid.cpp
@@ -0,0 +1,34 @@
+#include "DebugAndroid.hpp"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <cutils/properties.h>
+
+void AndroidEnterDebugger()
+{
+    ALOGE(__FUNCTION__);
+#ifndef NDEBUG
+    static volatile int * const makefault = nullptr;
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.db.uid", value, "-1");
+    int debug_uid = atoi(value);
+    if ((debug_uid >= 0) && (geteuid() < static_cast<uid_t>(debug_uid)))
+    {
+        ALOGE("Waiting for debugger: gdbserver :${PORT} --attach %u", gettid());
+        while (1) {
+            pause();
+        }
+    } else {
+        ALOGE("No debugger");
+    }
+#endif
+}
+
+void trace(const char *format, ...)
+{
+    va_list vararg;
+    va_start(vararg, format);
+    android_vprintLog(ANDROID_LOG_VERBOSE, NULL, LOG_TAG, format, vararg);
+    va_end(vararg);
+}
diff --git a/src/Common/DebugAndroid.hpp b/src/Common/DebugAndroid.hpp
new file mode 100644
index 0000000..f87ba66
--- /dev/null
+++ b/src/Common/DebugAndroid.hpp
@@ -0,0 +1,75 @@
+#ifndef DebugAndroid_hpp
+#define DebugAndroid_hpp
+
+#include <cutils/log.h>
+
+// On Android Virtual Devices we heavily depend on logging, even in
+// production builds. We do this because AVDs are components of larger
+// systems, and may be configured in ways that are difficult to
+// reproduce locally. For example some system run tests against
+// third-party code that we cannot access.  Aborting (cf. assert) on
+// unimplemented functionality creates two problems. First, it produces
+// a service failure where none is needed. Second, it puts the
+// customer on the critical path for notifying us of a problem.
+// The alternative, skipping unimplemented functionality silently, is
+// arguably worse: neither the service provider nor the customer will
+// learn that unimplemented functionality may have compromised the test
+// results.
+// Logging invocations of unimplemented functionality is useful to both
+// service provider and the customer. The service provider can learn
+// that the functionality is needed. The customer learns that the test
+// results may be compromised.
+
+/**
+ * Enter the debugger with a memory fault iff debuggerd is set to capture this
+ * process. Otherwise return.
+ */
+void AndroidEnterDebugger();
+
+#define ASSERT(E) do { \
+		if (!(E)) { \
+			ALOGE("badness: assertion_failed %s in %s at %s:%d", #E,	\
+				  __FUNCTION__, __FILE__, __LINE__);					\
+			AndroidEnterDebugger();										\
+		}																\
+	} while(0)
+
+#define assert(E) ASSERT(E)
+
+#define ERR(format, ...)												\
+	do {																\
+		ALOGE("badness: err %s %s:%d (" format ")", __FUNCTION__, __FILE__, \
+			  __LINE__, ##__VA_ARGS__);									\
+		AndroidEnterDebugger();											\
+	} while(0)
+
+#define FIXME(format, ...)												\
+	do {																\
+		ALOGE("badness: fixme %s %s:%d (" format ")", __FUNCTION__, __FILE__, \
+			  __LINE__, ##__VA_ARGS__);									\
+		AndroidEnterDebugger();											\
+	} while(0)
+
+#define UNIMPLEMENTED() do {						\
+		ALOGE("badness: unimplemented: %s %s:%d",	\
+			  __FUNCTION__, __FILE__, __LINE__);	\
+		AndroidEnterDebugger();						\
+	} while(0)
+
+#define UNREACHABLE() do {								\
+		ALOGE("badness: unreachable reached: %s %s:%d",	\
+			  __FUNCTION__, __FILE__, __LINE__);		\
+		AndroidEnterDebugger();							\
+	} while(0)
+
+#ifndef NDEBUG
+	#define TRACE(format, ...)								   \
+		ALOGV("%s %s:%d (" format ")", __FUNCTION__, __FILE__, \
+			  __LINE__, ##__VA_ARGS__)
+#else
+	#define TRACE(...) ((void)0)
+#endif
+
+void trace(const char *format, ...);
+
+#endif   // DebugAndroid_hpp