| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * Dalvik verification subroutines. |
| */ |
| #include "Dalvik.h" |
| #include "analysis/CodeVerify.h" |
| #include "libdex/InstrUtils.h" |
| |
| |
| /* |
| * This is used when debugging to apply a magnifying glass to the |
| * verification of a particular method. |
| */ |
| bool dvmWantVerboseVerification(const Method* meth) |
| { |
| return false; /* COMMENT OUT to enable verbose debugging */ |
| |
| const char* cd = "Lcom/android/server/am/ActivityManagerService;"; |
| const char* mn = "trimApplications"; |
| const char* sg = "()V"; |
| return (strcmp(meth->clazz->descriptor, cd) == 0 && |
| dvmCompareNameDescriptorAndMethod(mn, sg, meth) == 0); |
| } |
| |
| /* |
| * Output a code verifier warning message. For the pre-verifier it's not |
| * a big deal if something fails (and it may even be expected), but if |
| * we're doing just-in-time verification it's significant. |
| */ |
| void dvmLogVerifyFailure(const Method* meth, const char* format, ...) |
| { |
| va_list ap; |
| int logLevel; |
| |
| if (gDvm.optimizing) { |
| return; |
| //logLevel = ANDROID_LOG_DEBUG; |
| } else { |
| logLevel = ANDROID_LOG_WARN; |
| } |
| |
| va_start(ap, format); |
| LOG_PRI_VA(logLevel, LOG_TAG, format, ap); |
| if (meth != NULL) { |
| char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); |
| LOG_PRI(logLevel, LOG_TAG, "VFY: rejected %s.%s %s", |
| meth->clazz->descriptor, meth->name, desc); |
| free(desc); |
| } |
| } |
| |
| /* |
| * Show a relatively human-readable message describing the failure to |
| * resolve a class. |
| * |
| * TODO: this is somewhat misleading when resolution fails because of |
| * illegal access rather than nonexistent class. |
| */ |
| void dvmLogUnableToResolveClass(const char* missingClassDescr, |
| const Method* meth) |
| { |
| if (gDvm.optimizing) { |
| return; |
| } |
| |
| std::string dotMissingClass = dvmHumanReadableDescriptor(missingClassDescr); |
| std::string dotFromClass = dvmHumanReadableDescriptor(meth->clazz->descriptor); |
| LOGE("Could not find class '%s', referenced from method %s.%s", |
| dotMissingClass.c_str(), dotFromClass.c_str(), meth->name); |
| } |
| |
| /* |
| * Extract the relative offset from a branch instruction. |
| * |
| * Returns "false" on failure (e.g. this isn't a branch instruction). |
| */ |
| bool dvmGetBranchOffset(const Method* meth, const InsnFlags* insnFlags, |
| int curOffset, s4* pOffset, bool* pConditional) |
| { |
| const u2* insns = meth->insns + curOffset; |
| |
| switch (*insns & 0xff) { |
| case OP_GOTO: |
| *pOffset = ((s2) *insns) >> 8; |
| *pConditional = false; |
| break; |
| case OP_GOTO_32: |
| *pOffset = insns[1] | (((u4) insns[2]) << 16); |
| *pConditional = false; |
| break; |
| case OP_GOTO_16: |
| *pOffset = (s2) insns[1]; |
| *pConditional = false; |
| break; |
| case OP_IF_EQ: |
| case OP_IF_NE: |
| case OP_IF_LT: |
| case OP_IF_GE: |
| case OP_IF_GT: |
| case OP_IF_LE: |
| case OP_IF_EQZ: |
| case OP_IF_NEZ: |
| case OP_IF_LTZ: |
| case OP_IF_GEZ: |
| case OP_IF_GTZ: |
| case OP_IF_LEZ: |
| *pOffset = (s2) insns[1]; |
| *pConditional = true; |
| break; |
| default: |
| return false; |
| break; |
| } |
| |
| return true; |
| } |