//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public DebuggeeCodeContext(DebugEngine engine, DebuggeeDocumentContext documentContext, DebuggeeAddress address) { m_engine = engine; m_documentContext = documentContext ?? throw new ArgumentNullException(nameof(documentContext)); m_address = address ?? throw new ArgumentNullException(nameof(address)); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override int CreateBoundBreakpoint(string location, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext) { // // Register a new GDB breakpoint. // LoggingUtils.PrintFunction(); try { if (m_breakpointRequestInfo.bpLocation.bpLocationType == (uint)enum_BP_TYPE.BPT_DATA) { throw new NotImplementedException(); } m_debugger.RunInterruptOperation(delegate(CLangDebugger debugger) { string command = string.Format("-break-insert -f {0} {1}", ((m_breakpointEnabled) ? "" : "-d"), PathUtils.SantiseWindowsPath(location)); debugger.GdbClient.SendCommand(command, delegate(MiResultRecord resultRecord) { if (resultRecord != null) { if (resultRecord.IsError()) { string errorReason = "<unknown error>"; if (resultRecord.HasField("msg")) { errorReason = resultRecord ["msg"] [0].GetString(); } LoggingUtils.RequireOk(CreateErrorBreakpoint(errorReason, documentContext, codeContext)); } else { MiResultValue breakpointData = resultRecord ["bkpt"] [0]; MiBreakpoint breakpoint = new MiBreakpoint(breakpointData.Values); LoggingUtils.RequireOk(CreateBoundBreakpoint(breakpoint, documentContext, codeContext)); } } }); }); return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override int EvaluateBreakpointLocation(out DebuggeeDocumentContext documentContext, out DebuggeeCodeContext codeContext, out string location) { LoggingUtils.PrintFunction(); try { LoggingUtils.RequireOk(base.EvaluateBreakpointLocation(out documentContext, out codeContext, out location)); /*switch (m_breakpointRequestInfo.bpLocation.bpLocationType) * { * case (uint) enum_BP_LOCATION_TYPE.BPLT_CODE_FILE_LINE: * { * codeContext = CLangDebuggeeCodeContext.GetCodeContextForLocation (m_debugger, location); * * if (codeContext == null) * { * throw new InvalidOperationException (); * } * * documentContext = codeContext.DocumentContext; * * if (documentContext == null) * { * throw new InvalidOperationException (); * } * * break; * } * * default: * { * break; * } * }*/ return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); documentContext = null; codeContext = null; location = string.Empty; return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override int EvaluateBreakpointLocation (out DebuggeeDocumentContext documentContext, out DebuggeeCodeContext codeContext, out string location) { LoggingUtils.PrintFunction (); try { LoggingUtils.RequireOk (base.EvaluateBreakpointLocation (out documentContext, out codeContext, out location)); /*switch (m_breakpointRequestInfo.bpLocation.bpLocationType) { case (uint) enum_BP_LOCATION_TYPE.BPLT_CODE_FILE_LINE: { codeContext = CLangDebuggeeCodeContext.GetCodeContextForLocation (m_debugger, location); if (codeContext == null) { throw new InvalidOperationException (); } documentContext = codeContext.DocumentContext; if (documentContext == null) { throw new InvalidOperationException (); } break; } default: { break; } }*/ return Constants.S_OK; } catch (Exception e) { LoggingUtils.HandleException (e); documentContext = null; codeContext = null; location = string.Empty; return Constants.E_FAIL; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public DebuggeeCodeContext(DebugEngine engine, DebuggeeDocumentContext documentContext, DebuggeeAddress address) { if (documentContext == null) { throw new ArgumentNullException("documentContext"); } if (address == null) { throw new ArgumentNullException("address"); } m_engine = engine; m_documentContext = documentContext; m_address = address; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int EnumCodeContexts (IDebugDocumentPosition2 pDocPos, out IEnumDebugCodeContexts2 ppEnum) { // // Enumerates the code contexts for a given position in a source file. // LoggingUtils.PrintFunction (); try { string fileName; TEXT_POSITION [] startPos = new TEXT_POSITION [1]; TEXT_POSITION [] endPos = new TEXT_POSITION [1]; LoggingUtils.RequireOk (pDocPos.GetFileName (out fileName)); LoggingUtils.RequireOk (pDocPos.GetRange (startPos, endPos)); DebuggeeDocumentContext documentContext = new DebuggeeDocumentContext (m_debugger.Engine, fileName, startPos [0], endPos [0]); CLangDebuggeeCodeContext codeContext = CLangDebuggeeCodeContext.GetCodeContextForDocumentContext (m_debugger, documentContext); if (codeContext == null) { throw new InvalidOperationException ("Failed evaluating code-context for location."); } CLangDebuggeeCodeContext [] codeContexts = new CLangDebuggeeCodeContext [] { codeContext }; ppEnum = new DebuggeeCodeContext.Enumerator (codeContexts); return Constants.S_OK; } catch (Exception e) { LoggingUtils.HandleException (e); ppEnum = null; return Constants.E_FAIL; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public DebuggeeStackFrame(DebugEngine engine, DebuggeeThread thread, string frameName) { m_debugEngine = engine; m_thread = thread; m_codeContext = null; m_documentContext = null; m_property = new DebuggeeProperty(engine, this, frameName, string.Empty); m_stackRegisters = new ConcurrentDictionary <string, DebuggeeProperty> (); m_stackArguments = new ConcurrentDictionary <string, DebuggeeProperty> (); m_stackLocals = new ConcurrentDictionary <string, DebuggeeProperty> (); m_customExpressions = new ConcurrentDictionary <string, DebuggeeProperty> (); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public virtual int CreateErrorBreakpoint(string errorReason, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext) { // // Create and broadcast a generic (non language-specific) errored breakpoint. // LoggingUtils.PrintFunction(); try { DebuggeeBreakpointError errorBreakpoint = new DebuggeeBreakpointError(m_breakpointManager, this, codeContext, errorReason); lock (m_errorBreakpoints) { m_errorBreakpoints.Add(errorBreakpoint); } uint numDebugPrograms = 1; IEnumDebugPrograms2 debugPrograms; IDebugProgram2 [] debugProgramsArray = new IDebugProgram2 [numDebugPrograms]; LoggingUtils.RequireOk(m_breakpointManager.Engine.EnumPrograms(out debugPrograms)); LoggingUtils.RequireOk(debugPrograms.Next(numDebugPrograms, debugProgramsArray, ref numDebugPrograms)); m_breakpointManager.Engine.Broadcast(new DebugEngineEvent.BreakpointError(errorBreakpoint), debugProgramsArray [0], null); return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #region IDebugPendingBreakpoint2 Members //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public virtual int Bind() { // // Binds this pending breakpoint to one or more code locations. // LoggingUtils.PrintFunction(); DebuggeeDocumentContext documentContext = null; DebuggeeCodeContext codeContext = null; string bindLocation = string.Empty; try { ClearErrorBreakpoints(); if (m_breakpointDeleted) { return(Constants.E_BP_DELETED); } LoggingUtils.RequireOk(EvaluateBreakpointLocation(out documentContext, out codeContext, out bindLocation)); LoggingUtils.RequireOk(CreateBoundBreakpoint(bindLocation, documentContext, codeContext)); return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public virtual int EvaluateBreakpointLocation(out DebuggeeDocumentContext documentContext, out DebuggeeCodeContext codeContext, out string location) { LoggingUtils.PrintFunction(); documentContext = null; codeContext = null; location = string.Empty; try { switch (m_breakpointRequestInfo.bpLocation.bpLocationType) { case (uint)enum_BP_LOCATION_TYPE.BPLT_CODE_FILE_LINE: { // // Specifies the location type of the breakpoint as a line of source code. // string fileName; IDebugDocumentPosition2 documentPostion = (IDebugDocumentPosition2)Marshal.GetObjectForIUnknown(m_breakpointRequestInfo.bpLocation.unionmember2); LoggingUtils.RequireOk(documentPostion.GetFileName(out fileName)); bool fileInCurrentProject = true; // TODO if (File.Exists(fileName) && fileInCurrentProject) { TEXT_POSITION [] startPos = new TEXT_POSITION [1]; TEXT_POSITION [] endPos = new TEXT_POSITION [1]; LoggingUtils.RequireOk(documentPostion.GetRange(startPos, endPos)); documentContext = new DebuggeeDocumentContext(m_breakpointManager.Engine, fileName, startPos [0], endPos [0]); location = string.Format("\"{0}:{1}\"", fileName, startPos [0].dwLine + 1); } else { throw new NotImplementedException(); } break; } case (uint)enum_BP_LOCATION_TYPE.BPLT_CODE_FUNC_OFFSET: { // // Specifies the location type of the breakpoint as a code function offset. // string function = string.Empty; IDebugFunctionPosition2 functionPosition = (IDebugFunctionPosition2)Marshal.GetObjectForIUnknown(m_breakpointRequestInfo.bpLocation.unionmember2); TEXT_POSITION [] textPos = new TEXT_POSITION [1]; LoggingUtils.RequireOk(functionPosition.GetFunctionName(out function)); LoggingUtils.RequireOk(functionPosition.GetOffset(textPos)); if (!string.IsNullOrEmpty(function)) { location = function; } break; } case (uint)enum_BP_LOCATION_TYPE.BPLT_CODE_CONTEXT: { // // Specifies the location type of the breakpoint as a code context. // codeContext = ((IDebugCodeContext2)Marshal.GetObjectForIUnknown(m_breakpointRequestInfo.bpLocation.unionmember1)) as DebuggeeCodeContext; if (codeContext != null) { location = codeContext.Address.ToString(); } break; } case (uint)enum_BP_LOCATION_TYPE.BPLT_CODE_STRING: { // // Specifies the location type of the breakpoint as a code string. // throw new NotImplementedException(); } case (uint)enum_BP_LOCATION_TYPE.BPLT_CODE_ADDRESS: { // // Specifies the location type of the breakpoint as a code address. // string address = Marshal.PtrToStringBSTR(m_breakpointRequestInfo.bpLocation.unionmember4); if (!string.IsNullOrEmpty(address)) { location = address; } break; } case (uint)enum_BP_LOCATION_TYPE.BPLT_DATA_STRING: { // // Specifies the location type of the breakpoint as a data string. // string dataExpression = Marshal.PtrToStringBSTR(m_breakpointRequestInfo.bpLocation.unionmember3); if (!string.IsNullOrEmpty(dataExpression)) { location = dataExpression; } break; } default: { break; } } return(Constants.S_OK); } catch (NotImplementedException e) { LoggingUtils.HandleException(e); return(Constants.E_NOTIMPL); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static CLangDebuggeeCodeContext GetCodeContextForDocumentContext(CLangDebugger debugger, DebuggeeDocumentContext documentContext) { LoggingUtils.PrintFunction(); string fileName; TEXT_POSITION [] startOffset = new TEXT_POSITION [1]; TEXT_POSITION [] endOffset = new TEXT_POSITION [1]; LoggingUtils.RequireOk(documentContext.GetName(enum_GETNAME_TYPE.GN_FILENAME, out fileName)); LoggingUtils.RequireOk(documentContext.GetStatementRange(startOffset, endOffset)); string location = string.Format("\"{0}:{1}\"", fileName, startOffset [0].dwLine + 1); return(GetCodeContextForLocation(debugger, location)); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public CLangDebuggeeCodeContext(CLangDebugger debugger, DebuggeeAddress address, DebuggeeDocumentContext documentContext) : base(debugger.Engine, documentContext, address) { m_debugger = debugger; try { string command = string.Format("-interpreter-exec console \"info symbol {0}\"", m_address.ToString()); MiResultRecord resultRecord = m_debugger.GdbClient.SendSyncCommand(command); MiResultRecord.RequireOk(resultRecord, command); string pattern = "(?<symbol>.+)( [\\+] (?<offset>[0-9]+))? (in section (?<section>[^ ]+) of) (?<module>.+)"; Regex regExMatcher = new Regex(pattern, RegexOptions.IgnoreCase); foreach (MiStreamRecord record in resultRecord.Records) { if (!record.Stream.StartsWith("No symbol")) { continue; // early rejection. } StringBuilder sanitisedStream = new StringBuilder(record.Stream); sanitisedStream.Length -= 2; // Strip trailing "\\n" Match regExLineMatch = regExMatcher.Match(sanitisedStream.ToString()); if (regExLineMatch.Success) { string symbol = regExLineMatch.Result("${symbol}"); string offset = regExLineMatch.Result("${offset}"); string section = regExLineMatch.Result("${section}"); string module = regExLineMatch.Result("${module}"); ulong addressOffset = 0ul; ulong.TryParse(offset, out addressOffset); m_symbolName = symbol; m_symbolOffset = addressOffset.ToString(); //string moduleFile = Path.GetFileName (module); //CLangDebuggeeModule module = m_debugger.NativeProgram.GetModule (moduleFile); //MODULE_INFO [] moduleArray = new MODULE_INFO [1]; //LoggingUtils.RequireOk (module.GetInfo (enum_MODULE_INFO_FIELDS.MIF_URL, moduleArray)); //infoArray [0].bstrModuleUrl = moduleArray [0].m_bstrUrl; m_symbolModule = PathUtils.ConvertPathMingwToWindows(module); } } } catch (Exception e) { LoggingUtils.HandleException(e); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void GetInfoFromCurrentLevel (MiResultValueTuple frameTuple) { LoggingUtils.PrintFunction (); try { if (frameTuple == null) { throw new ArgumentNullException ("frameTuple"); } if (frameTuple.HasField ("level")) { m_stackLevel = frameTuple ["level"] [0].GetUnsignedInt (); } // // Discover the function or shared library location. // if (frameTuple.HasField ("addr")) { m_locationAddress = new DebuggeeAddress (frameTuple ["addr"] [0].GetString ()); } else { m_locationAddress = new DebuggeeAddress ("0x0"); } if (frameTuple.HasField ("func")) { m_locationFunction = frameTuple ["func"] [0].GetString (); } else { m_locationFunction = "??"; } m_locationIsSymbolicated = !(m_locationFunction.Equals ("??")); if (frameTuple.HasField ("from")) { m_locationModule = Path.GetFileName (frameTuple ["from"] [0].GetString ()); } else { m_locationModule = string.Empty; } // // Generate code and document contexts for this frame location. // if (frameTuple.HasField ("fullname") && frameTuple.HasField ("line")) { // // If the symbol table isn't yet loaded, we'll need to specify exactly the location of this stack frame. // TEXT_POSITION [] textPositions = new TEXT_POSITION [2]; textPositions [0].dwLine = frameTuple ["line"] [0].GetUnsignedInt () - 1; textPositions [0].dwColumn = 0; textPositions [1].dwLine = textPositions [0].dwLine; textPositions [1].dwColumn = textPositions [0].dwColumn; string filename = PathUtils.ConvertPathCygwinToWindows (frameTuple ["fullname"] [0].GetString ()); m_documentContext = new DebuggeeDocumentContext (m_debugger.Engine, filename, textPositions [0], textPositions [1]); m_codeContext = CLangDebuggeeCodeContext.GetCodeContextForLocation (m_debugger, m_locationAddress.ToString ()); if (m_codeContext == null) { throw new InvalidOperationException (); } } else { m_codeContext = CLangDebuggeeCodeContext.GetCodeContextForLocation (m_debugger, m_locationAddress.ToString ()); m_documentContext = (m_codeContext != null) ? m_codeContext.DocumentContext : null; } } catch (Exception e) { LoggingUtils.HandleException (e); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static CLangDebuggeeCodeContext GetCodeContextForLocation(CLangDebugger debugger, string location) { LoggingUtils.PrintFunction(); try { if (string.IsNullOrEmpty(location)) { throw new ArgumentNullException("location"); } if (location.StartsWith("0x")) { location = "*" + location; } else if (location.StartsWith("\"")) { location = location.Replace("\\", "/"); location = location.Replace("\"", "\\\""); // required to escape the nested string. } string command = string.Format("-interpreter-exec console \"info line {0}\"", location); MiResultRecord resultRecord = debugger.GdbClient.SendSyncCommand(command); MiResultRecord.RequireOk(resultRecord, command); string pattern = "Line (?<line>[0-9]+) of ([\\]*\"(?<file>.+)[\\]*[\"]+) starts at address (?<startaddr>[^ ]+) (?<startsym>[^+]+[+]?[0-9]*[>]?) (but contains no code|and ends at (?<endaddr>[^ ]+) (?<endsym>[^+]+[+]?[0-9]*[>]?)?)"; pattern = pattern.Replace("\\", "\\\\"); Regex regExMatcher = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); foreach (MiStreamRecord record in resultRecord.Records) { if (!record.Stream.StartsWith("Line")) { continue; // early rejection. } StringBuilder sanitisedStream = new StringBuilder(record.Stream); sanitisedStream.Replace("\\\"", "\""); sanitisedStream.Replace("\\\\", "\\"); Match regExLineMatch = regExMatcher.Match(sanitisedStream.ToString()); if (regExLineMatch.Success) { string line = regExLineMatch.Result("${line}"); string file = regExLineMatch.Result("${file}"); string startaddr = regExLineMatch.Result("${startaddr}"); string startsym = regExLineMatch.Result("${startsym}"); string endaddr = regExLineMatch.Result("${endaddr}"); string endsym = regExLineMatch.Result("${endsym}"); TEXT_POSITION [] documentPositions = new TEXT_POSITION [2]; documentPositions [0].dwLine = uint.Parse(line) - 1; documentPositions [0].dwColumn = 0; documentPositions [1].dwLine = documentPositions [0].dwLine; documentPositions [1].dwColumn = uint.MaxValue; DebuggeeAddress startAddress = new DebuggeeAddress(startaddr); DebuggeeDocumentContext documentContext = new DebuggeeDocumentContext(debugger.Engine, file, documentPositions [0], documentPositions [1]); CLangDebuggeeCodeContext codeContext = new CLangDebuggeeCodeContext(debugger, startAddress, documentContext); documentContext.SetCodeContext(codeContext); return(codeContext); } } } catch (Exception e) { LoggingUtils.HandleException(e); } return(null); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void RefreshBreakpoint(object breakpoint) { // // Validate breakpoint input type. This function can be used for 'bound' and 'error' objects, so we need to handle this appropriately. // LoggingUtils.PrintFunction(); CLangDebuggeeBreakpointBound boundBreakpoint = null; CLangDebuggeeBreakpointError errorBreakpoint = null; MiBreakpoint gdbBreakpoint; DebuggeeBreakpointResolution resolution; if (breakpoint == null) { throw new ArgumentNullException("breakpoint"); } else if (breakpoint is CLangDebuggeeBreakpointBound) { boundBreakpoint = breakpoint as CLangDebuggeeBreakpointBound; gdbBreakpoint = boundBreakpoint.GdbBreakpoint; IDebugBreakpointResolution2 boundBreakpointResolution; int handle = boundBreakpoint.GetBreakpointResolution(out boundBreakpointResolution); if (handle == Constants.E_BP_DELETED) { return; } LoggingUtils.RequireOk(handle); resolution = (DebuggeeBreakpointResolution)boundBreakpointResolution; } else if (breakpoint is CLangDebuggeeBreakpointError) { errorBreakpoint = breakpoint as CLangDebuggeeBreakpointError; gdbBreakpoint = errorBreakpoint.GdbBreakpoint; IDebugErrorBreakpointResolution2 errorBreakpointResolution; int handle = errorBreakpoint.GetBreakpointResolution(out errorBreakpointResolution); if (handle == Constants.E_BP_DELETED) { return; } resolution = (DebuggeeBreakpointResolution)errorBreakpointResolution; lock (m_errorBreakpoints) { m_errorBreakpoints.Remove(errorBreakpoint); } } else { throw new ArgumentException("breakpoint"); } // // Query breakpoint info/status directly from GDB/MI. // try { string command = string.Format("-break-info {0}", gdbBreakpoint.ID); m_debugger.GdbClient.SendCommand(command, delegate(MiResultRecord resultRecord) { if (resultRecord == null) { throw new InvalidOperationException(); } else if (resultRecord.IsError()) { // // GDB/MI breakpoint info request failed. // gdbBreakpoint.Address = MiBreakpoint.Pending; (resolution as DebuggeeBreakpointResolution).CodeContext.Address = new DebuggeeAddress(gdbBreakpoint.Address); errorBreakpoint = new CLangDebuggeeBreakpointError(m_debugger, m_breakpointManager, this, (resolution as DebuggeeBreakpointResolution).CodeContext, gdbBreakpoint, resultRecord.Records [1].Stream); lock (m_errorBreakpoints) { m_errorBreakpoints.Add(errorBreakpoint); } m_debugger.Engine.Broadcast(new DebugEngineEvent.BreakpointError(errorBreakpoint), m_debugger.NativeProgram.DebugProgram, m_debugger.NativeProgram.GetThread(m_debugger.NativeProgram.CurrentThreadId)); } else { // // We've probably got sane breakpoint information back. Update current breakpoint values and re-process. // MiResultValue breakpointData = resultRecord ["BreakpointTable"] [0] ["body"] [0] ["bkpt"] [0]; MiBreakpoint currentGdbBreakpoint = new MiBreakpoint(breakpointData.Values); DebuggeeCodeContext codeContext = (resolution as DebuggeeBreakpointResolution).CodeContext; DebuggeeDocumentContext documentContext = codeContext.DocumentContext; LoggingUtils.RequireOk(CreateBoundBreakpoint(currentGdbBreakpoint, documentContext, codeContext)); } }); } catch (Exception e) { LoggingUtils.HandleException(e); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override int CreateBoundBreakpoint (string location, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext) { // // Register a new GDB breakpoint. // LoggingUtils.PrintFunction (); try { if (m_breakpointRequestInfo.bpLocation.bpLocationType == (uint)enum_BP_TYPE.BPT_DATA) { throw new NotImplementedException (); } m_debugger.RunInterruptOperation (delegate (CLangDebugger debugger) { string command = string.Format ("-break-insert -f {0} {1}", ((m_breakpointEnabled) ? "" : "-d"), PathUtils.SantiseWindowsPath (location)); debugger.GdbClient.SendCommand (command, delegate (MiResultRecord resultRecord) { if (resultRecord != null) { if (resultRecord.IsError ()) { string errorReason = "<unknown error>"; if (resultRecord.HasField ("msg")) { errorReason = resultRecord ["msg"] [0].GetString (); } LoggingUtils.RequireOk (CreateErrorBreakpoint (errorReason, documentContext, codeContext)); } else { MiResultValue breakpointData = resultRecord ["bkpt"] [0]; MiBreakpoint breakpoint = new MiBreakpoint (breakpointData.Values); LoggingUtils.RequireOk (CreateBoundBreakpoint (breakpoint, documentContext, codeContext)); } } }); }); return Constants.S_OK; } catch (Exception e) { LoggingUtils.HandleException (e); return Constants.E_FAIL; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int CreateBoundBreakpoint(MiBreakpoint breakpoint, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext) { LoggingUtils.PrintFunction(); try { if (breakpoint == null) { throw new ArgumentNullException("breakpoint"); } if (breakpoint.IsPending()) { // // Address can't be satisfied. Unsatisfied likely indicates the modules or symbols associated with the context aren't loaded, yet. // DebuggeeAddress pendingAddress = new DebuggeeAddress(MiBreakpoint.Pending); DebuggeeCodeContext pendingContext = new CLangDebuggeeCodeContext(m_debugger, pendingAddress, documentContext); LoggingUtils.RequireOk(CreateErrorBreakpoint("Additional library symbols required.", breakpoint, documentContext, pendingContext)); } else if (breakpoint.IsMultiple()) { // // Breakpoint satisfied to multiple locations, no single memory address available. // CLangDebuggeeBreakpointBound boundBreakpoint = new CLangDebuggeeBreakpointBound(m_debugger, m_breakpointManager, this, codeContext, breakpoint); lock (m_boundBreakpoints) { m_boundBreakpoints.Clear(); m_boundBreakpoints.Add(boundBreakpoint); } m_debugger.Engine.Broadcast(new DebugEngineEvent.BreakpointBound(this, boundBreakpoint), m_debugger.NativeProgram.DebugProgram, m_debugger.NativeProgram.GetThread(m_debugger.NativeProgram.CurrentThreadId)); } else { // // Address satisfied, and the breakpoint is legitimately bound. // DebuggeeAddress boundAddress = new DebuggeeAddress(breakpoint.Address); DebuggeeCodeContext addressContext = new CLangDebuggeeCodeContext(m_debugger, boundAddress, documentContext); CLangDebuggeeBreakpointBound boundBreakpoint = new CLangDebuggeeBreakpointBound(m_debugger, m_breakpointManager, this, addressContext, breakpoint); lock (m_boundBreakpoints) { m_boundBreakpoints.Clear(); m_boundBreakpoints.Add(boundBreakpoint); } m_debugger.Engine.Broadcast(new DebugEngineEvent.BreakpointBound(this, boundBreakpoint), m_debugger.NativeProgram.DebugProgram, m_debugger.NativeProgram.GetThread(m_debugger.NativeProgram.CurrentThreadId)); } return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public CLangDebuggeeCodeContext (CLangDebugger debugger, DebuggeeAddress address, DebuggeeDocumentContext documentContext) : base (debugger.Engine, documentContext, address) { m_debugger = debugger; try { string command = string.Format ("-interpreter-exec console \"info symbol {0}\"", m_address.ToString ()); MiResultRecord resultRecord = m_debugger.GdbClient.SendSyncCommand (command); MiResultRecord.RequireOk (resultRecord, command); string pattern = "(?<symbol>.+)( [\\+] (?<offset>[0-9]+))? (in section (?<section>[^ ]+) of) (?<module>.+)"; Regex regExMatcher = new Regex (pattern, RegexOptions.IgnoreCase); foreach (MiStreamRecord record in resultRecord.Records) { if (!record.Stream.StartsWith ("No symbol")) { continue; // early rejection. } StringBuilder sanitisedStream = new StringBuilder (record.Stream); sanitisedStream.Length -= 2; // Strip trailing "\\n" Match regExLineMatch = regExMatcher.Match (sanitisedStream.ToString ()); if (regExLineMatch.Success) { string symbol = regExLineMatch.Result ("${symbol}"); string offset = regExLineMatch.Result ("${offset}"); string section = regExLineMatch.Result ("${section}"); string module = regExLineMatch.Result ("${module}"); ulong addressOffset = 0ul; ulong.TryParse (offset, out addressOffset); m_symbolName = symbol; m_symbolOffset = addressOffset.ToString (); //string moduleFile = Path.GetFileName (module); //CLangDebuggeeModule module = m_debugger.NativeProgram.GetModule (moduleFile); //MODULE_INFO [] moduleArray = new MODULE_INFO [1]; //LoggingUtils.RequireOk (module.GetInfo (enum_MODULE_INFO_FIELDS.MIF_URL, moduleArray)); //infoArray [0].bstrModuleUrl = moduleArray [0].m_bstrUrl; m_symbolModule = PathUtils.ConvertPathMingwToWindows (module); } } } catch (Exception e) { LoggingUtils.HandleException (e); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public virtual int CreateBoundBreakpoint(string location, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext) { LoggingUtils.PrintFunction(); throw new NotImplementedException(); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int CreateErrorBreakpoint (string errorReason, MiBreakpoint gdbBreakpoint, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext) { // // Create a C-language breakpoint. This is tied to a GDB/MI breakpoint object. // LoggingUtils.PrintFunction (); try { CLangDebuggeeBreakpointError errorBreakpoint = new CLangDebuggeeBreakpointError (m_debugger, m_breakpointManager, this, codeContext, gdbBreakpoint, errorReason); lock (m_errorBreakpoints) { m_errorBreakpoints.Clear (); m_errorBreakpoints.Add (errorBreakpoint); } uint numDebugPrograms = 1; IEnumDebugPrograms2 debugPrograms; IDebugProgram2 [] debugProgramsArray = new IDebugProgram2 [numDebugPrograms]; LoggingUtils.RequireOk (m_breakpointManager.Engine.EnumPrograms (out debugPrograms)); LoggingUtils.RequireOk (debugPrograms.Next (numDebugPrograms, debugProgramsArray, ref numDebugPrograms)); m_breakpointManager.Engine.Broadcast (new DebugEngineEvent.BreakpointError (errorBreakpoint), debugProgramsArray [0], null); return Constants.S_OK; } catch (Exception e) { LoggingUtils.HandleException (e); return Constants.E_FAIL; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int CreateBoundBreakpoint (MiBreakpoint breakpoint, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext) { LoggingUtils.PrintFunction (); try { if (breakpoint == null) { throw new ArgumentNullException ("breakpoint"); } if (breakpoint.IsPending ()) { // // Address can't be satisfied. Unsatisfied likely indicates the modules or symbols associated with the context aren't loaded, yet. // DebuggeeAddress pendingAddress = new DebuggeeAddress (MiBreakpoint.Pending); DebuggeeCodeContext pendingContext = new CLangDebuggeeCodeContext (m_debugger, pendingAddress, documentContext); LoggingUtils.RequireOk (CreateErrorBreakpoint ("Additional library symbols required.", breakpoint, documentContext, pendingContext)); } else if (breakpoint.IsMultiple ()) { // // Breakpoint satisfied to multiple locations, no single memory address available. // CLangDebuggeeBreakpointBound boundBreakpoint = new CLangDebuggeeBreakpointBound (m_debugger, m_breakpointManager, this, codeContext, breakpoint); lock (m_boundBreakpoints) { m_boundBreakpoints.Clear (); m_boundBreakpoints.Add (boundBreakpoint); } m_debugger.Engine.Broadcast (new DebugEngineEvent.BreakpointBound (this, boundBreakpoint), m_debugger.NativeProgram.DebugProgram, m_debugger.NativeProgram.GetThread (m_debugger.NativeProgram.CurrentThreadId)); } else { // // Address satisfied, and the breakpoint is legitimately bound. // DebuggeeAddress boundAddress = new DebuggeeAddress (breakpoint.Address); DebuggeeCodeContext addressContext = new CLangDebuggeeCodeContext (m_debugger, boundAddress, documentContext); CLangDebuggeeBreakpointBound boundBreakpoint = new CLangDebuggeeBreakpointBound (m_debugger, m_breakpointManager, this, addressContext, breakpoint); lock (m_boundBreakpoints) { m_boundBreakpoints.Clear (); m_boundBreakpoints.Add (boundBreakpoint); } m_debugger.Engine.Broadcast (new DebugEngineEvent.BreakpointBound (this, boundBreakpoint), m_debugger.NativeProgram.DebugProgram, m_debugger.NativeProgram.GetThread (m_debugger.NativeProgram.CurrentThreadId)); } return Constants.S_OK; } catch (Exception e) { LoggingUtils.HandleException (e); return Constants.E_FAIL; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static CLangDebuggeeCodeContext GetCodeContextForLocation (CLangDebugger debugger, string location) { LoggingUtils.PrintFunction (); try { if (string.IsNullOrEmpty (location)) { throw new ArgumentNullException ("location"); } if (location.StartsWith ("0x")) { location = "*" + location; } else if (location.StartsWith ("\"")) { location = location.Replace ("\\", "/"); location = location.Replace ("\"", "\\\""); // required to escape the nested string. } string command = string.Format ("-interpreter-exec console \"info line {0}\"", location); MiResultRecord resultRecord = debugger.GdbClient.SendSyncCommand (command); MiResultRecord.RequireOk (resultRecord, command); string pattern = "Line (?<line>[0-9]+) of ([\\]*\"(?<file>.+)[\\]*[\"]+) starts at address (?<startaddr>[^ ]+) (?<startsym>[^+]+[+]?[0-9]*[>]?) (but contains no code|and ends at (?<endaddr>[^ ]+) (?<endsym>[^+]+[+]?[0-9]*[>]?)?)"; pattern = pattern.Replace ("\\", "\\\\"); Regex regExMatcher = new Regex (pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); foreach (MiStreamRecord record in resultRecord.Records) { if (!record.Stream.StartsWith ("Line")) { continue; // early rejection. } StringBuilder sanitisedStream = new StringBuilder (record.Stream); sanitisedStream.Replace ("\\\"", "\""); sanitisedStream.Replace ("\\\\", "\\"); Match regExLineMatch = regExMatcher.Match (sanitisedStream.ToString ()); if (regExLineMatch.Success) { string line = regExLineMatch.Result ("${line}"); string file = regExLineMatch.Result ("${file}"); string startaddr = regExLineMatch.Result ("${startaddr}"); string startsym = regExLineMatch.Result ("${startsym}"); string endaddr = regExLineMatch.Result ("${endaddr}"); string endsym = regExLineMatch.Result ("${endsym}"); TEXT_POSITION [] documentPositions = new TEXT_POSITION [2]; documentPositions [0].dwLine = uint.Parse (line) - 1; documentPositions [0].dwColumn = 0; documentPositions [1].dwLine = documentPositions [0].dwLine; documentPositions [1].dwColumn = uint.MaxValue; DebuggeeAddress startAddress = new DebuggeeAddress (startaddr); DebuggeeDocumentContext documentContext = new DebuggeeDocumentContext (debugger.Engine, file, documentPositions [0], documentPositions [1]); CLangDebuggeeCodeContext codeContext = new CLangDebuggeeCodeContext (debugger, startAddress, documentContext); documentContext.SetCodeContext (codeContext); return codeContext; } } } catch (Exception e) { LoggingUtils.HandleException (e); } return null; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static CLangDebuggeeCodeContext GetCodeContextForDocumentContext (CLangDebugger debugger, DebuggeeDocumentContext documentContext) { LoggingUtils.PrintFunction (); string fileName; TEXT_POSITION [] startOffset = new TEXT_POSITION [1]; TEXT_POSITION [] endOffset = new TEXT_POSITION [1]; LoggingUtils.RequireOk (documentContext.GetName (enum_GETNAME_TYPE.GN_FILENAME, out fileName)); LoggingUtils.RequireOk (documentContext.GetStatementRange (startOffset, endOffset)); string location = string.Format ("\"{0}:{1}\"", fileName, startOffset [0].dwLine + 1); return GetCodeContextForLocation (debugger, location); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void GetInfoFromCurrentLevel(MiResultValueTuple frameTuple) { LoggingUtils.PrintFunction(); try { if (frameTuple == null) { throw new ArgumentNullException("frameTuple"); } if (frameTuple.HasField("level")) { m_stackLevel = frameTuple ["level"] [0].GetUnsignedInt(); } // // Discover the function or shared library location. // if (frameTuple.HasField("addr")) { m_locationAddress = new DebuggeeAddress(frameTuple ["addr"] [0].GetString()); } else { m_locationAddress = new DebuggeeAddress("0x0"); } if (frameTuple.HasField("func")) { m_locationFunction = frameTuple ["func"] [0].GetString(); } else { m_locationFunction = "??"; } m_locationIsSymbolicated = !(m_locationFunction.Equals("??")); if (frameTuple.HasField("from")) { m_locationModule = Path.GetFileName(frameTuple ["from"] [0].GetString()); } else { m_locationModule = string.Empty; } // // Generate code and document contexts for this frame location. // if (frameTuple.HasField("fullname") && frameTuple.HasField("line")) { // // If the symbol table isn't yet loaded, we'll need to specify exactly the location of this stack frame. // TEXT_POSITION [] textPositions = new TEXT_POSITION [2]; textPositions [0].dwLine = frameTuple ["line"] [0].GetUnsignedInt() - 1; textPositions [0].dwColumn = 0; textPositions [1].dwLine = textPositions [0].dwLine; textPositions [1].dwColumn = textPositions [0].dwColumn; string filename = PathUtils.ConvertPathCygwinToWindows(frameTuple ["fullname"] [0].GetString()); m_documentContext = new DebuggeeDocumentContext(m_debugger.Engine, filename, textPositions [0], textPositions [1]); m_codeContext = CLangDebuggeeCodeContext.GetCodeContextForLocation(m_debugger, m_locationAddress.ToString()); if (m_codeContext == null) { throw new InvalidOperationException(); } } else { m_codeContext = CLangDebuggeeCodeContext.GetCodeContextForLocation(m_debugger, m_locationAddress.ToString()); m_documentContext = (m_codeContext != null) ? m_codeContext.DocumentContext : null; } } catch (Exception e) { LoggingUtils.HandleException(e); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int CreateErrorBreakpoint(string errorReason, MiBreakpoint gdbBreakpoint, DebuggeeDocumentContext documentContext, DebuggeeCodeContext codeContext) { // // Create a C-language breakpoint. This is tied to a GDB/MI breakpoint object. // LoggingUtils.PrintFunction(); try { CLangDebuggeeBreakpointError errorBreakpoint = new CLangDebuggeeBreakpointError(m_debugger, m_breakpointManager, this, codeContext, gdbBreakpoint, errorReason); lock (m_errorBreakpoints) { m_errorBreakpoints.Clear(); m_errorBreakpoints.Add(errorBreakpoint); } uint numDebugPrograms = 1; IEnumDebugPrograms2 debugPrograms; IDebugProgram2 [] debugProgramsArray = new IDebugProgram2 [numDebugPrograms]; LoggingUtils.RequireOk(m_breakpointManager.Engine.EnumPrograms(out debugPrograms)); LoggingUtils.RequireOk(debugPrograms.Next(numDebugPrograms, debugProgramsArray, ref numDebugPrograms)); m_breakpointManager.Engine.Broadcast(new DebugEngineEvent.BreakpointError(errorBreakpoint), debugProgramsArray [0], null); return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }