ART: Add GetFrameCount and GetFrameLocation

Add support for GetFrameCount and GetFrameLocation. Add tests.

Bug: 31684812
Test: m test-art-host-run-test-911-get-stack-trace
Change-Id: I7656e243f614eb0ceb5fcd6841128119fad89968
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index f853387..d162e8a 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -20,6 +20,7 @@
 
 #include "android-base/stringprintf.h"
 
+#include "android-base/stringprintf.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "jni.h"
@@ -202,5 +203,55 @@
   return ret;
 }
 
+extern "C" JNIEXPORT jint JNICALL Java_Frames_getFrameCount(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread) {
+  jint count;
+  jvmtiError result = jvmti_env->GetFrameCount(thread, &count);
+  if (JvmtiErrorToException(env, result)) {
+    return -1;
+  }
+  return count;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Frames_getFrameLocation(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread, jint depth) {
+  jmethodID method;
+  jlocation location;
+
+  jvmtiError result = jvmti_env->GetFrameLocation(thread, depth, &method, &location);
+  if (JvmtiErrorToException(env, result)) {
+    return nullptr;
+  }
+
+  auto callback = [&](jint index) -> jobject {
+    switch (index) {
+      case 0:
+      {
+        jclass decl_class;
+        jvmtiError class_result = jvmti_env->GetMethodDeclaringClass(method, &decl_class);
+        if (JvmtiErrorToException(env, class_result)) {
+          return nullptr;
+        }
+        jint modifiers;
+        jvmtiError mod_result = jvmti_env->GetMethodModifiers(method, &modifiers);
+        if (JvmtiErrorToException(env, mod_result)) {
+          return nullptr;
+        }
+        constexpr jint kStatic = 0x8;
+        return env->ToReflectedMethod(decl_class,
+                                      method,
+                                      (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE);
+      }
+      case 1:
+        return env->NewStringUTF(
+            android::base::StringPrintf("%x", static_cast<uint32_t>(location)).c_str());
+    }
+    LOG(FATAL) << "Unreachable";
+    UNREACHABLE();
+  };
+  jobjectArray ret = CreateObjectArray(env, 2, "java/lang/Object", callback);
+  return ret;
+}
+
 }  // namespace Test911GetStackTrace
 }  // namespace art