////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeProperty (CLangDebugger debugger, CLangDebuggeeStackFrame stackFrame, MiVariable gdbVariable)
      : base (debugger.Engine, stackFrame, gdbVariable.Expression, string.Empty)
    {
      m_debugger = debugger;

      m_gdbVariable = gdbVariable;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeBreakpointBound (CLangDebugger debugger, DebugBreakpointManager breakpointManager, DebuggeeBreakpointPending pendingBreakpoint, DebuggeeCodeContext codeContext, MiBreakpoint gdbBreakpoint)
      : base (breakpointManager, pendingBreakpoint, codeContext)
    {
      m_debugger = debugger;

      GdbBreakpoint = gdbBreakpoint;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeBreakpointError (CLangDebugger debugger, DebugBreakpointManager breakpointManager, DebuggeeBreakpointPending pendingBreakpoint, DebuggeeCodeContext codeContext, MiBreakpoint gdbBreakpoint, string error)
      : base (breakpointManager, pendingBreakpoint, codeContext, error)
    {
      m_debugger = debugger;

      GdbBreakpoint = gdbBreakpoint;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeProperty (CLangDebugger debugger, CLangDebuggeeStackFrame stackFrame, string expression, string value)
      : base (debugger.Engine, stackFrame, expression, value)
    {
      m_debugger = debugger;

      m_gdbVariable = null;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeDisassemblyStream (CLangDebugger debugger, enum_DISASSEMBLY_STREAM_SCOPE streamScope, IDebugCodeContext2 codeContext)
    {
      m_debugger = debugger;

      m_streamScope = streamScope;

      m_codeContext = codeContext as DebuggeeCodeContext;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeThread (CLangDebugger debugger, CLangDebuggeeProgram program, uint id)
      : base (program.DebugProgram, id, string.Format ("[Native-{0}]", id))
    {
      m_debugger = debugger;

      NativeProgram = program;

      RequiresRefresh = true;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeProgram (CLangDebugger debugger, DebuggeeProgram debugProgram)
    {
      m_debugger = debugger;

      DebugProgram = debugProgram;

      IsRunning = false;

      m_debugModules = new Dictionary<string, DebuggeeModule> ();

      m_debugThreads = new Dictionary<uint, DebuggeeThread> ();
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeStackFrame (CLangDebugger debugger, CLangDebuggeeThread thread, MiResultValueTuple frameTuple, string frameName)
      : base (debugger.Engine, thread as DebuggeeThread, frameName)
    {
      m_debugger = debugger;

      if (frameTuple == null)
      {
        throw new ArgumentNullException ("frameTuple");
      }

      m_queriedRegisters = false;

      m_queriedArgumentsAndLocals = false;

      GetInfoFromCurrentLevel (frameTuple);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int OnDetachClient (CLangDebugger debugger)
    {
      LoggingUtils.PrintFunction ();

      try
      {
        bool shouldContinue = false;

        ManualResetEvent detachLock = new ManualResetEvent (false);

        debugger.RunInterruptOperation (delegate (CLangDebugger _debugger)
        {
          _debugger.GdbClient.Detach ();

          detachLock.Set ();
        }, shouldContinue);

        bool detachedSignaled = detachLock.WaitOne (1000);

        if (!detachedSignaled)
        {
          throw new InvalidOperationException ("Failed to detach GDB client");
        }

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int OnAttachClient (CLangDebugger debugger)
    {
      LoggingUtils.PrintFunction ();

      try
      {
        GdbServer gdbServer = debugger.GdbServer;

        debugger.GdbClient.Attach (gdbServer);

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int OnTerminateServer (CLangDebugger debugger)
    {
      LoggingUtils.PrintFunction ();

      try
      {
        debugger.GdbServer.Kill ();

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeBreakpointPending (CLangDebugger debugger, DebugBreakpointManager breakpointManager, IDebugBreakpointRequest2 breakpointRequest)
      : base (breakpointManager, breakpointRequest)
    {
      m_debugger = debugger;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    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 GetCodeContextForDocumentContext (CLangDebugger debugger, DebuggeeDocumentContext documentContext)
    {
      LoggingUtils.PrintFunction ();

      string fileName;

      TEXT_POSITION [] startOffset = new TEXT_POSITION [1];

      TEXT_POSITION [] endOffset = new TEXT_POSITION [1];

      LoggingUtils.RequireOk (documentContext.GetName (enum_GETNAME_TYPE.GN_FILENAME, out fileName));

      LoggingUtils.RequireOk (documentContext.GetStatementRange (startOffset, endOffset));

      string location = string.Format ("\"{0}:{1}\"", fileName, startOffset [0].dwLine + 1);

      return GetCodeContextForLocation (debugger, location);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    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 OnContinueClient (CLangDebugger debugger)
    {
      LoggingUtils.PrintFunction ();

      try
      {
        debugger.GdbClient.Continue ();

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        throw;
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int OnTerminateClient (CLangDebugger debugger)
    {
      LoggingUtils.PrintFunction ();

      try
      {
        debugger.GdbClient.Stop ();

        debugger.GdbClient.Terminate ();

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        return Constants.E_FAIL;
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggerVariableManager (CLangDebugger debugger)
    {
      m_debugger = debugger;

      m_trackedVariables = new Dictionary<string, MiVariable> ();
    }
Example #19
0
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    #region IDebugEngine2 Members

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public int Attach (IDebugProgram2 [] rgpPrograms, IDebugProgramNode2 [] rgpProgramNodes, uint celtPrograms, IDebugEventCallback2 ad7Callback, enum_ATTACH_REASON dwReason)
    {
      // 
      // Attach the debug engine to a program.
      // 

      LoggingUtils.PrintFunction ();

      m_sdmCallback = new DebugEngineCallback (this, ad7Callback);

      m_cLangCallback = new CLangDebuggerCallback (this);

      m_javaLangCallback = new JavaLangDebuggerCallback (this);

      try
      {
        if ((rgpPrograms == null) || (rgpPrograms.Length == 0))
        {
          throw new ApplicationException ("Attach failed. No target process specified.");
        }

        if (celtPrograms > 1)
        {
          throw new ApplicationException ("Attach failed. Can not debug multiple target processes concurrently.");
        }

        if (Program != null)
        {
          throw new ApplicationException ("Attach failed. Already attached to " + Program.DebugProcess.NativeProcess.Name);
        }

        AndroidAdb.Refresh ();

        Program = rgpPrograms [0] as DebuggeeProgram;

        Program.AttachedEngine = this;

        Program.DebugProcess.NativeProcess.RefreshPackageInfo ();

        Broadcast (new DebugEngineEvent.DebuggerConnectionEvent (DebugEngineEvent.DebuggerConnectionEvent.EventType.LogStatus, string.Format ("Starting GDB client...")), null, null);

        NativeDebugger = new CLangDebugger (this, m_launchConfiguration, Program);

        Broadcast (new DebugEngineEvent.DebuggerConnectionEvent (DebugEngineEvent.DebuggerConnectionEvent.EventType.LogStatus, string.Format ("Starting JDB client...")), null, null);

        JavaDebugger = new JavaLangDebugger (this, Program);

        ThreadPool.QueueUserWorkItem (delegate (object obj)
        {
          // 
          // When this method is called, the DE needs to send these events in sequence:
          // 1. IDebugEngineCreate2
          // 2. IDebugProgramCreateEvent2
          // 3. IDebugLoadCompleteEvent2
          // 4. (if enum_ATTACH_REASON.ATTACH_REASON_LAUNCH), IDebugEntryPointEvent2
          // 

          try
          {
            Broadcast (new DebugEngineEvent.EngineCreate (this), Program, null);

            // 
            // Run a couple of tests which prevent the run-as tool from functioning properly:
            // 
            // 1) Test if this device/emulator is susceptible to a (usually 4.3 specific) run-as permissions bug.
            //      https://code.google.com/p/android/issues/detail?id=58373
            // 2) Test if the installed package is not declared 'debuggable'.
            // 

            AndroidDevice debuggingDevice = Program.DebugProcess.NativeProcess.HostDevice;

            string runasPackageFileList = debuggingDevice.Shell (string.Format ("run-as {0}", Program.DebugProcess.NativeProcess.Name), "ls -l");

            if (runasPackageFileList.Contains (string.Format ("run-as: Package '{0}' is unknown", Program.DebugProcess.NativeProcess.Name)))
            {
              throw new InvalidOperationException ("Can not debug native code on this device/emulator.\nMore info: https://code.google.com/p/android/issues/detail?id=58373");
            }
            else if (runasPackageFileList.Contains (string.Format ("run-as: Package '{0}' is not debuggable", Program.DebugProcess.NativeProcess.Name)))
            {
              throw new InvalidOperationException (string.Format ("Package '{0}' is not debuggable.\nPlease ensure you're trying to connect to a 'Debug' application.\nAlternatively, completely uninstall the current app and try again.", Program.DebugProcess.NativeProcess.Name));
            }

            Broadcast (new DebugEngineEvent.DebuggerConnectionEvent (DebugEngineEvent.DebuggerConnectionEvent.EventType.LogStatus, string.Format ("Attaching to '{0}'...", Program.DebugProcess.NativeProcess.Name)), null, null);

            LoggingUtils.RequireOk (Program.Attach (m_sdmCallback), "Failed to attach to target application.");

            CLangDebuggeeThread currentThread = null;

            NativeDebugger.RunInterruptOperation (delegate (CLangDebugger debugger)
            {
              debugger.NativeProgram.RefreshAllThreads ();

              currentThread = debugger.NativeProgram.GetThread (debugger.NativeProgram.CurrentThreadId);

              if (currentThread == null)
              {
                // Lack of current thread is usually a good indication that connection/attaching failed.
                throw new InvalidOperationException (string.Format ("Failed to retrieve program's main thread (tid: {0}).", debugger.NativeProgram.CurrentThreadId));
              }
            });

            Broadcast (new DebugEngineEvent.ProgramCreate (), Program, null);

            Broadcast (new DebugEngineEvent.LoadComplete (), Program, currentThread);

            if (dwReason == enum_ATTACH_REASON.ATTACH_REASON_LAUNCH)
            {
              Broadcast (new DebugEngineEvent.EntryPoint (), Program, currentThread);
            }

            Broadcast (new DebugEngineEvent.AttachComplete (), Program, null);

            Broadcast (new DebugEngineEvent.DebuggerLogcatEvent (debuggingDevice), Program, null);

            Broadcast (new DebugEngineEvent.DebuggerConnectionEvent (DebugEngineEvent.DebuggerConnectionEvent.EventType.LogStatus, string.Format ("Attached successfully to '{0}'.", Program.DebugProcess.NativeProcess.Name)), null, null);

            Broadcast (new DebugEngineEvent.DebuggerConnectionEvent (DebugEngineEvent.DebuggerConnectionEvent.EventType.CloseDialog, string.Empty), null, null);
          }
          catch (Exception e)
          {
            LoggingUtils.HandleException (e);

            Broadcast (ad7Callback, new DebugEngineEvent.Error (e.Message, true), Program, null);

            Detach (Program);
          }
        });

        return Constants.S_OK;
      }
      catch (Exception e)
      {
        LoggingUtils.HandleException (e);

        Broadcast (ad7Callback, new DebugEngineEvent.Error (e.Message, true), Program, null);

        Detach (Program);

        return Constants.E_FAIL;
      }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public CLangDebuggeeMemoryBytes (CLangDebugger debugger)
    {
      m_debugger = debugger;
    }