diff --git a/.gitignore b/.gitignore index bcf4163d..5dd94c60 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,8 @@ Thumbs.db doc/* .qmake.stash sasm.app +ui_settings.h + +*.swp +*.o +sasm diff --git a/Linux/share/sasm/NASM/macro.c b/Linux/share/sasm/NASM/macro.c index d73ccf78..c01a4132 100644 --- a/Linux/share/sasm/NASM/macro.c +++ b/Linux/share/sasm/NASM/macro.c @@ -1,5 +1,104 @@ #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SEM_PRODUCER_FNAME "/myproducer" +#define SEM_CONSUMER_FNAME "/myconsumer" +#define BLOCK_SIZE 3145728 +#define FILENAME "/tmp" + FILE *get_stdin(void) { return stdin; } FILE *get_stdout(void) { return stdout; } void sasm_replace_stdin(void) {dup2(open("input.txt",0),0);} + +int sem_consumer_id, sem_producer_id; +int display_size; +char is_setup = 0; +int shared_block_id; +char* shm_block; + +void setup(int res_x, int res_y, char mode, char fps){ + if(is_setup){ + printf("already setup -> dont call twice\n"); + fflush(stdin); + exit(-1); + } + is_setup = 1; + + if(res_x < 100 || res_x > 1024 || res_y < 100 || res_y > 1024 || fps > 30 || fps < 1){ + printf("sem_prod failed\n"); + fflush(stdin); + exit(-1); + } + + struct sembuf sb = {0, -1, 0}; + sem_producer_id = semget(ftok(FILENAME, 'p'), 1, 0); + if(sem_producer_id == -1){ + printf("sem_prod failed(%ld)(%ld)\n", ftok(FILENAME, 'p'), errno); + exit(-1); + } + sem_consumer_id = semget(ftok(FILENAME, 'c'), 1, 0); + if(sem_consumer_id == -1){ + printf("sem_consumer failed\n"); + exit(-1); + } + if (semop(sem_consumer_id, &sb, 1) == -1){ //sem_wait(sem_consumer); + perror("semop"); + exit(1); + } + display_size = (mode) ? res_x*res_y*3 : res_x*res_y; + + key_t key = ftok(FILENAME, 'f'); + if(key < 0){ + exit(-1); + } + shared_block_id = shmget(key, BLOCK_SIZE, 0666 | IPC_CREAT); + if(shared_block_id == -1){ + exit(-1); + } + shm_block = shmat(shared_block_id, NULL, 0); + if(shm_block==(char*)-1){ + exit(-1); + } + for(int i = 0; i < 4; i++){ + shm_block[i] = (res_x >> (8*i)) & 0xff; + shm_block[i+4] = (res_y >> (8*i)) & 0xff; + } + shm_block[8] = mode; + shm_block[9] = fps; + sb.sem_op = 1; /* free resource sem_post(sem_producer); */ + if (semop(sem_producer_id, &sb, 1) == -1) { + perror("semop"); + exit(1); + } +} + +void update(char* data){ + if(!is_setup){ + printf("please call setup before update"); + fflush(stdin); + exit(-1); + } + struct sembuf sb = {0, -1, 0}; + if(semop(sem_consumer_id, &sb, 1) == -1){ //sem_wait(sem_consumer); + perror("semop"); + exit(1); + } + memcpy(shm_block, data, display_size); + sb.sem_op = 1; /* free resource sem_post(sem_producer); */ + if (semop(sem_producer_id, &sb, 1) == -1) { + perror("semop"); + exit(1); + } +} + +void sleepFunc(){usleep(10000000);} diff --git a/Linux/share/sasm/Projects/NASMHello.asm b/Linux/share/sasm/Projects/NASMHello.asm index 370ad00e..9ea516d1 100644 --- a/Linux/share/sasm/Projects/NASMHello.asm +++ b/Linux/share/sasm/Projects/NASMHello.asm @@ -6,8 +6,7 @@ section .data section .text global CMAIN CMAIN: - mov ebp, esp + mov ebp, esp; for correct debugging PRINT_STRING msg NEWLINE - xor eax, eax ret \ No newline at end of file diff --git a/Linux/share/sasm/Projects/NASMHellox64.asm b/Linux/share/sasm/Projects/NASMHellox64.asm index 4aafacad..8bda95de 100644 --- a/Linux/share/sasm/Projects/NASMHellox64.asm +++ b/Linux/share/sasm/Projects/NASMHellox64.asm @@ -8,6 +8,5 @@ section .text CMAIN: mov rbp, rsp PRINT_STRING msg - NEWLINE xor rax, rax ret \ No newline at end of file diff --git a/Linux/share/sasm/Projects/display_animation32.asm b/Linux/share/sasm/Projects/display_animation32.asm new file mode 100644 index 00000000..68bc05b0 --- /dev/null +++ b/Linux/share/sasm/Projects/display_animation32.asm @@ -0,0 +1,251 @@ +%include "io.inc" + +section .data + displayArray: times 262144 db 0xff + +section .text +global CMAIN +CMAIN: + mov ebp, esp + ;eax = min 1 | ebx = max 510 + setupDisplay 512, 512, 0, 30 + call quadrat + call quadrat + ret + +quadrat: + mov eax, 1 + mov ebx, 510 + mov ecx, 125 + mov edx, 385 + + andi: + call clearDisplay + + cmp eax, 205 + jl erstesq + mov eax, 1 + mov ebx, 510 + + erstesq: + + push eax + push eax + push ebx + push eax + call bresenham + add esp, 16 + + push eax + push eax + push eax + push ebx + call bresenham + add esp, 16 + + push eax + push ebx + push ebx + push ebx + call bresenham + add esp, 16 + + push ebx + push eax + push ebx + push ebx + call bresenham + add esp, 16 + + ;;;; + cmp ecx, 205 + jl zweitesq + mov ecx, 1 + mov edx, 510 + + zweitesq: + + push ecx + push ecx + push edx + push ecx + call bresenham + add esp, 16 + + push ecx + push ecx + push ecx + push edx + call bresenham + add esp, 16 + + push ecx + push edx + push edx + push edx + call bresenham + add esp, 16 + + push edx + push ecx + push edx + push edx + call bresenham + add esp, 16 + ;;;; + + inc eax + dec ebx + inc ecx + dec edx + + + updateDisplay displayArray + jmp andi + ret + +bresenham: +;Parameter: esp-24: y-ende | esp-48: x-ende | esp-56: y-anfang | esp-64: x-anfang --> 24, 28, 32, 36 -> : esp+0 +;eax = dx, ebx = dy, ecx = x, edx = y, edi = fehler, esp+0 singedflag for add +;--- +;swap points if xstart > xend + push eax + push ebx + push ecx + push edx + push 1 ;r8 ersatz + mov eax, [esp+28] + mov ebx, [esp+36] + cmp eax, ebx + jge noswap + mov [esp+36], eax + mov [esp+28], ebx + mov eax, [esp+24] + mov ebx, [esp+32] + mov [esp+32], eax + mov [esp+24], ebx +noswap: +;--- +;REM Initialisierungen +; dx*2; dy*2 +; x = xstart +; y = ystart +; SETPIXEL x,y +; fehler = dx +;--- + ;Initialisierungen + ;mov r8, 1 + mov eax, [esp+28] ;anpassen + mov ebx, [esp+24] + sub eax, [esp+36] + sub ebx, [esp+32] + mov edi, [esp+36] + mov esi, [esp+32] + call setPixel + mov ecx, [esp+36] + mov edx, [esp+32] + shl eax, 1 + shl ebx, 1 + cmp ebx, 0 + jge skip + mov edi, ebx + mov esi, 0 + call absvalue + mov ebx, edi + push eax + mov eax, -1 + mov [esp+4], eax + pop eax + skip: + mov edi, ebx + mov esi, 0 + call absvalue + cmp edi, eax + jg teil2 +;----teil1---- + mov edi, eax + loop: cmp [esp+28], ecx + jle end + inc ecx + sub edi, ebx + cmp edi, 0 + jge if + add edx, [esp] + add edi, eax + if: push edi + mov edi, ecx + mov esi, edx + call setPixel + pop edi + jmp loop + teil2: ;------- + mov edi, ebx + loop2: cmp [esp+24], edx + jle end + add edx, [esp] + sub edi, eax + cmp edi, 0 + jge if2 + inc ecx + add edi, ebx + if2: push edi + mov edi, ecx + mov esi, edx + call setPixel + pop edi + jmp loop2 + + end: + mov edi, [esp+24] + mov esi, [esp+28] + call setPixel + pop edx + pop edx + pop ecx + pop ebx + pop eax + ret + +setPixel: + ;x in edi und y in esi + push eax + push ebx + push edx + mov eax, 512 + mov ebx, esi + mul ebx + add eax, edi ;eax = y*128 + x --> current index + mov bl, 0x00 + mov [displayArray+eax], bl + pop edx + pop ebx + pop eax + ret + +absvalue: + ;first parameter in rdi second in rsi -> erg in rdi + cmp edi, esi + jl signjump + sub edi, esi + ret + signjump: + sub esi,edi + mov edi, esi + ret + +clearDisplay: + ;clears displayarray + push eax + push ebx + xor eax, eax + clearDisplayloop: + mov ebx, 0xffffffff + mov [displayArray+eax], ebx + add eax, 4 + cmp eax, 262144 + jl clearDisplayloop + pop ebx + pop eax + ret + +;fehler: wenn gerade nach unten \ No newline at end of file diff --git a/Linux/share/sasm/Projects/display_animation64.asm b/Linux/share/sasm/Projects/display_animation64.asm new file mode 100644 index 00000000..e57edc0c --- /dev/null +++ b/Linux/share/sasm/Projects/display_animation64.asm @@ -0,0 +1,244 @@ +%include "io64.inc" + +section .data + displayArray: times 262144 db 0xff + +section .text +global CMAIN +CMAIN: + mov rbp, rsp; for correct debugging + ;rax = min 1 | rbx = max 510 + setupDisplay 512, 512, 0, 30 + call quadrat + call quadrat + ret + +quadrat: + mov rax, 1 + mov rbx, 510 + mov rcx, 125 + mov rdx, 385 + + andi: + call clearDisplay + + cmp rax, 205 + jl erstesq + mov rax, 1 + mov rbx, 510 + + erstesq: + + push rax + push rax + push rbx + push rax + call bresenham + add rsp, 32 + + push rax + push rax + push rax + push rbx + call bresenham + add rsp, 32 + + push rax + push rbx + push rbx + push rbx + call bresenham + add rsp, 32 + + push rbx + push rax + push rbx + push rbx + call bresenham + add rsp, 32 + + ;;;; + cmp rcx, 205 + jl zweitesq + mov rcx, 1 + mov rdx, 510 + + zweitesq: + + push rcx + push rcx + push rdx + push rcx + call bresenham + add rsp, 32 + + push rcx + push rcx + push rcx + push rdx + call bresenham + add rsp, 32 + + push rcx + push rdx + push rdx + push rdx + call bresenham + add rsp, 32 + + push rdx + push rcx + push rdx + push rdx + call bresenham + add rsp, 32 + ;;;; + + inc rax + dec rbx + inc rcx + dec rdx + + + updateDisplay displayArray + jmp andi + ret + +bresenham: +;Parameter: esp-24: y-ende | esp-32: x-ende | esp-40: y-anfang | esp-48: x-anfang +;rax = dx, rbx = dy, rcx = x, rdx = y, rdi = fehler, r8 singedflag for add, r9 for tmp +;--- +;swap points if xstart > xend + push rax + push rbx + push rcx + push rdx + mov rax, [rsp+48] + mov rbx, [rsp+64] + cmp rax, rbx + jge noswap + mov [rsp+64], rax + mov [rsp+48], rbx + mov rax, [rsp+40] + mov rbx, [rsp+56] + mov [rsp+56], rax + mov [rsp+40], rbx +noswap: +;--- +;REM Initialisierungen +; dx*2; dy*2 +; x = xstart +; y = ystart +; SETPIXEL x,y +; fehler = dx +;--- + ;Initialisierungen + mov r8, 1 + mov rax, [rsp+48] ;anpassen + mov rbx, [rsp+40] + sub rax, [rsp+64] + sub rbx, [rsp+56] + mov rdi, [rsp+64] + mov rsi, [rsp+56] + call setPixel + mov rcx, [rsp+64] + mov rdx, [rsp+56] + shl rax, 1 + shl rbx, 1 + cmp rbx, 0 + jge skip + mov rdi, rbx + mov rsi, 0 + call absvalue + mov rbx, rdi + mov r8, -1 + skip: + mov rdi, rbx + mov rsi, 0 + call absvalue + cmp rdi, rax + jg teil2 +;----teil1---- + mov rdi, rax + loop: cmp [rsp+48], rcx + jle end + inc rcx + sub rdi, rbx + cmp rdi, 0 + jge if + add rdx, r8 + add rdi, rax + if: push rdi + mov rdi, rcx + mov rsi, rdx + call setPixel + pop rdi + jmp loop + teil2: ;------- + mov rdi, rbx + loop2: cmp [rsp+40], rdx + jle end + add rdx, r8 + sub rdi, rax + cmp rdi, 0 + jge if2 + inc rcx + add rdi, rbx + if2: push rdi + mov rdi, rcx + mov rsi, rdx + call setPixel + pop rdi + jmp loop2 + + end: + mov rdi, [rsp+40] + mov rsi, [rsp+48] + call setPixel + pop rdx + pop rcx + pop rbx + pop rax + ret + +setPixel: + ;x in rdi und y in rsi + push rax + push rbx + push rdx + mov rax, 512 + mov rbx, rsi + mul rbx + add rax, rdi ;rax = y*128 + x --> current index + mov bl, 0x00 + mov [displayArray+rax], bl + pop rdx + pop rbx + pop rax + ret + +absvalue: + ;first parameter in rdi second in rsi -> erg in rdi + cmp rdi, rsi + jl signjump + sub rdi, rsi + ret + signjump: + sub rsi,rdi + mov rdi, rsi + ret + +clearDisplay: + ;clears displayarray + push rax + push rbx + xor rax, rax + clearDisplayloop: + mov rbx, 0xffffffffffffffff + mov [displayArray+rax], rbx + add rax, 8 + cmp rax, 262144 + jl clearDisplayloop + pop rbx + pop rax + ret \ No newline at end of file diff --git a/Linux/share/sasm/Projects/stack_example32.asm b/Linux/share/sasm/Projects/stack_example32.asm new file mode 100644 index 00000000..dde44815 --- /dev/null +++ b/Linux/share/sasm/Projects/stack_example32.asm @@ -0,0 +1,17 @@ +%include "io.inc" + +section .text +global CMAIN +CMAIN: + mov ebp, esp; for correct debugging + mov eax, 0xffff1111 + push eax + push 0 + call example_function + pop ax + pop ax + pop eax + ret + +example_function: + ret diff --git a/Linux/share/sasm/include/io.inc b/Linux/share/sasm/include/io.inc index 1d18e5b7..7e398c56 100644 --- a/Linux/share/sasm/include/io.inc +++ b/Linux/share/sasm/include/io.inc @@ -43,6 +43,49 @@ CEXTERN fflush CEXTERN get_stdin CEXTERN get_stdout +CEXTERN update +%macro updateDisplay 1.nolist + sasmMacroFunc + push eax + push ecx + push edx + push esi + push edi + ALIGN_STACK 4 + push %1 + call update + UNALIGN_STACK + pop edi + pop esi + pop edx + pop ecx + pop eax + sasmMacroFuncE +%endmacro + +CEXTERN setup +%macro setupDisplay 4.nolist + sasmMacroFunc + push eax + push ecx + push edx + push esi + push edi + ALIGN_STACK 16 + push %4 + push %3 + push %2 + push %1 + call setup + UNALIGN_STACK + pop edi + pop esi + pop edx + pop ecx + pop eax + sasmMacroFuncE +%endmacro + ; Make stack be 16 bytes aligned after pushing %1 bytes %macro ALIGN_STACK 1.nolist enter 0, 0 diff --git a/Linux/share/sasm/include/io64.inc b/Linux/share/sasm/include/io64.inc index a65814a8..32b83194 100644 --- a/Linux/share/sasm/include/io64.inc +++ b/Linux/share/sasm/include/io64.inc @@ -40,10 +40,102 @@ CEXTERN fgets CEXTERN puts CEXTERN fputs CEXTERN fflush +CEXTERN sleepFunc CEXTERN get_stdin CEXTERN get_stdout +%macro sleepFunc 0.nolist + sasmMacroFunc + pushfq + push rax + push rcx + push rdx + push r8 + push r9 + push r10 + push r11 + push rsi + push rdi + ALIGN_STACK + call sleepFunc + UNALIGN_STACK + pop rdi + pop rsi + pop r11 + pop r10 + pop r9 + pop r8 + pop rdx + pop rcx + pop rax + popfq + sasmMacroFuncE +%endmacro + +CEXTERN update +%macro updateDisplay 1.nolist + sasmMacroFunc + pushfq + push rax + push rcx + push rdx + push r8 + push r9 + push r10 + push r11 + push rsi + push rdi + mov rdi, %1 + ALIGN_STACK + call update + UNALIGN_STACK + pop rdi + pop rsi + pop r11 + pop r10 + pop r9 + pop r8 + pop rdx + pop rcx + pop rax + popfq + sasmMacroFuncE +%endmacro + +CEXTERN setup +%macro setupDisplay 4.nolist + sasmMacroFunc + pushfq + push rax + push rcx + push rdx + push r8 + push r9 + push r10 + push r11 + push rsi + push rdi + mov rdi, %1 + mov rsi, %2 + mov rdx, %3 + mov rcx, %4 + ALIGN_STACK + call setup + UNALIGN_STACK + pop rdi + pop rsi + pop r11 + pop r10 + pop r9 + pop r8 + pop rdx + pop rcx + pop rax + popfq + sasmMacroFuncE +%endmacro + ; Make stack be 16 bytes aligned %macro ALIGN_STACK 0.nolist enter 0, 0 diff --git a/README.md b/README.md new file mode 100644 index 00000000..8da68b59 --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +SASM (SimpleASM) - простая кроссплатформенная среда разработки для языков ассемблера NASM, MASM, GAS, FASM с подсветкой синтаксиса и отладчиком. В SASM Вы можете легко разрабатывать и выполнять программы, написанные на языках ассемблера NASM, MASM, GAS, FASM. Вводите код в форму и запускайте приложение. Программа работает "из коробки" и хорошо подойдет для начинающих изучать язык ассемблера. +Основана на Qt. Распространяется по свободной лицензии GNU GPL v3.0. + +SASM (SimpleASM) - simple Open Source crossplatform IDE for NASM, MASM, GAS, FASM assembly languages. +SASM has syntax highlighting and debugger. The program works out of the box and is great for beginners to learn assembly language. SASM is translated into Russian, English, Turkish (thanks Ali Goren), Chinese (thanks Ahmed Zetao Yang), German (thanks Sebastian Fischer), Italian (thanks Carlo Dapor), Polish (thanks Krzysztof Rossa), Hebrew (thanks Elian Kamal), Spanish (thanks Mariano Cordoba). +Licensed under the GNU GPL v3.0. Based on the Qt. + + + +# How to build and run SASM: + + +## Linux + +### Software package dependencies + + * For assembly of SASM programs themselves: + * gcc (x86 OS) or gcc-multilib (x64 OS) + * gdb + * nasm + * Ubuntu 21.10: $ sudo apt install nasm gdb gcc gcc-multilib + + * For QT5 building (recommended): + * build-essential + * qtbase5-dev + * Ubuntu 21.10: $ sudo apt install build-essential qtbase5-dev + + * Compilation of SASM + * $ export QT_SELECT=5 (or 4 for Qt4) + * $ qmake + * OR $ qmake PREFIX= + * $ make -j + * Direct execution: + * run "./sasm" from folder right away + * Installation: + * $ make install + * Command "sasm" will open SASM + + + +## Windows: + + * For building: + * C++ compiler (e.g. gcc from MinGW) + * make (e.g. mingw32-make from MinGW) + * Qt 5 + + * For running: + * Everything needed is already included. + + * Instructions: + * Download sources and unpack source. + * Go to directory with their: "cd " + * 1) "qmake" + * 2) "mingw32-make" for Windows. + + * For Windows: + * Put "sasm.exe" executable file to folder "Windows". From this folder you can run the program. + * Also you can run program right away from SASM folder. + * If the program does not start after successful compilation and the error message (0xc000007b) appears, check that the path to GNU Compiler is set correctly in the environment variables. + + + + +# Prebuild packages + +Also you can download already compiled packages +from site https://dman95.github.io/SASM/ or +from OBS repository https://download.opensuse.org/repositories/home:/Dman95/ + +They might be outdated. + +More help info in file help.html +Also SASM supports doxygen: run "doxygen configfile" to generate documentation. In this documentation you can also find a small developer guide which includes information about adding new assemblers and languages support. + +Copyright © 2013 Dmitriy Manushin diff --git a/README.txt b/README.txt deleted file mode 100644 index d9981480..00000000 --- a/README.txt +++ /dev/null @@ -1,46 +0,0 @@ -SASM (SimpleASM) - простая кроссплатформенная среда разработки для языков ассемблера NASM, MASM, GAS, FASM с подсветкой синтаксиса и отладчиком. В SASM Вы можете легко разрабатывать и выполнять программы, написанные на языках ассемблера NASM, MASM, GAS, FASM. Вводите код в форму и запускайте приложение. Программа работает "из коробки" и хорошо подойдет для начинающих изучать язык ассемблера. -Основана на Qt. Распространяется по свободной лицензии GNU GPL v3.0. - -SASM (SimpleASM) - simple Open Source crossplatform IDE for NASM, MASM, GAS, FASM assembly languages. -SASM has syntax highlighting and debugger. The program works out of the box and is great for beginners to learn assembly language. SASM is translated into Russian, English, Turkish (thanks Ali Goren), Chinese (thanks Ahmed Zetao Yang), German (thanks Sebastian Fischer), Italian (thanks Carlo Dapor), Polish (thanks Krzysztof Rossa), Hebrew (thanks Elian Kamal), Spanish (thanks Mariano Cordoba). -Licensed under the GNU GPL v3.0. Based on the Qt. - -=========================================================================== -How to build and run SASM: -=========================================================================== -You need: -On Windows: -For building: - C++ compiler (e.g. gcc from MinGW) - make (e.g. mingw32-make from MinGW) - Qt 5 -For running: - Everything needed is included. - -On Linux: -For building: - build-essential - qtbase5-dev - qt5-default -For running: - gcc-multilib (x64 OS) or gcc (x86 OS) - gdb - nasm - -Download sources and unpack their. -Go to directory with their: "cd " -Further print commands: -1) "qmake" (For installing in specific directory on Linux - print: "qmake PREFIX=". By default SASM installs in "/usr/bin" and "usr/share") -2) "make" for Linux and "mingw32-make" for Windows. -3) For Linux: "make install" (command "sasm" will open SASM) or run "sasm" from folder right away or put "sasm" executable file to folder "Linux" (from this folder you can run the program). - For Windows: Put "sasm.exe" executable file to folder "Windows". From this folder you can run the program. Also you can run program right away from compilation folder. -=========================================================================== - -Also you can download already compiled packages -from site https://dman95.github.io/SASM/ or -from OBS repository https://download.opensuse.org/repositories/home:/Dman95/ - -More help info in file help.html -Also SASM supports doxygen: run "doxygen configfile" to generate documentation. In this documentation you can also find a small developer guide which includes information about adding new assemblers and languages support. - -Copyright © 2013 Dmitriy Manushin diff --git a/SASM.pro b/SASM.pro index 7aa7e044..349e925e 100644 --- a/SASM.pro +++ b/SASM.pro @@ -4,6 +4,7 @@ # #------------------------------------------------- + QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -47,6 +48,9 @@ INSTALLS += data INSTALLS += shortcutfiles INSTALLS += docfiles +LIBS += -pthread +QMAKE_CXXFLAGS += -pthread + include(singleapplication/qtsingleapplication.pri) SOURCES += main.cpp\ @@ -69,7 +73,10 @@ SOURCES += main.cpp\ fasm.cpp \ signallocker.cpp \ masm.cpp \ - gccbasedassembler.cpp + gccbasedassembler.cpp \ + stacksettingswidget.cpp \ + stackwidget.cpp \ + displayWindow.cpp HEADERS += mainwindow.h \ tab.h \ @@ -90,7 +97,10 @@ HEADERS += mainwindow.h \ fasm.h \ signallocker.h \ masm.h \ - gccbasedassembler.h + gccbasedassembler.h \ + stacksettingswidget.h \ + stackwidget.h \ + displayWindow.h FORMS += settings.ui diff --git a/Windows/NASM/macro.o b/Windows/NASM/macro.o index 6b143ba4..0f671732 100644 Binary files a/Windows/NASM/macro.o and b/Windows/NASM/macro.o differ diff --git a/Windows/NASM/macroWind.c b/Windows/NASM/macroWind.c new file mode 100644 index 00000000..70d785bc --- /dev/null +++ b/Windows/NASM/macroWind.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#define BLOCK_SIZE 3145728 + +FILE *get_stdin(void) { return stdin; } +FILE *get_stdout(void) { return stdout; } +void sasm_replace_stdin(void) {dup2(open("input.txt",0),0);} + +int display_size; +char is_setup = 0; +char output[BLOCK_SIZE]; +HANDLE hFile; + +void setup(int x, int y, char mode, char fps){ + if(is_setup){ + printf("already setup"); + exit(-1); + } + if(x < 100 || x > 1024 || y < 100 || y > 1024 || fps > 60 || fps < 1){ + printf("sem_prod failed\n"); + fflush(stdin); + exit(-1); + } + is_setup = 1; + for(int i = 0; i < 4; i++){ + output[i] = (x >> (8*i)) & 0xff; + output[i+4] = (y >> (8*i)) & 0xff; + } + output[8] = mode; + output[9] = fps; + + display_size = (mode) ? x*y*3 : x*y; + + hFile = CreateFileW( + L"\\\\.\\pipe\\SASMPIPE", + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if(hFile == NULL | hFile == INVALID_HANDLE_VALUE){ + printf("Could not create file object (%ld).\n", GetLastError()); + exit(-1); + } + + long dwNoBytesWrote; + BOOL writeSuccess = WriteFile( + hFile, + &output, + BLOCK_SIZE, + &dwNoBytesWrote, + NULL); + if(!FlushFileBuffers(hFile)){ + printf("Could not flush the file (%d).\n", GetLastError()); + exit(-1); + } +} + +void update(char* data){ + if(!is_setup){ + printf("please setup the display before this function!"); + exit(-1); + } + memcpy(&output, data, display_size); + long dwNoBytesWrote; + BOOL writeSuccess = WriteFile( + hFile, + &output, + BLOCK_SIZE, + &dwNoBytesWrote, + NULL); + if(!writeSuccess){ + printf("Could not write to file (%d).\n", GetLastError()); + } + if(!FlushFileBuffers(hFile)){ + printf("Could not flush the file (%d).\n", GetLastError()); + } + //CloseHandle(hFile); +} \ No newline at end of file diff --git a/Windows/Projects/stack_example32.asm b/Windows/Projects/stack_example32.asm new file mode 100644 index 00000000..0a48fd16 --- /dev/null +++ b/Windows/Projects/stack_example32.asm @@ -0,0 +1,17 @@ +%include "io.inc" + +section .text +global CMAIN +CMAIN: + mov ebp, esp; for correct debugging + mov eax, 0xffff1111 + push eax + push 0 + call example_function + pop ax + pop ax + pop eax + ret + +example_function: + ret \ No newline at end of file diff --git a/Windows/include/io.inc b/Windows/include/io.inc index 458d8540..cde32462 100644 --- a/Windows/include/io.inc +++ b/Windows/include/io.inc @@ -58,6 +58,42 @@ CEXTERN puts CEXTERN fputs CEXTERN fflush +CEXTERN update +%macro updateDisplay 1.nolist + sasmMacroFunc + push eax + push ecx + push edx + ALIGN_STACK 4 + push %1 + call update + UNALIGN_STACK + pop edx + pop ecx + pop eax + sasmMacroFuncE +%endmacro + +CEXTERN setup +%macro setupDisplay 4.nolist + sasmMacroFunc + push eax + push ecx + push edx + ALIGN_STACK 16 + push %4 + push %3 + push %2 + push %1 + call setup + UNALIGN_STACK + pop edx + pop ecx + pop eax + sasmMacroFuncE +%endmacro + + CEXTERN get_stdin CEXTERN get_stdout diff --git a/codeeditor.cpp b/codeeditor.cpp index db546c5c..f08864ba 100644 --- a/codeeditor.cpp +++ b/codeeditor.cpp @@ -48,7 +48,7 @@ CodeEditor::CodeEditor(QWidget *parent, bool withBeakpoints) : RuQPlainTextEdit(parent), debugImage(":/images/debugLine.png"), breakpointImage(":/images/breakpoint.png"), - settings("SASM Project", "SASM") + settings("SASM", "SASM") { hasBreakpoints = withBeakpoints; prevBlockCount = -1; @@ -77,7 +77,7 @@ int CodeEditor::lineNumberAreaWidth() ++digits; } - int space = fontMetrics().width(QLatin1Char('9')) * digits + debugAreaWidth; + int space = fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits + debugAreaWidth; return space; } diff --git a/common.cpp b/common.cpp index 8e4f6485..7df9260c 100644 --- a/common.cpp +++ b/common.cpp @@ -86,10 +86,18 @@ QString Common::pathInTemp(QString path) if (lastSymbol == QChar('/') || lastSymbol == QChar('\\')) { temp.chop(1); } - if (! QFile::exists(temp + "/SASM")) { - QDir().mkpath(temp + "/SASM"); + + // Generate temporary directory including username + QString name = qgetenv("USER"); + if (name.isEmpty()) + name = qgetenv("USERNAME"); + + QString tempPath = temp+"/SASM"+name; + + if (! QFile::exists(tempPath)) { + QDir().mkpath(tempPath); } - QString tempPath = temp + "/SASM"; + if (!path.isEmpty()) { tempPath += "/" + path; } diff --git a/debugger.cpp b/debugger.cpp old mode 100644 new mode 100755 index bdca20da..e0e4ed65 --- a/debugger.cpp +++ b/debugger.cpp @@ -52,28 +52,48 @@ namespace { bool readStruct(QTextStream& str, QMap* map); } - Debugger::Debugger(QTextEdit *tEdit, const QString &exePathParam, const QString &workingDirectoryPathParam, const QString &inputPathParam, Assembler *assembler, - QWidget *parent) + QWidget *parent, + bool i_verbose, + bool i_mimode) : QObject(parent) + { - QSettings settings("SASM Project", "SASM"); c = 0; pid = 0; + firstStack = true; firstAction = true; + firstRet = true; textEdit = tEdit; exePath = exePathParam; workingDirectoryPath = workingDirectoryPathParam; - inputPath = inputPathParam; + inputPath = inputPathParam; registersOk = true; this->assembler = assembler; + verbose = i_verbose; + mimode = i_mimode; + wincrflag = 0; + bitStack = 0; + systemStack = 16; + signStack = false; + run(); +} + +bool Debugger::run() +{ + QSettings settings("SASM", "SASM"); + if (settings.value("mode", QString("x86")).toString() == "x86") + addressSizeOffset = 4; + else + addressSizeOffset = 8; #ifdef Q_OS_WIN32 QString gdb; QString objdump; + wincrflag++; if (settings.value("mode", QString("x86")).toString() == "x86") { gdb = QCoreApplication::applicationDirPath() + "/MinGW/bin/gdb.exe"; objdump = QCoreApplication::applicationDirPath() + "/MinGW/bin/objdump.exe"; @@ -115,9 +135,14 @@ Debugger::Debugger(QTextEdit *tEdit, objdumpResult = objdumpResult.mid(index + startAddress.length()); entryPoint = objdumpResult.toLongLong(0, 16); - QStringList arguments; arguments << exePath; + + if (mimode) { + arguments << "--interpreter=mi"; + } + + printLog(tr("Starting Debugger: ")+gdb+" "+arguments.join(" ")+"\n", Qt::darkGreen); process = new QProcess; process->start(gdb, arguments); @@ -128,6 +153,27 @@ Debugger::Debugger(QTextEdit *tEdit, bufferTimer = new QTimer; QObject::connect(bufferTimer, SIGNAL(timeout()), this, SLOT(processOutput()), Qt::QueuedConnection); bufferTimer->start(10); + + process->waitForStarted(); + if (process->state() == QProcess::NotRunning) + { + // read output for debug information + readOutputToBuffer(); + + printLog(tr("Failed to start debugger!"), Qt::red); + if (buffer != "") + printLog(buffer, Qt::red); + + if (errorBuffer != "") + printLog(errorBuffer, Qt::red); + + delete process; + process = 0; + + return false; + } + + return true; } void Debugger::emitStarted() @@ -140,6 +186,7 @@ void Debugger::readOutputToBuffer() { if (!process) return; + QByteArray error = process->readAllStandardError(); errorBuffer += QString::fromLocal8Bit(error.constData(), error.size()); QByteArray output = process->readAllStandardOutput(); @@ -149,14 +196,25 @@ void Debugger::readOutputToBuffer() void Debugger::processOutput() { bufferTimer->stop(); + 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)") + if (verbose) + { + printLog(buffer+"\n", Qt::blue); + printLog(errorBuffer+"\n", Qt::blue); + } QString output = buffer.left(index); QString error = errorBuffer.left(linefeedIndex); - buffer.remove(0, index + 5); //remove processed message + buffer.remove(0, index + 5); + //remove processed message errorBuffer.remove(0, linefeedIndex + 1); - processMessage(output, error); + if(!mimode){ + processMessage(output, error); + }else{ + processMessageMiMode(output, error); + } } bufferTimer->start(10); } @@ -181,13 +239,25 @@ void Debugger::processMessage(QString output, QString error) Reading symbols from C:\Users\Dmitri\Dropbox\Projects\SASMstatic\release\Program\SASMprog.exe... done. (gdb)*/ + + #if 0 + // not required anymore, since GDB can be specified + if (output.indexOf(QString(") 8.1.")) != -1) { + actionTypeQueue.enqueue(anyAction); + processAction(tr("GDB 8.1 not supported due to buggy implementation (b main [newline] run not producing a break). Please use a different version.")); + QObject::disconnect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutputToBuffer())); + emit finished(); + return; + } + #endif + c++; doInput(QString("disas main\n"), none); return; } if (c == 1) { - if (error.indexOf("No symbol",0,Qt::CaseInsensitive)!=-1) { + if (error.indexOf("No symbol", 0, Qt::CaseInsensitive)!=-1) { dbgSymbols = false; } else { dbgSymbols = true; @@ -203,7 +273,8 @@ void Debugger::processMessage(QString output, QString error) End of assembler dump.*/ //skip this information (for gdb 8.0) c++; - run(); //perform Debugger::run(), that run program and open I/O files + + gdb_cmd_run(); //perform Debugger::run(), that run program and open I/O files return; } @@ -223,6 +294,7 @@ void Debugger::processMessage(QString output, QString error) c++; actionTypeQueue.enqueue(ni); doInput("info inferiors\n", none); + doInput(QString("p $sp\n"), infoStack); } //if an error with the wrong name of the section has occurred @@ -238,7 +310,7 @@ void Debugger::processMessage(QString output, QString error) offset = entryPoint; //changes in processLst() c++; processLst(); //count accordance - run(); //perform Debugger::run(), that run program and open I/O files + gdb_cmd_run(); //perform Debugger::run(), that run program and open I/O files return; } @@ -248,6 +320,7 @@ void Debugger::processMessage(QString output, QString error) c++; actionTypeQueue.enqueue(ni); doInput("info inferiors\n", none); + doInput(QString("p $sp\n"), infoStack); } } @@ -260,11 +333,28 @@ void Debugger::processMessage(QString output, QString error) if (output.indexOf(interruptSig) != -1) { stopped = true; emit wasStopped(); + QRegExp r = QRegExp("0x[0-9a-fA-F]{8,16}"); + int index = r.indexIn(output); + if(index != -1){ + quint64 lineNumber = output.mid(index, r.matchedLength()).toULongLong(0, 16); + 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) { + emit highlightLine(lineNumber); + } + } return; } if (!pid) { - QRegExp r("Num +Description +Executable"); + QRegExp r("Num +Description"); int index = output.indexOf(r); if (index != -1) { QString processString("process "); @@ -286,7 +376,9 @@ void Debugger::processMessage(QString output, QString error) void Debugger::processAction(QString output, QString error) { bool backtrace = (output.indexOf(QRegExp("#\\d+ 0x[0-9a-fA-F]{8,16} in .* ()")) != -1); - if (output.indexOf(exitMessage) != -1 && !backtrace) { + + if (output.indexOf(exitMessage) != -1 && !backtrace && firstRet) { + firstRet = false; doInput("c\n", none); return; } @@ -438,7 +530,7 @@ void Debugger::processAction(QString output, QString error) QTextStream registersStream(&output); QList registers; registersInfo info; - QSettings settings("SASM Project", "SASM"); + QSettings settings("SASM", "SASM"); QSet general; QString ip; @@ -478,6 +570,7 @@ void Debugger::processAction(QString output, QString error) registersStream.skipWhiteSpace(); info.decValue = registersStream.readLine(); } else if (mmx.exactMatch(info.name) || xmm.exactMatch(info.name) || ymm.exactMatch(info.name)) { + //TODO QMap fields; if (!readStruct(registersStream, &fields)) { @@ -512,6 +605,86 @@ void Debugger::processAction(QString output, QString error) emit printRegisters(registers); return; } + + if (actionType == infoStack) { + QTextStream stackStream(&output); + QList stacks; + QList stacks2; + QRegExp r = QRegExp("0x[0-9a-fA-F]{6,12}"); + int index; + if (firstStack){ + firstStack = false; + index = r.indexIn(output); + if(index != -1) + stackBottom = output.mid(index, r.matchedLength()).toULongLong(0, 16);// - addressSizeOffset; + return; + } + stackInfo info; + quint64 address; + quint64 value; + QString temporary_line; // TODO + for (int i = 0; !stackStream.atEnd(); i++) { + //info.value = stackStream.readLine(); + stackStream >> info.value; + index = info.value.indexOf(QString("Cannot access memory")); + if (index != -1){ + emit printLog(QString("Error showing stack"), Qt::red); + return; + } + index = r.indexIn(info.value); + address = info.value.mid(index, r.matchedLength()).toULongLong(0, 16); + if (index == -1 || address >= stackBottom) { + break; + } + + for(int j = 0; j < 2; j++){ + stackStream >> info.value; + index = r.indexIn(info.value); + value = info.value.mid(index, r.matchedLength()).toULongLong(0, 16); + stackStream >> info.value; + index = r.indexIn(info.value); + value += (info.value.mid(index, r.matchedLength()).toULongLong(0, 16)) << 32; + for(int k = 0; k < 8; k++){ //per line + if (address + k + j*8 >= stackBottom) { + goto exit; + } + stacks2.append((value >> 8*k)&0xff); + } + } + } + exit: + quint64 stackelem; + stackInfo bottom; + bottom.address = QString("0x") + QString::number(stackBottom, 16); + bottom.value = QString("Bottom"); + stacks.append(bottom); + for (int i = stacks2.size()-1; i >= 0; i-=bitStack){ + stackelem = stacks2[i]; + for (int j = 1; j < bitStack; j++){ + if (i-j<0){ + info.value = QString("(+") + QString::number(bitStack-j) + QString(" unused Byte) ") + QString::number(stackelem, systemStack); + info.address = QString("0x") + QString::number(stackBottom-bitStack-(stacks2.size()-1-i), 16); + stacks.append(info); + goto exit2; + } + stackelem = (stackelem << 8) + stacks2[i-j]; + } + if (signStack) + info.value = signedNumberStack(stackelem); + else + info.value = QString::number(stackelem, systemStack); + info.address = QString("0x") + QString::number(stackBottom-bitStack-(stacks2.size()-1-i), 16); + stacks.append(info); + } + exit2: + if(stacks.size()>=100){ + info.address = QString(""); + info.value = QString("..."); + stacks.append(info); + } + emit printStack(stacks); + return; + } if (output == QString("\r\n") || output == QString("\n") || output == QString("\r\n\n") || output == QString("\n\n")) //if empty @@ -521,6 +694,541 @@ void Debugger::processAction(QString output, QString error) emit printLog(output); } + +void Debugger::processMessageMiMode(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. + License GPLv3+: GNU GPL version 3 or later + This is free software: you are free to change and redistribute it. + There is NO WARRANTY, to the extent permitted by law. Type "show copying" + and "show warranty" for details. + + This GDB was configured as "i686-pc-mingw32". + For bug reporting instructions, please see: + ... + Reading symbols from C:\Users\Dmitri\Dropbox\Projects\SASMstatic\release\Program\SASMprog.exe... + + done. + (gdb)*/ + c++; + doInput(QString("disas main\n"), none); + return; + } + + if (c == 1) { + if (error.indexOf("No symbol", 0, Qt::CaseInsensitive)!=-1) { + dbgSymbols = false; + } else { + dbgSymbols = true; + } + } + + if (dbgSymbols) { //debug symbols exists + if (c == 1 && output != " ") { + /*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.*/ + //skip this information (for gdb 8.0) + c++; + + gdb_cmd_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("*stopped,reason=\"breakpoint-hit")) != -1) { + //set accordance between program in memory and program in file + //in example we need 0x00401390 + + //count offset + QRegExp r = QRegExp("addr=\"0x[0-9a-fA-F]{8,16}"); + int index = r.indexIn(output); + //take offset in hexadecimal representation (10 symbols) from string and convert it to int + offset = output.mid(index+6, r.matchedLength()-6).toULongLong(0, 16); + processLst(); //count accordance + + c++; + actionTypeQueue.enqueue(ni); + doInput("info inferiors\n", none); + doInput(QString("p $sp\n"), infoStack); + } + + //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); + processActionMiMode(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 = entryPoint; //changes in processLst() + c++; + processLst(); //count accordance + gdb_cmd_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("*stopped,reason=\"breakpoint-hit")) != -1) { + c++; + actionTypeQueue.enqueue(ni); + doInput("info inferiors\n", none); + doInput(QString("p $sp\n"), infoStack); + } + } + + //interrupt while debugging (program was stopped) + #ifdef Q_OS_WIN32 + QString interruptSig("SIGTRAP"); + #else + QString interruptSig("SIGINT"); + #endif + if (output.indexOf(interruptSig) != -1) { + stopped = true; + emit wasStopped(); + QRegExp r = QRegExp("addr=\"0x[0-9a-fA-F]{8,16}"); + int index = r.indexIn(output); + if(index != -1){ + quint64 lineNumber = output.mid(index+6, r.matchedLength()-6).toULongLong(0, 16); + 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) { + emit highlightLine(lineNumber); + } + } + return; + } + + if (!pid) { + QRegExp r("Num +Description"); + int index = output.indexOf(r); + if (index != -1) { + QString processString("process "); + r = QRegExp(processString + "[0-9]+"); + index = output.indexOf(r); + output = output.mid(index + processString.length()); + output = output.split(QChar(' ')).at(0); + pid = output.toULongLong(0, 10); + return; + } + } + + if (output.indexOf(QString("&\"p"))!=-1 && firstPrint){ + firstPrint = false; + return; + } + + //process all actions after start + if (c == 3) //if (output.indexOf(QString("$1 =")) == -1 && output.indexOf(QString("&\"si")) == -1 && output.indexOf(QString("&\"ni")) == -1 &&) //input file + if (output.indexOf(QRegExp("\\$1 =|&\"si|&\"ni|&\"c")) == -1 || output.indexOf(QString("&\"clear")) != -1) + processActionMiMode(output, error); +} + +void Debugger::processActionMiMode(QString output, QString error) +{ + bool backtrace = (output.indexOf(QRegExp("#\\d+ 0x[0-9a-fA-F]{8,16} in .* ()")) != -1); + + if (output.indexOf(exitMessage) != -1 && !backtrace) { + doInput("c\n", none); + return; + } + if (output.indexOf(QRegExp(cExitMessage)) != -1) { //if debug finished + //print output - message like bottom + /*...output...~"[Inferior 1 (process 7372) exited normally]\n" + =thread-exited,id="1",group-id="i1"\u000a=thread-group-exited,id="i1",exit-code="0" + *stopped,reason="exited-normally"\u000a"*/ + + QString msg = output.left(output.lastIndexOf(QChar('~'))); //program output + msg.remove(0,2); //rm first view whitespace + QRegExp threadMsg("=thread"); + while (threadMsg.indexIn(msg) != -1) + msg.remove(threadMsg.indexIn(msg), msg.indexOf(QChar('\n'), threadMsg.indexIn(msg) + 7)); + emit printOutput(msg); + + //exit from debugging + QObject::disconnect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutputToBuffer())); + emit finished(); + return; + } + if (actionTypeQueue.isEmpty()) { + return; + } + DebugActionType actionType = actionTypeQueue.dequeue(); + + if (actionType == breakpoint) + return; + + if(actionType == ni && firstAction){ + firstAction = false; + QRegExp r = QRegExp("addr=\"0x[0-9a-fA-F]{8,16}"); + int index = r.indexIn(output); + quint64 lineNumber = output.mid(index+6, r.matchedLength()-6).toULongLong(0, 16); + + 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(); + return; + } else { //if found highlight and print it + //highlight line number + emit highlightLine(lineNumber); + stopped = true; + emit wasStopped(); + 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("addr=\"0x[0-9a-fA-F]{8,16}"); + int index = r.indexIn(output); + int msgIndex = output.indexOf(QChar('~')); + //print output + if (msgIndex > 2+wincrflag) { + QString msg = output.left(msgIndex); //left part - probably output of program; + QRegExp asyncMsg("=thread|\\*running|\\*stopped|=library-|=traceframe-|=tsv-|=breakpoint|=record|=cmd-|=memory"); + QRegExp signalMsg("\r?\n(Program received signal.*)"); + while (asyncMsg.indexIn(msg) != -1){ + msg.remove(asyncMsg.indexIn(msg), msg.indexOf(QChar('\n'), asyncMsg.indexIn(msg) + 7)); + } + if (signalMsg.indexIn(msg) != -1) { + QString recievedSignal = signalMsg.cap(1); + if (QRegExp("SIG(TRAP|INT)").indexIn(recievedSignal) == -1) { + emit printLog(recievedSignal, Qt::red); + } + msg.remove(signalMsg); + } + msg.remove(0,2+wincrflag); //rm first view whitespace + emit printOutput(msg); + } + + quint64 lineNumber = output.mid(index+6, r.matchedLength()-6).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(); + } else { //if found highlight and print it + //highlight line number + emit highlightLine(lineNumber); + stopped = true; + emit wasStopped(); + } + return; + } + + if (actionType == anyAction) { + if (output[output.length() - 1] != '\n') + output += QChar('\n'); + //process as ni or si + if (output.indexOf(QString("*stopped,reason")) != -1 + && !backtrace) { + actionTypeQueue.enqueue(showLine); + processActionMiMode(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 { + QStringList tmpList; + bool firstElement = true; + for(QString t : output.split(QString("~\""))){ + if (t.isEmpty()){ + continue; + } + if (firstElement){ + firstElement = false; + continue; + } + tmpList.append(t.left(t.indexOf(QChar('\"')))); + } + output = tmpList.join(QString("")); + index = output.indexOf(QRegExp("\\$\\d+ = .*")); + output = output.right(output.length() - index); + output = output.right(output.length() - output.indexOf(QChar('=')) - 1); + output = output.left(output.indexOf(QString("\\n"))); + 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; + } + + if (actionType == infoRegisters) { + QTextStream registersStream(&output); + QList registers; + registersInfo info; + QSettings settings("SASM", "SASM"); + + QSet general; + QString ip; + QSet segment; + segment << "cs" << "ds" << "ss" << "es" << "fs" << "gs"; + QSet flags; + flags << "eflags" << "mxcsr"; + QSet fpu_info; + fpu_info << "fctrl" << "fstat" << "ftag" << "fiseg" << "fioff" << "foseg" << "fooff" << "fop"; + QRegExp mmx("mm\\d+"); + QRegExp xmm("xmm\\d+"); + QRegExp ymm("ymm\\d+"); + QRegExp fpu_stack("st\\d+"); + bool first = true; + + if (settings.value("mode", QString("x86")).toString() == "x86") { + //x86 + + general << "eax" << "ebx" << "ecx" << "edx" << "esi" << "edi" << "esp" << "ebp"; + ip = "eip"; + } else { + //x64 + general << "rax" << "rbx" << "rcx" << "rdx" << "rsi" << "rdi" << "rsp" << "rbp" << + "r8" << "r9" << "r10" << "r11" << "r12" << "r13" << "r14" << "r15"; + ip = "rip"; + } + + for (int i = 0; !registersStream.atEnd(); i++) { + registersStream >> info.name; + + if (info.name.isEmpty()) { + // last empty line + break; + } + + if (info.name.at(0) != QChar('~')||info.name.indexOf(QString("~\"\\n\""))!=-1) { + continue; + } + first = false; + info.name.remove(QString("~\"")); + + if (general.contains(info.name) || segment.contains(info.name) || fpu_info.contains(info.name) || + info.name == ip || flags.contains(info.name) || fpu_stack.exactMatch(info.name)) { + registersStream >> info.hexValue; + info.hexValue.remove(QRegExp("~|\"|\\\\n|\\\\t")); + registersStream.skipWhiteSpace(); + info.decValue = registersStream.readLine(); + info.decValue.remove(QRegExp("~|\"|\\\\n|\\\\t")); + } else if (mmx.exactMatch(info.name) || xmm.exactMatch(info.name) || ymm.exactMatch(info.name)) { + //TODO + QMap fields; + + if (!readStruct(registersStream, &fields)) { + // bad news + emit printLog(QString("can not parse register data: ") + info.name + "\n", Qt::red); + break; + } + + if (mmx.exactMatch(info.name)) + info.decValue = fields["v8_int8"]; + else if (xmm.exactMatch(info.name)) + info.decValue = fields["uint128"]; + else if (ymm.exactMatch(info.name)) + info.decValue = fields["v2_int128"]; + + info.hexValue = ""; + } else { + // unknown register, try to skip it. + registersStream.readLine(); + emit printLog(QString("unknown register: ") + info.name + "\n", Qt::red); + continue; + } + + registers.append(info); + if (first && info.name != "eax" && info.name != "rax" && registersOk) { + doInput(QString("info registers\n"), infoRegisters); + registersOk = false; + return; + } + } + + emit printRegisters(registers); + return; + } + + if (actionType == infoStack) { + QTextStream stackStream(&output); + QList stacks; + QList stacks2; + QRegExp r = QRegExp("0x[0-9a-fA-F]{6,12}"); + int index; + if (firstStack){ + firstStack = false; + index = r.indexIn(output); + if(index != -1) + stackBottom = output.mid(index, r.matchedLength()).toULongLong(0, 16);// - addressSizeOffset; + return; + } + stackInfo info; + quint64 address; + quint64 value; + QString temporary_line; // TODO + for (int i = 0; !stackStream.atEnd(); i++) { + // info.value = stackStream.readLine(); + stackStream >> info.value; + index = info.value.indexOf(QString("Cannot access memory")); + if (index != -1){ + emit printLog(QString("Error showing stack"), Qt::red); + return; + } + if (info.value.at(0) != QChar('~')||info.value.indexOf(QString("~\"\\n\"")) != -1) { + continue; + } + info.value.remove(QRegExp("~|\"|\\\\n")); + QList stackLine = info.value.split(QString("\\t")); + index = r.indexIn(info.value); + address = info.value.mid(index, r.matchedLength()).toULongLong(0, 16); + if (index == -1 || address >= stackBottom) { + break; + } + + for(int j = 0; j < 2; j++){ + info.value = stackLine[j*2+1]; + index = r.indexIn(info.value); + value = info.value.mid(index, r.matchedLength()).toULongLong(0, 16); + info.value = stackLine[j*2+2]; + index = r.indexIn(info.value); + value += (info.value.mid(index, r.matchedLength()).toULongLong(0, 16)) << 32; + for(int k = 0; k < 8; k++){ //per line + if (address + k + j*8 >= stackBottom) { + goto exit; + } + stacks2.append((value >> 8*k)&0xff); + } + } + } + exit: + quint64 stackelem; + stackInfo bottom; + bottom.address = QString("0x") + QString::number(stackBottom, 16); + bottom.value = QString("Bottom"); + stacks.append(bottom); + for (int i = stacks2.size()-1; i >= 0; i-=bitStack){ + stackelem = stacks2[i]; + for (int j = 1; j < bitStack; j++){ + if (i-j<0){ + info.value = QString("(+") + QString::number(bitStack-j) + QString(" unused Byte) ") + QString::number(stackelem, systemStack); + info.address = QString("0x") + QString::number(stackBottom-bitStack-(stacks2.size()-1-i), 16); + stacks.append(info); + goto exit2; + } + stackelem = (stackelem << 8) + stacks2[i-j]; + } + if (signStack) + info.value = signedNumberStack(stackelem); + else + info.value = QString::number(stackelem, systemStack); + info.address = QString("0x") + QString::number(stackBottom-bitStack-(stacks2.size()-1-i), 16); + stacks.append(info); + } + exit2: + if(stacks.size()>=100){ + info.address = QString(""); + info.value = QString("..."); + stacks.append(info); + } + emit printStack(stacks); + return; + } + + + if (output == QString("\r\n") || output == QString("\n") || + output == QString("\r\n\n") || output == QString("\n\n")||output.at(0)=='*') //if empty or starts with * + return; + + //print information to log field + emit printLog(output); +} + +// convert unsinged to signed and add - +QString Debugger::signedNumberStack(quint64 value) { + switch (bitStack) { + case 1: + if ((value&0x80) > 0) + return QString("-") + QString::number(((-1*((qint8)value))&0xff), systemStack); + break; + case 2: + if ((value&0x8000) > 0) + return QString("-") + QString::number(((-1*((qint16)value))&0xffff), systemStack); + break; + case 4: + if ((value&0x80000000) > 0) + return QString("-") + QString::number(((-1*((qint32)value))&0xffffffff), systemStack); + break; + case 8: + default: + if ((value&0x8000000000000000) > 0) + return QString("-") + QString::number((-1*((qint64)value)), systemStack); //falls mit führender Null: QStringLiteral("%1").arg((-1*((qint64)value)), 63, systemStack, QLatin1Char('0')); + break; + } + return QString::number(value, systemStack); +} + bool Debugger::isStopped() { return stopped; @@ -544,6 +1252,9 @@ void Debugger::pause() void Debugger::doInput(QString command, DebugActionType actionType) { + if (verbose) + printLog("CMD: "+command+"\n", Qt::darkYellow); + if (actionType != none) actionTypeQueue.enqueue(actionType); //put \n after commands! @@ -560,6 +1271,41 @@ void Debugger::setWatchesCount(int count) watchesCount = count; } +void Debugger::setBitStack(int bit){ + switch (bit) { + case 0: + bitStack = 1; + break; + case 1: + bitStack = 2; + break; + case 2: + bitStack = 4; + break; + case 3: + default: + bitStack = 8; + } +} + +void Debugger::setSystemStack(int system){ + switch (system) { + case 0: + systemStack = 16; + break; + case 1: + systemStack = 10; + break; + case 2: + default: + systemStack = 2; + } +} + +void Debugger::setSignStack(bool sign){ + signStack = sign; +} + void Debugger::processLst() { //set accordance with .lst file and program in memory @@ -599,7 +1345,7 @@ void Debugger::processLst() } } -void Debugger::run() +void Debugger::gdb_cmd_run() { //set breakpoint on main, run program amd open output and input files //put \n after commands! @@ -655,16 +1401,24 @@ void Debugger::changeBreakpoint(quint64 lineNumber, bool isAdded) Debugger::~Debugger() { emit highlightLine(-1); - if (process->state() == QProcess::Running) { - doInput("quit\n", none); - process->waitForFinished(1000); - if (process->state() == QProcess::Running) { //if still running + if (process) + { + if (process->state() == QProcess::Running) { doInput("quit\n", none); - process->terminate(); + process->waitForFinished(1000); + if (process->state() == QProcess::Running) { //if still running + doInput("quit\n", none); + process->terminate(); + } } } - delete process; - process = 0; + + if (process != 0) + { + delete process; + process = 0; + } + lines.clear(); delete bufferTimer; } diff --git a/debugger.h b/debugger.h index f3c62e3c..4c6f8bbc 100644 --- a/debugger.h +++ b/debugger.h @@ -68,7 +68,7 @@ * Defines the debugger. */ -enum DebugActionType {ni, si, showLine, infoRegisters, infoMemory, anyAction, none, breakpoint}; +enum DebugActionType {ni, si, showLine, infoRegisters, infoMemory, infoStack, anyAction, none, breakpoint}; /** @@ -82,11 +82,14 @@ class Debugger : public QObject public: Debugger(QTextEdit *tEdit, - const QString &exePathParam, - const QString &workingDirectoryPathParam, - const QString &inputPathParam, - Assembler *assembler, - QWidget *parent = 0); + const QString &path, + const QString &tmp, + const QString &inputPathParam, + Assembler *assembler, + QWidget *parent = 0, + bool verbose = true, + bool mimode = true); + ~Debugger(); void setWatchesCount(int count); @@ -101,14 +104,34 @@ class Debugger : public QObject bool isValid; }; + struct stackInfo { + QString value; + QString address; + }; + typedef Assembler::LineNum LineNum; bool isStopped(); void pause(); + //! Global gdb output buffer + QString buffer; + + //! Global gdb error buffer + QString errorBuffer; + + // start debugger + bool run(); + private: void processLst(); - void run(); + void gdb_cmd_run(); + + bool verbose; + bool mimode; + bool con; + bool firstPrint; + int wincrflag; QProcess *process; QTextEdit *textEdit; @@ -116,6 +139,7 @@ class Debugger : public QObject //! Offset between program code in memory and in file quint64 offset; + //! Accordance between program lines in memory and in file QVector lines; //! Counter for sequential performing of actions @@ -139,12 +163,6 @@ class Debugger : public QObject //! Path to temporary input.txt file QString inputPath; - //! Global gdb output buffer - QString buffer; - - //! Global gdb error buffer - QString errorBuffer; - //! Timer for checking output and sending ready output to processing with Debugger::processOutput() function QTimer *bufferTimer; @@ -165,17 +183,33 @@ class Debugger : public QObject bool stopped; quint64 pid; bool dbgSymbols; + bool firstStack; quint64 entryPoint; + + // save Stack + quint64 stackBottom; + int bitStack; + int systemStack; + bool signStack; + int addressSizeOffset; + + bool firstRet; public slots: void readOutputToBuffer(); void processOutput(); void processMessage(QString output, QString error); + void processMessageMiMode(QString output, QString error); void processAction(QString output, QString error = QString()); + void processActionMiMode(QString output, QString error = QString()); void doInput(QString command, DebugActionType actionType); void changeBreakpoint(quint64 lineNumber, bool isAdded); void emitStarted(); + void setBitStack(int bit); + void setSystemStack(int system); + void setSignStack(bool sign); + QString signedNumberStack(quint64 value); signals: //! Highlight the current debug line. @@ -184,6 +218,7 @@ public slots: //! Signal is emited when debugger is ready to get commands like step into and etc. void started(); void printRegisters(QList); + void printStack(QList); void printMemory(QList); void printLog(QString msg, QColor color = QColor(Qt::black)); void printOutput(QString msg); diff --git a/debugtablewidget.cpp b/debugtablewidget.cpp index 42cc8c2f..cc9ee713 100644 --- a/debugtablewidget.cpp +++ b/debugtablewidget.cpp @@ -49,6 +49,8 @@ QByteArray DebugTableWidget::memoryHeaderState; bool DebugTableWidget::geometryRegistersSaved; bool DebugTableWidget::geometryMemorySaved; QByteArray DebugTableWidget::registerWindowState; +bool DebugTableWidget::geometryStackSaved; +QByteArray DebugTableWidget::stackWindowState; DebugTableWidget::DebugTableWidget(int rows, int columns, DebugTableWidgetType widgetType, QWidget *parent) : QTableWidget(rows, columns, parent) @@ -78,6 +80,20 @@ DebugTableWidget::DebugTableWidget(int rows, int columns, DebugTableWidgetType w if (geometryRegistersSaved) restoreGeometry(registerWindowState); } + + if (type == stackTable) { + setSelectionMode(QAbstractItemView::NoSelection); + QStringList header; + header << "Address" << "Stack-top"; + setHorizontalHeaderLabels(header); + //setResizeMode(QHeaderView::ResizeToContents) + horizontalHeader()->setStretchLastSection(true); + setWindowTitle(tr("Stack")); + addStack(QString(" -- "), QString("Bottom")); + resizeColumnsToContents(); + if (geometryStackSaved) + restoreGeometry(stackWindowState); + } } void DebugTableWidget::initializeMemoryWindow(const QList &watches) @@ -111,6 +127,18 @@ void DebugTableWidget::setValuesFromDebugger(QList regi } } +void DebugTableWidget::setValuesFromDebugger(QList stacks) //the stack +{ + setRowCount(0); + for (int i = 0; i < stacks.size(); i++) + addStack(stacks[i].value, stacks[i].address); + show(); + if (firstTime) { + firstTime = false; + activateWindow(); + } +} + void DebugTableWidget::changeMemoryWindow(int row, int column) { disconnect(this, SIGNAL(cellChanged(int,int)), this, SLOT(changeMemoryWindow(int,int))); @@ -214,6 +242,27 @@ void DebugTableWidget::addRegister(const QString &name, const QString &hexValue, } } +void DebugTableWidget::addStack(const QString &hexValue, const QString &address) +{ + empty = false; + if (type == stackTable) { + QTableWidgetItem *hexValueItem = new QTableWidgetItem(hexValue); + QFont monoFont("Courier"); + monoFont.setStyleHint(QFont::Monospace); + hexValueItem->setTextAlignment(Qt::AlignCenter); + hexValueItem->setFont(monoFont); + hexValueItem->setFlags(Qt::ItemIsEnabled); + QTableWidgetItem *addressItem = new QTableWidgetItem(address); + addressItem->setTextAlignment(Qt::AlignCenter); + addressItem->setFont(monoFont); + addressItem->setFlags(Qt::ItemIsEnabled); + insertRow(0); + setItem(0, 1, hexValueItem); + setItem(0, 0, addressItem); + } + resizeColumnsToContents(); +} + bool DebugTableWidget::isEmpty() { return empty; @@ -263,4 +312,8 @@ DebugTableWidget::~DebugTableWidget() registerWindowState = saveGeometry(); geometryRegistersSaved = true; } + if (type == stackTable) { + stackWindowState = saveGeometry(); + geometryStackSaved = true; + } } diff --git a/debugtablewidget.h b/debugtablewidget.h index 0a042def..1bcc6cd0 100644 --- a/debugtablewidget.h +++ b/debugtablewidget.h @@ -10,6 +10,7 @@ #include #include "debugger.h" #include "watchsettingswidget.h" +#include "stacksettingswidget.h" #include "ruqplaintextedit.h" /** @@ -17,7 +18,7 @@ * Defines the debugging window (memory or registers table). */ -enum DebugTableWidgetType {registersTable, memoryTable}; +enum DebugTableWidgetType {registersTable, memoryTable, stackTable}; /** @@ -38,8 +39,10 @@ class DebugTableWidget : public QTableWidget void initializeMemoryWindow(const QList &watches); static QByteArray memoryHeaderState; static QByteArray registerWindowState; + static QByteArray stackWindowState; static bool geometryMemorySaved; static bool geometryRegistersSaved; + static bool geometryStackSaved; protected: void closeEvent(QCloseEvent *); @@ -56,9 +59,11 @@ public slots: void addVariable(const RuQPlainTextEdit::Watch &variable, int rowNumber = -1); void changeVariableValue(const QString &value, int rowNumber, bool isValid); void addRegister(const QString &name, const QString &hexValue, const QString &decValue, int rowNumber); + void addStack(const QString &hexValue, const QString &address); void changeMemoryWindow(int row, int column); void setValuesFromDebugger(QList watches); void setValuesFromDebugger(QList registers); + void setValuesFromDebugger(QList stacks); private: int contextMenuLineNumber; diff --git a/displayWindow.cpp b/displayWindow.cpp new file mode 100755 index 00000000..0f103c8e --- /dev/null +++ b/displayWindow.cpp @@ -0,0 +1,361 @@ +/**************************************************************************** +** SASM - simple IDE for assembler 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 "displayWindow.h" + +#define IPC_RESULT_ERROR (-1) +#define FILENAME "/tmp" + + +DisplayWindow::DisplayWindow(QWidget *parent) : + QWidget(parent) +{ + zoom = 1; + this->resize(QSize(512+50, 512+125)); + this->setStyleSheet("background-color:grey;"); + verticalLayout = new QVBoxLayout(this); + zoomComboBox = new QComboBox(this); + QStringList comboBoxList; + comboBoxList << "1" << "2" << "4" << "8" << "16" << "32"; + zoomComboBox->insertItems(0, comboBoxList); + connect(zoomComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(zoomSettingsChanged(int))); + + verticalLayout->addWidget(zoomComboBox); + + scrollArea = new QScrollArea(this); + scrollArea->setWidgetResizable(true); + scrollAreaWidgetContents = new BufferFrame(this); + + scrollArea->setWidget(scrollAreaWidgetContents); + + verticalLayout->addWidget(scrollArea); +} + +void DisplayWindow::changeDisplay(int msgid){ + loop = true; + zoomComboBox->setEnabled(false); + displayPicture = new QImage(512, 512, QImage::Format_RGB32); + displayPicture->fill(qRgb(255, 255, 255)); + memset(buffer, 0xff, 512*512); + scrollAreaWidgetContents->setFixedSize(512*zoom+26, 512*zoom+26); + this->msgid = msgid; + res_x = 512; + res_y = 512; + mode = 0; + qint64 fps = 30; + QElapsedTimer programExecutionTime; + QElapsedTimer programExecutionTime2; + this->resize(QSize(512+60, 512+92)); + scrollAreaWidgetContents->update(); + programExecutionTime.start(); + programExecutionTime2.start(); + #ifdef Q_OS_WIN32 + if(!ConnectNamedPipe(hCreateNamedPipe, NULL)){ + if(GetLastError()!=535) + emit printLog(QString("Connection Failed with Error (")+QString::number(GetLastError())+")\n", Qt::red); + } + + DWORD dwNoBytesRead; + BOOL readSuccess = ReadFile( + hCreateNamedPipe, + buffer, + BLOCK_SIZE, + &dwNoBytesRead, + NULL); + if(readSuccess && loop){ + res_x = buffer[0]; + res_y = buffer[4]; + for(int i = 1; i < 4; i++){ + res_x += buffer[i] << (8*i); + res_y += buffer[4+i] << (8*i); + } + mode = buffer[8]; + fps = buffer[9]; + display_size = (mode) ? res_x*res_y*3 : res_x*res_y; + displayPicture = new QImage(res_x, res_y, QImage::Format_RGB32); + displayPicture->fill(qRgb(255, 255, 255)); + this->resize(QSize(res_x+60, res_y+92)); + scrollAreaWidgetContents->setFixedSize(res_x*zoom, res_y*zoom); + scrollAreaWidgetContents->update(); + } else { + if(GetLastError()!=109&&GetLastError()!=0) + emit printLog(QString("Read Failed with Error (")+QString::number(GetLastError())+")\n", Qt::red); + loop = false; + } + + while(loop){ + DWORD dwNoBytesRead; + BOOL readSuccess = ReadFile( + hCreateNamedPipe, + buffer, + BLOCK_SIZE, + &dwNoBytesRead, + NULL); + if(!loop) + break; + if(!readSuccess){ + if(GetLastError()!=109) + emit printLog(QString("Read Failed with Error (")+QString::number(GetLastError())+")\n", Qt::red); + break; + } + // display the message and print on display + int currentcharx; + int currentchary; + int needed_pixel = (mode) ? res_x*res_y*3 : res_x*res_y; + if(mode){ + for(int l = 0; l < needed_pixel; l+=3) { + currentcharx = (l/3)%res_x; + currentchary = l/3/res_x; + displayPicture->setPixel(currentcharx, currentchary, qRgb(buffer[l], buffer[l+1], buffer[l+2])); + } + } else { + for(int l = 0; l < needed_pixel; l++){ + currentcharx = l%res_x; + currentchary = l/res_x; + if(buffer[l]){ + displayPicture->setPixel(currentcharx, currentchary, qRgb(255, 255, 255)); + } else { + displayPicture->setPixel(currentcharx, currentchary, qRgb(0, 0, 0)); + } + } + } + qint64 elapsed_time = programExecutionTime.elapsed(); + if(elapsed_time < 1000/fps) + usleep((1000/fps - elapsed_time)*1000); + programExecutionTime.start(); + scrollAreaWidgetContents->update(); + } + CloseHandle(hCreateNamedPipe); + #else + // wait sem_wait(sem_producer); + struct sembuf sb = {0, -1, 0}; + if (semop(sem_pro_id, &sb, 1) == -1 && loop){ + emit printLog(QString("sem_pro failed (semop)"+QString(strerror(errno))+"\n"), Qt::red); + } + + if(loop){ + //setup the shared memory + key_t key = ftok(FILENAME, 'f'); + if(key == IPC_RESULT_ERROR){} + shared_block_id = shmget(key, BLOCK_SIZE, 0666 | IPC_CREAT); + if(shared_block_id == IPC_RESULT_ERROR){ + emit printLog(QString("shmget failed\n"), Qt::red); + } + block_values = (uint8_t*)shmat(shared_block_id, NULL, 0); + if(block_values == (uint8_t*)IPC_RESULT_ERROR){ + emit printLog(QString("shmat failed\n"), Qt::red); + } + /// read setup + res_x = block_values[0]; + res_y = block_values[4]; + for(int i = 1; i < 4; i++){ + res_x += block_values[i] << (8*i); + res_y += block_values[4+i] << (8*i); + } + mode = block_values[8]; + fps = block_values[9]; + if(fps < 1 || fps > 60){ + emit printLog(QString("fps has wrong settings\n"), Qt::red); + fps = 1; + } + display_size = (mode) ? res_x*res_y*3 : res_x*res_y; + displayPicture = new QImage(res_x, res_y, QImage::Format_RGB32); + displayPicture->fill(qRgb(255, 255, 255)); + scrollAreaWidgetContents->setFixedSize(res_x*zoom+26, res_y*zoom+26); + this->resize(QSize(res_x+60, res_y+92)); + scrollAreaWidgetContents->update(); + // sem_post(sem_consumer); + sb.sem_op = 1; + if (semop(sem_con_id, &sb, 1) == -1) { + emit printLog(QString("1 sem_con failed (semop)\n"), Qt::red); + } + } + /// + + while(loop){ + // receive message + // sem_wait(sem_producer); + sb.sem_op = -1; + if (semop(sem_pro_id, &sb, 1) == -1 && loop) { + emit printLog(QString("sem_pro failed (semop)\n"), Qt::red); + } + if(!loop) + break; + // display the message and print on display + int currentcharx, currentchary; + if (mode){ + for(int l = 0; l < display_size; l+=3) { + currentcharx = (l/3)%res_x; + currentchary = l/3/res_x; + displayPicture->setPixel(currentcharx, currentchary, qRgb(block_values[l], block_values[l+1], block_values[l+2])); + } + } else { + for(int l = 0; l < display_size; l++){ + currentcharx = l%res_x; + currentchary = l/res_x; + if(block_values[l]){ + displayPicture->setPixel(currentcharx, currentchary, qRgb(255, 255, 255)); + } else { + displayPicture->setPixel(currentcharx, currentchary, qRgb(0, 0, 0)); + } + } + } + + + qint64 elapsed_time = programExecutionTime.elapsed(); + //emit printLog("time: "+QString::number(elapsed_time)+"\n"); + if(elapsed_time < 1000/fps) + usleep((1000/fps - elapsed_time)*1000); + programExecutionTime.start(); + scrollAreaWidgetContents->update(); + //sem_post(sem_consumer); + sb.sem_op = 1; + if (semop(sem_con_id, &sb, 1) == -1 && loop) { + emit printLog(QString("2 sem_con failed (semop)\n"), Qt::red); + } + } + //sem_close(sem_consumer); + //sem_close(sem_producer); + /*if(shmctl(shared_block_id, IPC_RMID, NULL) == IPC_RESULT_ERROR){ + //emit printLog(QString("shmctl failed\n"), Qt::red); + } + if (semctl(sem_pro_id, 0, IPC_RMID, arg) == -1){ + emit printLog(QString("sem_pro failed (close)\n"), Qt::red); + } + if (semctl(sem_con_id, 0, IPC_RMID, arg) == -1){ + emit printLog(QString("sem_con failed (close)\n"), Qt::red); + }*/ + #endif + loop = false; + zoomComboBox->setEnabled(true); + emit closeDisplay(); +} + +void DisplayWindow::finish(int msgid){ + this->msgid = msgid; + loop = false; + #ifdef Q_OS_WIN32 + HANDLE hFile = CreateFileW( + L"\\\\.\\pipe\\SASMPIPE", + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + if(hFile == INVALID_HANDLE_VALUE){ + emit printLog("Could not create file object ("+QString::number(GetLastError())+").\n", Qt::red); + } + DWORD dwNoBytesWrote; + BOOL writeSuccess = WriteFile( + hFile, + &buffer, + BLOCK_SIZE, + &dwNoBytesWrote, + NULL); + CloseHandle(hFile); + #else + if(loop){ + if(shmctl(shared_block_id, IPC_RMID, NULL) == IPC_RESULT_ERROR){ + emit printLog(QString("shmctl failed\n"), Qt::red); + } + } + if (semctl(sem_pro_id, 0, IPC_RMID, arg) == -1){ + emit printLog(QString("sem_pro failed (close)\n"), Qt::red); + } + if (semctl(sem_con_id, 0, IPC_RMID, arg) == -1){ + emit printLog(QString("sem_con failed (close)\n"), Qt::red); + } + #endif +} + +void DisplayWindow::zoomSettingsChanged(int value){ + if(!loop){ + zoom = std::pow(2, value); + scrollAreaWidgetContents->setFixedSize(res_x*zoom+26, res_y*zoom+26); + this->resize(QSize(res_x+60, res_y+92)); + scrollAreaWidgetContents->update(); + } +} + +void DisplayWindow::updateDisplay() { + // display the message and print on display + int currentcharx; + int currentchary; + int needed_pixel = (mode) ? res_x*res_y*3 : res_x*res_y; + if (mode){ + for(int l = 0; l < needed_pixel; l+=3) { + currentcharx = (l/3)%res_x; + currentchary = l/3/res_x; + displayPicture->setPixel(currentcharx, currentchary, qRgb(buffer[l], buffer[l+1], buffer[l+2])); + } + } else { + for(int l = 0; l < needed_pixel; l++){ + currentcharx = l%res_x; + currentchary = l/res_x; + if(buffer[l]){ + displayPicture->setPixel(currentcharx, currentchary, qRgb(255, 255, 255)); + } else { + displayPicture->setPixel(currentcharx, currentchary, qRgb(0, 0, 0)); + } + } + } +} + +void DisplayWindow::closeEvent(QCloseEvent *) { + emit closeSignal(); +} + +DisplayWindow::~DisplayWindow(){ + delete displayImageLabel; + //delete layout; +} + +BufferFrame::BufferFrame(DisplayWindow *parent) : + QWidget(parent){ + d = parent; +} + +void BufferFrame::paintEvent(QPaintEvent*){ + QPainter painter(this); + //if(!painter.isActive()){ + painter.drawImage(QRect(0,0,d->res_x*d->zoom,d->res_y*d->zoom),*(d->displayPicture)); + //} +} diff --git a/displayWindow.h b/displayWindow.h new file mode 100644 index 00000000..6d75a09a --- /dev/null +++ b/displayWindow.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** SASM - simple IDE for assembler 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 DISPLAYWINDOW_H +#define DISPLAYWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef Q_OS_WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#endif +#define BLOCK_SIZE 3145728 +#define FILENAME "/tmp" + +class DisplayWindow : public QWidget +{ + Q_OBJECT +public: + + explicit DisplayWindow(QWidget *parent = 0); + ~DisplayWindow(); + void changeDisplay(int msgid); + void finish(int msgid); + void updateDisplay(); + #ifdef Q_OS_WIN32 + HANDLE hCreateNamedPipe; + #else + sem_t* sem_producer; + sem_t* sem_consumer; + int sem_con_id, sem_pro_id; + union semun { + int val; /* used for SETVAL only */ + struct semid_ds *buf; /* used for IPC_STAT and IPC_SET */ + ushort *array; /* used for GETALL and SETALL */ + } arg; + #endif + +protected: + void closeEvent(QCloseEvent *); + +private: + friend class BufferFrame; + QVBoxLayout *verticalLayout; + QHBoxLayout *horizontalLayout; + QImage* displayPicture; + QLabel* displayImageLabel; + QComboBox *zoomComboBox; + QScrollArea *scrollArea; + QWidget *scrollAreaWidgetContents; + uint8_t buffer[BLOCK_SIZE]; + int zoom; + int msgid, res_x, res_y, mode, display_size; + std::atomic loop; + int shared_block_id; + uint8_t* block_values; + +public slots: +void zoomSettingsChanged(int value); + +signals: + void displayChanged(void); + void closeSignal(); + void closeDisplay(); + void printLog(QString msg, QColor color = QColor(Qt::black)); +}; + +class BufferFrame : public QWidget{ +public: + BufferFrame(DisplayWindow *parent = 0); + DisplayWindow* d; + +private: + friend class DisplayWindow; + +protected: + void paintEvent(QPaintEvent *event); + +}; + +#endif diff --git a/finddialog.cpp b/finddialog.cpp index 96d8d162..e8bc2261 100644 --- a/finddialog.cpp +++ b/finddialog.cpp @@ -98,8 +98,8 @@ FindDialog::FindDialog(QWidget *parent) searchLayout = new QHBoxLayout; searchLayout->addWidget(searchLabel); searchSpacer = new QSpacerItem( - replaceLabel->fontMetrics().width(tr("Replace with:")) - - searchLabel->fontMetrics().width(tr("Find what:")), + replaceLabel->fontMetrics().horizontalAdvance(tr("Replace with:")) - + searchLabel->fontMetrics().horizontalAdvance(tr("Find what:")), 0, QSizePolicy::Fixed, QSizePolicy::Fixed); searchLayout->addSpacerItem(searchSpacer); searchLayout->addWidget(searchEdit); diff --git a/highlighter.cpp b/highlighter.cpp index 9f09a37c..82c8bf05 100644 --- a/highlighter.cpp +++ b/highlighter.cpp @@ -72,7 +72,7 @@ formats << &keywordFormat << ®isterFormat << &numberFormat << &memoryFormat << &labelFormat << &commentFormat << &systemFormat << &iomacrosFormat << "ationFormat; - QSettings settings("SASM Project", "SASM"); + QSettings settings("SASM", "SASM"); for (int i = 0; i < formats.size(); i++) { formats[i]->setForeground(settings.value(names[i] + "color", defaultColors[i]).value()); formats[i]->setBackground(settings.value(names[i] + "colorbg", QPalette().color(QPalette::Base)).value()); diff --git a/main.cpp b/main.cpp index ede09571..f73f2e92 100644 --- a/main.cpp +++ b/main.cpp @@ -67,7 +67,7 @@ int main(int argc, char *argv[]) return 0; } QTranslator translator, qtTranslator; - QSettings settings("SASM Project", "SASM"); + QSettings settings("SASM", "SASM"); #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) QTextCodec *codec = QTextCodec::codecForName("UTF-8"); QTextCodec::setCodecForCStrings(codec); diff --git a/mainwindow.cpp b/mainwindow.cpp old mode 100644 new mode 100755 index 03be5505..9617efa6 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -12,7 +12,7 @@ ** (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 +** but WITHOUT ANY WARRANTY; without even the implieddwarranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** @@ -39,6 +39,7 @@ ****************************************************************************/ #include "mainwindow.h" +#include /** * @file mainwindow.cpp @@ -46,7 +47,7 @@ */ MainWindow::MainWindow(const QStringList &args, QWidget *parent) - : QMainWindow(parent), settings("SASM Project", "SASM") + : QMainWindow(parent), settings("SASM", "SASM") { setWindowTitle("SASM"); setWindowIcon(QIcon(":images/mainIcon.png")); @@ -64,12 +65,14 @@ MainWindow::MainWindow(const QStringList &args, QWidget *parent) help = 0; registersWindow = 0; memoryWindow = 0; + stackWindow = 0; debugger = 0; programStopped = true; highlighter = 0; tabs = 0; memoryDock = 0; registersDock = 0; + stackDock = 0; //! Initialize assembler assembler = 0; @@ -228,6 +231,7 @@ void MainWindow::createMenus() debugMenu->addAction(debugToggleBreakpointAction); debugMenu->addAction(debugShowRegistersAction); debugMenu->addAction(debugShowMemoryAction); + debugMenu->addAction(debugShowStackAction); debugMenu->addSeparator(); debugMenu->addAction(stopAction); settingsMenu = menuBar()->addMenu(tr("Settings")); @@ -459,6 +463,18 @@ void MainWindow::createActions() debugShowMemoryAction->setShortcut(key); debugShowMemoryAction->setCheckable(true); connect(debugShowMemoryAction, SIGNAL(toggled(bool)), this, SLOT(debugShowMemory()), Qt::QueuedConnection); + + //neu: + debugShowStackAction = new QAction("Show stack", this); + /* + key = keySettings.value("showMemory", "default").toString(); + stdKey = QKeySequence(QString("Ctrl+M")); + if (key == "default") + key = stdKey.toString(); + debugShowMemoryAction->setShortcut(key); + */ + debugShowStackAction->setCheckable(true); + connect(debugShowStackAction, SIGNAL(toggled(bool)), this, SLOT(debugShowStack()), Qt::QueuedConnection); disableDebugActions(true); @@ -748,6 +764,12 @@ void MainWindow::closeAllChildWindows() delete memoryWindow; memoryWindow = 0; } + if (stackWindow) { + stackWindow->close(); + delete stackWindow; + stackWindow = 0; + } + } bool MainWindow::deleteTab(int index, bool saveFileName) @@ -858,8 +880,7 @@ void MainWindow::buildProgram(bool debugMode) QStringList assemblerArguments = assemblerOptions.split(QChar(' ')); assemblerArguments.replaceInStrings("$SOURCE$", Common::pathInTemp("program.asm")); assemblerArguments.replaceInStrings("$LSTOUTPUT$", Common::pathInTemp("program.lst")); - assemblerArguments.replaceInStrings("$PROGRAM.OBJ$", - Common::pathInTemp(settings.value("objectfilename", "program.o").toString())); + assemblerArguments.replaceInStrings("$PROGRAM.OBJ$", Common::pathInTemp(settings.value("objectfilename", "program.o").toString())); assemblerArguments.replaceInStrings("$PROGRAM$", Common::pathInTemp("SASMprog.exe")); assemblerArguments.replaceInStrings("$MACRO.OBJ$", stdioMacros); QProcess assemblerProcess; @@ -878,6 +899,10 @@ void MainWindow::buildProgram(bool debugMode) } else { assemblerProcess.setWorkingDirectory(applicationDataPath() + "/include"); } + + if (settings.value("sasmverbose", false).toBool()) + printLog("Assembler: "+assemblerPath+" "+assemblerArguments.join(" ")+"\n", Qt::darkGreen); + assemblerProcess.start(assemblerPath, assemblerArguments); assemblerProcess.waitForFinished(); @@ -908,7 +933,7 @@ void MainWindow::buildProgram(bool debugMode) //! macro.c compilation QStringList gccMArguments; - gccMArguments << "-x" << "c" << Common::pathInTemp("macro.c") << "-c" << "-g" << "-o" << stdioMacros; + gccMArguments << "-x" << "c" << Common::pathInTemp("macro.c") << "-c" << "-g" << "-pthread" << "-o" << stdioMacros; if (settings.value("mode", QString("x86")).toString() == "x86") gccMArguments << "-m32"; else @@ -916,6 +941,10 @@ void MainWindow::buildProgram(bool debugMode) QProcess gccMProcess; gccMProcess.start(gcc, gccMArguments); gccMProcess.waitForFinished(); + QByteArray error = gccMProcess.readAllStandardError(); + QString errorBuffer = QString::fromLocal8Bit(error.constData(), error.size()); + if (errorBuffer.contains("fatal error: ")) + emit printLog(QString("can not compile macro.c: ") + errorBuffer + "\n", Qt::red); #endif //! Final linking @@ -933,6 +962,14 @@ void MainWindow::buildProgram(bool debugMode) linkerOutput = Common::pathInTemp("linkererror.txt"); linkerProcess.setStandardOutputFile(linkerOutput); linkerProcess.setStandardErrorFile(linkerOutput, QIODevice::Append); + + #ifdef Q_OS_WIN32 + #else + linkerArguments << "-pthread"; + #endif + if (settings.value("sasmverbose", false).toBool()) + printLog("Linker: "+linker+" "+linkerArguments.join(" ")+"\n", Qt::darkGreen); + linkerProcess.start(linker, linkerArguments); linkerProcess.waitForFinished(); @@ -1023,7 +1060,54 @@ void MainWindow::runProgram() QString program = Common::pathInTemp("SASMprog.exe"); runProcess->setStandardInputFile(input); - + + // start display + if (!displayWindow) { + displayWindow = new DisplayWindow; + displayWindow->setWindowIcon(QIcon(":images/mainIcon.png")); + displayWindow->setWindowFlags(Qt::Widget | Qt::MSWindowsFixedSizeDialogHint); + displayWindow->activateWindow(); + } + if (settings.value("display", false).toBool()){ + displayWindow->show(); + } + #ifdef Q_OS_WIN32 + HANDLE hCreateNamedPipe = CreateNamedPipe( + L"\\\\.\\pipe\\sasmpipe", + PIPE_ACCESS_INBOUND, + PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + BLOCK_SIZE, + BLOCK_SIZE, + 0, + NULL); + if(hCreateNamedPipe == INVALID_HANDLE_VALUE){ + printLog(QString("Couldnt create Pipe"+QString::number(GetLastError()))+"\n", Qt::red); + } + displayWindow->hCreateNamedPipe = hCreateNamedPipe; + consumer = new std::thread(&DisplayWindow::changeDisplay, displayWindow, -1); + #else + + /* create producer semaphore | set to 0: */ + if ((displayWindow->sem_pro_id = semget(ftok(FILENAME, 'p'), 1, 0666 | IPC_CREAT)) == -1){ + emit printLog(QString("sem_prod failed (semget)\n"), Qt::red); + } + displayWindow->arg.val = 0; + if (semctl(displayWindow->sem_pro_id, 0, SETVAL, displayWindow->arg) == -1){ + emit printLog(QString("sem_prod failed (semctl)\n"), Qt::red); + } + /* create consumer semaphore | set to 1*/ + if ((displayWindow->sem_con_id = semget(ftok(FILENAME, 'c'), 1, 0666 | IPC_CREAT)) == -1){ + emit printLog(QString("sem_con failed (semget)\n"), Qt::red); + } + displayWindow->arg.val = 1; + if (semctl(displayWindow->sem_con_id, 0, SETVAL, displayWindow->arg) == -1){ + emit printLog(QString("sem_con failed (semctl)\n"), Qt::red); + } + + consumer = new std::thread(&DisplayWindow::changeDisplay, displayWindow, msgid); + #endif + //! Run program in code directory if it exists QString codePath = currentTab->getCurrentFilePath(); if (!codePath.isEmpty()) { @@ -1061,6 +1145,8 @@ void MainWindow::testStopOfProgram() debugAction->setEnabled(true); buildAction->setEnabled(true); if (!programStopped) { + displayWindow->finish(msgid); + consumer->join(); if (runProcess->exitStatus() == QProcess::NormalExit) printLogWithTime(tr("The program finished normally. Execution time: %1 s") .arg(programExecutionTime.elapsed() / 1000.0) @@ -1097,6 +1183,7 @@ void MainWindow::stopProgram() stopAction->setEnabled(false); runProcess->kill(); + displayWindow->finish(msgid); printLogWithTime(tr("The program stopped.") + '\n', Qt::darkGreen); } else { @@ -1149,6 +1236,7 @@ void MainWindow::debug() } ((Tab *) tabs->currentWidget())->clearOutput(); printLogWithTime(tr("Debugging started...") + '\n', Qt::darkGreen); + Tab *currentTab = (Tab *) tabs->currentWidget(); CodeEditor *code = currentTab->code; @@ -1165,11 +1253,62 @@ void MainWindow::debug() } workingDirectoryPath.replace("\\", "/"); + QString gdbpath = settings.value("gdbpath", "gdb").toString(); + //! Determine input path QString inputPath = Common::pathInTemp("input.txt"); inputPath.replace("\\", "/"); - - debugger = new Debugger(compilerOut, exePath, workingDirectoryPath, inputPath, assembler); + + // start display + if (!displayWindow) { + displayWindow = new DisplayWindow; + displayWindow->setWindowIcon(QIcon(":images/mainIcon.png")); + displayWindow->setWindowFlags(Qt::Widget | Qt::MSWindowsFixedSizeDialogHint); + displayWindow->activateWindow(); + } + if (settings.value("display", false).toBool()) + displayWindow->show(); + #ifdef Q_OS_WIN32 + HANDLE hCreateNamedPipe = CreateNamedPipe( + L"\\\\.\\pipe\\sasmpipe", + PIPE_ACCESS_INBOUND, + PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + BLOCK_SIZE, + BLOCK_SIZE, + 0, + NULL); + if(hCreateNamedPipe == INVALID_HANDLE_VALUE){ + printLog(QString("Couldnt create Pipe"+QString::number(GetLastError()))+"\n", Qt::red); + } + displayWindow->hCreateNamedPipe = hCreateNamedPipe; + consumer = new std::thread(&DisplayWindow::changeDisplay, displayWindow, -1); + #else + /* create producer semaphore | set to 0: */ + if ((displayWindow->sem_pro_id = semget(ftok(FILENAME, 'p'), 1, 0666 | IPC_CREAT)) == -1){ + emit printLog(QString("sem_prod failed (semget)\n"), Qt::red); + } + displayWindow->arg.val = 0; + if (semctl(displayWindow->sem_pro_id, 0, SETVAL, displayWindow->arg) == -1){ + emit printLog(QString("sem_prod failed (semctl)\n"), Qt::red); + } + /* create consumer semaphore | set to 1*/ + if ((displayWindow->sem_con_id = semget(ftok(FILENAME, 'c'), 1, 0666 | IPC_CREAT)) == -1){ + emit printLog(QString("sem_con failed (semget)\n"), Qt::red); + } + displayWindow->arg.val = 1; + if (semctl(displayWindow->sem_con_id, 0, SETVAL, displayWindow->arg) == -1){ + emit printLog(QString("sem_con failed (semctl)\n"), Qt::red); + } + + consumer = new std::thread(&DisplayWindow::changeDisplay, displayWindow, msgid); + #endif + + debugger = new Debugger(compilerOut, exePath, workingDirectoryPath, inputPath, assembler, 0, settings.value("sasmverbose", false).toBool(), settings.value("mi", false).toBool()); + // connect print signals for output in Debugger + connect(debugger, SIGNAL(printLog(QString,QColor)), this, SLOT(printLog(QString,QColor))); + connect(displayWindow, SIGNAL(printLog(QString,QColor)), this, SLOT(printLog(QString,QColor))); // remove + connect(debugger, SIGNAL(printOutput(QString)), this, SLOT(printOutput(QString))); 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())); @@ -1177,11 +1316,10 @@ void MainWindow::debug() 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())); connect(debugger, SIGNAL(needToContinue()), this, SLOT(debug())); + code->setDebugEnabled(); } //Pause or continue debugger @@ -1212,6 +1350,7 @@ void MainWindow::changeDebugActionToStart() else { debugShowRegisters(); debugShowMemory(); + debugShowStack(); } } @@ -1232,6 +1371,7 @@ void MainWindow::enableDebugActions() debugNextNiAction->setEnabled(true); debugShowRegistersAction->setEnabled(true); debugShowMemoryAction->setEnabled(true); + debugShowStackAction->setEnabled(true); stopAction->setEnabled(true); //! Change stopAction @@ -1245,6 +1385,7 @@ void MainWindow::enableDebugActions() //! Restore windows debugShowRegistersAction->setChecked(settings.value("debugregisters", false).toBool()); debugShowMemoryAction->setChecked(settings.value("debugmemory", false).toBool()); + debugShowStackAction->setChecked(settings.value("debugstack", false).toBool()); } void MainWindow::disableDebugActions(bool start) @@ -1257,6 +1398,7 @@ void MainWindow::disableDebugActions(bool start) debugNextNiAction->setEnabled(false); debugShowRegistersAction->setEnabled(false); debugShowMemoryAction->setEnabled(false); + debugShowStackAction->setEnabled(false); stopAction->setEnabled(false); //! Change stopAction @@ -1320,6 +1462,8 @@ void MainWindow::debugShowMemory() restoreState(settings.value("debugstate").toByteArray()); if (registersDock) registersDock->show(); + if (stackDock) + stackDock->show(); if (memoryDock) memoryDock->show(); @@ -1382,6 +1526,50 @@ void MainWindow::debugShowMemory() } } +void MainWindow::debugShowStack() +{ + if (debugShowStackAction->isChecked()) { + if (!stackWindow) { + stackDock = new QDockWidget(tr("Stack"), this); + stackDock->setAllowedAreas(Qt::AllDockWidgetAreas); + + stackWindow = new StackWidget; + connect(stackWindow, SIGNAL(closeSignal()), this, SLOT(setShowStackToUnchecked())); + connect(debugger, SIGNAL(printStack(QList)), + stackWindow->stackContent, SLOT(setValuesFromDebugger(QList))); + connect(stackWindow->settings, SIGNAL(stacksettingsChanged()), this, SLOT(debugShowStack()), Qt::QueuedConnection); + + stackDock->setWidget(stackWindow); + stackDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + addDockWidget(Qt::LeftDockWidgetArea, stackDock); + stackDock->setObjectName("stackDock"); + + restoreState(settings.value("debugstate").toByteArray()); + if (registersDock) + registersDock->show(); + if (memoryDock) + memoryDock->show(); + if (stackDock) + stackDock->show(); + } + if (debugger->isStopped()) { + debugger->setSystemStack(stackWindow->settings->typeComboBox->currentIndex()); + debugger->setBitStack(stackWindow->settings->sizeComboBox->currentIndex()); + debugger->setSignStack(stackWindow->settings->signCheckbox->isChecked()); + debugger->doInput(QString("x/100x $sp\n"), infoStack); + } + } else + if (stackWindow) { + stackWindow->close(); + //stackWindow->clear(); + delete stackWindow; + stackWindow = 0; + stackDock->close(); + delete stackDock; + stackDock = 0; + } +} + void MainWindow::saveWatches(DebugTableWidget *table) { watches.clear(); @@ -1444,6 +1632,8 @@ void MainWindow::debugShowRegisters() registersDock->show(); if (memoryDock) memoryDock->show(); + if (stackDock) + stackDock->show(); } static SignalLocker locker; if (debugger->isStopped() && locker.tryLock()) { @@ -1471,10 +1661,16 @@ void MainWindow::setShowRegistersToUnchecked() debugShowRegistersAction->setChecked(false); } +void MainWindow::setShowStackToUnchecked() +{ + debugShowStackAction->setChecked(false); +} +//TODO void MainWindow::debugExit() { settings.setValue("debugregisters", debugShowRegistersAction->isChecked()); settings.setValue("debugmemory", debugShowMemoryAction->isChecked()); + settings.setValue("debugstack", debugShowStackAction->isChecked()); settings.setValue("debugstate", saveState()); CodeEditor *code = ((Tab *) tabs->currentWidget())->code; disconnect(code, SIGNAL(addWatchSignal(const RuQPlainTextEdit::Watch &)), @@ -1484,14 +1680,19 @@ void MainWindow::debugExit() code->setDebugDisabled(); //! Many actions performed here - deleting of highlighting too delete debugger; + // close display: + displayWindow->finish(msgid); + consumer->join(); debugger = 0; closeAnyCommandWidget(); debugShowRegistersAction->setChecked(false); debugShowMemoryAction->setChecked(false); + debugShowStackAction->setChecked(false); printLogWithTime(tr("Debugging finished.") + '\n', Qt::darkGreen); disableDebugActions(); } + void MainWindow::showAnyCommandWidget() { debugAnyCommandWidget->show(); @@ -1571,7 +1772,7 @@ void MainWindow::findNext(const QString &pattern, Qt::CaseSensitivity cs, bool a if (cs == Qt::CaseSensitive) newCursor = document->find(pattern, newCursor, QTextDocument::FindCaseSensitively); else - newCursor = document->find(pattern, newCursor, 0); + newCursor = document->find(pattern, newCursor); //! Replace mode if (replace && i == tabs->currentIndex()) { newCursor.removeSelectedText(); @@ -1603,13 +1804,13 @@ void MainWindow::findNext(const QString &pattern, Qt::CaseSensitivity cs, bool a if (cs == Qt::CaseSensitive) newCursor = document->find(pattern, newCursor, QTextDocument::FindCaseSensitively); else - newCursor = document->find(pattern, newCursor, 0); + newCursor = document->find(pattern, newCursor); //! Continue from start if (newCursor.isNull()) { if (cs == Qt::CaseSensitive) newCursor = document->find(pattern, newCursor, QTextDocument::FindCaseSensitively); else - newCursor = document->find(pattern, newCursor, 0); + newCursor = document->find(pattern, newCursor); } if (!newCursor.isNull()) { selection.cursor = newCursor; @@ -1853,8 +2054,16 @@ void MainWindow::initAssemblerSettings(bool firstOpening) settingsUi.objectFileNameEdit->setText(settings.value("objectfilename", "program.o").toString()); + settingsUi.gdbPathEdit->setText(settings.value("gdbpath", "gdb").toString()); + settingsUi.disableLinkingCheckbox->setChecked(settings.value("disablelinking", false).toBool()); + settingsUi.sasmVerboseCheckBox->setChecked(settings.value("sasmverbose", false).toBool()); + + settingsUi.MiModusCheckBox->setChecked(settings.value("mi", true).toBool()); + + settingsUi.sasmDisplayCheckBox->setChecked(settings.value("display", false).toBool()); + settingsUi.runInCurrentDirectoryCheckbox->setChecked(settings.value("currentdir", false).toBool()); QString assemblerPath = assembler->getAssemblerPath(); @@ -1938,6 +2147,7 @@ void MainWindow::changeMode(bool x86) settings.setValue("mode", QString("x86")); else settings.setValue("mode", QString("x64")); + recreateAssembler(); } @@ -1947,6 +2157,7 @@ void MainWindow::recreateAssembler(bool start) delete assembler; assembler = 0; } + bool x86 = true; if (settings.value("mode", QString("x86")).toString() != "x86") x86 = false; @@ -1991,14 +2202,21 @@ void MainWindow::recreateAssembler(bool start) settingsUi.linkingOptionsEdit->setText(assembler->getLinkerOptions()); settingsUi.objectFileNameEdit->setText("program.o"); settingsUi.disableLinkingCheckbox->setChecked(false); + settingsUi.sasmVerboseCheckBox->setChecked(false); + settingsUi.MiModusCheckBox->setChecked(false); settingsUi.runInCurrentDirectoryCheckbox->setChecked(false); settingsUi.assemblerPathEdit->setText(assembler->getAssemblerPath()); + settingsUi.gdbPathEdit->setText("gdb"); settingsUi.linkerPathEdit->setText(assembler->getLinkerPath()); settings.setValue("assemblyoptions", assembler->getAssemblerOptions()); settings.setValue("linkingoptions", assembler->getLinkerOptions()); settings.setValue("objectfilename", "program.o"); settings.setValue("disablelinking", false); settings.setValue("currentdir", false); + settings.setValue("sasmverbose", false); + settings.setValue("mi", true); + settings.setValue("display", false); + settings.setValue("gdbpath", "gdb"); settings.setValue("assemblerpath", assembler->getAssemblerPath()); settings.setValue("linkerpath", assembler->getLinkerPath()); changeStartText(); @@ -2020,6 +2238,10 @@ void MainWindow::backupSettings() backupAssemblerPath = settings.value("assemblerpath", assembler->getAssemblerPath()).toString(); backupLinkerOptions = settings.value("linkingoptions", assembler->getLinkerOptions()).toString(); backupObjectFileName = settings.value("objectfilename", "program.o").toString(); + backupGDBPath = settings.value("gdbpath", "gdb").toString(); + backupGDBVerbose = settings.value("sasmverbose", false).toBool(); + backupGDBDisplay = settings.value("display", false).toBool(); + backupGDBMi = settings.value("mi", true).toBool(); backupDisableLinking = settings.value("disablelinking", false).toBool(); backupCurrentDir = settings.value("currentdir", false).toBool(); backupStartText = settings.value("starttext", assembler->getStartText()).toString(); @@ -2036,6 +2258,10 @@ void MainWindow::restoreSettingsAndExit() settings.setValue("linkingoptions", backupLinkerOptions); settings.setValue("objectfilename", backupObjectFileName); settings.setValue("disablelinking", backupDisableLinking); + settings.setValue("gdbpath", backupGDBPath); + settings.setValue("sasmverbose", backupGDBVerbose); + settings.setValue("mi", backupGDBMi); + settings.setValue("display", backupGDBDisplay); settings.setValue("currentdir", backupCurrentDir); settings.setValue("starttext", backupStartText); settings.setValue("linkerpath", backupLinkerPath); @@ -2080,8 +2306,12 @@ void MainWindow::saveSettings() settings.setValue("linkingoptions", settingsUi.linkingOptionsEdit->text()); settings.setValue("objectfilename", settingsUi.objectFileNameEdit->text()); settings.setValue("disablelinking", settingsUi.disableLinkingCheckbox->isChecked()); + settings.setValue("sasmverbose", settingsUi.sasmVerboseCheckBox->isChecked()); + settings.setValue("mi", settingsUi.MiModusCheckBox->isChecked()); + settings.setValue("display", settingsUi.sasmDisplayCheckBox->isChecked()); settings.setValue("currentdir", settingsUi.runInCurrentDirectoryCheckbox->isChecked()); settings.setValue("assemblerpath", settingsUi.assemblerPathEdit->text()); + settings.setValue("gdbpath", settingsUi.gdbPathEdit->text()); settings.setValue("linkerpath", settingsUi.linkerPathEdit->text()); settings.setValue("starttext", settingsStartTextEditor->document()->toPlainText()); @@ -2202,6 +2432,7 @@ void MainWindow::changeActionsState(int widgetIndex) debugNextAction->setEnabled(false); debugNextNiAction->setEnabled(false); debugShowRegistersAction->setEnabled(false); + debugShowStackAction->setEnabled(false); debugToggleBreakpointAction->setEnabled(false); debugShowMemoryAction->setEnabled(false); } else { @@ -2316,4 +2547,9 @@ MainWindow::~MainWindow() { //! Delete all temporary files removeDirRecuresively(Common::pathInTemp(QString())); + // close display + if(displayWindow){ + displayWindow->close(); + delete displayWindow; + } } diff --git a/mainwindow.h b/mainwindow.h index 28206fcc..b6432b9f 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ #include #include #include +#include #include "tab.h" #include "highlighter.h" #include "debugger.h" @@ -74,8 +76,31 @@ #include "fasm.h" #include "signallocker.h" #include "masm.h" +#include "stackwidget.h" +#include "displayWindow.h" +#include +#ifdef Q_OS_WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#include +/// +#include +#include +#include +#endif #define SASM_VERSION "3.12.1" +#define SEM_PRODUCER_FNAME "/myproducer" +#define SEM_CONSUMER_FNAME "/myconsumer" +#define FILENAME "/tmp" +#define IPC_RESULT_ERROR (-1) +#define BLOCK_SIZE 3145728 /** * @file mainwindow.h @@ -151,6 +176,7 @@ class MainWindow : public QMainWindow QAction *debugToggleBreakpointAction; QAction *debugShowRegistersAction; QAction *debugShowMemoryAction; + QAction *debugShowStackAction; QAction *settingsAction; QAction *helpAction; QAction *aboutAction; @@ -165,13 +191,15 @@ class MainWindow : public QMainWindow QProcess *runProcess; CodeEditor *prevCodeEditor; QTimer *timer; - QTime programExecutionTime; + QElapsedTimer programExecutionTime; Debugger *debugger; bool programIsBuilded; QPointer registersWindow; QDockWidget *registersDock; QPointer memoryWindow; QDockWidget *memoryDock; + QPointer stackWindow; + QDockWidget *stackDock; QList watches; DebugAnyCommandWidget *debugAnyCommandWidget; bool programStopped; @@ -209,6 +237,10 @@ class MainWindow : public QMainWindow QString backupAssemblerOptions; QString backupLinkerOptions; QString backupObjectFileName; + QString backupGDBPath; + bool backupGDBVerbose; + bool backupGDBMi; + bool backupGDBDisplay; bool backupDisableLinking; bool backupCurrentDir; QString backupAssemblerPath; @@ -218,6 +250,11 @@ class MainWindow : public QMainWindow //! About close bool closeFromCloseAll; void closeEvent(QCloseEvent *e); + + // display + QPointer displayWindow; + std::thread *consumer; + int msgid; public slots: //! Actions and Menus @@ -254,9 +291,11 @@ public slots: void debugToggleBreakpoint(); void debugShowRegisters(); void debugShowMemory(); + void debugShowStack(); void debugRunCommand(QString command, bool print); void saveWatches(DebugTableWidget *table); void setShowRegistersToUnchecked(); + void setShowStackToUnchecked(); void setShowMemoryToUnchecked(); void setShowMemoryToChecked(const RuQPlainTextEdit::Watch &variable); void showAnyCommandWidget(); @@ -301,6 +340,7 @@ public slots: //! Single Application message void onMessageReceived(const QString &message); + protected: void dragEnterEvent(QDragEnterEvent *event); diff --git a/ruqplaintextedit.cpp b/ruqplaintextedit.cpp index e8ab5621..715eb855 100644 --- a/ruqplaintextedit.cpp +++ b/ruqplaintextedit.cpp @@ -48,7 +48,7 @@ RuQPlainTextEdit::RuQPlainTextEdit(QWidget *parent) : QPlainTextEdit(parent) { - QSettings settings("SASM Project", "SASM"); + QSettings settings("SASM", "SASM"); QPalette palette = this->palette(); palette.setColor(QPalette::Base, settings.value("backgroundcolor", palette.color(QPalette::Base)).value()); palette.setColor(QPalette::Text, settings.value("fontcolor", palette.color(QPalette::Text)).value()); diff --git a/ruqtextedit.cpp b/ruqtextedit.cpp index a0b9b934..4eacb643 100644 --- a/ruqtextedit.cpp +++ b/ruqtextedit.cpp @@ -49,7 +49,7 @@ RuQTextEdit::RuQTextEdit(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(false); - QSettings settings("SASM Project", "SASM"); + QSettings settings("SASM", "SASM"); QPalette palette = this->palette(); palette.setColor(QPalette::Base, settings.value("backgroundcolor", palette.color(QPalette::Base)).value()); palette.setColor(QPalette::Text, settings.value("fontcolor", palette.color(QPalette::Text)).value()); diff --git a/settings.ui b/settings.ui index 9c4148fb..0507c6ea 100644 --- a/settings.ui +++ b/settings.ui @@ -6,8 +6,8 @@ 0 0 - 743 - 494 + 1702 + 971 @@ -41,7 +41,7 @@ Qt::LeftToRight - 0 + 2 Qt::ElideNone @@ -1957,6 +1957,15 @@ QFormLayout::AllNonFixedFieldsGrow + + 12 + + + 12 + + + 0 + @@ -2124,14 +2133,41 @@ - + + + + GDB path (Unix only): + + + + + + + + + + Build in current directory: + + + + + + + true + + + + + + + Disable linking: - + true @@ -2141,21 +2177,52 @@ - - + + - Build in current directory: + SASM verbose mode: - - - - true + + + + + + + + + + + MI-Mode: + + + + + + + + + true + + + + + + + SASM display: + + + + + + + false + diff --git a/stacksettingswidget.cpp b/stacksettingswidget.cpp new file mode 100644 index 00000000..e2ad1771 --- /dev/null +++ b/stacksettingswidget.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** SASM - simple IDE for assembler 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 "stacksettingswidget.h" + +/*! \brief This defines the layout such as spacing and items of the stack + * + * + * First, the parent widget is passed to the class. Next, the form items are added + * and spaced appropriately. The form items are then further defined and then connected. +*/ +StackSettingsWidget::StackSettingsWidget(QWidget *parent) : + QWidget(parent) +{ + layout = new QHBoxLayout(this); + typeComboBox = new QComboBox; + sizeComboBox = new QComboBox; + signCheckbox = new QCheckBox(tr("Signed/Unsigned")); + layout->addWidget(typeComboBox); + layout->addWidget(sizeComboBox); + //layout->addSpacing(1); + layout->addWidget(signCheckbox); + + QStringList comboBoxList; + comboBoxList << tr("Hex") << QString("Dec") << tr("Bin"); + typeComboBox->insertItems(0, comboBoxList); + + QStringList sizeBoxList; + sizeBoxList << QString("8") << QString("16") << QString("32") << QString("64"); + sizeComboBox->insertItems(0, sizeBoxList); + + signCheckbox->setChecked(false); + + layout->setSpacing(0); + layout->setMargin(0); + + connect(typeComboBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(stacksettingsChanged())); + connect(sizeComboBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(stacksettingsChanged())); + connect(signCheckbox, SIGNAL(stateChanged(int)), this, SIGNAL(stacksettingsChanged())); + + setLayout(layout); +} + +StackSettingsWidget::~StackSettingsWidget() +{ + delete typeComboBox; + delete sizeComboBox; + delete signCheckbox; + delete layout; +} diff --git a/stacksettingswidget.h b/stacksettingswidget.h new file mode 100644 index 00000000..a2f16b2c --- /dev/null +++ b/stacksettingswidget.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** SASM - simple IDE for assembler 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 STACKSETTINGSWIDGET_H +#define STACKSETTINGSWIDGET_H + +#include +#include +#include +#include + + +class StackSettingsWidget : public QWidget +{ + Q_OBJECT +public: + explicit StackSettingsWidget(QWidget *parent = 0); + ~StackSettingsWidget(); + QComboBox *typeComboBox; + QComboBox *sizeComboBox; + QCheckBox *signCheckbox; + +private: + QHBoxLayout *layout; + +signals: + void stacksettingsChanged(void); +}; + +#endif // WATCHSETTINGSWIDGET_H diff --git a/stackwidget.cpp b/stackwidget.cpp new file mode 100644 index 00000000..a2e68baf --- /dev/null +++ b/stackwidget.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** SASM - simple IDE for assembler 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 "stackwidget.h" + + +StackWidget::StackWidget(QWidget *parent) : + QWidget(parent) +{ + layout = new QVBoxLayout(this); + stackContent = new DebugTableWidget(0, 2, stackTable, this);; + settings = new StackSettingsWidget; + + layout->addWidget(settings); + layout->addWidget(stackContent); + + layout->setSpacing(0); + layout->setMargin(0); + + setLayout(layout); +} + +void StackWidget::closeEvent(QCloseEvent *) { + emit closeSignal(); +} + +StackWidget::~StackWidget() +{ + delete stackContent; + stackContent = 0; + delete settings; + delete layout; +} diff --git a/stackwidget.h b/stackwidget.h new file mode 100644 index 00000000..0e636693 --- /dev/null +++ b/stackwidget.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** SASM - simple IDE for assembler 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 STACKWIDGET_H +#define STACKWIDGET_H + +#include +#include +#include +#include +#include "stacksettingswidget.h" +#include "debugtablewidget.h" + + +class StackWidget : public QWidget +{ + Q_OBJECT +public: + explicit StackWidget(QWidget *parent = 0); + ~StackWidget(); + QPointer stackContent; + StackSettingsWidget *settings; + +protected: + void closeEvent(QCloseEvent *); + +private: + QVBoxLayout *layout; + +signals: + void stacksettingsChanged(void); + void closeSignal(); +}; + +#endif diff --git a/tab.cpp b/tab.cpp index 47ae700a..f0852efb 100644 --- a/tab.cpp +++ b/tab.cpp @@ -86,7 +86,7 @@ Tab::Tab(QWidget *parent) : setFonts(); //! Restore state - QSettings settings("SASM Project", "SASM"); + QSettings settings("SASM", "SASM"); restoreGeometry(settings.value("tabgeometry").toByteArray()); restoreState(settings.value("tabwindowstate").toByteArray()); } @@ -97,7 +97,7 @@ Tab::Tab(QWidget *parent) : */ void Tab::setFonts() { - QSettings settings("SASM Project", "SASM"); + QSettings settings("SASM", "SASM"); QFont codeFont; codeFont.setPointSize(settings.value("fontsize", 12).toInt()); diff --git a/watchsettingswidget.cpp b/watchsettingswidget.cpp index 8f9c4a69..8556a941 100644 --- a/watchsettingswidget.cpp +++ b/watchsettingswidget.cpp @@ -93,14 +93,14 @@ WatchSettingsWidget::WatchSettingsWidget(QWidget *parent) : int WatchSettingsWidget::sumSize() { return typeComboBox->sizeHint().width() + sizeComboBox->sizeHint().width() - + arraySizeEdit->fontMetrics().width(arraySizeEdit->placeholderText()) + + arraySizeEdit->fontMetrics().horizontalAdvance(arraySizeEdit->placeholderText()) + addressCheckbox->sizeHint().width() + 50; } QSize WatchSettingsWidget::sizeHint() const { return QSize(typeComboBox->sizeHint().width() + sizeComboBox->sizeHint().width() - + arraySizeEdit->fontMetrics().width(arraySizeEdit->placeholderText()) + + arraySizeEdit->fontMetrics().horizontalAdvance(arraySizeEdit->placeholderText()) + addressCheckbox->sizeHint().width() + 50, 0); }