public override int SetValueAsString(string pszValue, uint dwRadix, uint dwTimeout) { var stackFrameVal = Value as DalvikStackFrameValue; if (stackFrameVal == null || !Value.IsPrimitive ) return VSConstants.E_FAIL; object val = ParsePrimitive(pszValue, Value.Tag, (int)dwRadix); // is there as simpler way to grab the debugger? var debugger = _stackFrame.Thread.Program.Process.Debugger; var slotValue = new SlotValue(stackFrameVal.Variable.Slot, Value.Tag, val); debugger.StackFrame.SetValuesAsync(_stackFrame.Thread.Id, _stackFrame.Id, slotValue) .Await((int)dwTimeout); _stackFrame.InvalidateVariablesValueCache(); return VSConstants.S_OK; }
/// <summary> /// /// </summary> public int SetNextStatement(IDebugStackFrame2 pStackFrame, IDebugCodeContext2 pCodeContext) { // TODO: move this code to DalvikThread, or to a SetNextInstructionManager DLog.Debug(DContext.VSDebuggerComCall, "IDebugThread2.SetNextStatement"); var stack = (DebugStackFrame)pStackFrame; var ctx = (DebugCodeContext)pCodeContext; // nothing to do. if (ctx.Location.Equals(stack.Location)) return VSConstants.S_OK; if (!ctx.Location.IsSameMethod(stack.Location)) return HResults.E_CANNOT_SETIP_TO_DIFFERENT_FUNCTION; var loc = stack.GetDocumentLocationAsync().Await(DalvikProcess.VmTimeout); if (loc.MethodEntry == null) { DLog.Info(DContext.VSStatusBar, "Can not set next instruction: Debug info not available."); return HResults.E_CANNOT_SET_NEXT_STATEMENT_GENERAL; } var nextInstrVar = loc.MethodEntry.Variables.FirstOrDefault(v => v.Name == DebuggerConstants.SetNextInstructionVariableName); if (nextInstrVar == null) { DLog.Info(DContext.VSStatusBar, "Can not set next instruction: missing compiler setting or method optimized."); return HResults.E_CANNOT_SET_NEXT_STATEMENT_GENERAL; } // make sure there are no branch instructions // between the current instruction and our branch instruction. // note that for convinence, we *do* allow assignments to // fields of objects, even though these are visible to the // program. var disassembly = Program.DisassemblyProvider.GetFromLocation(loc); if (disassembly == null) return HResults.E_CANNOT_SET_NEXT_STATEMENT_GENERAL; var body = disassembly.Method.Body; int idx = body.Instructions.FindIndex(i => (ulong)i.Offset == loc.Location.Index); if(idx == -1) return HResults.E_CANNOT_SET_NEXT_STATEMENT_GENERAL; bool foundSetNextInstruction = false; for (;idx < body.Instructions.Count; ++idx) { var ins = body.Instructions[idx]; foundSetNextInstruction = ins.OpCode == OpCodes.If_nez && ins.Registers.Count == 1 && ins.Registers[0].Index == nextInstrVar.Register; if (foundSetNextInstruction) break; if (ins.OpCode.IsJump()) break; } if (!foundSetNextInstruction) { DLog.Info(DContext.VSStatusBar, "Can not set next instruction from current position. Try again at a later position if any."); return HResults.E_CANNOT_SET_NEXT_STATEMENT_GENERAL; } DLog.Info(DContext.VSStatusBar, "Setting next instruction to beginning of block."); // find target instruction. var targetIns = (Instruction)body.Instructions[idx].Operand; idx = body.Instructions.FindIndex(p => p.Offset == targetIns.Offset); idx = FindNextLocationWithSource(disassembly, idx) ?? idx; targetIns = body.Instructions[idx]; var targetLoc = loc.Location.GetAtIndex(targetIns.Offset); // set a temporary breakpoint. The reset logic could get into a "DalvikTemporaryBreakpoint" class. var bp = new DalvikAwaitableBreakpoint(targetLoc); var waitBp = bp.WaitUntilHit(); var waitBound = Debugger.Process.BreakpointManager.SetBreakpoint(bp); try { if (!waitBound.Await(DalvikProcess.VmTimeout)) return HResults.E_CANNOT_SET_NEXT_STATEMENT_GENERAL; // set the special variable. var newSlotVal = new SlotValue(nextInstrVar.Register, Jdwp.Tag.Int, 1); Debugger.StackFrame.SetValuesAsync(stack.Thread.Id, stack.Id, newSlotVal) .Await(DalvikProcess.VmTimeout); // resume the process. Debugger.Process.ResumeAsync(); // wait for breakpoint to be hit. try { waitBp.Await(1000); } catch (Exception) { // ups. something went wrong. suspend again. if (!Debugger.Process.IsSuspended) Debugger.Process.SuspendAsync(); return VSConstants.E_FAIL; } return VSConstants.S_OK; } finally { // clear the breakpoint again. Debugger.Process.BreakpointManager.ResetAsync(bp) .Await(DalvikProcess.VmTimeout); // reset the special variable, in case this was not performed automatically. // (should not happen, but maybe the set value code got optimized away per // accident) var newSlotVal = new SlotValue(nextInstrVar.Register, Jdwp.Tag.Int, 0); Debugger.StackFrame.SetValuesAsync(stack.Thread.Id, stack.Id, newSlotVal) .Await(DalvikProcess.VmTimeout); } }