mirror of
https://github.com/epasveer/seer.git
synced 2026-08-29 16:40:42 +08:00
Commandline for "attach" mode now detects executable name and path from /proc/<pid>/exe.
This commit is contained in:
+2
-1
@@ -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/<pid>/exe.
|
||||
* Commandline for "attach" mode now detects executable name and path from /proc/<pid>/exe.
|
||||
|
||||
## [2.0] - 2023-03-06
|
||||
* Seer is Qt6 based. Still compiles with Qt5.
|
||||
|
||||
+101
-91
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -13,7 +13,10 @@ Launch Options (pick one):
|
||||
|
||||
-s, --start <executable> <arguments> Load the executable, break in "main", and run it.
|
||||
|
||||
--attach <pid> <executable> Attach to a locally running process.
|
||||
--attach <pid> [<executable>] Attach to a locally running process.
|
||||
<executable> is the path to the executable to load.
|
||||
If <executable> is not given, use the executable stated
|
||||
by /proc/<pid>/exe
|
||||
|
||||
--connect <medium> [--sym <symbolfile>] Connect to an already running gdbserver (local or remote).
|
||||
Possible connection mediums are:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "SeerMainWindow.h"
|
||||
#include "SeerUtl.h"
|
||||
#include "QProcessInfo.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtGui/QIcon>
|
||||
#include <QtCore/QCommandLineParser>
|
||||
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user