forked from killswitch1111/powerguivsx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScirptProgramNode.cs
More file actions
544 lines (443 loc) · 17.9 KB
/
Copy pathScirptProgramNode.cs
File metadata and controls
544 lines (443 loc) · 17.9 KB
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
#region Usings
using System;
using System.Diagnostics;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Debugger.Interop;
using PowerShellTools.Common.ServiceManagement.DebuggingContract;
using PowerShellTools.Common.Debugging;
using PowerShellTools.Common.Logging;
#endregion
namespace PowerShellTools.DebugEngine
{
// This class implements IDebugProgramNode2.
// This interface represents a program that can be debugged.
// A debug engine (DE) or a custom port supplier implements this interface to represent a program that can be debugged.
public class ScriptProgramNode : IDebugProgramNode2, IDebugProgram2, IDebugProgramNodeAttach2, IDebugEngineProgram2, IDebugThread2, IEnumDebugThreads2, IDebugModule3
{
private static readonly ILog Log = LogManager.GetLogger(typeof (ScriptProgramNode));
public ScriptDebugProcess Process { get; set; }
public ScriptDebugger Debugger
{
get;
set;
}
public Guid Id { get; set; }
/// <summary>
/// This is either the file name or the contents of the script. IsFile determines which it is.
/// TODO: Rename.
/// </summary>
public string FileName { get; set; }
/// <summary>
/// Arguments that will be passed to the script.
/// </summary>
public string Arguments { get; set; }
/// <summary>
/// Whether or not this program node represents a file or a command being debugged.
/// </summary>
public bool IsFile { get; set; }
/// <summary>
/// Whether or not this program node represents a runspace that is being debugged that has been
/// attached to.
/// </summary>
public bool IsAttachedProgram { get; set; }
/// <summary>
/// Whether or not this program node represents a runspace on a remote machine.
/// </summary>
public bool IsRemoteProgram { get; set; }
public ScriptProgramNode(ScriptDebugProcess process)
{
Id = Guid.NewGuid();
this.Process = process;
}
#region IDebugProgramNode2 Members
public int GetHostName(enum_GETHOSTNAME_TYPE dwHostNameType, out string pbstrHostName)
{
Log.Debug("ScriptProgramNode: Entering GetHostName");
pbstrHostName = null;
return VSConstants.E_NOTIMPL;
}
// Gets the name and identifier of the DE running this program.
int IDebugProgramNode2.GetEngineInfo(out string engineName, out Guid engineGuid)
{
Log.Debug("ScriptProgramNode: Entering GetEngineInfo");
engineName = ResourceStrings.EngineName;
engineGuid = new Guid(Engine.Id);
return VSConstants.S_OK;
}
// Gets the system process identifier for the process hosting a program.
int IDebugProgramNode2.GetHostPid(AD_PROCESS_ID[] pHostProcessId)
{
Log.Debug("ScriptProgramNode: Entering GetHostPid");
// Return the process id of the debugged process
pHostProcessId[0].ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID;
pHostProcessId[0].guidProcessId = Process.Id;
return VSConstants.S_OK;
}
// Gets the name of a program.
int IDebugProgramNode2.GetProgramName(out string programName)
{
Log.Debug("ScriptProgramNode: Entering GetProgramName");
// Since we are using default transport and don't want to customize the process name, this method doesn't need
// to be implemented.
programName = null;
return VSConstants.E_NOTIMPL;
}
#endregion
#region Deprecated interface methods
// These methods are not called by the Visual Studio debugger, so they don't need to be implemented
int IDebugProgramNode2.Attach_V7(IDebugProgram2 pMDMProgram, IDebugEventCallback2 pCallback, uint dwReason)
{
Debug.Fail("This function is not called by the debugger");
return VSConstants.E_NOTIMPL;
}
int IDebugProgramNode2.DetachDebugger_V7()
{
Debug.Fail("This function is not called by the debugger");
return VSConstants.E_NOTIMPL;
}
int IDebugProgramNode2.GetHostMachineName_V7(out string hostMachineName)
{
Debug.Fail("This function is not called by the debugger");
hostMachineName = null;
return VSConstants.E_NOTIMPL;
}
#endregion
#region Implementation of IDebugProgram2
public int WriteDump(enum_DUMPTYPE DUMPTYPE, string pszDumpUrl)
{
Log.Debug("Program: WriteDump");
return VSConstants.E_NOTIMPL;
}
public int EnumThreads(out IEnumDebugThreads2 ppEnum)
{
Log.Debug("ScriptProgramNode: Entering EnumThreads");
ppEnum = this;
return VSConstants.S_OK;
}
public int GetName(out string pbstrName)
{
Log.Debug("ScriptProgramNode: Entering GetName");
pbstrName = "PowerShell Script";
return VSConstants.S_OK;
}
public int GetProcess(out IDebugProcess2 ppProcess)
{
Log.Debug("ScriptProgramNode: Entering GetProcess");
ppProcess = Process;
return VSConstants.S_OK;
}
public int Terminate()
{
Log.Debug("ScriptProgramNode: Entering Terminate");
return VSConstants.S_OK;
}
public int Attach(IDebugEventCallback2 pCallback)
{
Log.Debug("ScriptProgramNode: Entering Attach");
return VSConstants.S_OK;
}
public int CanDetach()
{
Log.Debug("ScriptProgramNode: Entering CanDetach");
return VSConstants.S_OK;
}
public int Detach()
{
Log.Debug("ScriptProgramNode: Entering Detach");
DebugScenario scenario = Debugger.DebuggingService.GetDebugScenario();
bool result = (scenario == DebugScenario.Local);
if (scenario == DebugScenario.LocalAttach)
{
result = Debugger.DebuggingService.DetachFromRunspace();
}
else if (scenario == DebugScenario.RemoteAttach)
{
result = Debugger.DebuggingService.DetachFromRemoteRunspace();
}
if (!result)
{
// try as hard as we can to detach/cleanup the mess for the length of CleanupRetryTimeout
TimeSpan retryTimeSpan = TimeSpan.FromMilliseconds(DebugEngineConstants.CleanupRetryTimeout);
Stopwatch timeElapsed = Stopwatch.StartNew();
while (timeElapsed.Elapsed < retryTimeSpan && !result)
{
result = (Debugger.DebuggingService.CleanupAttach() == DebugScenario.Local);
}
}
if (result)
{
Debugger.DebuggerFinished();
Debugger.RefreshPrompt();
}
return result ? VSConstants.S_OK : VSConstants.S_FALSE;
}
public int GetProgramId(out Guid pguidProgramId)
{
Log.Debug(String.Format("ScriptProgramNode: Entering GetProgramId {0}", Id));
pguidProgramId = Id;
return VSConstants.S_OK;
}
public int GetDebugProperty(out IDebugProperty2 ppProperty)
{
Log.Debug("ScriptProgramNode: Entering GetDebugProperty");
ppProperty = null;
return VSConstants.E_NOTIMPL;
}
public int Execute()
{
Log.Debug("ScriptProgramNode: Entering Execute");
Debugger.Continue();
return VSConstants.S_OK;
}
public int Continue(IDebugThread2 pThread)
{
Log.Debug("ScriptProgramNode: Entering Continue");
Debugger.Continue();
return VSConstants.S_OK;
}
public int Step(IDebugThread2 pThread, enum_STEPKIND sk, enum_STEPUNIT Step)
{
Log.Debug("ScriptProgramNode: Entering Step");
switch(sk)
{
case enum_STEPKIND.STEP_OVER:
Debugger.StepOver();
break;
case enum_STEPKIND.STEP_INTO:
Debugger.StepInto();
break;
case enum_STEPKIND.STEP_OUT:
Debugger.StepOut();
break;
}
return VSConstants.S_OK;
}
public int CauseBreak()
{
Log.Debug("ScriptProgramNode: Entering CauseBreak");
//TODO: Debugger.DebuggerManager.BreakDebug();
return VSConstants.S_OK;
}
public int GetEngineInfo(out string pbstrEngine, out Guid pguidEngine)
{
Log.Debug("ScriptProgramNode: Entering GetEngineInfo");
pbstrEngine = ResourceStrings.EngineName;
pguidEngine = Guid.Parse(Engine.Id);
return VSConstants.S_OK;
}
public int EnumCodeContexts(IDebugDocumentPosition2 pDocPos, out IEnumDebugCodeContexts2 ppEnum)
{
Log.Debug("Program: EnumCodeContexts");
ppEnum = null;
return VSConstants.E_NOTIMPL;
}
public int GetMemoryBytes(out IDebugMemoryBytes2 ppMemoryBytes)
{
Log.Debug("Program: GetMemoryBytes");
ppMemoryBytes = null;
return VSConstants.E_NOTIMPL;
}
public int GetDisassemblyStream(enum_DISASSEMBLY_STREAM_SCOPE dwScope, IDebugCodeContext2 pCodeContext, out IDebugDisassemblyStream2 ppDisassemblyStream)
{
Log.Debug("Program: GetDisassemblyStream");
ppDisassemblyStream = null;
return VSConstants.E_NOTIMPL;
}
public int EnumModules(out IEnumDebugModules2 ppEnum)
{
Log.Debug("Program: EnumModules");
ppEnum = null;
return VSConstants.E_NOTIMPL;
}
public int GetENCUpdate(out object ppUpdate)
{
Log.Debug("Program: GetENCUpdate");
ppUpdate = null;
return VSConstants.E_NOTIMPL;
}
public int EnumCodePaths(string pszHint, IDebugCodeContext2 pStart, IDebugStackFrame2 pFrame, int fSource, out IEnumCodePaths2 ppEnum, out IDebugCodeContext2 ppSafety)
{
Log.Debug("Program: EnumCodePaths");
ppEnum = null;
ppSafety = null;
return VSConstants.E_NOTIMPL;
}
#endregion
#region Implementation of IDebugProgramNodeAttach2
public int OnAttach(ref Guid guidProgramId)
{
Log.Debug("ScriptProgramNode: Entering OnAttach");
return VSConstants.S_OK;
}
#endregion
#region Implementation of IDebugEngineProgram2
public int Stop()
{
Log.Debug("Program: Stop");
Debugger.Stop();
return VSConstants.S_OK;
}
public int WatchForThreadStep(IDebugProgram2 pOriginatingProgram, uint dwTid, int fWatch, uint dwFrame)
{
Log.Debug("Program: WatchForThreadStep");
return VSConstants.S_OK;
}
public int WatchForExpressionEvaluationOnThread(IDebugProgram2 pOriginatingProgram, uint dwTid, uint dwEvalFlags, IDebugEventCallback2 pExprCallback, int fWatch)
{
Log.Debug("Program: WatchForExpressionEvaluationOnThread");
return VSConstants.S_OK;
}
#endregion
#region Implementation of IDebugThread2
public int EnumFrameInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, uint nRadix, out IEnumDebugFrameInfo2 ppEnum)
{
Log.Debug("Thread: EnumFrameInfo");
ppEnum = new ScriptStackFrameCollection(Debugger.CallStack, this);
return VSConstants.S_OK;
}
public int SetThreadName(string pszName)
{
Log.Debug("Thread: SetThreadName");
return VSConstants.E_NOTIMPL;
}
public int GetProgram(out IDebugProgram2 ppProgram)
{
Log.Debug("Thread: GetProgram");
ppProgram = this;
return VSConstants.S_OK;
}
public int CanSetNextStatement(IDebugStackFrame2 pStackFrame, IDebugCodeContext2 pCodeContext)
{
Log.Debug("Thread: CanSetNextStatement");
return VSConstants.S_OK;
}
public int SetNextStatement(IDebugStackFrame2 pStackFrame, IDebugCodeContext2 pCodeContext)
{
Log.Debug("Thread: SetNextStatement");
return VSConstants.S_OK;
}
public int GetThreadId(out uint pdwThreadId)
{
Log.Debug("Thread: GetThreadId");
pdwThreadId = 0;
return VSConstants.S_OK;
}
public int Suspend(out uint pdwSuspendCount)
{
Log.Debug("Thread: Suspend");
pdwSuspendCount = 0;
return VSConstants.S_OK;
}
public int Resume(out uint pdwSuspendCount)
{
Log.Debug("Thread: Resume");
pdwSuspendCount = 0;
return VSConstants.E_NOTIMPL;
}
public int GetThreadProperties(enum_THREADPROPERTY_FIELDS dwFields, THREADPROPERTIES[] ptp)
{
Log.Debug("Thread: GetThreadProperties");
if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_ID) != 0)
{
ptp[0].dwThreadId = 0;
ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_ID;
}
if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_NAME) != 0)
{
ptp[0].bstrName = "Thread";
ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_NAME;
}
if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_STATE) != 0)
{
ptp[0].dwThreadState = (int)enum_THREADSTATE.THREADSTATE_STOPPED;
ptp[0].dwFields |= enum_THREADPROPERTY_FIELDS.TPF_STATE;
}
return VSConstants.S_OK;
}
public int GetLogicalThread(IDebugStackFrame2 pStackFrame, out IDebugLogicalThread2 ppLogicalThread)
{
Log.Debug("Thread: GetLogicalThread");
ppLogicalThread = null;
return VSConstants.E_NOTIMPL;
}
#endregion
#region Implementation of IEnumDebugThreads2
public int Next(uint celt, IDebugThread2[] rgelt, ref uint pceltFetched)
{
rgelt[0] = this;
pceltFetched = 1;
return VSConstants.S_OK;
}
public int Skip(uint celt)
{
return VSConstants.E_NOTIMPL;
}
public int Reset()
{
return VSConstants.S_OK;
}
public int Clone(out IEnumDebugThreads2 ppEnum)
{
ppEnum = null;
return VSConstants.E_NOTIMPL;
}
public int GetCount(out uint pcelt)
{
pcelt = 1;
return VSConstants.S_OK;
}
#endregion
#region Implementation of IDebugModule2
public int GetInfo(enum_MODULE_INFO_FIELDS dwFields, MODULE_INFO[] pinfo)
{
Log.Debug("ScriptProgramNode: IDebugModule2.GetInfo");
if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_NAME) != 0)
{
pinfo[0].m_bstrName = FileName;
pinfo[0].dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_NAME;
}
if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_FLAGS) != 0)
{
pinfo[0].m_dwModuleFlags = enum_MODULE_FLAGS.MODULE_FLAG_SYMBOLS;
pinfo[0].dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_FLAGS;
}
if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION) != 0)
{
pinfo[0].m_bstrUrlSymbolLocation = @".\";
pinfo[0].dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION;
}
return VSConstants.S_OK;
}
public int ReloadSymbols_Deprecated(string pszUrlToSymbols, out string pbstrDebugMessage)
{
throw new NotImplementedException();
}
#endregion
#region Implementation of IDebugModule3
public int GetSymbolInfo(enum_SYMBOL_SEARCH_INFO_FIELDS dwFields, MODULE_SYMBOL_SEARCH_INFO[] pinfo)
{
// This engine only supports loading symbols at the location specified in the binary's symbol path location in the PE file and
// does so only for the primary exe of the debuggee.
// Therefore, it only displays if the symbols were loaded or not. If symbols were loaded, that path is added.
pinfo[0] = new MODULE_SYMBOL_SEARCH_INFO();
pinfo[0].dwValidFields = 1; // SSIF_VERBOSE_SEARCH_INFO;
string symbolPath = "Symbols Loaded - " + FileName;
pinfo[0].bstrVerboseSearchInfo = symbolPath;
return VSConstants.S_OK;
}
public int LoadSymbols()
{
return VSConstants.E_NOTIMPL;
}
public int IsUserCode(out int pfUser)
{
pfUser = 1;
return VSConstants.S_OK;
}
public int SetJustMyCodeState(int fIsUserCode)
{
return VSConstants.E_NOTIMPL;
}
#endregion
}
}