Skip to content

Commit

Permalink
Merge pull request #421 from jakobrs/linux-lldb
Browse files Browse the repository at this point in the history
A couple improvements to debugger support
  • Loading branch information
clementgallet authored Jul 20, 2021
2 parents f631ee8 + 7f30086 commit 8c916e7
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 63 deletions.
4 changes: 4 additions & 0 deletions src/library/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ void __attribute__((constructor)) init(void)
message = receiveMessage();
}

if (shared_config.sigint_upon_launch) {
raise(SIGINT);
}

/* Set the frame count to the initial frame count */
framecount = shared_config.initial_framecount;

Expand Down
8 changes: 8 additions & 0 deletions src/program/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ void Config::save(const std::string& gamepath) {
}
general_settings.endArray();

general_settings.setValue("debugger", debugger);

/* Open the preferences for the game */
QSettings settings(iniPath(gamepath), QSettings::IniFormat);
settings.setFallbacksEnabled(false);
Expand Down Expand Up @@ -174,6 +176,12 @@ void Config::load(const std::string& gamepath) {
}
general_settings.endArray();

#ifdef __unix__
debugger = general_settings.value("debugger", debugger).toInt();
#elif defined(__APPLE__) && defined(__MACH__)
debugger = DEBUGGER_LLDB;
#endif

if (gamepath.empty())
return;

