📄 code-analyse.c
字号:
STACKOUT(1, TVOID); break; case 'F': STACKOUT(0, TFLOAT); break; case 'D': STACKOUT(0, TDOUBLE); STACKOUT(1, TVOID); break; case 'V': default: break; } INCPC(5); break; case INVOKESTATIC: if (getMethodSignatureClass(WORD(pc+1), meth->class, true, false, &call, einfo) == false) { if (!checkNoClassDefFoundError(einfo) || call.signature == 0) { goto done_fail; } } if (METHOD_TRANSLATED(meth)) goto done_fail; sig = call.signature->data; assert(sig[0] == '('); sig++; idx = call.in - 1; while (sig[0] != ')') { switch (sig[0]) { case '[': STACKIN(idx, TOBJ); idx -= 1; while (sig[0] == '[') { sig++; } if (sig[0] == 'L') { while (sig[0] != ';') { sig++; } } sig++; break; case 'L': STACKIN(idx, TOBJ); idx -= 1; while (sig[0] != ';') { sig++; } sig++; break; case 'I': case 'Z': case 'S': case 'B': case 'C': STACKIN(idx, TINT); idx -= 1; sig++; break; case 'J': STACKIN(idx-1, TLONG); STACKIN(idx, TVOID); idx -= 2; sig++; break; case 'F': STACKIN(idx, TFLOAT); idx -= 1; sig++; break; case 'D': STACKIN(idx-1, TDOUBLE); STACKIN(idx, TVOID); idx -= 2; sig++; break; default: assert("Signature character unknown" == 0); } } STKPOP(call.in); STKPUSH(call.out); switch (call.rettype) { case '[': case 'L': STACKOUT(0, TOBJ); break; case 'I': case 'Z': case 'S': case 'B': case 'C': STACKOUT(0, TINT); break; case 'J': STACKOUT(0, TLONG); STACKOUT(1, TVOID); break; case 'F': STACKOUT(0, TFLOAT); break; case 'D': STACKOUT(0, TDOUBLE); STACKOUT(1, TVOID); break; case 'V': default: break; } INCPC(3); break; case NEW: if (getClass(WORD(pc+1), meth->class, einfo) == 0) { if (!checkNoClassDefFoundError(einfo)) { goto done_fail; } } if (METHOD_TRANSLATED(meth)) goto done_fail; STKPUSH(1); STACKOUT(0, TOBJ); INCPC(3); break; case NEWARRAY: STACKIN(0, TINT); STACKOUT(0, TOBJ); INCPC(2); break; case ANEWARRAY: if (getClass(WORD(pc+1), meth->class, einfo) == 0) { if (!checkNoClassDefFoundError(einfo)) { goto done_fail; } } if (METHOD_TRANSLATED(meth)) goto done_fail; STACKIN(0, TINT); STACKOUT(0, TOBJ); INCPC(3); break; case MULTIANEWARRAY: if (getClass(WORD(pc+1), meth->class, einfo) == 0) { if (!checkNoClassDefFoundError(einfo)) { goto done_fail; } } if (METHOD_TRANSLATED(meth)) goto done_fail; for (idx = INSN(pc+3) - 1; idx >= 0; idx--) { STACKIN(idx, TINT); } STKPOP(INSN(pc+3) - 1); STACKOUT(0, TOBJ); INCPC(4); break; case ARRAYLENGTH: STACKIN(0, TOBJ); STACKOUT(0, TINT); INCPC(1); break; case ATHROW: STACKIN(0, TOBJ); STKPOP(1); INCPC(1); break; case CHECKCAST: if (getClass(WORD(pc+1), meth->class, einfo) == 0) { if (!checkNoClassDefFoundError(einfo)) { goto done_fail; } } if (METHOD_TRANSLATED(meth)) goto done_fail; STACKIN(0, TOBJ); STACKOUT(0, TOBJ); INCPC(3); break; case INSTANCEOF: if (getClass(WORD(pc+1), meth->class, einfo) == 0) { if (!checkNoClassDefFoundError(einfo)) { } } if (METHOD_TRANSLATED(meth)) goto done_fail; STACKIN(0, TOBJ); STACKOUT(0, TINT); INCPC(3); break; case MONITORENTER: case MONITOREXIT: STACKIN(0, TOBJ); STKPOP(1); INCPC(1); break; case IFNULL: case IFNONNULL: STACKIN(0, TOBJ); STKPOP(1); FRAMEMERGE(pc + WORD(pc+1), sp); FRAMEMERGE(pc + 3, sp); INCPC(3); break; case WIDE: wide = true; INCPC(1); break; case BREAKPOINT: INCPC(1); break; default: postExceptionMessage(einfo, JAVA_LANG(VerifyError), "(class: %s, method: %s signature: %s) " "invalid opcode", meth->class->name->data, meth->name->data, meth->parsed_sig->signature->data); goto done_fail; } } while (pc < meth->c.bcode.codelen && !IS_STARTOFBASICBLOCK(pc) && !IS_STARTOFEXCEPTION(pc)); /* If we flow into the next basic block, set the stack pointer * and merge in the frame. */ if (!failed && pc < meth->c.bcode.codelen && IS_NORMALFLOW(pc)) { assert(IS_STARTOFBASICBLOCK(pc) || IS_STARTOFEXCEPTION(pc)); FRAMEMERGE(pc, sp); } if (firsttime) { updateLocals(codeInfo, opc, activeFrame); }done: /* Discard active frame */ KFREE(activeFrame); return (failed);done_fail: failed = true; goto done;}boolanalyzeMethod(Method* meth, codeinfo **pcodeinfo, errorInfo *einfo){ uint32 pc; int32 tabpc; int32 idx; int32 sp; int32 lcl; int count; perPCInfo* bhead; perPCInfo* btail; perPCInfo* bcurr; bool rerun; bool failed; bool wide; codeinfo *codeInfo; localUse* localuse;DBG(CODEANALYSE, dprintf("%s %p: %s.%s\n", __FUNCTION__, THREAD_NATIVE(), meth->class->name->data, meth->name->data); ); if( meth->c.bcode.code == 0 ) { postExceptionMessage(einfo, JAVA_LANG(VerifyError), "No code attribute for %s.%s.", meth->class->name->data, meth->name->data); return false; } codeInfo = gc_malloc(sizeof(codeinfo) + meth->c.bcode.codelen*sizeof(perPCInfo), KGC_ALLOC_CODEANALYSE); *pcodeinfo = codeInfo; if (!codeInfo) { postOutOfMemory(einfo); return false; } /* Allocate space for local register info - we add in an extra one * to avoid mallocing 0 bytes. */ localuse = gc_malloc(sizeof(localUse) * (meth->localsz+1), KGC_ALLOC_CODEANALYSE); if (!localuse) { KFREE(codeInfo); postOutOfMemory(einfo); return false; } codeInfo->localuse = localuse; /* We don't need to do this twice */ meth->kFlags |= KFLAG_VERIFIED; for (lcl = 0; lcl < meth->localsz; lcl++) { localuse = codeInfo->localuse; localuse[lcl].use = 0; localuse[lcl].first = 0x7FFFFFFF; localuse[lcl].last = -1; localuse[lcl].write = -1; localuse[lcl].type = NULL; }DBG(CODEANALYSE, dprintf("%s %p: codeInfo = %p\n", __FUNCTION__, THREAD_NATIVE(), codeInfo); ); /* Allocate code info. block */ codeInfo->localsz = meth->localsz; codeInfo->stacksz = meth->stacksz; codeInfo->codelen = meth->c.bcode.codelen; /* First basic block becomes head of block chain */ SET_NEEDVERIFY(0); bhead = &codeInfo->perPC[0]; btail = bhead; /* Scan the code and mark the beginning of basic blocks */ wide = false; for (pc = 0; pc < codeInfo->codelen;) { SET_STARTOFINSTRUCTION(pc); /* set native pc to -1 so that we can recognize whether * a corresponding native PC will be generated. */ SET_INSNPC(pc, -1); switch (INSN(pc)) { case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE: case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE: case IF_ACMPEQ: case IF_ACMPNE: case IFNULL: case IFNONNULL: tabpc = pc + WORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); SET_STARTOFBASICBLOCK(pc); SET_NORMALFLOW(pc); break; case GOTO: tabpc = pc + WORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case GOTO_W: tabpc = pc + DWORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case JSR: tabpc = pc + WORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); SET_STARTOFBASICBLOCK(pc); SET_NORMALFLOW(pc); break; case JSR_W: tabpc = pc + DWORD(pc+1); SET_STARTOFBASICBLOCK(tabpc); SET_JUMPFLOW(pc, tabpc); pc = pc + INSNLEN(pc); SET_STARTOFBASICBLOCK(pc); SET_NORMALFLOW(pc); break; case TABLESWITCH: tabpc = (pc + 4) & -4; idx = DWORD(tabpc+8)-DWORD(tabpc+4)+1; for (; idx > 0; idx--) { SET_STARTOFBASICBLOCK(pc+DWORD(tabpc+idx*4+8)); SET_JUMPFLOW(pc, pc+DWORD(tabpc+idx*4+8)); } SET_STARTOFBASICBLOCK(pc+DWORD(tabpc)); SET_JUMPFLOW(pc, pc+DWORD(tabpc)); pc = tabpc + (DWORD(tabpc+8)-DWORD(tabpc+4)+1+3) * 4; if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case LOOKUPSWITCH: tabpc = (pc + 4) & -4; idx = DWORD(tabpc+4); for (; idx > 0; idx--) { SET_STARTOFBASICBLOCK(pc+DWORD(tabpc+idx*8+4)); SET_JUMPFLOW(pc, pc+DWORD(tabpc+idx*8+4)); } SET_STARTOFBASICBLOCK(pc+DWORD(tabpc)); SET_JUMPFLOW(pc, pc+DWORD(tabpc)); pc = tabpc + (DWORD(tabpc+4)+1) * 8; if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case IRETURN: case LRETURN: case ARETURN: case FRETURN: case DRETURN: case RETURN: case ATHROW: case RET: pc = pc + INSNLEN(pc); if (pc < codeInfo->codelen) { SET_STARTOFBASICBLOCK(pc); } break; case WIDE: wide = true; pc = pc + INSNLEN(pc); SET_NORMALFLOW(pc); break; case ILOAD: case LLOAD: case FLOAD: case DLOAD: case ALOAD: case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: pc = pc + INSNLEN(pc); if (wide == true) { wide = false; pc += 1; } SET_NORMALFLOW(pc); break; case IINC: pc = pc + INSNLEN(pc); if (wide == true) { wide = false; pc += 2; } SET_NORMALFLOW(pc); break; default: /* The default */ pc = pc + INSNLEN(pc); SET_NORMALFLOW(pc); break; } } /* Setup exception info. */ sp = meth->localsz + meth->stacksz - 1; if (meth->exception_table != 0) { for (lcl = 0; lcl < (int32)meth->exception_table->length; lcl++) { bool succ; jexceptionEntry *entry; entry = &(meth->exception_table->entry[lcl]); /* Verify catch clause exception has valid type. */ succ = analyzeCatchClause(entry, meth->class, einfo); if (succ == false) { return false; } pc = entry->handler_pc; ATTACH_NEW_BASICBLOCK(pc); SET_STARTOFEXCEPTION(pc); SET_STACKPOINTER(pc, sp); SET_NEWFRAME(pc); STACKINIT(0, TOBJ); } } /* Mark the various starting states. These include the main * entry point plus all the exception entry points, their arguments * and stack values. */ pc = 0; SET_STACKPOINTER(pc, meth->localsz + meth->stacksz); SET_NEWFRAME(pc); /* Parse the method signature to setup the inital locals */ idx = 0; if ((meth->accflags & ACC_STATIC) == 0) { LOCALINIT(0, TOBJ); idx++; } for (count = 0; count < METHOD_NARGS(meth); ++count) { switch (*METHOD_ARG_TYPE(meth, count)) { case 'L': case '[': LOCALINIT(idx, TOBJ); idx += 1; break; case 'I': case 'Z': case 'S': case 'B': case 'C': LOCALINIT(idx, TINT); idx += 1; break; case 'J': LOCALINIT(idx, TLONG); LOCALINIT(idx+1, TVOID); idx += 2; break; case 'F': LOCALINIT(idx, TFLOAT); idx += 1; break; case 'D': LOCALINIT(idx, TDOUBLE); LOCALINIT(idx+1, TVOID); idx += 2; break; default: assert("Signature character unknown" == 0); } } /* Scan out list of basic blocks. Unfortunately they're not in * precise order so we have to do this until they're all done. */ do { rerun = false; for (bcurr = bhead; bcurr != NULL; bcurr = bcurr->nextBB) { pc = bcurr - codeInfo->perPC; if (IS_NEEDVERIFY(pc)) { failed = analyzeBasicBlock(codeInfo, meth, pc, einfo); if (failed) { tidyAnalyzeMethod(pcodeinfo); return (false); } rerun = true; } } } while (rerun == true); /* Check we've processed each block at least once */ /* Note that it is perfectly legal for code to contain unreachable * basic blocks; There's no need to complain. */#if VDBG(1) - 1 == 0 for (bcurr = bhead; bcurr != NULL; bcurr = bcurr->nextBB) { if ((bcurr->flags & FLAG_DONEVERIFY) == 0) { VDBG(dprintf("%s.%s%s pc %d bcurr->flags 0x%04x\n", meth->class->name->data, meth->name->data, METHOD_SIGD(meth), bcurr - codeInfo->perPC, bcurr->flags);) } }#endif return (true);}/* * Merge the current frame into the beginning of a basic block. */staticvoidmergeFrame(codeinfo* codeInfo, int pc, int sp, frameElement* from, Method* meth){ int m; frameElement* to; to = FRAME(pc); assert(to != 0); /* Merge locals */ for (m = 0; m < meth->localsz; m++) { if (from[m].type != TUNASSIGNED && from[m].type != to[m].type && to[m].type != TUNSTABLE) { SET_NEEDVERIFY(pc); if (to[m].type == TUNASSIGNED) { to[m].type = from[m].type; } else { to[m].type = TUNSTABLE; } } } /* Merge stacks */ for (m = sp; m < meth->localsz + meth->stacksz; m++) { if (from[m].type != TUNASSIGNED && from[m].type != to[m].type && to[m].type != TUNSTABLE) { SET_NEEDVERIFY(pc); if (to[m].type == TUNASSIGNED) { to[m].type = from[m].type; } else { to[m].type = TUNSTABLE; } } }}/* * Tidy up after verfication data has been finished with. */voidtidyAnalyzeMethod(codeinfo** codeInfo){ int pc; /* Free the old data */ if (!*codeInfo) { return; } for (pc = 0; pc < (*codeInfo)->codelen; pc++) { if ((*codeInfo)->perPC[pc].frame != 0) { KFREE((*codeInfo)->perPC[pc].frame); } } KFREE((*codeInfo)->localuse); KFREE(*codeInfo); *codeInfo = NULL;DBG(CODEANALYSE, dprintf("%s %p: clearing codeInfo %p\n",__FUNCTION__, THREAD_NATIVE(), codeInfo); );}staticvoidupdateLocals(codeinfo* codeInfo, int32 pc, frameElement* frame){ int i; localUse* l; for (i = 0; i < codeInfo->localsz; i++) { if (frame[i].used == 0) { continue; } l = &codeInfo->localuse[i]; if (pc < l->first) { l->first = pc; } if (pc > l->last) { l->last = pc; } if (frame[i].modified != 0 && pc > l->write) { l->write = pc; } l->use++; if (l->type == TUNASSIGNED) { l->type = frame[i].type; } else if (frame[i].type == TUNASSIGNED || l->type == frame[i].type) { /* Do nothing */ } else { l->type = TUNSTABLE; } }}/* * Verification requires us to resolve the catch type and check that * its actually a Throwable. But, we also do it to ensure that the * classes are ready when we need them and have little room to work * (e.g. a stack overflow). */static boolanalyzeCatchClause(jexceptionEntry* eptr, Hjava_lang_Class* class, errorInfo *einfo){ if( eptr->catch_idx == 0 ) { /* A finally clause... */ } else { eptr->catch_type = getClass(eptr->catch_idx, class, einfo); /* * If we could not resolve the catch class, then we * must record that fact to guard against possible * recursive attempts to load it. Throw whatever * error getClass() generated. */ if (eptr->catch_type == NULL) { eptr->catch_type = UNRESOLVABLE_CATCHTYPE; /* Pass on einfo generated by getClass() */ return false; } /* * Make sure the exception is a subclass of Throwable. */ if( !instanceof(javaLangThrowable, eptr->catch_type) ) { postException(einfo, JAVA_LANG(VerifyError)); return false; } } /* Catch clause is okay. */ return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -