// Creates an enumerator for properties associated with the stack frame, such as local variables. // The sample engine only supports returning locals and parameters. Other possible values include // class fields (this pointer), registers, exceptions... int IDebugStackFrame2.EnumProperties(enum_DEBUGPROP_INFO_FLAGS dwFields, uint nRadix, ref Guid guidFilter, uint dwTimeout, out uint elementsReturned, out IEnumDebugPropertyInfo2 enumObject) { int hr; elementsReturned = 0; enumObject = null; try { if (guidFilter == AD7Guids.guidFilterLocalsPlusArgs || guidFilter == AD7Guids.guidFilterAllLocalsPlusArgs) { CreateLocalsPlusArgsProperties(out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else if (guidFilter == AD7Guids.guidFilterLocals) { CreateLocalProperties(out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else if (guidFilter == AD7Guids.guidFilterArgs) { CreateParameterProperties(out elementsReturned, out enumObject); hr = VSConstants.S_OK; } else { hr = VSConstants.E_NOTIMPL; } } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(hr); }
// Gets the file statement range of the document context. // A statement range is the range of the lines that contributed the code to which this document context refers. int IDebugDocumentContext2.GetStatementRange(TEXT_POSITION[] pBegPosition, TEXT_POSITION[] pEndPosition) { try { pBegPosition[0].dwColumn = m_begPos.dwColumn; pBegPosition[0].dwLine = m_begPos.dwLine; pEndPosition[0].dwColumn = m_endPos.dwColumn; pEndPosition[0].dwLine = m_endPos.dwLine; } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
// Gets the file statement range of the document context. // A statement range is the range of the lines that contributed the code to which this document context refers. int IDebugDocumentContext2.GetStatementRange(TEXT_POSITION[] pBegPosition, TEXT_POSITION[] pEndPosition) { try { pBegPosition[0].dwColumn = _textPosition.BeginPosition.dwColumn; pBegPosition[0].dwLine = _textPosition.BeginPosition.dwLine; pEndPosition[0].dwColumn = _textPosition.EndPosition.dwColumn; pEndPosition[0].dwLine = _textPosition.EndPosition.dwLine; } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(Constants.S_OK); }
public int GetStatementRange(TEXT_POSITION[] pBegPosition, TEXT_POSITION[] pEndPosition) { try { pBegPosition[0].dwColumn = start.dwColumn; pBegPosition[0].dwLine = start.dwLine; pEndPosition[0].dwColumn = end.dwColumn; pEndPosition[0].dwLine = end.dwLine; } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
public int Bind() { var docPosition = (IDebugDocumentPosition2)Marshal.GetObjectForIUnknown(requestInfo.bpLocation.unionmember2); string documentName; EngineUtils.CheckOk(docPosition.GetFileName(out documentName)); // Remap document name TODO: Implement this properly const string localRoot = @"C:/dev/TestDebug/TestDebug"; documentName = documentName.Replace('\\', '/'); const string remoteRoot = @"/mnt/c/dev/TestDebug/TestDebug"; documentName = remoteRoot + documentName.Substring(localRoot.Length); var startPosition = new TEXT_POSITION[1]; var endPosition = new TEXT_POSITION[1]; EngineUtils.CheckOk(docPosition.GetRange(startPosition, endPosition)); var engine = breakpointManager.Engine; breakpoint = engine.Session.Breakpoints.Add(documentName, (int)startPosition[0].dwLine + 1, (int)startPosition[0].dwColumn + 1); breakpointManager.Add(breakpoint, this); SetCondition(requestInfo.bpCondition); SetPassCount(requestInfo.bpPassCount); lock (boundBreakpoints) { uint address = 0; var breakpointResolution = new MonoBreakpointResolution(engine, address, GetDocumentContext(address)); var boundBreakpoint = new MonoBoundBreakpoint(engine, address, this, breakpointResolution); boundBreakpoints.Add(boundBreakpoint); engine.Send(new MonoBreakpointBoundEvent(this, boundBreakpoint), MonoBreakpointBoundEvent.IID, null); } return(VSConstants.S_OK); }
private void SendStartDebuggingError(Exception exception) { if (exception is OperationCanceledException) { return; // don't show a message in this case } string description = EngineUtils.GetExceptionDescription(exception); string message = string.Format(CultureInfo.CurrentCulture, MICoreResources.Error_UnableToStartDebugging, description); var initializationException = exception as MIDebuggerInitializeFailedException; if (initializationException != null) { string outputMessage = string.Join("\r\n", initializationException.OutputLines) + "\r\n"; // NOTE: We can't write to the output window by sending an AD7 event because this may be called before the session create event LiveLogger.WriteLine(outputMessage); } _engineCallback.OnErrorImmediate(message); }
// Gets the name of the stack frame. // The name of a stack frame is typically the name of the method being executed. int IDebugStackFrame2.GetName(out string name) { name = null; try { if (_functionName != null) { name = _functionName; } return(VSConstants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
public int Attach(IDebugProgram2[] programs, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 pCallback, enum_ATTACH_REASON dwReason) { var program = programs[0]; IDebugProcess2 process; program.GetProcess(out process); Guid processId; process.GetProcessId(out processId); if (processId != this.processId.guidProcessId) { return(VSConstants.S_FALSE); } EngineUtils.RequireOk(program.GetProgramId(out programId)); Session.Run(new SoftDebuggerStartInfo(new SoftDebuggerConnectArgs("", new IPAddress(new byte[] { 192, 168, 137, 3 }), 12345)), new DebuggerSessionOptions { EvaluationOptions = EvaluationOptions.DefaultOptions, ProjectAssembliesOnly = false }); return(VSConstants.S_OK); }
// Gets information that describes this context. public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo) { try { pinfo[0].dwFields = 0; if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS) != 0) { //pinfo[0].bstrAddress = EngineUtils.AsAddr(_address, _engine.DebuggedProcess.Is64BitArch); pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS; } // Fields not supported by the sample if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSOFFSET) != 0) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE) != 0) { //pinfo[0].bstrAddressAbsolute = EngineUtils.AsAddr(_address, _engine.DebuggedProcess.Is64BitArch); pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE; } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTIONOFFSET) != 0) { } return(VSConstants.S_OK); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint aCeltPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { // Attach the debug engine to a program. // // Attach can either be called to attach to a new process, or to complete an attach // to a launched process. // So could we simplify and move code from LaunchSuspended to here and maybe even // eliminate the debughost? Although I supposed DebugHost has some other uses as well. if (aCeltPrograms != 1) { System.Diagnostics.Debug.Fail("Cosmos Debugger only supports one debug target at a time."); throw new ArgumentException(); } try { EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out mProgramID)); mProgram = rgpPrograms[0]; AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); AD7ModuleLoadEvent.Send(this, mModule, true); // Dummy main thread // We dont support threads yet, but the debugger expects threads. // So we create a dummy object to represente our only "thread". mThread = new AD7Thread(this, mProcess); AD7LoadCompleteEvent.Send(this, mThread); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(VSConstants.S_OK); }
/// <summary> /// Gets the document context for this stack frame. The debugger will call this when the current stack frame is changed /// and will use it to open the correct source document for this stack frame. /// </summary> /// <param name="docContext">The document context.</param> /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns> public int GetDocumentContext(out IDebugDocumentContext2 docContext) { docContext = null; try { if (_hasSource) { // Assume all lines begin and end at the beginning of the line. // TODO: Accurate line endings var lineNumber = (uint)LineNumber; var begTp = new TEXT_POSITION { dwColumn = 0, dwLine = lineNumber - 1 }; var endTp = new TEXT_POSITION { dwColumn = 0, dwLine = lineNumber - 1 }; docContext = new MonoDocumentContext(_documentName, begTp, endTp, null); return(S_OK); } } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } return(S_FALSE); }
public int LaunchSuspended(string server, IDebugPort2 port, string exe, string args, string directory, string environment, string options, enum_LAUNCH_FLAGS launchFlags, uint standardInput, uint standardOutput, uint standardError, IDebugEventCallback2 callback, out IDebugProcess2 process) { waiter = new AutoResetEvent(false); settings = MonoDebuggerSettings.Parse(options); Task.Run(() => { var outputWindow = (IVsOutputWindow)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsOutputWindow)); var generalPaneGuid = VSConstants.GUID_OutWindowDebugPane; outputWindow.GetPane(ref generalPaneGuid, out this.outputWindow); // Upload the contents of the output folder to the target directory if (connection == null) { connection = ConnectionManager.Get(settings); if (!connection.IsConnected) { Log("Connecting SSH and SFTP..."); // Debugger.Launch(); connection.Connect(); Log("Connected"); } } Log("Uploading program..."); // Ensure target directory exists: var targetDirectories = directory.Split('/'); foreach (var part in targetDirectories) { if (!connection.Sftp.Exists(part)) { connection.Sftp.CreateDirectory(part); } connection.Sftp.ChangeDirectory(part); } foreach (var _ in targetDirectories) { connection.Sftp.ChangeDirectory(".."); } var outputDirectory = new DirectoryInfo(Path.GetDirectoryName(exe)); foreach (var file in outputDirectory.EnumerateFiles().Where(x => x.Extension == ".dll" || x.Extension == ".mdb" || x.Extension == ".exe")) { using (var stream = file.OpenRead()) { connection.Sftp.UploadFile(stream, $"{directory}/{file.Name}", true); } Log($"Uploaded {file.FullName}"); } Log("Done"); var targetExe = directory + "/" + Path.GetFileName(exe); connection.Ssh.RunCommand("cd ~"); Log("Launching application"); var commandText = $"mono --debug=mdb-optimizations --debugger-agent=transport=dt_socket,address=0.0.0.0:6438,server=y {targetExe}"; connection.Ssh.RunCommand("kill $(ps auxww | grep '" + commandText + "' | awk '{print $2}')", this.outputWindow, null); runCommand = connection.Ssh.BeginCommand(commandText, this.outputWindow, out runCommandAsyncResult); // Trigger that the app is now running for whomever might be waiting for that signal waiter.Set(); }); Session = new SoftDebuggerSession(); Session.TargetReady += (sender, eventArgs) => { var activeThread = Session.ActiveThread; ThreadManager.Add(activeThread, new MonoThread(this, activeThread)); // Session.Stop(); }; Session.ExceptionHandler = exception => true; Session.TargetExited += (sender, x) => { // runCommand.EndExecute(runCommandAsyncResult); Send(new MonoProgramDestroyEvent((uint?)x.ExitCode ?? 0), MonoProgramDestroyEvent.IID, null); }; Session.TargetUnhandledException += (sender, x) => { Send(new MonoExceptionEvent(x.Backtrace.GetFrame(0)) { IsUnhandled = true }, MonoExceptionEvent.IID, ThreadManager[x.Thread]); }; Session.LogWriter = (stderr, text) => Console.WriteLine(text); Session.OutputWriter = (stderr, text) => Console.WriteLine(text); Session.TargetThreadStarted += (sender, x) => ThreadManager.Add(x.Thread, new MonoThread(this, x.Thread)); Session.TargetThreadStopped += (sender, x) => { ThreadManager.Remove(x.Thread); }; Session.TargetStopped += (sender, x) => Console.WriteLine(x.Type); Session.TargetStarted += (sender, x) => Console.WriteLine(); Session.TargetSignaled += (sender, x) => Console.WriteLine(x.Type); Session.TargetInterrupted += (sender, x) => Console.WriteLine(x.Type); Session.TargetExceptionThrown += (sender, x) => { Send(new MonoExceptionEvent(x.Backtrace.GetFrame(0)), MonoExceptionEvent.IID, ThreadManager[x.Thread]); }; Session.TargetHitBreakpoint += (sender, x) => { var breakpoint = x.BreakEvent as Breakpoint; var pendingBreakpoint = breakpointManager[breakpoint]; Send(new MonoBreakpointEvent(new MonoBoundBreakpointsEnum(pendingBreakpoint.BoundBreakpoints)), MonoBreakpointEvent.IID, ThreadManager[x.Thread]); }; processId = new AD_PROCESS_ID(); processId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID; processId.guidProcessId = Guid.NewGuid(); EngineUtils.CheckOk(port.GetProcess(processId, out process)); Callback = callback; return(VSConstants.S_OK); }
public string GetAddressDescription(uint ip) { // DebuggedModule module = m_debuggedProcess.ResolveAddress(ip); return(EngineUtils.GetAddressDescription(/*module,*/ this, ip)); }
public int LaunchSuspended(string server, IDebugPort2 port, string exe, string args, string directory, string environment, string options, enum_LAUNCH_FLAGS launchFlags, uint standardInput, uint standardOutput, uint standardError, IDebugEventCallback2 callback, out IDebugProcess2 process) { waiter = new AutoResetEvent(false); settings = MonoDebuggerSettings.Load(options); Task.Run(() => { var outputWindow = (IVsOutputWindow)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsOutputWindow)); var generalPaneGuid = VSConstants.GUID_OutWindowDebugPane; outputWindow.GetPane(ref generalPaneGuid, out this.outputWindow); settings.Launcher.Launch(); // Trigger that the app is now running for whomever might be waiting for that signal waiter.Set(); }); Session = new SoftDebuggerSession(); Session.TargetReady += (sender, eventArgs) => { var activeThread = Session.ActiveThread; ThreadManager.Add(activeThread, new MonoThread(this, activeThread)); // Session.Stop(); }; Session.ExceptionHandler = exception => true; Session.TargetExited += (sender, x) => { // runCommand.EndExecute(runCommandAsyncResult); Send(new MonoProgramDestroyEvent((uint?)x.ExitCode ?? 0), MonoProgramDestroyEvent.IID, null); }; Session.TargetUnhandledException += (sender, x) => { Send(new MonoExceptionEvent(x.Backtrace.GetFrame(0)) { IsUnhandled = true }, MonoExceptionEvent.IID, ThreadManager[x.Thread]); }; Session.LogWriter = (stderr, text) => Console.WriteLine(text); Session.OutputWriter = (stderr, text) => Console.WriteLine(text); Session.TargetThreadStarted += (sender, x) => ThreadManager.Add(x.Thread, new MonoThread(this, x.Thread)); Session.TargetThreadStopped += (sender, x) => { ThreadManager.Remove(x.Thread); }; Session.TargetStopped += (sender, x) => Console.WriteLine(x.Type); Session.TargetStarted += (sender, x) => Console.WriteLine(); Session.TargetSignaled += (sender, x) => Console.WriteLine(x.Type); Session.TargetInterrupted += (sender, x) => Console.WriteLine(x.Type); Session.TargetExceptionThrown += (sender, x) => { Send(new MonoExceptionEvent(x.Backtrace.GetFrame(0)), MonoExceptionEvent.IID, ThreadManager[x.Thread]); }; Session.TargetHitBreakpoint += (sender, x) => { var breakpoint = x.BreakEvent as Breakpoint; var pendingBreakpoint = breakpointManager[breakpoint]; Send(new MonoBreakpointEvent(new MonoBoundBreakpointsEnum(pendingBreakpoint.BoundBreakpoints)), MonoBreakpointEvent.IID, ThreadManager[x.Thread]); }; processId = new AD_PROCESS_ID(); processId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID; processId.guidProcessId = Guid.NewGuid(); EngineUtils.CheckOk(port.GetProcess(processId, out process)); Callback = callback; return(VSConstants.S_OK); }
public int Compare(enum_CONTEXT_COMPARE compare, IDebugMemoryContext2[] compareToItems, uint compareToLength, out uint foundIndex) { foundIndex = uint.MaxValue; try { enum_CONTEXT_COMPARE contextCompare = compare; for (uint c = 0; c < compareToLength; c++) { MonoMemoryAddress compareTo = compareToItems[c] as MonoMemoryAddress; if (compareTo == null) { continue; } if (!ReferenceEquals(this.engine, compareTo.engine)) { continue; } bool result; switch (contextCompare) { case enum_CONTEXT_COMPARE.CONTEXT_EQUAL: result = address == compareTo.address; break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN: result = address < compareTo.address; break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN: result = address > compareTo.address; break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN_OR_EQUAL: result = address <= compareTo.address; break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN_OR_EQUAL: result = address >= compareTo.address; break; // The sample debug engine doesn't understand scopes or functions case enum_CONTEXT_COMPARE.CONTEXT_SAME_SCOPE: case enum_CONTEXT_COMPARE.CONTEXT_SAME_FUNCTION: result = address == compareTo.address; break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_MODULE: result = address == compareTo.address; if (!result) { /* * DebuggedModule module = engine.DebuggedProcess.ResolveAddress(address); * * if (module != null) * { * result = (compareTo.address >= module.BaseAddress) && * (compareTo.address < module.BaseAddress + module.Size); * } */ } break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_PROCESS: result = true; break; default: // A new comparison was invented that we don't support return(VSConstants.E_NOTIMPL); } if (result) { foundIndex = c; return(VSConstants.S_OK); } } return(VSConstants.S_FALSE); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
private static RegisterGroup GetGroupForRegister(List<RegisterGroup> registerGroups, string name, EngineUtils.RegisterNameMap nameMap) { string grpName = nameMap.GetGroupName(name); RegisterGroup grp = registerGroups.FirstOrDefault((g) => { return g.Name == grpName; }); if (grp == null) { grp = new RegisterGroup(grpName); registerGroups.Add(grp); } return grp; }
private static void OnInterrupt <G>(string code, InstructionExecutor <G> _, InterruptedEventArgs <G> args) where G : IGroupState <G>, new() { PrintStackPointers(args.ExecutionState); PrintGroupPointers(args.ExecutionState); PrintStackRegister(args.ExecutionState); PrintListRegister(args.ExecutionState); Instruction <G> instruction = args.ExecutionState.GroupState.Group.Instructions[args.ExecutionState.InstructionIndex]; Debug.WriteLine($"\nInstruction: {args.ExecutionState.InstructionIndex}. {instruction.Code} {string.Join(", ", instruction.Payload?.Select(item => ToValueString(item)) ?? Enumerable.Empty<string>())} \n {(instruction.SourcePosition != null ? EngineUtils.GetLineAtPosition(code, instruction.SourcePosition.Value, 100) : null)}"); }
internal async Task BindAsync() { if (CanBind()) { string documentName = null; string functionName = null; TEXT_POSITION[] startPosition = new TEXT_POSITION[1]; TEXT_POSITION[] endPosition = new TEXT_POSITION[1]; string condition = null; lock (_boundBreakpoints) { if (_bp != null) // already bound { Debug.Fail("Breakpoint already bound"); return; } if ((_bpRequestInfo.dwFields & enum_BPREQI_FIELDS.BPREQI_BPLOCATION) != 0) { if (_bpRequestInfo.bpLocation.bpLocationType == (uint)enum_BP_LOCATION_TYPE.BPLT_CODE_FUNC_OFFSET) { IDebugFunctionPosition2 functionPosition = HostMarshal.GetDebugFunctionPositionForIntPtr(_bpRequestInfo.bpLocation.unionmember2); EngineUtils.CheckOk(functionPosition.GetFunctionName(out functionName)); } else if (_bpRequestInfo.bpLocation.bpLocationType == (uint)enum_BP_LOCATION_TYPE.BPLT_CODE_FILE_LINE) { IDebugDocumentPosition2 docPosition = HostMarshal.GetDocumentPositionForIntPtr(_bpRequestInfo.bpLocation.unionmember2); // Get the name of the document that the breakpoint was put in EngineUtils.CheckOk(docPosition.GetFileName(out documentName)); // Get the location in the document that the breakpoint is in. EngineUtils.CheckOk(docPosition.GetRange(startPosition, endPosition)); } } if ((_bpRequestInfo.dwFields & enum_BPREQI_FIELDS.BPREQI_CONDITION) != 0 && _bpRequestInfo.bpCondition.styleCondition == enum_BP_COND_STYLE.BP_COND_WHEN_TRUE) { condition = _bpRequestInfo.bpCondition.bstrCondition; } } PendingBreakpoint.BindResult bindResult; // Bind all breakpoints that match this source and line number. if (documentName != null) { bindResult = await PendingBreakpoint.Bind(documentName, startPosition[0].dwLine + 1, startPosition[0].dwColumn, _engine.DebuggedProcess, condition, this); } else { bindResult = await PendingBreakpoint.Bind(functionName, _engine.DebuggedProcess, condition, this); } lock (_boundBreakpoints) { if (bindResult.PendingBreakpoint != null) { _bp = bindResult.PendingBreakpoint; // an MI breakpoint object exists: TODO: lock? } if (bindResult.BoundBreakpoints == null || bindResult.BoundBreakpoints.Count == 0) { _BPError = new AD7ErrorBreakpoint(this, bindResult.ErrorMessage); _engine.Callback.OnBreakpointError(_BPError); } else { Debug.Assert(_bp != null); foreach (BoundBreakpoint bp in bindResult.BoundBreakpoints) { AddBoundBreakpoint(bp); } } } } }
// Compares the memory context to each context in the given array in the manner indicated by compare flags, // returning an index of the first context that matches. public int Compare(enum_CONTEXT_COMPARE Compare, IDebugMemoryContext2[] rgpMemoryContextSet, uint dwMemoryContextSetLen, out uint pdwMemoryContext) { pdwMemoryContext = UInt32.MaxValue; try { for (uint c = 0; c < dwMemoryContextSetLen; c++) { if (!(rgpMemoryContextSet[c] is AD7MemoryAddress compareTo)) { continue; } if (!ReferenceEquals(m_engine, compareTo.m_engine)) { continue; } bool result; switch (Compare) { case enum_CONTEXT_COMPARE.CONTEXT_EQUAL: result = (m_address == compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN: result = (m_address < compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN: result = (m_address > compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN_OR_EQUAL: result = (m_address <= compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN_OR_EQUAL: result = (m_address >= compareTo.m_address); break; // The sample debug engine doesn't understand scopes or functions case enum_CONTEXT_COMPARE.CONTEXT_SAME_SCOPE: case enum_CONTEXT_COMPARE.CONTEXT_SAME_FUNCTION: result = (m_address == compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_MODULE: result = (m_address == compareTo.m_address); if (result == false) { //DebuggedModule module = m_engine.DebuggedProcess.ResolveAddress(m_address); //if (module != null) //{ // result = (compareTo.m_address >= module.BaseAddress) && // (compareTo.m_address < module.BaseAddress + module.Size); //} } break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_PROCESS: result = true; break; default: // A new comparison was invented that we don't support return(VSConstants.E_NOTIMPL); } if (result) { pdwMemoryContext = c; return(VSConstants.S_OK); } } return(VSConstants.S_FALSE); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
void OnEntityResLoaded(string resName, string resPath, UnityEngine.Object resObject, System.Object userData) { IGameObject go = userData as IGameObject; Entity entity = userData as Entity; if (go == null || entity == null) { throw new Exception("World::OnResLoaded: userData cannot transfer to IGameObject or Entity"); } if (KBEngineApp.app.findEntity(entity.id) == null) { Debug.LogWarningFormat("World::OnEntityResLoaded:发现entity已经不存在,则不需要加载资源了"); return; } float y = entity.position.y; //if (entity.isOnGround) // y = 1.3f; Vector3 pos = new Vector3(entity.position.x, y, entity.position.z); Quaternion rotation = Quaternion.Euler(EngineUtils.EngineDirectionToUnity(entity.direction)); GameObject renderObj = GameObject.Instantiate(resObject, pos, rotation) as GameObject; renderObj.name = entity.className + "_" + entity.id; //该方法会由Entity的实现类去完成Unity相关组件的添加和初始化 go.SetRenderObj(renderObj); var synchronizer = renderObj.GetComponent <BaseSynchronizer>(); if (synchronizer != null) { synchronizer.SetDestPosition(entity.position); synchronizer.SetDestDirection(EngineUtils.EngineDirectionToUnity(entity.direction)); synchronizer.SpaceID = KBEngineApp.app.spaceID; _entitySynchronizerDict.Add(entity.id, synchronizer); } EntityUnityComponent component = null; if (entity.isPlayer()) { //如果是玩家自己,需要先disable一下,等待地形完成加载 _playerEntity = renderObj.GetComponent <EntityUnityComponent>(); } component = renderObj.GetComponent <EntityUnityComponent>(); if (component == null) { Debug.LogErrorFormat("Entity资源加载后,竟然没有EntityUnityComponent!,entityId={0}, className={1}", entity.id, entity.className); return; } _entityList.Add(component); _entityDict.Add(entity.id, component); if (OnEntityEnter != null) { OnEntityEnter(component); } if (entity.isPlayer()) { if (_terrain != null) { FinishMyselfLoadTask(); } } }
// Compares the memory context to each context in the given array in the manner indicated by compare flags, // returning an index of the first context that matches. public int Compare(enum_CONTEXT_COMPARE contextCompare, IDebugMemoryContext2[] compareToItems, uint compareToLength, out uint foundIndex) { foundIndex = uint.MaxValue; try { for (uint c = 0; c < compareToLength; c++) { AD7MemoryAddress compareTo = compareToItems[c] as AD7MemoryAddress; if (compareTo == null) { continue; } if (!AD7Engine.ReferenceEquals(_engine, compareTo._engine)) { continue; } bool result; switch (contextCompare) { case enum_CONTEXT_COMPARE.CONTEXT_EQUAL: result = (_address == compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN: result = (_address < compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN: result = (_address > compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN_OR_EQUAL: result = (_address <= compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN_OR_EQUAL: result = (_address >= compareTo._address); break; // The debug engine doesn't understand scopes case enum_CONTEXT_COMPARE.CONTEXT_SAME_SCOPE: result = (_address == compareTo._address); break; case enum_CONTEXT_COMPARE.CONTEXT_SAME_PROCESS: result = true; break; default: // A new comparison was invented that we don't support return(VSConstants.E_NOTIMPL); } if (result) { foundIndex = c; return(VSConstants.S_OK); } } return(VSConstants.S_FALSE); } catch (MIException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Binds this pending breakpoint to one or more code locations. int IDebugPendingBreakpoint2.Bind() { if (CanBind()) { IDebugDocumentPosition2 docPosition = (IDebugDocumentPosition2)(Marshal.GetObjectForIUnknown(_bpRequestInfo.bpLocation.unionmember2)); // Get the name of the document that the breakpoint was put in EngineUtils.CheckOk(docPosition.GetFileName(out global::System.String documentName)); // Get the location in the document that the breakpoint is in. TEXT_POSITION[] startPosition = new TEXT_POSITION[1]; TEXT_POSITION[] endPosition = new TEXT_POSITION[1]; EngineUtils.CheckOk(docPosition.GetRange(startPosition, endPosition)); lock (_boundBreakpoints) { if (_bpRequestInfo.guidLanguage == DebuggerConstants.guidLanguagePython) { PythonBreakpoint bp = _engine.Process.AddBreakpoint( documentName, (int)(startPosition[0].dwLine + 1), _bpRequestInfo.bpCondition.styleCondition.ToPython(), _bpRequestInfo.bpCondition.bstrCondition, _bpRequestInfo.bpPassCount.stylePassCount.ToPython(), (int)_bpRequestInfo.bpPassCount.dwPassCount); AD7BreakpointResolution breakpointResolution = new AD7BreakpointResolution(_engine, bp, GetDocumentContext(bp)); AD7BoundBreakpoint boundBreakpoint = new AD7BoundBreakpoint(_engine, bp, this, breakpointResolution, _enabled); _boundBreakpoints.Add(boundBreakpoint); _bpManager.AddBoundBreakpoint(bp, boundBreakpoint); if (_enabled) { TaskHelpers.RunSynchronouslyOnUIThread(ct => bp.AddAsync(ct)); } return(VSConstants.S_OK); } else if (_bpRequestInfo.guidLanguage == DebuggerConstants.guidLanguageDjangoTemplate) { // bind a Django template PythonBreakpoint bp = _engine.Process.AddDjangoBreakpoint( documentName, (int)(startPosition[0].dwLine + 1) ); AD7BreakpointResolution breakpointResolution = new AD7BreakpointResolution(_engine, bp, GetDocumentContext(bp)); AD7BoundBreakpoint boundBreakpoint = new AD7BoundBreakpoint(_engine, bp, this, breakpointResolution, _enabled); _boundBreakpoints.Add(boundBreakpoint); _bpManager.AddBoundBreakpoint(bp, boundBreakpoint); if (_enabled) { TaskHelpers.RunSynchronouslyOnUIThread(ct => bp.AddAsync(ct)); } return(VSConstants.S_OK); } } } // The breakpoint could not be bound. This may occur for many reasons such as an invalid location, an invalid expression, etc... // The Python engine does not support this. // TODO: send an instance of IDebugBreakpointErrorEvent2 to the UI and return a valid instance of IDebugErrorBreakpoint2 from // IDebugPendingBreakpoint2::EnumErrorBreakpoints. The debugger will then display information about why the breakpoint did not // bind to the user. return(VSConstants.S_FALSE); }
// Binds this pending breakpoint to one or more code locations. int IDebugPendingBreakpoint2.Bind() { try { if (CanBind()) { var xDocPos = (IDebugDocumentPosition2)(Marshal.GetObjectForIUnknown(mBpRequestInfo.bpLocation.unionmember2)); // Get the name of the document that the breakpoint was put in string xDocName; EngineUtils.CheckOk(xDocPos.GetFileName(out xDocName)); xDocName = xDocName.ToLower(); //Bug: Some filenames were returned with the drive letter as lower case but in DocumentGUIDs it was captialised so file-not-found! // Get the location in the document that the breakpoint is in. var xStartPos = new TEXT_POSITION[1]; var xEndPos = new TEXT_POSITION[1]; EngineUtils.CheckOk(xDocPos.GetRange(xStartPos, xEndPos)); uint xAddress = 0; var xDebugInfo = mEngine.mProcess.mDebugInfoDb; // We must check for DocID. This is important because in a solution that contains many projects, // VS will send us BPs from other Cosmos projects (and possibly non Cosmos ones, didnt look that deep) // but we wont have them in our doc list because it contains only ones from the currently project // to run. long xDocID; if (xDebugInfo.DocumentGUIDs.TryGetValue(xDocName, out xDocID)) { // Find which Method the Doc, Line, Col are in. // Must add +1 for both Line and Col. They are 0 based, while SP ones are 1 based. // () around << are VERY important.. + has precedence over << long xPos = (((long)xStartPos[0].dwLine + 1) << 32) + xStartPos[0].dwColumn + 1; try { var xMethod = xDebugInfo.GetMethodByDocumentIDAndLinePosition(xDocID, xPos, xPos); var asm = xDebugInfo.GetAssemblyFileById(xMethod.AssemblyFileID); // We have the method. Now find out what Sequence Point it belongs to. var xSPs = xDebugInfo.GetSequencePoints(asm.Pathname, xMethod.MethodToken); var xSP = xSPs.Single(q => q.LineColStart <= xPos && q.LineColEnd >= xPos); // We have the Sequence Point, find the MethodILOp var xOp = xDebugInfo.GetFirstMethodIlOpByMethodIdAndILOffset(xMethod.ID, xSP.Offset); // Get the address of the Label xAddress = xDebugInfo.GetAddressOfLabel(xOp.LabelName); if (xAddress > 0) { var xBPR = new AD7BreakpointResolution(mEngine, xAddress, GetDocumentContext(xAddress)); var xBBP = new AD7BoundBreakpoint(mEngine, xAddress, this, xBPR); mBoundBPs.Add(xBBP); } // Ask the symbol engine to find all addresses in all modules with symbols that match this source and line number. //uint[] addresses = mEngine.DebuggedProcess.GetAddressesForSourceLocation(null, documentName, startPosition[0].dwLine + 1, startPosition[0].dwColumn); lock (mBoundBPs) { //foreach (uint addr in addresses) { // AD7BreakpointResolution breakpointResolution = new AD7BreakpointResolution(mEngine, addr, GetDocumentContext(addr)); // AD7BoundBreakpoint boundBreakpoint = new AD7BoundBreakpoint(mEngine, addr, this, breakpointResolution); // m_boundBreakpoints.Add(boundBreakpoint); // mEngine.DebuggedProcess.SetBreakpoint(addr, boundBreakpoint); //} } } catch (InvalidOperationException) { //No elements in potXMethods sequence! return(VSConstants.S_FALSE); } } return(VSConstants.S_OK); } else { // The breakpoint could not be bound. This may occur for many reasons such as an invalid location, an invalid expression, etc... // The sample engine does not support this, but a real world engine will want to send an instance of IDebugBreakpointErrorEvent2 to the // UI and return a valid instance of IDebugErrorBreakpoint2 from IDebugPendingBreakpoint2::EnumErrorBreakpoints. The debugger will then // display information about why the breakpoint did not bind to the user. return(VSConstants.S_FALSE); } } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets the MODULE_INFO that describes this module. // This is how the debugger obtains most of the information about the module. int IDebugModule2.GetInfo(enum_MODULE_INFO_FIELDS dwFields, MODULE_INFO[] infoArray) { try { MODULE_INFO info = new MODULE_INFO(); if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_NAME)) { //info.m_bstrName = System.IO.Path.GetFileName(this.DebuggedModule.Name); info.m_bstrName = "DEADBEEF"; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_NAME; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_URL)) { //info.m_bstrUrl = this.DebuggedModule.Name; info.m_bstrUrl = "DEADBEEF"; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URL; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS)) { //info.m_addrLoadAddress = (ulong)this.DebuggedModule.BaseAddress; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_PREFFEREDADDRESS)) { // A debugger that actually supports showing the preferred base should crack the PE header and get // that field. This debugger does not do that, so assume the module loaded where it was suppose to. //info.m_addrPreferredLoadAddress = (ulong)this.DebuggedModule.BaseAddress; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_PREFFEREDADDRESS; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_SIZE)) { //info.m_dwSize = this.DebuggedModule.Size; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_SIZE; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_LOADORDER)) { //info.m_dwLoadOrder = this.DebuggedModule.GetLoadOrder(); info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_LOADORDER; } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION)) { //if (this.DebuggedModule.SymbolsLoaded) { //info.m_bstrUrlSymbolLocation = this.DebuggedModule.SymbolPath; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION; } } if (dwFields.HasFlag(enum_MODULE_INFO_FIELDS.MIF_FLAGS)) { info.m_dwModuleFlags = 0; //if (this.DebuggedModule.SymbolsLoaded) { info.m_dwModuleFlags |= (enum_MODULE_FLAGS.MODULE_FLAG_SYMBOLS); } info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_FLAGS; } infoArray[0] = info; return(VSConstants.S_OK); } //catch (ComponentException e) //{ // return e.HResult; //} catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Attach the debug engine to a program. int IDebugEngine2.Attach(IDebugProgram2[] rgpPrograms, IDebugProgramNode2[] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason) { Debug.Assert(_ad7ProgramId == Guid.Empty); if (celtPrograms != 1) { Debug.Fail("Node debugging only supports one program in a process"); throw new ArgumentException(); } IDebugProgram2 program = rgpPrograms[0]; int processId = EngineUtils.GetProcessId(program); if (processId == 0) { // engine only supports system processes Debug.WriteLine("NodeEngine failed to get process id during attach"); return(VSConstants.E_NOTIMPL); } EngineUtils.RequireOk(program.GetProgramId(out _ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process if (_process == null) { // TODO: Where do we get the language version from? _events = ad7Callback; // Check if we're attaching remotely using the node remote debugging transport if (!NodeProcess.TryAttach(processId, out _process)) { MessageBox.Show("Failed to attach debugger:\n", null, MessageBoxButtons.OK, MessageBoxIcon.Error); return(VSConstants.E_FAIL); } AttachProcessEvents(_process); _attached = true; } else { if (processId != _process.Id) { Debug.Fail("Asked to attach to a process while we are debugging"); return(VSConstants.E_FAIL); } } AD7EngineCreateEvent.Send(this); lock (_syncLock) { _programCreated = true; if (_processLoadedThread != null) { SendLoadComplete(_processLoadedThread); } } Debug.WriteLine("NodeEngine Attach returning S_OK"); return(VSConstants.S_OK); }