2 using System.Collections.Generic;
5 using Mono.Cecil.Metadata;
8 using System.Reflection;
10 namespace Mono.Debugger.Soft
12 public class MethodBodyMirror : Mirror
17 internal MethodBodyMirror (VirtualMachine vm, MethodMirror method, MethodBodyInfo info) : base (vm, 0) {
22 public MethodMirror Method {
28 public List<ILExceptionHandler> ExceptionHandlers {
30 vm.CheckProtocolVersion (2, 18);
31 return info.clauses.Select (c =>
33 var handler = new ILExceptionHandler (c.try_offset, c.try_length, (ILExceptionHandlerType) c.flags, c.handler_offset, c.handler_length);
34 if (c.flags == ExceptionClauseFlags.None)
35 handler.CatchType = vm.GetType (c.catch_type_id);
36 else if (c.flags == ExceptionClauseFlags.Filter)
37 handler.FilterOffset = c.filter_offset;
44 public byte[] GetILAsByteArray () {
48 public List<ILInstruction> Instructions {
50 return ReadCilBody (new BinaryReader (new MemoryStream (info.il)), info.il.Length);
54 static bool opcodes_inited;
56 static OpCode [] OneByteOpCode = new OpCode [0xe0 + 1];
57 static OpCode [] TwoBytesOpCode = new OpCode [0x1e + 1];
59 static string EscapeString (string text)
61 StringBuilder sb = new StringBuilder ();
62 for (int i = 0; i < text.Length; i++) {
66 case '"': txt = "\\\""; break;
67 case '\0': txt = @"\0"; break;
68 case '\\': txt = @"\\"; break;
69 case '\a': txt = @"\a"; break;
70 case '\b': txt = @"\b"; break;
71 case '\f': txt = @"\f"; break;
72 case '\v': txt = @"\v"; break;
73 case '\n': txt = @"\n"; break;
74 case '\r': txt = @"\r"; break;
75 case '\t': txt = @"\t"; break;
77 if (char.GetUnicodeCategory (c) == UnicodeCategory.OtherNotAssigned) {
78 sb.AppendFormat ("\\u{0:x4}", (int) c);
86 return sb.ToString ();
90 List<ILInstruction> ReadCilBody (BinaryReader br, int code_size)
92 long start = br.BaseStream.Position;
93 ILInstruction last = null;
94 //GenericContext context = new GenericContext (body.Method);
95 List<ILInstruction> code = new List<ILInstruction> ();
97 var by_offset = new Dictionary<int, ILInstruction> ();
99 if (!opcodes_inited) {
100 foreach (FieldInfo fi in typeof (OpCodes).GetFields (BindingFlags.Static|BindingFlags.Public)) {
101 var val = (OpCode)fi.GetValue (null);
104 OneByteOpCode [val.Op2] = val;
106 TwoBytesOpCode [val.Op2] = val;
108 opcodes_inited = true;
111 while (br.BaseStream.Position < start + code_size) {
113 long offset = br.BaseStream.Position - start;
114 int cursor = br.ReadByte ();
119 op = TwoBytesOpCode [br.ReadByte ()];
121 op = OneByteOpCode [cursor];
123 ILInstruction instr = new ILInstruction ((int)offset, op, null);
125 by_offset [instr.Offset] = instr;
127 switch (op.OperandType) {
128 case OperandType.InlineNone :
130 case OperandType.InlineSwitch :
131 uint length = br.ReadUInt32 ();
132 int [] branches = new int [length];
133 int [] buf = new int [length];
134 for (int i = 0; i < length; i++)
135 buf [i] = br.ReadInt32 ();
136 for (int i = 0; i < length; i++)
137 branches [i] = Convert.ToInt32 (br.BaseStream.Position - start + buf [i]);
138 instr.Operand = branches;
140 case OperandType.ShortInlineBrTarget :
141 sbyte sbrtgt = br.ReadSByte ();
142 instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + sbrtgt);
144 case OperandType.InlineBrTarget :
145 int brtgt = br.ReadInt32 ();
146 instr.Operand = Convert.ToInt32 (br.BaseStream.Position - start + brtgt);
148 case OperandType.ShortInlineI :
149 if (op == OpCodes.Ldc_I4_S)
150 instr.Operand = br.ReadSByte ();
152 instr.Operand = br.ReadByte ();
154 case OperandType.ShortInlineVar :
155 instr.Operand = br.ReadByte ();
157 case OperandType.ShortInlineArg :
158 instr.Operand = br.ReadByte ();
160 case OperandType.InlineSig :
162 //instr.Operand = GetCallSiteAt (br.ReadInt32 (), context);
164 case OperandType.InlineI :
165 instr.Operand = br.ReadInt32 ();
167 case OperandType.InlineVar :
168 instr.Operand = br.ReadInt16 ();
170 case OperandType.InlineArg :
171 instr.Operand = br.ReadInt16 ();
173 case OperandType.InlineI8 :
174 instr.Operand = br.ReadInt64 ();
176 case OperandType.ShortInlineR :
177 instr.Operand = br.ReadSingle ();
179 case OperandType.InlineR :
180 instr.Operand = br.ReadDouble ();
182 case OperandType.InlineString :
183 token = br.ReadInt32 ();
184 t = vm.conn.Method_ResolveToken (Method.Id, token);
185 if (t.Type == TokenType.STRING)
186 instr.Operand = EscapeString (t.Str);
188 case OperandType.InlineField :
189 case OperandType.InlineMethod :
190 case OperandType.InlineType :
191 case OperandType.InlineTok :
192 token = br.ReadInt32 ();
194 t = vm.conn.Method_ResolveToken (Method.Id, token);
198 instr.Operand = vm.GetType (t.Id);
200 case TokenType.FIELD:
201 // FIXME: No vm.GetField ()
202 //instr.Operand = vm.GetField (t.Id);
204 case TokenType.METHOD:
205 instr.Operand = vm.GetMethod (t.Id);
207 case TokenType.UNKNOWN:
210 throw new NotImplementedException ("Unknown token type: " + t.Type);
217 instr.Previous = last;
226 foreach (ILInstruction i in code) {
227 switch (i.OpCode.OperandType) {
228 case OperandType.ShortInlineBrTarget:
229 case OperandType.InlineBrTarget:
230 i.Operand = by_offset [(int)i.Operand];
232 case OperandType.InlineSwitch:
233 int [] lbls = (int []) i.Operand;
234 ILInstruction [] instrs = new ILInstruction [lbls.Length];
235 for (int j = 0; j < lbls.Length; j++)
236 instrs [j] = by_offset [lbls [j]];