1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | /***************************************************************************/ |
6 | /* ILFormatter.h */ |
7 | /***************************************************************************/ |
8 | |
9 | #include "stdafx.h" |
10 | #include <cor.h> |
11 | #include <debugmacros.h> // for ASSERTE |
12 | #include "ilformatter.h" |
13 | #include "outstring.h" |
14 | #include "opinfo.h" |
15 | |
16 | /***************************************************************************/ |
17 | void ILFormatter::init(IMetaDataImport* aMeta, const BYTE* aStart, |
18 | const BYTE* aLimit, unsigned maxStack, const COR_ILMETHOD_SECT_EH* eh) { |
19 | this->~ILFormatter(); // clean out old stuff |
20 | |
21 | meta = aMeta; |
22 | start = aStart; |
23 | limit = aLimit; |
24 | if (maxStack == 0) maxStack++; |
25 | stackStart = stackCur = new StackEntry[maxStack]; |
26 | stackEnd = stackStart + maxStack; |
27 | targetStart = targetCur = targetEnd = 0; |
28 | if (eh != 0) { |
29 | COR_ILMETHOD_SECT_EH_CLAUSE_FAT buff; |
30 | const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* clause; |
31 | for(unsigned i = 0; i < eh->EHCount(); i++) { |
32 | clause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)eh->EHClause(i, &buff); |
33 | // is it a regular catch clause ? |
34 | if ((clause->GetFlags() & (COR_ILEXCEPTION_CLAUSE_FINALLY | COR_ILEXCEPTION_CLAUSE_FAULT)) == 0) |
35 | setTarget(clause->GetHandlerOffset(), 1); |
36 | if(clause->GetFlags() & COR_ILEXCEPTION_CLAUSE_FILTER) |
37 | setTarget(clause->GetFilterOffset(), 1); |
38 | } |
39 | } |
40 | } |
41 | |
42 | /***************************************************************************/ |
43 | inline size_t ILFormatter::stackDepth() { |
44 | return(stackCur - stackStart); |
45 | } |
46 | |
47 | /***************************************************************************/ |
48 | inline void ILFormatter::pushAndClear(OutString* val, int prec) { |
49 | if (stackCur >= stackEnd) { |
50 | _ASSERTE(!"Stack Overflow (can be ignored)" ); |
51 | return; // Ignore overflow in free build |
52 | } |
53 | stackCur->val.swap(*val); |
54 | val->clear(); |
55 | stackCur->prec = prec; |
56 | stackCur++; |
57 | } |
58 | |
59 | /***************************************************************************/ |
60 | inline OutString* ILFormatter::top() { |
61 | if (stackDepth() == 0) { |
62 | _ASSERTE(!"Stack underflow (can be ignored)" ); |
63 | stackStart->val.clear(); |
64 | stackStart->val << "<UNDERFLOW ERROR>" ; |
65 | return (&stackStart->val); |
66 | } |
67 | return(&stackCur[-1].val); |
68 | } |
69 | |
70 | /***************************************************************************/ |
71 | inline OutString* ILFormatter::pop(int prec) { |
72 | if (stackDepth() == 0) { |
73 | _ASSERTE(!"Stack underflow (can be ignored)" ); |
74 | stackStart->val.clear(); |
75 | stackStart->val << "<UNDERFLOW ERROR>" ; |
76 | return (&stackStart->val); |
77 | } |
78 | --stackCur; |
79 | if (stackCur->prec < prec) { |
80 | stackCur->val.prepend('('); |
81 | stackCur->val << ')'; |
82 | } |
83 | return(&stackCur->val); |
84 | } |
85 | |
86 | /***************************************************************************/ |
87 | inline void ILFormatter::popN(size_t num) { |
88 | if (stackCur-stackStart < (SSIZE_T)num) { |
89 | _ASSERTE(!"Stack underflow (can be ignored)" ); |
90 | stackCur = stackStart; |
91 | return; |
92 | } |
93 | stackCur -= num; |
94 | } |
95 | |
96 | /***************************************************************************/ |
97 | void ILFormatter::setStackAsTarget(size_t ilOffset) { |
98 | |
99 | Target*ptr = targetStart; |
100 | for(;;) { |
101 | if (ptr >= targetCur) |
102 | return; |
103 | if (ptr->ilOffset == ilOffset) |
104 | break; |
105 | ptr++; |
106 | } |
107 | |
108 | for(size_t i = 0; i < ptr->stackDepth; i++) { |
109 | stackStart[i].val.clear(); |
110 | stackStart[i].val << "@STK" << (unsigned)i; |
111 | } |
112 | stackCur = stackStart + ptr->stackDepth; |
113 | } |
114 | |
115 | /***************************************************************************/ |
116 | void ILFormatter::setTarget(size_t ilOffset, size_t depth) { |
117 | if (depth == 0) |
118 | return; |
119 | |
120 | if (targetCur >= targetEnd) { |
121 | Target* targetOld = targetStart; |
122 | size_t oldLen = targetCur-targetStart; |
123 | targetStart = new Target[oldLen+10]; |
124 | targetEnd = &targetStart[oldLen+10]; |
125 | targetCur = &targetStart[oldLen]; |
126 | memcpy(targetStart, targetOld, sizeof(Target)*oldLen); |
127 | delete [] targetOld; |
128 | } |
129 | targetCur->ilOffset = ilOffset; |
130 | targetCur->stackDepth = depth; |
131 | targetCur++; |
132 | } |
133 | |
134 | /***************************************************************************/ |
135 | void ILFormatter::spillStack(OutString* out) { |
136 | |
137 | for(unsigned i = 0; i < stackDepth(); i++) { |
138 | // don't bother spilling something already spilled. |
139 | if (memcmp(stackStart[i].val.val(), "@STK" , 4) != 0) |
140 | *out << "@STK" << i << " = " << stackStart[i].val.val() << "\n" ; |
141 | stackStart[i].val.clear(); |
142 | stackStart[i].val << "@STK" << i ; |
143 | } |
144 | } |
145 | |
146 | /***************************************************************************/ |
147 | const BYTE* ILFormatter::formatInstr(const BYTE* instrPtr, OutString* out) { |
148 | |
149 | _ASSERTE(start < instrPtr && instrPtr < limit); |
150 | OpArgsVal arg; |
151 | OpInfo op; |
152 | instrPtr = op.fetch(instrPtr, &arg); |
153 | *out << op.getName(); |
154 | if (op.getArgsInfo() != InlineNone) |
155 | *out << ' '; |
156 | formatInstrArgs(op, arg, out, instrPtr - start); |
157 | return(instrPtr); |
158 | } |
159 | |
160 | /***************************************************************************/ |
161 | void ILFormatter::formatArgs(unsigned numArgs, OutString* out) { |
162 | |
163 | *out << '('; |
164 | if (numArgs > stackDepth()) { |
165 | _ASSERTE(!"Underflow error" ); |
166 | *out << "<UNDERFLOW ERROR>" ; |
167 | } |
168 | else { |
169 | popN(numArgs); |
170 | for(unsigned i = 0; i < numArgs; i++) { |
171 | if (i != 0) *out << ", " ; |
172 | *out << stackCur[i].val.val(); |
173 | } |
174 | } |
175 | *out << ')'; |
176 | } |
177 | |
178 | /***************************************************************************/ |
179 | void ILFormatter::formatInstrArgs(OpInfo op, OpArgsVal arg, OutString* out, size_t curILOffset) { |
180 | |
181 | MDUTF8CSTR typeName=0; |
182 | HRESULT hr = S_OK; |
183 | switch(op.getArgsInfo() & PrimaryMask) { |
184 | case InlineNone: |
185 | break; |
186 | case InlineVar: |
187 | *out << arg.i; |
188 | break; |
189 | case InlineI: |
190 | case InlineRVA: |
191 | out->hex(arg.i, 0, OutString::put0x); |
192 | break; |
193 | case InlineR: |
194 | *out << arg.r; |
195 | break; |
196 | case InlineBrTarget: { |
197 | _ASSERTE(curILOffset != INVALID_IL_OFFSET); |
198 | size_t target = curILOffset + arg.i; |
199 | setTarget(target, stackDepth()); |
200 | *out << "IL_" ; out->hex(static_cast<unsigned __int64>(target), 4, OutString::zeroFill); |
201 | } break; |
202 | case InlineI8: |
203 | out->hex(arg.i, 0, OutString::put0x); |
204 | break; |
205 | case InlineString: { |
206 | ULONG numChars; |
207 | wchar_t str[84]; |
208 | |
209 | hr = meta->GetUserString(arg.i, str, 80, &numChars); |
210 | _ASSERTE(SUCCEEDED(hr)); |
211 | if (numChars < 80) |
212 | str[numChars] = 0; |
213 | wcscpy_s(&str[79], 4, W("..." )); |
214 | *out << '"'; |
215 | wchar_t* ptr = str; |
216 | while(*ptr != 0) { |
217 | if (*ptr == '\n') |
218 | *out << "\\n" ; |
219 | else if (*ptr == '"') |
220 | *out << "\\\"" ; |
221 | else if (*ptr < 0x20 || * ptr >= 0x80) { |
222 | *out << '\\'; |
223 | out->hex(*ptr, 4, OutString::zeroFill); |
224 | } |
225 | else |
226 | *out << char(*ptr); |
227 | ptr++; |
228 | } |
229 | *out << '"'; |
230 | } break; |
231 | case InlineMethod: |
232 | case InlineField: |
233 | case InlineTok: { |
234 | // Get the typeName if possible |
235 | mdToken mdType = mdTypeDefNil; |
236 | if (TypeFromToken(arg.i) == mdtMethodDef) |
237 | hr = meta->GetMethodProps(mdMethodDef(arg.i), &mdType, 0, 0, 0, 0, 0, 0, 0, 0); |
238 | else if (TypeFromToken(arg.i) == mdtMemberRef) |
239 | hr = meta->GetMemberRefProps(mdMemberRef(arg.i), &mdType, 0, 0, 0, 0, 0); |
240 | else if (TypeFromToken(arg.i) == mdtFieldDef) |
241 | hr = meta->GetFieldProps(mdMethodDef(arg.i), &mdType, 0, 0, 0, 0, 0, 0, 0, 0, 0); |
242 | if (SUCCEEDED(hr) && mdType != mdTypeDefNil) { |
243 | hr = meta->GetNameFromToken(mdType, &typeName); |
244 | } |
245 | } |
246 | // FALL THROUGH |
247 | case InlineType: { |
248 | // FIX handle case if (TypeFromToken(arg.i) == mdtTypeSpec) |
249 | MDUTF8CSTR name; |
250 | hr = meta->GetNameFromToken(arg.i, &name); |
251 | if (SUCCEEDED(hr)) { |
252 | if (typeName) { |
253 | const char* lastDot = strrchr(typeName, '.'); |
254 | if (lastDot) typeName = lastDot + 1; |
255 | *out << typeName << "::" ; |
256 | } |
257 | *out << name; |
258 | } |
259 | else { |
260 | *out << "TOK<" ; |
261 | out->hex(arg.i, 0, OutString::put0x); |
262 | *out << '>'; |
263 | } |
264 | } break; |
265 | case InlineSig: |
266 | *out << "SIG<" ; |
267 | out->hex(arg.i, 0, OutString::put0x); |
268 | *out << '>'; |
269 | break; |
270 | case InlineSwitch: { |
271 | _ASSERTE(curILOffset != INVALID_IL_OFFSET); |
272 | unsigned count = arg.switch_.count; |
273 | unsigned i; |
274 | for (i = 0; i < count; i++) { |
275 | size_t target = curILOffset + GET_UNALIGNED_VAL32(&arg.switch_.targets[i]); |
276 | setTarget(target, stackDepth()-1); |
277 | *out << "IL_" ; out->hex(static_cast<unsigned __int64>(target), 4, OutString::zeroFill); |
278 | if (i < count) |
279 | *out << ' '; |
280 | } |
281 | } break; |
282 | case InlinePhi: { |
283 | unsigned count = arg.phi.count; |
284 | unsigned i; |
285 | for (i = 0; i < count; i++) { |
286 | *out << GET_UNALIGNED_VAL32(&arg.phi.vars[i]); |
287 | if (i < count) |
288 | *out << ' '; |
289 | } |
290 | } break; |
291 | default: |
292 | _ASSERTE(!"BadType" ); |
293 | } |
294 | } |
295 | |
296 | #ifdef _PREFAST_ |
297 | #pragma warning(push) |
298 | #pragma warning(disable:21000) // Suppress PREFast warning about overly large function |
299 | #endif |
300 | /***************************************************************************/ |
301 | const BYTE* ILFormatter::formatStatement(const BYTE* instrPtr, OutString* out) { |
302 | |
303 | OutString result; |
304 | OpInfo op; |
305 | OutString *lhs, *rhs, *idx; |
306 | const char* name; |
307 | int prec = 0; |
308 | |
309 | // set stack as it would be if it was begin jumped to |
310 | setStackAsTarget(instrPtr - start); |
311 | |
312 | while(instrPtr < limit) { |
313 | OpArgsVal inlineArg; |
314 | instrPtr = op.fetch(instrPtr, &inlineArg); |
315 | |
316 | switch(op.getOpcode()) { |
317 | case CEE_UNALIGNED: |
318 | case CEE_TAILCALL: |
319 | case CEE_VOLATILE: |
320 | // for now just skip these |
321 | break; |
322 | |
323 | case CEE_LDARGA_S: |
324 | case CEE_LDARGA: |
325 | result << "&" ; |
326 | goto DO_LDARG; |
327 | |
328 | case CEE_LDARG_0: |
329 | case CEE_LDARG_1: |
330 | case CEE_LDARG_2: |
331 | case CEE_LDARG_3: |
332 | inlineArg.i = op.getOpcode() - CEE_LDARG_0; |
333 | goto DO_LDARG; |
334 | |
335 | case CEE_LDARG: |
336 | case CEE_LDARG_S: |
337 | DO_LDARG: |
338 | name = "arg" ; |
339 | DO_LDARG_LDLOC: |
340 | result << name << inlineArg.i; |
341 | prec = 0x1000; |
342 | goto DO_PUSH; |
343 | DO_PUSH: |
344 | pushAndClear(&result, prec); // also clears result! |
345 | break; |
346 | |
347 | case CEE_LDLOCA_S: |
348 | case CEE_LDLOCA: |
349 | result << "&" ; |
350 | goto DO_LDLOC; |
351 | |
352 | case CEE_LDLOC_0: |
353 | case CEE_LDLOC_1: |
354 | case CEE_LDLOC_2: |
355 | case CEE_LDLOC_3: |
356 | inlineArg.i = op.getOpcode() - CEE_LDLOC_0; |
357 | goto DO_LDLOC; |
358 | |
359 | case CEE_LDLOC: |
360 | case CEE_LDLOC_S: |
361 | DO_LDLOC: |
362 | name = "loc" ; |
363 | goto DO_LDARG_LDLOC; |
364 | |
365 | case CEE_STARG: |
366 | case CEE_STARG_S: |
367 | name = "arg" ; |
368 | DO_STARG_STLOC: |
369 | lhs = pop(0x10); |
370 | result << name << inlineArg.i << " = " << lhs->val(); |
371 | DO_STMT: |
372 | spillStack(out); |
373 | *out << result.val() << '\n'; |
374 | // if flow of control does not fall through, |
375 | // assume the stack is empty |
376 | if (op.getFlow() == FLOW_BRANCH || op.getFlow() == FLOW_RETURN || |
377 | op.getFlow() == FLOW_THROW) { |
378 | popN(stackDepth()); |
379 | } |
380 | return(instrPtr); |
381 | |
382 | case CEE_STLOC_0: |
383 | case CEE_STLOC_1: |
384 | case CEE_STLOC_2: |
385 | case CEE_STLOC_3: |
386 | inlineArg.i = op.getOpcode() - CEE_STLOC_0; |
387 | goto DO_STLOC; |
388 | |
389 | case CEE_STLOC: |
390 | case CEE_STLOC_S: |
391 | DO_STLOC: |
392 | name = "loc" ; |
393 | goto DO_STARG_STLOC; |
394 | |
395 | case CEE_LDC_I4_M1: |
396 | case CEE_LDC_I4_0: |
397 | case CEE_LDC_I4_1: |
398 | case CEE_LDC_I4_2: |
399 | case CEE_LDC_I4_3: |
400 | case CEE_LDC_I4_4: |
401 | case CEE_LDC_I4_5: |
402 | case CEE_LDC_I4_6: |
403 | case CEE_LDC_I4_7: |
404 | case CEE_LDC_I4_8: |
405 | inlineArg.i = op.getOpcode() - CEE_LDC_I4_0; |
406 | // FALL THROUGH |
407 | case CEE_LDC_I4: |
408 | case CEE_LDC_I4_S: |
409 | result << inlineArg.i; |
410 | prec = 0x1000; |
411 | goto DO_PUSH; |
412 | |
413 | case CEE_LDC_I8: |
414 | result.hex(inlineArg.i8); |
415 | prec = 0x1000; |
416 | goto DO_PUSH; |
417 | |
418 | case CEE_LDC_R4: |
419 | case CEE_LDC_R8: |
420 | result << inlineArg.r; |
421 | prec = 0x1000; |
422 | goto DO_PUSH; |
423 | |
424 | case CEE_LDNULL: |
425 | result << "null" ; |
426 | prec = 0x1000; |
427 | goto DO_PUSH; |
428 | |
429 | case CEE_LDSTR: |
430 | formatInstrArgs(op, inlineArg, &result); |
431 | prec = 0x1000; |
432 | goto DO_PUSH; |
433 | |
434 | case CEE_BEQ: |
435 | case CEE_BEQ_S: |
436 | name = "==" ; prec = 0x40; goto DO_BR_BINOP; |
437 | case CEE_BGE: |
438 | case CEE_BGE_S: |
439 | name = ">=" ; prec = 0x40; goto DO_BR_BINOP; |
440 | case CEE_BGE_UN: |
441 | case CEE_BGE_UN_S: |
442 | name = ">=un" ; prec = 0x40; goto DO_BR_BINOP; |
443 | |
444 | case CEE_BGT: |
445 | case CEE_BGT_S: |
446 | name = ">" ; prec = 0x40; goto DO_BR_BINOP; |
447 | case CEE_BGT_UN: |
448 | case CEE_BGT_UN_S: |
449 | name = ">un" ; prec = 0x40; goto DO_BR_BINOP; |
450 | case CEE_BLE: |
451 | case CEE_BLE_S: |
452 | name = "<=" ; prec = 0x40; goto DO_BR_BINOP; |
453 | case CEE_BLE_UN: |
454 | case CEE_BLE_UN_S: |
455 | name = "<=un" ; prec = 0x40; goto DO_BR_BINOP; |
456 | case CEE_BLT: |
457 | case CEE_BLT_S: |
458 | name = "<" ; prec = 0x40; goto DO_BR_BINOP; |
459 | case CEE_BLT_UN: |
460 | case CEE_BLT_UN_S: |
461 | name = "<un" ; prec = 0x40; goto DO_BR_BINOP; |
462 | case CEE_BNE_UN: |
463 | case CEE_BNE_UN_S: |
464 | name = "!=un" ; prec = 0x40; goto DO_BR_BINOP; |
465 | DO_BR_BINOP: |
466 | rhs = pop(prec); |
467 | lhs = pop(prec-1); |
468 | result << "if (" << lhs->val() << ' ' << name << ' ' << rhs->val() << ") " ; |
469 | goto DO_BR; |
470 | |
471 | case CEE_LEAVE_S: |
472 | case CEE_LEAVE: |
473 | while (stackDepth() > 0) { |
474 | lhs = pop(); |
475 | *lhs << '\n' << result; // put the result in front of anything else |
476 | result.swap(*lhs); |
477 | } |
478 | /* fall through */ |
479 | case CEE_BR_S: |
480 | case CEE_BR: |
481 | DO_BR: { |
482 | size_t target = (instrPtr - start) + inlineArg.i; |
483 | setTarget(target, stackDepth()); |
484 | result << "goto IL_" ; result.hex(static_cast<unsigned __int64>(target), 4, OutString::zeroFill); |
485 | } goto DO_STMT; |
486 | |
487 | case CEE_BRFALSE_S: |
488 | case CEE_BRFALSE: |
489 | name = "!" ; |
490 | goto DO_BR_UNOP; |
491 | case CEE_BRTRUE_S: |
492 | case CEE_BRTRUE: |
493 | name = "" ; |
494 | DO_BR_UNOP: |
495 | lhs = pop(); |
496 | result << "if (" << name << lhs->val() << ") " ; |
497 | goto DO_BR; |
498 | |
499 | case CEE_OR: |
500 | name = "|" ; prec = 0x20; goto DO_BINOP; |
501 | case CEE_XOR: |
502 | name = "^" ; prec = 0x20; goto DO_BINOP; |
503 | case CEE_AND: |
504 | name = "&" ; prec = 0x30; goto DO_BINOP; |
505 | case CEE_SHL: |
506 | name = "<<" ; prec = 0x50; goto DO_BINOP; |
507 | case CEE_SHR: |
508 | name = ">>" ; prec = 0x50; goto DO_BINOP; |
509 | case CEE_SHR_UN: |
510 | name = ">>un" ; prec = 0x50; goto DO_BINOP; |
511 | case CEE_CEQ: |
512 | name = "==" ; prec = 0x40; goto DO_BINOP; |
513 | case CEE_CGT: |
514 | name = ">" ; prec = 0x40; goto DO_BINOP; |
515 | case CEE_CGT_UN: |
516 | name = ">un" ; prec = 0x40; goto DO_BINOP; |
517 | case CEE_CLT: |
518 | name = "<" ; prec = 0x40; goto DO_BINOP; |
519 | case CEE_CLT_UN: |
520 | name = "<un" ; prec = 0x40; goto DO_BINOP; |
521 | case CEE_ADD: |
522 | name = "+" ; prec = 0x60; goto DO_BINOP; |
523 | case CEE_ADD_OVF: |
524 | name = "+ovf" ; prec = 0x60; goto DO_BINOP; |
525 | case CEE_ADD_OVF_UN: |
526 | name = "+ovf.un" ;prec = 0x60; goto DO_BINOP; |
527 | case CEE_SUB: |
528 | name = "-" ; prec = 0x60; goto DO_BINOP; |
529 | case CEE_SUB_OVF: |
530 | name = "-ovf" ; prec = 0x60; goto DO_BINOP; |
531 | case CEE_SUB_OVF_UN: |
532 | name = "-ovf.un" ;prec = 0x60; goto DO_BINOP; |
533 | case CEE_MUL: |
534 | name = "*" ; prec = 0x70; goto DO_BINOP; |
535 | case CEE_MUL_OVF: |
536 | name = "*ovf" ; prec = 0x70; goto DO_BINOP; |
537 | case CEE_MUL_OVF_UN: |
538 | name = "*ovf.un" ;prec = 0x70; goto DO_BINOP; |
539 | case CEE_DIV: |
540 | name = "/" ; prec = 0x70; goto DO_BINOP; |
541 | case CEE_DIV_UN: |
542 | name = "/un" ; prec = 0x70; goto DO_BINOP; |
543 | case CEE_REM: |
544 | name = "%" ; prec = 0x70; goto DO_BINOP; |
545 | case CEE_REM_UN: |
546 | name = "%un" ; prec = 0x70; goto DO_BINOP; |
547 | DO_BINOP: |
548 | rhs = pop(prec); |
549 | lhs = pop(prec-1); |
550 | result << lhs->val() << ' ' << name << ' ' << rhs->val(); |
551 | goto DO_PUSH; |
552 | |
553 | case CEE_NOT: |
554 | name = "~" ; prec = 0x80; goto DO_UNOP; |
555 | case CEE_NEG: |
556 | name = "-" ; prec = 0x80; goto DO_UNOP; |
557 | DO_UNOP: |
558 | lhs = pop(prec-1); |
559 | result << name << lhs->val(); |
560 | goto DO_PUSH; |
561 | |
562 | case CEE_RET: |
563 | _ASSERTE(stackDepth() <= 1); |
564 | result << "return" ; |
565 | if (stackDepth() > 0) { |
566 | lhs = pop(); |
567 | result << ' ' << lhs->val(); |
568 | } |
569 | goto DO_STMT; |
570 | |
571 | case CEE_POP: |
572 | lhs = pop(); |
573 | result.swap(*lhs); |
574 | goto DO_STMT; |
575 | |
576 | case CEE_DUP: |
577 | spillStack(out); |
578 | lhs = top(); |
579 | result << lhs->val(); |
580 | prec = 0x1000; // spillstack makes them temps, so they have high prec |
581 | goto DO_PUSH; |
582 | |
583 | case CEE_LDFLDA: |
584 | name = "&" ; |
585 | goto DO_LDFLD_LDFLDA; |
586 | case CEE_LDFLD: |
587 | name = "" ; |
588 | DO_LDFLD_LDFLDA: |
589 | prec = 0x110; |
590 | lhs = pop(prec-1); |
591 | result << name << lhs->val() << '.'; |
592 | formatInstrArgs(op, inlineArg, &result); |
593 | goto DO_PUSH; |
594 | |
595 | case CEE_LDSFLDA: |
596 | name = "&" ; |
597 | goto DO_LDSFLD_LDSFLDA; |
598 | case CEE_LDSFLD: |
599 | name = "" ; |
600 | DO_LDSFLD_LDSFLDA: |
601 | prec = 0x1000; |
602 | result << name; |
603 | formatInstrArgs(op, inlineArg, &result); |
604 | goto DO_PUSH; |
605 | |
606 | case CEE_STFLD: |
607 | rhs = pop(0x10); |
608 | lhs = pop(0x110-1); |
609 | result << lhs->val() << '.'; |
610 | formatInstrArgs(op, inlineArg, &result); |
611 | result << " = " << rhs->val(); |
612 | goto DO_STMT; |
613 | |
614 | case CEE_STSFLD: |
615 | rhs = pop(0x20); |
616 | formatInstrArgs(op, inlineArg, &result); |
617 | result << " = " << rhs->val(); |
618 | goto DO_STMT; |
619 | |
620 | case CEE_CALLI: |
621 | lhs = pop(); |
622 | result << "CALLI<" << lhs->val() << '>'; |
623 | goto DO_CALL; |
624 | |
625 | case CEE_NEWOBJ: |
626 | result << "new " ; |
627 | // FALL THROUGH |
628 | case CEE_CALL: |
629 | case CEE_CALLVIRT: { |
630 | formatInstrArgs(op, inlineArg, &result); |
631 | |
632 | DO_CALL: |
633 | // Get the signature stuff |
634 | PCCOR_SIGNATURE sig; |
635 | ULONG cSig; |
636 | HRESULT hr; |
637 | if (TypeFromToken(inlineArg.i) == mdtMethodDef) |
638 | hr = meta->GetMethodProps(mdMethodDef(inlineArg.i), 0, 0, 0, 0, 0, &sig, &cSig, 0, 0); |
639 | else if (TypeFromToken(inlineArg.i) == mdtMemberRef) |
640 | hr = meta->GetMemberRefProps(mdMemberRef(inlineArg.i), 0, 0, 0, 0, &sig, &cSig); |
641 | else |
642 | hr = meta->GetSigFromToken(mdSignature(inlineArg.i), &sig, &cSig); |
643 | _ASSERTE(SUCCEEDED(hr)); |
644 | unsigned callConv = CorSigUncompressData(sig); |
645 | unsigned hasThis = callConv & IMAGE_CEE_CS_CALLCONV_HASTHIS; |
646 | if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC) |
647 | { |
648 | CorSigUncompressData(sig); |
649 | } |
650 | unsigned numArgs = CorSigUncompressData(sig); |
651 | while(*sig == ELEMENT_TYPE_CMOD_REQD || *sig == ELEMENT_TYPE_CMOD_OPT) { |
652 | sig++; |
653 | CorSigUncompressToken(sig); |
654 | } |
655 | |
656 | formatArgs(numArgs, &result); |
657 | if (hasThis && op.getOpcode() != CEE_NEWOBJ) { |
658 | lhs = pop(0x90); |
659 | result.swap(*lhs); |
660 | result << '.' << lhs->val(); |
661 | } |
662 | prec = 0x1000; |
663 | if (op.getOpcode() == CEE_NEWOBJ || *sig != ELEMENT_TYPE_VOID) |
664 | goto DO_PUSH; |
665 | } goto DO_STMT; |
666 | |
667 | case CEE_LDELEM_I1: |
668 | case CEE_LDELEM_I2: |
669 | case CEE_LDELEM_I4: |
670 | case CEE_LDELEM_I8: |
671 | case CEE_LDELEM_REF: |
672 | case CEE_LDELEM_R4: |
673 | case CEE_LDELEM_R8: |
674 | case CEE_LDELEM_U1: |
675 | case CEE_LDELEM_U2: |
676 | case CEE_LDELEM_I: |
677 | rhs = pop(0x100); |
678 | lhs = pop(); |
679 | result << lhs->val() << '[' << rhs->val() << ']'; |
680 | prec = 0x100; |
681 | goto DO_PUSH; |
682 | |
683 | case CEE_STELEM_I1: |
684 | case CEE_STELEM_I2: |
685 | case CEE_STELEM_I4: |
686 | case CEE_STELEM_I8: |
687 | case CEE_STELEM_REF: |
688 | case CEE_STELEM_R4: |
689 | case CEE_STELEM_R8: |
690 | case CEE_STELEM_I: |
691 | rhs = pop(0x100); |
692 | idx = pop(); |
693 | lhs = pop(0x20); |
694 | result << lhs->val() << '[' << idx->val() << "] = " << rhs->val(); |
695 | goto DO_STMT; |
696 | |
697 | case CEE_LDIND_I1: name = "I1" ; goto DO_LDIND; |
698 | case CEE_LDIND_I2: name = "I2" ; goto DO_LDIND; |
699 | case CEE_LDIND_I4: name = "I4" ; goto DO_LDIND; |
700 | case CEE_LDIND_I8: name = "I8" ; goto DO_LDIND; |
701 | case CEE_LDIND_I: name = "I" ; goto DO_LDIND; |
702 | case CEE_LDIND_R4: name = "R4" ; goto DO_LDIND; |
703 | case CEE_LDIND_R8: name = "R8" ; goto DO_LDIND; |
704 | case CEE_LDIND_U1: name = "U1" ; goto DO_LDIND; |
705 | case CEE_LDIND_U2: name = "U2" ; goto DO_LDIND; |
706 | case CEE_LDIND_REF: name = "REF" ;goto DO_LDIND; |
707 | DO_LDIND: |
708 | prec = 0x90; |
709 | lhs = pop(prec); |
710 | result << name << "(*" << lhs->val() << ')'; |
711 | goto DO_PUSH; |
712 | |
713 | case CEE_STIND_I1: name = "I1" ; goto DO_STIND; |
714 | case CEE_STIND_I2: name = "I2" ; goto DO_STIND; |
715 | case CEE_STIND_I4: name = "I4" ; goto DO_STIND; |
716 | case CEE_STIND_I8: name = "I8" ; goto DO_STIND; |
717 | case CEE_STIND_REF: name = "REF" ;goto DO_STIND; |
718 | case CEE_STIND_R4: name = "R4" ; goto DO_STIND; |
719 | case CEE_STIND_R8: name = "R8" ; goto DO_STIND; |
720 | DO_STIND: |
721 | rhs = pop(); |
722 | lhs = pop(0x90); |
723 | result << '*' << lhs->val() << " = " << name << '(' << rhs->val() << ')'; |
724 | goto DO_STMT; |
725 | |
726 | case CEE_LDVIRTFTN: |
727 | case CEE_ARGLIST: |
728 | case CEE_BREAK: |
729 | case CEE_ENDFILTER: |
730 | case CEE_CPBLK: |
731 | case CEE_INITBLK: |
732 | case CEE_LDOBJ: |
733 | case CEE_CPOBJ: |
734 | case CEE_STOBJ: |
735 | case CEE_INITOBJ: |
736 | case CEE_LOCALLOC: |
737 | case CEE_NOP: |
738 | case CEE_SWITCH: |
739 | case CEE_CASTCLASS: |
740 | case CEE_ISINST: |
741 | case CEE_LDLEN: |
742 | case CEE_JMP: |
743 | case CEE_NEWARR: |
744 | case CEE_THROW: |
745 | case CEE_RETHROW: |
746 | case CEE_LDELEM_U4: |
747 | case CEE_LDIND_U4: |
748 | case CEE_LDELEMA: |
749 | case CEE_ENDFINALLY: |
750 | case CEE_STIND_I: |
751 | case CEE_CKFINITE: |
752 | case CEE_MKREFANY: |
753 | case CEE_REFANYTYPE: |
754 | case CEE_REFANYVAL: |
755 | case CEE_CONV_I1: |
756 | case CEE_CONV_I2: |
757 | case CEE_CONV_I4: |
758 | case CEE_CONV_I8: |
759 | case CEE_CONV_R4: |
760 | case CEE_CONV_R8: |
761 | case CEE_CONV_R_UN: |
762 | case CEE_CONV_OVF_I_UN: |
763 | case CEE_CONV_OVF_I1_UN: |
764 | case CEE_CONV_OVF_I2_UN: |
765 | case CEE_CONV_OVF_I4_UN: |
766 | case CEE_CONV_OVF_I8_UN: |
767 | case CEE_CONV_OVF_U_UN: |
768 | case CEE_CONV_OVF_U1_UN: |
769 | case CEE_CONV_OVF_U2_UN: |
770 | case CEE_CONV_OVF_U4_UN: |
771 | case CEE_CONV_OVF_U8_UN: |
772 | case CEE_CONV_OVF_I1: |
773 | case CEE_CONV_OVF_I2: |
774 | case CEE_CONV_OVF_I4: |
775 | case CEE_CONV_OVF_I8: |
776 | case CEE_CONV_OVF_U1: |
777 | case CEE_CONV_OVF_U2: |
778 | case CEE_CONV_OVF_U4: |
779 | case CEE_CONV_OVF_U8: |
780 | case CEE_CONV_U4: |
781 | case CEE_CONV_U8: |
782 | case CEE_CONV_U2: |
783 | case CEE_CONV_U1: |
784 | case CEE_CONV_I: |
785 | case CEE_CONV_OVF_I: |
786 | case CEE_CONV_OVF_U: |
787 | case CEE_CONV_U: |
788 | case CEE_BOX: |
789 | case CEE_LDELEM: |
790 | case CEE_STELEM: |
791 | case CEE_UNBOX_ANY: |
792 | case CEE_UNBOX: |
793 | case CEE_LDFTN: |
794 | case CEE_LDTOKEN: |
795 | case CEE_SIZEOF: |
796 | default: |
797 | result << op.getName(); |
798 | if (op.getArgsInfo() != InlineNone) { |
799 | result << '<'; |
800 | formatInstrArgs(op, inlineArg, &result, instrPtr-start); |
801 | result << '>'; |
802 | } |
803 | |
804 | _ASSERTE(op.getNumPop() >= 0); |
805 | if (op.getNumPop() > 0) |
806 | formatArgs(op.getNumPop(), &result); |
807 | |
808 | prec = 0x1000; |
809 | _ASSERTE(op.getNumPush() == 0 || op.getNumPush() == 1); |
810 | if (op.getNumPush() > 0) |
811 | goto DO_PUSH; |
812 | goto DO_STMT; |
813 | } |
814 | } |
815 | return(instrPtr); |
816 | } |
817 | #ifdef _PREFAST_ |
818 | #pragma warning(pop) |
819 | #endif |
820 | |
821 | |
822 | |