自制反汇编逆向分析工具 迭代第四版本
上一个版本,本工具支持的第一个逆向策略,(对反汇编的函数体内的分支控制结构逆向生成cpp代码,)一直都可以正常工作,直到遇上了一个函数。这个使我的逆向策略算法失效的函数,主要的特点是它含有众多无条件跳转指令(,都是在函数体内的跳转)。
为什么无条件跳转指令会使得我的第一个逆向算法失效,因为这些无条件跳转指令让函数的执行流变得不易于线性理解。
在一个没有反汇编出来的函数汇编代码中,如果无条件跳转指令很少,特殊地连一条无条件跳转指令也没有时,将汇编代码的执行流当作行文阅读,总可以找到一个特例让所有条件跳转满足一种情况,使得行文可以从头到尾。中间的条件跳转就像,你愿意不愿意对跳转的区域行文阅读,但总的来说,情节还是单线顺序发展的。
但是反汇编出来的函数汇编代码中,包含了很多无条件跳转指令,代码的行文就会变得支离破碎。或者说有很多插叙或倒叙,你的行文阅读(某条主线或支线,执行流)并不要知道某些插叙或倒叙,这时就会有无条件跳转。你不得不去不停地翻书的页(,在函数汇编代码中跳来跳去)。插叙和倒叙,叙述了并行发展的情节(,不是并行执行的那个并行),而且不同的情节之间还会有关联(相交点),每个情节抽离出来都是一个故事支线。要完整呈现这个支线故事就不得不从其他支线故事中引用相关(双线交叉)的情节,就像内联一样。所有的顺叙,插叙或倒叙中的某段情节都将可能会内联到某一个支线故事当中去。
所以对于这种包含了很多无条件跳转指令的函数,我想到的是函数体使用了内联,还可能是宏的方式。比如定义了三个代码片段的宏A,B,C。B和C都使用了A。一个函数内多次是使用了这三个宏的话,编译器可能会将A抽出来,将A内联到的地方都无条件跳转到A的代码片段,A代码片段结束处又无条件跳转到另一处。因此我也使用同样的策略来处理这种逆向情况,将汇编代码进行内联。
下面这个包含多个jmp指令的函数CA::Layer::collect_animations__的反汇编代码:
QuartzCore`CA::Layer::collect_animations__: <+0>: pushq %rbp <+1>: movq %rsp, %rbp <+4>: pushq %r15 <+6>: pushq %r14 <+8>: pushq %r13 <+10>: pushq %r12 <+12>: pushq %rbx <+13>: subq $0x48, %rsp <+17>: movq %rsi, %rbx <+20>: movapd %xmm0, %xmm1 <+24>: movss 0x8(%rdx), %xmm0 <+29>: andps 0x3d8de(%rip), %xmm0 ; .memset_pattern + 560 <+36>: orps 0x3d8e7(%rip), %xmm0 ; .memset_pattern + 576 <+43>: cvtss2sd %xmm0, %xmm0 <+47>: movsd %xmm0, -0x48(%rbp) <+52>: movq 0x98(%rdi), %rax <+59>: movq %rax, -0x30(%rbp) <+63>: testq %rax, %rax <+66>: je 0x1041b20bf ; <+145> <+68>: leaq 0x4(%rdi), %rsi <+72>: leaq -0x30(%rbp), %rcx <+76>: movq %rcx, -0x40(%rbp) <+80>: xorl %r12d, %r12d <+83>: testl $0x1800000, 0x4(%rdi) <+90>: je 0x1041b20c6 ; <+152> <+92>: movq %rbx, -0x60(%rbp) <+96>: lock <+97>: andl $0xfe7fffff, (%rsi) <+103>: movq -0x30(%rbp), %rax <+107>: xorl %ecx, %ecx <+109>: testq %rax, %rax <+112>: je 0x1041b235a ; <+812> <+118>: movq %rsi, -0x68(%rbp) <+122>: movq %rdx, %r14 <+125>: xorl %ecx, %ecx <+127>: movq %rcx, -0x50(%rbp) <+131>: movsd %xmm1, -0x38(%rbp) <+136>: movq %rdi, -0x70(%rbp) <+140>: xorl %r12d, %r12d <+143>: jmp 0x1041b20e0 ; <+178> <+145>: xorl %eax, %eax <+147>: jmp 0x1041b24b8 ; <+1162> <+152>: movq %rsi, -0x68(%rbp) <+156>: movq %rdx, %r14 <+159>: xorl %ecx, %ecx <+161>: movq %rcx, -0x50(%rbp) <+165>: movsd %xmm1, -0x38(%rbp) <+170>: movq %rdi, -0x70(%rbp) <+174>: movq %rbx, -0x60(%rbp) <+178>: xorl %ecx, %ecx <+180>: movq %rcx, -0x58(%rbp) <+184>: movq %rax, %rbx <+187>: testb $0x2, 0x38(%rbx) <+191>: je 0x1041b22ee ; <+704> <+197>: movq 0x20(%rbx), %rdi <+201>: testq %rdi, %rdi <+204>: je 0x1041b22ee ; <+704> <+210>: movq 0x20(%rdi), %r15 <+214>: callq 0x104101b12 ; CA::Render::Timing::end_time() const <+219>: movq 0x20(%rbx), %rax <+223>: movl 0x8(%rax), %r13d <+227>: shrl $0x12, %r13d <+231>: andb $0x1, %r13b <+235>: movl 0x8(%rax), %ecx <+238>: shrl $0x11, %ecx <+241>: andb $0x1, %cl <+244>: movss 0x8(%r14), %xmm1 <+250>: xorpd %xmm2, %xmm2 <+254>: ucomiss %xmm1, %xmm2 <+257>: je 0x1041b21ef ; <+449> <+263>: movd %xmm0, %rax <+268>: ucomiss %xmm2, %xmm1 <+271>: jae 0x1041b2146 ; <+280> <+273>: movq %rax, %rdx <+276>: movb %cl, %al <+278>: jmp 0x1041b2152 ; <+292> <+280>: movq %r15, %rdx <+283>: movq %rax, %r15 <+286>: movb %r13b, %al <+289>: movb %cl, %r13b <+292>: movd %rdx, %xmm0 <+297>: ucomiss %xmm2, %xmm1 <+300>: jbe 0x1041b217b ; <+333> <+302>: movsd -0x38(%rbp), %xmm1 <+307>: ucomisd %xmm1, %xmm0 <+311>: ja 0x1041b220b ; <+477> <+317>: movd %r15, %xmm0 <+322>: ucomisd %xmm1, %xmm0 <+326>: jbe 0x1041b2199 ; <+363> <+328>: jmp 0x1041b221d ; <+495> <+333>: movsd -0x38(%rbp), %xmm1 <+338>: ucomisd %xmm1, %xmm0 <+342>: jb 0x1041b220b ; <+477> <+348>: movd %r15, %xmm0 <+353>: ucomisd %xmm1, %xmm0 <+357>: jb 0x1041b221d ; <+495> <+363>: movsd %xmm1, -0x38(%rbp) <+368>: movq 0x8(%rbx), %rdi <+372>: movl $0x2, %esi <+377>: movl $0xffffffff, %edx <+382>: callq 0x1041914ba ; CAAnimationSetFlags <+387>: movq %rbx, %rdi <+390>: callq 0x1041b159c ; schedule_stop_callback(CA::Layer::Animation*) <+395>: testb $0x1, 0x38(%rbx) <+399>: je 0x1041b224c ; <+542> <+405>: movq (%rbx), %rax <+408>: movq -0x40(%rbp), %rcx <+412>: movq %rax, (%rcx) <+415>: movq 0x6d574(%rip), %rax ; animation_state (.2) <+422>: movq %rax, (%rbx) <+425>: movq %rbx, 0x6d56a(%rip) ; animation_state (.2) <+432>: movq (%rcx), %rbx <+435>: testq %rbx, %rbx <+438>: jne 0x1041b20e9 ; <+187> <+444>: jmp 0x1041b2310 ; <+738> <+449>: movd %r15, %xmm1 <+454>: movsd -0x38(%rbp), %xmm2 <+459>: ucomisd %xmm2, %xmm1 <+463>: movapd %xmm2, %xmm1 <+467>: jbe 0x1041b2256 ; <+552> <+469>: movb %r13b, %al <+472>: jmp 0x1041b22b4 ; <+646> <+477>: movzwl 0x38(%rbx), %ecx <+481>: testw $0x220, %cx <+486>: je 0x1041b2262 ; <+564> <+488>: movsd %xmm1, -0x38(%rbp) <+493>: jmp 0x1041b2284 ; <+598> <+495>: movsd %xmm0, -0x40(%rbp) <+500>: movsd %xmm1, -0x38(%rbp) <+505>: movq %rbx, %rdi <+508>: callq 0x1041b24d0 ; schedule_start_callback(CA::Layer::Animation*) <+513>: testb $0x4, 0x39(%rbx) <+517>: jne 0x1041b2243 ; <+533> <+519>: movb $0x1, %al <+521>: cmpq $0x0, 0x30(%rbx) <+526>: movsd -0x48(%rbp), %xmm0 <+531>: je 0x1041b2284 ; <+598> <+533>: movb $0x1, %al <+535>: movsd -0x40(%rbp), %xmm0 <+540>: jmp 0x1041b2284 ; <+598> <+542>: movb %r13b, %al <+545>: movsd -0x48(%rbp), %xmm0 <+550>: jmp 0x1041b2284 ; <+598> <+552>: movb $0x1, %al <+554>: ucomisd %xmm1, %xmm0 <+558>: ja 0x1041b22b4 ; <+646> <+560>: movb %cl, %al <+562>: jmp 0x1041b22b4 ; <+646> <+564>: testb $0x4, %ch <+567>: jne 0x1041b226e ; <+576> <+569>: cmpq $0x0, 0x30(%rbx) <+574>: je 0x1041b227a ; <+588> <+576>: movsd %xmm1, -0x38(%rbp) <+581>: movd %r15, %xmm0 <+586>: jmp 0x1041b2284 ; <+598> <+588>: movsd %xmm1, -0x38(%rbp) <+593>: movsd -0x48(%rbp), %xmm0 <+598>: xorpd %xmm1, %xmm1 <+602>: ucomiss 0x8(%r14), %xmm1 <+607>: jae 0x1041b2299 ; <+619> <+609>: ucomisd -0x48(%rbp), %xmm0 <+614>: setb %cl <+617>: jmp 0x1041b22a1 ; <+627> <+619>: ucomisd -0x48(%rbp), %xmm0 <+624>: seta %cl <+627>: movsd -0x38(%rbp), %xmm1 <+632>: testb %cl, %cl <+634>: jne 0x1041b22af ; <+641> <+636>: movsd -0x48(%rbp), %xmm0 <+641>: movsd %xmm0, -0x48(%rbp) <+646>: testb %al, %al <+648>: je 0x1041b22e9 ; <+699> <+650>: movzwl 0x38(%rbx), %eax <+654>: movl %eax, %ecx <+656>: andl $0x20, %ecx <+659>: testw %cx, %cx <+662>: je 0x1041b22e9 ; <+699> <+664>: movl %eax, %ecx <+666>: andl $0x80, %ecx <+672>: testw %cx, %cx <+675>: je 0x1041b22d9 ; <+683> <+677>: movb $0x1, %cl <+679>: movq %rcx, -0x50(%rbp) <+683>: andl $0x100, %eax <+688>: testw %ax, %ax <+691>: je 0x1041b22e9 ; <+699> <+693>: movb $0x1, %al <+695>: movq %rax, -0x58(%rbp) <+699>: movsd %xmm1, -0x38(%rbp) <+704>: leaq 0x10(%rbx), %rdi <+708>: xorl %esi, %esi <+710>: callq 0x1040e0598 ; CA::Render::key_path_atom(void* const*, unsigned long) <+715>: cmpl $0x63, %eax <+718>: cmoveq %rbx, %r12 <+722>: movq (%rbx), %rax <+725>: testq %rax, %rax <+728>: movq %rbx, -0x40(%rbp) <+732>: jne 0x1041b20e6 ; <+184> <+738>: movq -0x68(%rbp), %rsi <+742>: movl (%rsi), %ebx <+744>: movq -0x50(%rbp), %rax <+748>: testb $0x1, %al <+750>: movl $0x0, %ecx <+755>: je 0x1041b232f ; <+769> <+757>: lock <+758>: orl $0x1000000, (%rsi) <+764>: movl $0x1000, %ecx <+769>: movl %ebx, %eax <+771>: andl $0x3000, %eax <+776>: movq -0x58(%rbp), %rdx <+780>: testb $0x1, %dl <+783>: je 0x1041b234c ; <+798> <+785>: orl $0x2000, %ecx <+791>: lock <+792>: orl $0x800000, (%rsi) <+798>: movq -0x70(%rbp), %rdi <+802>: movsd -0x38(%rbp), %xmm1 <+807>: movq %r14, %rdx <+810>: jmp 0x1041b2366 ; <+824> <+812>: movl (%rsi), %ebx <+814>: movl %ebx, %eax <+816>: andl $0x3000, %eax <+821>: xorl %r12d, %r12d <+824>: cmpl %eax, %ecx <+826>: jne 0x1041b238f ; <+865> <+828>: testl %eax, %eax <+830>: je 0x1041b24a9 ; <+1147> <+836>: xorpd %xmm0, %xmm0 <+840>: ucomiss 0x8(%rdx), %xmm0 <+844>: jne 0x1041b2386 ; <+856> <+846>: cmpl $0x0, 0xc(%rdx) <+850>: je 0x1041b24a9 ; <+1147> <+856>: movq %r12, %r13 <+859>: movq 0x10(%rdi), %r14 <+863>: jmp 0x1041b23b2 ; <+900> <+865>: movq %r12, %r13 <+868>: movq 0x10(%rdi), %r14 <+872>: movl %ebx, %eax <+874>: orl $0xffffcfff, %eax <+879>: xorl $0x3000, %eax <+884>: movq %rcx, %rdx <+887>: andl %eax, %ecx <+889>: lock <+890>: orl %ecx, (%rsi) <+892>: movq %rdx, %rcx <+895>: orl %ecx, %eax <+897>: lock <+898>: andl %eax, (%rsi) <+900>: movq %rdi, %r15 <+903>: testl %ecx, %ecx <+905>: je 0x1041b245c ; <+1070> <+911>: movq %rcx, %r12 <+914>: movsd %xmm1, -0x38(%rbp) <+919>: movq 0x68964(%rip), %rsi ; "_scheduleAnimationTimer" <+926>: movq %r14, %rdi <+929>: callq *0x6de63(%rip) ; (void *)0x000000010357d800: objc_msgSend <+935>: testb %al, %al <+937>: movq -0x60(%rbp), %rbx <+941>: movq %r15, %rdi <+944>: je 0x1041b24ad ; <+1151> <+950>: movq %r12, %rax <+953>: testb $0x10, %ah <+956>: je 0x1041b2408 ; <+986> <+958>: movq 0x68855(%rip), %rsi ; "setNeedsLayout" <+965>: movq %rdi, %r15 <+968>: movq %r14, %rdi <+971>: movq %rax, %r12 <+974>: callq *0x6de36(%rip) ; (void *)0x000000010357d800: objc_msgSend <+980>: movq %r12, %rax <+983>: movq %r15, %rdi <+986>: testb $0x20, %ah <+989>: je 0x1041b2450 ; <+1058> <+991>: movq %rdi, %r15 <+994>: testq %r13, %r13 <+997>: je 0x1041b2436 ; <+1032> <+999>: movq 0x6809c(%rip), %rdx ; "removeAnimationForKey:" <+1006>: movq 0x68915(%rip), %rsi ; "performSelectorOnMainThread:withObject:waitUntilDone:" <+1013>: leaq 0x7a106(%rip), %rcx ; @"contents" <+1020>: xorl %r8d, %r8d <+1023>: movq %r14, %rdi <+1026>: callq *0x6de02(%rip) ; (void *)0x000000010357d800: objc_msgSend <+1032>: movq 0x68823(%rip), %rsi ; "setNeedsDisplay" <+1039>: movq %r14, %rdi <+1042>: callq *0x6ddf2(%rip) ; (void *)0x000000010357d800: objc_msgSend <+1048>: movq %r15, %rdi <+1051>: orb $0x20, 0x85(%rdi) <+1058>: movsd -0x38(%rbp), %xmm0 <+1063>: movsd %xmm0, -0x48(%rbp) <+1068>: jmp 0x1041b24ad ; <+1151> <+1070>: movq 0x688dd(%rip), %rsi ; "_cancelAnimationTimer" <+1077>: movq %r14, %rdi <+1080>: callq *0x6ddcc(%rip) ; (void *)0x000000010357d800: objc_msgSend <+1086>: testb $0x10, %bh <+1089>: je 0x1041b2481 ; <+1107> <+1091>: movq 0x687d0(%rip), %rsi ; "setNeedsLayout" <+1098>: movq %r14, %rdi <+1101>: callq *0x6ddb7(%rip) ; (void *)0x000000010357d800: objc_msgSend <+1107>: testb $0x20, %bh <+1110>: jne 0x1041b248f ; <+1121> <+1112>: movq -0x60(%rbp), %rbx <+1116>: movq %r15, %rdi <+1119>: jmp 0x1041b24ad ; <+1151> <+1121>: movq 0x687ca(%rip), %rsi ; "setNeedsDisplay" <+1128>: movq %r14, %rdi <+1131>: callq *0x6dd99(%rip) ; (void *)0x000000010357d800: objc_msgSend <+1137>: movq %r15, %rdi <+1140>: orb $0x20, 0x85(%rdi) <+1147>: movq -0x60(%rbp), %rbx <+1151>: movq -0x30(%rbp), %rsi <+1155>: callq 0x1041b0e50 ; CA::Layer::set_animations(CA::Layer::Animation*) <+1160>: movb $0x1, %al <+1162>: movsd -0x48(%rbp), %xmm0 <+1167>: movsd %xmm0, (%rbx) <+1171>: addq $0x48, %rsp <+1175>: popq %rbx <+1176>: popq %r12 <+1178>: popq %r13 <+1180>: popq %r14 <+1182>: popq %r15 <+1184>: popq %rbp <+1185>: retq
下面是跳转的形态图:
这个函数一共有17个jmp指令,我将其划分成17个jmp block孤岛,分支跳转指令在这17座孤岛中穿插。下面我借用UML对象图的符号来描述,符号的作用被重定义为:
~(package),入口地址。
+(public),外出跳转。
#(protected),往回走(backwards)的外出跳转。
-(private),jmp block内跳转,没有离开jmp block的跳转。
=(初始值),表示跳转的目的偏移位置。
->(direct-link),有向线表示jmp blocks之间的跳转,蓝色代表跳转到另一个jmp block的入口,黑色代表跳转到另一个jmp block的体内。
对象符号表示一个jmp block孤岛,绿色代表按某种策略选定为主线成员,不宜作为inline候选。
下面是反映这个函数分支连接的图:
可以看出(黑色)非主线成员的孤岛可以被内联到(绿色)主线成员孤岛的分支中,然后回到主线上。但是并没有一条线路可以满足将17个孤岛连成线的。
下面是对第#4号JmpBlock进行内联后逆向分支输出:
#6号JmpBlock被内联到#4号在offset 342处的分支内,#11内联到了#6号内联块的结尾offset 493,并且#11号内联片段是从体内截取出来,而不是#11号内联从头开始的整个代码块。
477到493,598到617的片段被内联到了offset 342的分支内,分支外继续#4号JmpBlock的执行流。这样就减少了,逆向代码中凌乱的跳转,而且将跳转的单位上升到JmpBlock的粒度,并且是non-inline的JmpBlock。虽然没有减少goto的数量,但是大大减少了goto目的选择的可能性,而且内联减少了很多中间的跳转,使跳转更加直接,容易归纳分析。
另外在每个JmpBlock的开头输出的注释,提供了有力的跟踪分析的信息。例如内联块的指令数目,可以看出#6和#11都是只有几条指令的小内联块。还有内联块的入边和出边分别关联到哪些其它块的可能,也还是从何处来往何处走,#11内联的注释表示这个块将内联到多处,但结果都将走向#12号JmpBlock。
世上没有通杀的银子弹,和包治百病的药,具体问题还要具体分析,所以针对像这样包含了很无条件跳转指令的函数的逆向分析,我使用了另一个逆向策略-内联。其实,这只策略在本文中分析的目标函数,也并不完全适用,因为在后面4个JmpBlock中它们的关联并非内联,而更多是二路分支if-else。
总算是多了一个帮助分析的选择。
最后贴上部分输出结果:
/*** * Summary: * total JmpBlock(s): 17 * noninline block(s): #0, #2, #4, #7, #10, #12, #13, #14, #15, #16 * inline block(s): #1, #3, #5, #6, #8, #9, #11 */ /*** * #0<<JmpBlock>> * 0 to 143 * instrs: 40 * inners: 0 * */ _f0: // 66 if () { /*** * #1<<Inline JmpBlock>> * 145(145) to 147 * instrs: 2 * incomings: 1 ; #0 * outgoings: 1 ; #16 * depth: 1 * */ // 145 // 147 goto _f1162; // to #16 // end of inline #1 } // 90 if () { goto _f152; // to #2, BoJ } // 112 if () { goto _f812; // to #13, BoJ } // 143 goto _f178; // to #2 // end of non-inline #0 /*** * #2<<JmpBlock>> * 152 to 278 * instrs: 34 * inners: 0 * */ _f152: _f152: // from #0(90) _f178: // from #0(143, EoJ) _b184: // from #12(732) _b187: // from #4(438) // 191 if () { goto _f704; // to #12 } // 204 if () { goto _f704; // to #12 } // 257 if () { /*** * #5<<Inline JmpBlock>> * 449(449) to 472 * instrs: 7 * incomings: 1 ; #2 * outgoings: 2 ; #9, #12 * depth: 1 * */ // 449 // 467 if () { /*** * #9<<Inline JmpBlock>> * 552(552) to 562 * instrs: 5 * incomings: 1 ; #5 * outgoings: 2 ; #12 * depth: 2 * */ // 552 // 558 if () { goto _f646; // to #12 } // 562 goto _f646; // to #12 // end of inline #9 } // 472 goto _f646; // to #12 // end of inline #5 } // 271 if () { /*** * #3<<Inline JmpBlock>> * 280(280) to 328 * instrs: 14 * incomings: 2 ; #2 * outgoings: 4 ; #4, #6, #7 * depth: 1 * */ // 280 // 300 if () { goto _f333; // to #4, BoJ } // 311 if () { /*** * #6<<Inline JmpBlock>> * 477(477) to 493 * instrs: 5 * incomings: 2 ; #3, #4 * outgoings: 2 ; #10, #11 * depth: 2 * */ // 477 // 486 if () { goto _f564; // to #10, BoJ } // 493 /*** * #11<<Inline JmpBlock>> * 588(598) to 617 * instrs: 8 * incomings: 6 ; #6, #7, #8, #10 * outgoings: 2 ; #12 * depth: 3 * concast #6 to #11 * */ // 598 // 607 if () { goto _f619; // to #12, BoJ } // 617 goto _f627; // to #12 // end of inline #11 // end of inline #6 } // 326 if () { goto _f363; // to #4 } // 328 goto _f495; // to #7, BoJ // end of inline #3 } // 278 /*** * #3<<Inline JmpBlock>> * 280(292) to 328 * instrs: 14 * incomings: 2 ; #2 * outgoings: 4 ; #4, #6, #7 * depth: 1 * concast #2 to #3 * */ // 292 // 300 if () { goto _f333; // to #4, BoJ } // 311 if () { /*** * #6<<Inline JmpBlock>> * 477(477) to 493 * instrs: 5 * incomings: 2 ; #3, #4 * outgoings: 2 ; #10, #11 * depth: 2 * */ // 477 // 486 if () { goto _f564; // to #10, BoJ } // 493 /*** * #11<<Inline JmpBlock>> * 588(598) to 617 * instrs: 8 * incomings: 6 ; #6, #7, #8, #10 * outgoings: 2 ; #12 * depth: 3 * concast #6 to #11 * */ // 598 // 607 if () { goto _f619; // to #12, BoJ } // 617 goto _f627; // to #12 // end of inline #11 // end of inline #6 } // 326 if () { goto _f363; // to #4 } // 328 goto _f495; // to #7, BoJ // end of inline #3 // end of non-inline #2 /*** * #4<<JmpBlock>> * 333 to 444 * instrs: 25 * inners: 0 * */ _f333: _f333: // from #3(300, inline) // 342 if () { /*** * #6<<Inline JmpBlock>> * 477(477) to 493 * instrs: 5 * incomings: 2 ; #3, #4 * outgoings: 2 ; #10, #11 * depth: 1 * */ // 477 // 486 if () {et goto _f564; // to #10, BoJ } // 493 /*** * #11<<Inline JmpBlock>> * 588(598) to 617 * instrs: 8 * incomings: 6 ; #6, #7, #8, #10 * outgoings: 2 ; #12 * depth: 2 * concast #6 to #11 * */ // 598 // 607 if () { goto _f619; // to #12, BoJ } // 617 goto _f627; // to #12 // end of inline #11 // end of inline #6 } // 357 if () { goto _f495; // to #7, BoJ } _f363: // from #3(326, inline) // 399 if () { /*** * #8<<Inline JmpBlock>> * 542(542) to 550 * instrs: 3 * incomings: 1 ; #4 * outgoings: 1 ; #11 * depth: 1 * */ // 542 // 550 /*** * #11<<Inline JmpBlock>> * 588(598) to 617 * instrs: 8 * incomings: 6 ; #6, #7, #8, #10 * outgoings: 2 ; #12 * depth: 2 * concast #8 to #11 * */ // 598 // 607 if () { goto _f619; // to #12, BoJ } // 617 goto _f627; // to #12 // end of inline #11 // end of inline #8 } // 438 if () { goto _b187; // to #2 } // 444 goto _f738; // to #12 // end of non-inline #4 /*** * #7<<JmpBlock>> * 495 to 540 * instrs: 13 * inners: 1 * */ _f495: _f495: // from #3(328, inline, EoJ) _f495: // from #4(357) // 531 if () { /*** * #11<<Inline JmpBlock>> * 588(598) to 617 * instrs: 8 * incomings: 6 ; #6, #7, #8, #10 * outgoings: 2 ; #12 * depth: 1 * */ // 598 // 607 if () { goto _f619; // to #12, BoJ } // 617 goto _f627; // to #12 // end of inline #11 } // 540 /*** * #11<<Inline JmpBlock>> * 588(598) to 617 * instrs: 8 * incomings: 6 ; #6, #7, #8, #10 * outgoings: 2 ; #12 * depth: 1 * concast #7 to #11 * */ // 598 // 607 if () { goto _f619; // to #12, BoJ } // 617 goto _f627; // to #12 // end of inline #11 // end of non-inline #7 /*** * #10<<JmpBlock>> * 564 to 586 * instrs: 7 * inners: 1 * */ _f564: _f564: // from #6(486, inline) // 574 if () { /*** * #11<<Inline JmpBlock>> * 588(588) to 617 * instrs: 8 * incomings: 6 ; #6, #7, #8, #10 * outgoings: 2 ; #12 * depth: 1 * */ // 588 // 607 if () { goto _f619; // to #12, BoJ } // 617 goto _f627; // to #12 // end of inline #11 } // 586 /*** * #11<<Inline JmpBlock>> * 588(598) to 617 * instrs: 8 * incomings: 6 ; #6, #7, #8, #10 * outgoings: 2 ; #12 * depth: 1 * concast #10 to #11 * */ // 598 // 607 if () { goto _f619; // to #12, BoJ } // 617 goto _f627; // to #12 // end of inline #11 // end of non-inline #10 /*** * #12<<JmpBlock>> * 619 to 810 * instrs: 56 * inners: 7 * */ _f619: _f619: // from #11(607, inline) _f627: // from #11(617, inline, EoJ) _f646: // from #5(472, inline, EoJ) _f646: // from #9(558, inline) _f646: // from #9(562, inline, EoJ) _f704: // from #2(191) _f704: // from #2(204) // 732 if () { goto _b184; // to #2 } _f738: // from #4(444, EoJ) // 810 goto _f824; // to #13 // end of non-inline #12 /*** * #13<<JmpBlock>> * 812 to 863 * instrs: 16 * inners: 1 * */ _f812: _f812: // from #0(112) _f824: // from #12(810, EoJ) // 826 if () { goto _f865; // to #14, BoJ } // 830 if () { goto _f1147; // to #16 } // 850 if () { goto _f1147; // to #16 } // 863 goto _f900; // to #14 // end of non-inline #13 /*** * #14<<JmpBlock>> * 865 to 1068 * instrs: 54 * inners: 3 * */ _f865: _f865: // from #13(826) _f900: // from #13(863, EoJ) // 905 if () { goto _f1070; // to #15, BoJ } // 944 if () { goto _f1151; // to #16 } // 1068 goto _f1151; // to #16 // end of non-inline #14 /*** * #15<<JmpBlock>> * 1070 to 1119 * instrs: 13 * inners: 1 * */ _f1070: _f1070: // from #14(905) // 1110 if () { goto _f1121; // to #16, BoJ } // 1119 goto _f1151; // to #16 // end of non-inline #15 /*** * #16<<JmpBlock>> * 1121 to 1185 * instrs: 19 * inners: 0 * */ _f1121: // 1185 return; // end of non-inline #16