예제 #1
0
 public int getPositionInVirtualTable(
     Pointer<Pointer<?>> pVirtualTable, Method method, NativeLibrary library) {
   // Pointer<?> typeInfo = pVirtualTable.get(1);
   int methodsOffset = 0; // library.isMSVC() ? 0 : -2;///2;
   String className = getCPPClassName(method.getDeclaringClass());
   for (int iVirtual = 0; ; iVirtual++) {
     Pointer<?> pMethod = pVirtualTable.get(methodsOffset + iVirtual);
     String virtualMethodName = pMethod == null ? null : library.getSymbolName(pMethod.getPeer());
     // System.out.println("#\n# At index " + methodsOffset + " + " + iVirtual + " of vptr for
     // class " + className + ", found symbol " + Long.toHexString(pMethod.getPeer()) + " = '" +
     // virtualMethodName + "'\n#");
     if (virtualMethodName == null) {
       if (debug) info("\tVtable(" + className + ")[" + iVirtual + "] = null");
       return -1;
     }
     try {
       MemberRef mr = library.parseSymbol(virtualMethodName);
       if (debug)
         info("\tVtable(" + className + ")[" + iVirtual + "] = " + virtualMethodName + " = " + mr);
       if (mr != null && mr.matchesSignature(method)) return iVirtual;
       else if (library.isMSVC() && !mr.matchesEnclosingType(method))
         break; // no NULL terminator in MSVC++ vtables, so we have to guess when we've reached the
                // end
     } catch (Demangler.DemanglingException ex) {
       BridJ.warning(
           "Failed to demangle '"
               + virtualMethodName
               + "' during inspection of virtual table for '"
               + method.toGenericString()
               + "' : "
               + ex);
     }
   }
   return -1;
 }
예제 #2
0
  protected <T extends CPPObject> Pointer<T> newCPPInstance(
      T instance, final Type type, int constructorId, Object... args) {
    Pointer<T> peer = null;
    try {
      final Class<T> typeClass = Utils.getClass(type);
      NativeLibrary lib = BridJ.getNativeLibrary(typeClass);

      if (BridJ.debug)
        info("Creating C++ instance of type " + type + " with args " + Arrays.asList(args));
      Pointer.Releaser releaser = newCPPReleaser(type, typeClass, lib);

      long size = sizeOf(type, null);
      peer = (Pointer) Pointer.allocateBytes(PointerIO.getInstance(type), size, releaser).as(type);

      DynamicFunction constructor =
          constructorId == SKIP_CONSTRUCTOR
              ? null
              : getConstructor(typeClass, type, lib, constructorId);

      if (lib != null && CPPObject.class.isAssignableFrom(typeClass)) {
        installRegularVTablePtr(type, lib, peer);
      } else {
        // TODO ObjCObject : call alloc on class type !!
      }

      // Setting the C++ template parameters in the instance :
      int templateParametersCount = getTemplateParametersCount(typeClass);
      if (templateParametersCount > 0) {
        Object[] templateArgs = new Object[templateParametersCount];
        System.arraycopy(args, 0, templateArgs, 0, templateParametersCount);
        setTemplateParameters(instance, typeClass, templateArgs);
      }

      // Calling the constructor with the non-template parameters :
      if (constructor != null) {
        Object[] consThisArgs = new Object[args.length - templateParametersCount + 1];
        consThisArgs[0] = peer;
        System.arraycopy(
            args, templateParametersCount, consThisArgs, 1, args.length - templateParametersCount);

        constructor.apply(consThisArgs);
      }

      // Install synthetic virtual table and associate the Java instance to the corresponding native
      // pointer :
      if (CPPObject.class.isAssignableFrom(typeClass)) {
        if (installSyntheticVTablePtr(type, lib, peer))
          BridJ.setJavaObjectFromNativePeer(peer.getPeer(), instance);
      } else {
        // TODO ObjCObject : call alloc on class type !!
      }
      return peer;
    } catch (Exception ex) {
      ex.printStackTrace();
      if (peer != null) {
        peer.release();
      }
      throw new RuntimeException("Failed to allocate new instance of type " + type, ex);
    }
  }
