From 8bcf603b27626a9883400e50b189a2f57b638079 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Thu, 12 Feb 2015 13:19:11 +0300 Subject: [PATCH] fix tokenizer; initial implementation of win32 debugger --- dlangide.visualdproj | 5 + src/ddc/lexer/tokenizer.d | 54 ++++++---- src/ddebug/windows/windebug.d | 190 ++++++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 23 deletions(-) create mode 100644 src/ddebug/windows/windebug.d diff --git a/dlangide.visualdproj b/dlangide.visualdproj index b7a89b5..b7abcc4 100644 --- a/dlangide.visualdproj +++ b/dlangide.visualdproj @@ -216,6 +216,11 @@ + + + + + diff --git a/src/ddc/lexer/tokenizer.d b/src/ddc/lexer/tokenizer.d index c0d5268..5e951f2 100644 --- a/src/ddc/lexer/tokenizer.d +++ b/src/ddc/lexer/tokenizer.d @@ -1483,11 +1483,15 @@ class Tokenizer protected dchar nextChar() { if (_pos >= _len) { if (!nextLine()) { + _pos = _prevLineLength + 1; return EOF_CHAR; } return EOL_CHAR; } - return _lineText[_pos++]; + dchar res = _lineText[_pos++]; + if (_pos >= _len) + nextLine(); + return res; } protected dchar peekChar() { @@ -1503,16 +1507,12 @@ class Tokenizer protected Token emitEof() { // TODO: check for current state - return new EofToken(_lineStream.file, _line, _pos); + return new EofToken(_lineStream.file, _startLine, _startPos + 2); } protected Token processWhiteSpace(dchar firstChar) { // reuse the same token instance, to avoid extra heap spamming - if (_pos == 0) { - _sharedWhiteSpaceToken.setPos(_line - 1, _prevLineLength); - } else { - _sharedWhiteSpaceToken.setPos(_line, _pos - 1); - } + _sharedWhiteSpaceToken.setPos(_startLine, _startPos); for (;;) { int i = _pos; for (; i < _len; i++) { @@ -1531,18 +1531,19 @@ class Tokenizer } protected Token processOneLineComment() { - _sharedCommentToken.setPos(_line, _pos - 1); + _sharedCommentToken.setPos(_startLine, _startPos); _sharedCommentToken.isDocumentationComment = _pos + 1 < _lineText.length && _lineText[_pos + 1] == '/'; _sharedCommentToken.isMultilineComment = false; if (_enableCommentText) { _sharedCommentToken.text = _lineText[_pos + 1 .. $]; } _pos = _len; + nextChar(); return _sharedCommentToken; } protected Token processOneLineSharpComment() { - _sharedCommentToken.setPos(_line, _pos - 1); + _sharedCommentToken.setPos(_startLine, _startPos); if (_enableCommentText) { _sharedCommentToken.text = _lineText[_pos .. $]; } @@ -1552,7 +1553,7 @@ class Tokenizer // Comment /* */ protected Token processMultilineComment() { - _sharedCommentToken.setPos(_line, _pos - 1); + _sharedCommentToken.setPos(_startLine, _startPos); _sharedCommentToken.isDocumentationComment = _pos + 1 < _lineText.length && _lineText[_pos + 1] == '*'; _sharedCommentToken.isMultilineComment = true; _commentAppender.reset(); @@ -1587,7 +1588,7 @@ class Tokenizer // Comment /+ +/ protected Token processNestedComment() { - _sharedCommentToken.setPos(_line, _pos - 1); + _sharedCommentToken.setPos(_startLine, _startPos); _sharedCommentToken.isDocumentationComment = _pos + 1 < _lineText.length && _lineText[_pos + 1] == '+'; _sharedCommentToken.isMultilineComment = true; _commentAppender.reset(); @@ -1649,7 +1650,7 @@ class Tokenizer } protected Token processIdent() { - _sharedIdentToken.setPos(_line, _pos - 1); + _sharedIdentToken.setPos(_startLine, _startPos); _identAppender.reset(); int startPos = _pos - 1; int endPos = _len; @@ -1695,7 +1696,7 @@ class Tokenizer } protected Token processBinaryNumber() { - _sharedIntegerToken.setPos(_line, _pos - 1); + _sharedIntegerToken.setPos(_startLine, _startPos); _pos++; if (_pos >= _len) return parserError("Unexpected end of line in binary number", _sharedIntegerToken); @@ -1717,8 +1718,8 @@ class Tokenizer } protected Token processHexNumber() { - _sharedIntegerToken.setPos(_line, _pos - 1); - _sharedRealToken.setPos(_line, _pos - 1); + _sharedIntegerToken.setPos(_startLine, _startPos); + _sharedRealToken.setPos(_startLine, _startPos); _pos++; if (_pos >= _len) return parserError("Unexpected end of line in hex number", _sharedIntegerToken); @@ -1749,7 +1750,7 @@ class Tokenizer } protected Token processOctNumber() { - _sharedIntegerToken.setPos(_line, _pos - 1); + _sharedIntegerToken.setPos(_startLine, _startPos); if (_pos >= _len) return parserError("Unexpected end of line in octal number", _sharedIntegerToken); int digits = 0; @@ -1872,8 +1873,8 @@ class Tokenizer protected Token processDecNumber(dchar c) { _pos--; - _sharedIntegerToken.setPos(_line, _pos); - _sharedRealToken.setPos(_line, _pos); + _sharedIntegerToken.setPos(_startLine, _startPos); + _sharedRealToken.setPos(_startLine, _startPos); if (_pos >= _len) return parserError("Unexpected end of line in number", _sharedIntegerToken); int digits = 0; @@ -2375,7 +2376,7 @@ class Tokenizer } protected Token processCharacterLiteral() { - _sharedCharacterLiteralToken.setPos(_line, _pos - 1); + _sharedCharacterLiteralToken.setPos(_startLine, _startPos); if (_pos + 2 > _len) return parserError("Invalid character literal", _sharedCharacterLiteralToken); dchar ch = _lineText[_pos++]; @@ -2424,7 +2425,7 @@ class Tokenizer protected Token processDoubleQuotedOrWysiwygString(dchar delimiter) { bool wysiwyg = (delimiter == 'r' || delimiter == '`'); //writeln("processDoubleQuotedString()"); - _sharedStringLiteralToken.setPos(_line, _pos - 1); + _sharedStringLiteralToken.setPos(_startLine, _startPos); _stringLiteralAppender.reset(); if (delimiter == 'r') { _pos++; @@ -2501,7 +2502,7 @@ class Tokenizer static immutable dstring VENDOR = "coolreader.org"; protected Token makeSpecialTokenString(dstring str, int pos) { - _sharedStringLiteralToken.setPos(_line, pos); + _sharedStringLiteralToken.setPos(_startLine, _startPos); _sharedStringLiteralToken.setText(cast(dchar[])str, 0); return _sharedStringLiteralToken; } @@ -2525,8 +2526,13 @@ class Tokenizer return null; } + protected int _startLine; + protected int _startPos; + // returns next token (clone it if you want to store for future usage, otherwise it may be overwritten by further nextToken() calls). Token nextToken() { + _startLine = _line; + _startPos = _pos; dchar ch = nextChar(); if (ch == EOF_CHAR) { return emitEof(); @@ -2587,7 +2593,7 @@ class Tokenizer case Keyword.VERSION_: // Compiler version as an integer, such as 2001 return processSpecialToken(keyword, oldPos); default: - _sharedKeywordToken.setPos(_line, oldPos); + _sharedKeywordToken.setPos(_startLine, _startPos); _sharedKeywordToken.keyword = keyword; return _sharedKeywordToken; } @@ -2596,10 +2602,12 @@ class Tokenizer } OpCode op = detectOp(ch); if (op != OpCode.NONE) { - _sharedOpToken.setPos(_line, oldPos); + _sharedOpToken.setPos(_startLine, _startPos); _sharedOpToken.opCode = op; return _sharedOpToken; } + + // TODO: for tolerant parsing, return error token return null; } diff --git a/src/ddebug/windows/windebug.d b/src/ddebug/windows/windebug.d new file mode 100644 index 0000000..d7622fe --- /dev/null +++ b/src/ddebug/windows/windebug.d @@ -0,0 +1,190 @@ +// just an attempt to implement D debugger for win32 +module ddebug.windows.windebug; + +import win32.windows; + +import std.utf; + +version(Windows): + + +class WinDebugger { + this() { + } + + STARTUPINFOW _si; + PROCESS_INFORMATION _pi; + + bool startDebugging(string exefile, string args) { + _stopRequested = false; + _si = STARTUPINFOW.init; + _si.cb = _si.sizeof; + _pi = PROCESS_INFORMATION.init; + + string cmdline = "\"" ~ exefile ~ "\""; + if (args.length > 0) + cmdline = cmdline ~ " " ~ args; + wchar[] exefilew = cast(wchar[])toUTF16(exefile); + exefilew ~= cast(dchar)0; + wchar[] cmdlinew = cast(wchar[])toUTF16(cmdline); + cmdlinew ~= cast(dchar)0; + if (!CreateProcessW(cast(const wchar*)exefilew.ptr, + cmdlinew.ptr, + cast(SECURITY_ATTRIBUTES*)NULL, cast(SECURITY_ATTRIBUTES*)NULL, + FALSE, + DEBUG_ONLY_THIS_PROCESS, + NULL, + cast(const wchar*)NULL, &_si, &_pi)) { + return false; + } + return true; + } + + uint onCreateThreadDebugEvent(ref DEBUG_EVENT debug_event) { + return DBG_CONTINUE; + } + uint onCreateProcessDebugEvent(ref DEBUG_EVENT debug_event) { + return DBG_CONTINUE; + } + uint onExitThreadDebugEvent(ref DEBUG_EVENT debug_event) { + return DBG_CONTINUE; + } + uint onExitProcessDebugEvent(ref DEBUG_EVENT debug_event) { + return DBG_CONTINUE; + } + uint onLoadDllDebugEvent(ref DEBUG_EVENT debug_event) { + return DBG_CONTINUE; + } + uint onUnloadDllDebugEvent(ref DEBUG_EVENT debug_event) { + return DBG_CONTINUE; + } + uint onOutputDebugStringEvent(ref DEBUG_EVENT debug_event) { + return DBG_CONTINUE; + } + uint onRipEvent(ref DEBUG_EVENT debug_event) { + return DBG_TERMINATE_PROCESS; + } + + void processDebugEvent(ref DEBUG_EVENT debug_event) { + switch (debug_event.dwDebugEventCode) + { + case EXCEPTION_DEBUG_EVENT: + // Process the exception code. When handling + // exceptions, remember to set the continuation + // status parameter (dwContinueStatus). This value + // is used by the ContinueDebugEvent function. + + switch(debug_event.Exception.ExceptionRecord.ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + // First chance: Pass this on to the system. + // Last chance: Display an appropriate error. + break; + + case EXCEPTION_BREAKPOINT: + // First chance: Display the current + // instruction and register values. + break; + + case EXCEPTION_DATATYPE_MISALIGNMENT: + // First chance: Pass this on to the system. + // Last chance: Display an appropriate error. + break; + + case EXCEPTION_SINGLE_STEP: + // First chance: Update the display of the + // current instruction and register values. + break; + + case DBG_CONTROL_C: + // First chance: Pass this on to the system. + // Last chance: Display an appropriate error. + break; + + default: + // Handle other exceptions. + break; + } + + break; + + case CREATE_THREAD_DEBUG_EVENT: + // As needed, examine or change the thread's registers + // with the GetThreadContext and SetThreadContext functions; + // and suspend and resume thread execution with the + // SuspendThread and ResumeThread functions. + + _continueStatus = onCreateThreadDebugEvent(debug_event); + break; + + case CREATE_PROCESS_DEBUG_EVENT: + // As needed, examine or change the registers of the + // process's initial thread with the GetThreadContext and + // SetThreadContext functions; read from and write to the + // process's virtual memory with the ReadProcessMemory and + // WriteProcessMemory functions; and suspend and resume + // thread execution with the SuspendThread and ResumeThread + // functions. Be sure to close the handle to the process image + // file with CloseHandle. + + _continueStatus = onCreateProcessDebugEvent(debug_event); + break; + + case EXIT_THREAD_DEBUG_EVENT: + // Display the thread's exit code. + + _continueStatus = onExitThreadDebugEvent(debug_event); + break; + + case EXIT_PROCESS_DEBUG_EVENT: + // Display the process's exit code. + + _continueStatus = onExitProcessDebugEvent(debug_event); + break; + + case LOAD_DLL_DEBUG_EVENT: + // Read the debugging information included in the newly + // loaded DLL. Be sure to close the handle to the loaded DLL + // with CloseHandle. + + _continueStatus = onLoadDllDebugEvent(debug_event); + break; + + case UNLOAD_DLL_DEBUG_EVENT: + // Display a message that the DLL has been unloaded. + + _continueStatus = onUnloadDllDebugEvent(debug_event); + break; + + case OUTPUT_DEBUG_STRING_EVENT: + // Display the output debugging string. + + _continueStatus = onOutputDebugStringEvent(debug_event); + break; + + case RIP_EVENT: + _continueStatus = onRipEvent(debug_event); + break; + default: + // UNKNOWN EVENT + break; + } + } + + uint _continueStatus; + bool _stopRequested; + + bool enterDebugLoop() { + _continueStatus = DBG_CONTINUE; + DEBUG_EVENT debug_event; + for(;;) + { + if (!WaitForDebugEvent(&debug_event, INFINITE)) + return false; + processDebugEvent(debug_event); + ContinueDebugEvent(debug_event.dwProcessId, + debug_event.dwThreadId, + _continueStatus); + } + } +}