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;
        }
Beispiel #2
0
        /// <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);
            }
        }