private SourceFile(ApkFile apk, JarFile jar, ISpySettings settings, MapFile mapFile, string singleFilePath = null) { this.apk = apk; this.jar = jar; this.settings = settings; this.mapFile = mapFile; this.singleFilePath = singleFilePath; #if DEBUG classLoader = new AssemblyClassLoader(module.OnClassLoaded); var modParams = new ModuleParameters { AssemblyResolver = new AssemblyResolver(new[] { Frameworks.Instance.FirstOrDefault().Folder }, classLoader, module.OnAssemblyLoaded), Kind = ModuleKind.Dll }; assembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition("spy", Version.Parse("1.0.0.0")), "main", modParams); classLoader.LoadAssembly(assembly); var dot42Assembly = modParams.AssemblyResolver.Resolve("dot42"); // Force loading of classes if (jar != null) { foreach (var fileName in jar.ClassFileNames) { OpenClass(fileName); } } #endif }
/// <summary> /// Default ctor /// </summary> internal DebugProgram(DebugProcess process, DebuggerLib.Debugger debugger, string apkPath, MapFile mapFile, EngineEventCallback eventCallback) : base(debugger, mapFile) { this.process = process; this.apkPath = apkPath; this.eventCallback = eventCallback; programGuid = Guid.NewGuid(); modules.Add(new DebugModule()); }
/// <summary> /// Default ctor /// </summary> internal DebugProcess(DebugEngine engine, DebugPort port, DebuggerLib.Debugger debugger, int processId, Guid guid, string apkPath, MapFile mapFile, EngineEventCallback eventCallback) { this.engine = engine; this.port = port; this.debugger = debugger; this.processId = processId; this.guid = guid; this.apkPath = apkPath; this.eventCallback = eventCallback; creationDate = DateTime.Now; program = new DebugProgram(this, debugger, apkPath, mapFile, eventCallback); program.Terminated += OnProgramTerminated; }
public MapFileLookup(MapFile map) { _map = map; // note the OrderBy(MethodOffset), which allows us to perform a binary search later on. _positionsByMethodId = map.Documents.SelectMany(d => d.Positions, SourceCodePosition.Create) .GroupBy(p=>p.Position.MethodId) .ToDictionary(p=>p.Key, p=>p.OrderBy(dp=>dp.Position.MethodOffset).ToList()); foreach (var entry in map.TypeEntries) { Add(entry); } }
/// <summary> /// Default ctor /// </summary> public DalvikProcess(Debugger debugger, MapFile mapFile, string apkPath) { ApkPath = apkPath; this.debugger = debugger; debugger.Process = this; this.mapFile = new MapFileLookup(mapFile); debugger.ConnectedChanged += OnDebuggerConnectionChanged; breakpointManager = new Lazy<DalvikBreakpointManager>(CreateBreakpointManager); exceptionManager = new Lazy<DalvikExceptionManager>(CreateExceptionManager); referenceTypeManager = new Lazy<DalvikReferenceTypeManager>(CreateReferenceTypeManager); threadManager = new Lazy<DalvikThreadManager>(CreateThreadManager); disassemblyProvider = new Lazy<DalvikDisassemblyProvider>(() => new DalvikDisassemblyProvider(this, ApkPath, this.mapFile)); }
/// <summary> /// Connect to the VM in the given process id on the given device. /// </summary> public void Connect(IDevice device, int pid, MapFile mapFile) { // Disconnect any pending connections Disconnect(); // Cleanup process = null; this.mapFile = mapFile; this.pid = pid; // Setup forward var port = GetFreePort(); var adb = new Adb(); adb.ForwardJdwp(device, port, pid); // Establish connection connection = new JdwpConnection(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port), ChunkHandler, pid, PacketHandler); connection.Disconnect += OnConnectionDisconnect; // Notify ConnectedChanged.Fire(this); }
/// <summary> /// Default ctor /// </summary> public DebugProcess(Dot42.DebuggerLib.Debugger debugger, MapFile mapFile) : base(debugger, mapFile, null) { }
/// <summary> /// Compile RL into the Dex method body. /// </summary> internal void CompileToTarget(ITargetPackage targetPackage, bool generateDebugInfo, MapFile mapFile) { CompileToDex((DexTargetPackage) targetPackage, generateDebugInfo, mapFile); }
/// <summary> /// Compile RL into the Dex method body. /// </summary> private void CompileToDex(DexTargetPackage targetPackage, bool generateDebugInfo, MapFile mapFile) { var dmethod = DexMethod; if (dmethod == null) throw new ArgumentException("No DexMethod set"); if ((dmethod.IsAbstract) || (dmethod.IsNative)) return; var rlBody = RLBody; if (rlBody == null) throw new ArgumentException("No RL body set"); // Ensure RL is optimized OptimizeRL(targetPackage.DexFile); // Compile to Dex var dbody = new Dot42.DexLib.Instructions.MethodBody(dmethod, 0); var dexCompiler = new DexCompiler(rlBody, dbody, InvocationFrame); regMapper = dexCompiler.Compile(); // Optimize code //dbody.UpdateInstructionOffsets(); DexOptimizer.DexOptimizer.Optimize(dbody); // Ensure correct offsets dbody.UpdateInstructionOffsets(); dmethod.Body = dbody; if (generateDebugInfo || (mapFile != null)) { // Add debug info var debugInfoBuilder = new DebugInfoBuilder(this); if (generateDebugInfo) debugInfoBuilder.CreateDebugInfo(dbody, regMapper, targetPackage); if (mapFile != null) debugInfoBuilder.AddDocumentMapping(mapFile); } }
public void RecordMapping(MapFile mapFile) { }
/// <summary> /// Compile RL into the Dex method body. /// </summary> private void CompileToDex(DexTargetPackage targetPackage, bool generateDebugInfo, MapFile mapFile) { var dmethod = DexMethod; if (dmethod == null) throw new ArgumentException("No DexMethod set"); if ((dmethod.IsAbstract) || (dmethod.IsNative)) return; var rlBody = RLBody; if (rlBody == null && dmethod.Body != null) // already satisfied from the cache? return; if (rlBody == null) throw new ArgumentException(string.Format("internal compiler error: No RL body set on method '{2}'.'{3}' => '{0}'.'{1}'", dmethod.Owner.Name, dmethod.Name, method == null ? null : method.DeclaringType.FullName, method == null ? null : method.Name)); // Ensure RL is optimized OptimizeRL(targetPackage.DexFile); // Compile to Dex var dbody = new Dot42.DexLib.Instructions.MethodBody(dmethod, 0); var dexCompiler = new DexCompiler(rlBody, dbody, InvocationFrame); regMapper = dexCompiler.Compile(); // Optimize code //dbody.UpdateInstructionOffsets(); DexOptimizer.DexOptimizer.Optimize(dbody); // Ensure correct offsets dbody.UpdateInstructionOffsets(); dmethod.Body = dbody; if (generateDebugInfo || (mapFile != null)) { // Add debug info var debugInfoBuilder = new DebugInfoBuilder(this); if (generateDebugInfo) debugInfoBuilder.CreateDebugInfo(dbody, regMapper, targetPackage); if (mapFile != null && dmethod.MapFileId != 0) debugInfoBuilder.AddDocumentMapping(mapFile); } }
/// <summary> /// Add document and position data to the given map file. /// </summary> internal void AddDocumentMapping(MapFile mapFile) { var source = compiledMethod.DexMethod; if ((source == null) || (source.Body == null) || (source.Body.Instructions.Count == 0)) return; if (this.compiledMethod.DexMethod.Name == "testTryCatch") { } var sequencePointsInstr = source.Body.Instructions.Where(x => x.SequencePoint != null); foreach (var seqPointIns in sequencePointsInstr) { // Get document var seqPoint = (ISourceLocation)seqPointIns.SequencePoint; var doc = mapFile.GetOrCreateDocument(seqPoint.Document, true); // Add position var docPos = new DocumentPosition(seqPoint.StartLine, seqPoint.StartColumn, seqPoint.EndLine, seqPoint.EndColumn, compiledMethod.DexMethod.Owner.MapFileId, compiledMethod.DexMethod.MapFileId, seqPointIns.Offset) { IsReturn = seqPointIns.OpCode.IsReturn() }; doc.Positions.Add(docPos); } }
/// <summary> /// Convert method arguments /// </summary> /// <param name="args"></param> /// <param name="map"></param> /// <returns></returns> private static string ConvertMethodArguments(Argument[] args, MapFile map) { StringBuilder sb = new StringBuilder(); foreach (Argument arg in args) { if (sb.Length > 0) { sb.Append(", "); } sb.Append(arg.Type); sb.Append(' '); sb.Append(arg.Name); } return sb.ToString(); }
/// <summary> /// Attach to the given process ID. /// </summary> private void Attach(int pid) { MapFile mapFile; string mapFileName; using (var dialog = new OpenFileDialog()) { dialog.Title = "Select map file"; dialog.DefaultExt = ".d42map"; if (dialog.ShowDialog(this) != DialogResult.OK) return; mapFileName = dialog.FileName; mapFile = new MapFile(mapFileName); } var device = lvDevices.SelectedDevice.Device; var connectTask = Task.Factory.StartNew(() => debugger.Connect(device, pid, mapFile, Path.ChangeExtension(mapFileName, "apk"))); connectTask.ContinueWith(t => debugger.PrepareAsync()); }
/// <summary> /// Record the mapping from .NET to Dex /// </summary> public void RecordMapping(MapFile mapFile) { // Create mapping var dexName = (classDef != null) ? classDef.Fullname : null; var mapFileId = (classDef != null) ? classDef.MapFileId : 0; var entry = new TypeEntry(typeDef.FullName, typeDef.Scope.Name, dexName, mapFileId); if (fieldBuilders != null) fieldBuilders.ForEach(x => x.RecordMapping(entry)); if (methodBuilders != null) methodBuilders.ForEach(x => x.RecordMapping(entry)); mapFile.Add(entry); // Create mapping of nested classes if (nestedBuilders != null) nestedBuilders.ForEach(x => x.RecordMapping(mapFile)); }
/// <summary> /// Record the mapping from .NET to Dex /// </summary> public void RecordMapping(TypeEntry typeEntry, MapFile mapFile) { var entry = RecordMapping(typeEntry, xMethod, method, dmethod, compiledMethod); if (cachedBody != null) { // take the mapping and debug info from the cached body. foreach (var v in cachedBody.MethodEntry.Variables) entry.Variables.Add(v); foreach (var p in cachedBody.MethodEntry.Parameters) entry.Parameters.Add(p); if (cachedBody.SourceCodePositions.Count > 0) { var doc = mapFile.GetOrCreateDocument(cachedBody.SourceCodePositions[0].Document.Path, true); foreach (var pos in cachedBody.SourceCodePositions.Select(p=>p.Position)) { var newPos = new DocumentPosition(pos.Start.Line,pos.Start.Column, pos.End.Line, pos.End.Column, typeEntry.Id, dmethod.MapFileId, pos.MethodOffset) { AlwaysKeep = true }; doc.Positions.Add(newPos); } } } }
/// <summary> /// Record the mapping from .NET to Dex /// </summary> public virtual void RecordMapping(MapFile mapFile) { var entry = CreateMappingEntry(); mapFile.Add(entry); if (fieldBuilders != null) fieldBuilders.ForEach(x => x.RecordMapping(entry)); if (methodBuilders != null) methodBuilders.ForEach(x => x.RecordMapping(entry, mapFile)); // Create mapping of nested classes if (nestedBuilders != null) nestedBuilders.ForEach(x => x.RecordMapping(mapFile)); }
/// <summary> /// Record the mapping from .NET to Dex /// </summary> public void RecordMapping(MapFile mapFile) { var dexName = (classDef != null) ? classDef.Fullname : null; var mapFileId = (classDef != null) ? classDef.MapFileId : 0; var entry = new TypeEntry(typeDef.ClassName, "<java>", dexName, mapFileId); if (fieldBuilders != null) fieldBuilders.ForEach(x => x.RecordMapping(entry)); if (methodBuilders != null) methodBuilders.ForEach(x => x.RecordMapping(entry)); mapFile.Add(entry); }
public override void RecordMapping(MapFile mapFile) { base.RecordMapping(mapFile); // create the mapping for all our instance type. foreach (var instance in delegateType.Instances) { // Create mapping var dexName = instance.InstanceDefinition.Fullname; var mapFileId = instance.InstanceDefinition.MapFileId; var scopeId = XType.ScopeId.Substring(XType.ScopeId.IndexOf(':') + 1); scopeId += ":delegate:" + instance.CalledMethod.DeclaringType.ScopeId + "|" + instance.CalledMethod.ScopeId; var entry = new TypeEntry(Type.FullName, Type.Scope.Name, dexName, mapFileId, scopeId); mapFile.Add(entry); } }
/// <summary> /// Merge the given set of map files into 1. /// </summary> private static MapFile MergeMapFiles(List<MapFile> mapFiles) { if (mapFiles.Count == 0) return new MapFile(); if (mapFiles.Count == 1) return mapFiles[0]; var result = new MapFile(); foreach (var entry in mapFiles.SelectMany(mapFile => mapFile)) { result.Add(entry); } return result; }