Expand Down
11 changes: 11 additions & 0 deletions src/program/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ class Config {
/* Load a game-specific config from the config file */
void load(const std::string& gamepath);

enum Debugger {
DEBUGGER_GDB = 0,
DEBUGGER_LLDB = 1,
};

#ifdef __unix__
int debugger = DEBUGGER_GDB;
#elif defined(__APPLE__) && defined(__MACH__)
int debugger = DEBUGGER_LLDB;
#endif

private:
QString iniPath(const std::string& gamepath) const;
};
Expand Down
117 changes: 67 additions & 50 deletions src/program/GameThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,17 @@ void GameThread::launch(Context *context)
}
else {
if (context->attach_gdb) {
#ifdef __unix__
std::string cmd = "which gdb";
#elif defined(__APPLE__) && defined(__MACH__)
std::string cmd = "which lldb";
#endif
std::string cmd;

switch (context->config.debugger) {
case Config::DEBUGGER_GDB:
cmd = "which gdb";
break;
case Config::DEBUGGER_LLDB:
cmd = "which lldb";
break;
}

FILE *output = popen(cmd.c_str(), "r");
std::array<char,256> buf;
fgets(buf.data(), buf.size(), output);
Expand All @@ -202,57 +208,68 @@ void GameThread::launch(Context *context)
arg_list.push_back(dbgpath);

/* Push debugger arguments */
#ifdef __unix__
arg_list.push_back("-q");
arg_list.push_back("-ex");

/* LD_PRELOAD must be set inside a gdb
* command to be effective */
std::string ldpreloadstr = "set exec-wrapper env 'LD_PRELOAD=";
ldpreloadstr += context->libtaspath;
if (!context->old_ld_preload.empty()) {
ldpreloadstr += ":";
ldpreloadstr += context->old_ld_preload;
switch (context->config.debugger) {
case Config::DEBUGGER_GDB: {
arg_list.push_back("-q");
arg_list.push_back("-ex");

/* LD_PRELOAD must be set inside a gdb
* command to be effective */
std::string ldpreloadstr = "set exec-wrapper env 'LD_PRELOAD=";
ldpreloadstr += context->libtaspath;
if (!context->old_ld_preload.empty()) {
ldpreloadstr += ":";
ldpreloadstr += context->old_ld_preload;
}
ldpreloadstr += "'";
arg_list.push_back(ldpreloadstr);

/* We are using SIGSYS and SIGXFSZ for savestates, so don't
* print and pause when one signal is sent *
* Signals SIGPWR SIGXCPU SIG35 and SIG36 are used a lot in some games */
arg_list.push_back("-ex");
arg_list.push_back("handle SIGSYS SIGXFSZ SIGUSR1 SIGUSR2 SIGPWR SIGXCPU SIG35 SIG36 nostop noprint");
arg_list.push_back("-ex");
arg_list.push_back("run");
arg_list.push_back("--args");

break;
}
ldpreloadstr += "'";
arg_list.push_back(ldpreloadstr);

/* We are using SIGSYS and SIGXFSZ for savestates, so don't
* print and pause when one signal is sent *
* Signals SIGPWR SIGXCPU SIG35 and SIG36 are used a lot in some games */
arg_list.push_back("-ex");
arg_list.push_back("handle SIGSYS SIGXFSZ SIGUSR1 SIGUSR2 SIGPWR SIGXCPU SIG35 SIG36 nostop noprint");
arg_list.push_back("-ex");
arg_list.push_back("run");
arg_list.push_back("--args");
case Config::DEBUGGER_LLDB: {
arg_list.push_back("-o");

/* LD_PRELOAD/DYLD_INSERT_LIBRARIES must be set inside an lldb
* command to be effective */
#ifdef __unix__
std::string ldpreloadstr = "set se target.env-vars 'LD_PRELOAD=";
#elif defined(__APPLE__) && defined(__MACH__)
std::string ldpreloadstr = "set se target.env-vars 'DYLD_INSERT_LIBRARIES=";
#endif
ldpreloadstr += context->libtaspath;
if (!context->old_ld_preload.empty()) {
ldpreloadstr += ":";
ldpreloadstr += context->old_ld_preload;
}
ldpreloadstr += "'";
arg_list.push_back(ldpreloadstr);

arg_list.push_back("-o");
#if defined(__APPLE__) && defined(__MACH__)
arg_list.push_back("-o");
arg_list.push_back("set se target.env-vars 'DYLD_FORCE_FLAT_NAMESPACE=1'");
#endif

/* DYLD_INSERT_LIBRARIES must be set inside a lldb
* command to be effective */
std::string ldpreloadstr = "set se target.env-vars 'DYLD_INSERT_LIBRARIES=";
ldpreloadstr += context->libtaspath;
if (!context->old_ld_preload.empty()) {
ldpreloadstr += ":";
ldpreloadstr += context->old_ld_preload;
/* We are using SIGSYS and SIGXFSZ for savestates, so don't
* print and pause when one signal is sent */
arg_list.push_back("-o");
arg_list.push_back("run");
/* Signal handling cannot be performed in llvm before the process has started */
// arg_list.push_back("-o");
// arg_list.push_back("process handle -n false -p false -s false SIGSYS SIGXFSZ SIGUSR1 SIGUSR2 SIGXCPU");
arg_list.push_back("--");

break;
}
}
ldpreloadstr += "'";
arg_list.push_back(ldpreloadstr);

arg_list.push_back("-o");
arg_list.push_back("set se target.env-vars 'DYLD_FORCE_FLAT_NAMESPACE=1'");

/* We are using SIGSYS and SIGXFSZ for savestates, so don't
* print and pause when one signal is sent */
arg_list.push_back("-o");
arg_list.push_back("run");
/* Signal handling cannot be performed in llvm before the process has started */
// arg_list.push_back("-o");
// arg_list.push_back("process handle -n false -p false -s false SIGSYS SIGXFSZ SIGUSR1 SIGUSR2 SIGXCPU");
arg_list.push_back("--");
#endif
}

/* Tell SDL >= 2.0.2 to let us override functions even if it is statically linked.
Expand Down
16 changes: 13 additions & 3 deletions src/program/ui/ErrorChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,19 +200,29 @@ bool ErrorChecking::checkArchType(Context* context)

/* Check for gdb presence in case of Start and attach gdb */
if (context->attach_gdb) {
std::string cmd = "which gdb";
std::string cmd;

switch (context->config.debugger) {
case Config::DEBUGGER_GDB:
cmd = "which gdb";
break;
case Config::DEBUGGER_LLDB:
cmd = "which lldb";
break;
}

FILE *output = popen(cmd.c_str(), "r");
if (output != NULL) {
std::array<char,256> buf;
fgets(buf.data(), buf.size(), output);
int ret = pclose(output);
if (ret != 0) {
critical(QString("Trying to start a game with attached gdb, but gdb cannot be found"), context->interactive);
critical(QString("Trying to start a game with attached debugger, but debugger cannot be found"), context->interactive);
return false;
}
}
else {
critical(QString("Coundn't popen to locate gdb"), context->interactive);
critical(QString("Coundn't popen to locate debugger"), context->interactive);
return false;
}
}
Expand Down
69 changes: 61 additions & 8 deletions src/program/ui/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,32 @@ MainWindow::MainWindow(Context* c) : QMainWindow(), context(c)

/* Buttons */
launchButton = new QPushButton(tr("Start"));
connect(launchButton, &QAbstractButton::clicked, this, &MainWindow::slotLaunch);
connect(launchButton, &QAbstractButton::clicked, this, [this] { MainWindow::slotLaunch(false); });
disabledWidgetsOnStart.append(launchButton);

launchGdbButton = new QPushButton(tr("Start and attach gdb"));
connect(launchGdbButton, &QAbstractButton::clicked, this, &MainWindow::slotLaunch);
disabledWidgetsOnStart.append(launchGdbButton);
launchGdbButton = new QToolButton();
launchGdbButton->setToolButtonStyle(Qt::ToolButtonTextOnly);

launchGdbAction = new QAction(tr("Launch with GDB"), this);
launchLldbAction = new QAction(tr("Launch with LLDB"), this);

connect(launchGdbAction, &QAction::triggered, this, &MainWindow::slotLaunchGdb);
connect(launchLldbAction, &QAction::triggered, this, &MainWindow::slotLaunchLldb);

/* launchGdbButton is a special case, it's explicitly disabled along with
* all the other widgets on launch
*/
//disabledWidgetsOnStart.append(launchGdbButton);

#ifdef __unix__
launchGdbButton->setPopupMode(QToolButton::MenuButtonPopup);

QMenu *launchGdbButtonMenu = new QMenu();
launchGdbButton->setMenu(launchGdbButtonMenu);

launchGdbButtonMenu->addAction(launchGdbAction);
launchGdbButtonMenu->addAction(launchLldbAction);
#endif

stopButton = new QPushButton(tr("Stop"));
connect(stopButton, &QAbstractButton::clicked, this, &MainWindow::slotStop);
Expand Down Expand Up @@ -360,7 +380,7 @@ MainWindow::MainWindow(Context* c) : QMainWindow(), context(c)
if (!context->interactive) {
slotPause(false);
slotFastForward(true);
slotLaunch();
slotLaunch(false);
}
}

Expand Down Expand Up @@ -800,6 +820,11 @@ void MainWindow::createMenus()

debugMenu->addSeparator();

sigintAction = debugMenu->addAction(tr("Raise SIGINT upon game launch (if debugging)"));
sigintAction->setCheckable(true);

debugMenu->addSeparator();

debugMenu->addActions(loggingOutputGroup->actions());
disabledActionsOnStart.append(loggingOutputGroup->actions());

Expand Down Expand Up @@ -897,6 +922,8 @@ void MainWindow::updateStatus()
initialTimeSec->setValue(context->config.sc.initial_time_sec);
initialTimeNsec->setValue(context->config.sc.initial_time_nsec);

launchGdbButton->setEnabled(true);

if (context->config.sc.av_dumping) {
context->config.sc.av_dumping = false;
configEncodeAction->setEnabled(true);
Expand Down Expand Up @@ -929,6 +956,8 @@ void MainWindow::updateStatus()
fpsDenField->setEnabled(false);
}

launchGdbButton->setEnabled(false);

movieBox->setCheckable(false);
if (context->config.sc.recording == SharedConfig::NO_RECORDING) {
movieBox->setEnabled(false);
Expand Down Expand Up @@ -1254,6 +1283,15 @@ void MainWindow::updateUIFromConfig()

setRadioFromList(movieEndGroup, context->config.on_movie_end);

switch (context->config.debugger) {
case Config::DEBUGGER_GDB:
launchGdbButton->setDefaultAction(launchGdbAction);
break;
case Config::DEBUGGER_LLDB:
launchGdbButton->setDefaultAction(launchLldbAction);
break;
}

updateStatusBar();
}

Expand All @@ -1279,12 +1317,25 @@ void MainWindow::updateStatusBar()
}
}