예제 #3
0
  long getVirtualTable(Type type, NativeLibrary library) {
    Long vtable = vtables.get(type);
    if (vtable == null) {
      final Class<?> typeClass = Utils.getClass(type);
      if (false) {
        String className = typeClass.getSimpleName();
        String vtableSymbol;
        if (Platform.isWindows()) vtableSymbol = "??_7" + className + "@@6B@";
        else vtableSymbol = "_ZTV" + className.length() + className;

        vtables.put(type, vtable = library.getSymbolAddress(vtableSymbol));
      } else {
        Symbol symbol =
            library.getFirstMatchingSymbol(
                new SymbolAccepter() {
                  public boolean accept(Symbol symbol) {
                    return symbol.matchesVirtualTable(typeClass);
                  }
                });
        if (symbol != null) {
          if (BridJ.debug)
            info("Registering vtable of " + Utils.toString(type) + " as " + symbol.getName());
          //                    Pointer<Pointer> pp = pointerToAddress(symbol.getAddress(),
          // Pointer.class);
          //
          //                    for (int i = 0; i < 6; i++) {
          //                        Pointer p = pp.get(i);
          ////                        if (p == null)
          ////                            break;
          //                        String n = p == null ? null :
          // library.getSymbolName(p.getPeer());
          //                        info("\tVtable entry " + i + " = " + p + " (" + n + ")");
          ////                        if (n == null)
          ////                            break;
          //                    }
        } else if (getVirtualMethodsCount(typeClass) > 0)
          error("Failed to find a vtable for type " + Utils.toString(type));

        if (symbol != null) {
          long address = symbol.getAddress();
          vtable = library.isMSVC() ? address : address + 2 * Pointer.SIZE;
        } else {
          vtable = 0L;
        }
        vtables.put(type, vtable); // */
      }
    }
    return vtable;
  }
예제 #4
0
  CPPDestructor getDestructor(final Class<?> typeClass, Type type, NativeLibrary lib) {
    CPPDestructor destructor = destructors.get(type);
    if (destructor == null) {
      Symbol symbol =
          lib.getFirstMatchingSymbol(
              new SymbolAccepter() {
                public boolean accept(Symbol symbol) {
                  return symbol.matchesDestructor(typeClass);
                }
              });
      if (BridJ.debug && symbol != null)
        info("Registering destructor of " + Utils.toString(type) + " as " + symbol.getName());

      if (symbol != null)
        destructors.put(
            type, destructor = pointerToAddress(symbol.getAddress(), CPPDestructor.class).get());
    }
    return destructor;
  }
예제 #5
0
  DynamicFunction getConstructor(
      final Class<?> typeClass, final Type type, NativeLibrary lib, int constructorId) {
    Pair<Type, Integer> key = new Pair<Type, Integer>(type, constructorId);
    DynamicFunction constructor = constructors.get(key);
    if (constructor == null) {
      try {
        final Constructor<?> constr;
        try {
          constr = findConstructor(typeClass, constructorId, true);

          if (debug) BridJ.info("Found constructor for " + Utils.toString(type) + " : " + constr);
        } catch (NoSuchMethodException ex) {
          if (debug) BridJ.info("No constructor for " + Utils.toString(type));
          return null;
        }
        Symbol symbol =
            lib == null
                ? null
                : lib.getFirstMatchingSymbol(
                    new SymbolAccepter() {
                      public boolean accept(Symbol symbol) {
                        return symbol.matchesConstructor(
                            constr.getDeclaringClass() == Utils.getClass(type)
                                ? type
                                : constr.getDeclaringClass() /* TODO */,
                            constr);
                      }
                    });
        if (symbol == null) {
          if (debug)
            BridJ.info("No matching constructor for " + Utils.toString(type) + " (" + constr + ")");
          return null;
        }

        if (debug) info("Registering constructor " + constr + " as " + symbol.getName());

        // TODO do something with these args !
        int templateParametersCount = getTemplateParametersCount(typeClass);

        Class<?>[] consParamTypes = constr.getParameterTypes();
        Class<?>[] consThisParamTypes =
            new Class[consParamTypes.length + 1 - templateParametersCount];
        consThisParamTypes[0] = Pointer.class;
        System.arraycopy(
            consParamTypes,
            templateParametersCount,
            consThisParamTypes,
            1,
            consParamTypes.length - templateParametersCount);

        DynamicFunctionFactory constructorFactory =
            getDynamicFunctionFactory(lib, Style.ThisCall, void.class, consThisParamTypes);

        constructor = constructorFactory.newInstance(pointerToAddress(symbol.getAddress()));
        constructors.put(key, constructor);
      } catch (Throwable th) {
        th.printStackTrace();
        throw new RuntimeException(
            "Unable to create constructor " + constructorId + " for " + type + " : " + th, th);
      }
    }
    return constructor;
  }
