//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public DebugEngineCallback(DebugEngine engine, IDebugEventCallback2 ad7EventCallback) { Engine = engine; m_ad7EventCallback = ad7EventCallback; m_cLangEventCallback = new CLangDebuggerCallback(engine); m_javaLangEventCallback = new JavaLangDebuggerCallback(engine); // // Register function handlers for specific events. // m_debuggerCallback = new Dictionary <Guid, DebuggerEventDelegate> (); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.BreakpointHit)), OnBreakpoint); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.BreakpointBound)), OnBreakpointBound); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.BreakpointError)), OnBreakpointError); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.Error)), OnError); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.Exception)), OnException); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.LoadComplete)), OnLoadComplete); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.ModuleLoad)), OnModuleLoad); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.OutputString)), OnOutputString); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.ProcessCreate)), OnProgramCreate); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.ProgramDestroy)), OnProgramDestroy); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.StepComplete)), OnStepComplete); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.SymbolSearch)), OnSymbolSearch); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.ThreadCreate)), OnThreadCreate); m_debuggerCallback.Add(ComUtils.GuidOf(typeof(DebugEngineEvent.ThreadDestroy)), OnThreadDestroy); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public JavaLangDebugger (DebugEngine debugEngine, DebuggeeProgram debugProgram) { Engine = debugEngine; m_javaLangCallback = new JavaLangDebuggerCallback (debugEngine); JavaProgram = new JavaLangDebuggeeProgram (this, debugProgram); m_jdbSetup = new JdbSetup (debugProgram.DebugProcess.NativeProcess); Engine.Broadcast (new DebugEngineEvent.DebuggerConnectionEvent (DebugEngineEvent.DebuggerConnectionEvent.EventType.LogStatus, string.Format ("Configuring JDB for {0}:{1}...", m_jdbSetup.Host, m_jdbSetup.Port)), null, null); JdbClient = new JdbClient (m_jdbSetup); JdbClient.OnAsyncStdout = OnClientAsyncOutput; JdbClient.OnAsyncStderr = OnClientAsyncOutput; JdbClient.Start (); }
//private int m_interruptOperationCounter = 0; //private ManualResetEvent m_interruptOperationCompleted = null; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public JavaLangDebugger(DebugEngine debugEngine, DebuggeeProgram debugProgram) { Engine = debugEngine; m_javaLangCallback = new JavaLangDebuggerCallback(debugEngine); JavaProgram = new JavaLangDebuggeeProgram(this, debugProgram); m_jdbSetup = new JdbSetup(debugProgram.DebugProcess.NativeProcess); Engine.Broadcast(new DebugEngineEvent.DebuggerConnectionEvent(DebugEngineEvent.DebuggerConnectionEvent.EventType.LogStatus, string.Format("Configuring JDB for {0}:{1}...", m_jdbSetup.Host, m_jdbSetup.Port)), null, null); JdbClient = new JdbClient(m_jdbSetup); JdbClient.OnAsyncStdout = OnClientAsyncOutput; JdbClient.OnAsyncStderr = OnClientAsyncOutput; JdbClient.Start(); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #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 int Detach (DebuggeeProgram program) { LoggingUtils.PrintFunction (); try { if ((program.AttachedEngine != null) && (program.AttachedEngine.NativeDebugger != null)) { program.AttachedEngine.NativeDebugger.Kill (); program.AttachedEngine.NativeDebugger.Dispose (); program.AttachedEngine.NativeDebugger = null; } if ((program.AttachedEngine != null) && (program.AttachedEngine.JavaDebugger != null)) { program.AttachedEngine.JavaDebugger.Kill (); program.AttachedEngine.JavaDebugger.Dispose (); program.AttachedEngine.JavaDebugger = null; } return Constants.S_OK; } catch (Exception e) { LoggingUtils.HandleException (e); return Constants.E_FAIL; } finally { if ((program != null) && (program.AttachedEngine != null)) { Broadcast (new DebugEngineEvent.ProgramDestroy (0), program, null); program.AttachedEngine = null; } m_cLangCallback = null; m_javaLangCallback = null; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public DebugEngineCallback (DebugEngine engine, IDebugEventCallback2 ad7EventCallback) { Engine = engine; m_ad7EventCallback = ad7EventCallback; m_cLangEventCallback = new CLangDebuggerCallback (engine); m_javaLangEventCallback = new JavaLangDebuggerCallback (engine); // // Register function handlers for specific events. // m_debuggerCallback = new Dictionary<Guid, DebuggerEventDelegate> (); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.BreakpointHit)), OnBreakpoint); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.BreakpointBound)), OnBreakpointBound); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.BreakpointError)), OnBreakpointError); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.Error)), OnError); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.Exception)), OnException); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.LoadComplete)), OnLoadComplete); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.ModuleLoad)), OnModuleLoad); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.OutputString)), OnOutputString); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.ProcessCreate)), OnProgramCreate); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.ProgramDestroy)), OnProgramDestroy); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.StepComplete)), OnStepComplete); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.SymbolSearch)), OnSymbolSearch); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.ThreadCreate)), OnThreadCreate); m_debuggerCallback.Add (ComUtils.GuidOf (typeof (DebugEngineEvent.ThreadDestroy)), OnThreadDestroy); }