1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "minidumpruncontrol.h"
6#include "reversedebuggerconstants.h"
7#include "common/util/custompaths.h"
8
9#include <QDebug>
10#include <QFile>
11#include <QMessageBox>
12#include <QDir>
13
14#include <string>
15#include <unistd.h>
16
17using namespace std;
18
19// global variable used extern.
20bool kEmdRunning = false;
21bool g_emd_buffer_syscall = false;
22QString g_emd_params;
23
24namespace ReverseDebugger {
25namespace Internal {
26
27string found_crash(const char *subdir, int *ppid)
28{
29 // find crash.txt
30 string parent_dir = getenv("HOME");
31 parent_dir += subdir; // "/.local/share/rdb/";
32 string linkname = parent_dir;
33 linkname += "latest-trace";
34 string filename = parent_dir;
35 int pos = filename.size();
36 filename.resize(512, 0);
37 int len = readlink(linkname.data(),
38 (char *)filename.data() + pos, 512 - pos);
39 if (len < 0) {
40 return string();
41 }
42 filename.resize(len + pos);
43 parent_dir = filename;
44 filename += "/crash.txt";
45
46 // parse crash.txt
47 QFile file(QString::fromStdString(filename));
48 if (file.size() > 0 && file.open(QFile::ReadOnly)) {
49 char buf[256];
50 int size = file.readLine(buf, sizeof(buf));
51 buf[size] = 0;
52 char *stop = nullptr;
53 int pid = strtol(buf, &stop, 10);
54 int sig = strtol(stop + 1, NULL, 10);
55 if (sig > 0 && pid > 0) {
56 qDebug() << __FUNCTION__ << "found crash sig: " << sig;
57 *ppid = pid;
58 return parent_dir;
59 }
60 }
61
62 return string();
63}
64
65MinidumpRunControl::MinidumpRunControl(QObject *parent)
66 : QObject(parent),
67 process(new QProcess(this))
68{
69 if (kEmdRunning) {
70 qDebug() << "emd is running now!";
71 return;
72 }
73
74 // process->setWorkingDirectory()
75 // process->setProcessEnvironment();
76
77 connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
78 this, SLOT(onStraceExit(int, QProcess::ExitStatus)));
79}
80
81MinidumpRunControl::~MinidumpRunControl()
82{
83}
84
85void MinidumpRunControl::start(const QString &params, const QString &target)
86{
87 qDebug() << __FUNCTION__ << ", object:" << this;
88
89 if (target.isEmpty() || !QFile::exists(target)) {
90 QMessageBox::warning(nullptr, tr("Reverse debug"), tr("Target: %1 not found, recored failed!").arg(target));
91 return;
92 }
93
94 execFile = CustomPaths::global(CustomPaths::Tools) + QDir::separator() + "emd";
95 if (!params.isEmpty()) {
96 execFile += ' ' + params + ' ';
97 }
98 execFile += target; // target debuggee
99
100 appendMessage(tr("[Start] %1").arg(execFile) + QLatin1Char('\n'));
101
102 process->start(execFile);
103 if (!process->waitForStarted(1000)) {
104 qDebug() << "Failed to run emd";
105 return;
106 }
107
108 kEmdRunning = true;
109}
110
111StopResult MinidumpRunControl::stop()
112{
113 qDebug() << __FUNCTION__ << ", object:" << this;
114
115 if (process) {
116 QByteArray data = process->readAll();
117 QString outstr = QString::fromLocal8Bit(data.data());
118 appendMessage(outstr + QLatin1Char('\n'));
119 }
120
121 kEmdRunning = false;
122
123 appendMessage(tr("[Stop] %1").arg(execFile) + QLatin1Char('\n'));
124
125 return StoppedSynchronously;
126}
127
128bool MinidumpRunControl::isRunning() const
129{
130 return kEmdRunning;
131}
132
133QString MinidumpRunControl::displayName() const
134{
135 return "event debug recored";
136}
137
138void MinidumpRunControl::appendMessage(const QString &msg)
139{
140 Q_UNUSED(msg)
141}
142
143void MinidumpRunControl::onStraceExit(int, QProcess::ExitStatus)
144{
145 stop();
146
147 int pid = 0;
148 string parent_dir = found_crash(("/.local/share/emd/"), &pid);
149 if (!parent_dir.empty()) {
150 // emd_replay(QString::fromStdString(parent_dir), pid);
151 return;
152 }
153
154 QMessageBox::information(nullptr, tr("reverse debug"), tr("Recored done, minidump load ready."));
155}
156
157} // namespace Internal
158} // namespace ReverseDebugger
159