//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 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 int Read (uint dwInstructions, enum_DISASSEMBLY_STREAM_FIELDS dwFields, out uint pdwInstructionsRead, DisassemblyData [] prgDisassembly) { // // Reads instructions starting from the current position in the disassembly stream. // LoggingUtils.PrintFunction (); try { ulong startAddress = m_codeContext.Address.MemoryAddress; ulong endAddress = startAddress + ((ulong)(dwInstructions) * 4); // TODO: 4 for a 32-bit instruction set? string disassemblyCommand = string.Format ("-data-disassemble -s 0x{0:X8} -e 0x{1:X8} -- 1", startAddress, endAddress); MiResultRecord resultRecord = m_debugger.GdbClient.SendSyncCommand (disassemblyCommand); MiResultRecord.RequireOk (resultRecord, disassemblyCommand); if (!resultRecord.HasField ("asm_insns")) { throw new InvalidOperationException ("-data-disassemble result missing 'asm_insns' field"); } MiResultValueList assemblyRecords = (MiResultValueList) resultRecord ["asm_insns"] [0]; long maxInstructions = Math.Min (assemblyRecords.Values.Count, dwInstructions); if (maxInstructions == 0) { throw new InvalidOperationException (); } int currentInstruction = 0; for (int i = 0; i < assemblyRecords.Values.Count; ++i) { MiResultValue recordValue = assemblyRecords [i]; if (recordValue.Variable.Equals ("src_and_asm_line")) { // // Parse mixed-mode disassembly reports. // uint line = recordValue ["line"] [0].GetUnsignedInt (); string file = recordValue ["file"] [0].GetString (); MiResultValueList lineAsmInstructionValues = (MiResultValueList) recordValue ["line_asm_insn"] [0]; foreach (MiResultValue instructionValue in lineAsmInstructionValues.Values) { string address = instructionValue ["address"] [0].GetString (); if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS) != 0) { prgDisassembly [currentInstruction].bstrAddress = address; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESSOFFSET) != 0) { string offset = instructionValue ["offset"] [0].GetString (); prgDisassembly [currentInstruction].bstrAddressOffset = offset; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESSOFFSET; } if (((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE) != 0) || ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS) != 0) || ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS) != 0)) { string inst = instructionValue ["inst"] [0].GetString (); string [] operations = inst.Split (new string [] { "\\t" }, StringSplitOptions.None); if (operations.Length > 0) { prgDisassembly [currentInstruction].bstrOpcode = operations [0]; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE; } if (operations.Length > 1) { prgDisassembly [currentInstruction].bstrOperands = operations [1]; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS; } if (operations.Length > 2) { prgDisassembly [currentInstruction].bstrOperands += " " + operations [2]; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS; } } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL) != 0) { string functionName = instructionValue ["func-name"] [0].GetString (); prgDisassembly [currentInstruction].bstrSymbol = functionName; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID) != 0) { DebuggeeAddress instructionAddress = new DebuggeeAddress (address); prgDisassembly [currentInstruction].uCodeLocationId = instructionAddress.MemoryAddress; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION) != 0) { prgDisassembly [currentInstruction].posBeg.dwLine = line; prgDisassembly [currentInstruction].posBeg.dwColumn = 0; prgDisassembly [currentInstruction].posEnd.dwLine = line; prgDisassembly [currentInstruction].posEnd.dwColumn = uint.MaxValue; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL) != 0) { prgDisassembly [currentInstruction].bstrDocumentUrl = "file://" + file; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET) != 0) { uint offset = instructionValue ["offset"] [0].GetUnsignedInt (); prgDisassembly [currentInstruction].dwByteOffset = offset; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS) != 0) { prgDisassembly [currentInstruction].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_HASSOURCE; prgDisassembly [currentInstruction].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS; } if (++currentInstruction >= maxInstructions) { break; } } } } pdwInstructionsRead = (uint) currentInstruction; return Constants.S_OK; } catch (Exception e) { LoggingUtils.HandleException (e); pdwInstructionsRead = 0; 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; }