internal static List <ClassDefinition> Hierarchicalize(List <ClassDefinition> container) { var result = new List <ClassDefinition>(); var dex = new DexLookup(container, false); foreach (var cdef in container) { int idx = cdef.Fullname.LastIndexOf(DexConsts.InnerClassMarker); if (idx == -1) { result.Add(cdef); } else { string ownerFullName = cdef.Fullname.Substring(0, idx); var owner = dex.GetClass(ownerFullName); if (owner != null) { owner.AddInnerClass(cdef); cdef.Owner = owner; } else { DLog.Error(DContext.CompilerCodeGenerator, "owner not found for inner class {0}", cdef.Fullname); result.Add(cdef); } } } return(result); }
/// <summary> /// Allocates the predfined number of objects within the pool /// </summary> /// <returns></returns> public virtual bool Allocate(string objectPath = "") { if (!this._isInitialized) { return(false); } if (this._objectLoadPolicy == null) { DLog.Error("Did you forget to set your object policy?!", DLogCategory.Loading); return(false); } try { for (int i = 0; i < this._sizeOfPool; i++) { T obj = this._objectLoadPolicy.Load(); if (obj == null) { return(false); } this._pool.Enqueue(obj); } } catch (Exception ex) { DLog.Error(ex, DLogCategory.Loading); return(false); } return(true); }
/// <summary> /// We're done loading the initial threads. /// Notify the GUI that we're good to go. /// </summary> private void OnLoadThreadsDone(Dot42.DebuggerLib.Debugger debugger, DebugProcess debugProcess) { // Notify module //eventCallback.Send(program, new ModuleLoadEvent(program.MainModule, "Loading module", true)); //eventCallback.Send(program, new SymbolSearchEvent(program.MainModule, "Symbols loaded", enum_MODULE_INFO_FLAGS.MIF_SYMBOLS_LOADED)); var mainThread = debugProcess.ThreadManager.MainThread(); if (mainThread != null) { // Threads loaded // Load complete //eventCallback.Send(mainThread, new LoadCompleteEvent()); //eventCallback.Send(mainThread, new EntryPointEvent()); // Resume now debugger.VirtualMachine.ResumeAsync(); // Notify SD Action onDebugStarted = () => { if (stateUpdate != null) { stateUpdate(LauncherStates.Attached, string.Empty); stateUpdate = null; } DebugStarted.Fire(this); }; Dot42Addin.InvokeAsyncAndForget(onDebugStarted); } else { DLog.Error(DContext.VSDebuggerLauncher, "No main thread found"); } }
/// <summary> /// Returns a gameobject back to the pool. This will fail if /// the pool isn't initialized. /// </summary> /// <param name="obj">The gameobject to return.</param> override public void Return(GameObject obj) { if (!this._isInitialized) { return; } if (!this._pool.Contains(obj)) { this._pool.Enqueue(obj); } obj.transform.position = Vector3.zero; obj.transform.rotation = this._original.transform.rotation; obj.SetActive(false); if (this._parent != null) { obj.transform.SetParent(this._parent.transform); obj.name = "GameObject"; } else { DLog.Error("Parent is null when adding obj: " + obj.name, DLogCategory.Loading); } }
/// <summary> /// Allocates a single object. /// </summary> /// <returns>The game object or null</returns> public override GameObject AllocateSingle() { if (!this._isInitialized) { return(null); } Assert.IsNotNull(this._original, "Please call allocate beforehand trying to allocate a new single object!"); try { GameObject obj = UnityEngine.Object.Instantiate(_original); if (obj == null) { return(null); } obj.transform.parent = this._parent.transform; obj.SetActive(false); return(obj); } catch (Exception ex) { DLog.Error(ex, DLogCategory.Loading); return(null); } }
/// <summary> /// Notify clients of the given event. /// </summary> private void OnEventAsync(JdwpEvent @event) { Task.Factory.StartNew(() => JdwpEvent.Fire(this, @event)) .ContinueWith(task => { DLog.Error(DContext.DebuggerLibJdwpConnection, "OnEventAsync: Internal failure on event processing. IsCancelled={0}. Exception={1}", task.IsCanceled, task.Exception); }, TaskContinuationOptions.NotOnRanToCompletion); }
/// <summary> /// Perform actual send /// </summary> private void Send(IDebugProcess2 process, IDebugProgram2 program, IDebugThread2 thread, BaseEvent @event) { var guid = @event.IID; DLog.Debug(DContext.VSDebuggerEvent, "DebugEngine Event {0} {1}", @event.GetType().Name, guid); var rc = callback.Event(engine, process, program, thread, @event, ref guid, (uint)@event.Attributes); if (!ErrorHandler.Succeeded(rc)) { DLog.Error(DContext.VSDebuggerEvent, "DebugEngine Event failed {0}", rc); } }
/// <summary> /// Process the output of AAPT to display property errors in VisualStudio. /// </summary> private static void ProcessAaptErrors(string output, string tempFolder, List <Tuple <string, ResourceType> > resources) { #if DEBUG //Debugger.Launch(); #endif const string errorPrefix = "Error: "; const string errorLevel = "error"; var lines = output.Split(new[] { '\n', '\r' }); var paths = resources.Select(x => Tuple.Create(x.Item1, ResourceExtensions.GetNormalizedResourcePath(tempFolder, x.Item1, x.Item2))).ToList(); foreach (var line in lines) { var parts = SplitAaptErrorLine(line.Trim(), 4).ToArray(); int lineNr; if ((parts.Length < 4) || !int.TryParse(parts[1], out lineNr)) { if (line.Length > 0) { Console.WriteLine(line); } continue; } // src:line:severity:remaining var msg = parts[3].Trim(); if (msg.StartsWith(errorPrefix)) { msg = msg.Substring(errorPrefix.Length); } var url = parts[0]; var level = parts[2].Trim(); var pathEntry = paths.FirstOrDefault(x => x.Item2 == url); url = (pathEntry != null) ? pathEntry.Item1 : url; switch (level.ToLowerInvariant()) { case errorLevel: DLog.Error(DContext.ResourceCompilerAaptError, url, 0, lineNr, msg); break; default: DLog.Warning(DContext.ResourceCompilerAaptError, url, 0, lineNr, msg); break; } //Console.WriteLine(line); // DEBUG PURPOSES } }
/// <summary> /// Takes care of allocating the pool objects at a specific path. /// </summary> /// <param name="objectPath">The path of the object.</param> /// <returns>True or false depending on the result of the loading process</returns> public override bool Allocate(string objectPath = "") { if (!this._isInitialized) { return(false); } Assert.IsNotNull(this._objectLoadPolicy, "No Object Load Policy specified! In order to run the pool you need one!"); Assert.IsTrue(this._objectLoadPolicy.IsCreated(), "Object Load Policy has not been created please call Initialize on Object Pool!"); Assert.IsNotNull(this._parent, "The parent object is null! You need to specify a parent object at construction time!"); UnityEngine.Object original = this._objectLoadPolicy.Load(objectPath); if (original == null) { DLog.Error("Couldn't find original allocation object for pool ( " + objectPath + ").", DLogCategory.Loading); return(false); } this._original = (GameObject)GameObject.Instantiate(original); this._original.transform.parent = this._parent.transform; this._original.SetActive(false); this._original.name = "GameObject_Reference"; try { for (int i = 0; i < this._sizeOfPool; i++) { GameObject obj = UnityEngine.Object.Instantiate(_original); if (obj == null) { return(false); } obj.name = "GameObject"; obj.transform.parent = this._parent.transform; obj.SetActive(false); this._pool.Enqueue(obj); } } catch (Exception ex) { DLog.Error(ex, DLogCategory.Loading); return(false); } return(true); }
/// <summary> /// Resolve an assembly by name with given parameters. /// </summary> public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) { AssemblyDefinition result; if (references.TryGetValue(name.Name, out result)) { return(result); } var path = ResolvePath(name.Name); if (path == null) { DLog.Error(DContext.CompilerAssemblyResolver, "Failed to resolve assembly {0} in {1}", name, string.Join("; ", referenceFolders)); throw new AssemblyResolutionException(name); } try { Console.WriteLine(string.Format("Loading {0}", name.Name)); var reference = AssemblyDefinition.ReadAssembly(path, parameters); references[name.Name] = reference; VerifyFrameworkAssembly(reference, path); if (assemblyLoaded != null) { assemblyLoaded(reference); } if (classLoader != null) { classLoader.LoadAssembly(reference); } return(reference); } catch (Exception ex) { // Unload the reference references.Remove(name.Name); #if DEBUG Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); #endif // Log the error DLog.Error(DContext.CompilerAssemblyResolver, "Failed to load assembly {0}", ex, name); // Pass the error on throw new AssemblyResolutionException(name); } }
/// <summary> /// Process the result of an AllThreads request. /// </summary> private void ProcessAllThreads(Task <List <ThreadId> > task) { if (!task.CompletedOk()) { DLog.Error(DContext.DebuggerLibModel, "LoadAllThreads failed", task.Exception); task.ForwardException(); return; } List <DalvikThread> created = null; List <DalvikThread> removed = null; lock (threadsLock) { // Create missing threads foreach (var id in task.Result.Where(x => !threads.ContainsKey(x))) { // Create and record var thread = CreateThread(id); threads[id] = thread; list.Add(thread); created = created ?? new List <DalvikThread>(); created.Add(thread); } // Remove obsolete threads var toRemove = threads.Keys.Where(x => !task.Result.Contains(x)).ToList(); foreach (var id in toRemove) { var thread = threads[id]; threads.Remove(id); list.Remove(thread); removed = removed ?? new List <DalvikThread>(); removed.Add(thread); } } if (created != null) { created.ForEach(OnThreadCreated); } if (removed != null) { removed.ForEach(OnThreadEnd); } }
public void Convert(ReachableContext reachableContext) { // Collect all names var reachableInterfaces = reachableContext.ReachableTypes.Where(i => i.IsInterface).ToList(); var interfaceToImplementingTypes = reachableContext.ReachableTypes .Except(reachableInterfaces) .SelectMany(t => GetInterfaces(t).Distinct(), Tuple.Create) .Where(e => e.Item2.IsReachable) .ToLookup(e => e.Item2, e => e.Item1); // TODO: I don't think the we cover all possible cases here yet. // What about methods overriding imported methods? foreach (var intf in reachableInterfaces) { foreach (var iMethod in intf.Methods) { // ignore DexImport Interface types. TODO: also cover the reverse: a method implementing // both a import-interface as well as a .NET interface. if (iMethod.GetDexOrJavaImportAttribute() != null || iMethod.GetDexNameAttribute() != null) { continue; } var nativeImpls = interfaceToImplementingTypes[intf].Select(t => Tuple.Create(t, iMethod.GetImplementation(t))) .Where(e => e.Item2 != null && (e.Item2.GetDexOrJavaImportAttribute() != null || e.Item2.GetDexNameAttribute() != null)); foreach (var typeAndImpl in nativeImpls) { var type = typeAndImpl.Item1; var impl = typeAndImpl.Item2; var finalName = GetFinalImplementationName(impl); if (finalName == iMethod.Name) { continue; } // TODO: automatically create a redirecting stub. DLog.Error(DContext.CompilerILConverter, "Type '{0}' implements interface method '{1}' using imported method '{2}'. This is not supported at the moment. As a workaround, create a 'new' or explicit implementation of the interface, that redirects to the imported.", type.FullName, iMethod.FullName, impl.FullName); } } } }
/// <summary> /// Send the given event to all event sinks /// </summary> private void SendEvent(IDebugCoreServer2 server, IDebugPort2 port, IDebugProcess2 process, IDebugProgram2 program, BaseEvent @event) { var iid = @event.IID; DLog.Debug(DContext.VSDebuggerEvent, "DebugPort Event {0} {1}", @event.GetType().Name, iid); foreach (var eventSink in eventSinks) { var events = eventSink as IDebugPortEvents2; if (events != null) { var rc = events.Event(server, port, process, program, @event, ref iid); if (!ErrorHandler.Succeeded(rc)) { DLog.Error(DContext.VSDebuggerEvent, "DebugPort Event failed {0}", rc); } } } }
//Request Methods public async Task <TResult> Request <TResult>(string url, HttpMethod method, object data = null) where TResult : class { var logString = $"{method} - {url}\n"; CurrentRequestState = RequestState.Ongoing; HttpResponseMessage response = null; try { HttpRequestMessage request = new HttpRequestMessage(method, url); if (data != null) { var postContent = JsonConvert.SerializeObject(data); logString += $"Request Content - ${postContent}\n"; request.Content = new StringContent(postContent); request.Content.Headers.ContentType = new MediaTypeHeaderValue(RequestContentType); } response = await _httpClient.SendAsync(request); } catch (Exception ex) { logString += $"Rest Client Exception - {ex.Message}\nStackTrace - {ex.StackTrace}"; } if (response?.IsSuccessStatusCode ?? false) { var responseString = await response.Content.ReadAsStringAsync(); DLog.Success($"{logString}Response Data - {responseString}"); if (!String.IsNullOrEmpty(responseString)) { var result = JsonConvert.DeserializeObject <TResult>(responseString); return(result); } CurrentRequestState = RequestState.Success; return(default(TResult)); } DLog.Error($"{logString}Status Code - {response?.StatusCode}"); CurrentRequestState = RequestState.Failed; return(default(TResult)); }
/// <summary> /// Resolve an assembly by name with given parameters. /// </summary> public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) { AssemblyDefinition result; if (references.TryGetValue(name.Name, out result)) { return(result); } var referencePaths = referenceFolders.Select(x => Path.Combine(x, name.Name + ".dll")); var path = referencePaths.FirstOrDefault(x => string.Equals(Path.GetFileNameWithoutExtension(x), name.Name, StringComparison.OrdinalIgnoreCase) && File.Exists(x)); if (path == null) { DLog.Error(DContext.CompilerAssemblyResolver, "Failed to resolve assembly {0} in {1}", name, string.Join("; ", referenceFolders)); throw new AssemblyResolutionException(name); } try { if (ShowLoading) { Console.WriteLine(string.Format("Loading {0}", name.Name)); } var reference = AssemblyDefinition.ReadAssembly(path, parameters); references[name.Name] = reference; return(reference); } catch (Exception ex) { // Unload the reference references.Remove(name.Name); #if DEBUG Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); #endif // Log the error DLog.Error(DContext.CompilerAssemblyResolver, "Failed to load assembly {0}", ex, name); // Pass the error on throw new AssemblyResolutionException(name); } }
/// <summary> /// Resolve an assembly by name with given parameters. /// </summary> public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) { AssemblyDefinition result; if (referencesByName.TryGetValue(name.Name, out result)) { return(result); } var path = ResolvePath(name.Name); if (path == null) { DLog.Error(DContext.CompilerAssemblyResolver, "Failed to resolve assembly {0} in {1}", name, string.Join("; ", referenceFolders)); throw new AssemblyResolutionException(name); } return(Load(name, path, parameters)); }
/// <summary> /// Allocates a single element! /// (ATTENTION THIS WILL RETURN AN OBJECT THAT ISN'T MANAGED BY THE POOL) /// </summary> /// <returns></returns> public virtual T AllocateSingle() { if (!this._isInitialized) { return(null); } if (this._objectLoadPolicy == null) { DLog.Error("Did you forget to set your object policy?!", DLogCategory.Loading); return(null); } try { T obj = this._objectLoadPolicy.Load(); return(obj); } catch (Exception ex) { DLog.Error(ex, DLogCategory.Loading); return(null); } }
/// <summary> /// Resumes process execution. /// </summary> public int ResumeProcess(IDebugProcess2 pProcess) { DLog.Debug(DContext.VSDebuggerComCall, "IDebugEngine2.ResumeProcess"); var process = pProcess as DebugProcess; if (process == null) { return(VSConstants.E_INVALIDARG); } try { var program = process.Program; ((IDebugPortNotify2)process.Port).AddProgramNode(program); // Suspend and prepare the VM var debugger = process.Debugger; var suspend = process.Debugger.VirtualMachine.SuspendAsync(); var prepare = suspend.ContinueWith(t => { t.ForwardException(); return(debugger.PrepareAsync()); }).Unwrap(); var loadThreads = prepare.ContinueWith(t => { t.ForwardException(); return(program.ThreadManager.RefreshAsync()); }).Unwrap(); loadThreads.ContinueWith(t => { t.ForwardException(); // Notify module eventCallback.Send(program, new ModuleLoadEvent(program.MainModule, "Loading module", true)); eventCallback.Send(program, new SymbolSearchEvent(program.MainModule, "Symbols loaded", enum_MODULE_INFO_FLAGS.MIF_SYMBOLS_LOADED)); var mainThread = program.ThreadManager.MainThread(); if (mainThread != null) { // Threads loaded // Load complete eventCallback.Send(mainThread, new LoadCompleteEvent()); eventCallback.Send(mainThread, new EntryPointEvent()); // Resume now debugger.VirtualMachine.ResumeAsync(); // We're fully attached now if (stateUpdate != null) { stateUpdate(LauncherStates.Attached, string.Empty); } stateUpdate = null; } else { DLog.Error(DContext.VSDebuggerLauncher, "No main thread found"); } }); return(VSConstants.S_OK); } catch (Exception ex) { DLog.Error(DContext.VSDebuggerLauncher, "ResumeProcess failed", ex); return(VSConstants.E_FAIL); } }
private void HandleCompositeCommand(JdwpPacket packet) { var data = packet.Data; var suspendPolicy = (Jdwp.SuspendPolicy)data.GetByte(); var count = data.GetInt(); for (var i = 0; i < count; i++) { var eventKind = (Jdwp.EventKind)data.GetByte(); JdwpEvent evt; switch (eventKind) { case Jdwp.EventKind.VmInit: evt = new VmStart(data); break; case Jdwp.EventKind.SingleStep: evt = new SingleStep(data); break; case Jdwp.EventKind.BreakPoint: evt = new Breakpoint(data); break; case Jdwp.EventKind.MethodEntry: evt = new MethodEntry(data); break; case Jdwp.EventKind.MethodExit: evt = new MethodExit(data); break; case Jdwp.EventKind.Exception: evt = new Exception(data); break; case Jdwp.EventKind.ThreadStart: evt = new ThreadStart(data); break; case Jdwp.EventKind.ThreadEnd: evt = new ThreadDeath(data); break; case Jdwp.EventKind.ClassPrepare: evt = new ClassPrepare(data); break; case Jdwp.EventKind.ClassUnload: evt = new ClassUnload(data); break; case Jdwp.EventKind.FieldAccess: evt = new FieldAccess(data); break; case Jdwp.EventKind.FieldModification: evt = new FieldModification(data); break; case Jdwp.EventKind.VmDeath: evt = new VmDeath(data); break; default: throw new ArgumentException("Unknown event kind in compositive command " + (int)eventKind); } DLog.Debug(DContext.DebuggerLibDebugger, "JDWP event {0} {1}", eventKind, evt); Task.Factory.StartNew(() => { evt.Accept(compositeCommandProcessor, suspendPolicy); }).ContinueWith(task => { DLog.Error(DContext.DebuggerLibJdwpConnection, "HandleCompositeCommand: Internal failure on event processing. SuspendPolicy was {1}; IsCancelled={0}. Exception={1}", suspendPolicy, task.IsCanceled, task.Exception); if (suspendPolicy != Jdwp.SuspendPolicy.None) { // we should better resume the VM, as the command handler may have failed to do so. if (Connected) { VirtualMachine.ResumeAsync(); } } }, TaskContinuationOptions.NotOnRanToCompletion); } }
/// <summary> /// Read incoming packets /// </summary> private void ReadLoop() { var myThread = Thread.CurrentThread; var readBuffer = new byte[1024 * 1024]; var readBufferOffset = 0; while (readThread == myThread) { // Should we stop? if ((!tcpClient.Connected) || (readThread != myThread)) { return; } // Read all available data var available = tcpClient.Available; if (available > 0) { Read(readBuffer, readBufferOffset, available); readBufferOffset += available; } else if (readBufferOffset == 0) { // Wait a while Thread.Sleep(10); } // Try to find packet and process them if (readBufferOffset == 0) { continue; } if (state == States.AwaitingHandshake) { // Look for handshake if (readBufferOffset < Handshake.Length) { continue; } if (Equals(readBuffer, Handshake, Handshake.Length)) { DLog.Debug(DContext.DebuggerLibJdwpConnection, "Valid handshake received from VM"); // Found correct handshake ConsumeReadBuffer(Handshake.Length, readBuffer, ref readBufferOffset); state = States.Ready; NotifyWriteQueue(); } else { // Invalid handshake DLog.Error(DContext.DebuggerLibJdwpConnection, "Received invalid handshape"); } } else if (state == States.Ready) { // Normal packet expected var packet = FindPacket(this, readBuffer, readBufferOffset); if (packet == null) { continue; } // Remove packet from buffer var length = packet.Length; ConsumeReadBuffer(length, readBuffer, ref readBufferOffset); #if DEBUG DLog.Debug(DContext.DebuggerLibJdwpConnection, "Read packet " + (packet.IsChunk() ? packet.AsChunk() : packet)); #endif // Find callback var processed = false; if (packet.IsReply) { var packetId = packet.Id; Action <JdwpPacket> callback; if (callbacks.TryRemove(packetId, out callback)) { // Perform callback. processed = true; callback(packet); } } if (!processed) { if (packet.IsChunk()) { // Handle non-reply chunks chunkHandler(packet.AsChunk()); } else if (!packet.IsReply) { // Handle non-reply packet packetHandler(packet); } processed = true; } if (!processed) { DLog.Debug(DContext.DebuggerLibJdwpConnection, "Unknown JDWP packet read {0}", packet); } } } }
/// <summary> /// Write the error message at log file /// </summary> /// <param name="messageLog">Message to write on log file</param> public static void Error(string messageLog) { //Proceed to save log DLog.Error(messageLog); }
/// <summary> /// this is fully reentrant and multithreading capable, but will itself block. /// </summary> private AssemblyDefinition Load(AssemblyNameReference name, string assemblyFilename, ReaderParameters parameters) { AssemblyDefinition ret = null; TaskCompletionSource <AssemblyDefinition> loadingTaskSource = new TaskCompletionSource <AssemblyDefinition>(); bool nameRegistered = false, filenameRegistered = false; try { // First, make sure we are the only one loading. while (true) { Task <AssemblyDefinition> loadingTask; if (name != null && !nameRegistered) { if (loadingTasks.TryGetValue(name.Name, out loadingTask)) { ret = loadingTask.Result; return(ret); } if (!loadingTasks.TryAdd(name.Name, loadingTaskSource.Task)) { continue; } nameRegistered = true; } if (loadingTasks.TryAdd(assemblyFilename, loadingTaskSource.Task)) { filenameRegistered = true; break; } if (loadingTasks.TryGetValue(assemblyFilename, out loadingTask)) { if (loadingTask == loadingTaskSource.Task) { break; } ret = loadingTask.Result; return(ret); } } // now check if it has already been loaded. if (name != null) { if (referencesByName.TryGetValue(name.Name, out ret)) { return(ret); } } ret = fileNamesByAssembly.FirstOrDefault(v => v.Value.Equals(assemblyFilename, StringComparison.InvariantCultureIgnoreCase)).Key; if (ret != null) { return(ret); } // now load the assembly. Console.WriteLine("Loading {0}...", Path.GetFileName(assemblyFilename)); AssemblyDefinition assm = AssemblyDefinition.ReadAssembly(assemblyFilename, parameters); VerifyFrameworkAssembly(assm, assemblyFilename); // have to use a lock to update both data structures at the same time. lock (referencesByName) { // now check again by the assembly name if it has been loaded before. // This can happen if we were only provided a file name if (!referencesByName.TryAdd(assm.Name.Name, assm)) { ret = referencesByName[assm.Name.Name]; return(ret); } fileNamesByAssembly[assm] = assemblyFilename; } ret = assm; // now notify any listeners. note that if we were called on multiple threads // these might be called reentrantly as well. if (assemblyLoaded != null) { assemblyLoaded(ret); } if (classLoader != null) { classLoader.LoadAssembly(ret); } // done. return(ret); } catch (Exception ex) { #if DEBUG Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); #endif // Log the error var assemblyName = name == null?assemblyFilename:name.ToString(); DLog.Error(DContext.CompilerAssemblyResolver, "Failed to load assembly {0}: {1}", assemblyName, ex.Message); // Pass the error on var exn = new AssemblyResolutionException(name ?? new AssemblyNameDefinition(assemblyFilename, new Version())); loadingTaskSource.SetException(exn); throw exn; } finally { loadingTaskSource.TrySetResult(ret); // cleanup our registrations Task <AssemblyDefinition> ignore; if (nameRegistered) { loadingTasks.TryRemove(name.Name, out ignore); } if (filenameRegistered) { loadingTasks.TryRemove(assemblyFilename, out ignore); } } }
/// <summary> /// Process the given exception event. /// </summary> protected override void OnExceptionEvent(Exception @event, DalvikThread thread) { var prev = Interlocked.CompareExchange(ref processing, @event, null); if (prev != null) { if (@event.ExceptionObject.Equals(prev.ExceptionObject) && @event.ThreadId.Equals(prev.ThreadId)) { // the same exception is reported multiple times. just ignore. Debugger.VirtualMachine.ResumeAsync(); return; } DLog.Error(DContext.VSDebuggerMessage, "Multiple exceptions in debuggee or exceptions while retrieving exception information. " + "Current Exception/Thread: {0}/{1}; previous Exception/Thread: {2}/{3} ", @event.ThreadId, @event.ExceptionObject, prev.ThreadId, prev.ExceptionObject); Debugger.VirtualMachine.ResumeAsync(); return; // This cancelling might not be neccessary any more; check this. //// I have no idea why we have to resume twice, but if we dont, the debuggee will hang. //Debugger.Process.ResumeAsync(); //if(cancelProcessing != null) // cancelProcessing.Cancel(); } cancelProcessing = new CancellationTokenSource(); var cancelToken = cancelProcessing.Token; bool wasThreadNull = thread == null; bool caught; string exceptionName = "(unknown)"; string catchingClass = "(unknown)"; string exceptionMessage = null; try { // Get information about the exception var exceptionTypeId = Debugger.ObjectReference.ReferenceTypeAsync(@event.ExceptionObject.Object) .Await(DalvikProcess.VmTimeout, cancelToken); var exceptionType = Process.ReferenceTypeManager[exceptionTypeId]; exceptionName = exceptionType.GetNameAsync() .Await(DalvikProcess.VmTimeout, cancelToken); caught = @event.IsCaught; if (!ShouldHandle(exceptionName, caught)) { DLog.Debug(DContext.VSDebuggerMessage, "not handling exception {0}", exceptionName); Debugger.VirtualMachine.ResumeAsync(); return; } if (caught && @event.CatchLocation != null) { // filter out internal exceptions, that are used for control flow. catchingClass = Process.ReferenceTypeManager[@event.CatchLocation.Class].GetNameAsync() .Await(DalvikProcess.VmTimeout, cancelToken); if (CaughtExceptionLocationExcludePattern.IsMatch(catchingClass)) { DLog.Debug(DContext.VSDebuggerMessage, "not handling exception {0}, catching class={1}", exceptionName, catchingClass); Debugger.VirtualMachine.ResumeAsync(); return; } } if (wasThreadNull) { thread = Debugger.Process.ThreadManager.Threads.First(); } base.OnExceptionEvent(@event, thread); exceptionMessage = GetExceptionMessageAsync(@event.ExceptionObject).Await(DalvikProcess.VmTimeout); } catch (System.Exception ex) { DLog.Error(DContext.VSDebuggerMessage, "Exception in debugger while processing exception: {0}. involved thread: {1}; exception.object={2}; exception type: {3}; ccatching class: {4}", ex.Message, GetThreadId(thread), @event.ExceptionObject.Object, exceptionName, catchingClass); Debugger.VirtualMachine.ResumeAsync(); return; } finally { Interlocked.Exchange(ref processing, null); } // Prepare VS event var info = new EXCEPTION_INFO(); info.bstrExceptionName = exceptionName; info.dwState = caught ? enum_EXCEPTION_STATE.EXCEPTION_STOP_FIRST_CHANCE : enum_EXCEPTION_STATE.EXCEPTION_STOP_USER_UNCAUGHT; program.GetName(out info.bstrProgramName); info.pProgram = program; info.guidType = GuidList.Guids.guidDot42DebuggerId; string description = info.bstrExceptionName; if (exceptionMessage != null) { description += ": \"" + exceptionMessage + "\""; } if (caught) { description += "\n(first chance, caught by debuggee)"; } else { description += "\n(not caught by debugee)"; } if (thread == null) { DLog.Warning(DContext.VSDebuggerEvent, "Exception without a thread: {0}. Original thread id: {1}.", exceptionName, @event.ThreadId); description += "\n The exceptions thread has already died, the VS call stack window has no meaning. The exception was raised on thread " + @event.ThreadId; } // Send VS event var vsEvent = new ExceptionEvent(info, description, false); Send((DebugThread)thread, vsEvent); }