//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int GetCodeContext(ulong uCodeLocationId, out IDebugCodeContext2 ppCodeContext) { // // Returns a code context object corresponding to a specified code location identifier. // LoggingUtils.PrintFunction(); try { string location = string.Format("0x{0:X8}", uCodeLocationId); ppCodeContext = CLangDebuggeeCodeContext.GetCodeContextForLocation(m_debugger, location); if (ppCodeContext == null) { throw new InvalidOperationException(); } return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); ppCodeContext = null; return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public override int GetMemoryContext(out IDebugMemoryContext2 memoryContext) { // // Returns the memory context for a property value. // LoggingUtils.PrintFunction(); memoryContext = null; try { // // Pick out a memory address from a pool of potential strings. // // This is mainly to support GDB reporting symbols like: // // {void (JNIEnv *, jclass)} 0xb3e66c84 <Java_com_example_hellogdbserver_HelloGdbServer_invokeCrash> // string [] expressionPool = { m_expression, m_gdbVariable.Value }; string pattern = "(?<address>0x[A-Za-z0-9]+)"; Regex regExMatcher = new Regex(pattern, RegexOptions.IgnoreCase); foreach (string expression in expressionPool) { Match regExLineMatch = regExMatcher.Match(expression); if (regExLineMatch.Success) { string address = regExLineMatch.Result("${address}"); memoryContext = CLangDebuggeeCodeContext.GetCodeContextForLocation(m_debugger, address); break; } } if (memoryContext == null) { return(Constants.S_GETMEMORYCONTEXT_NO_MEMORY_CONTEXT); } return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 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; }