├── .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 |
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 |
27 |
28 |
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 |
15 |
16 |
17 |
18 |
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 | 
34 |
35 | 
36 |
37 | 
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
--------------------------------------------------------------------------------