diff --git a/.gitignore b/.gitignore
index e988817cdb19d21c8a0d576885cfcca7808b3d61..d39a0a4a07f33856d938f8873ce7daafa0d520c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,6 +81,7 @@ scratch/
 bin/
 share/
 etc/
+doc/
 src_gen/
 /local/
 /.hgtip
@@ -113,4 +114,5 @@ test_gnur
 test_fastr
 lib.install.cran*
 package.blacklist
-com.oracle.truffle.r.test.native/embedded/main
+com.oracle.truffle.r.test.native/embedded/lib
+
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
index 0727968f1c6d6eebc176930a48abba8e4ea1d66c..abd98ab841ad5b44169e32c7a8ba0e8594a654a5 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
@@ -575,11 +575,6 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
         return RASTUtils.unwrap(promise.getRep()).asRSyntaxNode();
     }
 
-    @Override
-    public void enableDebug(RFunction func) {
-        DebugHandling.enableDebug(func, "", RNull.instance, false);
-    }
-
     @Override
     public boolean isTaggedWith(Node node, Class<?> tag) {
         if (!(node instanceof RSyntaxNode)) {
@@ -642,4 +637,19 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
         return ConstantNode.create(o);
     }
 
+    @Override
+    public boolean enableDebug(RFunction func, boolean once) {
+        return DebugHandling.enableDebug(func, "", RNull.instance, once);
+    }
+
+    @Override
+    public boolean isDebugged(RFunction func) {
+        return DebugHandling.isDebugged(func);
+    }
+
+    @Override
+    public boolean disableDebug(RFunction func) {
+        return DebugHandling.undebug(func);
+    }
+
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
index ce068b4847c71392daa929cef73bb9268bd43d51..a3196da63f2358cb4ba1e4e0dd580f23d8f6faef 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
@@ -76,7 +76,7 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> {
             RPackageSource.initialize();
             RContext.initialize(new RASTBuilder(), new RRuntimeASTAccessImpl(), RBuiltinPackages.getInstance(), new RForeignAccessFactoryImpl());
         } catch (Throwable t) {
-            System.out.println("error during engine initialization:");
+            System.err.println("error during engine initialization: " + t);
             t.printStackTrace();
             System.exit(-1);
         }
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
index af0a6d0093c85443143aced3efcf735413de3604..0708f7b286e314ef6574acdc288d0e612f5b5515 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
@@ -11,14 +11,17 @@
  */
 #include <dlfcn.h>
 #include <sys/utsname.h>
+#include <sys/stat.h>
 #include <rffiutils.h>
 #include <R_ext/RStartup.h>
 #include <Rinterface.h>
 
+extern char **environ;
 
 static JavaVM *javaVM;
 static jobject engine;
 static int initialized = 0;
+static char *java_home;
 
 static jclass rembeddedClass;
 static jclass rStartParamsClass;
@@ -51,7 +54,7 @@ static int process_vmargs(int argc, char *argv[], char *vmargv[], char *uargv[])
 	int ucount = 0;
 	for (int i = 0; i < argc; i++) {
 		char *arg = argv[i];
-		if (arg[0] == '-' && arg[1] == 'X') {
+		if ((arg[0] == '-' && arg[1] == 'X') || (arg[0] == '-' && arg[1] == 'D')) {
 			vmargv[vcount++] = arg;
 		} else {
 			uargv[ucount++] = arg;
@@ -60,13 +63,16 @@ static int process_vmargs(int argc, char *argv[], char *vmargv[], char *uargv[])
 	return vcount;
 }
 
-char *get_classpath(char *r_home);
+static char **update_environ_with_java_home(void);
+static void print_environ(char **env);
+static char *get_classpath(char *r_home);
 
 int Rf_initialize_R(int argc, char *argv[]) {
 	if (initialized) {
 		fprintf(stderr, "%s", "R is already initialized\n");
 		exit(1);
 	}
+	// print_environ(environ);
 	char *r_home = getenv("R_HOME");
 	if (r_home == NULL) {
 		printf("R_HOME must be set\n");
@@ -75,10 +81,19 @@ int Rf_initialize_R(int argc, char *argv[]) {
 	struct utsname utsname;
 	uname(&utsname);
 	char jvmlib_path[256];
-	char *java_home = getenv("JAVA_HOME");
+	java_home = getenv("JAVA_HOME");
 	if (java_home == NULL) {
-		printf("Rf_initialize_R: can't find JAVA_HOME");
-		exit(1);
+		if (strcmp(utsname.sysname, "Linux") == 0) {
+			char *jvmdir = "/usr/java/latest";
+			struct stat statbuf;
+			if (stat(jvmdir, &statbuf) == 0) {
+				java_home = jvmdir;
+			}
+		}
+		if (java_home == NULL) {
+			printf("Rf_initialize_R: can't find a JAVA_HOME\n");
+			exit(1);
+		}
 	}
 	strcpy(jvmlib_path, java_home);
 	if (strcmp(utsname.sysname, "Linux") == 0) {
@@ -435,7 +450,7 @@ int R_wait_usec;
 #include <unistd.h>
 #include <errno.h>
 
-void perror_exit(char *msg) {
+static void perror_exit(char *msg) {
 	perror(msg);
 	exit(1);
 }
@@ -443,7 +458,9 @@ void perror_exit(char *msg) {
 // support for getting the correct classpath for the VM
 // We use $R_HOME/bin/exec/Rclasspath to do this to emulate what happens
 // during normal execution
-char *get_classpath(char *r_home) {
+static char *get_classpath(char *r_home) {
+	char **env = update_environ_with_java_home();
+	//print_environ(env);
 	int pipefd[2];
 	if (pipe(pipefd) == -1) {
 		perror_exit("pipe");
@@ -460,7 +477,7 @@ char *get_classpath(char *r_home) {
 		while ((dup2(pipefd[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
 		close(pipefd[1]);
 		close(pipefd[0]);
-		int rc = execl(path, (char *)NULL);
+		int rc = execle(path, path, (char *)NULL, env);
 		if (rc == -1) {
 			perror_exit("exec");
 		}
@@ -498,3 +515,46 @@ char *get_classpath(char *r_home) {
 		return buf;
 	}
 }
+
+// debugging
+static void print_environ(char **env) {
+	printf("## Environment variables at %p\n", env);
+	char **e = env;
+	while (*e != NULL) {
+		printf("%s\n", *e);
+		e++;
+	}
+}
+
+static char **update_environ(char *def) {
+	int count = 0;
+	char **e = environ;
+	while (*e != NULL) {
+		e++;
+		count++;
+	}
+	char **new_env = malloc(sizeof(char *) * (count + 2));
+	e = environ;
+	char **ne = new_env;
+	while (*e != NULL) {
+		*ne++ = *e++;
+	}
+	*ne++ = def;
+	*ne = (char*) NULL;
+	return new_env;
+}
+
+static char **update_environ_with_java_home(void) {
+	char **e = environ;
+	while (*e != NULL) {
+		if (strstr(*e, "JAVA_HOME=")) {
+			return environ;
+		}
+		e++;
+	}
+	char *java_home_env = malloc(strlen(java_home) + 10);
+	strcpy(java_home_env, "JAVA_HOME=");
+	strcat(java_home_env, java_home);
+	return update_environ(java_home_env);
+}
+
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
index 7893e1e94a3e25357b91f18ea0c8015af70b1a38..629ec2aa16d41774fb68a43631c434d9364bc8bc 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -90,6 +90,11 @@ static jmethodID DUPLICATE_ATTRIB_MethodID;
 static jmethodID isS4ObjectMethodID;
 static jmethodID logObject_MethodID;
 static jmethodID R_tryEvalMethodID;
+static jmethodID RDEBUGMethodID;
+static jmethodID SET_RDEBUGMethodID;
+static jmethodID RSTEPMethodID;
+static jmethodID SET_RSTEPMethodID;
+
 
 static jclass RExternalPtrClass;
 static jmethodID createExternalPtrMethodID;
@@ -172,6 +177,10 @@ void init_internals(JNIEnv *env) {
 	isS4ObjectMethodID = checkGetMethodID(env, CallRFFIHelperClass, "isS4Object", "(Ljava/lang/Object;)I", 1);
 	logObject_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "logObject", "(Ljava/lang/Object;)V", 1);
 	R_tryEvalMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_tryEval", "(Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object;", 1);
+	RDEBUGMethodID = checkGetMethodID(env, CallRFFIHelperClass, "RDEBUG", "(Ljava/lang/Object;)I", 1);
+	SET_RDEBUGMethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_RDEBUG", "(Ljava/lang/Object;I)V", 1);
+	RSTEPMethodID = checkGetMethodID(env, CallRFFIHelperClass, "RSTEP", "(Ljava/lang/Object;)I", 1);
+	SET_RSTEPMethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_RSTEP", "(Ljava/lang/Object;I)V", 1);
 
 	RExternalPtrClass = checkFindClass(env, "com/oracle/truffle/r/runtime/data/RExternalPtr");
 	createExternalPtrMethodID = checkGetMethodID(env, RDataFactoryClass, "createExternalPtr", "(JLjava/lang/Object;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RExternalPtr;", 1);
@@ -854,13 +863,13 @@ SEXP CLOENV(SEXP x) {
 }
 
 int RDEBUG(SEXP x) {
-    unimplemented("RDEBUG");
-    return 0;
+    JNIEnv *thisenv = getEnv();
+    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, RDEBUGMethodID, x);
 }
 
 int RSTEP(SEXP x) {
-	unimplemented("RSTEP");
-    return 0;
+    JNIEnv *thisenv = getEnv();
+    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, RSTEPMethodID, x);
 }
 
 int RTRACE(SEXP x) {
@@ -869,11 +878,13 @@ int RTRACE(SEXP x) {
 }
 
 void SET_RDEBUG(SEXP x, int v) {
-    unimplemented("SET_RDEBUG");
+    JNIEnv *thisenv = getEnv();
+    (*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_RDEBUGMethodID, x, v);
 }
 
 void SET_RSTEP(SEXP x, int v) {
-    unimplemented("SET_RSTEP");
+    JNIEnv *thisenv = getEnv();
+    (*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_RSTEPMethodID, x, v);
 }
 
 void SET_RTRACE(SEXP x, int v) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
index efeab31d46a10033007875ea14fc546ebeb6865a..33264d6fd04b61bba6316f00927b0b16b6307dfc 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
@@ -223,7 +223,7 @@ public class RInstrumentation {
             FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode();
             for (String debugFunctionName : debugFunctionNames) {
                 if (debugFunctionName.equals(fdn.toString())) {
-                    RContext.getRRuntimeASTAccess().enableDebug(func);
+                    RContext.getRRuntimeASTAccess().enableDebug(func, false);
                 }
             }
         }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java
index ea8c579410fb0ec9c732ed0d1357ad3e402800c5..137427c09f32b64cd1c723b75827258a2426819e 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java
@@ -22,14 +22,22 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import java.io.FileWriter;
 import java.io.IOException;
+import java.io.PrintWriter;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 
 public class RFFIUtils {
+    /**
+     * Set this to {@code true} when it is not possible to set {@link FastROptions}.
+     */
+    private static boolean alwaysTrace;
+
     public static byte[] wrapChar(char v) {
         return new byte[]{(byte) v};
     }
@@ -47,25 +55,69 @@ public class RFFIUtils {
         throw new IOException(errMsg);
     }
 
-    public static void traceCall(String name, Object... args) {
-        if (FastROptions.TraceNativeCalls.getBooleanValue()) {
-            System.out.print("CallRFFI " + name + ": ");
-            printArgs(args);
-            System.out.println();
+    /**
+     * Places in /tmp because in embedded mode can't trust that cwd is writeable. Also, tag with
+     * time in event of multiple concurrent instances.
+     */
+    private static final String tracePathPrefix = "/tmp/fastr_trace_nativecalls.log-";
+    private static PrintWriter traceWriter;
+
+    private static void initialize() {
+        if (traceWriter == null) {
+            String tracePath = tracePathPrefix + Long.toString(System.currentTimeMillis());
+            try {
+                traceWriter = new PrintWriter(new FileWriter(tracePath));
+            } catch (IOException ex) {
+                System.err.println(ex.getMessage());
+                System.exit(1);
+            }
+        }
+    }
+
+    public static void traceUpCall(String name, Object... args) {
+        traceCall(false, name, args);
+    }
+
+    public static void traceDownCall(String name, Object... args) {
+        traceCall(true, name, args);
+    }
+
+    private static void traceCall(boolean down, String name, Object... args) {
+        if (alwaysTrace || FastROptions.TraceNativeCalls.getBooleanValue()) {
+            initialize();
+            StringBuffer sb = new StringBuffer();
+            sb.append("CallRFFI[");
+            sb.append(down ? "Down" : "Up");
+            sb.append(']');
+            sb.append(name);
+            sb.append('(');
+            printArgs(sb, args);
+            sb.append(')');
+            traceWriter.println(sb.toString());
+            traceWriter.flush();
         }
     }
 
-    private static void printArgs(Object[] args) {
+    private static void printArgs(StringBuffer sb, Object[] args) {
+        boolean first = true;
         for (Object arg : args) {
-            System.out.print(" ");
-            System.out.print(arg == null ? "" : arg.getClass().getSimpleName());
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(arg == null ? "" : arg.getClass().getSimpleName());
             if (arg instanceof RPairList) {
-                System.out.print("[");
-                printArgs(((RPairList) arg).toRList().getDataCopy());
-                System.out.print("]");
+                sb.append("[");
+                printArgs(sb, ((RPairList) arg).toRList().getDataCopy());
+                sb.append("]");
+            }
+            if (arg instanceof RSymbol) {
+                RSymbol symbol = (RSymbol) arg;
+                sb.append("\"" + symbol.getName() + "\")");
             }
             if (!(arg instanceof RTypedValue)) {
-                System.out.print("(" + arg + ")");
+                sb.append("(" + arg + ")");
             }
         }
     }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
index 32ddbbeebf3e0a24c939669d6cd910005cf9dec8..845d6070a18c3714e551e74fec276d616139bbfb 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
@@ -68,6 +68,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
+import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 import com.oracle.truffle.r.runtime.nodes.DuplicationHelper;
 import com.oracle.truffle.r.runtime.rng.RRNG;
@@ -142,23 +143,28 @@ public class CallRFFIHelper {
     // Checkstyle: stop method name check
 
     public static RIntVector Rf_ScalarInteger(int value) {
+        RFFIUtils.traceUpCall("Rf_ScalarInteger", value);
         return RDataFactory.createIntVectorFromScalar(value);
     }
 
     public static RLogicalVector Rf_ScalarLogical(int value) {
+        RFFIUtils.traceUpCall("Rf_ScalarLogical", value);
         return RDataFactory.createLogicalVectorFromScalar(value != 0);
     }
 
     public static RDoubleVector Rf_ScalarDouble(double value) {
+        RFFIUtils.traceUpCall("Rf_ScalarDouble", value);
         return RDataFactory.createDoubleVectorFromScalar(value);
     }
 
     public static RStringVector Rf_ScalarString(Object value) {
+        RFFIUtils.traceUpCall("Rf_ScalarString", value);
         CharSXPWrapper chars = guaranteeInstanceOf(value, CharSXPWrapper.class);
         return RDataFactory.createStringVectorFromScalar(chars.getContents());
     }
 
     public static int Rf_asInteger(Object x) {
+        RFFIUtils.traceUpCall("Rf_asInteger", x);
         if (x instanceof Integer) {
             return ((Integer) x).intValue();
         } else if (x instanceof Double) {
@@ -172,6 +178,7 @@ public class CallRFFIHelper {
     }
 
     public static double Rf_asReal(Object x) {
+        RFFIUtils.traceUpCall("Rf_asReal", x);
         if (x instanceof Double) {
             return ((Double) x).doubleValue();
         } else if (x instanceof Byte) {
@@ -183,6 +190,7 @@ public class CallRFFIHelper {
     }
 
     public static int Rf_asLogical(Object x) {
+        RFFIUtils.traceUpCall("Rf_asLogical", x);
         if (x instanceof Byte) {
             return ((Byte) x).intValue();
         } else {
@@ -192,6 +200,7 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_asChar(Object x) {
+        RFFIUtils.traceUpCall("Rf_asChar", x);
         if (x instanceof CharSXPWrapper) {
             return x;
         } else if (x instanceof RSymbol) {
@@ -214,15 +223,18 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_mkCharLenCE(byte[] bytes, @SuppressWarnings("unused") int encoding) {
+        RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
         // TODO: handle encoding properly
         return new CharSXPWrapper(new String(bytes, StandardCharsets.UTF_8));
     }
 
     public static Object Rf_cons(Object car, Object cdr) {
+        RFFIUtils.traceUpCall("Rf_cons", car, cdr);
         return RDataFactory.createPairList(car, cdr);
     }
 
     public static void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
+        RFFIUtils.traceUpCall("Rf_defineVar", symbolArg, value, envArg);
         REnvironment env = (REnvironment) envArg;
         RSymbol name = (RSymbol) symbolArg;
         try {
@@ -233,10 +245,12 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_findVar(Object symbolArg, Object envArg) {
+        RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg);
         return findVarInFrameHelper(symbolArg, envArg, true);
     }
 
     public static Object Rf_findVarInFrame(Object symbolArg, Object envArg) {
+        RFFIUtils.traceUpCall("Rf_findVarInFrame", symbolArg, envArg);
         return findVarInFrameHelper(symbolArg, envArg, false);
     }
 
@@ -264,6 +278,7 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_getAttrib(Object obj, Object name) {
+        RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
         Object result = RNull.instance;
         if (obj instanceof RAttributable) {
             RAttributable attrObj = (RAttributable) obj;
@@ -280,6 +295,7 @@ public class CallRFFIHelper {
     }
 
     public static void Rf_setAttrib(Object obj, Object name, Object val) {
+        RFFIUtils.traceUpCall("Rf_setAttrib", obj, name);
         if (obj instanceof RAttributable) {
             RAttributable attrObj = (RAttributable) obj;
             String nameAsString;
@@ -301,6 +317,7 @@ public class CallRFFIHelper {
     }
 
     public static RStringVector getClassHr(Object v) {
+        RFFIUtils.traceUpCall("getClassHr", v);
         if (v instanceof RAttributable) {
             return ((RAttributable) v).getClassHierarchy();
         } else if (v instanceof Byte) {
@@ -322,6 +339,7 @@ public class CallRFFIHelper {
     }
 
     public static int Rf_inherits(Object x, String clazz) {
+        RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
         RStringVector hierarchy = getClassHr(x);
         for (int i = 0; i < hierarchy.getLength(); i++) {
             if (hierarchy.getDataAt(i).equals(clazz)) {
@@ -332,19 +350,23 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_lengthgets(Object x, int newSize) {
+        RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
         RAbstractVector vec = (RAbstractVector) RRuntime.asAbstractVector(x);
         return vec.resize(newSize);
     }
 
     public static int Rf_isString(Object x) {
+        RFFIUtils.traceUpCall("Rf_isString", x);
         return RRuntime.checkType(x, RType.Character) ? 1 : 0;
     }
 
     public static int Rf_isNull(Object x) {
+        RFFIUtils.traceUpCall("Rf_isNull", x);
         return x == RNull.instance ? 1 : 0;
     }
 
     public static Object Rf_PairToVectorList(Object x) {
+        RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
         if (x == RNull.instance) {
             return RDataFactory.createList();
         }
@@ -353,18 +375,22 @@ public class CallRFFIHelper {
     }
 
     public static void Rf_error(String msg) {
+        RFFIUtils.traceUpCall("Rf_error", msg);
         throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
     }
 
     public static void Rf_warning(String msg) {
+        RFFIUtils.traceUpCall("Rf_warning", msg);
         RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
     }
 
     public static void Rf_warningcall(Object call, String msg) {
+        RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
         RErrorHandling.warningcallRFFI(call, msg);
     }
 
     public static Object Rf_allocateVector(int mode, int n) {
+        RFFIUtils.traceUpCall("Rf_allocateVector", mode, n);
         SEXPTYPE type = SEXPTYPE.mapInt(mode);
         if (n < 0) {
             throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED);
@@ -391,6 +417,7 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_allocateArray(int mode, Object dimsObj) {
+        RFFIUtils.traceUpCall("Rf_allocateArray", mode, dimsObj);
         RIntVector dims = (RIntVector) dimsObj;
         int n = 1;
         int[] newDims = new int[dims.getLength()];
@@ -406,6 +433,7 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_allocateMatrix(int mode, int ncol, int nrow) {
+        RFFIUtils.traceUpCall("Rf_allocateMatrix", mode, ncol, nrow);
         SEXPTYPE type = SEXPTYPE.mapInt(mode);
         if (nrow < 0 || ncol < 0) {
             throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_EXTENTS_TO_MATRIX);
@@ -429,6 +457,7 @@ public class CallRFFIHelper {
     }
 
     public static int LENGTH(Object x) {
+        RFFIUtils.traceUpCall("LENGTH", x);
         if (x instanceof RAbstractContainer) {
             return ((RAbstractContainer) x).getLength();
         } else if (x == RNull.instance) {
@@ -443,17 +472,20 @@ public class CallRFFIHelper {
     }
 
     public static void SET_STRING_ELT(Object x, int i, Object v) {
+        RFFIUtils.traceUpCall("SET_STRING_ELT", x, i, v);
         RStringVector vector = guaranteeInstanceOf(x, RStringVector.class);
         CharSXPWrapper element = guaranteeInstanceOf(v, CharSXPWrapper.class);
         vector.setElement(i, element.getContents());
     }
 
     public static void SET_VECTOR_ELT(Object x, int i, Object v) {
+        RFFIUtils.traceUpCall("SET_VECTOR_ELT", i, v);
         RList list = guaranteeInstanceOf(x, RList.class);
         list.setElement(i, v);
     }
 
     public static byte[] RAW(Object x) {
+        RFFIUtils.traceUpCall("RAW", x);
         if (x instanceof RRawVector) {
             return ((RRawVector) x).getDataWithoutCopying();
         } else if (x instanceof RRaw) {
@@ -464,6 +496,7 @@ public class CallRFFIHelper {
     }
 
     public static byte[] LOGICAL(Object x) {
+        RFFIUtils.traceUpCall("LOGICAL", x);
         if (x instanceof RLogicalVector) {
             return ((RLogicalVector) x).getDataWithoutCopying();
         } else if (x instanceof Byte) {
@@ -474,6 +507,7 @@ public class CallRFFIHelper {
     }
 
     public static int[] INTEGER(Object x) {
+        RFFIUtils.traceUpCall("INTEGER", x);
         if (x instanceof RIntVector) {
             return ((RIntVector) x).getDataWithoutCopying();
         } else if (x instanceof RIntSequence) {
@@ -494,6 +528,7 @@ public class CallRFFIHelper {
     }
 
     public static double[] REAL(Object x) {
+        RFFIUtils.traceUpCall("REAL", x);
         if (x instanceof RDoubleVector) {
             return ((RDoubleVector) x).getDataWithoutCopying();
         } else if (x instanceof RDoubleSequence) {
@@ -510,17 +545,20 @@ public class CallRFFIHelper {
     }
 
     public static Object STRING_ELT(Object x, int i) {
+        RFFIUtils.traceUpCall("STRING_ELT", x, i);
         RAbstractStringVector vector = guaranteeInstanceOf(RRuntime.asAbstractVector(x), RAbstractStringVector.class);
         return new CharSXPWrapper(vector.getDataAt(i));
     }
 
     public static Object VECTOR_ELT(Object x, int i) {
+        RFFIUtils.traceUpCall("VECTOR_ELT", x, i);
         Object vec = x;
         RAbstractListVector list = guaranteeInstanceOf(RRuntime.asAbstractVector(vec), RAbstractListVector.class);
         return list.getDataAt(i);
     }
 
     public static int NAMED(Object x) {
+        RFFIUtils.traceUpCall("NAMED", x);
         if (x instanceof RShareable) {
             return ((RShareable) x).isShared() ? 1 : 0;
         } else {
@@ -529,6 +567,7 @@ public class CallRFFIHelper {
     }
 
     public static Object SET_TYPEOF_FASTR(Object x, int v) {
+        RFFIUtils.traceUpCall("SET_TYPEOF_FASTR", x, v);
         int code = SEXPTYPE.gnuRCodeForObject(x);
         if (code == SEXPTYPE.LISTSXP.code && v == SEXPTYPE.LANGSXP.code) {
             RList l;
@@ -544,6 +583,7 @@ public class CallRFFIHelper {
     }
 
     public static int TYPEOF(Object x) {
+        RFFIUtils.traceUpCall("TYPEOF", x);
         if (x instanceof CharSXPWrapper) {
             return SEXPTYPE.CHARSXP.code;
         } else {
@@ -552,6 +592,7 @@ public class CallRFFIHelper {
     }
 
     public static int OBJECT(Object x) {
+        RFFIUtils.traceUpCall("OBJECT", x);
         if (x instanceof RAttributable) {
             return ((RAttributable) x).getAttr(RRuntime.CLASS_ATTR_KEY) == null ? 0 : 1;
         } else {
@@ -560,11 +601,13 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_duplicate(Object x) {
+        RFFIUtils.traceUpCall("Rf_duplicate", x);
         guaranteeInstanceOf(x, RAbstractVector.class);
         return ((RAbstractVector) x).copy();
     }
 
     public static int Rf_anyDuplicated(Object x, int fromLast) {
+        RFFIUtils.traceUpCall("Rf_anyDuplicated", x, fromLast);
         RAbstractVector vec = (RAbstractVector) x;
         if (vec.getLength() == 0) {
             return 0;
@@ -574,11 +617,13 @@ public class CallRFFIHelper {
     }
 
     public static Object PRINTNAME(Object x) {
+        RFFIUtils.traceUpCall("PRINTNAME", x);
         guaranteeInstanceOf(x, RSymbol.class);
         return new CharSXPWrapper(((RSymbol) x).getName());
     }
 
     public static Object TAG(Object e) {
+        RFFIUtils.traceUpCall("TAG", e);
         if (e instanceof RPairList) {
             return ((RPairList) e).getTag();
         } else {
@@ -589,24 +634,28 @@ public class CallRFFIHelper {
     }
 
     public static Object CAR(Object e) {
+        RFFIUtils.traceUpCall("CAR", e);
         guaranteeInstanceOf(e, RPairList.class);
         Object car = ((RPairList) e).car();
         return car;
     }
 
     public static Object CDR(Object e) {
+        RFFIUtils.traceUpCall("CDR", e);
         guaranteeInstanceOf(e, RPairList.class);
         Object cdr = ((RPairList) e).cdr();
         return cdr;
     }
 
     public static Object CADR(Object e) {
+        RFFIUtils.traceUpCall("CADR", e);
         guaranteeInstanceOf(e, RPairList.class);
         Object cadr = ((RPairList) e).cadr();
         return cadr;
     }
 
     public static Object SET_TAG(Object x, Object y) {
+        RFFIUtils.traceUpCall("SET_TAG", x, y);
         if (x instanceof RPairList) {
             ((RPairList) x).setTag(y);
         } else {
@@ -618,18 +667,21 @@ public class CallRFFIHelper {
     }
 
     public static Object SETCAR(Object x, Object y) {
+        RFFIUtils.traceUpCall("SETCAR", x, y);
         guaranteeInstanceOf(x, RPairList.class);
         ((RPairList) x).setCar(y);
         return x; // TODO check or y?
     }
 
     public static Object SETCDR(Object x, Object y) {
+        RFFIUtils.traceUpCall("SETCDR", x, y);
         guaranteeInstanceOf(x, RPairList.class);
         ((RPairList) x).setCdr(y);
         return x; // TODO check or y?
     }
 
     public static Object SYMVALUE(Object x) {
+        RFFIUtils.traceUpCall("SYMVALUE", x);
         if (!(x instanceof RSymbol)) {
             throw RInternalError.shouldNotReachHere();
         }
@@ -642,6 +694,7 @@ public class CallRFFIHelper {
     }
 
     public static void SET_SYMVALUE(Object x, Object v) {
+        RFFIUtils.traceUpCall("SET_SYMVALUE", x, v);
         if (!(x instanceof RSymbol)) {
             throw RInternalError.shouldNotReachHere();
         }
@@ -649,11 +702,13 @@ public class CallRFFIHelper {
     }
 
     public static Object R_FindNamespace(Object name) {
+        RFFIUtils.traceUpCall("R_FindNamespace", name);
         Object result = RContext.getInstance().stateREnvironment.getNamespaceRegistry().get(RRuntime.asString(name));
         return result;
     }
 
     public static Object Rf_eval(Object expr, Object env) {
+        RFFIUtils.traceUpCall("Rf_eval", expr, env);
         guarantee(env instanceof REnvironment);
         Object result;
         if (expr instanceof RPromise) {
@@ -670,6 +725,7 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_findfun(Object symbolObj, Object envObj) {
+        RFFIUtils.traceUpCall("Rf_findfun", symbolObj, envObj);
         guarantee(envObj instanceof REnvironment);
         REnvironment env = (REnvironment) envObj;
         guarantee(symbolObj instanceof RSymbol);
@@ -685,12 +741,14 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_GetOption1(Object tag) {
+        RFFIUtils.traceUpCall("Rf_GetOption1", tag);
         guarantee(tag instanceof RSymbol);
         Object result = RContext.getInstance().stateROptions.getValue(((RSymbol) tag).getName());
         return result;
     }
 
     public static void Rf_gsetVar(Object symbol, Object value, Object rho) {
+        RFFIUtils.traceUpCall("Rf_gsetVar", symbol, value, rho);
         guarantee(symbol instanceof RSymbol);
         REnvironment baseEnv = RContext.getInstance().stateREnvironment.getBaseEnv();
         guarantee(rho == baseEnv);
@@ -702,6 +760,7 @@ public class CallRFFIHelper {
     }
 
     public static void DUPLICATE_ATTRIB(Object to, Object from) {
+        RFFIUtils.traceUpCall("DUPLICATE_ATTRIB", to, from);
         if (from instanceof RAttributable) {
             guaranteeInstanceOf(to, RAttributable.class);
             RAttributes attributes = ((RAttributable) from).getAttributes();
@@ -711,12 +770,14 @@ public class CallRFFIHelper {
     }
 
     public static REnvironment Rf_createNewEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
+        RFFIUtils.traceUpCall("Rf_createNewEnv", parent, name, hashed, initialSize);
         REnvironment env = RDataFactory.createNewEnv(name, hashed, initialSize);
         RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
         return env;
     }
 
     public static int R_computeIdentical(Object x, Object y, int flags) {
+        RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
         RFunction indenticalBuiltin = RContext.lookupBuiltin("identical");
         Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
                         RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0))));
@@ -725,16 +786,19 @@ public class CallRFFIHelper {
 
     @SuppressWarnings("unused")
     public static void Rf_copyListMatrix(Object s, Object t, int byrow) {
+        RFFIUtils.traceUpCall("Rf_copyListMatrix", t, byrow);
         throw unimplemented();
     }
 
     @SuppressWarnings("unused")
     public static void Rf_copyMatrix(Object s, Object t, int byrow) {
+        RFFIUtils.traceUpCall("Rf_copyMatrix", t, byrow);
         throw unimplemented();
     }
 
     @SuppressWarnings("unused")
     public static Object R_tryEval(Object expr, Object env, boolean silent) {
+        RFFIUtils.traceUpCall("R_tryEval", expr, env, silent);
         Object handlerStack = RErrorHandling.getHandlerStack();
         Object restartStack = RErrorHandling.getRestartStack();
         try {
@@ -749,8 +813,37 @@ public class CallRFFIHelper {
         }
     }
 
+    public static int RDEBUG(Object x) {
+        RFFIUtils.traceUpCall("RDEBUG", x);
+        RFunction func = guaranteeInstanceOf(x, RFunction.class);
+        return RContext.getRRuntimeASTAccess().isDebugged(func) ? 1 : 0;
+    }
+
+    public static void SET_RDEBUG(Object x, int v) {
+        RFFIUtils.traceUpCall("SET_RDEBUG", x, v);
+        RFunction func = guaranteeInstanceOf(x, RFunction.class);
+        if (v == 1) {
+            RContext.getRRuntimeASTAccess().enableDebug(func, false);
+        } else {
+            RContext.getRRuntimeASTAccess().disableDebug(func);
+        }
+    }
+
+    public static int RSTEP(Object x) {
+        RFFIUtils.traceUpCall("RSTEP", x);
+        RFunction func = guaranteeInstanceOf(x, RFunction.class);
+        throw RInternalError.unimplemented("RSTEP");
+    }
+
+    public static void SET_RSTEP(Object x, int v) {
+        RFFIUtils.traceUpCall("SET_RSTEP", x, v);
+        RFunction func = guaranteeInstanceOf(x, RFunction.class);
+        throw RInternalError.unimplemented("SET_RSTEP");
+    }
+
     @SuppressWarnings("unused")
     private static String R_HomeDir() {
+        RFFIUtils.traceUpCall("R_HomeDir");
         return REnvVars.rHome();
     }
 
@@ -766,26 +859,32 @@ public class CallRFFIHelper {
     }
 
     public static Object getGlobalEnv() {
+        RFFIUtils.traceUpCall("getGlobalEnv");
         return RContext.getInstance().stateREnvironment.getGlobalEnv();
     }
 
     public static Object getBaseEnv() {
+        RFFIUtils.traceUpCall("getBaseEnv");
         return RContext.getInstance().stateREnvironment.getBaseEnv();
     }
 
     public static Object getBaseNamespace() {
+        RFFIUtils.traceUpCall("getBaseNamespace");
         return RContext.getInstance().stateREnvironment.getBaseNamespace();
     }
 
     public static Object getNamespaceRegistry() {
+        RFFIUtils.traceUpCall("getNamespaceRegistry");
         return RContext.getInstance().stateREnvironment.getNamespaceRegistry();
     }
 
     public static int isInteractive() {
+        RFFIUtils.traceUpCall("isInteractive");
         return RContext.getInstance().isInteractive() ? 1 : 0;
     }
 
     public static int isS4Object(Object x) {
+        RFFIUtils.traceUpCall("isS4Object");
         return x instanceof RS4Object ? 1 : 0;
     }
 
@@ -794,14 +893,17 @@ public class CallRFFIHelper {
     }
 
     public static void getRNGstate() {
+        RFFIUtils.traceUpCall("getRNGstate");
         RRNG.getRNGState();
     }
 
     public static void putRNGstate() {
+        RFFIUtils.traceUpCall("putRNGstate");
         RRNG.updateDotRandomSeed();
     }
 
     public static double unifRand() {
+        RFFIUtils.traceUpCall("unifRand");
         return RRNG.unifRand();
     }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_CallRFFI.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_CallRFFI.java
index 83957a8d909bc91d59694c97b306d0cd789c45b7..0964f60ebd84d23a2fd8a7b28791755277029172 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_CallRFFI.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_CallRFFI.java
@@ -22,7 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.ffi.jnr;
 
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceCall;
+import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCall;
 
 import java.util.concurrent.Semaphore;
 
@@ -66,7 +66,7 @@ public class JNI_CallRFFI implements CallRFFI {
             throw new RInternalError(ex, "error while loading " + librffiPath);
         }
         System.load(librffiPath);
-        traceCall("initialize");
+        traceDownCall("initialize");
         initialize(RFFIVariables.values());
     }
 
@@ -74,7 +74,7 @@ public class JNI_CallRFFI implements CallRFFI {
 
     @Override
     public Object invokeCall(long address, String name, Object[] args) {
-        traceCall(name, args);
+        traceDownCall(name, args);
         try {
             inCritical.acquire();
             switch (args.length) {
@@ -130,7 +130,7 @@ public class JNI_CallRFFI implements CallRFFI {
 
     @Override
     public void invokeVoidCall(long address, String name, Object[] args) {
-        traceCall(name, args);
+        traceDownCall(name, args);
         try {
             inCritical.acquire();
             switch (args.length) {
@@ -155,7 +155,7 @@ public class JNI_CallRFFI implements CallRFFI {
 
     @Override
     public void setTempDir(String tempDir) {
-        traceCall("setTempDir", tempDir);
+        traceDownCall("setTempDir", tempDir);
         try {
             inCritical.acquire();
             RFFIVariables.setTempDir(tempDir);
@@ -168,7 +168,7 @@ public class JNI_CallRFFI implements CallRFFI {
 
     @Override
     public void setInteractive(boolean interactive) {
-        traceCall("setInteractive", interactive);
+        traceDownCall("setInteractive", interactive);
         try {
             inCritical.acquire();
             nativeSetInteractive(interactive);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
index 0b0c7bdd7e31cd1e176f7b713f397308f78eebd1..a6f96c9b38872c451e009a865fcec257c5b62413 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
@@ -170,11 +170,6 @@ public interface RRuntimeASTAccess {
      */
     void traceAllFunctions();
 
-    /**
-     * Project circularity workaround.
-     */
-    void enableDebug(RFunction func);
-
     /**
      * Project circularity workaround. Equivalent to
      * RASTUtils.unwrap(promise.getRep()).asRSyntaxNode().
@@ -190,4 +185,10 @@ public interface RRuntimeASTAccess {
 
     RBaseNode createConstantNode(Object o);
 
+    boolean enableDebug(RFunction func, boolean once);
+
+    boolean disableDebug(RFunction func);
+
+    boolean isDebugged(RFunction func);
+
 }