diff --git a/Images.qrc b/Images.qrc
index 035a85d2..0ec72d62 100644
--- a/Images.qrc
+++ b/Images.qrc
@@ -19,5 +19,6 @@
images/stepinto.png
images/stepover.png
images/undo.png
+ images/debugPause.png
diff --git a/SASM.pro b/SASM.pro
index 5e8a3c4b..4133c9d9 100644
--- a/SASM.pro
+++ b/SASM.pro
@@ -49,7 +49,8 @@ SOURCES += main.cpp\
nasm.cpp \
gas.cpp \
common.cpp \
- fasm.cpp
+ fasm.cpp \
+ signallocker.cpp
HEADERS += mainwindow.h \
tab.h \
@@ -67,7 +68,8 @@ HEADERS += mainwindow.h \
nasm.h \
gas.h \
common.h \
- fasm.h
+ fasm.h \
+ signallocker.h
FORMS += settings.ui
diff --git a/Windows/MinGW/bin/objdump.exe b/Windows/MinGW/bin/objdump.exe
new file mode 100644
index 00000000..c30b9a0d
Binary files /dev/null and b/Windows/MinGW/bin/objdump.exe differ
diff --git a/Windows/MinGW64/bin/objdump.exe b/Windows/MinGW64/bin/objdump.exe
new file mode 100644
index 00000000..01a91671
Binary files /dev/null and b/Windows/MinGW64/bin/objdump.exe differ
diff --git a/assembler.h b/assembler.h
index ea8030ea..4f4c4f2f 100644
--- a/assembler.h
+++ b/assembler.h
@@ -74,7 +74,7 @@ class Assembler : public QObject //Abstract class
bool x86;
explicit Assembler(bool x86, QObject *parent = 0);
virtual QString getAssemblerPath() = 0;
- virtual quint64 getMainOffset(QFile &lst) = 0;
+ virtual quint64 getMainOffset(QFile &lst, QString entryLabel) = 0;
virtual void parseLstFile(QFile &lst, QVector &lines, bool ioIncIncluded, quint64 ioIncSize, quint64 offset) = 0;
virtual void fillHighligherRules(QVector &highlightingRules,
QList &formats,
diff --git a/codeeditor.cpp b/codeeditor.cpp
index 6a7412a5..d56bea96 100644
--- a/codeeditor.cpp
+++ b/codeeditor.cpp
@@ -42,7 +42,8 @@
CodeEditor::CodeEditor(QWidget *parent, bool withBeakpoints) :
RuQPlainTextEdit(parent), debugImage(":/images/debugLine.png"),
- breakpointImage(":/images/breakpoint.png")
+ breakpointImage(":/images/breakpoint.png"),
+ settings("SASM Project", "SASM")
{
hasBreakpoints = withBeakpoints;
prevBlockCount = -1;
@@ -105,7 +106,6 @@ void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
//paint on line number area
QPainter painter(lineNumberArea);
- QSettings settings("SASM Project", "SASM");
painter.fillRect(event->rect(), settings.value("linenumberpanelcolor", palette().color(QPalette::Window)).value());
QTextBlock block = firstVisibleBlock();
@@ -113,10 +113,6 @@ void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top + (int) blockBoundingRect(block).height();
- //set debugAreaWidth before drawing
- debugAreaWidth = 3 + debugImage.width() + 1; //left margin + arrow width + right margin
- updateLineNumberAreaWidth(0);
-
while (block.isValid() && top <= event->rect().bottom()) {
if (block.isVisible() && bottom >= event->rect().top()) {
QString number = QString::number(blockNumber + 1);
@@ -213,7 +209,6 @@ QList *CodeEditor::getBreakpoints()
void CodeEditor::highlightCurrentLine()
{
- QSettings settings("SASM Project", "SASM");
if (!debugMode) {
if (settings.value("currentlinemode", true).toBool()) {
QList extraSelections;
@@ -243,10 +238,9 @@ void CodeEditor::highlightDebugLine(int lineNumber)
if (debugMode) {
QList extraSelections;
- if (!isReadOnly()) {
+ if (!isReadOnly() && lineNumber > 0) {
QTextEdit::ExtraSelection selection;
- QSettings settings("SASM Project", "SASM");
QColor lineColor = settings.value("debuglinecolor", QColor(235, 200, 40)).value();
selection.format.setBackground(lineColor);
@@ -264,11 +258,16 @@ void CodeEditor::highlightDebugLine(int lineNumber)
void CodeEditor::updateDebugLine(int number)
{
+ //number > 0 => highlight line
+ //number == -1 => exit from debug mode
+ //number == -2 => does not highlight any line, but does not exit from debug mode
+ //last case for waiting program stops on next instruction or breakpoint
if (number == -1)
setDebugMode(false);
else
setDebugMode(true);
- currentDebugLine = number;
+ if (number != -2)
+ currentDebugLine = number;
//create rectangle of line number area and highlight debug line throw updateRequest()
QRect lineNumberAreaRect(lineNumberArea->x(), lineNumberArea->y(),
diff --git a/codeeditor.h b/codeeditor.h
index 5ae3ea83..9c53eb38 100644
--- a/codeeditor.h
+++ b/codeeditor.h
@@ -99,6 +99,7 @@ private slots:
int firstTopMargin;
bool hasBreakpoints;
int prevBlockCount;
+ QSettings settings;
signals:
void breakpointsChanged(quint64 lineNumber, bool isAdded);
diff --git a/debugger.cpp b/debugger.cpp
index ef3e8635..120c2031 100644
--- a/debugger.cpp
+++ b/debugger.cpp
@@ -67,23 +67,45 @@ Debugger::Debugger(QTextEdit *tEdit, const QString &path, bool ioInc, QString tm
#endif
#ifdef Q_OS_WIN32
QString gdb;
+ QString objdump;
if (settings.value("mode", QString("x86")).toString() == "x86") {
gdb = QCoreApplication::applicationDirPath() + "/MinGW/bin/gdb.exe";
+ objdump = QCoreApplication::applicationDirPath() + "/MinGW/bin/objdump.exe";
if (! QFile::exists(gdb))
gdb = QCoreApplication::applicationDirPath() + "/Windows/MinGW/bin/gdb.exe";
+ if (! QFile::exists(objdump))
+ objdump = QCoreApplication::applicationDirPath() + "/Windows/MinGW/bin/objdump.exe";
exitMessage = "mingw_CRTStartup";
} else {
gdb = QCoreApplication::applicationDirPath() + "/MinGW64/bin/gdb.exe";
+ objdump = QCoreApplication::applicationDirPath() + "/MinGW/bin/objdump.exe";
if (! QFile::exists(gdb))
gdb = QCoreApplication::applicationDirPath() + "/Windows/MinGW64/bin/gdb.exe";
+ if (! QFile::exists(objdump))
+ objdump = QCoreApplication::applicationDirPath() + "/Windows/MinGW/bin/objdump.exe";
exitMessage = "__fu0__set_invalid_parameter_handler";
}
#else
QString gdb = "gdb";
+ QString objdump = "objdump";
exitMessage = "libc_start_main";
#endif
cExitMessage = QRegExp("\\[Inferior .* exited");
+ connect(this, SIGNAL(wasStopped()), this, SLOT(emitStarted()));
+
+ //determine entry point
+ QProcess objdumpProcess;
+ QStringList objdumpArguments;
+ objdumpArguments << "-f" << path;
+ objdumpProcess.start(objdump, objdumpArguments);
+ objdumpProcess.waitForFinished();
+ QString objdumpResult = QString(objdumpProcess.readAllStandardOutput());
+ QString startAddress("start address ");
+ int index = objdumpResult.indexOf(startAddress);
+ objdumpResult = objdumpResult.mid(index + startAddress.length());
+ entryPoint = objdumpResult.toLongLong(0, 16);
+
QStringList arguments;
arguments << path;
@@ -98,6 +120,12 @@ Debugger::Debugger(QTextEdit *tEdit, const QString &path, bool ioInc, QString tm
bufferTimer->start(10);
}
+void Debugger::emitStarted()
+{
+ disconnect(this, SIGNAL(wasStopped()), this, SLOT(emitStarted()));
+ emit started();
+}
+
void Debugger::readOutputToBuffer()
{
if (!process)
@@ -112,15 +140,22 @@ void Debugger::processOutput()
int index = buffer.indexOf(QString("(gdb)"));
int linefeedIndex = errorBuffer.indexOf("\n");
if (index != -1) { //if whole message ready to processing (end of whole message is "(gdb)")
- processMessage(buffer.left(index), errorBuffer.left(linefeedIndex));
+ QString output = buffer.left(index);
+ QString error = errorBuffer.left(linefeedIndex);
buffer.remove(0, index + 5); //remove processed message
errorBuffer.remove(0, linefeedIndex + 1);
+ processMessage(output, error);
}
bufferTimer->start(10);
}
void Debugger::processMessage(QString output, QString error)
{
+ if (error.indexOf("PC register is not available") != -1) {
+ emit printLog(tr("GDB error\n"), Qt::red);
+ emit finished();
+ return;
+ }
if (c == 0) { //in start wait for printing of start gdb text like this:
/*GNU gdb (GDB) 7.4
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -134,47 +169,85 @@ void Debugger::processMessage(QString output, QString error)
Reading symbols from C:\Users\Dmitri\Dropbox\Projects\SASMstatic\release\Program\SASMprog.exe...
done.
(gdb)*/
-
- doInput(QString("disas main\n"), none);
- c++;
- return;
+ if (output.indexOf("no debugging symbols found") != -1) {
+ dbgSymbols = false;
+ c++;
+ } else {
+ dbgSymbols = true;
+ doInput(QString("disas main\n"), none);
+ c++;
+ return;
+ }
}
- if (c == 1 && output != " ") {
- //next disassembly top part of code for setting according with program in memory and program in file
- /*Dump of assembler code for function sasmStartL:
- 0x00401390 <+0>: xor %eax,%eax
- 0x00401392 <+2>: ret
- 0x00401393 <+3>: add %dl,-0x77(%ebp)
- End of assembler dump.*/
- //we need first number (0x00401390)
+ if (dbgSymbols) { //debug symbols exists
+ if (c == 1 && output != " ") {
+ //next disassembly top part of code for setting according with program in memory and program in file
+ /*Dump of assembler code for function sasmStartL:
+ 0x00401390 <+0>: xor %eax,%eax
+ 0x00401392 <+2>: ret
+ 0x00401393 <+3>: add %dl,-0x77(%ebp)
+ End of assembler dump.*/
+ //we need first number (0x00401390)
+
+ //count offset
+ QRegExp r = QRegExp("0x[0-9a-fA-F]{8,16}");
+ int index = r.indexIn(output);
+ offset = output.mid(index, r.matchedLength()).toULongLong(0, 16);
+ //take offset in hexadecimal representation (10 symbols) from string and convert it to int
+ c++;
+ processLst(); //count accordance
+ run(); //perform Debugger::run(), that run program and open I/O files
+ return;
+ }
- //count offset
- QRegExp r = QRegExp("0x[0-9a-fA-F]{8,16}");
- int index = r.indexIn(output);
- offset = output.mid(index, r.matchedLength()).toULongLong(0, 16);
- //take offset in hexadecimal representation (10 symbols) from string and convert it to int
- c++;
- processLst(); //count accordance
- run(); //perform Debugger::run(), that run program and open I/O files
- return;
+ //determine run of program
+ //wait for message like this: Breakpoint 1, 0x00401390 in sasmStartL ()
+ if (c == 2 && output.indexOf(QString(" in ")) != -1) {
+ c++;
+ actionTypeQueue.enqueue(ni);
+ }
+
+ //if an error with the wrong name of the section has occurred
+ if ((c == 2 && output.indexOf(QString("Make breakpoint pending on future shared library load")) != -1)
+ || (c == 1 && output == " ")) {
+ actionTypeQueue.enqueue(anyAction);
+ processAction(tr("An error has occurred in the debugger. Please check the names of the sections."));
+ QObject::disconnect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutputToBuffer()));
+ emit finished();
+ }
+ } else { //debug symbols does not exists (for example, non-gcc linker)
+ if (c == 1) {
+ offset = 0x401000; //!!!!!!!!!!!!! - start of text or code section
+ c++;
+ processLst(); //count accordance
+ run(); //perform Debugger::run(), that run program and open I/O files
+ return;
+ }
+
+ //determine run of program
+ //wait for message like this: Breakpoint 1, 0x00401390 in sasmStartL ()
+ if (c == 2 && output.indexOf(QString(" in ")) != -1) {
+ c++;
+ actionTypeQueue.enqueue(ni);
+ }
}
- //determine run of program
- //wait for message like this: Breakpoint 1, 0x00401390 in sasmStartL ()
- if (c == 2 && output.indexOf(QString(" in ")) != -1) {
- c++;
- actionTypeQueue.enqueue(ni);
- emit started(); //emit start signal
+ QString sigTrap("SIGTRAP"); //was stopped
+ if (output.indexOf(sigTrap) != -1) {
+ stopped = true;
+ emit wasStopped();
+ return;
}
- //if an error with the wrong name of the section has occurred
- if ((c == 2 && output.indexOf(QString("Make breakpoint pending on future shared library load")) != -1)
- || (c == 1 && output == " ")) {
- actionTypeQueue.enqueue(anyAction);
- processAction(tr("An error has occurred in the debugger. Please check the names of the sections."));
- QObject::disconnect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutputToBuffer()));
- emit finished();
+ QString s("New Thread");
+ int index = output.indexOf(s);
+ if (index != -1) {
+ QString temp = output;
+ temp = temp.mid(index + s.length() + 1);
+ temp = temp.split(QChar('.')).at(0);
+ pid = temp.toULongLong(0, 10);
+ output.remove(QRegExp("\\[New Thread[^\\]]*\\]\r?\n"));
}
//process all actions after start
@@ -218,187 +291,186 @@ void Debugger::processAction(QString output, QString error)
emit finished();
return;
}
-
if (actionTypeQueue.isEmpty()) {
return;
}
DebugActionType actionType = actionTypeQueue.dequeue();
- int failIndex = output.indexOf(QString("Program received signal")); //program was completed incorrectly
- if (failIndex == -1) { //if program works normally
- if (actionType == breakpoint)
- return;
-
- if (actionType == si || actionType == ni || actionType == showLine) {
- //message is: line number + data
- //print line number and other data if si or ni and print line number only if showLine
- //scan line number in memory
- QRegExp r = QRegExp("0x[0-9a-fA-F]{8,16}");
- int index = r.indexIn(output);
+ if (actionType == breakpoint)
+ return;
+ if (actionType == si || actionType == ni || actionType == showLine) {
+ //message is: line number + data
+ //print line number and other data if si or ni and print line number only if showLine
+ //scan line number in memory
+ QRegExp r = QRegExp("0x[0-9a-fA-F]{8,16}");
+ int index = r.indexIn(output);
- //print output
- if (index > 1 && !firstAction) {
- QString msg = output.left(index); //left part - probably ouput of program;
- msg.remove(0, 1); //remove first whitespace
- QRegExp continuingMsg("Continuing.\r?\n");
- QRegExp breakpointMsg("\r?\nBreakpoint \\d+, ");
- msg.remove(continuingMsg);
- msg.remove(breakpointMsg);
- emit printOutput(msg);
- }
- firstAction = false;
-
- quint64 lineNumber = output.mid(index, r.matchedLength()).toULongLong(0, 16);
- //take line number in hexadecimal representation
- //(10 symbols) in memory from string and convert it to int
-
- //find line number in accordance array and get number line in file with code
- bool found = false;
- for (int i = lines.count() - 1; i >= 0; i--) {
- if (lineNumber == lines[i].numInMem) {
- lineNumber = lines[i].numInCode;
- found = true;
- break;
- }
+ //print output
+ if (index > 1 && !firstAction) {
+ QString msg = output.left(index); //left part - probably output of program;
+ msg.remove(0, 1); //remove first whitespace
+ QRegExp continuingMsg("Continuing.\r?\n");
+ QRegExp breakpointMsg("\r?\nBreakpoint \\d+, ");
+ QRegExp threadMsg("\\[Switching to Thread [^\\]]*\\]\r?\n");
+ msg.remove(continuingMsg);
+ msg.remove(breakpointMsg);
+ msg.remove(threadMsg);
+ emit printOutput(msg);
+ }
+ firstAction = false;
+
+ quint64 lineNumber = output.mid(index, r.matchedLength()).toULongLong(0, 16);
+ //take line number in hexadecimal representation
+ //(10 symbols) in memory from string and convert it to int
+
+ //find line number in accordance array and get number line in file with code
+ bool found = false;
+ for (int i = lines.count() - 1; i >= 0; i--) {
+ if (lineNumber == lines[i].numInMem) {
+ lineNumber = lines[i].numInCode;
+ found = true;
+ break;
}
+ }
- if (!found) {
- //output = tr("Inside the macro or outside the program.") + '\n';
- emit inMacro();
+ if (!found) {
+ //output = tr("Inside the macro or outside the program.") + '\n';
+ emit inMacro();
+ return;
+ } else { //if found highlight and print it
+ //highlight line number
+ emit highlightLine(lineNumber);
+ stopped = true;
+ emit wasStopped();
+
+ //print string number and all after it
+ //output = QString::number(lineNumber) + tr(" line") + output.mid(output.indexOf("()") + 2);
+ if (actionType == showLine)
return;
- } else { //if found highlight and print it
- //highlight line number
- emit highlightLine(lineNumber);
-
- //print string number and all after it
- //output = QString::number(lineNumber) + tr(" line") + output.mid(output.indexOf("()") + 2);
- if (actionType == showLine)
- return;
- output.remove(0, output.indexOf("()") + 2);
- }
+ output.remove(0, output.indexOf("()") + 2);
}
+ }
- if (actionType == anyAction) {
- if (output[output.length() - 1] != '\n')
- output += QChar('\n');
- //process as ni or si
- if (output.indexOf(QRegExp("0x[0-9a-fA-F]{8,16} in ")) != -1
- && !backtrace) {
- actionTypeQueue.enqueue(showLine);
- processAction(output);
- }
- if (!error.isEmpty()) {
- if (output != " \n")
- output = error + output;
- else
- output = error;
- }
+ if (actionType == anyAction) {
+ if (output[output.length() - 1] != '\n')
+ output += QChar('\n');
+ //process as ni or si
+ if (output.indexOf(QRegExp("0x[0-9a-fA-F]{8,16} in ")) != -1
+ && !backtrace) {
+ actionTypeQueue.enqueue(showLine);
+ processAction(output);
+ }
+ if (!error.isEmpty()) {
+ if (output != " \n")
+ output = error + output;
+ else
+ output = error;
}
+ }
- if (actionType == infoMemory) {
- bool isValid = false;
- if (output.indexOf(QString("No symbol")) == -1 &&
- output.indexOf(QString("no debug info")) == -1 && output != QString(" ")) {
- //if variable exists (isValid = true)
- isValid = true;
- int index = output.indexOf(QRegExp("\\$\\d+ = .*"));
- if (index == -1)
- isValid = false;
- else {
- output = output.right(output.length() - index);
- output = output.right(output.length() - output.indexOf(QChar('=')) - 1);
- for (int i = output.size() - 1; i >= 0; i--) {
- if (output[i].isSpace())
- output.remove(i, 1);
- }
+ if (actionType == infoMemory) {
+ bool isValid = false;
+ if (output.indexOf(QString("No symbol")) == -1 &&
+ output.indexOf(QString("no debug info")) == -1 && output != QString(" ")) {
+ //if variable exists (isValid = true)
+ isValid = true;
+ int index = output.indexOf(QRegExp("\\$\\d+ = .*"));
+ if (index == -1)
+ isValid = false;
+ else {
+ output = output.right(output.length() - index);
+ output = output.right(output.length() - output.indexOf(QChar('=')) - 1);
+ for (int i = output.size() - 1; i >= 0; i--) {
+ if (output[i].isSpace())
+ output.remove(i, 1);
}
}
- memoryInfo info;
- if (isValid)
- info.value = output;
- info.isValid = isValid;
- watches.append(info);
- if (watchesCount == watches.size()) {
- emit printMemory(watches);
- watches.clear();
- }
- return;
}
+ memoryInfo info;
+ if (isValid)
+ info.value = output;
+ info.isValid = isValid;
+ watches.append(info);
+ if (watchesCount == watches.size()) {
+ emit printMemory(watches);
+ watches.clear();
+ }
+ return;
+ }
- if (actionType == infoRegisters) {
- QTextStream registersStream(&output);
- QList registers;
- registersInfo info;
- QSettings settings("SASM Project", "SASM");
- if (settings.value("mode", QString("x86")).toString() == "x86") {
- for (int i = 0; i < 16; i++) {
- if (i == 9) {
- registersStream >> info.name >> info.hexValue;
- registersStream.skipWhiteSpace();
- info.decValue = registersStream.readLine();
- } else if (i == 8) {
- registersStream >> info.name >> info.hexValue;
- registersStream.skipWhiteSpace();
- char c;
- registersStream >> c;
- while (c != ' ')
- registersStream >> c;
- info.decValue = registersStream.readLine();
- } else {
- registersStream >> info.name >> info.hexValue >> info.decValue;
- }
- registers.append(info);
- if (i == 0 && info.name != "eax" && registersOk) {
- doInput(QString("info registers\n"), infoRegisters);
- registersOk = false;
- return;
- }
+ if (actionType == infoRegisters) {
+ QTextStream registersStream(&output);
+ QList registers;
+ registersInfo info;
+ QSettings settings("SASM Project", "SASM");
+ if (settings.value("mode", QString("x86")).toString() == "x86") {
+ for (int i = 0; i < 16; i++) {
+ if (i == 8 || i == 9) {
+ registersStream >> info.name >> info.hexValue;
+ registersStream.skipWhiteSpace();
+ info.decValue = registersStream.readLine();
+ } else {
+ registersStream >> info.name >> info.hexValue >> info.decValue;
+ }
+ registers.append(info);
+ if (i == 0 && info.name != "eax" && registersOk) {
+ doInput(QString("info registers\n"), infoRegisters);
+ registersOk = false;
+ return;
}
- } else { //x64
- for (int i = 0; i < 24; i++) {
- if (i == 17) {
- registersStream >> info.name >> info.hexValue;
- registersStream.skipWhiteSpace();
- info.decValue = registersStream.readLine();
- } else if (i == 16) {
- registersStream >> info.name >> info.hexValue;
- registersStream.skipWhiteSpace();
- char c;
+ }
+ } else { //x64
+ for (int i = 0; i < 24; i++) {
+ if (i == 17) {
+ registersStream >> info.name >> info.hexValue;
+ registersStream.skipWhiteSpace();
+ info.decValue = registersStream.readLine();
+ } else if (i == 16) {
+ registersStream >> info.name >> info.hexValue;
+ registersStream.skipWhiteSpace();
+ char c;
+ registersStream >> c;
+ while (c != ' ')
registersStream >> c;
- while (c != ' ')
- registersStream >> c;
- info.decValue = registersStream.readLine();
- } else {
- registersStream >> info.name >> info.hexValue >> info.decValue;
- }
- registers.append(info);
- if (i == 0 && info.name != "rax" && registersOk) {
- doInput(QString("info registers\n"), infoRegisters);
- registersOk = false;
- return;
- }
+ info.decValue = registersStream.readLine();
+ } else {
+ registersStream >> info.name >> info.hexValue >> info.decValue;
+ }
+ registers.append(info);
+ if (i == 0 && info.name != "rax" && registersOk) {
+ doInput(QString("info registers\n"), infoRegisters);
+ registersOk = false;
+ return;
}
}
- emit printRegisters(registers);
- return;
}
-
- if (output == QString("\r\n") || output == QString("\n") ||
- output == QString("\r\n\n") || output == QString("\n\n")) //if empty
- return;
- } else { //if program fail
- output = output.mid(failIndex);
+ emit printRegisters(registers);
+ return;
}
+ if (output == QString("\r\n") || output == QString("\n") ||
+ output == QString("\r\n\n") || output == QString("\n\n")) //if empty
+ return;
+
//print information to log field
emit printLog(output);
+}
- if (failIndex != -1) {
- QObject::disconnect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutputToBuffer()));
- emit finished();
- return;
- }
+bool Debugger::isStopped()
+{
+ return stopped;
+}
+
+void Debugger::pause()
+{
+ #ifdef Q_OS_WIN32 //!!!!!!!!!!!!!! - now Windows only
+ HANDLE proc;
+ proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD) pid);
+ DebugBreakProcess(proc);
+ CloseHandle(proc);
+ actionTypeQueue.clear();
+ #endif
}
void Debugger::doInput(QString command, DebugActionType actionType)
@@ -406,6 +478,10 @@ void Debugger::doInput(QString command, DebugActionType actionType)
if (actionType != none)
actionTypeQueue.enqueue(actionType);
//put \n after commands!
+ if (actionType == ni || actionType == si || actionType == showLine) {
+ emit highlightLine(-2); //does not turn off debug mode
+ stopped = false;
+ }
if (process)
process->write(command.toLatin1());
}
@@ -421,7 +497,13 @@ void Debugger::processLst()
QFile lst;
lst.setFileName(tmpPath + "program.lst");
if (lst.open(QIODevice::ReadOnly)) {
- offset -= assembler->getMainOffset(lst);
+ //heuristic:
+ //if debug symbols exists - offset is difference between main labels in listing and in executable
+ //otherwise - offset is difference between beginning of text sections in listing and in executable
+ if (dbgSymbols)
+ offset -= assembler->getMainOffset(lst, "main");
+ else
+ offset -= assembler->getMainOffset(lst, "start");
lst.close();
lst.open(QIODevice::ReadOnly);
assembler->parseLstFile(lst, lines, ioIncIncluded, ioIncSize, offset);
@@ -434,7 +516,11 @@ void Debugger::run()
//set breakpoint on main, run program amd open output and input files
//put \n after commands!
//b main and run before others!
- doInput(QString("b main\n"), none);
+ if (dbgSymbols)
+ doInput(QString("b main\n"), none);
+ else {
+ doInput("b *0x" + QString::number(entryPoint, 16) + "\n", none);
+ }
doInput(QString("cd " + tmpPath + "\n"), none);
doInput(QString("run\n"), none);
doInput(QString("p dup2(open(\"input.txt\",0),0)\n"), none);
@@ -442,6 +528,12 @@ void Debugger::run()
void Debugger::changeBreakpoint(quint64 lineNumber, bool isAdded)
{
+ if (!isStopped()) {
+ QEventLoop eventLoop;
+ connect(this, SIGNAL(wasStopped()), &eventLoop, SLOT(quit()));
+ pause();
+ eventLoop.exec();
+ }
quint64 numInMem = 0;
LineNum brkpoint;
for (int i = 0; i < lines.count(); i++) //find address of line
diff --git a/debugger.h b/debugger.h
index 9d5ee492..c21ab71b 100644
--- a/debugger.h
+++ b/debugger.h
@@ -54,6 +54,12 @@
#include
#include "assembler.h"
+#ifdef Q_OS_WIN32
+ #include
+ #include
+ #include
+#endif
+
enum DebugActionType {ni, si, showLine, infoRegisters, infoMemory, anyAction, none, breakpoint};
class Debugger : public QObject
@@ -78,6 +84,9 @@ class Debugger : public QObject
typedef Assembler::LineNum LineNum;
+ bool isStopped();
+ void pause();
+
private:
void processLst();
void run();
@@ -109,6 +118,12 @@ class Debugger : public QObject
Assembler *assembler;
+ bool stopped;
+ quint64 pid;
+ bool dbgSymbols;
+
+ quint64 entryPoint;
+
public slots:
void readOutputToBuffer();
void processOutput();
@@ -116,6 +131,7 @@ public slots:
void processAction(QString output, QString error = QString());
void doInput(QString command, DebugActionType actionType);
void changeBreakpoint(quint64 lineNumber, bool isAdded);
+ void emitStarted();
signals:
void highlightLine(int); //highlight current debug line
@@ -126,6 +142,7 @@ public slots:
void printLog(QString msg, QColor color = QColor(Qt::black));
void printOutput(QString msg);
void inMacro();
+ void wasStopped();
};
#endif // DEBUGGER_H
diff --git a/fasm.cpp b/fasm.cpp
index 904c10a8..19f9ce3a 100644
--- a/fasm.cpp
+++ b/fasm.cpp
@@ -61,6 +61,7 @@ QString FASM::getListingFilePath(QFile &lstOut)
QProcess getLst;
QStringList getLstArguments;
getLstArguments << lstOut.fileName() << listingPath;
+ getLst.setWorkingDirectory(Common::applicationDataPath() + "/include");
#ifdef Q_OS_WIN32
getLst.start(Common::applicationDataPath() + "/FASM/listing.exe", getLstArguments);
#else
@@ -70,12 +71,16 @@ QString FASM::getListingFilePath(QFile &lstOut)
return listingPath;
}
-quint64 FASM::getMainOffset(QFile &lstOut) {
+quint64 FASM::getMainOffset(QFile &lstOut, QString entryLabel)
+{
QFile lst(getListingFilePath(lstOut));
lst.open(QFile::ReadOnly);
-
QTextStream lstStream(&lst);
- QRegExp mainLabel("main:");
+ QRegExp mainLabel;
+ if (entryLabel == "start")
+ mainLabel = QRegExp("\\.text");
+ else
+ mainLabel = QRegExp(entryLabel + ":");
bool flag = false;
while (!lstStream.atEnd()) {
QString line = lstStream.readLine();
@@ -99,31 +104,48 @@ void FASM::parseLstFile(QFile &lstOut, QVector &lines, bool,
QFile lst(getListingFilePath(lstOut));
lst.open(QFile::ReadOnly);
- bool inTextSection = false;
- QRegExp sectionTextRegExp("\\.text");
- QRegExp sectionBssRegExp("\\.bss");
- QRegExp sectionDataRegExp("\\.data");
QTextStream lstStream(&lst);
quint64 currentLine = 0;
+ QList > instrList;
while (!lstStream.atEnd()) {
QString line = lstStream.readLine();
currentLine++;
- if (line.indexOf(sectionTextRegExp) != -1) {
- inTextSection = true;
- } else if (line.indexOf(sectionDataRegExp) != -1 || line.indexOf(sectionBssRegExp) != -1) {
- inTextSection = false;
- }
- if (inTextSection) {
- line = line.split(QChar(':')).at(0);
- if (line.length() > 16)
- continue;
+ int index = line.indexOf(QChar(':'));
+ if (index == -1 || index > 16)
+ continue;
+ QString first = line.left(index);
+ QString second = line.mid(index + 1);
+ QStringList l = line.split(QChar(':'));
+ int k = 0;
+ while (k < second.length() && second[k].isSpace())
+ k++;
+ second.remove(0, k);
+ instrList.append(QPair(first.toULongLong(0, 16) + offset, second));
+ }
+ lst.close();
+ QFile programFile(Common::pathInTemp("program.asm"));
+ programFile.open(QFile::ReadOnly);
+ QTextStream programStream(&programFile);
+ int i = 0; //offset in list
+ int numInCode = 0;
+ while (!programStream.atEnd()) {
+ QString line = programStream.readLine();
+ numInCode++;
+ int k = 0;
+ while (k < line.length() && line[k].isSpace())
+ k++;
+ line.remove(0, k);
+ if (line == instrList[i].second) {
LineNum l;
- l.numInCode = currentLine;
- l.numInMem = line.toULongLong(0, 16) + offset;
+ l.numInCode = numInCode;
+ l.numInMem = instrList[i].first;
lines.append(l);
+ i++;
+ if (i >= instrList.size())
+ break;
}
}
- lst.close();
+ programFile.close();
}
QString FASM::getStartText()
diff --git a/fasm.h b/fasm.h
index 0b0e70a6..bb71b899 100644
--- a/fasm.h
+++ b/fasm.h
@@ -42,6 +42,7 @@
#define FASM_H
#include
+#include
#include "assembler.h"
class FASM : public Assembler
@@ -50,7 +51,7 @@ class FASM : public Assembler
public:
explicit FASM(bool x86, QObject *parent = 0);
QString getAssemblerPath();
- quint64 getMainOffset(QFile &lstOut);
+ quint64 getMainOffset(QFile &lstOut, QString entryLabel);
void parseLstFile(QFile &lstOut, QVector &lines, bool, quint64, quint64 offset);
void fillHighligherRules(QVector &highlightingRules,
QList &formats,
diff --git a/gas.cpp b/gas.cpp
index ed421526..38e28c48 100644
--- a/gas.cpp
+++ b/gas.cpp
@@ -57,9 +57,12 @@ QString GAS::getAssemblerPath()
#endif
}
-quint64 GAS::getMainOffset(QFile &lst) {
+quint64 GAS::getMainOffset(QFile &lst, QString entryLabel)
+{
+ if (entryLabel == "start")
+ return 0;
QTextStream lstStream(&lst);
- QRegExp mainLabel("main:");
+ QRegExp mainLabel(entryLabel + ":");
bool flag = false;
while (!lstStream.atEnd()) {
QString line = lstStream.readLine();
@@ -69,7 +72,8 @@ quint64 GAS::getMainOffset(QFile &lst) {
//omit this string
continue;
}
- char *s = line.toLocal8Bit().data();
+ QByteArray lineArr = line.toLocal8Bit();
+ const char *s = lineArr.constData();
quint64 a, b, c;
if (sscanf(s, "%llu %llx %llx", &a, &b, &c) == 3) {
if (!(b == 0 && c == 0)) { //exclude 0 0
@@ -104,7 +108,8 @@ void GAS::parseLstFile(QFile &lst, QVector &lines, bool ioIn
continue;
}
if (inTextSection) {
- char *s = line.toLocal8Bit().data();
+ QByteArray lineArr = line.toLocal8Bit();
+ const char *s = lineArr.constData();
quint64 a, b, c;
if (sscanf(s, "%llu %llx %llx", &a, &b, &c) == 3){
if (!(b == 0 && c == 0)) { //exclude 0 0
diff --git a/gas.h b/gas.h
index ca432b4b..f8dc59d2 100644
--- a/gas.h
+++ b/gas.h
@@ -49,7 +49,7 @@ class GAS : public Assembler
public:
explicit GAS(bool x86, QObject *parent = 0);
QString getAssemblerPath();
- quint64 getMainOffset(QFile &lst);
+ quint64 getMainOffset(QFile &lst, QString entryLabel);
void parseLstFile(QFile &lst, QVector &lines, bool ioIncIncluded, quint64 ioIncSize, quint64 offset);
void fillHighligherRules(QVector &highlightingRules,
QList &formats,
diff --git a/images/debugPause.png b/images/debugPause.png
new file mode 100644
index 00000000..7b74a586
Binary files /dev/null and b/images/debugPause.png differ
diff --git a/language_ru.qm b/language_ru.qm
index 9d08ec3b..552a8d76 100644
Binary files a/language_ru.qm and b/language_ru.qm differ
diff --git a/language_ru.ts b/language_ru.ts
index 2106ea0a..2aac7e93 100644
--- a/language_ru.ts
+++ b/language_ru.ts
@@ -1,6 +1,6 @@
-
+
CommandDebugWindow
@@ -105,7 +105,14 @@
Debugger
-
+
+
+ Ошибка GDB
+
+
+
+
Во время отладки произошла ошибка. Проверьте названия секций.
@@ -204,145 +211,156 @@
-
+
Файл
-
+
Правка
-
+
Построение
-
-
+
+
+
Отладка
-
-
+
+
Настройки
-
-
-
+
+
+
Помощь
-
-
+
+
Новый
-
+
Открыть
-
+
Закрыть файл
-
+
Сохранить
-
+
Сохранить как
-
+
Сохранить .exe
-
+
Выход
-
+
Поиск и замена
-
+
Отменить
-
+
Повторить
-
+
Вырезать
-
+
Копировать
-
+
Вставить
-
+
Удалить
-
+
Выделить всё
-
+
Закомментировать
-
+
Раскомментировать
-
+
Отступ
-
+
Убрать отступ
-
+
Построить
-
+
+
+ Ошибка! Каталога программы не существует. Пожалуйста, переустановите программу.
+
+
+
+
+ Приостановить
+
+
+
SASM (SimpleASM) 2.3 - простая Open Source среда разработки на языке ассемблера NASM.
@@ -351,7 +369,7 @@
SASM (SimpleASM) 2.2 - простая Open Source среда разработки на языке ассемблера NASM.
-
+
Яндекс.Деньги - 410012181834380
@@ -360,47 +378,49 @@
Запустить
-
+
Запустить в отдельном окне
-
+
Остановить
-
+
+
+
Продолжить
-
+
Шаг с заходом
-
+
Шаг без захода
-
+
Построить и запустить
-
+
Точка останова
-
+
Показать регистры
-
+
Показать память
@@ -409,18 +429,18 @@
Программа
-
+
Исполняемые файлы (*.exe);;Все файлы (*.*)
-
+
The program finished normally. Execution time: %1 ms
Программа выполнена успешно. Время выполнения: %1 с
-
+
The program crashed! Execution time: %1 ms
Программа завершена аварийно. Время выполнения: %1 с
@@ -438,30 +458,30 @@
Команда gdb
-
+
О программе
-
+
Открыть файл
-
-
+
+
Assembler source file (*.asm)
All files (*.*)
Исходные коды ассемблера (*.asm);;Все файлы (*.*)
-
+
Сохранить файл
-
+
Сохранить .exe
@@ -472,52 +492,51 @@ All files (*.*)
Все файлы (*.*)
-
-
+
+
Да
-
+
Нет
-
-
+
+
Отмена
-
-
+
+
Сохранить изменения?
-
+
Build started...
Построение начато...
-
- Ошибка! Каталога NASM не существует. Пожалуйста, переустановите программу.
+ Ошибка! Каталога NASM не существует. Пожалуйста, переустановите программу.
-
+
Каталога NASM не существует. Пожалуйста, переустановите программу.
-
+
Программа уже запущена.
-
+
Программа выполняется...
@@ -531,7 +550,7 @@ All files (*.*)
Программа завершена аварийно!
-
+
Идея и разработка - Дмитрий Манушин
@@ -548,7 +567,7 @@ All files (*.*)
Integer
-
+
Регистры
@@ -561,7 +580,7 @@ All files (*.*)
Ошибка! Каталога NASM не существует. Пожалуйста, переустановите программу.
-
+
Ошибка!
@@ -570,14 +589,14 @@ All files (*.*)
Каталога NASM не существует. Пожалуйста, переустановите программу.
-
+
Warning! Errors have occurred in the build:
Внимание! В ходе построения обнаружены ошибки:
-
+
Внимание!
@@ -586,7 +605,7 @@ All files (*.*)
При построении программы обнаружены ошибки!
-
+
Built successfully.
@@ -605,55 +624,55 @@ All files (*.*)
Программа выполнена.
-
+
The program stopped.
Программа остановлена.
-
+
Программа не была запущена.
-
+
Before debugging you need to build the program.
Перед отладкой следует построить программу.
-
+
Debugging started...
Отладка началась...
-
+
Память
-
+
Debugging finished.
Отладка завершена.
-
+
В предыдущей сессии не было открыто ни одной сохранённой вкладки!
-
+
Все настройки будут удалены, а несохранённые данные потеряны! Вы уверены?
-
+
О программе
@@ -662,17 +681,17 @@ All files (*.*)
SASM (SimpleASM) 2.0 Beta - простая Open Source среда разработки на языке ассемблера NASM.
-
+
Распространяется по лицензии GNU GPL v3.0
-
+
Основана на Qt.
-
+
Copyright © 2013 Dmitriy Manushin
Copyright © 2013 Дмитрий Манушин
@@ -682,12 +701,12 @@ All files (*.*)
Разработка - Dmitriy Manushin
-
+
Иконка и советы - Алик Гайбуллаев
-
+
Wishes and error messages are sent to the e-mail: Dman1095@gmail.com
@@ -695,27 +714,27 @@ All files (*.*)
Пожелания и сообщения об ошибках отправляйте на адрес Dman1095@gmail.com
-
+
Сайт программы: http://dman95.github.io/SASM/
-
+
Поддержите проект:
-
+
PayPal - Dman1095@gmail.com
-
+
WMZ - Z282016332582
-
+
WMR - R331674303467
@@ -1064,6 +1083,16 @@ WMR - R331674303467
Опции компоновщика:
+
+
+
+ Ассемблер
+
+
+
+
+ Компоновщик
+
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 1112ac4c..d5094b83 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -213,7 +213,6 @@ void MainWindow::createMenus()
debugMenu = menuBar()->addMenu(tr("Debug"));
debugMenu->addAction(debugAction);
debugMenu->addSeparator();
- debugMenu->addAction(debugContinueAction);
debugMenu->addAction(debugNextNiAction);
debugMenu->addAction(debugNextAction);
debugMenu->addSeparator();
@@ -402,16 +401,9 @@ void MainWindow::createActions()
if (key == "default")
key = stdKey.toString();
debugAction->setShortcut(key);
+ debugKey = key;
connect(debugAction, SIGNAL(triggered()), this, SLOT(debug()));
- debugContinueAction = new QAction(QIcon(":/images/continue.png"), tr("Continue"), this);
- key = keySettings.value("continue", "default").toString();
- stdKey = QKeySequence(QString("F5"));
- if (key == "default")
- key = stdKey.toString();
- debugContinueAction->setShortcut(key);
- connect(debugContinueAction, SIGNAL(triggered()), this, SLOT(debugContinue()));
-
debugNextNiAction = new QAction(QIcon(":/images/stepover.png"), tr("Step over"), this);
key = keySettings.value("stepOver", "default").toString();
stdKey = QKeySequence(QString("F10"));
@@ -500,7 +492,6 @@ void MainWindow::createToolBars()
debugToolBar = addToolBar(tr("Debug"));
debugToolBar->addAction(debugAction);
- debugToolBar->addAction(debugContinueAction);
debugToolBar->addAction(debugNextNiAction);
debugToolBar->addAction(debugNextAction);
debugToolBar->addAction(stopAction);
@@ -816,6 +807,8 @@ void MainWindow::buildProgram(bool debugMode)
//assembler
QString assemblerPath = assembler->getAssemblerPath();
+ if (settings.contains("assemblerpath"))
+ assemblerPath = settings.value("assemblerpath").toString();
#ifdef Q_OS_WIN32
QString assemblerOptions = "-g -f win32 $SOURCE$ -l $LSTOUTPUT$ -o $PROGRAM.OBJ$";
#else
@@ -838,23 +831,22 @@ void MainWindow::buildProgram(bool debugMode)
assemblerProcess.waitForFinished();
//GCC
- QString gccOptions = "$PROGRAM.OBJ$ $MACRO.OBJ$ -g -o $PROGRAM$ -m32";
+ QString linkerOptions = "$PROGRAM.OBJ$ $MACRO.OBJ$ -g -o $PROGRAM$ -m32";
if (settings.contains("linkingoptions"))
- gccOptions = settings.value("linkingoptions").toString();
+ linkerOptions = settings.value("linkingoptions").toString();
//macro.c compilation/copying
QFile macro;
#ifdef Q_OS_WIN32
- QString gcc;
+ QString linker = settings.value("linkerpath", applicationDataPath() + "/MinGW/bin/gcc.exe").toString();
if (settings.value("mode", QString("x86")).toString() == "x86") {
macro.setFileName(applicationDataPath() + "/NASM/macro.o");
- gcc = applicationDataPath() + "/MinGW/bin/gcc.exe";
} else {
macro.setFileName(applicationDataPath() + "/NASM/macro64.o");
- gcc = applicationDataPath() + "/MinGW64/bin/gcc.exe";
}
macro.copy(stdioMacros);
#else
QString gcc = "gcc";
+ QString linker = settings.value("linkerpath", "gcc").toString();
macro.setFileName(applicationDataPath() + "/NASM/macro.c");
macro.copy(Common::pathInTemp("macro.c"));
@@ -870,18 +862,18 @@ void MainWindow::buildProgram(bool debugMode)
gccMProcess.waitForFinished();
#endif
//final linking
- gccOptions.replace("$PROGRAM.OBJ$", Common::pathInTemp("program.o"));
- gccOptions.replace("$MACRO.OBJ$", stdioMacros);
- gccOptions.replace("$PROGRAM$", Common::pathInTemp("SASMprog.exe"));
- gccOptions.replace("$SOURCE$", Common::pathInTemp("program.asm"));
- gccOptions.replace("$LSTOUTPUT$", Common::pathInTemp("program.lst"));
- QStringList gccArguments = gccOptions.split(QChar(' '));
- QProcess gccProcess;
- QString gccOutput = Common::pathInTemp("linkererror.txt");
- gccProcess.setStandardOutputFile(gccOutput);
- gccProcess.setStandardErrorFile(gccOutput, QIODevice::Append);
- gccProcess.start(gcc, gccArguments);
- gccProcess.waitForFinished();
+ linkerOptions.replace("$PROGRAM.OBJ$", Common::pathInTemp("program.o"));
+ linkerOptions.replace("$MACRO.OBJ$", stdioMacros);
+ linkerOptions.replace("$PROGRAM$", Common::pathInTemp("SASMprog.exe"));
+ linkerOptions.replace("$SOURCE$", Common::pathInTemp("program.asm"));
+ linkerOptions.replace("$LSTOUTPUT$", Common::pathInTemp("program.lst"));
+ QStringList linkerArguments = linkerOptions.split(QChar(' '));
+ QProcess linkerProcess;
+ QString linkerOutput = Common::pathInTemp("linkererror.txt");
+ linkerProcess.setStandardOutputFile(linkerOutput);
+ linkerProcess.setStandardErrorFile(linkerOutput, QIODevice::Append);
+ linkerProcess.start(linker, linkerArguments);
+ linkerProcess.waitForFinished();
QFile logFile;
logFile.setFileName(assemblerOutput);
@@ -903,7 +895,7 @@ void MainWindow::buildProgram(bool debugMode)
//print errors
printLog(logText, Qt::red);
- logFile.setFileName(gccOutput);
+ logFile.setFileName(linkerOutput);
logFile.open(QIODevice::ReadOnly);
QTextStream logLinker(&logFile);
logText = logLinker.readAll();
@@ -916,7 +908,7 @@ void MainWindow::buildProgram(bool debugMode)
printLogWithTime(tr("Built successfully.") + '\n', Qt::darkGreen);
//print warnings
printLog(logText, Qt::red);
- logFile.setFileName(gccOutput);
+ logFile.setFileName(linkerOutput);
logFile.open(QIODevice::ReadOnly);
QTextStream logLinker(&logFile);
logText = logLinker.readAll();
@@ -1062,31 +1054,65 @@ void MainWindow::printOutput(QString msg, int index)
void MainWindow::debug()
{
- buildProgram(true);
- if (!programIsBuilded) {
- printLogWithTime(tr("Before debugging you need to build the program.") + '\n', Qt::red);
- return;
+ if (!debugger) { //start debugger
+ debuggerWasStarted = false;
+ buildProgram(true);
+ if (!programIsBuilded) {
+ printLogWithTime(tr("Before debugging you need to build the program.") + '\n', Qt::red);
+ return;
+ }
+ ((Tab *) tabs->currentWidget())->clearOutput();
+ printLogWithTime(tr("Debugging started...") + '\n', Qt::darkGreen);
+ QString path = Common::pathInTemp("SASMprog.exe");
+ CodeEditor *code = ((Tab *) tabs->currentWidget())->code;
+ debugger = new Debugger(compilerOut, path, ioIncIncluded, Common::pathInTemp(QString()), assembler);
+ connect(debugger, SIGNAL(highlightLine(int)), code, SLOT(updateDebugLine(int)));
+ connect(debugger, SIGNAL(finished()), this, SLOT(debugExit()), Qt::QueuedConnection);
+ connect(debugger, SIGNAL(started()), this, SLOT(enableDebugActions()));
+ connect(debugger, SIGNAL(started()), this, SLOT(showAnyCommandWidget()));
+ connect(code, SIGNAL(breakpointsChanged(quint64,bool)), debugger, SLOT(changeBreakpoint(quint64,bool)));
+ connect(code, SIGNAL(addWatchSignal(const RuQPlainTextEdit::Watch &)),
+ this, SLOT(setShowMemoryToChecked(RuQPlainTextEdit::Watch)));
+ connect(debugger, SIGNAL(printLog(QString,QColor)), this, SLOT(printLog(QString,QColor)));
+ connect(debugger, SIGNAL(printOutput(QString)), this, SLOT(printOutput(QString)));
+ connect(debugger, SIGNAL(inMacro()), this, SLOT(debugNextNi()), Qt::QueuedConnection);
+ connect(debugger, SIGNAL(wasStopped()), this, SLOT(changeDebugActionToStart()));
+ code->setDebugEnabled();
+ } else { //pause or continue debugger
+ debugAction->setEnabled(false);
+ if (debugger->isStopped()) {
+ debugAction->setText(tr("Pause"));
+ debugAction->setIcon(QIcon(":/images/debugPause.png"));
+ debugger->doInput(QString("c\n"), ni);
+ debugAction->setShortcut(QString());
+ } else {
+ debugAction->setText(tr("Continue"));
+ debugAction->setIcon(QIcon(":/images/continue.png"));
+ debugAction->setShortcut(debugKey);
+ debugger->pause();
+ }
+ debugAction->setEnabled(true);
+ }
+}
+
+void MainWindow::changeDebugActionToStart()
+{
+ debugAction->setText(tr("Continue"));
+ debugAction->setIcon(QIcon(":/images/continue.png"));
+ debugAction->setShortcut(debugKey);
+ if (!debuggerWasStarted)
+ debuggerWasStarted = true;
+ else {
+ debugShowRegisters();
+ debugShowMemory();
}
- ((Tab *) tabs->currentWidget())->clearOutput();
- printLogWithTime(tr("Debugging started...") + '\n', Qt::darkGreen);
- QString path = Common::pathInTemp("SASMprog.exe");
- CodeEditor *code = ((Tab *) tabs->currentWidget())->code;
- debugger = new Debugger(compilerOut, path, ioIncIncluded, Common::pathInTemp(QString()), assembler);
- connect(debugger, SIGNAL(highlightLine(int)), code, SLOT(updateDebugLine(int)));
- connect(debugger, SIGNAL(finished()), this, SLOT(debugExit()), Qt::QueuedConnection);
- connect(debugger, SIGNAL(started()), this, SLOT(enableDebugActions()));
- connect(debugger, SIGNAL(started()), this, SLOT(showAnyCommandWidget()));
- connect(code, SIGNAL(breakpointsChanged(quint64,bool)), debugger, SLOT(changeBreakpoint(quint64,bool)));
- connect(code, SIGNAL(addWatchSignal(const RuQPlainTextEdit::Watch &)),
- this, SLOT(setShowMemoryToChecked(RuQPlainTextEdit::Watch)));
- connect(debugger, SIGNAL(printLog(QString,QColor)), this, SLOT(printLog(QString,QColor)));
- connect(debugger, SIGNAL(printOutput(QString)), this, SLOT(printOutput(QString)));
- connect(debugger, SIGNAL(inMacro()), this, SLOT(debugNextNi()), Qt::QueuedConnection);
- code->setDebugEnabled();
}
void MainWindow::enableDebugActions()
{
+ debugAction->setText(tr("Continue"));
+ debugAction->setIcon(QIcon(":/images/continue.png"));
+
//set all user's breakpoints
CodeEditor *code = ((Tab *) tabs->currentWidget())->code;
int lineNumber;
@@ -1095,8 +1121,6 @@ void MainWindow::enableDebugActions()
}
//enable all actions
- debugAction->setEnabled(false);
- debugContinueAction->setEnabled(true);
debugNextAction->setEnabled(true);
debugNextNiAction->setEnabled(true);
debugShowRegistersAction->setEnabled(true);
@@ -1118,8 +1142,9 @@ void MainWindow::enableDebugActions()
void MainWindow::disableDebugActions(bool start)
{
- debugAction->setEnabled(true);
- debugContinueAction->setEnabled(false);
+ debugAction->setText(tr("Debug"));
+ debugAction->setIcon(QIcon(":/images/debug.png"));
+
debugNextAction->setEnabled(false);
debugNextNiAction->setEnabled(false);
debugShowRegistersAction->setEnabled(false);
@@ -1137,15 +1162,6 @@ void MainWindow::disableDebugActions(bool start)
runAction->setEnabled(true);
}
-void MainWindow::debugContinue()
-{
- debugContinueAction->setEnabled(false);
- debugger->doInput(QString("c\n"), ni);
- debugShowRegisters();
- debugShowMemory();
- debugContinueAction->setEnabled(true);
-}
-
void MainWindow::debugNext()
{
CodeEditor *code = ((Tab *) tabs->currentWidget())->code;
@@ -1154,8 +1170,6 @@ void MainWindow::debugNext()
} else {
debugNextAction->setEnabled(false);
debugger->doInput(QString("si\n"), si);
- debugShowRegisters();
- debugShowMemory();
debugNextAction->setEnabled(true);
}
}
@@ -1170,8 +1184,6 @@ void MainWindow::debugNextNi()
{
debugNextNiAction->setEnabled(false);
debugger->doInput(QString("ni\n"), ni);
- debugShowRegisters();
- debugShowMemory();
debugNextNiAction->setEnabled(true);
}
@@ -1206,46 +1218,47 @@ void MainWindow::debugShowMemory()
//fill table
memoryWindow->initializeMemoryWindow(watches);
}
- debugger->setWatchesCount(memoryWindow->rowCount() - 1);
- for (int i = 0; i < memoryWindow->rowCount() - 1; i++) {
- if (memoryWindow->cellWidget(i, 2)) {
- WatchSettinsWidget *settings = (WatchSettinsWidget *) memoryWindow->cellWidget(i, 2);
-
- int arraySize = 0;
-
- int size = settings->sizeComboBox->currentIndex();
- QStringList sizeFormat;
- sizeFormat << "int" << "short" << "char" << "long long";
-
- bool ok;
- arraySize = settings->arraySizeEdit->text().toInt(&ok);
- if (!ok && sizeFormat[size] == "long long") {
- arraySize = 1;
- ok = true;
- }
- QString watchAsArray;
- if (ok && arraySize > 0)
- watchAsArray = "[" + QString::number(arraySize) + "]";
-
- int type = settings->typeComboBox->currentIndex();
- QStringList printFormat;
- printFormat << "p" << "p/x" << "p/t" << "p/c" << "p/d" << "p/u" << "p/f";
-
- if (! settings->addressCheckbox->isChecked()) { //watch as variable
- debugger->doInput(printFormat[type] + " (" + sizeFormat[size] + watchAsArray + ")" +
- memoryWindow->item(i, 0)->text() + "\n", infoMemory);
- } else { //watch as random address
- debugger->doInput(printFormat[type] + " (" + sizeFormat[size] + watchAsArray + ")" +
- "*((" + sizeFormat[size] + "*) " + memoryWindow->item(i, 0)->text() + ")" +
- "\n", infoMemory);
+ if (debugger->isStopped()) {
+ debugger->setWatchesCount(memoryWindow->rowCount() - 1);
+ for (int i = 0; i < memoryWindow->rowCount() - 1; i++) {
+ if (memoryWindow->cellWidget(i, 2)) {
+ WatchSettinsWidget *settings = (WatchSettinsWidget *) memoryWindow->cellWidget(i, 2);
+
+ int arraySize = 0;
+
+ int size = settings->sizeComboBox->currentIndex();
+ QStringList sizeFormat;
+ sizeFormat << "int" << "short" << "char" << "long long";
+
+ bool ok;
+ arraySize = settings->arraySizeEdit->text().toInt(&ok);
+ if (!ok && sizeFormat[size] == "long long") {
+ arraySize = 1;
+ ok = true;
+ }
+ QString watchAsArray;
+ if (ok && arraySize > 0)
+ watchAsArray = "[" + QString::number(arraySize) + "]";
+
+ int type = settings->typeComboBox->currentIndex();
+ QStringList printFormat;
+ printFormat << "p" << "p/x" << "p/t" << "p/c" << "p/d" << "p/u" << "p/f";
+
+ if (! settings->addressCheckbox->isChecked()) { //watch as variable
+ debugger->doInput(printFormat[type] + " (" + sizeFormat[size] + watchAsArray + ")" +
+ memoryWindow->item(i, 0)->text() + "\n", infoMemory);
+ } else { //watch as random address
+ debugger->doInput(printFormat[type] + " (" + sizeFormat[size] + watchAsArray + ")" +
+ "*((" + sizeFormat[size] + "*) " + memoryWindow->item(i, 0)->text() + ")" +
+ "\n", infoMemory);
+ }
}
}
- }
- if (memoryWindow->rowCount() > 1) {
- QEventLoop eventLoop;
- connect(debugger, SIGNAL(printMemory(QList)), &eventLoop, SLOT(quit()));
- connect(debugger, SIGNAL(finished()), &eventLoop, SLOT(quit()));
- eventLoop.exec();
+ static SignalLocker locker;
+ if (memoryWindow->rowCount() > 1 && locker.tryLock()) {
+ connect(debugger, SIGNAL(printMemory(QList)), &locker, SLOT(unlock()), Qt::UniqueConnection);
+ connect(debugger, SIGNAL(finished()), &locker, SLOT(unlock()), Qt::UniqueConnection);
+ }
}
} else
if (memoryWindow) {
@@ -1320,11 +1333,12 @@ void MainWindow::debugShowRegisters()
if (memoryDock)
memoryDock->show();
}
- debugger->doInput(QString("info registers\n"), infoRegisters);
- QEventLoop eventLoop;
- connect(debugger, SIGNAL(printRegisters(QList)), &eventLoop, SLOT(quit()));
- connect(debugger, SIGNAL(finished()), &eventLoop, SLOT(quit()));
- eventLoop.exec();
+ static SignalLocker locker;
+ if (debugger->isStopped() && locker.tryLock()) {
+ connect(debugger, SIGNAL(printRegisters(QList)), &locker, SLOT(unlock()), Qt::UniqueConnection);
+ connect(debugger, SIGNAL(finished()), &locker, SLOT(unlock()), Qt::UniqueConnection);
+ debugger->doInput(QString("info registers\n"), infoRegisters);
+ }
} else
if (registersWindow) {
registersWindow->close();
@@ -1379,16 +1393,16 @@ void MainWindow::closeAnyCommandWidget()
void MainWindow::debugRunCommand(QString command, bool print)
{
- printLog("> " + command + "\n", QColor(32, 71, 247));
- QEventLoop eventLoop;
- connect(debugger, SIGNAL(printLog(QString,QColor)), &eventLoop, SLOT(quit()));
- if (print)
- debugger->doInput("p " + command + "\n", anyAction);
- else
- debugger->doInput(command + "\n", anyAction);
- eventLoop.exec();
- debugShowRegisters();
- debugShowMemory();
+ static SignalLocker locker;
+ if (debugger->isStopped() && locker.tryLock()) {
+ connect(debugger, SIGNAL(printLog(QString,QColor)), &locker, SLOT(unlock()), Qt::UniqueConnection);
+ connect(debugger, SIGNAL(finished()), &locker, SLOT(unlock()), Qt::UniqueConnection);
+ printLog("> " + command + "\n", QColor(32, 71, 247));
+ if (print)
+ debugger->doInput("p " + command + "\n", anyAction);
+ else
+ debugger->doInput(command + "\n", anyAction);
+ }
}
void MainWindow::find()
@@ -1677,6 +1691,15 @@ void MainWindow::initAssemblerSettings(bool firstOpening)
QString linkerOptions = assembler->getLinkerOptions();
settingsUi.linkingOptionsEdit->setText(settings.value("linkingoptions", linkerOptions).toString());
+ QString assemblerPath = assembler->getAssemblerPath();
+ settingsUi.assemblerPathEdit->setText(settings.value("assemblerpath", assemblerPath).toString());
+
+#ifdef Q_OS_WIN32
+ settingsUi.linkerPathEdit->setText(settings.value("linkerpath", Common::applicationDataPath() + "/MinGW/bin/gcc.exe").toString());
+#else
+ settingsUi.linkerPathEdit->setText(settings.value("linkerpath", "gcc").toString());
+#endif
+
disconnect(settingsUi.x86RadioButton, SIGNAL(toggled(bool)), this, SLOT(changeMode(bool)));
//mode
if (assembler->isx86())
@@ -1755,8 +1778,10 @@ void MainWindow::recreateAssembler(bool start)
if (!start) {
settingsUi.assemblyOptionsEdit->setText(assembler->getAssemblerOptions());
settingsUi.linkingOptionsEdit->setText(assembler->getLinkerOptions());
+ settingsUi.assemblerPathEdit->setText(assembler->getAssemblerPath());
settings.setValue("assemblyoptions", assembler->getAssemblerOptions());
settings.setValue("linkingoptions", assembler->getLinkerOptions());
+ settings.setValue("assemblerpath", assembler->getAssemblerPath());
changeStartText();
recreateHighlighter();
}
@@ -1773,6 +1798,7 @@ void MainWindow::backupSettings()
backupAssembler = settings.value("assembler", QString("NASM")).toString();
backupMode = settings.value("mode", QString("x86")).toString();
backupAssemblerOptions = settings.value("assemblyoptions", assembler->getAssemblerOptions()).toString();
+ backupAssemblerPath = settings.value("assemblerpath", assembler->getAssemblerPath()).toString();
backupLinkerOptions = settings.value("linkingoptions", assembler->getLinkerOptions()).toString();
backupStartText = settings.value("starttext", assembler->getStartText()).toString();
}
@@ -1783,6 +1809,7 @@ void MainWindow::restoreSettingsAndExit()
settings.setValue("mode", backupMode);
recreateAssembler();
settings.setValue("assemblyoptions", backupAssemblerOptions);
+ settings.setValue("assemblerpath", backupAssemblerPath);
settings.setValue("linkingoptions", backupLinkerOptions);
settings.setValue("starttext", backupStartText);
settingsWindow->close();
@@ -1822,6 +1849,8 @@ void MainWindow::saveSettings()
settings.setValue("assemblyoptions", settingsUi.assemblyOptionsEdit->text());
settings.setValue("linkingoptions", settingsUi.linkingOptionsEdit->text());
+ settings.setValue("assemblerpath", settingsUi.assemblerPathEdit->text());
+ settings.setValue("linkerpath", settingsUi.linkerPathEdit->text());
settings.setValue("starttext", settingsStartTextEditor->document()->toPlainText());
backupSettings();
@@ -1936,7 +1965,6 @@ void MainWindow::changeActionsState(int widgetIndex)
runExeAction->setEnabled(false);
stopAction->setEnabled(false);
debugAction->setEnabled(false);
- debugContinueAction->setEnabled(false);
debugNextAction->setEnabled(false);
debugNextNiAction->setEnabled(false);
debugShowRegistersAction->setEnabled(false);
diff --git a/mainwindow.h b/mainwindow.h
index 5c495f0a..9a10abeb 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -55,6 +55,7 @@
#include
#include
#include
+#include
#include "tab.h"
#include "highlighter.h"
#include "debugger.h"
@@ -70,6 +71,7 @@
#include "gas.h"
#include "common.h"
#include "fasm.h"
+#include "signallocker.h"
class MainWindow : public QMainWindow
{
@@ -131,7 +133,6 @@ class MainWindow : public QMainWindow
QAction *runExeAction;
QAction *stopAction;
QAction *debugAction;
- QAction *debugContinueAction;
QAction *debugNextAction;
QAction *debugNextNiAction;
QAction *debugToggleBreakpointAction;
@@ -164,6 +165,8 @@ class MainWindow : public QMainWindow
bool programStopped;
int outputIndex;
Assembler *assembler;
+ bool debuggerWasStarted;
+ QString debugKey;
//highlighters
Highlighter *highlighter;
@@ -191,6 +194,7 @@ class MainWindow : public QMainWindow
QString backupMode;
QString backupAssemblerOptions;
QString backupLinkerOptions;
+ QString backupAssemblerPath;
QString backupStartText;
//about close
@@ -224,7 +228,6 @@ public slots:
//debug
void debug();
- void debugContinue();
void enableDebugActions();
void disableDebugActions(bool start = false);
void debugNext();
@@ -242,6 +245,7 @@ public slots:
void closeAnyCommandWidget();
void printOutput(QString msg, int index = -1);
void getOutput();
+ void changeDebugActionToStart();
//search
void find();
diff --git a/nasm.cpp b/nasm.cpp
index a0ebae38..550efc60 100644
--- a/nasm.cpp
+++ b/nasm.cpp
@@ -54,10 +54,12 @@ QString NASM::getAssemblerPath()
#endif
}
-quint64 NASM::getMainOffset(QFile &lst)
+quint64 NASM::getMainOffset(QFile &lst, QString entryLabel)
{
+ if (entryLabel == "start")
+ return 0;
QTextStream lstStream(&lst);
- QRegExp mainLabel("CMAIN:|main:");
+ QRegExp mainLabel(entryLabel + ":");
bool flag = false;
while (!lstStream.atEnd()) {
QString line = lstStream.readLine();
@@ -67,7 +69,8 @@ quint64 NASM::getMainOffset(QFile &lst)
//omit this string
continue;
}
- char *s = line.toLocal8Bit().data();
+ QByteArray lineArr = line.toLocal8Bit();
+ const char *s = lineArr.constData();
quint64 a, b, c;
if (sscanf(s, "%llu %llx %llx", &a, &b, &c) == 3) {
if (!(b == 0 && c == 0)) { //exclude 0 0
@@ -83,16 +86,26 @@ quint64 NASM::getMainOffset(QFile &lst)
}
void NASM::parseLstFile(QFile &lst, QVector &lines, bool ioIncIncluded, quint64 ioIncSize, quint64 offset)
+{
+ if (!parseStringsInLstFile(lst, lines, ioIncIncluded, ioIncSize, offset, true))
+ parseStringsInLstFile(lst, lines, ioIncIncluded, ioIncSize, offset, false);
+}
+
+bool NASM::parseStringsInLstFile(QFile &lst, QVector &lines,
+ bool ioIncIncluded, quint64 ioIncSize, quint64 offset, bool considerTextSection)
{
bool inTextSection = false;
QRegExp sectionTextRegExp("[Ss][Ee][Cc][Tt][Ii][Oo][Nn]\\s+\\.text");
QRegExp sectionRegExp("[Ss][Ee][Cc][Tt][Ii][Oo][Nn]");
quint64 omitLinesCount = 0; //for skipping strings from section .data - for processLst()
QTextStream lstStream(&lst);
+ bool hasTextSection = false;
+ lstStream.seek(0);
while (!lstStream.atEnd()) {
QString line = lstStream.readLine();
if (line.indexOf(sectionTextRegExp) != -1) {
inTextSection = true;
+ hasTextSection = true;
} else if (line.indexOf(sectionRegExp) != -1) {
inTextSection = false;
}
@@ -102,8 +115,9 @@ void NASM::parseLstFile(QFile &lst, QVector &lines, bool ioI
omitLinesCount++;
continue;
}
- if (inTextSection) {
- char *s = line.toLocal8Bit().data();
+ if (inTextSection || !considerTextSection) {
+ QByteArray lineArr = line.toLocal8Bit();
+ const char *s = lineArr.constData();
quint64 a, b, c;
if (sscanf(s, "%llu %llx %llx", &a, &b, &c) == 3) {
if (!(b == 0 && c == 0)) { //exclude 0 0
@@ -118,6 +132,7 @@ void NASM::parseLstFile(QFile &lst, QVector &lines, bool ioI
}
}
}
+ return hasTextSection;
}
QString NASM::getStartText()
diff --git a/nasm.h b/nasm.h
index 22c29bde..788afa35 100644
--- a/nasm.h
+++ b/nasm.h
@@ -49,8 +49,9 @@ class NASM : public Assembler
public:
explicit NASM(bool x86, QObject *parent = 0);
QString getAssemblerPath();
- quint64 getMainOffset(QFile &lst);
+ quint64 getMainOffset(QFile &lst, QString entryLabel);
void parseLstFile(QFile &lst, QVector &lines, bool ioIncIncluded, quint64 ioIncSize, quint64 offset);
+ bool parseStringsInLstFile(QFile &lst, QVector &lines, bool ioIncIncluded, quint64 ioIncSize, quint64 offset, bool considerTextSection);
void fillHighligherRules(QVector &highlightingRules,
QList &formats,
bool &multiLineComments,
diff --git a/settings.ui b/settings.ui
index 8db64370..2e16e5e7 100644
--- a/settings.ui
+++ b/settings.ui
@@ -1911,6 +1911,26 @@
-
+ -
+
+
+ Assembler path:
+
+
+
+ -
+
+
+ Linker path:
+
+
+
+ -
+
+
+ -
+
+
diff --git a/signallocker.cpp b/signallocker.cpp
new file mode 100644
index 00000000..f067f11d
--- /dev/null
+++ b/signallocker.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+** SASM - simple IDE for NASM development
+** Copyright (C) 2013 Dmitriy Manushin
+** Contact: site: http://dman95.github.io/SASM/
+** e-mail: Dman1095@gmail.com
+**
+** This file is part of SASM.
+**
+** SASM is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** SASM is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with SASM. If not, see .
+**
+** Этот файл — часть SASM.
+**
+** SASM - свободная программа: вы можете перераспространять ее и/или
+** изменять ее на условиях Стандартной общественной лицензии GNU в том виде,
+** в каком она была опубликована Фондом свободного программного обеспечения;
+** либо версии 3 лицензии, либо (по вашему выбору) любой более поздней
+** версии.
+**
+** SASM распространяется в надежде, что она будет полезной,
+** но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
+** или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
+** общественной лицензии GNU.
+**
+** Вы должны были получить копию Стандартной общественной лицензии GNU
+** вместе с этой программой. Если это не так, см.
+** .)
+**
+****************************************************************************/
+
+#include "signallocker.h"
+
+SignalLocker::SignalLocker(QObject *parent) :
+ QObject(parent)
+{
+ locked = false;
+}
+
+bool SignalLocker::tryLock()
+{
+ if (locked)
+ return false;
+ lock();
+ return true;
+}
+
+void SignalLocker::lock()
+{
+ locked = true;
+}
+
+void SignalLocker::unlock()
+{
+ locked = false;
+}
diff --git a/signallocker.h b/signallocker.h
new file mode 100644
index 00000000..482963a3
--- /dev/null
+++ b/signallocker.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+** SASM - simple IDE for NASM development
+** Copyright (C) 2013 Dmitriy Manushin
+** Contact: site: http://dman95.github.io/SASM/
+** e-mail: Dman1095@gmail.com
+**
+** This file is part of SASM.
+**
+** SASM is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** SASM is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with SASM. If not, see .
+**
+** Этот файл — часть SASM.
+**
+** SASM - свободная программа: вы можете перераспространять ее и/или
+** изменять ее на условиях Стандартной общественной лицензии GNU в том виде,
+** в каком она была опубликована Фондом свободного программного обеспечения;
+** либо версии 3 лицензии, либо (по вашему выбору) любой более поздней
+** версии.
+**
+** SASM распространяется в надежде, что она будет полезной,
+** но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
+** или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
+** общественной лицензии GNU.
+**
+** Вы должны были получить копию Стандартной общественной лицензии GNU
+** вместе с этой программой. Если это не так, см.
+** .)
+**
+****************************************************************************/
+
+#ifndef SIGNALLOCKER_H
+#define SIGNALLOCKER_H
+
+#include
+
+class SignalLocker : public QObject
+{
+ Q_OBJECT
+ bool locked;
+public:
+ explicit SignalLocker(QObject *parent = 0);
+
+signals:
+
+public slots:
+ void unlock();
+ bool tryLock();
+ void lock();
+
+};
+
+#endif // SIGNALLOCKER_H