// 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(EngineConstants.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 = m_address.ToString(); 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) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_MODULEURL) != 0) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTION) != 0) { } if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTIONOFFSET) != 0) { } return(EngineConstants.S_OK); } 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 & enum_MODULE_INFO_FIELDS.MIF_NAME) != 0) { info.m_bstrName = System.IO.Path.GetFileName(this.DebuggedModule.Name); info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_NAME; } if ((dwFields & enum_MODULE_INFO_FIELDS.MIF_URL) != 0) { info.m_bstrUrl = this.DebuggedModule.Name; info.dwValidFields |= enum_MODULE_INFO_FIELDS.MIF_URL; } /*if ((dwFields & (uint)enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS) != 0) * { * info.m_addrLoadAddress = (ulong)this.DebuggedModule.BaseAddress; * info.dwValidFields |= (uint)enum_MODULE_INFO_FIELDS.MIF_LOADADDRESS; * } * if ((dwFields & (uint)enum_MODULE_INFO_FIELDS.MIF_PREFFEREDADDRESS) != 0) * { * // 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 |= (uint)enum_MODULE_INFO_FIELDS.MIF_PREFFEREDADDRESS; ; * } * if ((dwFields & (uint)enum_MODULE_INFO_FIELDS.MIF_SIZE) != 0) * { * info.m_dwSize = this.DebuggedModule.Size; * info.dwValidFields |= (uint)enum_MODULE_INFO_FIELDS.MIF_SIZE; * } * if ((dwFields & (uint)enum_MODULE_INFO_FIELDS.MIF_LOADORDER) != 0) * { * info.m_dwLoadOrder = this.DebuggedModule.GetLoadOrder(); * info.dwValidFields |= (uint)enum_MODULE_INFO_FIELDS.MIF_LOADORDER; * } * if ((dwFields & (uint)enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION) != 0) * { * if (this.DebuggedModule.SymbolsLoaded) * { * info.m_bstrUrlSymbolLocation = this.DebuggedModule.SymbolPath; * info.dwValidFields |= (uint)enum_MODULE_INFO_FIELDS.MIF_URLSYMBOLLOCATION; * } * } * if ((dwFields & (uint)enum_MODULE_INFO_FIELDS.MIF_FLAGS) != 0) * { * info.m_dwModuleFlags = 0; * if (this.DebuggedModule.SymbolsLoaded) * { * info.m_dwModuleFlags |= (uint)(enum_MODULE_FLAGS.MODULE_FLAG_SYMBOLS); * } * info.dwValidFields |= (uint)enum_MODULE_INFO_FIELDS.MIF_FLAGS; * }*/ infoArray[0] = info; return(EngineConstants.S_OK); } catch (ComponentException e) { return(e.HRESULT); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { //Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); //Debug.Assert(m_pollThread == null); Debug.Assert(m_engineCallback == null); Debug.Assert(debuggedProcess == null); Debug.Assert(m_ad7ProgramId == Guid.Empty); process = null; try { //string commandLine = EngineUtils.BuildCommandLine(exe, args); //ProcessLaunchInfo processLaunchInfo = new ProcessLaunchInfo(exe, commandLine, dir, env, options, (uint)launchFlags, hStdInput, hStdOutput, hStdError); // We are being asked to debug a process when we currently aren't debugging anything //m_pollThread = new WorkerThread(); string portname; port.GetPortName(out portname); m_engineCallback = new EngineCallback(this, ad7Callback); XmlDocument doc = new XmlDocument(); doc.LoadXml(options); XmlElement root = (XmlElement)doc.ChildNodes[0]; string ipaddress = root.GetAttribute("targetaddress"); int ipport = Int32.Parse(root.GetAttribute("port")); int connectiontries = Int32.Parse(root.GetAttribute("connectiontries")); int connectiondelay = Int32.Parse(root.GetAttribute("connectiondelay")); bool autoruninterpreter = Boolean.Parse(root.GetAttribute("autoruninterpreter")); bool suspendonstartup = Boolean.Parse(root.GetAttribute("suspendonstartup")); List <SquirrelDebugFileContext> ctxs = new List <SquirrelDebugFileContext>(); foreach (XmlElement e in doc.GetElementsByTagName("context")) { string rootpath = e.GetAttribute("rootpath"); string pathfixup = e.GetAttribute("pathfixup"); SquirrelDebugFileContext sdfc = new SquirrelDebugFileContext(rootpath, pathfixup); ctxs.Add(sdfc); } // Complete the win32 attach on the poll thread //THIS IS A MASSIVE HACK //the 'options' parameter is formatted this way "targetaddress,port,autorunintepreter,suspendonstartup,projectfolder,pathfixup" //I should find a better way to pass this params //fix working dir) dir = dir.Replace('/', '\\'); Process proc = null; if (autoruninterpreter) { proc = new Process(); proc.EnableRaisingEvents = false; proc.StartInfo.UseShellExecute = false; baseDir = proc.StartInfo.WorkingDirectory = dir; proc.StartInfo.FileName = exe; proc.StartInfo.Arguments = args; proc.StartInfo.RedirectStandardOutput = false; proc.StartInfo.RedirectStandardError = false; proc.Start(); } AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); if (proc != null) { adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)proc.Id; } else { adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID; adProcessId.guidProcessId = Guid.NewGuid(); } EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); debuggedProcess = (SquirrelProcess)process; debuggedProcess.Engine = this; debuggedProcess.Process = proc; debuggedProcess.Name = proc != null? proc.StartInfo.FileName : "remoteprocess"; debuggedProcess.EngineCallback = m_engineCallback; debuggedProcess.IpAddress = ipaddress; debuggedProcess.IpPort = ipport; debuggedProcess.SuspendOnStartup = suspendonstartup; debuggedProcess.FileContexts = ctxs.ToArray(); //debuggedProcess.ConnectionTries = connectiontries; //debuggedProcess.ConnectionDelay = connectiondelay; //debuggedProcess.PathFixup = pathfixup; //debuggedProcess.ProjectFolder = projectfolder; /*DebuggedThread thread = new DebuggedThread(1); * DebuggedModule module = new DebuggedModule("the module"); * * m_engineCallback.OnModuleLoad(module); * m_engineCallback.OnSymbolSearch(module, "nothing", 0); * m_engineCallback.OnThreadStart(thread); * m_engineCallback.OnLoadComplete(thread);*/ return(EngineConstants.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(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_ad7ProgramId == Guid.Empty); // MessageBox.Show("IDebugEngine2.Attach", "Debugger debugging", MessageBoxButtons.OK, 0); if (celtPrograms != 1) { Debug.Fail("SampleEngine only expects to see one program in a process"); throw new ArgumentException(); } try { int processId = EngineUtils.GetProcessId(rgpPrograms[0]); if (processId == 0) { return(EngineConstants.E_NOTIMPL); // sample engine only supports system processes } EngineUtils.RequireOk(rgpPrograms[0].GetProgramId(out m_ad7ProgramId)); // Attach can either be called to attach to a new process, or to complete an attach // to a launched process /* if (m_pollThread == null) * { * // We are being asked to debug a process when we currently aren't debugging anything * m_pollThread = new WorkerThread(); * * m_engineCallback = new EngineCallback(this, ad7Callback); * * // Complete the win32 attach on the poll thread * m_pollThread.RunOperation(new Operation(delegate * { * m_debuggedProcess = Worker.AttachToProcess(m_engineCallback, processId); * })); * * m_pollThread.SetDebugProcess(m_debuggedProcess); * } * else * { * if (processId != m_debuggedProcess.Id) * { * Debug.Fail("Asked to attach to a process while we are debugging"); * return EngineConstants.E_FAIL; * } * * m_pollThread.SetDebugProcess(m_debuggedProcess); * } */ AD7EngineCreateEvent.Send(this); AD7ProgramCreateEvent.Send(this); // start polling for debug events on the poll thread /*m_pollThread.RunOperationAsync(new Operation(delegate * { * m_debuggedProcess.ResumeEventPump(); * }));*/ return(EngineConstants.S_OK); } catch (ComponentException e) { return(e.HRESULT); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Parses a text-based expression for evaluation. // The engine sample only supports locals and parameters so the only task here is to check the names in those collections. int IDebugExpressionContext2.ParseText(string pszCode, enum_PARSEFLAGS dwFlags, uint nRadix, out IDebugExpression2 ppExpr, out string pbstrError, out uint pichError) { pbstrError = ""; pichError = 0; ppExpr = null; if (pszCode.Length == 0) { pbstrError = "Invalid Expression"; pichError = (uint)pbstrError.Length; return(EngineConstants.S_FALSE); } try { bool iswatch = true; //HACK WARNING //I put a $ in front of the expression so I know that is not a watch in //is done by SquirrelAuthoringScope::GetDataTipText (alberto) if (pszCode[0] == '$') { Debug.WriteLine("!Evaluating " + pszCode); iswatch = false; pszCode = pszCode.Substring(1); if (pszCode.Length == 0) { pbstrError = "Invalid Expression"; pichError = (uint)pbstrError.Length; return(EngineConstants.S_FALSE); } } if (sqframe.Locals != null) { Debug.WriteLine("Evaluating " + pszCode); string[] targets = pszCode.Split(new char[] { '.' }); SquirrelDebugObject val; if (EvaluateSquirrelObject(sqframe.Locals, targets, 0, out val)) { ppExpr = new AD7Expression(new SquirrelDebugObject(pszCode, val.Value)); return(EngineConstants.S_OK); } if (targets[0] != "this") { List <string> trgswiththis = new List <string>(); trgswiththis.Add("this"); trgswiththis.AddRange(targets); if (EvaluateSquirrelObject(sqframe.Locals, trgswiththis.ToArray(), 0, out val)) { ppExpr = new AD7Expression(new SquirrelDebugObject(pszCode, val.Value)); Debug.WriteLine("Succeeded with 'this'" + pszCode); return(EngineConstants.S_OK); } } } //if(sqframe.Watches.ContainsKey(pszCode)) if (iswatch) { ctx.AddWatch(pszCode); SquirrelDebugObject val; if (sqframe.Watches.TryGetValue(pszCode, out val)) { ppExpr = new AD7Expression(val); return(EngineConstants.S_OK); } } pbstrError = "Invalid Expression"; pichError = (uint)pbstrError.Length; return(EngineConstants.S_FALSE); } catch (ComponentException e) { return(e.HRESULT); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// 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 uContextCompare, IDebugMemoryContext2[] compareToItems, uint compareToLength, out uint foundIndex) { foundIndex = uint.MaxValue; try { enum_CONTEXT_COMPARE contextCompare = (enum_CONTEXT_COMPARE)uContextCompare; for (uint c = 0; c < compareToLength; c++) { AD7MemoryAddress compareTo = compareToItems[c] as AD7MemoryAddress; if (compareTo == null) { continue; } if (!AD7Engine.ReferenceEquals(this.m_engine, compareTo.m_engine)) { continue; } bool result; switch (contextCompare) { case enum_CONTEXT_COMPARE.CONTEXT_EQUAL: result = (this.m_address == compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN: result = (this.m_address < compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN: result = (this.m_address > compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_LESS_THAN_OR_EQUAL: result = (this.m_address <= compareTo.m_address); break; case enum_CONTEXT_COMPARE.CONTEXT_GREATER_THAN_OR_EQUAL: result = (this.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 = (this.m_address == compareTo.m_address); break; /*Alberto * case enum_CONTEXT_COMPARE.CONTEXT_SAME_MODULE: * result = (this.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(EngineConstants.E_NOTIMPL); } if (result) { foundIndex = c; return(EngineConstants.S_OK); } } return(EngineConstants.S_FALSE); } catch (ComponentException e) { return(e.HRESULT); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Gets properties that describe a thread. int IDebugThread2.GetThreadProperties(enum_THREADPROPERTY_FIELDS dwFields, THREADPROPERTIES[] propertiesArray) { try { THREADPROPERTIES props; if (propertiesArray.Length > 0) { props = propertiesArray[0]; } else { props = new THREADPROPERTIES(); } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_ID) != 0) { props.dwThreadId = (uint)Id; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_ID; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT) != 0) { // sample debug engine doesn't support suspending threads props.dwSuspendCount = (uint)SuspendCount; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_STATE) != 0) { props.dwThreadState = (uint)enum_THREADSTATE.THREADSTATE_RUNNING; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_STATE; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_PRIORITY) != 0) { props.bstrPriority = "Normal"; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_PRIORITY; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_NAME) != 0) { props.bstrName = name; props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_NAME; } if ((dwFields & enum_THREADPROPERTY_FIELDS.TPF_LOCATION) != 0) { props.bstrLocation = GetCurrentLocation();// "SquirrelThread::GetCurrentLocation!!(alberto fix me)"; //GetCurrentLocation(true); props.dwFields |= enum_THREADPROPERTY_FIELDS.TPF_LOCATION; } if (propertiesArray.Length > 0) { propertiesArray[0] = props; } return(EngineConstants.S_OK); } catch (ComponentException e) { return(e.HRESULT); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }