blob: ad938972298732450f60bc55525299523956c9fc [file] [log] [blame]
/*
* 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 bytecode verifier.
*/
#ifndef _DALVIK_CODEVERIFY
#define _DALVIK_CODEVERIFY
/*
* InsnFlags is a 32-bit integer with the following layout:
* 0-15 instruction length (or 0 if this address doesn't hold an opcode)
* 16 opcode flag (indicating this address holds an opcode)
* 17 try block (indicating exceptions thrown here may be caught locally)
* 30 visited (verifier has examined this instruction at least once)
* 31 changed (set/cleared as bytecode verifier runs)
*/
typedef u4 InsnFlags;
#define kInsnFlagWidthMask 0x0000ffff
#define kInsnFlagInTry (1 << 16)
#define kInsnFlagBranchTarget (1 << 17)
#define kInsnFlagVisited (1 << 30)
#define kInsnFlagChanged (1 << 31)
/*
* Returns "true" if the flags indicate that this address holds the start
* of an instruction.
*/
INLINE bool dvmInsnIsOpcode(const InsnFlags* insnFlags, int addr) {
return (insnFlags[addr] & kInsnFlagWidthMask) != 0;
}
/*
* Extract the unsigned 16-bit instruction width from "flags".
*/
INLINE int dvmInsnGetWidth(const InsnFlags* insnFlags, int addr) {
return insnFlags[addr] & kInsnFlagWidthMask;
}
/*
* Changed?
*/
INLINE bool dvmInsnIsChanged(const InsnFlags* insnFlags, int addr) {
return (insnFlags[addr] & kInsnFlagChanged) != 0;
}
INLINE void dvmInsnSetChanged(InsnFlags* insnFlags, int addr, bool changed)
{
if (changed)
insnFlags[addr] |= kInsnFlagChanged;
else
insnFlags[addr] &= ~kInsnFlagChanged;
}
/*
* Visited?
*/
INLINE bool dvmInsnIsVisited(const InsnFlags* insnFlags, int addr) {
return (insnFlags[addr] & kInsnFlagVisited) != 0;
}
INLINE void dvmInsnSetVisited(InsnFlags* insnFlags, int addr, bool changed)
{
if (changed)
insnFlags[addr] |= kInsnFlagVisited;
else
insnFlags[addr] &= ~kInsnFlagVisited;
}
/*
* Visited or changed?
*/
INLINE bool dvmInsnIsVisitedOrChanged(const InsnFlags* insnFlags, int addr) {
return (insnFlags[addr] & (kInsnFlagVisited|kInsnFlagChanged)) != 0;
}
/*
* In a "try" block?
*/
INLINE bool dvmInsnIsInTry(const InsnFlags* insnFlags, int addr) {
return (insnFlags[addr] & kInsnFlagInTry) != 0;
}
INLINE void dvmInsnSetInTry(InsnFlags* insnFlags, int addr, bool inTry)
{
assert(inTry);
//if (inTry)
insnFlags[addr] |= kInsnFlagInTry;
//else
// insnFlags[addr] &= ~kInsnFlagInTry;
}
/*
* Instruction is a branch target or exception handler?
*/
INLINE bool dvmInsnIsBranchTarget(const InsnFlags* insnFlags, int addr) {
return (insnFlags[addr] & kInsnFlagBranchTarget) != 0;
}
INLINE void dvmInsnSetBranchTarget(InsnFlags* insnFlags, int addr,
bool isBranch)
{
assert(isBranch);
//if (isBranch)
insnFlags[addr] |= kInsnFlagBranchTarget;
//else
// insnFlags[addr] &= ~kInsnFlagBranchTarget;
}
/*
* Table that maps uninitialized instances to classes, based on the
* address of the new-instance instruction.
*/
typedef struct UninitInstanceMap {
int numEntries;
struct {
int addr; /* code offset, or -1 for method arg ("this") */
ClassObject* clazz; /* class created at this address */
} map[1];
} UninitInstanceMap;
#define kUninitThisArgAddr (-1)
#define kUninitThisArgSlot 0
/*
* Create a new UninitInstanceMap.
*/
UninitInstanceMap* dvmCreateUninitInstanceMap(const Method* meth,
const InsnFlags* insnFlags, int newInstanceCount);
/*
* Release the storage associated with an UninitInstanceMap.
*/
void dvmFreeUninitInstanceMap(UninitInstanceMap* uninitMap);
/*
* Associate a class with an address. Returns the map slot index, or -1
* if the address isn't listed in the map (shouldn't happen) or if a
* different class is already associated with the address (shouldn't
* happen either).
*/
int dvmSetUninitInstance(UninitInstanceMap* uninitMap, int addr,
ClassObject* clazz);
/*
* Return the class associated with an uninitialized reference. Pass in
* the map index.
*/
ClassObject* dvmGetUninitInstance(const UninitInstanceMap* uninitMap, int idx);
/*
* Clear the class associated with an uninitialized reference. Pass in
* the map index.
*/
//void dvmClearUninitInstance(UninitInstanceMap* uninitMap, int idx);
/*
* Verify bytecode in "meth". "insnFlags" should be populated with
* instruction widths and "in try" flags.
*/
bool dvmVerifyCodeFlow(const Method* meth, InsnFlags* insnFlags,
UninitInstanceMap* uninitMap);
/*
* Log standard method info for rejection message.
*/
void dvmLogVerifyFailure(const Method* meth, const char* format, ...);
/*
* Extract the relative branch target from a branch instruction.
*/
bool dvmGetBranchTarget(const Method* meth, InsnFlags* insnFlags,
int curOffset, int* pOffset, bool* pConditional);
#endif /*_DALVIK_CODEVERIFY*/