void MainWindow::slotLaunch()
void MainWindow::slotLaunchGdb() {
context->config.debugger = Config::DEBUGGER_GDB;
launchGdbButton->setDefaultAction(launchGdbAction);

slotLaunch(true);
}

void MainWindow::slotLaunchLldb() {
context->config.debugger = Config::DEBUGGER_LLDB;
launchGdbButton->setDefaultAction(launchLldbAction);

slotLaunch(true);
}

void MainWindow::slotLaunch(bool attach_gdb)
{

/* Do we attach gdb ? */
QPushButton* button = static_cast<QPushButton*>(sender());
context->attach_gdb = (button == launchGdbButton);
context->attach_gdb = attach_gdb;

if (context->status != Context::INACTIVE)
return;
Expand All @@ -1307,6 +1358,8 @@ void MainWindow::slotLaunch()

setListFromRadio(loggingOutputGroup, context->config.sc.logging_status);

context->config.sc.sigint_upon_launch = context->attach_gdb && sigintAction->isChecked();

context->config.sc.mouse_support = mouseAction->isChecked();
setListFromRadio(joystickGroup, context->config.sc.nb_controllers);

Expand Down
10 changes: 8 additions & 2 deletions src/program/ui/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QToolButton>
#include <QtCore/QElapsedTimer>
#include <QtCore/QTimer>
#include <forward_list>
Expand Down Expand Up @@ -123,6 +124,7 @@ class MainWindow : public QMainWindow
QActionGroup *asyncGroup;

QActionGroup *debugStateGroup;
QAction *sigintAction;
QActionGroup *loggingOutputGroup;
QActionGroup *loggingPrintGroup;
QActionGroup *loggingExcludeGroup;
Expand Down Expand Up @@ -169,7 +171,9 @@ class MainWindow : public QMainWindow
QSpinBox *initialTimeNsec;

QPushButton *launchButton;
QPushButton *launchGdbButton;
QToolButton *launchGdbButton;
QAction *launchGdbAction;
QAction *launchLldbAction;
QPushButton *stopButton;

QGroupBox *movieBox;
Expand Down Expand Up @@ -236,7 +240,9 @@ private slots:
/* Update framerate values */
void updateFramerate();

void slotLaunch();
void slotLaunchGdb();
void slotLaunchLldb();
void slotLaunch(bool attach_gdb);
void slotStop();
void slotBrowseGamePath();
void slotGamePathChanged();
Expand Down
3 changes: 3 additions & 0 deletions src/shared/SharedConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ struct __attribute__((packed, aligned(8))) SharedConfig {

/* Send stack traces of all time calls to libTAS program */
bool time_trace = false;

/* Call raise(SIGINT) in libtas::init */
bool sigint_upon_launch = false;
};

#endif

0 comments on commit 8c916e7

Please sign in to comment.