diff --git a/Process.c b/Process.c index e30c6808..4223adc1 100644 --- a/Process.c +++ b/Process.c @@ -472,7 +472,8 @@ void Process_makeCommandStr(Process *this) { const int baseAttr = Process_isThread(this) ? CRT_colors[PROCESS_THREAD_BASENAME] : CRT_colors[PROCESS_BASENAME]; const int commAttr = Process_isThread(this) ? CRT_colors[PROCESS_THREAD_COMM] : CRT_colors[PROCESS_COMM]; - const int delAttr = CRT_colors[FAILED_READ]; + const int delExeAttr = CRT_colors[FAILED_READ]; + const int delLibAttr = CRT_colors[PROCESS_TAG]; /* Establish some shortcuts to data we need */ const char *cmdline = this->cmdline; @@ -529,14 +530,18 @@ void Process_makeCommandStr(Process *this) { WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM); WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME); if (this->procExeDeleted) - WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, delAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + else if (this->usesDeletedLib) + WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); str = stpcpy(str, procExe); } else { if (haveCommInExe) WRITE_HIGHLIGHT(0, exeBasenameLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM); WRITE_HIGHLIGHT(0, exeBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME); if (this->procExeDeleted) - WRITE_HIGHLIGHT(0, exeBasenameLen, delAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + WRITE_HIGHLIGHT(0, exeBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); + else if (this->usesDeletedLib) + WRITE_HIGHLIGHT(0, exeBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED); str = stpcpy(str, procExe + exeBasenameOffset); } diff --git a/Process.h b/Process.h index 2ff1aa09..f4daac06 100644 --- a/Process.h +++ b/Process.h @@ -163,6 +163,9 @@ typedef struct Process_ { /* Tells if the executable has been replaced in the filesystem since start */ bool procExeDeleted; + /* Tells if the process uses replaced shared libraries since start */ + bool usesDeletedLib; + /* CPU number last executed on */ int processor; diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index 79706c04..1c5359fc 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -517,18 +517,24 @@ static void LinuxProcessList_calcLibSize_helper(ATTR_UNUSED ht_key_t key, void* *d += v->size; } -static uint64_t LinuxProcessList_calcLibSize(openat_arg_t procFd) { +static void LinuxProcessList_readMaps(LinuxProcess* process, openat_arg_t procFd, bool calcSize, bool checkDeletedLib) { + Process* proc = (Process*)process; + + proc->usesDeletedLib = false; + FILE* mapsfile = fopenat(procFd, "maps", "r"); if (!mapsfile) - return 0; + return; - Hashtable* ht = Hashtable_new(64, true); + Hashtable* ht = NULL; + if (calcSize) + ht = Hashtable_new(64, true); char buffer[1024]; while (fgets(buffer, sizeof(buffer), mapsfile)) { uint64_t map_start; uint64_t map_end; - char map_perm[5]; + bool map_execute; unsigned int map_devmaj; unsigned int map_devmin; uint64_t map_inode; @@ -548,8 +554,7 @@ static uint64_t LinuxProcessList_calcLibSize(openat_arg_t procFd) { if (' ' != *readptr++) continue; - memcpy(map_perm, readptr, 4); - map_perm[4] = '\0'; + map_execute = (readptr[2] == 'x'); readptr += 4; if (' ' != *readptr++) continue; @@ -575,38 +580,58 @@ static uint64_t LinuxProcessList_calcLibSize(openat_arg_t procFd) { if (!map_inode) continue; - LibraryData* libdata = Hashtable_get(ht, map_inode); - if (!libdata) { - libdata = xCalloc(1, sizeof(LibraryData)); - Hashtable_put(ht, map_inode, libdata); + if (calcSize) { + LibraryData* libdata = Hashtable_get(ht, map_inode); + if (!libdata) { + libdata = xCalloc(1, sizeof(LibraryData)); + Hashtable_put(ht, map_inode, libdata); + } + + libdata->size += map_end - map_start; + libdata->exec |= map_execute; } - libdata->size += map_end - map_start; - libdata->exec |= 'x' == map_perm[2]; + if (checkDeletedLib && map_execute && !proc->usesDeletedLib) { + while (*readptr == ' ') + readptr++; + + if (*readptr != '/') + continue; + + if (String_startsWith(readptr, "/memfd:")) + continue; + + if (strstr(readptr, " (deleted)\n")) { + proc->usesDeletedLib = true; + if (!calcSize) + break; + } + } } fclose(mapsfile); - uint64_t total_size = 0; - Hashtable_foreach(ht, LinuxProcessList_calcLibSize_helper, &total_size); + if (calcSize) { + uint64_t total_size = 0; + Hashtable_foreach(ht, LinuxProcessList_calcLibSize_helper, &total_size); - Hashtable_delete(ht); + Hashtable_delete(ht); - return total_size / pageSize; + process->m_lrs = total_size / pageSize; + } } -static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t procFd, bool performLookup, unsigned long long realtimeMs) { +static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t procFd) { FILE* statmfile = fopenat(procFd, "statm", "r"); if (!statmfile) return false; - long tmp_m_lrs = 0; int r = fscanf(statmfile, "%ld %ld %ld %ld %ld %ld %ld", &process->super.m_virt, &process->super.m_resident, &process->m_share, &process->m_trs, - &tmp_m_lrs, + &process->m_lrs, &process->m_drs, &process->m_dt); fclose(statmfile); @@ -614,22 +639,6 @@ static bool LinuxProcessList_readStatmFile(LinuxProcess* process, openat_arg_t p if (r == 7) { process->super.m_virt *= pageSizeKB; process->super.m_resident *= pageSizeKB; - - if (tmp_m_lrs) { - process->m_lrs = tmp_m_lrs; - } else if (performLookup) { - // Check if we really should recalculate the M_LRS value for this process - uint64_t passedTimeInMs = realtimeMs - process->last_mlrs_calctime; - - uint64_t recheck = ((uint64_t)rand()) % 2048; - - if(passedTimeInMs > 2000 || passedTimeInMs > recheck) { - process->last_mlrs_calctime = realtimeMs; - process->m_lrs = LinuxProcessList_calcLibSize(procFd); - } - } else { - // Keep previous value - } } return r == 7; @@ -1340,9 +1349,30 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ if (settings->flags & PROCESS_FLAG_IO) LinuxProcessList_readIoFile(lp, procFd, pl->realtimeMs); - if (!LinuxProcessList_readStatmFile(lp, procFd, !!(settings->flags & PROCESS_FLAG_LINUX_LRS_FIX), pl->realtimeMs)) + if (!LinuxProcessList_readStatmFile(lp, procFd)) goto errorReadingProcess; + { + bool prev = proc->usesDeletedLib; + + if ((lp->m_lrs == 0 && (settings->flags & PROCESS_FLAG_LINUX_LRS_FIX)) || settings->highlightDeletedExe) { + // Check if we really should recalculate the M_LRS value for this process + uint64_t passedTimeInMs = pl->realtimeMs - lp->last_mlrs_calctime; + + uint64_t recheck = ((uint64_t)rand()) % 2048; + + if (passedTimeInMs > 2000 || passedTimeInMs > recheck) { + lp->last_mlrs_calctime = pl->realtimeMs; + LinuxProcessList_readMaps(lp, procFd, settings->flags & PROCESS_FLAG_LINUX_LRS_FIX, settings->highlightDeletedExe); + } + } else { + /* reset if setting got disabled */ + proc->usesDeletedLib = false; + } + + proc->mergedCommand.exeChanged |= prev ^ proc->usesDeletedLib; + } + if ((settings->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) { if (!parent) { // Read smaps file of each process only every second pass to improve performance