├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── LuaDebugAttacher_x64 ├── LuaDebugAttacher_x64.vcxproj ├── LuaDebugAttacher_x64.vcxproj.filters └── main.cpp ├── LuaDebugHelper_x64 ├── LuaDebugHelper_x64.vcxproj └── LuaDebugHelper_x64.vcxproj.filters ├── LuaDebugHelper_x86 ├── LuaDebugHelper_x86.vcxproj ├── LuaDebugHelper_x86.vcxproj.filters └── dllmain.cpp ├── LuaDkmDebugger.sln ├── LuaDkmDebugger ├── LuaDkmDebugger.csproj ├── Properties │ └── AssemblyInfo.cs └── source.extension.vsixmanifest ├── LuaDkmDebugger17 ├── LuaDkmDebugger17.csproj ├── Properties │ └── AssemblyInfo.cs └── source.extension.vsixmanifest ├── LuaDkmDebuggerCommon ├── LuaDkmDebuggerCommon.projitems ├── LuaDkmDebuggerCommon.shproj ├── LuaDkmDebuggerPackage.cs └── ToolWindows │ ├── ScriptListWindow.cs │ ├── ScriptListWindowControl.xaml │ ├── ScriptListWindowControl.xaml.cs │ └── ScriptListWindowState.cs ├── LuaDkmDebuggerComponent ├── AttachmentHelpers.cs ├── Bytecode.cs ├── BytecodeSchema.cs ├── DebugHelpers.cs ├── Dia2Lib.dll ├── EvaluationHelpers.cs ├── ExpressionEvaluation.cs ├── Guids.cs ├── LocalComponent.cs ├── LocalComponent.vsdconfigxml ├── LocalWorkerComponent.cs ├── LocalWorkerComponent.vsdconfigxml ├── Log.cs ├── LuaConstants.cs ├── LuaDkmDebuggerComponent.csproj ├── LuaSymbolStore.cs ├── LuaValues.cs ├── Messages.cs ├── Properties │ └── AssemblyInfo.cs ├── RemoteComponent.cs └── RemoteComponent.vsdconfigxml ├── LuaDkmDebuggerShared ├── .pkgdef ├── LuaDkmDebugger.vsct └── license.txt ├── README.md ├── Tests ├── ExpressionEvaluationUnitTests.cs ├── Properties │ └── AssemblyInfo.cs ├── Tests.csproj └── packages.config └── resource ├── front_image.png ├── front_image_2.png └── front_image_3.png /.gitignore: -------------------------------------------------------------------------------- 1 | /LuaDkmDebugger/bin 2 | /LuaDkmDebugger/obj 3 | /LuaDkmDebuggerComponent/bin 4 | /LuaDkmDebuggerComponent/obj 5 | /.vs 6 | /Tests/bin 7 | /Tests/obj 8 | /TestResults 9 | /packages 10 | /Debug 11 | /LuaDebugHelper_x86/Debug 12 | /LuaDebugHelper_x86/Release 13 | *.user 14 | *.ilk 15 | *.pdb 16 | *.dll 17 | *.exp 18 | *.lib 19 | *.iobj 20 | *.ipdb 21 | /LuaDebugAttacher_x64/x64 22 | /LuaDebugHelper_x64/x64 23 | /builds 24 | /LuaDkmDebugger17/bin 25 | /LuaDkmDebugger17/obj 26 | /LuaDkmDebuggerShared/*.exe 27 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.9.9] - 2021-11-18 4 | 5 | ### Added 6 | 7 | - Added filter to the script list panel 8 | - Columns in the script list are now sortable 9 | - Added support for Visual Studio 2022 10 | 11 | ### Changed 12 | 13 | - Fixed the order of locals lookup to preserve shadowing 14 | 15 | ## [0.9.8] - 2021-07-17 16 | 17 | ### Added 18 | - Mouse hover evaluation over members access after array indexing 19 | - Added support for __index function evaluation 20 | - Mouse hover performs this by default. Evaluation could have side-effects, new menu item can be used to disable auto-evaluation 21 | 22 | ### Changed 23 | - Fixed inability to open files from temp folder which have spaces in the name 24 | - Fixed helper library load from paths with non-ASCII characters 25 | - Table indexing will no longer lookup members of a metatable, __index will be used immediately 26 | - Fixed value writes in Lua 5.1 27 | - Fixed written string type tag in Lua 5.2/5.3/5.4 to include 'collectible' flag 28 | - Array length operator will report element count until first 'nil' 29 | - Improvements for LuaJIT support (2.0.5 x86/x64, 2.1.0 x86/x64): 30 | - Global variable lookup 31 | - Fixed breaking on internal runtime errors 32 | - Breakpoint and stepping support in multiple global states 33 | - Fixed missing call stack in error handling 34 | - Additional internal LuaJIT functions are hidden 35 | - Value write support 36 | - Fixed launch without 'Compatibility Mode' enabled 37 | - Function upvalue lookup support 38 | - Stability improvements 39 | 40 | ## [0.9.7] - 2021-06-14 41 | 42 | ### Added 43 | 44 | - Experimental support for LuaJIT (2.0.5 x86/x64, 2.1.0 x86/x64). Limitations include: 45 | - Scripts loaded from a file are not captured for breakpoint placement/stepping immediately 46 | - Only writes to 'number' are supported with LUA_GC64 47 | - Conditional breakpoints are not supported 48 | - Only one global state is supported for breakpoints/stepping 49 | - Breakpoints based on function name are not supported 50 | - Status bar for information about detected Lua library and helper attachment state 51 | 52 | ### Changed 53 | 54 | - Fixed a case when failed helper attachment to x64 process could suspend thread indefinitely 55 | 56 | ## [0.9.6] - 2021-04-06 57 | 58 | ### Added 59 | 60 | - Lua Script List panel can be opened from menu 61 | 62 | ### Changed 63 | 64 | - Improved script name mapping to potential file name 65 | 66 | ## [0.9.5] - 2021-03-21 67 | 68 | ### Added 69 | 70 | - String values can be modified 71 | - Support for assignments in watch and immediate windows 72 | - Support for table and string length operator 73 | 74 | ### Changed 75 | 76 | - Watch values are refreshed after modification of a related value 77 | - Fixed bool value modification in Lua 5.4 78 | - Fixed nested linear array indexing 79 | - Fixed breakpoints not being activated immediately after script load 80 | - Fixed invalid call error display location 81 | - Fixed error display location in Lua 5.1 82 | - Fixed table size and content display in Lua 5.2 (nil entries) 83 | 84 | ## [0.9.4] - 2020-09-02 85 | 86 | ### Changed 87 | 88 | - Added handler for unexpected exceptions in DIA SDK symbol load functions 89 | 90 | ## [0.9.3] - 2020-07-20 91 | 92 | ### Changed 93 | 94 | - Fixed performance issue with Lua error handling 95 | 96 | ## [0.9.2] - 2020-07-07 97 | 98 | ### Added 99 | 100 | - Optimization for table summary and element lookups using batched memory reads and lazy evaluation 101 | - Optimization for function locals list using batched memory reads 102 | - Function location display now works with Lua 5.1 103 | - Function name caching for Lua 5.1 stack frames 104 | - Conditional breakpoint support for Lua 5.4 105 | 106 | ### Changed 107 | 108 | - Fixed Lua version lookup and hook setup when Lua library is built with optimization 109 | - Fixed crash on function data lookup when debugging Lua 5.1 110 | - Fix for Lua state creation hook when library is built with optimization 111 | - Fix for internal Lua function display on 'Step Out' when debugging Lua 5.1 112 | - Fixed conditional breakpoints 113 | 114 | ## [0.9.1] - 2020-06-23 115 | 116 | ### Added 117 | 118 | - Support for full process dump debug 119 | 120 | ## [0.9.0] - 2020-06-22 121 | 122 | ### Added 123 | 124 | - Support for Lua 5.4 125 | - Lookup in __index metadata table in expression evaluation 126 | - Location display for Lua function values and Jump to Source context menu option 127 | - Alternative name is generated for unnamed scripts 128 | 129 | ### Changed 130 | 131 | - Fixes for Lua libraries built with optimizations 132 | - Fix for Lua sources without a valid name 133 | - Compatibility Mode improvements 134 | - Lua table address is now displayed in Watch 135 | - Stability fixes 136 | - Additional source file search locations 137 | - '.lua' is added to temporary file names if the Lua source name doesn't contain it already 138 | - Fixed long debugger startup when application is linked with /DEBUG:FULL and symbol file is large 139 | 140 | ## [0.8.8] - 2020-06-10 141 | 142 | ### Added 143 | 144 | - Support for Visual Studio 2017 145 | 146 | ### Changed 147 | 148 | - Fixed debug hook setup for Lua 5.1 and 5.2 149 | - Fixed empty files being saved to Temp folder 150 | 151 | ## [0.8.7] - 2020-06-10 152 | 153 | ### Added 154 | 155 | - Compatibility Mode for customized Lua interpreters 156 | - Added 'Initialize...' action to the extension menu that can be used if extension hasn't loaded yet 157 | 158 | ### Changed 159 | 160 | - Breakpoints can now be set before application has launched 161 | - Lua hooks are only set when breakpoints are active or stepping through code was performed 162 | 163 | ## [0.8.2] - 2020-06-06 164 | 165 | ### Added 166 | 167 | - Support for debug helper injection into x86 UWP apps (for breakpoints and stepping) 168 | 169 | ### Changed 170 | 171 | - Fixed debug helper initialization after Lua state is created 172 | 173 | ## [0.8.1] - 2020-06-05 174 | 175 | ### Added 176 | 177 | - Allow debugging when Lua is built as a DLL from [@fsfod](https://github.com/fsfod). 178 | 179 | ## [0.8.0] - 2020-06-03 180 | 181 | ### Added 182 | 183 | - Quick Info tooltip display with variable value evaluation on mouse over in the code window 184 | - Global environment variable lookup in expression evaluation 185 | - External C function/closure pointer display with 'Go To Source' provided by Visual Studio 186 | - Hexadecimal value support in expression evaluation 187 | - Assertion failure, error call and runtime errors are displayed as unhandled exceptions (Break on Error option) 188 | - User data meta-table value display 189 | - ':' member access is now handled in expression evaluation 190 | - When Lua library is used together with sol library, C++ object in user data is available (may work for custom user data if meta-table contains '__type.name' string with C++ type name) 191 | 192 | ### Changed 193 | 194 | - Fixed hexadecimal value formatting & crash 195 | - Expression evaluation optimization (caching call info, function data, upvalues and table values are not fetched until accessed) 196 | 197 | ## [0.7.7] - 2020-06-01 198 | 199 | ### Added 200 | 201 | - Lua module code is marked as user code 202 | - Support for debug helper injection into x64 UWP apps (for breakpoints and stepping) 203 | 204 | ### Changed 205 | 206 | - Cleaned up module instance creation 207 | - Silent debug helper injection failures will not hang the app on a suspended thread 208 | 209 | ## [0.7.5] - 2020-05-31 210 | 211 | ### Changed 212 | 213 | - Fixed crash when crash dump is debugged 214 | 215 | ## [0.7.4] - 2020-05-31 216 | 217 | ### Added 218 | 219 | - Support for conditional breakpoints 220 | - Added display of source files that haven't been found disk 221 | - Option to show hidden Lua call stack frames (for troubleshooting) 222 | 223 | ### Changed 224 | 225 | - Fixed hook crash when application Lua library is compiled with a different LUA_IDSIZE 226 | - Fixed conditional breakpoints in Lua 5.3 built for x64 227 | - Some documents can be linked to known scripts using content comparison even when script source name doesn't match any file on disk 228 | 229 | ## [0.6.0] - 2020-05-30 230 | 231 | ### Added 232 | 233 | - Support for breakpoints 234 | - Support for Step Over, Step In and Step Out 235 | - Debug logs 236 | - Function name cache for fast stack filter for Lua 5.2 and 5.3 237 | - Lua function upvalue support in expression evaluation and Locals window 238 | 239 | ### Changed 240 | 241 | - Fixed access to local functions list of a Lua function 242 | - Fixed enumeration size and double completion callback call in Locals window 243 | - Additional stack filter optimizations 244 | - Hide Lua call stack frames between internal Lua calls for Lua 5.3 245 | 246 | ## [0.4.1] - 2020-05-23 247 | 248 | ### Added 249 | 250 | - Support for Lua 5.2 in default configuration (LUA_NANTRICK is enabled for x86 and disabled for other platforms) 251 | - Support for Lua 5.1 252 | - Numeric and light user data values can be modified 253 | 254 | ### Changed 255 | 256 | - Fixed missing locals when their lifetime ends after current instruction (off-by-one error) 257 | - Lua global function is called 'main' instead of '__global' 258 | - Identifier names can contain '_' symbol 259 | - Stack frame location is now provided for Lua 5.3 finalizers and Lua 5.2/5.3 tail-called functions 260 | - Fixed out-of-order/missing call stack sections 261 | - Stability improvements when accessing target process memory 262 | - Reduce amount of expression evaluation requests to C++ debugger 263 | - Fixed amount of skipped frames on stacks with multiple language transitions 264 | - Support call stacks with transitions between different Lua states/threads 265 | 266 | ## [0.3.0] - 2020-05-22 267 | 268 | ### Added 269 | 270 | - Complex expression evaluation 271 | - Support for relative Lua script source paths 272 | 273 | ### Changed 274 | 275 | - Adjusted frame instruction pointer value to point on the currently executing instruction (fixes missing locals) 276 | 277 | ## [0.2.6] - 2020-05-21 278 | 279 | ### Changed 280 | 281 | - Fixed search for files without '@' at the start of the name 282 | 283 | ## [0.2.5] - 2020-05-21 284 | 285 | ### Changed 286 | 287 | - Fixed interaction with C++ debugger that broke C++ breakpoint placement 288 | 289 | ## [0.2.4] - 2020-05-21 290 | 291 | ### Added 292 | 293 | - Support for configuration file with additional script search directories 294 | 295 | ## [0.2.3] - 2020-05-21 296 | 297 | ### First Release 298 | 299 | ## Code changes 300 | 301 | [unreleased]https://github.com/olivierlacan/keep-a-changelog/compare/v0.9.7...HEAD 302 | 303 | [0.9.7]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.9.6...v0.9.7 304 | 305 | [0.9.6]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.9.5...v0.9.6 306 | 307 | [0.9.5]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.9.4...v0.9.5 308 | 309 | [0.9.4]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.9.3...v0.9.4 310 | 311 | [0.9.3]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.9.2...v0.9.3 312 | 313 | [0.9.2]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.9.1...v0.9.2 314 | 315 | [0.9.1]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.9.0...v0.9.1 316 | 317 | [0.9.0]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.8.8...v0.9.0 318 | 319 | [0.8.8]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.8.7...v0.8.8 320 | 321 | [0.8.7]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.8.2...v0.8.7 322 | 323 | [0.8.2]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.8.1...v0.8.2 324 | 325 | [0.8.1]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.8.0...v0.8.1 326 | 327 | [0.8.0]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.7.7...v0.8.0 328 | 329 | [0.7.7]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.7.5...v0.7.7 330 | 331 | [0.7.5]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.7.4...v0.7.5 332 | 333 | [0.7.4]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.6.0...v0.7.4 334 | 335 | [0.6.0]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.4.1...v0.6.0 336 | 337 | [0.4.1]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.3.0...v0.4.1 338 | 339 | [0.3.0]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.2.6...v0.3.0 340 | 341 | [0.2.6]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.2.5...v0.2.6 342 | 343 | [0.2.5]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.2.4...v0.2.5 344 | 345 | [0.2.4]https://github.com/WheretIB/LuaDkmDebugger/compare/v0.2.3...v0.2.4 346 | 347 | [0.2.3]https://github.com/WheretIB/LuaDkmDebugger/releases/tag/v0.2.3 348 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-2020 Vyacheslav Egorov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LuaDebugAttacher_x64/LuaDebugAttacher_x64.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 16.0 15 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F} 16 | LuaDebugAttacherx64 17 | 10.0.17763.0 18 | 19 | 20 | 21 | Application 22 | true 23 | v141 24 | Unicode 25 | 26 | 27 | Application 28 | false 29 | v141 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | $(SolutionDir)LuaDkmDebuggerShared\ 48 | 49 | 50 | false 51 | $(SolutionDir)LuaDkmDebuggerShared\ 52 | 53 | 54 | 55 | Level3 56 | true 57 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 58 | true 59 | 60 | 61 | Console 62 | true 63 | 64 | 65 | 66 | 67 | Level3 68 | true 69 | true 70 | true 71 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 72 | true 73 | 74 | 75 | Console 76 | true 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /LuaDebugAttacher_x64/LuaDebugAttacher_x64.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /LuaDebugAttacher_x64/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #pragma warning(disable: 4996) 9 | 10 | int AdjustAccessControlListForUwp(char *dllPath) 11 | { 12 | // Get current Access Control List 13 | PACL currentAcl = 0; 14 | PSECURITY_DESCRIPTOR securityDescriptor = 0; 15 | 16 | if(unsigned errorCode = GetNamedSecurityInfoA(dllPath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, ¤tAcl, 0, &securityDescriptor)) 17 | { 18 | OutputDebugStringA("Call to 'GetNamedSecurityInfoA' failed\n"); 19 | 20 | char* msgBuf = nullptr; 21 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msgBuf, 0, NULL); 22 | OutputDebugStringA(msgBuf); 23 | 24 | return 11; 25 | } 26 | 27 | // sid for all application packages 28 | PSID sid; 29 | 30 | if(ConvertStringSidToSidA("S-1-15-2-1", &sid) == 0) 31 | { 32 | OutputDebugStringA("Call to 'ConvertStringSidToSidA' failed\n"); 33 | 34 | char* msgBuf = nullptr; 35 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msgBuf, 0, NULL); 36 | OutputDebugStringA(msgBuf); 37 | 38 | return 12; 39 | } 40 | 41 | EXPLICIT_ACCESS_A access = { 0 }; 42 | 43 | access.grfAccessPermissions = GENERIC_READ | GENERIC_EXECUTE; 44 | access.grfAccessMode = SET_ACCESS; 45 | access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; 46 | access.Trustee.TrusteeForm = TRUSTEE_IS_SID; 47 | access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; 48 | access.Trustee.ptstrName = (LPSTR)sid; 49 | 50 | // Set new access entry in the Access Control List 51 | PACL updatedAcl = 0; 52 | 53 | if(unsigned errorCode = SetEntriesInAclA(1, &access, currentAcl, &updatedAcl)) 54 | { 55 | OutputDebugStringA("Call to 'SetEntriesInAclA' failed\n"); 56 | 57 | char* msgBuf = nullptr; 58 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msgBuf, 0, NULL); 59 | OutputDebugStringA(msgBuf); 60 | 61 | return 13; 62 | } 63 | 64 | // Set new Access Control List 65 | if(unsigned errorCode = SetNamedSecurityInfoA((LPSTR)dllPath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, updatedAcl, 0)) 66 | { 67 | OutputDebugStringA("Call to 'SetNamedSecurityInfoA' failed\n"); 68 | 69 | char* msgBuf = nullptr; 70 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msgBuf, 0, NULL); 71 | OutputDebugStringA(msgBuf); 72 | 73 | return 14; 74 | } 75 | 76 | if(securityDescriptor) 77 | LocalFree((HLOCAL)securityDescriptor); 78 | 79 | if(updatedAcl) 80 | LocalFree((HLOCAL)updatedAcl); 81 | 82 | return 0; 83 | } 84 | 85 | // processId loadLibraryAddress dllNameAddress dllPath 86 | int main(int argc, char** argv) 87 | { 88 | unsigned processId = strtoul(argv[1], nullptr, 10); 89 | uintptr_t loadLibraryAddress = _strtoui64(argv[2], nullptr, 10); 90 | uintptr_t dllNameAddress = _strtoui64(argv[3], nullptr, 10); 91 | char *dllPath = argv[4]; 92 | 93 | char buf[256]; 94 | sprintf(buf, "Attacher %s %s %s\n", argv[1], argv[2], argv[3]); 95 | OutputDebugStringA(buf); 96 | 97 | HANDLE process = OpenProcess(0x001F0FFF, false, processId); 98 | 99 | if(process == nullptr) 100 | { 101 | OutputDebugStringA("Call to 'OpenProcess' failed\n"); 102 | 103 | char* msgBuf = nullptr; 104 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msgBuf, 0, NULL); 105 | OutputDebugStringA(msgBuf); 106 | 107 | return 1; 108 | } 109 | 110 | // To inject dll into sandboxed UWP process, our dll has to have read&Execute permissions in 'All Application Packages' group 111 | AdjustAccessControlListForUwp(dllPath); 112 | 113 | auto thread = CreateRemoteThread(process, nullptr, 0, (DWORD(__stdcall*)(LPVOID))loadLibraryAddress, (void*)dllNameAddress, 0, nullptr); 114 | 115 | if(thread == nullptr) 116 | { 117 | OutputDebugStringA("Call to 'CreateRemoteThread' failed\n"); 118 | 119 | char* msgBuf = nullptr; 120 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msgBuf, 0, NULL); 121 | OutputDebugStringA(msgBuf); 122 | 123 | return 2; 124 | } 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /LuaDebugHelper_x64/LuaDebugHelper_x64.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 16.0 15 | {D0A573AC-3559-4D68-B617-0EEC056FA018} 16 | Win32Proj 17 | LuaDebugHelperx64 18 | 10.0.17763.0 19 | 20 | 21 | 22 | DynamicLibrary 23 | true 24 | v141 25 | Unicode 26 | 27 | 28 | DynamicLibrary 29 | false 30 | v141 31 | false 32 | Unicode 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | true 48 | $(SolutionDir)LuaDkmDebuggerShared\ 49 | 50 | 51 | false 52 | $(SolutionDir)LuaDkmDebuggerShared\ 53 | 54 | 55 | 56 | NotUsing 57 | Level3 58 | true 59 | _DEBUG;LUADEBUGHELPERX64_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 60 | true 61 | 62 | 63 | 64 | 65 | Windows 66 | true 67 | false 68 | 69 | 70 | 71 | 72 | NotUsing 73 | Level3 74 | true 75 | true 76 | true 77 | NDEBUG;LUADEBUGHELPERX64_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | Windows 85 | false 86 | false 87 | true 88 | false 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /LuaDebugHelper_x64/LuaDebugHelper_x64.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /LuaDebugHelper_x86/LuaDebugHelper_x86.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 16.0 15 | {043C0981-A01F-46F4-A19C-FDCD72973492} 16 | Win32Proj 17 | LuaDebugHelperx86 18 | 10.0.17763.0 19 | 20 | 21 | 22 | DynamicLibrary 23 | true 24 | v141 25 | Unicode 26 | 27 | 28 | DynamicLibrary 29 | false 30 | v141 31 | false 32 | Unicode 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | true 48 | $(SolutionDir)LuaDkmDebuggerShared\ 49 | 50 | 51 | false 52 | $(SolutionDir)LuaDkmDebuggerShared\ 53 | 54 | 55 | 56 | NotUsing 57 | Level3 58 | true 59 | WIN32;_DEBUG;LUADEBUGHELPERX86_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 60 | true 61 | 62 | 63 | 64 | 65 | Windows 66 | true 67 | false 68 | 69 | 70 | 71 | 72 | NotUsing 73 | Level3 74 | true 75 | true 76 | true 77 | WIN32;NDEBUG;LUADEBUGHELPERX86_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | 82 | 83 | Windows 84 | false 85 | false 86 | true 87 | false 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /LuaDebugHelper_x86/LuaDebugHelper_x86.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /LuaDkmDebugger.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30011.22 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaDkmDebugger", "LuaDkmDebugger\LuaDkmDebugger.csproj", "{C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaDkmDebuggerComponent", "LuaDkmDebuggerComponent\LuaDkmDebuggerComponent.csproj", "{671C8B4F-93F5-4AEC-82E6-6C65A80798E7}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {043C0981-A01F-46F4-A19C-FDCD72973492} = {043C0981-A01F-46F4-A19C-FDCD72973492} 11 | {D0A573AC-3559-4D68-B617-0EEC056FA018} = {D0A573AC-3559-4D68-B617-0EEC056FA018} 12 | EndProjectSection 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{78515BB1-C701-4ED0-AD5A-954106A97345}" 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LuaDebugHelper_x86", "LuaDebugHelper_x86\LuaDebugHelper_x86.vcxproj", "{043C0981-A01F-46F4-A19C-FDCD72973492}" 17 | EndProject 18 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LuaDebugHelper_x64", "LuaDebugHelper_x64\LuaDebugHelper_x64.vcxproj", "{D0A573AC-3559-4D68-B617-0EEC056FA018}" 19 | EndProject 20 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LuaDebugAttacher_x64", "LuaDebugAttacher_x64\LuaDebugAttacher_x64.vcxproj", "{4D877B09-CA72-4416-B2F9-B4E243C0D51F}" 21 | EndProject 22 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "LuaDkmDebuggerCommon", "LuaDkmDebuggerCommon\LuaDkmDebuggerCommon.shproj", "{0E812732-115F-4F38-A162-7C335EEE87BC}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaDkmDebugger17", "LuaDkmDebugger17\LuaDkmDebugger17.csproj", "{2979BE80-DC0A-4096-8A07-439FEA4E4080}" 25 | EndProject 26 | Global 27 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 28 | LuaDkmDebuggerCommon\LuaDkmDebuggerCommon.projitems*{0e812732-115f-4f38-a162-7c335eee87bc}*SharedItemsImports = 13 29 | LuaDkmDebuggerCommon\LuaDkmDebuggerCommon.projitems*{2979be80-dc0a-4096-8a07-439fea4e4080}*SharedItemsImports = 4 30 | LuaDkmDebuggerCommon\LuaDkmDebuggerCommon.projitems*{c3330bb3-cdce-40b5-9dc0-c19db8eb0987}*SharedItemsImports = 4 31 | EndGlobalSection 32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 33 | Debug|Any CPU = Debug|Any CPU 34 | Debug|x64 = Debug|x64 35 | Debug|x86 = Debug|x86 36 | Release|Any CPU = Release|Any CPU 37 | Release|x64 = Release|x64 38 | Release|x86 = Release|x86 39 | EndGlobalSection 40 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 41 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Debug|x64.ActiveCfg = Debug|Any CPU 44 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Debug|x64.Build.0 = Debug|Any CPU 45 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Debug|x86.ActiveCfg = Debug|Any CPU 46 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Debug|x86.Build.0 = Debug|Any CPU 47 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Release|x64.ActiveCfg = Release|Any CPU 50 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Release|x64.Build.0 = Release|Any CPU 51 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Release|x86.ActiveCfg = Release|Any CPU 52 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987}.Release|x86.Build.0 = Release|Any CPU 53 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 54 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Debug|Any CPU.Build.0 = Debug|Any CPU 55 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Debug|x64.ActiveCfg = Debug|Any CPU 56 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Debug|x64.Build.0 = Debug|Any CPU 57 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Debug|x86.ActiveCfg = Debug|Any CPU 58 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Debug|x86.Build.0 = Debug|Any CPU 59 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Release|x64.ActiveCfg = Release|Any CPU 62 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Release|x64.Build.0 = Release|Any CPU 63 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Release|x86.ActiveCfg = Release|Any CPU 64 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7}.Release|x86.Build.0 = Release|Any CPU 65 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 66 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Debug|Any CPU.Build.0 = Debug|Any CPU 67 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Debug|x64.ActiveCfg = Debug|Any CPU 68 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Debug|x64.Build.0 = Debug|Any CPU 69 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Debug|x86.ActiveCfg = Debug|Any CPU 70 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Debug|x86.Build.0 = Debug|Any CPU 71 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Release|Any CPU.ActiveCfg = Release|Any CPU 72 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Release|Any CPU.Build.0 = Release|Any CPU 73 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Release|x64.ActiveCfg = Release|Any CPU 74 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Release|x64.Build.0 = Release|Any CPU 75 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Release|x86.ActiveCfg = Release|Any CPU 76 | {78515BB1-C701-4ED0-AD5A-954106A97345}.Release|x86.Build.0 = Release|Any CPU 77 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Debug|Any CPU.ActiveCfg = Release|Win32 78 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Debug|Any CPU.Build.0 = Release|Win32 79 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Debug|x64.ActiveCfg = Release|Win32 80 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Debug|x64.Build.0 = Release|Win32 81 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Debug|x86.ActiveCfg = Release|Win32 82 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Debug|x86.Build.0 = Release|Win32 83 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Release|Any CPU.ActiveCfg = Release|Win32 84 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Release|Any CPU.Build.0 = Release|Win32 85 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Release|x64.ActiveCfg = Release|Win32 86 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Release|x64.Build.0 = Release|Win32 87 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Release|x86.ActiveCfg = Release|Win32 88 | {043C0981-A01F-46F4-A19C-FDCD72973492}.Release|x86.Build.0 = Release|Win32 89 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Debug|Any CPU.ActiveCfg = Release|x64 90 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Debug|Any CPU.Build.0 = Release|x64 91 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Debug|x64.ActiveCfg = Release|x64 92 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Debug|x64.Build.0 = Release|x64 93 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Debug|x86.ActiveCfg = Release|x64 94 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Debug|x86.Build.0 = Release|x64 95 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Release|Any CPU.ActiveCfg = Release|x64 96 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Release|Any CPU.Build.0 = Release|x64 97 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Release|x64.ActiveCfg = Release|x64 98 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Release|x64.Build.0 = Release|x64 99 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Release|x86.ActiveCfg = Release|x64 100 | {D0A573AC-3559-4D68-B617-0EEC056FA018}.Release|x86.Build.0 = Release|x64 101 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Debug|Any CPU.ActiveCfg = Release|x64 102 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Debug|Any CPU.Build.0 = Release|x64 103 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Debug|x64.ActiveCfg = Release|x64 104 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Debug|x64.Build.0 = Release|x64 105 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Debug|x86.ActiveCfg = Release|x64 106 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Debug|x86.Build.0 = Release|x64 107 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Release|Any CPU.ActiveCfg = Release|x64 108 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Release|Any CPU.Build.0 = Release|x64 109 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Release|x64.ActiveCfg = Release|x64 110 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Release|x64.Build.0 = Release|x64 111 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Release|x86.ActiveCfg = Release|x64 112 | {4D877B09-CA72-4416-B2F9-B4E243C0D51F}.Release|x86.Build.0 = Release|x64 113 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 114 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Debug|Any CPU.Build.0 = Debug|Any CPU 115 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Debug|x64.ActiveCfg = Debug|Any CPU 116 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Debug|x64.Build.0 = Debug|Any CPU 117 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Debug|x86.ActiveCfg = Debug|x86 118 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Debug|x86.Build.0 = Debug|x86 119 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Release|Any CPU.ActiveCfg = Release|Any CPU 120 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Release|Any CPU.Build.0 = Release|Any CPU 121 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Release|x64.ActiveCfg = Release|Any CPU 122 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Release|x64.Build.0 = Release|Any CPU 123 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Release|x86.ActiveCfg = Release|x86 124 | {2979BE80-DC0A-4096-8A07-439FEA4E4080}.Release|x86.Build.0 = Release|x86 125 | EndGlobalSection 126 | GlobalSection(SolutionProperties) = preSolution 127 | HideSolutionNode = FALSE 128 | EndGlobalSection 129 | GlobalSection(ExtensibilityGlobals) = postSolution 130 | SolutionGuid = {B1CF0B09-5626-4E41-9F3E-07B9A680A430} 131 | EndGlobalSection 132 | EndGlobal 133 | -------------------------------------------------------------------------------- /LuaDkmDebugger/LuaDkmDebugger.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 16.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | Debug 10 | AnyCPU 11 | 2.0 12 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 13 | {C3330BB3-CDCE-40B5-9DC0-C19DB8EB0987} 14 | Library 15 | Properties 16 | LuaDkmDebugger 17 | LuaDkmDebugger 18 | v4.7.2 19 | true 20 | true 21 | true 22 | false 23 | false 24 | true 25 | true 26 | Program 27 | $(DevEnvDir)devenv.exe 28 | /rootsuffix Exp 29 | 30 | 31 | true 32 | full 33 | false 34 | bin\Debug\ 35 | DEBUG;TRACE 36 | prompt 37 | 4 38 | 39 | 40 | pdbonly 41 | true 42 | bin\Release\ 43 | TRACE 44 | prompt 45 | 4 46 | 47 | 48 | 49 | 50 | 51 | 52 | Designer 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 10.0.3 67 | 68 | 69 | 11.0.50728 70 | 71 | 72 | 15.8.525 73 | 74 | 75 | 15.8.525 76 | 77 | 78 | 15.9.28307 79 | 80 | 81 | 15.8.525 82 | 83 | 84 | 15.8.209 85 | 86 | 87 | 88 | 89 | 90 | .pkgdef 91 | true 92 | 93 | 94 | license.txt 95 | true 96 | 97 | 98 | LuaDebugAttacher_x64.exe 99 | true 100 | 101 | 102 | LuaDebugHelper_x64.dll 103 | true 104 | 105 | 106 | LuaDebugHelper_x86.dll 107 | true 108 | 109 | 110 | 111 | 112 | LuaDkmDebugger.vsct 113 | LuaDkmDebuggerMenus.ctmenu 114 | 115 | 116 | 117 | 118 | {671c8b4f-93f5-4aec-82e6-6c65a80798e7} 119 | LuaDkmDebuggerComponent 120 | 121 | 122 | 123 | 124 | 125 | 132 | -------------------------------------------------------------------------------- /LuaDkmDebugger/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LuaDkmDebugger")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LuaDkmDebugger")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Build and Revision Numbers 30 | // by using the '*' as shown below: 31 | // [assembly: AssemblyVersion("1.0.*")] 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /LuaDkmDebugger/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | C++ debugger extensions for Lua 6 | This extension adds integrated debugging for Lua scripts executing inside C++ applications with Lua library. 7 | license.txt 8 | https://raw.githubusercontent.com/WheretIB/LuaDkmDebugger/master/CHANGELOG.md 9 | lua, debugger 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LuaDkmDebugger17/LuaDkmDebugger17.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 17.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | Debug 10 | AnyCPU 11 | 2.0 12 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 13 | {2979BE80-DC0A-4096-8A07-439FEA4E4080} 14 | Library 15 | Properties 16 | LuaDkmDebugger17 17 | LuaDkmDebugger17 18 | v4.7.2 19 | true 20 | true 21 | true 22 | false 23 | false 24 | true 25 | true 26 | Program 27 | $(DevEnvDir)devenv.exe 28 | /rootsuffix Exp 29 | 30 | 31 | true 32 | full 33 | false 34 | bin\Debug\ 35 | DEBUG;TRACE 36 | prompt 37 | 4 38 | 39 | 40 | pdbonly 41 | true 42 | bin\Release\ 43 | TRACE 44 | prompt 45 | 4 46 | 47 | 48 | 49 | 50 | 51 | 52 | Designer 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | .pkgdef 71 | true 72 | 73 | 74 | license.txt 75 | true 76 | 77 | 78 | LuaDebugAttacher_x64.exe 79 | true 80 | 81 | 82 | LuaDebugHelper_x64.dll 83 | true 84 | 85 | 86 | LuaDebugHelper_x86.dll 87 | true 88 | 89 | 90 | 91 | 92 | LuaDkmDebugger.vsct 93 | LuaDkmDebuggerMenus.ctmenu 94 | 95 | 96 | 97 | 98 | {671c8b4f-93f5-4aec-82e6-6c65a80798e7} 99 | LuaDkmDebuggerComponent 100 | 101 | 102 | 103 | 104 | 105 | 112 | -------------------------------------------------------------------------------- /LuaDkmDebugger17/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LuaDkmDebugger17")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LuaDkmDebugger17")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Build and Revision Numbers 30 | // by using the '*' as shown below: 31 | // [assembly: AssemblyVersion("1.0.*")] 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /LuaDkmDebugger17/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | C++ debugger extensions for Lua 6 | This extension adds integrated debugging for Lua scripts executing inside C++ applications with Lua library. 7 | license.txt 8 | https://raw.githubusercontent.com/WheretIB/LuaDkmDebugger/master/CHANGELOG.md 9 | lua, debugger 10 | 11 | 12 | 13 | amd64 14 | 15 | 16 | amd64 17 | 18 | 19 | amd64 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /LuaDkmDebuggerCommon/LuaDkmDebuggerCommon.projitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | 0e812732-115f-4f38-a162-7c335eee87bc 7 | 8 | 9 | LuaDkmDebuggerCommon 10 | 11 | 12 | 13 | 14 | 15 | ScriptListWindowControl.xaml 16 | 17 | 18 | 19 | 20 | 21 | Designer 22 | MSBuild:Compile 23 | 24 | 25 | -------------------------------------------------------------------------------- /LuaDkmDebuggerCommon/LuaDkmDebuggerCommon.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0e812732-115f-4f38-a162-7c335eee87bc 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LuaDkmDebuggerCommon/ToolWindows/ScriptListWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using Microsoft.VisualStudio.Imaging; 4 | using Microsoft.VisualStudio.Shell; 5 | 6 | namespace LuaDkmDebugger.ToolWindows 7 | { 8 | [Guid(WindowGuidString)] 9 | public class ScriptListWindow : ToolWindowPane 10 | { 11 | public const string WindowGuidString = "E579870C-6E14-4EA5-BD89-86C627D50EAF"; 12 | public const string Title = "Lua Script List"; 13 | 14 | public ScriptListWindow(ScriptListWindowState state) : base() 15 | { 16 | Caption = Title; 17 | BitmapImageMoniker = KnownMonikers.ImageIcon; 18 | 19 | Content = new ScriptListWindowControl(state); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LuaDkmDebuggerCommon/ToolWindows/ScriptListWindowControl.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Lua: --- 18 | 19 | 20 | | 21 | 22 | 23 | Attach: --- 24 | 25 | 26 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /LuaDkmDebuggerCommon/ToolWindows/ScriptListWindowControl.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using System; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | 10 | namespace LuaDkmDebugger.ToolWindows 11 | { 12 | /// 13 | /// Interaction logic for ScriptListWindow.xaml 14 | /// 15 | public partial class ScriptListWindowControl : UserControl 16 | { 17 | private ScriptListWindowState _state; 18 | private GridViewColumnHeader _activeHeader; 19 | private ListSortDirection _activeDirection = ListSortDirection.Ascending; 20 | 21 | public ScriptListWindowControl(ScriptListWindowState state) 22 | { 23 | _state = state; 24 | 25 | InitializeComponent(); 26 | 27 | ScriptList.ItemsSource = _state.scripts; 28 | 29 | StatusText1.Text = _state.statusText1; 30 | StatusText2.Text = _state.statusText2; 31 | } 32 | 33 | private void ListViewItem_DoubleClick(object sender, RoutedEventArgs args) 34 | { 35 | ThreadHelper.ThrowIfNotOnUIThread(); 36 | 37 | if (sender is ListViewItem row) 38 | { 39 | if (row.Content is ScriptEntry scriptEntry) 40 | { 41 | try 42 | { 43 | if (scriptEntry.status == "Stored in memory" && scriptEntry.content.Length > 0) 44 | { 45 | File.WriteAllText(scriptEntry.path, scriptEntry.content); 46 | 47 | scriptEntry.status = "Loaded from memory"; 48 | } 49 | 50 | var cmdobj = _state.dte.Commands.Item("File.OpenFile"); 51 | 52 | // Support filenames and directories with whitespaces in path. 53 | string name = $"\"{scriptEntry.path}\""; 54 | object none = null; 55 | 56 | _state.dte.Commands.Raise(cmdobj.Guid, cmdobj.ID, name, none); 57 | } 58 | catch (Exception e) 59 | { 60 | Debug.WriteLine($"Failed to open file with: {e}"); 61 | } 62 | } 63 | } 64 | } 65 | 66 | private void ListViewItem_ColumnClick(object sender, RoutedEventArgs args) 67 | { 68 | // WPF doesn't provide auto-sortable lists... 69 | if (args.OriginalSource is GridViewColumnHeader headerClicked) 70 | { 71 | if (headerClicked.Role != GridViewColumnHeaderRole.Padding) 72 | { 73 | ListSortDirection direction = headerClicked != _activeHeader || _activeDirection == ListSortDirection.Descending ? ListSortDirection.Ascending : ListSortDirection.Descending; 74 | 75 | var columnBinding = headerClicked.Column.DisplayMemberBinding as Binding; 76 | var sortBy = columnBinding?.Path.Path ?? headerClicked.Column.Header as string; 77 | 78 | ICollectionView dataView = CollectionViewSource.GetDefaultView(ScriptList.ItemsSource); 79 | dataView.SortDescriptions.Clear(); 80 | SortDescription sd = new SortDescription(sortBy, direction); 81 | dataView.SortDescriptions.Add(sd); 82 | dataView.Refresh(); 83 | 84 | _activeHeader = headerClicked; 85 | _activeDirection = direction; 86 | } 87 | } 88 | } 89 | 90 | private void SearchTerm_TextChanged(object sender, TextChangedEventArgs e) 91 | { 92 | CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(ScriptList.ItemsSource); 93 | view.Filter = (item) => 94 | { 95 | if (item is ScriptEntry scriptEntry) 96 | return scriptEntry.name.Contains(SearchTerm.Text) || scriptEntry.path.Contains(SearchTerm.Text); 97 | 98 | return true; 99 | }; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /LuaDkmDebuggerCommon/ToolWindows/ScriptListWindowState.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | 4 | namespace LuaDkmDebugger.ToolWindows 5 | { 6 | public class ScriptEntry : INotifyPropertyChanged 7 | { 8 | private string _name; 9 | public string name { get { return _name; } set { _name = value; Changed("name"); } } 10 | private string _path; 11 | public string path { get { return _path; } set { _path = value; Changed("path"); } } 12 | private string _status; 13 | public string status { get { return _status; } set { _status = value; Changed("status"); } } 14 | private string _content; 15 | public string content { get { return _content; } set { _content = value; Changed("content"); } } 16 | 17 | public event PropertyChangedEventHandler PropertyChanged; 18 | 19 | private void Changed(string propertyName) 20 | { 21 | if (PropertyChanged != null) 22 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 23 | } 24 | } 25 | 26 | public class ScriptListWindowState 27 | { 28 | public EnvDTE80.DTE2 dte; 29 | 30 | public ObservableCollection scripts = new ObservableCollection(); 31 | public string statusText1 = "Lua: ---"; 32 | public string statusText2 = "Attach: ---"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/AttachmentHelpers.cs: -------------------------------------------------------------------------------- 1 | using Dia2Lib; 2 | using Microsoft.VisualStudio.Debugger; 3 | using Microsoft.VisualStudio.Debugger.Breakpoints; 4 | using Microsoft.VisualStudio.Debugger.Native; 5 | using System; 6 | using System.Diagnostics; 7 | using System.Runtime.InteropServices; 8 | using System.Security.AccessControl; 9 | 10 | namespace LuaDkmDebuggerComponent 11 | { 12 | internal class Kernel32 13 | { 14 | [DllImport("kernel32.dll")] 15 | public static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId); 16 | 17 | [DllImport("kernel32.dll", SetLastError = true)] 18 | internal static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, UIntPtr dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); 19 | 20 | [DllImport("kernel32.dll", SetLastError = true)] 21 | internal static extern IntPtr LocalFree(IntPtr hMem); 22 | } 23 | 24 | internal class Advapi32 25 | { 26 | public enum SE_OBJECT_TYPE 27 | { 28 | SE_UNKNOWN_OBJECT_TYPE = 0, 29 | SE_FILE_OBJECT, 30 | SE_SERVICE, 31 | SE_PRINTER, 32 | SE_REGISTRY_KEY, 33 | SE_LMSHARE, 34 | SE_KERNEL_OBJECT, 35 | SE_WINDOW_OBJECT, 36 | SE_DS_OBJECT, 37 | SE_DS_OBJECT_ALL, 38 | SE_PROVIDER_DEFINED_OBJECT, 39 | SE_WMIGUID_OBJECT, 40 | SE_REGISTRY_WOW64_32KEY 41 | } 42 | 43 | internal enum MULTIPLE_TRUSTEE_OPERATION 44 | { 45 | NO_MULTIPLE_TRUSTEE, 46 | TRUSTEE_IS_IMPERSONATE 47 | } 48 | 49 | internal enum TRUSTEE_FORM 50 | { 51 | TRUSTEE_IS_SID = 0, 52 | TRUSTEE_IS_NAME, 53 | TRUSTEE_BAD_FORM, 54 | TRUSTEE_IS_OBJECTS_AND_SID, 55 | TRUSTEE_IS_OBJECTS_AND_NAME 56 | } 57 | 58 | internal enum TRUSTEE_TYPE 59 | { 60 | TRUSTEE_IS_UNKNOWN = 0, 61 | TRUSTEE_IS_USER, 62 | TRUSTEE_IS_GROUP, 63 | TRUSTEE_IS_DOMAIN, 64 | TRUSTEE_IS_ALIAS, 65 | TRUSTEE_IS_WELL_KNOWN_GROUP, 66 | TRUSTEE_IS_DELETED, 67 | TRUSTEE_IS_INVALID, 68 | TRUSTEE_IS_COMPUTER 69 | } 70 | 71 | internal enum ACCESS_MODE : uint 72 | { 73 | NOT_USED_ACCESS = 0, 74 | GRANT_ACCESS, 75 | SET_ACCESS, 76 | REVOKE_ACCESS, 77 | SET_AUDIT_SUCCESS, 78 | SET_AUDIT_FAILURE 79 | } 80 | 81 | internal enum ACCESS_MASK : uint 82 | { 83 | GENERIC_ALL = 0x10000000, //268435456, 84 | GENERIC_READ = 0x80000000, //2147483648L, 85 | GENERIC_WRITE = 0x40000000, //1073741824, 86 | GENERIC_EXECUTE = 0x20000000, //536870912, 87 | STANDARD_RIGHTS_READ = 0x00020000, //131072 88 | STANDARD_RIGHTS_WRITE = 0x00020000, 89 | SHARE_ACCESS_READ = 0x1200A9, // 1179817 90 | SHARE_ACCESS_WRITE = 0x1301BF, // 1245631 91 | SHARE_ACCESS_FULL = 0x1f01ff // 2032127 92 | } 93 | 94 | internal enum ACCESS_INHERITANCE : uint 95 | { 96 | NO_INHERITANCE = 0, 97 | OBJECT_INHERIT_ACE = 0x1, 98 | CONTAINER_INHERIT_ACE = 0x2, 99 | NO_PROPAGATE_INHERIT_ACE = 0x4, 100 | INHERIT_ONLY_ACE = 0x8, 101 | INHERITED_ACE = 0x10, 102 | SUB_OBJECTS_ONLY_INHERIT = ACCESS_INHERITANCE.OBJECT_INHERIT_ACE | ACCESS_INHERITANCE.INHERIT_ONLY_ACE, 103 | SUB_CONTAINERS_ONLY_INHERIT = ACCESS_INHERITANCE.CONTAINER_INHERIT_ACE | ACCESS_INHERITANCE.INHERIT_ONLY_ACE, 104 | SUB_CONTAINERS_AND_OBJECTS_INHERIT = ACCESS_INHERITANCE.CONTAINER_INHERIT_ACE | ACCESS_INHERITANCE.OBJECT_INHERIT_ACE, 105 | } 106 | 107 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 108 | internal struct TRUSTEE 109 | { 110 | public IntPtr MultipleTrustee; 111 | public MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation; 112 | public TRUSTEE_FORM TrusteeForm; 113 | public TRUSTEE_TYPE TrusteeType; 114 | public IntPtr Name; 115 | } 116 | 117 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 118 | internal struct EXPLICIT_ACCESS 119 | { 120 | public ACCESS_MASK AccessPermissions; 121 | public ACCESS_MODE AccessMode; 122 | public ACCESS_INHERITANCE Inheritance; 123 | public TRUSTEE trustee; 124 | } 125 | 126 | [DllImport("advapi32.dll", EntryPoint = "GetNamedSecurityInfoW", ExactSpelling = true, CharSet = CharSet.Unicode)] 127 | internal static extern int GetNamedSecurityInfo(string objectName, SE_OBJECT_TYPE objectType, System.Security.AccessControl.SecurityInfos securityInfo, out IntPtr sidOwner, out IntPtr sidGroup, out IntPtr dacl, out IntPtr sacl, out IntPtr securityDescriptor); 128 | 129 | [DllImport("advapi32.dll", EntryPoint = "SetNamedSecurityInfoW", ExactSpelling = true, CharSet = CharSet.Unicode)] 130 | internal static extern int SetNamedSecurityInfo(string objectName, SE_OBJECT_TYPE objectType, System.Security.AccessControl.SecurityInfos securityInfo, IntPtr sidOwner, IntPtr sidGroup, IntPtr dacl, IntPtr sacl); 131 | 132 | [DllImport("advapi32.dll", EntryPoint = "ConvertStringSidToSidW", ExactSpelling = true, CharSet = CharSet.Unicode)] 133 | internal static extern int ConvertStringSidToSid(string stringSid, out IntPtr sid); 134 | 135 | [DllImport("advapi32.dll", EntryPoint = "SetEntriesInAclW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] 136 | internal static extern int SetEntriesInAcl(int cCountOfExplicitEntries, ref EXPLICIT_ACCESS pListOfExplicitEntries, IntPtr oldAcl, out IntPtr newAcl); 137 | 138 | public static int AdjustAccessControlListForUwp(string dllPath) 139 | { 140 | // Get current Access Control List 141 | int errorCode = GetNamedSecurityInfo(dllPath, SE_OBJECT_TYPE.SE_FILE_OBJECT, SecurityInfos.DiscretionaryAcl, out _, out _, out IntPtr currentAcl, out _, out IntPtr securityDescriptor); 142 | 143 | if (errorCode != 0) 144 | { 145 | Debug.WriteLine("Call to 'GetNamedSecurityInfoA' failed"); 146 | 147 | return 11; 148 | } 149 | 150 | // sid for all application packages 151 | if (ConvertStringSidToSid("S-1-15-2-1", out IntPtr sid) == 0) 152 | { 153 | Debug.WriteLine("Call to 'ConvertStringSidToSidA' failed"); 154 | 155 | return 12; 156 | } 157 | 158 | EXPLICIT_ACCESS access = new EXPLICIT_ACCESS 159 | { 160 | AccessPermissions = ACCESS_MASK.GENERIC_READ | ACCESS_MASK.GENERIC_EXECUTE, 161 | AccessMode = ACCESS_MODE.SET_ACCESS, 162 | Inheritance = ACCESS_INHERITANCE.SUB_CONTAINERS_AND_OBJECTS_INHERIT, 163 | 164 | trustee = new TRUSTEE 165 | { 166 | TrusteeForm = TRUSTEE_FORM.TRUSTEE_IS_SID, 167 | TrusteeType = TRUSTEE_TYPE.TRUSTEE_IS_WELL_KNOWN_GROUP, 168 | Name = sid 169 | } 170 | }; 171 | 172 | // Set new access entry in the Access Control List 173 | errorCode = SetEntriesInAcl(1, ref access, currentAcl, out IntPtr updatedAcl); 174 | 175 | if (errorCode != 0) 176 | { 177 | Debug.WriteLine("Call to 'SetEntriesInAclA' failed"); 178 | 179 | return 13; 180 | } 181 | 182 | // Set new Access Control List 183 | errorCode = SetNamedSecurityInfo(dllPath, SE_OBJECT_TYPE.SE_FILE_OBJECT, SecurityInfos.DiscretionaryAcl, IntPtr.Zero, IntPtr.Zero, updatedAcl, IntPtr.Zero); 184 | 185 | if (errorCode != 0) 186 | { 187 | Debug.WriteLine("Call to 'SetNamedSecurityInfoA' failed"); 188 | 189 | return 14; 190 | } 191 | 192 | if (securityDescriptor != IntPtr.Zero) 193 | Kernel32.LocalFree(securityDescriptor); 194 | 195 | if (updatedAcl != IntPtr.Zero) 196 | Kernel32.LocalFree(updatedAcl); 197 | 198 | return 0; 199 | } 200 | } 201 | 202 | internal class AttachmentHelpers 203 | { 204 | internal static void ReleaseComObject(object obj) 205 | { 206 | if (obj != null && Marshal.IsComObject(obj)) 207 | Marshal.ReleaseComObject(obj); 208 | } 209 | 210 | internal static IDiaSymbol TryGetDiaSymbols(DkmModuleInstance moduleInstance, out string error) 211 | { 212 | if (moduleInstance == null) 213 | { 214 | error = $"TryGetDiaSymbols() Module instance is null"; 215 | return null; 216 | } 217 | 218 | if (moduleInstance.Module == null) 219 | { 220 | error = $"TryGetDiaSymbols() Module is null"; 221 | return null; 222 | } 223 | 224 | IDiaSession diaSession; 225 | try 226 | { 227 | diaSession = (IDiaSession)moduleInstance.Module.GetSymbolInterface(typeof(IDiaSession).GUID); 228 | } 229 | catch (InvalidCastException) 230 | { 231 | error = $"TryGetDiaSymbols() diaSession InvalidCastException"; 232 | return null; 233 | } 234 | 235 | diaSession.findChildren(null, SymTagEnum.SymTagExe, null, 0, out IDiaEnumSymbols exeSymEnum); 236 | 237 | if (exeSymEnum.count != 1) 238 | { 239 | error = $"TryGetDiaSymbols() exeSymEnum.count {exeSymEnum.count} != 1"; 240 | 241 | ReleaseComObject(diaSession); 242 | return null; 243 | } 244 | 245 | var symbol = exeSymEnum.Item(0); 246 | 247 | ReleaseComObject(exeSymEnum); 248 | ReleaseComObject(diaSession); 249 | 250 | error = null; 251 | return symbol; 252 | } 253 | 254 | internal static IDiaSymbol TryGetDiaSymbol(IDiaSymbol symbol, SymTagEnum symTag, string name, out string error) 255 | { 256 | symbol.findChildren(symTag, name, 1, out IDiaEnumSymbols enumSymbols); 257 | 258 | if (enumSymbols.count != 1) 259 | { 260 | error = $"TryGetDiaSymbols() enumSymbols.count {enumSymbols.count} != 1"; 261 | 262 | ReleaseComObject(enumSymbols); 263 | 264 | return null; 265 | } 266 | 267 | error = null; 268 | return enumSymbols.Item(0u); 269 | } 270 | 271 | internal static IDiaSymbol TryGetDiaFunctionSymbol(DkmModuleInstance moduleInstance, string name, out string error) 272 | { 273 | var moduleSymbols = TryGetDiaSymbols(moduleInstance, out error); 274 | 275 | if (moduleSymbols == null) 276 | return null; 277 | 278 | var functionSymbol = TryGetDiaSymbol(moduleSymbols, SymTagEnum.SymTagFunction, name, out error); 279 | 280 | if (functionSymbol == null) 281 | { 282 | ReleaseComObject(moduleSymbols); 283 | 284 | return null; 285 | } 286 | 287 | ReleaseComObject(moduleSymbols); 288 | 289 | return functionSymbol; 290 | } 291 | 292 | internal static ulong? TryGetFunctionAddress(DkmModuleInstance moduleInstance, string name, out string error) 293 | { 294 | try 295 | { 296 | var functionSymbol = TryGetDiaFunctionSymbol(moduleInstance, name, out error); 297 | 298 | if (functionSymbol == null) 299 | return null; 300 | 301 | uint rva = functionSymbol.relativeVirtualAddress; 302 | 303 | ReleaseComObject(functionSymbol); 304 | 305 | return moduleInstance.BaseAddress + rva; 306 | } 307 | catch (Exception ex) 308 | { 309 | error = "TryGetFunctionAddress() Unexpected error: " + ex.ToString(); 310 | } 311 | 312 | return null; 313 | } 314 | 315 | internal static ulong? TryGetFunctionAddressAtDebugStart(DkmModuleInstance moduleInstance, string name, out string error) 316 | { 317 | try 318 | { 319 | var functionSymbol = TryGetDiaFunctionSymbol(moduleInstance, name, out error); 320 | 321 | if (functionSymbol == null) 322 | return null; 323 | 324 | var functionStartSymbol = TryGetDiaSymbol(functionSymbol, SymTagEnum.SymTagFuncDebugStart, null, out error); 325 | 326 | if (functionStartSymbol == null) 327 | { 328 | ReleaseComObject(functionSymbol); 329 | 330 | return null; 331 | } 332 | 333 | uint rva = functionStartSymbol.relativeVirtualAddress; 334 | 335 | ReleaseComObject(functionStartSymbol); 336 | ReleaseComObject(functionSymbol); 337 | 338 | return moduleInstance.BaseAddress + rva; 339 | } 340 | catch (Exception ex) 341 | { 342 | error = "TryGetFunctionAddressAtDebugStart() Unexpected error: " + ex.ToString(); 343 | } 344 | 345 | return null; 346 | } 347 | 348 | internal static ulong? TryGetFunctionAddressAtDebugEnd(DkmModuleInstance moduleInstance, string name, out string error) 349 | { 350 | try 351 | { 352 | var functionSymbol = TryGetDiaFunctionSymbol(moduleInstance, name, out error); 353 | 354 | if (functionSymbol == null) 355 | return null; 356 | 357 | var functionEndSymbol = TryGetDiaSymbol(functionSymbol, SymTagEnum.SymTagFuncDebugEnd, null, out error); 358 | 359 | if (functionEndSymbol == null) 360 | { 361 | ReleaseComObject(functionSymbol); 362 | 363 | return null; 364 | } 365 | 366 | uint rva = functionEndSymbol.relativeVirtualAddress; 367 | 368 | ReleaseComObject(functionEndSymbol); 369 | ReleaseComObject(functionSymbol); 370 | 371 | return moduleInstance.BaseAddress + rva; 372 | } 373 | catch (Exception ex) 374 | { 375 | error = "TryGetFunctionAddressAtDebugEnd() Unexpected error: " + ex.ToString(); 376 | } 377 | 378 | return null; 379 | } 380 | 381 | internal static Guid? CreateHelperFunctionBreakpoint(DkmNativeModuleInstance nativeModuleInstance, string functionName) 382 | { 383 | var functionAddress = TryGetFunctionAddressAtDebugStart(nativeModuleInstance, functionName, out string error); 384 | 385 | if (functionAddress != null) 386 | { 387 | LocalComponent.log.Debug($"Creating breakpoint in '{functionName}'"); 388 | 389 | var nativeAddress = nativeModuleInstance.Process.CreateNativeInstructionAddress(functionAddress.Value); 390 | 391 | var breakpoint = DkmRuntimeInstructionBreakpoint.Create(Guids.luaSupportBreakpointGuid, null, nativeAddress, false, null); 392 | 393 | breakpoint.Enable(); 394 | 395 | return breakpoint.UniqueId; 396 | } 397 | else 398 | { 399 | var nativeFunctionAddress = FindFunctionAddress(nativeModuleInstance, functionName); 400 | 401 | if (nativeFunctionAddress != 0) 402 | { 403 | LocalComponent.log.Debug($"Creating 'native' breakpoint in '{functionName}'"); 404 | 405 | var nativeAddress = nativeModuleInstance.Process.CreateNativeInstructionAddress(nativeFunctionAddress); 406 | 407 | var breakpoint = DkmRuntimeInstructionBreakpoint.Create(Guids.luaSupportBreakpointGuid, null, nativeAddress, false, null); 408 | 409 | breakpoint.Enable(); 410 | 411 | return breakpoint.UniqueId; 412 | } 413 | else 414 | { 415 | LocalComponent.log.Warning($"Failed to create breakpoint in '{functionName}' with {error}"); 416 | } 417 | } 418 | 419 | return null; 420 | } 421 | 422 | internal static ulong FindFunctionAddress(DkmNativeModuleInstance nativeModuleInstance, string functionName) 423 | { 424 | var address = nativeModuleInstance.FindExportName(functionName, IgnoreDataExports: true); 425 | 426 | if (address != null) 427 | { 428 | LocalComponent.log.Debug($"Found helper library '{functionName}' function at 0x{address.CPUInstructionPart.InstructionPointer:x}"); 429 | 430 | return address.CPUInstructionPart.InstructionPointer; 431 | } 432 | 433 | LocalComponent.log.Warning($"Failed to find helper library '{functionName}' function"); 434 | 435 | return 0; 436 | } 437 | 438 | internal static ulong FindVariableAddress(DkmNativeModuleInstance nativeModuleInstance, string variableName) 439 | { 440 | var address = nativeModuleInstance.FindExportName(variableName, IgnoreDataExports: false); 441 | 442 | if (address != null) 443 | { 444 | LocalComponent.log.Debug($"Found helper library '{variableName}' variable at 0x{address.CPUInstructionPart.InstructionPointer:x}"); 445 | 446 | return address.CPUInstructionPart.InstructionPointer; 447 | } 448 | 449 | LocalComponent.log.Warning($"Failed to find helper library '{variableName}' variable"); 450 | 451 | return 0; 452 | } 453 | 454 | internal static DkmRuntimeInstructionBreakpoint CreateTargetFunctionBreakpointObjectAtAddress(DkmProcess process, DkmModuleInstance moduleWithLoadedLua, string name, string desc, ulong address, bool enabled) 455 | { 456 | if (address != 0) 457 | { 458 | LocalComponent.log.Debug($"Hooking Lua '{desc}' ({name}) function (address 0x{address:x})"); 459 | 460 | var nativeAddress = process.CreateNativeInstructionAddress(address); 461 | 462 | var breakpoint = DkmRuntimeInstructionBreakpoint.Create(Guids.luaSupportBreakpointGuid, null, nativeAddress, false, null); 463 | 464 | if (enabled) 465 | breakpoint.Enable(); 466 | 467 | return breakpoint; 468 | } 469 | else 470 | { 471 | LocalComponent.log.Warning($"Failed to create breakpoint in '{name}' with missing address"); 472 | } 473 | 474 | return null; 475 | } 476 | 477 | internal static Guid? CreateTargetFunctionBreakpointAtAddress(DkmProcess process, DkmModuleInstance moduleWithLoadedLua, string name, string desc, ulong address) 478 | { 479 | DkmRuntimeInstructionBreakpoint breakpoint = CreateTargetFunctionBreakpointObjectAtAddress(process, moduleWithLoadedLua, name, desc, address, true); 480 | 481 | if (breakpoint != null) 482 | return breakpoint.UniqueId; 483 | 484 | return null; 485 | } 486 | 487 | internal static DkmRuntimeInstructionBreakpoint CreateTargetFunctionBreakpointObjectAtDebugStart(DkmProcess process, DkmModuleInstance moduleWithLoadedLua, string name, string desc, out ulong breakAddress, bool enabled) 488 | { 489 | var address = TryGetFunctionAddressAtDebugStart(moduleWithLoadedLua, name, out string error); 490 | 491 | if (address != null) 492 | { 493 | LocalComponent.log.Debug($"Hooking Lua '{desc}' ({name}) function (address 0x{address.Value:x})"); 494 | 495 | var nativeAddress = process.CreateNativeInstructionAddress(address.Value); 496 | 497 | var breakpoint = DkmRuntimeInstructionBreakpoint.Create(Guids.luaSupportBreakpointGuid, null, nativeAddress, false, null); 498 | 499 | if (enabled) 500 | breakpoint.Enable(); 501 | 502 | breakAddress = address.Value; 503 | return breakpoint; 504 | } 505 | else 506 | { 507 | LocalComponent.log.Warning($"Failed to create breakpoint in '{name}' with {error}"); 508 | } 509 | 510 | breakAddress = 0; 511 | return null; 512 | } 513 | 514 | internal static Guid? CreateTargetFunctionBreakpointAtDebugStart(DkmProcess process, DkmModuleInstance moduleWithLoadedLua, string name, string desc, out ulong breakAddress) 515 | { 516 | DkmRuntimeInstructionBreakpoint breakpoint = CreateTargetFunctionBreakpointObjectAtDebugStart(process, moduleWithLoadedLua, name, desc, out breakAddress, true); 517 | 518 | if (breakpoint != null) 519 | return breakpoint.UniqueId; 520 | 521 | return null; 522 | } 523 | 524 | internal static Guid? CreateTargetFunctionBreakpointAtDebugEnd(DkmProcess process, DkmModuleInstance moduleWithLoadedLua, string name, string desc, out ulong breakAddress) 525 | { 526 | var address = TryGetFunctionAddressAtDebugEnd(moduleWithLoadedLua, name, out string error); 527 | 528 | if (address != null) 529 | { 530 | LocalComponent.log.Debug($"Hooking Lua '{desc}' ({name}) function (address 0x{address.Value:x})"); 531 | 532 | var nativeAddress = process.CreateNativeInstructionAddress(address.Value); 533 | 534 | var breakpoint = DkmRuntimeInstructionBreakpoint.Create(Guids.luaSupportBreakpointGuid, null, nativeAddress, false, null); 535 | 536 | breakpoint.Enable(); 537 | 538 | breakAddress = address.Value; 539 | return breakpoint.UniqueId; 540 | } 541 | else 542 | { 543 | LocalComponent.log.Warning($"Failed to create breakpoint in '{name}' with {error}"); 544 | } 545 | 546 | breakAddress = 0; 547 | return null; 548 | } 549 | } 550 | } 551 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/DebugHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.Debugger; 3 | using Microsoft.VisualStudio.Debugger.DefaultPort; 4 | using Microsoft.VisualStudio.Debugger.Native; 5 | 6 | namespace LuaDkmDebuggerComponent 7 | { 8 | public class BatchRead 9 | { 10 | protected ulong address = 0; 11 | protected byte[] data = null; 12 | 13 | public BatchRead(ulong address, byte[] data) 14 | { 15 | this.address = address; 16 | this.data = data; 17 | } 18 | 19 | static public BatchRead Create(DkmProcess process, ulong address, int bytes) 20 | { 21 | if (bytes <= 0 || bytes > 8 * 1024 * 1024) 22 | return null; 23 | 24 | byte[] data = new byte[bytes]; 25 | 26 | try 27 | { 28 | if (process.ReadMemory(address, DkmReadMemoryFlags.None, data) == 0) 29 | return null; 30 | } 31 | catch (DkmException) 32 | { 33 | return null; 34 | } 35 | 36 | return new BatchRead(address, data); 37 | } 38 | 39 | public bool TryRead(ulong target, int length, out byte[] result) 40 | { 41 | result = null; 42 | 43 | if (target < address) 44 | return false; 45 | 46 | if (target + (ulong)length > address + (ulong)data.Length) 47 | return false; 48 | 49 | result = new byte[length]; 50 | Array.Copy(data, (int)(target - address), result, 0, length); 51 | return true; 52 | } 53 | } 54 | 55 | static class DebugHelpers 56 | { 57 | internal static T GetOrCreateDataItem(DkmDataContainer container) where T : DkmDataItem, new() 58 | { 59 | T item = container.GetDataItem(); 60 | 61 | if (item != null) 62 | return item; 63 | 64 | item = new T(); 65 | 66 | container.SetDataItem(DkmDataCreationDisposition.CreateNew, item); 67 | 68 | return item; 69 | } 70 | 71 | internal static ulong FindFunctionAddress(DkmRuntimeInstance runtimeInstance, string name) 72 | { 73 | foreach (var module in runtimeInstance.GetModuleInstances()) 74 | { 75 | var address = (module as DkmNativeModuleInstance)?.FindExportName(name, IgnoreDataExports: true); 76 | 77 | if (address != null) 78 | return address.CPUInstructionPart.InstructionPointer; 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | internal static bool Is64Bit(DkmProcess process) 85 | { 86 | return (process.SystemInformation.Flags & DkmSystemInformationFlags.Is64Bit) != 0; 87 | } 88 | 89 | internal static int GetPointerSize(DkmProcess process) 90 | { 91 | return Is64Bit(process) ? 8 : 4; 92 | } 93 | 94 | internal static byte? ReadByteVariable(DkmProcess process, ulong address, BatchRead batch = null) 95 | { 96 | byte[] variableAddressData = new byte[1]; 97 | 98 | try 99 | { 100 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 101 | variableAddressData = batchData; 102 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 103 | return null; 104 | } 105 | catch (DkmException) 106 | { 107 | return null; 108 | } 109 | 110 | return variableAddressData[0]; 111 | } 112 | 113 | internal static short? ReadShortVariable(DkmProcess process, ulong address, BatchRead batch = null) 114 | { 115 | byte[] variableAddressData = new byte[2]; 116 | 117 | try 118 | { 119 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 120 | variableAddressData = batchData; 121 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 122 | return null; 123 | } 124 | catch (DkmException) 125 | { 126 | return null; 127 | } 128 | 129 | return BitConverter.ToInt16(variableAddressData, 0); 130 | } 131 | 132 | internal static int? ReadIntVariable(DkmProcess process, ulong address, BatchRead batch = null) 133 | { 134 | byte[] variableAddressData = new byte[4]; 135 | 136 | try 137 | { 138 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 139 | variableAddressData = batchData; 140 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 141 | return null; 142 | } 143 | catch (DkmException) 144 | { 145 | return null; 146 | } 147 | 148 | return BitConverter.ToInt32(variableAddressData, 0); 149 | } 150 | 151 | internal static uint? ReadUintVariable(DkmProcess process, ulong address, BatchRead batch = null) 152 | { 153 | byte[] variableAddressData = new byte[4]; 154 | 155 | try 156 | { 157 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 158 | variableAddressData = batchData; 159 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 160 | return null; 161 | } 162 | catch (DkmException) 163 | { 164 | return null; 165 | } 166 | 167 | return BitConverter.ToUInt32(variableAddressData, 0); 168 | } 169 | 170 | internal static long? ReadLongVariable(DkmProcess process, ulong address, BatchRead batch = null) 171 | { 172 | byte[] variableAddressData = new byte[8]; 173 | 174 | try 175 | { 176 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 177 | variableAddressData = batchData; 178 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 179 | return null; 180 | } 181 | catch (DkmException) 182 | { 183 | return null; 184 | } 185 | 186 | return BitConverter.ToInt64(variableAddressData, 0); 187 | } 188 | 189 | internal static ulong? ReadUlongVariable(DkmProcess process, ulong address, BatchRead batch = null) 190 | { 191 | byte[] variableAddressData = new byte[8]; 192 | 193 | try 194 | { 195 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 196 | variableAddressData = batchData; 197 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 198 | return null; 199 | } 200 | catch (DkmException) 201 | { 202 | return null; 203 | } 204 | 205 | return BitConverter.ToUInt64(variableAddressData, 0); 206 | } 207 | 208 | internal static float? ReadFloatVariable(DkmProcess process, ulong address, BatchRead batch = null) 209 | { 210 | byte[] variableAddressData = new byte[4]; 211 | 212 | try 213 | { 214 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 215 | variableAddressData = batchData; 216 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 217 | return null; 218 | } 219 | catch (DkmException) 220 | { 221 | return null; 222 | } 223 | 224 | return BitConverter.ToSingle(variableAddressData, 0); 225 | } 226 | 227 | internal static double? ReadDoubleVariable(DkmProcess process, ulong address, BatchRead batch = null) 228 | { 229 | byte[] variableAddressData = new byte[8]; 230 | 231 | try 232 | { 233 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 234 | variableAddressData = batchData; 235 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 236 | return null; 237 | } 238 | catch (DkmException) 239 | { 240 | return null; 241 | } 242 | 243 | return BitConverter.ToDouble(variableAddressData, 0); 244 | } 245 | 246 | internal static ulong? ReadPointerVariable(DkmProcess process, ulong address, BatchRead batch = null) 247 | { 248 | if (!Is64Bit(process)) 249 | return ReadUintVariable(process, address, batch); 250 | 251 | return ReadUlongVariable(process, address, batch); 252 | } 253 | 254 | internal static byte[] ReadRawStringVariable(DkmProcess process, ulong address, int limit) 255 | { 256 | try 257 | { 258 | return process.ReadMemoryString(address, DkmReadMemoryFlags.AllowPartialRead, 1, limit); 259 | } 260 | catch (DkmException) 261 | { 262 | } 263 | 264 | return null; 265 | } 266 | 267 | internal static string ReadStringVariable(DkmProcess process, ulong address, int limit) 268 | { 269 | try 270 | { 271 | byte[] nameData = process.ReadMemoryString(address, DkmReadMemoryFlags.AllowPartialRead, 1, limit); 272 | 273 | if (nameData != null && nameData.Length != 0) 274 | return System.Text.Encoding.UTF8.GetString(nameData, 0, nameData.Length - 1); 275 | } 276 | catch (DkmException) 277 | { 278 | return null; 279 | } 280 | 281 | return null; 282 | } 283 | 284 | internal static ulong? ReadPointerVariable(DkmProcess process, string name) 285 | { 286 | var runtimeInstance = process.GetNativeRuntimeInstance(); 287 | 288 | if (runtimeInstance != null) 289 | { 290 | foreach (var module in runtimeInstance.GetModuleInstances()) 291 | { 292 | var nativeModule = module as DkmNativeModuleInstance; 293 | 294 | var variableAddress = nativeModule?.FindExportName(name, IgnoreDataExports: false); 295 | 296 | if (variableAddress != null) 297 | return ReadPointerVariable(process, variableAddress.CPUInstructionPart.InstructionPointer); 298 | } 299 | } 300 | 301 | return null; 302 | } 303 | 304 | internal static ulong? ReadUleb128Variable(DkmProcess process, ulong address, out ulong length, BatchRead batch = null) 305 | { 306 | byte[] variableAddressData = new byte[8]; 307 | 308 | length = 0; 309 | 310 | try 311 | { 312 | if (batch != null && batch.TryRead(address, variableAddressData.Length, out byte[] batchData)) 313 | variableAddressData = batchData; 314 | else if (process.ReadMemory(address, DkmReadMemoryFlags.None, variableAddressData) == 0) 315 | return null; 316 | } 317 | catch (DkmException) 318 | { 319 | return null; 320 | } 321 | 322 | ulong pos = 0; 323 | ulong v = variableAddressData[pos++]; 324 | 325 | if (v >= 0x80) 326 | { 327 | int sh = 0; 328 | v &= 0x7f; 329 | 330 | do 331 | { 332 | sh += 7; 333 | v |= (variableAddressData[pos] & 0x7fu) << sh; 334 | } 335 | while (variableAddressData[pos++] >= 0x80); 336 | } 337 | 338 | length = pos; 339 | return v; 340 | } 341 | 342 | internal static bool TryWriteRawBytes(DkmProcess process, ulong address, byte[] value) 343 | { 344 | try 345 | { 346 | process.WriteMemory(address, value); 347 | } 348 | catch (DkmException) 349 | { 350 | return false; 351 | } 352 | 353 | return true; 354 | } 355 | 356 | internal static bool TryWriteByteVariable(DkmProcess process, ulong address, byte value) 357 | { 358 | try 359 | { 360 | process.WriteMemory(address, new byte[1] { value }); 361 | } 362 | catch (DkmException) 363 | { 364 | return false; 365 | } 366 | 367 | return true; 368 | } 369 | 370 | internal static bool TryWriteShortVariable(DkmProcess process, ulong address, short value) 371 | { 372 | try 373 | { 374 | process.WriteMemory(address, BitConverter.GetBytes(value)); 375 | } 376 | catch (DkmException) 377 | { 378 | return false; 379 | } 380 | 381 | return true; 382 | } 383 | 384 | internal static bool TryWriteIntVariable(DkmProcess process, ulong address, int value) 385 | { 386 | try 387 | { 388 | process.WriteMemory(address, BitConverter.GetBytes(value)); 389 | } 390 | catch (DkmException) 391 | { 392 | return false; 393 | } 394 | 395 | return true; 396 | } 397 | 398 | internal static bool TryWriteUintVariable(DkmProcess process, ulong address, uint value) 399 | { 400 | try 401 | { 402 | process.WriteMemory(address, BitConverter.GetBytes(value)); 403 | } 404 | catch (DkmException) 405 | { 406 | return false; 407 | } 408 | 409 | return true; 410 | } 411 | 412 | internal static bool TryWriteLongVariable(DkmProcess process, ulong address, long value) 413 | { 414 | try 415 | { 416 | process.WriteMemory(address, BitConverter.GetBytes(value)); 417 | } 418 | catch (DkmException) 419 | { 420 | return false; 421 | } 422 | 423 | return true; 424 | } 425 | 426 | internal static bool TryWriteUlongVariable(DkmProcess process, ulong address, ulong value) 427 | { 428 | try 429 | { 430 | process.WriteMemory(address, BitConverter.GetBytes(value)); 431 | } 432 | catch (DkmException) 433 | { 434 | return false; 435 | } 436 | 437 | return true; 438 | } 439 | 440 | internal static bool TryWriteFloatVariable(DkmProcess process, ulong address, float value) 441 | { 442 | try 443 | { 444 | process.WriteMemory(address, BitConverter.GetBytes(value)); 445 | } 446 | catch (DkmException) 447 | { 448 | return false; 449 | } 450 | 451 | return true; 452 | } 453 | 454 | internal static bool TryWriteDoubleVariable(DkmProcess process, ulong address, double value) 455 | { 456 | try 457 | { 458 | process.WriteMemory(address, BitConverter.GetBytes(value)); 459 | } 460 | catch (DkmException) 461 | { 462 | return false; 463 | } 464 | 465 | return true; 466 | } 467 | 468 | internal static bool TryWritePointerVariable(DkmProcess process, ulong address, ulong value) 469 | { 470 | if (!Is64Bit(process)) 471 | return TryWriteUintVariable(process, address, (uint)value); 472 | 473 | return TryWriteUlongVariable(process, address, value); 474 | } 475 | 476 | internal static byte? ReadStructByte(DkmProcess process, ref ulong address, BatchRead batch = null) 477 | { 478 | var result = ReadByteVariable(process, address, batch); 479 | 480 | address += 1ul; 481 | 482 | return result; 483 | } 484 | 485 | internal static short? ReadStructShort(DkmProcess process, ref ulong address, BatchRead batch = null) 486 | { 487 | address = (address + 1ul) & ~1ul; // Align 488 | 489 | var result = ReadShortVariable(process, address, batch); 490 | 491 | address += 2ul; 492 | 493 | return result; 494 | } 495 | 496 | internal static int? ReadStructInt(DkmProcess process, ref ulong address, BatchRead batch = null) 497 | { 498 | address = (address + 3ul) & ~3ul; // Align 499 | 500 | var result = ReadIntVariable(process, address, batch); 501 | 502 | address += 4ul; 503 | 504 | return result; 505 | } 506 | 507 | internal static uint? ReadStructUint(DkmProcess process, ref ulong address, BatchRead batch = null) 508 | { 509 | address = (address + 3ul) & ~3ul; // Align 510 | 511 | var result = ReadUintVariable(process, address, batch); 512 | 513 | address += 4ul; 514 | 515 | return result; 516 | } 517 | 518 | internal static long? ReadStructLong(DkmProcess process, ref ulong address, BatchRead batch = null) 519 | { 520 | address = (address + 7ul) & ~7ul; // Align 521 | 522 | var result = ReadLongVariable(process, address, batch); 523 | 524 | address += 8ul; 525 | 526 | return result; 527 | } 528 | 529 | internal static ulong? ReadStructUlong(DkmProcess process, ref ulong address, BatchRead batch = null) 530 | { 531 | address = (address + 7ul) & ~7ul; // Align 532 | 533 | var result = ReadUlongVariable(process, address, batch); 534 | 535 | address += 8ul; 536 | 537 | return result; 538 | } 539 | 540 | internal static ulong? ReadStructPointer(DkmProcess process, ref ulong address, BatchRead batch = null) 541 | { 542 | if (!Is64Bit(process)) 543 | return ReadStructUint(process, ref address, batch); 544 | 545 | return ReadStructUlong(process, ref address, batch); 546 | } 547 | 548 | internal static void SkipStructByte(DkmProcess process, ref ulong address) 549 | { 550 | address += 1ul; 551 | } 552 | 553 | internal static void SkipStructShort(DkmProcess process, ref ulong address) 554 | { 555 | address = (address + 1ul) & ~1ul; // Align 556 | 557 | address += 2ul; 558 | } 559 | 560 | internal static void SkipStructInt(DkmProcess process, ref ulong address) 561 | { 562 | address = (address + 3ul) & ~3ul; // Align 563 | 564 | address += 4ul; 565 | } 566 | 567 | internal static void SkipStructUint(DkmProcess process, ref ulong address) 568 | { 569 | address = (address + 3ul) & ~3ul; // Align 570 | 571 | address += 4ul; 572 | } 573 | 574 | internal static void SkipStructLong(DkmProcess process, ref ulong address) 575 | { 576 | address = (address + 7ul) & ~7ul; // Align 577 | 578 | address += 8ul; 579 | } 580 | 581 | internal static void SkipStructUlong(DkmProcess process, ref ulong address) 582 | { 583 | address = (address + 7ul) & ~7ul; // Align 584 | 585 | address += 8ul; 586 | } 587 | 588 | internal static void SkipStructPointer(DkmProcess process, ref ulong address) 589 | { 590 | if (!Is64Bit(process)) 591 | SkipStructUint(process, ref address); 592 | else 593 | SkipStructUlong(process, ref address); 594 | } 595 | } 596 | } 597 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/Dia2Lib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WheretIB/LuaDkmDebugger/abf4f46ef988a8a95f4bd3df723c00a347cd6920/LuaDkmDebuggerComponent/Dia2Lib.dll -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/Guids.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LuaDkmDebuggerComponent 4 | { 5 | static class Guids 6 | { 7 | public static readonly Guid luaLocalComponentGuid = new Guid("CF3F5D48-EFBB-49CB-916A-F19812A322ED"); 8 | public static readonly Guid luaRemoteComponentGuid = new Guid("1A5CBF53-315C-4E2C-A790-4042F9435EB7"); 9 | public static readonly Guid luaVsPackageComponentGuid = new Guid("B1C83EED-ADA7-492D-8E41-D47D97315BED"); 10 | 11 | public static readonly Guid luaCompilerGuid = new Guid("DD79A808-7001-4458-99D9-469BB771B9B4"); 12 | public static readonly Guid luaLanguageGuid = new Guid("C241D4C1-BC0C-45F7-99D3-D5264155BD05"); 13 | public static readonly Guid luaRuntimeGuid = new Guid("A2D176A1-8907-483C-9B36-4544EF424967"); 14 | public static readonly Guid luaSymbolProviderGuid = new Guid("00BB9B25-E5EA-4B0F-AD3D-C017B16F4FA1"); 15 | 16 | public static readonly Guid luaSupportBreakpointGuid = new Guid("F8B5C32C-126E-49EC-979E-3AE10F8321FA"); 17 | public static readonly Guid luaExceptionGuid = new Guid("AD1C7DA0-C25B-491D-8D9C-C86058F77034"); 18 | } 19 | 20 | static class MessageToRemote 21 | { 22 | public static readonly Guid guid = new Guid("ED25F587-E107-4F94-9775-885BEC371006"); 23 | 24 | public static readonly int createRuntime = 1; 25 | public static readonly int luaHelperDataLocations = 2; 26 | public static readonly int pauseBreakpoints = 3; 27 | public static readonly int resumeBreakpoints = 4; 28 | public static readonly int luaVersionInfo = 5; 29 | public static readonly int throwException = 6; 30 | public static readonly int registerLuaState = 7; 31 | public static readonly int unregisterLuaState = 8; 32 | } 33 | 34 | static class MessageToLocal 35 | { 36 | public static readonly Guid guid = new Guid("40C433F5-7EB9-400F-8DAC-DC4CAC739BE4"); 37 | 38 | public static readonly int luaSupportBreakpointHit = 1; 39 | public static readonly int luaSymbols = 2; 40 | } 41 | 42 | static class MessageToLocalWorker 43 | { 44 | public static readonly Guid guid = new Guid("CD3A296C-3C54-4B5E-AF46-8B72F528E4B5"); 45 | 46 | public static readonly int fetchLuaSymbols = 1; 47 | } 48 | 49 | static class MessageToVsService 50 | { 51 | public static readonly int reloadBreakpoints = 1; 52 | public static readonly int scriptLoad = 2; 53 | public static readonly int setStatusText = 3; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/LocalComponent.vsdconfigxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/LocalWorkerComponent.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Debugger; 2 | using Microsoft.VisualStudio.Debugger.ComponentInterfaces; 3 | using System; 4 | using System.Linq; 5 | 6 | namespace LuaDkmDebuggerComponent 7 | { 8 | public class LocalWorkerComponent : IDkmCustomMessageForwardReceiver 9 | { 10 | DkmCustomMessage IDkmCustomMessageForwardReceiver.SendLower(DkmCustomMessage customMessage) 11 | { 12 | var process = customMessage.Process; 13 | 14 | if (customMessage.MessageCode == MessageToLocalWorker.fetchLuaSymbols) 15 | { 16 | var moduleUniqueId = new Guid(customMessage.Parameter1 as byte[]); 17 | 18 | var nativeModuleInstance = process.GetNativeRuntimeInstance().GetNativeModuleInstances().FirstOrDefault(el => el.UniqueId == moduleUniqueId); 19 | 20 | if (nativeModuleInstance == null) 21 | return null; 22 | 23 | // Check if Lua library is loaded 24 | ulong luaNewState = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "lua_newstate", out _).GetValueOrDefault(0); 25 | ulong luaLibNewState = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "luaL_newstate", out _).GetValueOrDefault(0); 26 | 27 | if (luaNewState != 0 || luaLibNewState != 0) 28 | { 29 | var locations = new LuaLocationsMessage(); 30 | 31 | locations.luaExecuteAtStart = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaV_execute", out _).GetValueOrDefault(0); 32 | locations.luaExecuteAtEnd = AttachmentHelpers.TryGetFunctionAddressAtDebugEnd(nativeModuleInstance, "luaV_execute", out _).GetValueOrDefault(0); 33 | 34 | if (luaNewState != 0) 35 | { 36 | locations.luaNewStateAtStart = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "lua_newstate", out _).GetValueOrDefault(0); 37 | locations.luaNewStateAtEnd = AttachmentHelpers.TryGetFunctionAddressAtDebugEnd(nativeModuleInstance, "lua_newstate", out _).GetValueOrDefault(0); 38 | } 39 | else 40 | { 41 | locations.luaNewStateAtStart = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_newstate", out _).GetValueOrDefault(0); 42 | locations.luaNewStateAtEnd = AttachmentHelpers.TryGetFunctionAddressAtDebugEnd(nativeModuleInstance, "luaL_newstate", out _).GetValueOrDefault(0); 43 | } 44 | 45 | locations.luaClose = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "lua_close", out _).GetValueOrDefault(0); 46 | locations.closeState = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "close_state", out _).GetValueOrDefault(0); 47 | 48 | locations.luaLoadFileEx = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_loadfilex", out _).GetValueOrDefault(0); 49 | locations.luaLoadFile = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_loadfile", out _).GetValueOrDefault(0); 50 | locations.solCompatLoadFileEx = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "kp_compat53L_loadfilex", out _).GetValueOrDefault(0); 51 | 52 | locations.luaLoadBufferEx = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_loadbufferx", out _).GetValueOrDefault(0); 53 | locations.luaLoadBufferAtStart = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_loadbuffer", out _).GetValueOrDefault(0); 54 | locations.luaLoadBufferAtEnd = AttachmentHelpers.TryGetFunctionAddressAtDebugEnd(nativeModuleInstance, "luaL_loadbuffer", out _).GetValueOrDefault(0); 55 | 56 | locations.luaLoad = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "lua_load", out _).GetValueOrDefault(0); 57 | 58 | locations.luaError = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaB_error", out _).GetValueOrDefault(0); 59 | locations.luaRunError = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaG_runerror", out _).GetValueOrDefault(0); 60 | locations.luaThrow = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaD_throw", out _).GetValueOrDefault(0); 61 | 62 | locations.luaPcall = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "lua_pcall", out _).GetValueOrDefault(0); 63 | locations.luaPcallk = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "lua_pcallk", out _).GetValueOrDefault(0); 64 | 65 | // Check if it's luajit 66 | locations.ljSetMode = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "luaJIT_setmode", out _).GetValueOrDefault(0); 67 | 68 | if (locations.ljSetMode != 0) 69 | { 70 | locations.luaLibNewStateAtStart = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "luaL_newstate", out _).GetValueOrDefault(0); 71 | locations.luaLibNewStateAtEnd = AttachmentHelpers.TryGetFunctionAddressAtDebugEnd(nativeModuleInstance, "luaL_newstate", out _).GetValueOrDefault(0); 72 | 73 | locations.luaSetHook = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "lua_sethook", out _).GetValueOrDefault(0); 74 | locations.luaGetInfo = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "lua_getinfo", out _).GetValueOrDefault(0); 75 | locations.luaGetStack = AttachmentHelpers.TryGetFunctionAddress(nativeModuleInstance, "lua_getstack", out _).GetValueOrDefault(0); 76 | 77 | locations.ljErrRun = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "lj_err_run", out _).GetValueOrDefault(0); 78 | locations.ljErrThrow = AttachmentHelpers.TryGetFunctionAddressAtDebugStart(nativeModuleInstance, "lj_err_throw", out _).GetValueOrDefault(0); 79 | } 80 | 81 | return DkmCustomMessage.Create(process.Connection, process, MessageToLocal.guid, MessageToLocal.luaSymbols, locations.Encode(), null); 82 | } 83 | } 84 | 85 | return null; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/LocalWorkerComponent.vsdconfigxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/Log.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | 5 | namespace LuaDkmDebuggerComponent 6 | { 7 | public class Log 8 | { 9 | public enum LogLevel 10 | { 11 | None, 12 | Error, 13 | Warning, 14 | Debug, 15 | Verbose 16 | }; 17 | 18 | public Log(LogLevel level, bool isGlobal) 19 | { 20 | logLevel = level; 21 | 22 | if (isGlobal) 23 | instance = this; 24 | } 25 | 26 | public void Error(string text) 27 | { 28 | if (logLevel >= LogLevel.Error) 29 | Output($"ERROR: {text}"); 30 | } 31 | 32 | public void Warning(string text) 33 | { 34 | if (logLevel >= LogLevel.Warning) 35 | Output($"WARNING: {text}"); 36 | } 37 | 38 | public void Debug(string text) 39 | { 40 | if (logLevel >= LogLevel.Debug) 41 | Output($"INFO: {text}"); 42 | } 43 | 44 | public void Verbose(string text) 45 | { 46 | if (logLevel >= LogLevel.Verbose) 47 | Output($"VERBOSE: {text}"); 48 | } 49 | 50 | protected void Output(string text) 51 | { 52 | try 53 | { 54 | string formatted = $"{text} at {(DateTime.Now.Ticks / 10000.0) - startTime}ms"; 55 | 56 | System.Diagnostics.Debug.WriteLine(formatted); 57 | 58 | if (logPath != null) 59 | { 60 | using (var writer = File.AppendText(logPath)) 61 | writer.WriteLine(formatted); 62 | } 63 | } 64 | catch (Exception) 65 | { 66 | } 67 | } 68 | 69 | public static Log instance = null; 70 | public LogLevel logLevel = LogLevel.Warning; 71 | public string logPath = null; 72 | public double startTime = DateTime.Now.Ticks / 10000.0; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/LuaConstants.cs: -------------------------------------------------------------------------------- 1 | namespace LuaDkmDebuggerComponent 2 | { 3 | enum CallStatus_5_2 4 | { 5 | // call is running a Lua function 6 | Lua = (1 << 0), 7 | 8 | // call is running a debug hook 9 | Hooked = (1 << 1), 10 | 11 | // call is running on same invocation of luaV_execute of previous call 12 | Reentry = (1 << 2), 13 | 14 | // call reentered after suspension 15 | Yielded = (1 << 3), 16 | 17 | // call is a yieldable protected call 18 | YieldableProtectedCall = (1 << 4), 19 | 20 | // call has an error status (pcall) 21 | Stat = (1 << 5), 22 | 23 | // call was tail called 24 | Tail = (1 << 6), 25 | 26 | // last hook called yielded 27 | HookYield = (1 << 7), 28 | } 29 | 30 | enum CallStatus_5_3 31 | { 32 | // original value of 'allowhook' 33 | OriginalAllowHook = (1 << 0), 34 | 35 | // call is running a Lua function 36 | Lua = (1 << 1), 37 | 38 | // call is running a debug hook 39 | Hooked = (1 << 2), 40 | 41 | //call is running on a fresh invocation of luaV_execute 42 | Fresh = (1 << 3), 43 | 44 | // call is a yieldable protected call 45 | YieldableProtectedCall = (1 << 4), 46 | 47 | // call was tail called 48 | TailCall = (1 << 5), 49 | 50 | // last hook called yielded 51 | HookYield = (1 << 6), 52 | 53 | // using __lt for __le 54 | LessEqual = (1 << 7), 55 | 56 | // call is running a finalizer 57 | Finalizer = (1 << 8), 58 | } 59 | 60 | enum CallStatus_5_4 61 | { 62 | // original value of 'allowhook' 63 | OriginalAllowHook = (1 << 0), 64 | 65 | // call is running a C function 66 | C = (1 << 1), 67 | 68 | // call is running a debug hook 69 | Hooked = (1 << 2), 70 | 71 | // call is a yieldable protected call 72 | YieldableProtectedCall = (1 << 3), 73 | 74 | // call was tail called 75 | TailCall = (1 << 4), 76 | 77 | // last hook called yielded 78 | HookYield = (1 << 5), 79 | 80 | // call is running a finalizer 81 | Finalizer = (1 << 6), 82 | 83 | // 'ci' has transfer information 84 | Transfer = (1 << 7), 85 | 86 | // using __lt for __le 87 | LessEqual = (1 << 8), 88 | } 89 | 90 | enum InstructionCode 91 | { 92 | Call = 36, 93 | TailCall = 37, 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/LuaDkmDebuggerComponent.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {671C8B4F-93F5-4AEC-82E6-6C65A80798E7} 8 | Library 9 | Properties 10 | LuaDkmDebuggerComponent 11 | LuaDkmDebuggerComponent 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | False 36 | True 37 | .\Dia2Lib.dll 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | all 75 | 76 | 77 | all 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/LuaSymbolStore.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Debugger; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | 5 | namespace LuaDkmDebuggerComponent 6 | { 7 | public class LuaScriptSymbols 8 | { 9 | public string sourceFileName = null; 10 | public string scriptContent = null; 11 | public byte[] sha1Hash = null; 12 | 13 | public string resolvedFileName = null; 14 | } 15 | 16 | public class LuaSourceSymbols 17 | { 18 | public string sourceFileName = null; 19 | public ulong address = 0; 20 | public string resolvedFileName = null; 21 | 22 | public Dictionary knownFunctions = new Dictionary(); 23 | } 24 | 25 | public class LuaStateSymbols 26 | { 27 | public Dictionary knownSources = new Dictionary(); 28 | public Dictionary functionNames = new Dictionary(); 29 | public Dictionary knownScripts = new Dictionary(); 30 | public Dictionary unnamedScriptMapping = new Dictionary(); 31 | 32 | public void AddSourceFromFunction(DkmProcess process, LuaFunctionData function) 33 | { 34 | if (function.originalAddress == 0) 35 | { 36 | Debug.Assert(false, "Initialize function data before adding to symbol store"); 37 | return; 38 | } 39 | 40 | function.ReadSource(process); 41 | 42 | if (function.source == null) 43 | return; 44 | 45 | if (!knownSources.ContainsKey(function.source)) 46 | knownSources.Add(function.source, new LuaSourceSymbols() { sourceFileName = function.source, address = function.sourceAddress }); 47 | 48 | LuaSourceSymbols source = knownSources[function.source]; 49 | 50 | if (source.knownFunctions.ContainsKey(function.originalAddress)) 51 | return; 52 | 53 | source.knownFunctions[function.originalAddress] = function; 54 | 55 | if (function.hasDefinitionLineInfo && function.definitionStartLine_opt == 0) 56 | { 57 | function.ReadLocalFunctions(process); 58 | } 59 | } 60 | 61 | public LuaSourceSymbols FetchSourceSymbols(string sourceFileName) 62 | { 63 | if (knownSources.ContainsKey(sourceFileName)) 64 | return knownSources[sourceFileName]; 65 | 66 | return null; 67 | } 68 | 69 | public void AddFunctionName(ulong address, string name) 70 | { 71 | if (!functionNames.ContainsKey(address)) 72 | functionNames.Add(address, name); 73 | else 74 | functionNames[address] = name; 75 | } 76 | 77 | public string FetchFunctionName(ulong address) 78 | { 79 | if (functionNames.ContainsKey(address)) 80 | return functionNames[address]; 81 | 82 | return null; 83 | } 84 | 85 | public void AddScriptSource(string scriptName, string scriptContent, byte[] sha1Hash) 86 | { 87 | if (!knownScripts.ContainsKey(scriptName)) 88 | knownScripts.Add(scriptName, new LuaScriptSymbols { sourceFileName = scriptName, scriptContent = scriptContent, sha1Hash = sha1Hash }); 89 | else 90 | knownScripts[scriptName] = new LuaScriptSymbols { sourceFileName = scriptName, scriptContent = scriptContent, sha1Hash = sha1Hash }; 91 | } 92 | 93 | public LuaScriptSymbols FetchScriptSource(string sourceFileName) 94 | { 95 | if (knownScripts.ContainsKey(sourceFileName)) 96 | return knownScripts[sourceFileName]; 97 | 98 | return null; 99 | } 100 | } 101 | 102 | public class LuaSymbolStore 103 | { 104 | public Dictionary knownStates = new Dictionary(); 105 | 106 | public LuaStateSymbols FetchOrCreate(ulong stateAddress) 107 | { 108 | if (!knownStates.ContainsKey(stateAddress)) 109 | knownStates.Add(stateAddress, new LuaStateSymbols()); 110 | 111 | return knownStates[stateAddress]; 112 | } 113 | 114 | public void Remove(ulong stateAddress) 115 | { 116 | knownStates.Remove(stateAddress); 117 | } 118 | 119 | public LuaSourceSymbols FetchSourceSymbols(string sourceFileName) 120 | { 121 | foreach (var state in knownStates) 122 | { 123 | var sourceSymbols = state.Value.FetchSourceSymbols(sourceFileName); 124 | 125 | if (sourceSymbols != null) 126 | return sourceSymbols; 127 | } 128 | 129 | return null; 130 | } 131 | 132 | public LuaScriptSymbols FetchScriptSource(string sourceFileName) 133 | { 134 | foreach (var state in knownStates) 135 | { 136 | var scriptSource = state.Value.FetchScriptSource(sourceFileName); 137 | 138 | if (scriptSource != null) 139 | return scriptSource; 140 | } 141 | 142 | return null; 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/LuaValues.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Debugger.Evaluation; 2 | using System.Diagnostics; 3 | 4 | namespace LuaDkmDebuggerComponent 5 | { 6 | public abstract class LuaValueDataBase 7 | { 8 | public LuaBaseType baseType; 9 | public LuaExtendedType extendedType; 10 | public DkmEvaluationResultFlags evaluationFlags; 11 | public ulong tagAddress; 12 | public ulong originalAddress; 13 | 14 | public abstract bool LuaCompare(LuaValueDataBase rhs); 15 | public abstract string GetLuaType(); 16 | public abstract string AsSimpleDisplayString(uint radix); 17 | } 18 | 19 | [DebuggerDisplay("error ({extendedType})")] 20 | public class LuaValueDataError : LuaValueDataBase 21 | { 22 | public LuaValueDataError() 23 | { 24 | } 25 | 26 | public LuaValueDataError(string value, bool stoppedOnSideEffect = false) 27 | { 28 | baseType = LuaBaseType.Nil; 29 | extendedType = LuaExtendedType.Nil; 30 | evaluationFlags = DkmEvaluationResultFlags.ReadOnly; 31 | tagAddress = 0; 32 | originalAddress = 0; 33 | this.value = value; 34 | this.stoppedOnSideEffect = stoppedOnSideEffect; 35 | } 36 | 37 | public override bool LuaCompare(LuaValueDataBase rhs) 38 | { 39 | var rhsAsMe = rhs as LuaValueDataError; 40 | 41 | if (rhsAsMe == null) 42 | return false; 43 | 44 | return value == rhsAsMe.value; 45 | } 46 | 47 | public override string GetLuaType() 48 | { 49 | return "error"; 50 | } 51 | 52 | public override string AsSimpleDisplayString(uint radix) 53 | { 54 | return value; 55 | } 56 | 57 | public string value; 58 | public bool stoppedOnSideEffect; 59 | } 60 | 61 | [DebuggerDisplay("nil ({extendedType})")] 62 | public class LuaValueDataNil : LuaValueDataBase 63 | { 64 | public LuaValueDataNil() 65 | { 66 | baseType = LuaBaseType.Nil; 67 | extendedType = LuaExtendedType.Nil; 68 | evaluationFlags = DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly; 69 | tagAddress = 0; 70 | originalAddress = 0; 71 | } 72 | 73 | public override bool LuaCompare(LuaValueDataBase rhs) 74 | { 75 | var rhsAsMe = rhs as LuaValueDataNil; 76 | 77 | if (rhsAsMe == null) 78 | return false; 79 | 80 | return true; 81 | } 82 | 83 | public override string GetLuaType() 84 | { 85 | return "nil"; 86 | } 87 | 88 | public override string AsSimpleDisplayString(uint radix) 89 | { 90 | return "nil"; 91 | } 92 | } 93 | 94 | [DebuggerDisplay("value = {value} ({extendedType})")] 95 | public class LuaValueDataBool : LuaValueDataBase 96 | { 97 | public LuaValueDataBool() 98 | { 99 | } 100 | 101 | public LuaValueDataBool(bool value) 102 | { 103 | baseType = LuaBaseType.Boolean; 104 | 105 | if (LuaHelpers.luaVersion == 504) 106 | extendedType = value ? LuaExtendedType.BooleanTrue : LuaExtendedType.Boolean; 107 | else 108 | extendedType = LuaExtendedType.Boolean; 109 | 110 | evaluationFlags = (value ? DkmEvaluationResultFlags.BooleanTrue : DkmEvaluationResultFlags.None) | DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.Boolean | DkmEvaluationResultFlags.ReadOnly; 111 | tagAddress = 0; 112 | originalAddress = 0; 113 | this.value = value; 114 | } 115 | 116 | public override bool LuaCompare(LuaValueDataBase rhs) 117 | { 118 | var rhsAsMe = rhs as LuaValueDataBool; 119 | 120 | if (rhsAsMe == null) 121 | return false; 122 | 123 | return value == rhsAsMe.value; 124 | } 125 | 126 | public override string GetLuaType() 127 | { 128 | return "bool"; 129 | } 130 | 131 | public override string AsSimpleDisplayString(uint radix) 132 | { 133 | return value ? "true" : "false"; 134 | } 135 | 136 | public bool value; 137 | } 138 | 139 | [DebuggerDisplay("value = 0x{value,x} ({extendedType})")] 140 | public class LuaValueDataLightUserData : LuaValueDataBase 141 | { 142 | public LuaValueDataLightUserData() 143 | { 144 | } 145 | 146 | public LuaValueDataLightUserData(ulong value) 147 | { 148 | baseType = LuaBaseType.LightUserData; 149 | extendedType = LuaExtendedType.LightUserData; 150 | evaluationFlags = DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly; 151 | tagAddress = 0; 152 | originalAddress = 0; 153 | this.value = value; 154 | } 155 | 156 | public override bool LuaCompare(LuaValueDataBase rhs) 157 | { 158 | var rhsAsMe = rhs as LuaValueDataLightUserData; 159 | 160 | if (rhsAsMe == null) 161 | return false; 162 | 163 | return value == rhsAsMe.value; 164 | } 165 | 166 | public override string GetLuaType() 167 | { 168 | return "light_user_data"; 169 | } 170 | 171 | public override string AsSimpleDisplayString(uint radix) 172 | { 173 | return $"0x{value:x}"; 174 | } 175 | 176 | public ulong value; 177 | } 178 | 179 | [DebuggerDisplay("value = {value} ({extendedType})")] 180 | public class LuaValueDataNumber : LuaValueDataBase 181 | { 182 | public LuaValueDataNumber() 183 | { 184 | } 185 | 186 | public LuaValueDataNumber(int value) 187 | { 188 | baseType = LuaBaseType.Number; 189 | extendedType = LuaHelpers.GetIntegerNumberExtendedType(); 190 | evaluationFlags = DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly; 191 | tagAddress = 0; 192 | originalAddress = 0; 193 | this.value = value; 194 | } 195 | 196 | public LuaValueDataNumber(double value) 197 | { 198 | baseType = LuaBaseType.Number; 199 | extendedType = LuaHelpers.GetFloatNumberExtendedType(); 200 | evaluationFlags = DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly; 201 | tagAddress = 0; 202 | originalAddress = 0; 203 | this.value = value; 204 | } 205 | 206 | public override bool LuaCompare(LuaValueDataBase rhs) 207 | { 208 | var rhsAsMe = rhs as LuaValueDataNumber; 209 | 210 | if (rhsAsMe == null) 211 | return false; 212 | 213 | return value == rhsAsMe.value; 214 | } 215 | 216 | public override string GetLuaType() 217 | { 218 | return extendedType == LuaHelpers.GetIntegerNumberExtendedType() ? "int" : "double"; 219 | } 220 | 221 | public override string AsSimpleDisplayString(uint radix) 222 | { 223 | if (extendedType == LuaHelpers.GetIntegerNumberExtendedType()) 224 | { 225 | if (radix == 16) 226 | return $"0x{(int)value:x8}"; 227 | 228 | return $"{(int)value}"; 229 | } 230 | 231 | return $"{value}"; 232 | } 233 | 234 | public double value; 235 | } 236 | 237 | [DebuggerDisplay("value = {value} ({extendedType})")] 238 | public class LuaValueDataString : LuaValueDataBase 239 | { 240 | public LuaValueDataString() 241 | { 242 | } 243 | 244 | public LuaValueDataString(string value) 245 | { 246 | baseType = LuaBaseType.String; 247 | extendedType = LuaExtendedType.ShortString; 248 | evaluationFlags = DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly; 249 | tagAddress = 0; 250 | originalAddress = 0; 251 | this.value = value; 252 | } 253 | 254 | public override bool LuaCompare(LuaValueDataBase rhs) 255 | { 256 | var rhsAsMe = rhs as LuaValueDataString; 257 | 258 | if (rhsAsMe == null) 259 | return false; 260 | 261 | return value == rhsAsMe.value; 262 | } 263 | 264 | public override string GetLuaType() 265 | { 266 | return extendedType == LuaExtendedType.ShortString ? "short_string" : "long_string"; 267 | } 268 | 269 | public override string AsSimpleDisplayString(uint radix) 270 | { 271 | return $"\"{value}\""; 272 | } 273 | 274 | public string value; 275 | public ulong targetAddress; 276 | } 277 | 278 | [DebuggerDisplay("({extendedType})")] 279 | public class LuaValueDataTable : LuaValueDataBase 280 | { 281 | public override bool LuaCompare(LuaValueDataBase rhs) 282 | { 283 | var rhsAsMe = rhs as LuaValueDataTable; 284 | 285 | if (rhsAsMe == null) 286 | return false; 287 | 288 | return value == rhsAsMe.value; 289 | } 290 | 291 | public override string GetLuaType() 292 | { 293 | return "table"; 294 | } 295 | 296 | public override string AsSimpleDisplayString(uint radix) 297 | { 298 | return "{}"; 299 | } 300 | 301 | public LuaTableData value; 302 | public ulong targetAddress; 303 | } 304 | 305 | [DebuggerDisplay("({extendedType})")] 306 | public class LuaValueDataLuaFunction : LuaValueDataBase 307 | { 308 | public override bool LuaCompare(LuaValueDataBase rhs) 309 | { 310 | var rhsAsMe = rhs as LuaValueDataLuaFunction; 311 | 312 | if (rhsAsMe == null) 313 | return false; 314 | 315 | return targetAddress == rhsAsMe.targetAddress; 316 | } 317 | 318 | public override string GetLuaType() 319 | { 320 | return "lua_function"; 321 | } 322 | 323 | public override string AsSimpleDisplayString(uint radix) 324 | { 325 | return $"0x{targetAddress:x}"; 326 | } 327 | 328 | public LuaClosureData value; 329 | public ulong targetAddress; 330 | } 331 | 332 | [DebuggerDisplay("({extendedType})")] 333 | public class LuaValueDataExternalFunction : LuaValueDataBase 334 | { 335 | public override bool LuaCompare(LuaValueDataBase rhs) 336 | { 337 | var rhsAsMe = rhs as LuaValueDataExternalFunction; 338 | 339 | if (rhsAsMe == null) 340 | return false; 341 | 342 | return targetAddress == rhsAsMe.targetAddress; 343 | } 344 | 345 | public override string GetLuaType() 346 | { 347 | return "c_function"; 348 | } 349 | 350 | public override string AsSimpleDisplayString(uint radix) 351 | { 352 | return $"0x{targetAddress:x}"; 353 | } 354 | 355 | public ulong targetAddress; 356 | } 357 | 358 | [DebuggerDisplay("({extendedType})")] 359 | public class LuaValueDataExternalClosure : LuaValueDataBase 360 | { 361 | public override bool LuaCompare(LuaValueDataBase rhs) 362 | { 363 | var rhsAsMe = rhs as LuaValueDataExternalClosure; 364 | 365 | if (rhsAsMe == null) 366 | return false; 367 | 368 | return targetAddress == rhsAsMe.targetAddress; 369 | } 370 | 371 | public override string GetLuaType() 372 | { 373 | return "c_closure"; 374 | } 375 | 376 | public override string AsSimpleDisplayString(uint radix) 377 | { 378 | return $"0x{targetAddress:x}"; 379 | } 380 | 381 | public LuaExternalClosureData value; 382 | public ulong targetAddress; 383 | } 384 | 385 | [DebuggerDisplay("({extendedType})")] 386 | public class LuaValueDataUserData : LuaValueDataBase 387 | { 388 | public override bool LuaCompare(LuaValueDataBase rhs) 389 | { 390 | var rhsAsMe = rhs as LuaValueDataUserData; 391 | 392 | if (rhsAsMe == null) 393 | return false; 394 | 395 | return targetAddress == rhsAsMe.targetAddress; 396 | } 397 | 398 | public override string GetLuaType() 399 | { 400 | return "user_data"; 401 | } 402 | 403 | public override string AsSimpleDisplayString(uint radix) 404 | { 405 | return $"0x{targetAddress:x}"; 406 | } 407 | 408 | public LuaUserDataData value; 409 | public ulong targetAddress; 410 | } 411 | 412 | [DebuggerDisplay("({extendedType})")] 413 | public class LuaValueDataThread : LuaValueDataBase 414 | { 415 | public override bool LuaCompare(LuaValueDataBase rhs) 416 | { 417 | var rhsAsMe = rhs as LuaValueDataThread; 418 | 419 | if (rhsAsMe == null) 420 | return false; 421 | 422 | return targetAddress == rhsAsMe.targetAddress; 423 | } 424 | 425 | public override string GetLuaType() 426 | { 427 | return "thread"; 428 | } 429 | 430 | public override string AsSimpleDisplayString(uint radix) 431 | { 432 | return $"0x{targetAddress:x}"; 433 | } 434 | 435 | public ulong targetAddress; 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/Messages.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.IO; 4 | 5 | namespace LuaDkmDebuggerComponent 6 | { 7 | public class SupportBreakpointHitMessage 8 | { 9 | public Guid breakpointId; 10 | public Guid threadId; 11 | 12 | public ulong retAddr; 13 | public ulong frameBase; 14 | public ulong vframe; 15 | 16 | public byte[] Encode() 17 | { 18 | using (var stream = new MemoryStream()) 19 | { 20 | using (var writer = new BinaryWriter(stream)) 21 | { 22 | writer.Write(breakpointId.ToByteArray()); 23 | writer.Write(threadId.ToByteArray()); 24 | 25 | writer.Write(retAddr); 26 | writer.Write(frameBase); 27 | writer.Write(vframe); 28 | 29 | writer.Flush(); 30 | 31 | return stream.ToArray(); 32 | } 33 | } 34 | } 35 | 36 | public bool ReadFrom(byte[] data) 37 | { 38 | using (var stream = new MemoryStream(data)) 39 | { 40 | using (var reader = new BinaryReader(stream)) 41 | { 42 | breakpointId = new Guid(reader.ReadBytes(16)); 43 | threadId = new Guid(reader.ReadBytes(16)); 44 | 45 | retAddr = reader.ReadUInt64(); 46 | frameBase = reader.ReadUInt64(); 47 | vframe = reader.ReadUInt64(); 48 | } 49 | } 50 | 51 | return true; 52 | } 53 | } 54 | 55 | public class HelperLocationsMessage 56 | { 57 | public ulong helperBreakCountAddress = 0; 58 | public ulong helperBreakDataAddress = 0; 59 | public ulong helperBreakHitIdAddress = 0; 60 | public ulong helperBreakHitLuaStateAddress = 0; 61 | public ulong helperBreakSourcesAddress = 0; 62 | 63 | public ulong helperStepOverAddress = 0; 64 | public ulong helperStepIntoAddress = 0; 65 | public ulong helperStepOutAddress = 0; 66 | public ulong helperSkipDepthAddress = 0; 67 | public ulong helperStackDepthAtCallAddress = 0; 68 | public ulong helperAsyncBreakCodeAddress = 0; 69 | 70 | public Guid breakpointLuaHelperBreakpointHit; 71 | public Guid breakpointLuaHelperStepComplete; 72 | public Guid breakpointLuaHelperStepInto; 73 | public Guid breakpointLuaHelperStepOut; 74 | public Guid breakpointLuaHelperAsyncBreak; 75 | 76 | public ulong helperStartAddress = 0; 77 | public ulong helperEndAddress = 0; 78 | 79 | public ulong executionStartAddress = 0; 80 | public ulong executionEndAddress = 0; 81 | 82 | public byte[] Encode() 83 | { 84 | using (var stream = new MemoryStream()) 85 | { 86 | using (var writer = new BinaryWriter(stream)) 87 | { 88 | writer.Write(helperBreakCountAddress); 89 | writer.Write(helperBreakDataAddress); 90 | writer.Write(helperBreakHitIdAddress); 91 | writer.Write(helperBreakHitLuaStateAddress); 92 | writer.Write(helperBreakSourcesAddress); 93 | 94 | writer.Write(helperStepOverAddress); 95 | writer.Write(helperStepIntoAddress); 96 | writer.Write(helperStepOutAddress); 97 | writer.Write(helperSkipDepthAddress); 98 | writer.Write(helperStackDepthAtCallAddress); 99 | writer.Write(helperAsyncBreakCodeAddress); 100 | 101 | writer.Write(breakpointLuaHelperBreakpointHit.ToByteArray()); 102 | writer.Write(breakpointLuaHelperStepComplete.ToByteArray()); 103 | writer.Write(breakpointLuaHelperStepInto.ToByteArray()); 104 | writer.Write(breakpointLuaHelperStepOut.ToByteArray()); 105 | writer.Write(breakpointLuaHelperAsyncBreak.ToByteArray()); 106 | 107 | writer.Write(helperStartAddress); 108 | writer.Write(helperEndAddress); 109 | 110 | writer.Write(executionStartAddress); 111 | writer.Write(executionEndAddress); 112 | 113 | writer.Flush(); 114 | 115 | return stream.ToArray(); 116 | } 117 | } 118 | } 119 | 120 | public bool ReadFrom(byte[] data) 121 | { 122 | using (var stream = new MemoryStream(data)) 123 | { 124 | using (var reader = new BinaryReader(stream)) 125 | { 126 | helperBreakCountAddress = reader.ReadUInt64(); 127 | helperBreakDataAddress = reader.ReadUInt64(); 128 | helperBreakHitIdAddress = reader.ReadUInt64(); 129 | helperBreakHitLuaStateAddress = reader.ReadUInt64(); 130 | helperBreakSourcesAddress = reader.ReadUInt64(); 131 | 132 | helperStepOverAddress = reader.ReadUInt64(); 133 | helperStepIntoAddress = reader.ReadUInt64(); 134 | helperStepOutAddress = reader.ReadUInt64(); 135 | helperSkipDepthAddress = reader.ReadUInt64(); 136 | helperStackDepthAtCallAddress = reader.ReadUInt64(); 137 | helperAsyncBreakCodeAddress = reader.ReadUInt64(); 138 | 139 | breakpointLuaHelperBreakpointHit = new Guid(reader.ReadBytes(16)); 140 | breakpointLuaHelperStepComplete = new Guid(reader.ReadBytes(16)); 141 | breakpointLuaHelperStepInto = new Guid(reader.ReadBytes(16)); 142 | breakpointLuaHelperStepOut = new Guid(reader.ReadBytes(16)); 143 | breakpointLuaHelperAsyncBreak = new Guid(reader.ReadBytes(16)); 144 | 145 | helperStartAddress = reader.ReadUInt64(); 146 | helperEndAddress = reader.ReadUInt64(); 147 | 148 | executionStartAddress = reader.ReadUInt64(); 149 | executionEndAddress = reader.ReadUInt64(); 150 | } 151 | } 152 | 153 | return true; 154 | } 155 | } 156 | 157 | public class RegisterStateMessage 158 | { 159 | public ulong stateAddress = 0; 160 | 161 | public ulong hookFunctionAddress = 0; 162 | public ulong hookBaseCountAddress = 0; 163 | public ulong hookCountAddress = 0; 164 | public ulong hookMaskAddress = 0; 165 | 166 | // For Lua 5.4 'settraps' 167 | public ulong setTrapStateCallInfoOffset = 0; 168 | public ulong setTrapCallInfoPreviousOffset = 0; 169 | public ulong setTrapCallInfoCallStatusOffset = 0; 170 | public ulong setTrapCallInfoTrapOffset = 0; 171 | 172 | public ulong helperHookFunctionAddress = 0; 173 | 174 | public byte[] Encode() 175 | { 176 | using (var stream = new MemoryStream()) 177 | { 178 | using (var writer = new BinaryWriter(stream)) 179 | { 180 | writer.Write(stateAddress); 181 | 182 | writer.Write(hookFunctionAddress); 183 | writer.Write(hookBaseCountAddress); 184 | writer.Write(hookCountAddress); 185 | writer.Write(hookMaskAddress); 186 | 187 | writer.Write(setTrapStateCallInfoOffset); 188 | writer.Write(setTrapCallInfoPreviousOffset); 189 | writer.Write(setTrapCallInfoCallStatusOffset); 190 | writer.Write(setTrapCallInfoTrapOffset); 191 | 192 | writer.Write(helperHookFunctionAddress); 193 | 194 | writer.Flush(); 195 | 196 | return stream.ToArray(); 197 | } 198 | } 199 | } 200 | 201 | public bool ReadFrom(byte[] data) 202 | { 203 | using (var stream = new MemoryStream(data)) 204 | { 205 | using (var reader = new BinaryReader(stream)) 206 | { 207 | stateAddress = reader.ReadUInt64(); 208 | 209 | hookFunctionAddress = reader.ReadUInt64(); 210 | hookBaseCountAddress = reader.ReadUInt64(); 211 | hookCountAddress = reader.ReadUInt64(); 212 | hookMaskAddress = reader.ReadUInt64(); 213 | 214 | setTrapStateCallInfoOffset = reader.ReadUInt64(); 215 | setTrapCallInfoPreviousOffset = reader.ReadUInt64(); 216 | setTrapCallInfoCallStatusOffset = reader.ReadUInt64(); 217 | setTrapCallInfoTrapOffset = reader.ReadUInt64(); 218 | 219 | helperHookFunctionAddress = reader.ReadUInt64(); 220 | } 221 | } 222 | 223 | return true; 224 | } 225 | } 226 | 227 | public class UnregisterStateMessage 228 | { 229 | public ulong stateAddress = 0; 230 | 231 | public byte[] Encode() 232 | { 233 | using (var stream = new MemoryStream()) 234 | { 235 | using (var writer = new BinaryWriter(stream)) 236 | { 237 | writer.Write(stateAddress); 238 | 239 | writer.Flush(); 240 | 241 | return stream.ToArray(); 242 | } 243 | } 244 | } 245 | 246 | public bool ReadFrom(byte[] data) 247 | { 248 | using (var stream = new MemoryStream(data)) 249 | { 250 | using (var reader = new BinaryReader(stream)) 251 | { 252 | stateAddress = reader.ReadUInt64(); 253 | } 254 | } 255 | 256 | return true; 257 | } 258 | } 259 | 260 | public class LuaLocationsMessage 261 | { 262 | public ulong luaExecuteAtStart = 0; 263 | public ulong luaExecuteAtEnd = 0; 264 | 265 | public ulong luaNewStateAtStart = 0; 266 | public ulong luaNewStateAtEnd = 0; 267 | 268 | public ulong luaClose = 0; 269 | public ulong closeState = 0; 270 | 271 | public ulong luaLoadFileEx = 0; 272 | public ulong luaLoadFile = 0; 273 | public ulong solCompatLoadFileEx = 0; 274 | 275 | public ulong luaLoadBufferEx = 0; 276 | public ulong luaLoadBufferAtStart = 0; 277 | public ulong luaLoadBufferAtEnd = 0; 278 | 279 | public ulong luaLoad = 0; 280 | 281 | public ulong luaError = 0; 282 | public ulong luaRunError = 0; 283 | public ulong luaThrow = 0; 284 | 285 | public ulong luaPcall = 0; 286 | public ulong luaPcallk = 0; 287 | 288 | // For luajit 289 | public ulong ljSetMode = 0; 290 | 291 | public ulong luaLibNewStateAtStart = 0; 292 | public ulong luaLibNewStateAtEnd = 0; 293 | 294 | public ulong luaSetHook = 0; 295 | public ulong luaGetInfo = 0; 296 | public ulong luaGetStack = 0; 297 | 298 | public ulong ljErrRun = 0; 299 | public ulong ljErrThrow = 0; 300 | 301 | public byte[] Encode() 302 | { 303 | using (var stream = new MemoryStream()) 304 | { 305 | using (var writer = new BinaryWriter(stream)) 306 | { 307 | writer.Write(luaExecuteAtStart); 308 | writer.Write(luaExecuteAtEnd); 309 | writer.Write(luaNewStateAtStart); 310 | writer.Write(luaNewStateAtEnd); 311 | writer.Write(luaClose); 312 | writer.Write(closeState); 313 | writer.Write(luaLoadFileEx); 314 | writer.Write(luaLoadFile); 315 | writer.Write(solCompatLoadFileEx); 316 | writer.Write(luaLoadBufferEx); 317 | writer.Write(luaLoadBufferAtStart); 318 | writer.Write(luaLoadBufferAtEnd); 319 | writer.Write(luaLoad); 320 | writer.Write(luaError); 321 | writer.Write(luaRunError); 322 | writer.Write(luaThrow); 323 | writer.Write(luaPcall); 324 | writer.Write(luaPcallk); 325 | 326 | writer.Write(ljSetMode); 327 | writer.Write(luaLibNewStateAtStart); 328 | writer.Write(luaLibNewStateAtEnd); 329 | writer.Write(luaSetHook); 330 | writer.Write(luaGetInfo); 331 | writer.Write(luaGetStack); 332 | writer.Write(ljErrRun); 333 | writer.Write(ljErrThrow); 334 | 335 | writer.Flush(); 336 | 337 | return stream.ToArray(); 338 | } 339 | } 340 | } 341 | 342 | public bool ReadFrom(byte[] data) 343 | { 344 | using (var stream = new MemoryStream(data)) 345 | { 346 | using (var reader = new BinaryReader(stream)) 347 | { 348 | luaExecuteAtStart = reader.ReadUInt64(); 349 | luaExecuteAtEnd = reader.ReadUInt64(); 350 | luaNewStateAtStart = reader.ReadUInt64(); 351 | luaNewStateAtEnd = reader.ReadUInt64(); 352 | luaClose = reader.ReadUInt64(); 353 | closeState = reader.ReadUInt64(); 354 | luaLoadFileEx = reader.ReadUInt64(); 355 | luaLoadFile = reader.ReadUInt64(); 356 | solCompatLoadFileEx = reader.ReadUInt64(); 357 | luaLoadBufferEx = reader.ReadUInt64(); 358 | luaLoadBufferAtStart = reader.ReadUInt64(); 359 | luaLoadBufferAtEnd = reader.ReadUInt64(); 360 | luaLoad = reader.ReadUInt64(); 361 | luaError = reader.ReadUInt64(); 362 | luaRunError = reader.ReadUInt64(); 363 | luaThrow = reader.ReadUInt64(); 364 | luaPcall = reader.ReadUInt64(); 365 | luaPcallk = reader.ReadUInt64(); 366 | 367 | ljSetMode = reader.ReadUInt64(); 368 | luaLibNewStateAtStart = reader.ReadUInt64(); 369 | luaLibNewStateAtEnd = reader.ReadUInt64(); 370 | luaSetHook = reader.ReadUInt64(); 371 | luaGetInfo = reader.ReadUInt64(); 372 | luaGetStack = reader.ReadUInt64(); 373 | ljErrRun = reader.ReadUInt64(); 374 | ljErrThrow = reader.ReadUInt64(); 375 | } 376 | } 377 | 378 | return true; 379 | } 380 | } 381 | 382 | public class ScriptLoadMessage 383 | { 384 | public string name; 385 | public string path; 386 | public string status; 387 | public string content; 388 | 389 | public byte[] Encode() 390 | { 391 | using (var stream = new MemoryStream()) 392 | { 393 | using (var writer = new BinaryWriter(stream)) 394 | { 395 | writer.Write(name); 396 | writer.Write(path); 397 | writer.Write(status); 398 | writer.Write(content); 399 | 400 | writer.Flush(); 401 | 402 | return stream.ToArray(); 403 | } 404 | } 405 | } 406 | } 407 | 408 | public class StatusTextMessage 409 | { 410 | public int id; 411 | public string content; 412 | 413 | public byte[] Encode() 414 | { 415 | using (var stream = new MemoryStream()) 416 | { 417 | using (var writer = new BinaryWriter(stream)) 418 | { 419 | writer.Write(id); 420 | writer.Write(content); 421 | 422 | writer.Flush(); 423 | 424 | return stream.ToArray(); 425 | } 426 | } 427 | } 428 | } 429 | } 430 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LuaDkmDebuggerComponent")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LuaDkmDebuggerComponent")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("671c8b4f-93f5-4aec-82e6-6c65a80798e7")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /LuaDkmDebuggerComponent/RemoteComponent.vsdconfigxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /LuaDkmDebuggerShared/.pkgdef: -------------------------------------------------------------------------------- 1 | ; Language name 2 | "Language"="Lua" 3 | 4 | ; Language service (optional) 5 | ; If the adapter has an associated VS Language Service, specify its GUID in the "LanguageId" property 6 | ;"LanguageId"="{C241D4C1-BC0C-45F7-99D3-D5264155BD05}" 7 | 8 | [$RootKey$\AD7Metrics\ExpressionEvaluator\{C241D4C1-BC0C-45F7-99D3-D5264155BD05}\{DD79A808-7001-4458-99D9-469BB771B9B4}] 9 | "Language"="Lua" 10 | "Name"="Lua" 11 | 12 | [$RootKey$\AD7Metrics\ExpressionEvaluator\{C241D4C1-BC0C-45F7-99D3-D5264155BD05}\{DD79A808-7001-4458-99D9-469BB771B9B4}\Engine] 13 | "0"="{449EC4CC-30D2-4032-9256-EE18EB41B62B}" 14 | "1"="{92EF0900-2251-11D2-B72E-0000F87572EF}" 15 | "2"="{3B476D35-A401-11D2-AAD4-00C04F990171}" 16 | -------------------------------------------------------------------------------- /LuaDkmDebuggerShared/LuaDkmDebugger.vsct: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Lua Debugger 12 | Lua Debugger 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 32 | 33 | 42 | 51 | 52 | 61 | 62 | 71 | 72 | 81 | 82 | 91 | 92 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /LuaDkmDebuggerShared/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-2021 Vyacheslav Egorov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ Debugger Extensions for Lua 2 | 3 | --- 4 | This Visual Studio extension enables debugging of Lua scripts running inside C++ applications with Lua library. 5 | 6 | Supported Lua versions: 7 | * Lua 5.4 8 | * Lua 5.3 9 | * Lua 5.2 with LUA_NANTRICK (default configuration) 10 | * Lua 5.1 11 | * LuaJIT 2.0.5 12 | * LuaJIT 2.1.0 13 | 14 | [Extension on Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=wheretib.lua-dkm-debug) 15 | 16 | ## Features: 17 | * Lua call stack frames in the Call Stack window 18 | * Lua library call stack frames are marked as non-user code 19 | * Jump to Lua source/line from Lua call stack frames 20 | * Function arguments, local variables and upvalues are displayed in the 'Locals' window 21 | * Lua expression evaluation in Watch, Immediate and similar elements 22 | * Numeric, string and user data values can be modified 23 | * Breakpoints 24 | * Up to 256 breakpoints are supported 25 | * Step Over, Step Into and Step Out 26 | * Conditional breakpoints (not supported in LuaJIT) 27 | * Quick Info tooltip display with variable value evaluation on mouse over in the code window 28 | * External C function/closure pointer display with 'Go To Source' provided by Visual Studio 29 | * Assertion failure, 'error' call and runtime errors are displayed as unhandled exceptions ('Break on Error' option) 30 | * Location display and Jump to Source context menu option for Lua function values 31 | * When Lua library is used together with sol library, C++ object in user data is available 32 | 33 | ![Example debug session](https://github.com/WheretIB/LuaDkmDebugger/blob/master/resource/front_image_2.png?raw=true) 34 | 35 | ![Example debug session](https://github.com/WheretIB/LuaDkmDebugger/blob/master/resource/front_image.png?raw=true) 36 | 37 | ![Assertion Failure and User Data display](https://github.com/WheretIB/LuaDkmDebugger/blob/master/resource/front_image_3.png?raw=true) 38 | 39 | ## Requirements 40 | 41 | This extension relies on debug information for the Lua library itself. This means that debug information has to be provided for the Lua source files. This is different from other Lua debuggers that use the built-in `debug.` package. 42 | 43 | When using pre-compiled Lua libraries (static .lib or a .dll) a .pdb file has to be available as well. You can build Lua or LuaJIT with debug information with or without optimizations. 44 | 45 | If Lua source files are included in the project in your solution, debug information should be available by default. If not, you can enable it in the project settings even if building in Release configuration (without affecting performance). 46 | 47 | ## Additional configuration 48 | 49 | In the default configuration, debugger searches for script files in current working directory and application executable directory. 50 | 51 | Application may provide Lua with script file paths that do not match the file system. To help the debugger find your script files in this scenario, additional script search paths can be provided using an optional configuration file. 52 | 53 | `lua_dkm_debug.json` file can be placed in application working directory or near the executable file. 54 | 55 | Add `ScriptPaths` key with an array of additional search paths. 56 | 57 | ``` 58 | { 59 | "ScriptPaths": [ 60 | "../", 61 | "../scripts/base/" 62 | ] 63 | } 64 | ``` 65 | 66 | ## Troubleshooting 67 | 68 | If you experience issues with the extension, you can enable debug logs in 'Extensions -> Lua Debugger' menu if you wish to provide additional info in your report. 69 | 70 | ### Breakpoints and Stepping information 71 | 72 | As in other Lua debuggers, breakpoints are implemented using Lua library hooks. The hooks are set when breakpoints are active or if stepping through Lua code was performed. 73 | 74 | This debugger or other debuggers might override each other hooks, so if breakpoints are not hit, this might be the reason. 75 | 76 | If you experience issues with the debugger on launch, you can disable attachment to your process in 'Extensions -> Lua Debugger' menu. Debug logs can be enabled there as well if you wish to report the issue. (note that names of your Lua scripts might be included in the log). If debugger attachment is disabled, all features except for breakpoints and stepping will still work. 77 | 78 | ## Compatibility Mode 79 | 80 | If you use Lua 5.2 without LUA_NANTRICK or if you have your own modifications in Lua library and you are experiencing issues with this extension, you can enable 'Compatibility Mode' from the extension menu options. 81 | 82 | With this options, the debugger will load Lua data using symbolic field offsets instead of constant byte offsets expected for a specific version of Lua library. 83 | 84 | ## Known Issues: 85 | * This extension will always add Lua module to the application (can be seen in 'Modules' section of the debugger) even when debugging applications with no Lua code 86 | * Step Into from Lua into C++ doesn't work at the moment 87 | -------------------------------------------------------------------------------- /Tests/ExpressionEvaluationUnitTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace Tests 5 | { 6 | [TestClass] 7 | public class ExpressionEvaluationUnitTests 8 | { 9 | LuaDkmDebuggerComponent.ExpressionEvaluation evaluation = new LuaDkmDebuggerComponent.ExpressionEvaluation(null, null, null, null, 0, null); 10 | 11 | [TestMethod] 12 | public void TestSimpleValues() 13 | { 14 | { 15 | var result = evaluation.Evaluate("nil"); 16 | 17 | Assert.IsNotNull(result); 18 | 19 | Assert.AreEqual("nil", result.AsSimpleDisplayString(10)); 20 | } 21 | 22 | { 23 | var result = evaluation.Evaluate("true"); 24 | 25 | Assert.IsNotNull(result); 26 | 27 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 28 | } 29 | 30 | { 31 | var result = evaluation.Evaluate("false"); 32 | 33 | Assert.IsNotNull(result); 34 | 35 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 36 | } 37 | } 38 | 39 | [TestMethod] 40 | public void TestNumbers() 41 | { 42 | { 43 | var result = evaluation.Evaluate("1"); 44 | 45 | Assert.IsNotNull(result); 46 | 47 | Assert.AreEqual("1", result.AsSimpleDisplayString(10)); 48 | } 49 | 50 | { 51 | var result = evaluation.Evaluate("123456789"); 52 | 53 | Assert.IsNotNull(result); 54 | 55 | Assert.AreEqual("123456789", result.AsSimpleDisplayString(10)); 56 | } 57 | 58 | { 59 | var result = evaluation.Evaluate("0.125"); 60 | 61 | Assert.IsNotNull(result); 62 | 63 | Assert.AreEqual("0.125", result.AsSimpleDisplayString(10)); 64 | } 65 | 66 | { 67 | var result = evaluation.Evaluate("1e5"); 68 | 69 | Assert.IsNotNull(result); 70 | 71 | Assert.AreEqual("100000", result.AsSimpleDisplayString(10)); 72 | } 73 | 74 | { 75 | var result = evaluation.Evaluate("0xffe"); 76 | 77 | Assert.IsNotNull(result); 78 | 79 | Assert.AreEqual("4094", result.AsSimpleDisplayString(10)); 80 | } 81 | 82 | { 83 | var result = evaluation.Evaluate("0XBAAB"); 84 | 85 | Assert.IsNotNull(result); 86 | 87 | Assert.AreEqual("47787", result.AsSimpleDisplayString(10)); 88 | } 89 | } 90 | 91 | [TestMethod] 92 | public void TestUnary() 93 | { 94 | { 95 | var result = evaluation.Evaluate("-10"); 96 | 97 | Assert.IsNotNull(result); 98 | 99 | Assert.AreEqual("-10", result.AsSimpleDisplayString(10)); 100 | } 101 | 102 | { 103 | var result = evaluation.Evaluate("- 20"); 104 | 105 | Assert.IsNotNull(result); 106 | 107 | Assert.AreEqual("-20", result.AsSimpleDisplayString(10)); 108 | } 109 | 110 | { 111 | var result = evaluation.Evaluate("not false"); 112 | 113 | Assert.IsNotNull(result); 114 | 115 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 116 | } 117 | 118 | { 119 | var result = evaluation.Evaluate("not true"); 120 | 121 | Assert.IsNotNull(result); 122 | 123 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 124 | } 125 | 126 | { 127 | var result = evaluation.Evaluate("not nil"); 128 | 129 | Assert.IsNotNull(result); 130 | 131 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 132 | } 133 | 134 | { 135 | var result = evaluation.Evaluate("not 3"); 136 | 137 | Assert.IsNotNull(result); 138 | 139 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 140 | } 141 | } 142 | 143 | [TestMethod] 144 | public void TestMultiplicative() 145 | { 146 | { 147 | var result = evaluation.Evaluate("2 * 4"); 148 | 149 | Assert.IsNotNull(result); 150 | 151 | Assert.AreEqual("8", result.AsSimpleDisplayString(10)); 152 | } 153 | 154 | { 155 | var result = evaluation.Evaluate("2.5 * 4"); 156 | 157 | Assert.IsNotNull(result); 158 | 159 | Assert.AreEqual("10", result.AsSimpleDisplayString(10)); 160 | } 161 | 162 | { 163 | var result = evaluation.Evaluate("10 / 2"); 164 | 165 | Assert.IsNotNull(result); 166 | 167 | Assert.AreEqual("5", result.AsSimpleDisplayString(10)); 168 | } 169 | 170 | { 171 | var result = evaluation.Evaluate("3 / 2"); 172 | 173 | Assert.IsNotNull(result); 174 | 175 | Assert.AreEqual("1.5", result.AsSimpleDisplayString(10)); 176 | } 177 | } 178 | 179 | [TestMethod] 180 | public void TestAdditive() 181 | { 182 | { 183 | var result = evaluation.Evaluate("2 + 4"); 184 | 185 | Assert.IsNotNull(result); 186 | 187 | Assert.AreEqual("6", result.AsSimpleDisplayString(10)); 188 | } 189 | 190 | { 191 | var result = evaluation.Evaluate("5.5 - 1.5"); 192 | 193 | Assert.IsNotNull(result); 194 | 195 | Assert.AreEqual("4", result.AsSimpleDisplayString(10)); 196 | } 197 | 198 | { 199 | var result = evaluation.Evaluate("1.5 - 5.5"); 200 | 201 | Assert.IsNotNull(result); 202 | 203 | Assert.AreEqual("-4", result.AsSimpleDisplayString(10)); 204 | } 205 | } 206 | 207 | [TestMethod] 208 | public void TestConcatenation() 209 | { 210 | { 211 | var result = evaluation.Evaluate("2 .. 4"); 212 | 213 | Assert.IsNotNull(result); 214 | 215 | Assert.AreEqual("\"24\"", result.AsSimpleDisplayString(10)); 216 | } 217 | 218 | { 219 | var result = evaluation.Evaluate("\"hello\"..2"); 220 | 221 | Assert.IsNotNull(result); 222 | 223 | Assert.AreEqual("\"hello2\"", result.AsSimpleDisplayString(10)); 224 | } 225 | 226 | { 227 | var result = evaluation.Evaluate("\"hello\"..\" world\""); 228 | 229 | Assert.IsNotNull(result); 230 | 231 | Assert.AreEqual("\"hello world\"", result.AsSimpleDisplayString(10)); 232 | } 233 | } 234 | 235 | [TestMethod] 236 | public void TestComparisons() 237 | { 238 | { 239 | var result = evaluation.Evaluate("2 > 4"); 240 | 241 | Assert.IsNotNull(result); 242 | 243 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 244 | } 245 | 246 | { 247 | var result = evaluation.Evaluate("4 > 4"); 248 | 249 | Assert.IsNotNull(result); 250 | 251 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 252 | } 253 | 254 | { 255 | var result = evaluation.Evaluate("8 > 4"); 256 | 257 | Assert.IsNotNull(result); 258 | 259 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 260 | } 261 | 262 | { 263 | var result = evaluation.Evaluate("2 >= 4"); 264 | 265 | Assert.IsNotNull(result); 266 | 267 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 268 | } 269 | 270 | { 271 | var result = evaluation.Evaluate("4 >= 4"); 272 | 273 | Assert.IsNotNull(result); 274 | 275 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 276 | } 277 | 278 | { 279 | var result = evaluation.Evaluate("8 >= 4"); 280 | 281 | Assert.IsNotNull(result); 282 | 283 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 284 | } 285 | 286 | { 287 | var result = evaluation.Evaluate("2 < 4"); 288 | 289 | Assert.IsNotNull(result); 290 | 291 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 292 | } 293 | 294 | { 295 | var result = evaluation.Evaluate("4 < 4"); 296 | 297 | Assert.IsNotNull(result); 298 | 299 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 300 | } 301 | 302 | { 303 | var result = evaluation.Evaluate("8 < 4"); 304 | 305 | Assert.IsNotNull(result); 306 | 307 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 308 | } 309 | 310 | { 311 | var result = evaluation.Evaluate("2 <= 4"); 312 | 313 | Assert.IsNotNull(result); 314 | 315 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 316 | } 317 | 318 | { 319 | var result = evaluation.Evaluate("4 <= 4"); 320 | 321 | Assert.IsNotNull(result); 322 | 323 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 324 | } 325 | 326 | { 327 | var result = evaluation.Evaluate("8 <= 4"); 328 | 329 | Assert.IsNotNull(result); 330 | 331 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 332 | } 333 | 334 | { 335 | var result = evaluation.Evaluate("2 == 4"); 336 | 337 | Assert.IsNotNull(result); 338 | 339 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 340 | } 341 | 342 | { 343 | var result = evaluation.Evaluate("4 == 4"); 344 | 345 | Assert.IsNotNull(result); 346 | 347 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 348 | } 349 | 350 | { 351 | var result = evaluation.Evaluate("2 ~= 4"); 352 | 353 | Assert.IsNotNull(result); 354 | 355 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 356 | } 357 | 358 | { 359 | var result = evaluation.Evaluate("4 ~= 4"); 360 | 361 | Assert.IsNotNull(result); 362 | 363 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 364 | } 365 | 366 | { 367 | var result = evaluation.Evaluate("\"a\" > \"b\""); 368 | 369 | Assert.IsNotNull(result); 370 | 371 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 372 | } 373 | 374 | { 375 | var result = evaluation.Evaluate("\"a\" < \"b\""); 376 | 377 | Assert.IsNotNull(result); 378 | 379 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 380 | } 381 | 382 | { 383 | var result = evaluation.Evaluate("\"a\" >= \"b\""); 384 | 385 | Assert.IsNotNull(result); 386 | 387 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 388 | } 389 | 390 | { 391 | var result = evaluation.Evaluate("\"b\" >= \"a\""); 392 | 393 | Assert.IsNotNull(result); 394 | 395 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 396 | } 397 | 398 | { 399 | var result = evaluation.Evaluate("\"a\" >= \"a\""); 400 | 401 | Assert.IsNotNull(result); 402 | 403 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 404 | } 405 | 406 | { 407 | var result = evaluation.Evaluate("\"me\" == \"me\""); 408 | 409 | Assert.IsNotNull(result); 410 | 411 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 412 | } 413 | 414 | { 415 | var result = evaluation.Evaluate("\"me\" ~= \"me\""); 416 | 417 | Assert.IsNotNull(result); 418 | 419 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 420 | } 421 | 422 | { 423 | var result = evaluation.Evaluate("\"me\" == \"you\""); 424 | 425 | Assert.IsNotNull(result); 426 | 427 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 428 | } 429 | 430 | { 431 | var result = evaluation.Evaluate("\"me\" ~= \"you\""); 432 | 433 | Assert.IsNotNull(result); 434 | 435 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 436 | } 437 | } 438 | 439 | [TestMethod] 440 | public void TestLogical() 441 | { 442 | { 443 | var result = evaluation.Evaluate("(1 < 2) and (10 > 2)"); 444 | 445 | Assert.IsNotNull(result); 446 | 447 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 448 | } 449 | 450 | { 451 | var result = evaluation.Evaluate("(10 < 2) or (10 > 2)"); 452 | 453 | Assert.IsNotNull(result); 454 | 455 | Assert.AreEqual("true", result.AsSimpleDisplayString(10)); 456 | } 457 | 458 | { 459 | var result = evaluation.Evaluate("(10 < 2) and (10 > 2)"); 460 | 461 | Assert.IsNotNull(result); 462 | 463 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 464 | } 465 | 466 | { 467 | var result = evaluation.Evaluate("(1 < 2) and (10 > 20)"); 468 | 469 | Assert.IsNotNull(result); 470 | 471 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 472 | } 473 | 474 | { 475 | var result = evaluation.Evaluate("(10 < 2) or (10 > 20)"); 476 | 477 | Assert.IsNotNull(result); 478 | 479 | Assert.AreEqual("false", result.AsSimpleDisplayString(10)); 480 | } 481 | } 482 | } 483 | } 484 | -------------------------------------------------------------------------------- /Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("Tests")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Tests")] 10 | [assembly: AssemblyCopyright("Copyright © 2020")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("78515bb1-c701-4ed0-ad5a-954106a97345")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /Tests/Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {78515BB1-C701-4ED0-AD5A-954106A97345} 9 | Library 10 | Properties 11 | Tests 12 | Tests 13 | v4.7.2 14 | 512 15 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 16 | 15.0 17 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 18 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 19 | False 20 | UnitTest 21 | 22 | 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\Debug\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\Release\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | 44 | ..\packages\MSTest.TestFramework.2.1.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll 45 | 46 | 47 | ..\packages\MSTest.TestFramework.2.1.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | {671c8b4f-93f5-4aec-82e6-6c65a80798e7} 62 | LuaDkmDebuggerComponent 63 | 64 | 65 | 66 | 67 | 68 | 69 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /resource/front_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WheretIB/LuaDkmDebugger/abf4f46ef988a8a95f4bd3df723c00a347cd6920/resource/front_image.png -------------------------------------------------------------------------------- /resource/front_image_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WheretIB/LuaDkmDebugger/abf4f46ef988a8a95f4bd3df723c00a347cd6920/resource/front_image_2.png -------------------------------------------------------------------------------- /resource/front_image_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WheretIB/LuaDkmDebugger/abf4f46ef988a8a95f4bd3df723c00a347cd6920/resource/front_image_3.png --------------------------------------------------------------------------------