summaryrefslogtreecommitdiff
path: root/runtime/openjdkjvmti
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/openjdkjvmti')
-rw-r--r--runtime/openjdkjvmti/OpenjdkJvmTi.cc2
-rw-r--r--runtime/openjdkjvmti/ti_method.cc59
-rw-r--r--runtime/openjdkjvmti/ti_method.h5
-rw-r--r--runtime/openjdkjvmti/ti_redefine.cc74
-rw-r--r--runtime/openjdkjvmti/ti_redefine.h8
-rw-r--r--runtime/openjdkjvmti/ti_stack.cc10
6 files changed, 134 insertions, 24 deletions
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 1ad3f0814f..5f97b60079 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -700,7 +700,7 @@ class JvmtiFunctions {
jmethodID method,
jint* entry_count_ptr,
jvmtiLineNumberEntry** table_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return MethodUtil::GetLineNumberTable(env, method, entry_count_ptr, table_ptr);
}
static jvmtiError GetMethodLocation(jvmtiEnv* env,
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index ffa5ac7e32..a0a09239fa 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -130,4 +130,63 @@ jvmtiError MethodUtil::GetMethodModifiers(jvmtiEnv* env ATTRIBUTE_UNUSED,
return ERR(NONE);
}
+using LineNumberContext = std::vector<jvmtiLineNumberEntry>;
+
+static bool CollectLineNumbers(void* void_context, const art::DexFile::PositionInfo& entry) {
+ LineNumberContext* context = reinterpret_cast<LineNumberContext*>(void_context);
+ jvmtiLineNumberEntry jvmti_entry = { static_cast<jlocation>(entry.address_),
+ static_cast<jint>(entry.line_) };
+ context->push_back(jvmti_entry);
+ return false; // Collect all, no early exit.
+}
+
+jvmtiError MethodUtil::GetLineNumberTable(jvmtiEnv* env,
+ jmethodID method,
+ jint* entry_count_ptr,
+ jvmtiLineNumberEntry** table_ptr) {
+ if (method == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+ art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
+ DCHECK(!art_method->IsRuntimeMethod());
+
+ const art::DexFile::CodeItem* code_item;
+ const art::DexFile* dex_file;
+ {
+ art::ScopedObjectAccess soa(art::Thread::Current());
+
+ if (art_method->IsProxyMethod()) {
+ return ERR(ABSENT_INFORMATION);
+ }
+ if (art_method->IsNative()) {
+ return ERR(NATIVE_METHOD);
+ }
+ if (entry_count_ptr == nullptr || table_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ code_item = art_method->GetCodeItem();
+ dex_file = art_method->GetDexFile();
+ DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
+ }
+
+ LineNumberContext context;
+ bool success = dex_file->DecodeDebugPositionInfo(code_item, CollectLineNumbers, &context);
+ if (!success) {
+ return ERR(ABSENT_INFORMATION);
+ }
+
+ unsigned char* data;
+ jlong mem_size = context.size() * sizeof(jvmtiLineNumberEntry);
+ jvmtiError alloc_error = env->Allocate(mem_size, &data);
+ if (alloc_error != ERR(NONE)) {
+ return alloc_error;
+ }
+ *table_ptr = reinterpret_cast<jvmtiLineNumberEntry*>(data);
+ memcpy(*table_ptr, context.data(), mem_size);
+ *entry_count_ptr = static_cast<jint>(context.size());
+
+ return ERR(NONE);
+}
+
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_method.h b/runtime/openjdkjvmti/ti_method.h
index 43f11f97ec..fb2fbb2b27 100644
--- a/runtime/openjdkjvmti/ti_method.h
+++ b/runtime/openjdkjvmti/ti_method.h
@@ -52,6 +52,11 @@ class MethodUtil {
static jvmtiError GetMethodModifiers(jvmtiEnv* env,
jmethodID method,
jint* modifiers_ptr);
+
+ static jvmtiError GetLineNumberTable(jvmtiEnv* env,
+ jmethodID method,
+ jint* entry_count_ptr,
+ jvmtiLineNumberEntry** table_ptr);
};
} // namespace openjdkjvmti
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index d0349b987f..68815e7de0 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -33,6 +33,8 @@
#include <limits>
+#include "android-base/stringprintf.h"
+
#include "art_jvmti.h"
#include "base/logging.h"
#include "events-inl.h"
@@ -49,13 +51,15 @@
namespace openjdkjvmti {
+using android::base::StringPrintf;
+
// Moves dex data to an anonymous, read-only mmap'd region.
std::unique_ptr<art::MemMap> Redefiner::MoveDataToMemMap(const std::string& original_location,
jint data_len,
unsigned char* dex_data,
std::string* error_msg) {
std::unique_ptr<art::MemMap> map(art::MemMap::MapAnonymous(
- art::StringPrintf("%s-transformed", original_location.c_str()).c_str(),
+ StringPrintf("%s-transformed", original_location.c_str()).c_str(),
nullptr,
data_len,
PROT_READ|PROT_WRITE,
@@ -246,9 +250,9 @@ art::mirror::LongArray* Redefiner::AllocateDexFileCookie(
}
void Redefiner::RecordFailure(jvmtiError result, const std::string& error_msg) {
- *error_msg_ = art::StringPrintf("Unable to perform redefinition of '%s': %s",
- class_sig_,
- error_msg.c_str());
+ *error_msg_ = StringPrintf("Unable to perform redefinition of '%s': %s",
+ class_sig_,
+ error_msg.c_str());
result_ = result;
}
@@ -392,19 +396,14 @@ void Redefiner::RestoreJavaDexFile(art::ObjPtr<art::mirror::Object> java_dex_fil
}
}
-// Performs updates to class that will allow us to verify it.
-bool Redefiner::UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
- art::ObjPtr<art::mirror::DexCache> new_dex_cache) {
+bool Redefiner::UpdateMethods(art::ObjPtr<art::mirror::Class> mclass,
+ art::ObjPtr<art::mirror::DexCache> new_dex_cache,
+ const art::DexFile::ClassDef& class_def) {
art::ClassLinker* linker = runtime_->GetClassLinker();
art::PointerSize image_pointer_size = linker->GetImagePointerSize();
- const art::DexFile::ClassDef* class_def = art::OatFile::OatDexFile::FindClassDef(
- *dex_file_, class_sig_, art::ComputeModifiedUtf8Hash(class_sig_));
- if (class_def == nullptr) {
- RecordFailure(ERR(INVALID_CLASS_FORMAT), "Unable to find ClassDef!");
- return false;
- }
- const art::DexFile::TypeId& declaring_class_id = dex_file_->GetTypeId(class_def->class_idx_);
+ const art::DexFile::TypeId& declaring_class_id = dex_file_->GetTypeId(class_def.class_idx_);
const art::DexFile& old_dex_file = mclass->GetDexFile();
+ // Update methods.
for (art::ArtMethod& method : mclass->GetMethods(image_pointer_size)) {
const art::DexFile::StringId* new_name_id = dex_file_->FindStringId(method.GetName());
art::dex::TypeIndex method_return_idx =
@@ -431,15 +430,58 @@ bool Redefiner::UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
uint32_t dex_method_idx = dex_file_->GetIndexForMethodId(*method_id);
method.SetDexMethodIndex(dex_method_idx);
linker->SetEntryPointsToInterpreter(&method);
- method.SetCodeItemOffset(dex_file_->FindCodeItemOffset(*class_def, dex_method_idx));
+ method.SetCodeItemOffset(dex_file_->FindCodeItemOffset(class_def, dex_method_idx));
method.SetDexCacheResolvedMethods(new_dex_cache->GetResolvedMethods(), image_pointer_size);
method.SetDexCacheResolvedTypes(new_dex_cache->GetResolvedTypes(), image_pointer_size);
}
+ return true;
+}
+
+bool Redefiner::UpdateFields(art::ObjPtr<art::mirror::Class> mclass) {
+ // TODO The IFields & SFields pointers should be combined like the methods_ arrays were.
+ for (auto fields_iter : {mclass->GetIFields(), mclass->GetSFields()}) {
+ for (art::ArtField& field : fields_iter) {
+ std::string declaring_class_name;
+ const art::DexFile::TypeId* new_declaring_id =
+ dex_file_->FindTypeId(field.GetDeclaringClass()->GetDescriptor(&declaring_class_name));
+ const art::DexFile::StringId* new_name_id = dex_file_->FindStringId(field.GetName());
+ const art::DexFile::TypeId* new_type_id = dex_file_->FindTypeId(field.GetTypeDescriptor());
+ // TODO Handle error, cleanup.
+ CHECK(new_name_id != nullptr && new_type_id != nullptr && new_declaring_id != nullptr);
+ const art::DexFile::FieldId* new_field_id =
+ dex_file_->FindFieldId(*new_declaring_id, *new_name_id, *new_type_id);
+ CHECK(new_field_id != nullptr);
+ // We only need to update the index since the other data in the ArtField cannot be updated.
+ field.SetDexFieldIndex(dex_file_->GetIndexForFieldId(*new_field_id));
+ }
+ }
+ return true;
+}
+
+// Performs updates to class that will allow us to verify it.
+bool Redefiner::UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
+ art::ObjPtr<art::mirror::DexCache> new_dex_cache) {
+ const art::DexFile::ClassDef* class_def = art::OatFile::OatDexFile::FindClassDef(
+ *dex_file_, class_sig_, art::ComputeModifiedUtf8Hash(class_sig_));
+ if (class_def == nullptr) {
+ RecordFailure(ERR(INVALID_CLASS_FORMAT), "Unable to find ClassDef!");
+ return false;
+ }
+ if (!UpdateMethods(mclass, new_dex_cache, *class_def)) {
+ // TODO Investigate appropriate error types.
+ RecordFailure(ERR(INTERNAL), "Unable to update class methods.");
+ return false;
+ }
+ if (!UpdateFields(mclass)) {
+ // TODO Investigate appropriate error types.
+ RecordFailure(ERR(INTERNAL), "Unable to update class fields.");
+ return false;
+ }
+
// Update the class fields.
// Need to update class last since the ArtMethod gets its DexFile from the class (which is needed
// to call GetReturnTypeDescriptor and GetParameterTypeList above).
mclass->SetDexCache(new_dex_cache.Ptr());
- mclass->SetDexCacheStrings(new_dex_cache->GetStrings());
mclass->SetDexClassDefIndex(dex_file_->GetIndexForClassDef(*class_def));
mclass->SetDexTypeIndex(dex_file_->GetIndexForTypeId(*dex_file_->FindTypeId(class_sig_)));
return true;
diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h
index c819acd5ac..73cfc2b69b 100644
--- a/runtime/openjdkjvmti/ti_redefine.h
+++ b/runtime/openjdkjvmti/ti_redefine.h
@@ -159,6 +159,14 @@ class Redefiner {
art::ObjPtr<art::mirror::LongArray> original_cookie)
REQUIRES(art::Locks::mutator_lock_);
+ bool UpdateFields(art::ObjPtr<art::mirror::Class> mclass)
+ REQUIRES(art::Locks::mutator_lock_);
+
+ bool UpdateMethods(art::ObjPtr<art::mirror::Class> mclass,
+ art::ObjPtr<art::mirror::DexCache> new_dex_cache,
+ const art::DexFile::ClassDef& class_def)
+ REQUIRES(art::Locks::mutator_lock_);
+
bool UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
art::ObjPtr<art::mirror::DexCache> new_dex_cache)
REQUIRES(art::Locks::mutator_lock_);
diff --git a/runtime/openjdkjvmti/ti_stack.cc b/runtime/openjdkjvmti/ti_stack.cc
index 6f8976f03d..579fb50ecc 100644
--- a/runtime/openjdkjvmti/ti_stack.cc
+++ b/runtime/openjdkjvmti/ti_stack.cc
@@ -67,14 +67,10 @@ struct GetStackTraceVisitor : public art::StackVisitor {
m = m->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
jmethodID id = art::jni::EncodeArtMethod(m);
- art::mirror::DexCache* dex_cache = m->GetDexCache();
- int32_t line_number = -1;
- if (dex_cache != nullptr) { // be tolerant of bad input
- const art::DexFile* dex_file = dex_cache->GetDexFile();
- line_number = art::annotations::GetLineNumFromPC(dex_file, m, GetDexPc(false));
- }
+ uint32_t dex_pc = GetDexPc(false);
+ jlong dex_location = (dex_pc == art::DexFile::kDexNoIndex) ? -1 : static_cast<jlong>(dex_pc);
- jvmtiFrameInfo info = { id, static_cast<jlong>(line_number) };
+ jvmtiFrameInfo info = { id, dex_location };
frames.push_back(info);
if (stop == 1) {