gator: Version 5.20

Signed-off-by: Jon Medhurst <tixy@linaro.org>
diff --git a/tools/gator/daemon/Proc.cpp b/tools/gator/daemon/Proc.cpp
index 9f01770..e6b26b1 100644
--- a/tools/gator/daemon/Proc.cpp
+++ b/tools/gator/daemon/Proc.cpp
@@ -10,13 +10,16 @@
 
 #include <dirent.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "Buffer.h"
 #include "DynBuf.h"
 #include "Logging.h"
+#include "SessionData.h"
 
 struct ProcStat {
 	// From linux-dev/include/linux/sched.h
@@ -57,6 +60,8 @@
 	return true;
 }
 
+static const char APP_PROCESS[] = "app_process";
+
 static const char *readProcExe(DynBuf *const printb, const int pid, const int tid, DynBuf *const b) {
 	if (tid == -1 ? !printb->printf("/proc/%i/exe", pid)
 			: !printb->printf("/proc/%i/task/%i/exe", pid, tid)) {
@@ -82,7 +87,8 @@
 	}
 
 	// Android apps are run by app_process but the cmdline is changed to reference the actual app name
-	if (strcmp(image, "app_process") != 0) {
+	// On 64-bit android app_process can be app_process32 or app_process64
+	if (strncmp(image, APP_PROCESS, sizeof(APP_PROCESS) - 1) != 0) {
 		return image;
 	}
 
@@ -100,7 +106,7 @@
 	return b->getBuf();
 }
 
-static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
+static bool readProcTask(const uint64_t currTime, Buffer *const buffer, const int pid, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
 	bool result = false;
 
 	if (!b1->printf("/proc/%i/task", pid)) {
@@ -110,7 +116,8 @@
 	DIR *task = opendir(b1->getBuf());
 	if (task == NULL) {
 		logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
-		return result;
+		// This is not a fatal error - the thread just doesn't exist any more
+		return true;
 	}
 
 	struct dirent *dirent;
@@ -138,7 +145,7 @@
 			goto fail;
 		}
 
-		buffer->comm(pid, tid, image, ps.comm);
+		buffer->comm(currTime, pid, tid, image, ps.comm);
 	}
 
 	result = true;
@@ -149,7 +156,7 @@
 	return result;
 }
 
-bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) {
+bool readProcComms(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
 	bool result = false;
 
 	DIR *proc = opendir("/proc");
@@ -177,19 +184,6 @@
 			goto fail;
 		}
 
-		if (sendMaps) {
-			if (!printb->printf("/proc/%i/maps", pid)) {
-				logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
-				goto fail;
-			}
-			if (!b2->read(printb->getBuf())) {
-				logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
-				// This is not a fatal error - the process just doesn't exist any more
-				continue;
-			}
-
-			buffer->maps(pid, pid, b2->getBuf());
-		}
 		if (ps.numThreads <= 1) {
 			const char *const image = readProcExe(printb, pid, -1, b1);
 			if (image == NULL) {
@@ -197,9 +191,9 @@
 				goto fail;
 			}
 
-			buffer->comm(pid, pid, image, ps.comm);
+			buffer->comm(currTime, pid, pid, image, ps.comm);
 		} else {
-			if (!readProcTask(buffer, pid, printb, b1, b3)) {
+			if (!readProcTask(currTime, buffer, pid, printb, b1, b2)) {
 				logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
 				goto fail;
 			}
@@ -213,3 +207,106 @@
 
 	return result;
 }
+
+bool readProcMaps(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b) {
+	bool result = false;
+
+	DIR *proc = opendir("/proc");
+	if (proc == NULL) {
+		logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
+		return result;
+	}
+
+	struct dirent *dirent;
+	while ((dirent = readdir(proc)) != NULL) {
+		char *endptr;
+		const int pid = strtol(dirent->d_name, &endptr, 10);
+		if (*endptr != '\0') {
+			// Ignore proc items that are not integers like ., cpuinfo, etc...
+			continue;
+		}
+
+		if (!printb->printf("/proc/%i/maps", pid)) {
+			logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
+			goto fail;
+		}
+		if (!b->read(printb->getBuf())) {
+			logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
+			// This is not a fatal error - the process just doesn't exist any more
+			continue;
+		}
+
+		buffer->maps(currTime, pid, pid, b->getBuf());
+	}
+
+	result = true;
+
+ fail:
+	closedir(proc);
+
+	return result;
+}
+
+bool readKallsyms(const uint64_t currTime, Buffer *const buffer, const bool *const isDone) {
+	int fd = ::open("/proc/kallsyms", O_RDONLY | O_CLOEXEC);
+
+	if (fd < 0) {
+		logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
+		return true;
+	};
+
+	char buf[1<<12];
+	ssize_t pos = 0;
+	while (gSessionData->mSessionIsActive && !ACCESS_ONCE(*isDone)) {
+		// Assert there is still space in the buffer
+		if (sizeof(buf) - pos - 1 == 0) {
+			logg->logError(__FILE__, __LINE__, "no space left in buffer");
+			handleException();
+		}
+
+		{
+			// -1 to reserve space for \0
+			const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1);
+			if (bytes < 0) {
+				logg->logError(__FILE__, __LINE__, "read failed", __FUNCTION__, __FILE__, __LINE__);
+				handleException();
+			}
+			if (bytes == 0) {
+				// Assert the buffer is empty
+				if (pos != 0) {
+					logg->logError(__FILE__, __LINE__, "buffer not empty on eof");
+					handleException();
+				}
+				break;
+			}
+			pos += bytes;
+		}
+
+		ssize_t newline;
+		// Find the last '\n'
+		for (newline = pos - 1; newline >= 0; --newline) {
+			if (buf[newline] == '\n') {
+				const char was = buf[newline + 1];
+				buf[newline + 1] = '\0';
+				buffer->kallsyms(currTime, buf);
+				// Sleep 3 ms to avoid sending out too much data too quickly
+				usleep(3000);
+				buf[0] = was;
+				// Assert the memory regions do not overlap
+				if (pos - newline >= newline + 1) {
+					logg->logError(__FILE__, __LINE__, "memcpy src and dst overlap");
+					handleException();
+				}
+				if (pos - newline - 2 > 0) {
+					memcpy(buf + 1, buf + newline + 2, pos - newline - 2);
+				}
+				pos -= newline + 1;
+				break;
+			}
+		}
+	}
+
+	close(fd);
+
+	return true;
+}