diff options
Diffstat (limited to 'runtime/openjdkjvmti')
| -rw-r--r-- | runtime/openjdkjvmti/OpenjdkJvmTi.cc | 2 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_method.cc | 59 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_method.h | 5 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_redefine.cc | 74 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_redefine.h | 8 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_stack.cc | 10 |
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) { |