2 * Copyright (C) ARM Limited 2013-2015. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
22 #include "SessionData.h"
25 // From linux-dev/include/linux/sched.h
26 #define TASK_COMM_LEN 16
27 // TASK_COMM_LEN may grow, so be ready for it to get larger
28 char comm[2*TASK_COMM_LEN];
32 static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) {
33 if (!b->read(pathname)) {
34 logg->logMessage("DynBuf::read failed, likely because the thread exited");
35 // This is not a fatal error - the thread just doesn't exist any more
39 char *comm = strchr(b->getBuf(), '(');
41 logg->logMessage("parsing stat failed");
45 char *const str = strrchr(comm, ')');
47 logg->logMessage("parsing stat failed");
51 strncpy(ps->comm, comm, sizeof(ps->comm) - 1);
52 ps->comm[sizeof(ps->comm) - 1] = '\0';
54 const int count = sscanf(str + 2, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld", &ps->numThreads);
56 logg->logMessage("sscanf failed");
63 static const char APP_PROCESS[] = "app_process";
65 static const char *readProcExe(DynBuf *const printb, const int pid, const int tid, DynBuf *const b) {
66 if (tid == -1 ? !printb->printf("/proc/%i/exe", pid)
67 : !printb->printf("/proc/%i/task/%i/exe", pid, tid)) {
68 logg->logMessage("DynBuf::printf failed");
72 const int err = b->readlink(printb->getBuf());
75 image = strrchr(b->getBuf(), '/');
81 } else if (err == -ENOENT) {
82 // readlink /proc/[pid]/exe returns ENOENT for kernel threads
85 logg->logMessage("DynBuf::readlink failed");
89 // Android apps are run by app_process but the cmdline is changed to reference the actual app name
90 // On 64-bit android app_process can be app_process32 or app_process64
91 if (strncmp(image, APP_PROCESS, sizeof(APP_PROCESS) - 1) != 0) {
95 if (tid == -1 ? !printb->printf("/proc/%i/cmdline", pid)
96 : !printb->printf("/proc/%i/task/%i/cmdline", pid, tid)) {
97 logg->logMessage("DynBuf::printf failed");
101 if (!b->read(printb->getBuf())) {
102 logg->logMessage("DynBuf::read failed, likely because the thread exited");
109 static bool readProcTask(const uint64_t currTime, Buffer *const buffer, const int pid, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
112 if (!b1->printf("/proc/%i/task", pid)) {
113 logg->logMessage("DynBuf::printf failed");
116 DIR *task = opendir(b1->getBuf());
118 logg->logMessage("opendir failed");
119 // This is not a fatal error - the thread just doesn't exist any more
123 struct dirent *dirent;
124 while ((dirent = readdir(task)) != NULL) {
126 const int tid = strtol(dirent->d_name, &endptr, 10);
127 if (*endptr != '\0') {
128 // Ignore task items that are not integers like ., etc...
132 if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) {
133 logg->logMessage("DynBuf::printf failed");
137 if (!readProcStat(&ps, printb->getBuf(), b1)) {
138 logg->logMessage("readProcStat failed");
142 const char *const image = readProcExe(printb, pid, tid, b2);
144 logg->logMessage("readImage failed");
148 buffer->marshalComm(currTime, pid, tid, image, ps.comm);
159 bool readProcComms(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
162 DIR *proc = opendir("/proc");
164 logg->logMessage("opendir failed");
168 struct dirent *dirent;
169 while ((dirent = readdir(proc)) != NULL) {
171 const int pid = strtol(dirent->d_name, &endptr, 10);
172 if (*endptr != '\0') {
173 // Ignore proc items that are not integers like ., cpuinfo, etc...
177 if (!printb->printf("/proc/%i/stat", pid)) {
178 logg->logMessage("DynBuf::printf failed");
182 if (!readProcStat(&ps, printb->getBuf(), b1)) {
183 logg->logMessage("readProcStat failed");
187 if (ps.numThreads <= 1) {
188 const char *const image = readProcExe(printb, pid, -1, b1);
190 logg->logMessage("readImage failed");
194 buffer->marshalComm(currTime, pid, pid, image, ps.comm);
196 if (!readProcTask(currTime, buffer, pid, printb, b1, b2)) {
197 logg->logMessage("readProcTask failed");
211 bool readProcMaps(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b) {
214 DIR *proc = opendir("/proc");
216 logg->logMessage("opendir failed");
220 struct dirent *dirent;
221 while ((dirent = readdir(proc)) != NULL) {
223 const int pid = strtol(dirent->d_name, &endptr, 10);
224 if (*endptr != '\0') {
225 // Ignore proc items that are not integers like ., cpuinfo, etc...
229 if (!printb->printf("/proc/%i/maps", pid)) {
230 logg->logMessage("DynBuf::printf failed");
233 if (!b->read(printb->getBuf())) {
234 logg->logMessage("DynBuf::read failed, likely because the process exited");
235 // This is not a fatal error - the process just doesn't exist any more
239 buffer->marshalMaps(currTime, pid, pid, b->getBuf());
250 bool readKallsyms(const uint64_t currTime, Buffer *const buffer, const bool *const isDone) {
251 int fd = ::open("/proc/kallsyms", O_RDONLY | O_CLOEXEC);
254 logg->logMessage("open failed");
260 while (gSessionData->mSessionIsActive && !ACCESS_ONCE(*isDone)) {
261 // Assert there is still space in the buffer
262 if (sizeof(buf) - pos - 1 == 0) {
263 logg->logError("no space left in buffer");
268 // -1 to reserve space for \0
269 const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1);
271 logg->logError("read failed");
275 // Assert the buffer is empty
277 logg->logError("buffer not empty on eof");
286 // Find the last '\n'
287 for (newline = pos - 1; newline >= 0; --newline) {
288 if (buf[newline] == '\n') {
289 const char was = buf[newline + 1];
290 buf[newline + 1] = '\0';
291 buffer->marshalKallsyms(currTime, buf);
292 // Sleep 3 ms to avoid sending out too much data too quickly
295 // Assert the memory regions do not overlap
296 if (pos - newline >= newline + 1) {
297 logg->logError("memcpy src and dst overlap");
300 if (pos - newline - 2 > 0) {
301 memcpy(buf + 1, buf + newline + 2, pos - newline - 2);