diff options
author | Jon Medhurst <tixy@linaro.org> | 2014-10-30 18:01:15 +0000 |
---|---|---|
committer | Jon Medhurst <tixy@linaro.org> | 2014-11-18 14:26:02 +0000 |
commit | 730ab7f66781e433083572fb9000092e172bec3c (patch) | |
tree | 3f288815ce3ff5e84fafbe568bb4597b988a8191 /tools/gator/daemon/Proc.cpp | |
parent | e49849053ac342ce82c92aa0d2244e4767fd1fbb (diff) |
gator: Version 5.20
Signed-off-by: Jon Medhurst <tixy@linaro.org>
Diffstat (limited to 'tools/gator/daemon/Proc.cpp')
-rw-r--r-- | tools/gator/daemon/Proc.cpp | 137 |
1 files changed, 117 insertions, 20 deletions
diff --git a/tools/gator/daemon/Proc.cpp b/tools/gator/daemon/Proc.cpp index 9f01770d6609..e6b26b1199fa 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 @@ static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf 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 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti } // 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 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti 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 @@ static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const prin 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 @@ static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const prin goto fail; } - buffer->comm(pid, tid, image, ps.comm); + buffer->comm(currTime, pid, tid, image, ps.comm); } result = true; @@ -149,7 +156,7 @@ static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const prin 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 @@ bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf 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 @@ bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf 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 @@ bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf 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; +} |