/// <summary>Build source code for a single method.</summary> /// <param name="method"></param> /// <returns></returns> private string BuildSourceCode(IMethod method, AstNode methodRootNode, Dictionary<string, string> namespaceByImportedType) { byte[] byteCode = method.GetByteCode(); if (null == byteCode) { return ""; } StringBuilder resultBuilder = new StringBuilder(); int opCodeIndex = 0; SortedList<uint, uint> exclusions = new SortedList<uint, uint>(); GenerateMethodHeader(method, resultBuilder, namespaceByImportedType); throw new NotImplementedException(); //SourceCodeWalkerContext sourceCodeWalkerContext = new SourceCodeWalkerContext(resultBuilder); //methodRootNode.Walk(SourceCodeWalker, WalkMode.TransitBeforeAndAfter, // sourceCodeWalkerContext); //foreach(InstructionAstNode scannedNode in methodRootNode.WalkLeaf<InstructionAstNode>()) { // resultBuilder.AppendLine(scannedNode.AssemblyCode); //} //IEnumerator<ITryBlock> tryBlocksEnumerator = method.EnumerateTryBlocks().GetEnumerator(); //ITryBlock nextGuardedBlock = // tryBlocksEnumerator.MoveNext() ? tryBlocksEnumerator.Current : null; //Stack<ITryBlock> partialTryBlocks = new Stack<ITryBlock>(); //while (byteCode.Length > opCodeIndex) //{ // // Check for next guarded block beginning. // while ((null != nextGuardedBlock) // && ((sizeof(ushort) * nextGuardedBlock.StartAddress) == opCodeIndex)) // { // // The current block is starting at current decoder position. // resultBuilder.Append("try { \n"); // partialTryBlocks.Push(nextGuardedBlock); // // Acquire next guarded block if any and loop again. This is because this // // new guarded block may share the same start offset than the one we just // // handled. // nextGuardedBlock = // tryBlocksEnumerator.MoveNext() ? tryBlocksEnumerator.Current : null; // } // // Decode current instruction. // resultBuilder.Append(OpCodeDecoder.Decode(null, byteCode, method.ByteCodeRawAddress, // _objectResolver, exclusions, ref opCodeIndex)); // // Handle partial guarded block termination. // while (true) // { // if (0 == partialTryBlocks.Count) { break; } // ITryBlock nextClosingBlock = partialTryBlocks.Peek(); // int lastCoveredOpCodeIndex = (int)(sizeof(ushort) * // (nextClosingBlock.StartAddress + nextClosingBlock.InstructionsCount - 1)); // if (lastCoveredOpCodeIndex >= opCodeIndex) { break; } // // This test for code robustness. Should never be true. // if (lastCoveredOpCodeIndex != (opCodeIndex - sizeof(ushort))) // { // throw new ApplicationException(); // } // // Current block terminates here. // nextClosingBlock = partialTryBlocks.Pop(); // } //} //if (0 != partialTryBlocks.Count) { throw new REException(); } //if (byteCode.Length != opCodeIndex) { throw new REException(); } //if (0 < exclusions.Count) { throw new REException(); } resultBuilder.Append("}"); return resultBuilder.ToString(); }
/// <summary>Decode instructions for the given method.</summary> /// <param name="method">The method to be decoded.</param> /// <param name="objectResolver">An implementation of an object resolver to be /// used for retrieving classes and constant strings referenced from the bytecode. /// </param> /// <returns>An array indexed by the offset within method byte code and storing /// the instruction starting at this offset (if any).</returns> private static DalvikInstruction[] BuildInstructionList(IMethod method, IResolver objectResolver) { DalvikInstruction[] result = new DalvikInstruction[method.ByteCodeSize]; byte[] byteCode = method.GetByteCode(); List<uint> pendingInstructionsOffset = new List<uint>(); // Add entry point. pendingInstructionsOffset.Add(0); // As well as catch blocks from the exception because they aren't // referenced from normal code. foreach (ITryBlock tryBlock in method.EnumerateTryBlocks()) { foreach (IGuardHandler handler in tryBlock.EnumerateHandlers()) { uint addedOffset = handler.HandlerMethodOffset; // For debugging purpose. Should never occur. if (addedOffset >= byteCode.Length) { throw new ApplicationException(); } pendingInstructionsOffset.Add(addedOffset); } } Console.WriteLine( "Decoding '{0}' method bytecode on {1} bytes starting at 0x{2:X8}.", Helpers.BuildMethodDeclarationString(method), byteCode.Length, method.ByteCodeRawAddress); while (0 < pendingInstructionsOffset.Count) { uint opCodeIndex = pendingInstructionsOffset[0]; pendingInstructionsOffset.RemoveAt(0); bool fallInSequence = true; while (fallInSequence) { // Avoid targeting twice a single instruction. if (null != result[opCodeIndex]) { break; } DalvikInstruction newNode = OpCodeDecoder.Decode(byteCode, method.ByteCodeRawAddress, objectResolver, result, ref opCodeIndex); // Analyse possible targets after this instruction and augment // pending instructions list accordingly. fallInSequence = newNode.ContinueInSequence; uint[] otherTargetMethodOffsets = newNode.AdditionalTargetMethodOffsets; if (null != otherTargetMethodOffsets) { for(int index = 0; index < otherTargetMethodOffsets.Length; index++) { uint targetOffset = otherTargetMethodOffsets[index]; if (targetOffset >= byteCode.Length) { throw new ApplicationException(); } if (!pendingInstructionsOffset.Contains(targetOffset) && (null == result[targetOffset])) { pendingInstructionsOffset.Add(targetOffset); } } } } } return result; }