private static StringBuilder getNodeState(ExecutionNode node, ExecutionGraph graph) { MethodState state = node.getContext().getMethodState(); String op = node.toString().replaceAll(DOT, "?").replace("\"", "\\\""); String stateStr = state.toString().replaceAll(DOT, "?").replace("\"", "\\\"").trim(); int nodeIndex = graph.getNodeIndex(node); StringBuilder sb = new StringBuilder(); sb.append("\"@").append(node.getAddress()).append('.').append(nodeIndex).append(" :: "); sb.append(op).append('\n').append(stateStr).append('"'); return sb; } }
private ExecutionContext buildNonLocalCalleeContext(ExecutionContext callerContext) { ExecutionContext calleeContext = new ExecutionContext(vm, method); int parameterSize = method.getParameterSize(); int registerCount = parameterSize; MethodState calleeMethodState = new MethodState(calleeContext, registerCount, method.getParameterTypeNames().size(), parameterSize); assignCalleeMethodArguments(callerContext.getMethodState(), calleeMethodState); calleeContext.setMethodState(calleeMethodState); calleeContext.registerCaller(callerContext, getAddress()); return calleeContext; }
private HeapItem getSafeField(Field field, Object instance, ExecutionContext context, Op op, ExceptionFactory exceptionFactory) { HeapItem item = null; try { Object getObject = field.get(instance); String type = ClassNameUtils.toInternal(field.getType()); item = new HeapItem(getObject, type); } catch (IllegalArgumentException | IllegalAccessException e) { String message = e.getMessage(); VirtualMethod callingMethod = context.getCallerContext().getMethod(); VirtualType callingClass = callingMethod.getDefiningClass(); message = message.replace(java_lang_reflect_Field_get.class.getName(), callingClass.getBinaryName()); Throwable exception = exceptionFactory.build(op, e.getClass(), message); setException(exception); } return item; }
BaseState getParent() { ExecutionContext parentContext = context.getParent(); MethodState parent = null; if (parentContext != null) { parent = parentContext.getMethodState(); } return parent; }
public ExecutionContext spawnChild() { ExecutionContext child = new ExecutionContext(vm, method); child.setParent(this); return child; }
public ClassState readClassState(VirtualType virtualClass) { staticallyInitializeClassIfNecessary(virtualClass); return peekClassState(virtualClass); }
public void setParent(ExecutionContext parent) { setShallowParent(parent); MethodState childMethodState = parent.getMethodState().getChild(this); setMethodState(childMethodState); }
public ClassState peekClassState(VirtualType virtualClass) { ExecutionContext ancestor = getAncestorWithClass(virtualClass); if (ancestor == null) { // VirtualClass has not been initialized; build template and cache it locally to track initialization state ClassState templateClassState = TemplateStateFactory.forClass(this, virtualClass); setClassState(templateClassState); return templateClassState; } else if (ancestor != this) { ClassState ancestorClassState = ancestor.peekClassState(virtualClass); ClassState cState = ancestorClassState.getChild(this); SideEffect.Level level = ancestor.getClassSideEffectLevel(virtualClass); // Must initialize, because the ancestor probably just has the template class state. initializeClass(cState, level); return cState; } return classToStatus.get(virtualClass).getClassState(); }
@Override public void execute(VirtualMachine vm, Op op, ExecutionContext context) { MethodState mState = context.getMethodState(); String binaryClassName = (String) mState.peekParameter(0).getValue(); String className = ClassNameUtils.binaryToInternal(binaryClassName); throw new ClassNotFoundException(); if (!context.isClassInitialized(virtualClass) && !className.equals("Lorg/cf/obfuscated/Reflection;")) { context.staticallyInitializeClassIfNecessary(virtualClass); level = context.getClassSideEffectLevel(virtualClass);
private void collapseMultiverse(VirtualMethod calledMethod, ExecutionGraph graph, ExecutionContext callerContext, int[] parameterRegisters) { int[] terminatingAddresses = graph.getConnectedTerminatingAddresses(); if (parameterRegisters != null) { MethodState callerMethodState = callerContext.getMethodState(); List<String> parameterTypes = calledMethod.getParameterTypeNames(); int parameterRegister = graph.getNodePile(0).get(0).getContext().getMethodState().getParameterStart(); for (int parameterIndex = 0; parameterIndex < parameterTypes.size(); parameterIndex++) { String type = parameterTypes.get(parameterIndex); boolean isInitializedInCaller = callerContext.isClassInitialized(virtualClass); hasOneInitialization: if (!isInitializedInCaller) { if (context.isClassInitialized(virtualClass)) { break hasOneInitialization; cState = callerContext.peekClassState(virtualClass); } else { callerContext.initializeClass(cState, level);
@Override public void execute(VirtualMachine vm, Op op, ExecutionContext context) { MethodState mState = context.getMethodState(); HeapItem fieldItem = mState.peekParameter(0); HeapItem instanceItem = mState.peekParameter(1); Field field = (Field) fieldItem.getValue(); int accessFlags = field.getModifiers(); String fieldClassName = ClassNameUtils.toInternal(field.getDeclaringClass()); if (!field.isAccessible()) { VirtualType callingClass = context.getCallerContext().getMethod().getDefiningClass(); ClassManager classManager = vm.getClassManager(); VirtualClass fieldClass = classManager.getVirtualClass(fieldClassName); boolean hasAccess = checkAccess(callingClass, fieldClass, accessFlags, op, vm.getExceptionFactory()); if (!hasAccess) { return; } } Object instance = instanceItem.getValue(); HeapItem getItem = get(field, instance, fieldClassName, accessFlags, context, vm, op); mState.assignReturnRegister(getItem); }
public void setShallowParent(ExecutionContext parent) { assert parent.getMethodState() != null; this.parent = parent; callDepth = parent.getCallDepth(); getHeap().setParent(parent.getHeap()); }
@Override public void execute(ExecutionNode node, ExecutionContext context) { Object instance = new UninitializedInstance(virtualClass); if (vm.isSafe(virtualClass)) { sideEffectLevel = SideEffect.Level.NONE; } else { // New-instance causes static initialization (but not new-array!) context.readClassState(virtualClass); // access will initialize if necessary sideEffectLevel = context.getClassSideEffectLevel(virtualClass); } MethodState mState = context.getMethodState(); HeapItem instanceItem = new HeapItem(instance, virtualClass.getName()); mState.assignRegister(destRegister, instanceItem); }
@Test public void methodStateForVirtualMethodCreatedCorrectly() throws VirtualMachineException { String methodDescriptor = "someString()Ljava/lang/String;"; VirtualMethod method = vm.getClassManager().getMethod(CLASS_NAME, methodDescriptor); ExecutionContext spawnedContext = new ExecutionContext(vm, method); ClassState templateClassState = TemplateStateFactory.forClass(spawnedContext, method.getDefiningClass()); spawnedContext.setClassState(templateClassState); MethodState templateMethodState = TemplateStateFactory.forMethod(spawnedContext); spawnedContext.setMethodState(templateMethodState); assertEquals(2, templateMethodState.getRegisterCount()); assertEquals(1, templateMethodState.getParameterCount()); int instanceRegister = templateMethodState.getParameterStart(); assertEquals(1, instanceRegister); HeapItem instanceItem = templateMethodState.peekRegister(instanceRegister); assertEquals(CLASS_NAME, instanceItem.getType()); assertEquals(UnknownValue.class, instanceItem.getValue().getClass()); }
public ExecutionContext spawnRootContext(VirtualMethod method, @Nullable ExecutionContext callerContext, int callerAddress) { if (!method.hasImplementation()) { // Native or abstract methods have no implementation. Shouldn't be executing them. throw new IllegalArgumentException("No implementation for " + method); } ExecutionContext spawnedContext = new ExecutionContext(this, method); ClassState templateClassState = TemplateStateFactory.forClass(spawnedContext, method.getDefiningClass()); spawnedContext.setClassState(templateClassState); MethodState templateMethodState = TemplateStateFactory.forMethod(spawnedContext); spawnedContext.setMethodState(templateMethodState); if (callerContext != null) { spawnedContext.registerCaller(callerContext, callerAddress); } return spawnedContext; }
private void inheritClassStates(ExecutionContext parentContext, ExecutionContext childContext) { for (VirtualClass virtualClass : classManager.getLoadedClasses()) { if (!parentContext.isClassInitialized(virtualClass)) { continue; } ClassState fromClassState = parentContext.peekClassState(virtualClass); ClassState toClassState = fromClassState.getChild(childContext); for (VirtualField field : fromClassState.getVirtualClass().getFields()) { HeapItem item = fromClassState.peekField(field); // TODO: should update field here? toClassState.pokeField(field, item); } SideEffect.Level level = parentContext.getClassSideEffectLevel(virtualClass); childContext.initializeClass(toClassState, level); } }
if (vm.isSafe(virtualClass) || isClassInitialized(virtualClass)) { continue; staticallyInitializeClassIfNecessary(ancestor); ClassState cState = peekClassState(virtualClass); initializeClass(cState, SideEffect.Level.NONE); return; ClassState cState = initContext.peekClassState(virtualClass); initContext.initializeClass(cState, SideEffect.Level.NONE);
private static void setupClassStates(ExecutionContext context, VirtualMachine vm, Map<String, Map<String, HeapItem>> classNameToFieldDescriptorToItem) { ClassManager classManager = vm.getClassManager(); for (Entry<String, Map<String, HeapItem>> entry : classNameToFieldDescriptorToItem.entrySet()) { String className = entry.getKey(); VirtualClass virtualClass = classManager.getVirtualClass(className); Map<String, HeapItem> fieldDescriptorToItem = entry.getValue(); ClassState cState = context.peekClassState(virtualClass); for (Entry<String, HeapItem> fieldNameAndTypeToItem : fieldDescriptorToItem.entrySet()) { String fieldNameAndType = fieldNameAndTypeToItem.getKey(); String fieldName = fieldNameAndType.split(":")[0]; VirtualField field = virtualClass.getField(fieldName); HeapItem item = fieldNameAndTypeToItem.getValue(); cState.pokeField(field, item); } context.initializeClass(cState, SideEffect.Level.NONE); } }
public void initializeClass(ClassState cState, SideEffect.Level level) { setClassState(cState); setClassInitialized(cState.getVirtualClass(), level); }
@Override public String toString() { StringBuilder sb = new StringBuilder("ExecutionNode{"); if (this.context != null) { sb.append("signature=").append(context.getMethod()).append(", "); } sb.append("op=").append(op.toString()).append(", "); sb.append("@=").append(op.getAddress()).append('}'); return sb.toString(); }