Commandline for "attach" mode now detects executable name and path from /proc/<pid>/exe.

This commit is contained in:
Ernie Pasveer
2023-07-31 13:29:59 -05:00
parent 3996e63ab9
commit da0eac7cbb
5 changed files with 116 additions and 93 deletions
+101 -91
View File
@@ -20,6 +20,105 @@
#include <sys/types.h>
QProcessInfo QProcessInfo::populate(uint32_t pid) {
QProcessInfo info;
info.setPid(pid);
QDir processDir(QStringLiteral("/proc/") + QString::number(pid));
// default to the exe symlink if valid
QFileInfo exe(processDir.absoluteFilePath(QStringLiteral("exe")));
exe = QFileInfo(exe.symLinkTarget());
info.setName(exe.completeBaseName());
info.setPath(exe.absolutePath());
// if we didn't get a name from the symlink, check in the status file
if (info.name().isEmpty()) {
QFile status(processDir.absoluteFilePath(QStringLiteral("status")));
if (status.open(QIODevice::ReadOnly)) {
QByteArray contents = status.readAll();
QTextStream in(&contents);
while(!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith(QStringLiteral("Name:"))) {
line.remove(0, 5);
// if we're using this name, surround with []s to indicate it's not a file
info.setName(QStringLiteral("[%1]").arg(line.trimmed()));
info.setPath("");
break;
}
}
status.close();
}
}
// Get the username.
QFile status(processDir.absoluteFilePath(QStringLiteral("status")));
if (status.open(QIODevice::ReadOnly)) {
QByteArray contents = status.readAll();
QTextStream in(&contents);
while(!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith(QStringLiteral("Uid:"))) {
info.setUsername(line.split(QRegularExpression("\\s+")).at(1));
break;
}
}
status.close();
struct passwd* pw = getpwuid(info.username().toULong());
if (pw) {
info.setUsername(pw->pw_name);
}
}
// Get the command line
QFile cmdline(processDir.absoluteFilePath(QStringLiteral("cmdline")));
if (cmdline.open(QIODevice::ReadOnly)) {
QByteArray contents = cmdline.readAll();
int nullIdx = contents.indexOf('\0');
if (nullIdx > 0) {
QString firstparam = QString::fromUtf8(contents.data(), nullIdx);
// if name is a truncated form of a filename, replace it
if (firstparam.endsWith(info.name()) && QFileInfo::exists(firstparam)) {
info.setName(QFileInfo(firstparam).completeBaseName());
info.setPath(QFileInfo(firstparam).absolutePath());
}
// if we don't have a name, replace it but with []s
if (info.name().isEmpty()) {
info.setName(QStringLiteral("[%1]").arg(firstparam));
info.setPath("");
}
contents.replace('\0', ' ');
}
info.setCommandLine(QString::fromUtf8(contents).trimmed());
cmdline.close();
}
return info;
}
QProcessList QProcessInfo::populate() {
QProcessList ret;
@@ -35,97 +134,8 @@ QProcessList QProcessInfo::populate() {
if (ok) {
QProcessInfo info;
info.setPid(pid);
QDir processDir(QStringLiteral("/proc/") + f);
// default to the exe symlink if valid
QFileInfo exe(processDir.absoluteFilePath(QStringLiteral("exe")));
exe = QFileInfo(exe.symLinkTarget());
info.setName(exe.completeBaseName());
info.setPath(exe.absolutePath());
// if we didn't get a name from the symlink, check in the status file
if (info.name().isEmpty()) {
QFile status(processDir.absoluteFilePath(QStringLiteral("status")));
if (status.open(QIODevice::ReadOnly)) {
QByteArray contents = status.readAll();
QTextStream in(&contents);
while(!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith(QStringLiteral("Name:"))) {
line.remove(0, 5);
// if we're using this name, surround with []s to indicate it's not a file
info.setName(QStringLiteral("[%1]").arg(line.trimmed()));
info.setPath("");
break;
}
}
status.close();
}
}
// Get the username.
QFile status(processDir.absoluteFilePath(QStringLiteral("status")));
if (status.open(QIODevice::ReadOnly)) {
QByteArray contents = status.readAll();
QTextStream in(&contents);
while(!in.atEnd()) {
QString line = in.readLine();
if (line.startsWith(QStringLiteral("Uid:"))) {
info.setUsername(line.split(QRegularExpression("\\s+")).at(1));
break;
}
}
status.close();
struct passwd* pw = getpwuid(info.username().toULong());
if (pw) {
info.setUsername(pw->pw_name);
}
}
// Get the command line
QFile cmdline(processDir.absoluteFilePath(QStringLiteral("cmdline")));
if (cmdline.open(QIODevice::ReadOnly)) {
QByteArray contents = cmdline.readAll();
int nullIdx = contents.indexOf('\0');
if (nullIdx > 0) {
QString firstparam = QString::fromUtf8(contents.data(), nullIdx);
// if name is a truncated form of a filename, replace it
if (firstparam.endsWith(info.name()) && QFileInfo::exists(firstparam)) {
info.setName(QFileInfo(firstparam).completeBaseName());
info.setPath(QFileInfo(firstparam).absolutePath());
}
// if we don't have a name, replace it but with []s
if (info.name().isEmpty()) {
info.setName(QStringLiteral("[%1]").arg(firstparam));
info.setPath("");
}
contents.replace('\0', ' ');
}
info.setCommandLine(QString::fromUtf8(contents).trimmed());
cmdline.close();
}
// Get process info for pid.
QProcessInfo info = QProcessInfo::populate(pid);
// Add the process to the list.
ret.push_back(info);