예제 #6
0
  @Override
  protected void registerNativeMethod(
      Class<?> type,
      NativeLibrary typeLibrary,
      Method method,
      NativeLibrary methodLibrary,
      Builder builder,
      MethodCallInfoBuilder methodCallInfoBuilder)
      throws FileNotFoundException {

    int modifiers = method.getModifiers();
    boolean isCPPClass = CPPObject.class.isAssignableFrom(method.getDeclaringClass());

    //		Annotation[][] anns = method.getParameterAnnotations();
    if (!isCPPClass) {
      super.registerNativeMethod(
          type, typeLibrary, method, methodLibrary, builder, methodCallInfoBuilder);
      return;
    }

    MethodCallInfo mci = methodCallInfoBuilder.apply(method);

    Virtual va = method.getAnnotation(Virtual.class);
    if (va == null) {
      Symbol symbol = methodLibrary.getSymbol(method);
      mci.setForwardedPointer(symbol == null ? 0 : symbol.getAddress());
      if (mci.getForwardedPointer() == 0) {
        assert error(
            "Method "
                + method.toGenericString()
                + " is not virtual but its address could not be resolved in the library.");
        return;
      }
      if (Modifier.isStatic(modifiers)) {
        builder.addFunction(mci);
        if (debug)
          info("Registering " + method + " as function or static C++ method " + symbol.getName());
      } else {
        builder.addFunction(mci);
        if (debug) info("Registering " + method + " as C++ method " + symbol.getName());
      }
    } else {
      if (Modifier.isStatic(modifiers)) {
        warning(
            "Method "
                + method.toGenericString()
                + " is native and maps to a function, but is not static.");
      }

      int theoreticalVirtualIndex = va.value();
      int theoreticalAbsoluteVirtualIndex =
          theoreticalVirtualIndex < 0
              ? -1
              : getAbsoluteVirtualIndex(method, theoreticalVirtualIndex, type);

      int absoluteVirtualIndex;

      Pointer<Pointer<?>> pVirtualTable =
          isCPPClass && typeLibrary != null
              ? (Pointer) pointerToAddress(getVirtualTable(type, typeLibrary), Pointer.class)
              : null;
      if (pVirtualTable == null) {
        if (theoreticalAbsoluteVirtualIndex < 0) {
          error(
              "Method "
                  + method.toGenericString()
                  + " is virtual but the virtual table of class "
                  + type.getName()
                  + " was not found and the virtual method index is not provided in its @Virtual annotation.");
          return;
        }
        absoluteVirtualIndex = theoreticalAbsoluteVirtualIndex;
      } else {
        int guessedAbsoluteVirtualIndex =
            getPositionInVirtualTable(pVirtualTable, method, typeLibrary);
        if (guessedAbsoluteVirtualIndex < 0) {
          if (theoreticalAbsoluteVirtualIndex < 0) {
            error(
                "Method "
                    + method.toGenericString()
                    + " is virtual but its position could not be found in the virtual table.");
            return;
          } else {
            absoluteVirtualIndex = theoreticalAbsoluteVirtualIndex;
          }
        } else {
          if (theoreticalAbsoluteVirtualIndex >= 0
              && guessedAbsoluteVirtualIndex != theoreticalAbsoluteVirtualIndex) {
            warning(
                "Method "
                    + method.toGenericString()
                    + " has @Virtual annotation indicating virtual index "
                    + theoreticalAbsoluteVirtualIndex
                    + ", but analysis of the actual virtual table rather indicates it has index "
                    + guessedAbsoluteVirtualIndex
                    + " (using the guess)");
          }
          absoluteVirtualIndex = guessedAbsoluteVirtualIndex;
        }
      }
      mci.setVirtualIndex(absoluteVirtualIndex);
      if (debug)
        info(
            "Registering "
                + method.toGenericString()
                + " as virtual C++ method with absolute virtual table index = "
                + absoluteVirtualIndex);
      builder.addVirtualMethod(mci);
    }
  }