diff --git a/CHANGELOG.md b/CHANGELOG.md index 0596d8c..aaafeb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ * Add a method to add/change a breakpoint's condition command. * Add a method to add/change a breakpoint's ignore count. * Add a method to add/change a breakpoint's command list. -* Debug dialog for "attach" mode now detects executable name and path. +* Debug dialog for "attach" mode now detects executable name and path from /proc//exe. +* Commandline for "attach" mode now detects executable name and path from /proc//exe. ## [2.0] - 2023-03-06 * Seer is Qt6 based. Still compiles with Qt5. diff --git a/src/QProcessInfo.cpp b/src/QProcessInfo.cpp index 13785e4..0f2590e 100644 --- a/src/QProcessInfo.cpp +++ b/src/QProcessInfo.cpp @@ -20,6 +20,105 @@ #include +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); diff --git a/src/QProcessInfo.h b/src/QProcessInfo.h index f30f17b..bee0852 100644 --- a/src/QProcessInfo.h +++ b/src/QProcessInfo.h @@ -11,6 +11,7 @@ class QProcessInfo { QProcessInfo(); static QProcessList populate(); + static QProcessInfo populate(uint32_t pid); uint32_t pid () const; void setPid (uint32_t pid); diff --git a/src/resources/help/seergdb.hlp b/src/resources/help/seergdb.hlp index 1a262a0..09b8bbd 100644 --- a/src/resources/help/seergdb.hlp +++ b/src/resources/help/seergdb.hlp @@ -13,7 +13,10 @@ Launch Options (pick one): -s, --start Load the executable, break in "main", and run it. - --attach Attach to a locally running process. + --attach [] Attach to a locally running process. + is the path to the executable to load. + If is not given, use the executable stated + by /proc//exe --connect [--sym ] Connect to an already running gdbserver (local or remote). Possible connection mediums are: diff --git a/src/seergdb.cpp b/src/seergdb.cpp index 3ec3d9e..204e327 100644 --- a/src/seergdb.cpp +++ b/src/seergdb.cpp @@ -1,5 +1,6 @@ #include "SeerMainWindow.h" #include "SeerUtl.h" +#include "QProcessInfo.h" #include #include #include @@ -196,6 +197,13 @@ int main (int argc, char* argv[]) { QString pid = parser.value(attachOption); executablePid = pid.toInt(); + + if (executableName == "") { + + QProcessInfo info = QProcessInfo::populate(executablePid); + + executableName = info.path() + "/" + info.name(); + } } if (parser.isSet(connectOption)) {