//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public int Subtract(ulong count, out IDebugMemoryContext2 offsetAddressContext) { // // Subtracts a specified value to the current context's address to create a new context. // LoggingUtils.PrintFunction(); try { DebuggeeAddress offsetAddress = m_address.Subtract(count); offsetAddressContext = new DebuggeeCodeContext(m_engine, DocumentContext, offsetAddress); return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); offsetAddressContext = null; return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 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; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 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 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 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); } }