//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void RefreshThread(uint tid) { LoggingUtils.PrintFunction(); try { m_debugger.RunInterruptOperation(delegate(CLangDebugger debugger) { string command = string.Format("-thread-info {0}", (tid == 0) ? "" : tid.ToString()); MiResultRecord resultRecord = m_debugger.GdbClient.SendSyncCommand(command); MiResultRecord.RequireOk(resultRecord, command); if (!resultRecord.HasField("threads")) { throw new InvalidOperationException("-thread-info result missing 'threads' field"); } MiResultValueList threadsValueList = (MiResultValueList)resultRecord ["threads"] [0]; List <MiResultValue> threadsData = threadsValueList.List; bool refreshedProcesses = false; for (int i = threadsData.Count - 1; i >= 0; --i) // reported threads are in descending order. { uint id = threadsData [i] ["id"] [0].GetUnsignedInt(); CLangDebuggeeThread thread = GetThread(id) ?? AddThread(id); if (thread.RequiresRefresh) { MiResultValue threadData = threadsData [i]; if (!refreshedProcesses) { AndroidDevice hostDevice = DebugProgram.DebugProcess.NativeProcess.HostDevice; hostDevice.RefreshProcesses(DebugProgram.DebugProcess.NativeProcess.Pid); refreshedProcesses = true; } thread.Refresh(ref threadData); } } if (resultRecord.HasField("current-thread-id")) { CurrentThreadId = resultRecord ["current-thread-id"] [0].GetUnsignedInt(); } }); } 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 void Refresh(ref MiResultValue threadData) { LoggingUtils.PrintFunction(); if (threadData.HasField("name")) { m_threadDisplayName = threadData ["name"] [0].GetString(); // user-specified name } else if (threadData.HasField("target-id")) { uint threadPid; m_threadDisplayName = threadData ["target-id"] [0].GetString(); // usually the raw name, i.e. 'Thread 18771' if (m_threadDisplayName.StartsWith("Thread ") && uint.TryParse(m_threadDisplayName.Substring("Thread ".Length), out threadPid)) { AndroidDevice hostDevice = NativeProgram.DebugProgram.DebugProcess.NativeProcess.HostDevice; AndroidProcess threadProcess = hostDevice.GetProcessFromPid(threadPid); if (threadProcess != null) { m_threadDisplayName = threadProcess.Name; } } } if (threadData.HasField("frame")) { MiResultValueTuple frameTuple = threadData ["frame"] [0] as MiResultValueTuple; uint stackLevel = frameTuple ["level"] [0].GetUnsignedInt(); string stackFrameId = m_threadName + "#" + stackLevel; CLangDebuggeeStackFrame stackFrame = new CLangDebuggeeStackFrame(m_debugger, this, frameTuple, stackFrameId); lock (m_threadStackFrames) { m_threadStackFrames.Add(stackFrame); } } RequiresRefresh = false; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// protected override int QueryRegisters() { LoggingUtils.PrintFunction(); try { // // Returns a list of registers for the current stack level. // if (!m_queriedRegisters) { uint threadId; LoggingUtils.RequireOk(m_thread.GetThreadId(out threadId)); string command = string.Format("-data-list-register-values --thread {0} --frame {1} r", threadId, StackLevel); m_debugger.GdbClient.SendCommand(command, delegate(MiResultRecord resultRecord) { MiResultRecord.RequireOk(resultRecord, command); if (!resultRecord.HasField("register-values")) { throw new InvalidOperationException("Failed to retrieve list of register values"); } MiResultValue registerValues = resultRecord ["register-values"] [0]; int registerValuesCount = registerValues.Values.Count; Dictionary <uint, string> registerIdMapping = m_debugger.GdbClient.GetRegisterIdMapping(); for (int i = 0; i < registerValuesCount; ++i) { uint registerId = registerValues [i] ["number"] [0].GetUnsignedInt(); string registerValue = registerValues [i] ["value"] [0].GetString(); string registerName = registerIdMapping [registerId]; string registerNamePrettified = "$" + registerName; CLangDebuggeeProperty property = new CLangDebuggeeProperty(m_debugger, this, registerNamePrettified, registerValue); m_stackRegisters.TryAdd(registerNamePrettified, property); LoggingUtils.RequireOk(m_property.AddChildren(new DebuggeeProperty [] { property })); } m_queriedRegisters = true; }); } return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// protected override int QueryArgumentsAndLocals() { LoggingUtils.PrintFunction(); try { if (!m_queriedArgumentsAndLocals) { uint threadId; LoggingUtils.RequireOk(m_thread.GetThreadId(out threadId)); string command = string.Format("-stack-list-variables --thread {0} --frame {1} --no-values", threadId, StackLevel); m_debugger.GdbClient.SendCommand(command, delegate(MiResultRecord resultRecord) { MiResultRecord.RequireOk(resultRecord, command); if (resultRecord.HasField("variables")) { MiResultValue localVariables = resultRecord ["variables"] [0]; for (int i = 0; i < localVariables.Values.Count; ++i) { string variableName = localVariables [i] ["name"] [0].GetString(); MiVariable variable = m_debugger.VariableManager.CreateVariableFromExpression(this, variableName); if (variable == null) { continue; } CLangDebuggeeProperty property = m_debugger.VariableManager.CreatePropertyFromVariable(this, variable); if (property == null) { throw new InvalidOperationException(); } if (localVariables [i].HasField("arg")) { m_stackArguments.TryAdd(variableName, property); LoggingUtils.RequireOk(m_property.AddChildren(new DebuggeeProperty [] { property })); } else { m_stackLocals.TryAdd(variableName, property); LoggingUtils.RequireOk(m_property.AddChildren(new DebuggeeProperty [] { property })); } //LoggingUtils.RequireOk (m_property.AddChildren (new DebuggeeProperty [] { property })); } m_queriedArgumentsAndLocals = true; } }); } return(Constants.S_OK); } catch (Exception e) { LoggingUtils.HandleException(e); return(Constants.E_FAIL); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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); } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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); } }