From 4998374789fc62c147027eef022c74a97949ac6e Mon Sep 17 00:00:00 2001 From: Sebastien Hertz Date: Thu, 11 Jun 2015 18:42:58 +0200 Subject: [PATCH] JDWP: update handling of 8-bit and 16-bit fields We must use special getter/setter for types smaller than int: boolean, byte, char and short. However, JDWP still requires to treat: - int and float as 32-bit values - long and double as 64-bit values Bug: 21746739 (cherry picked from commit 05c26b30843dd8283c703356e75d51726e8b8e3a) Change-Id: I2d667291974e191f2c9b10311ce02435b902dd0c --- runtime/debugger.cc | 170 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 121 insertions(+), 49 deletions(-) diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 3c6f98af1..546a1fb94 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1762,6 +1762,51 @@ JDWP::JdwpTag Dbg::GetStaticFieldBasicTag(JDWP::FieldId field_id) { return BasicTagFromDescriptor(FromFieldId(field_id)->GetTypeDescriptor()); } +static JValue GetArtFieldValue(ArtField* f, mirror::Object* o) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Primitive::Type fieldType = f->GetTypeAsPrimitiveType(); + JValue field_value; + switch (fieldType) { + case Primitive::kPrimBoolean: + field_value.SetZ(f->GetBoolean(o)); + return field_value; + + case Primitive::kPrimByte: + field_value.SetB(f->GetByte(o)); + return field_value; + + case Primitive::kPrimChar: + field_value.SetC(f->GetChar(o)); + return field_value; + + case Primitive::kPrimShort: + field_value.SetS(f->GetShort(o)); + return field_value; + + case Primitive::kPrimInt: + case Primitive::kPrimFloat: + // Int and Float must be treated as 32-bit values in JDWP. + field_value.SetI(f->GetInt(o)); + return field_value; + + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + // Long and Double must be treated as 64-bit values in JDWP. + field_value.SetJ(f->GetLong(o)); + return field_value; + + case Primitive::kPrimNot: + field_value.SetL(f->GetObject(o)); + return field_value; + + case Primitive::kPrimVoid: + LOG(FATAL) << "Attempt to read from field of type 'void'"; + UNREACHABLE(); + } + LOG(FATAL) << "Attempt to read from field of unknown type"; + UNREACHABLE(); +} + static JDWP::JdwpError GetFieldValueImpl(JDWP::RefTypeId ref_type_id, JDWP::ObjectId object_id, JDWP::FieldId field_id, JDWP::ExpandBuf* pReply, bool is_static) @@ -1796,27 +1841,17 @@ static JDWP::JdwpError GetFieldValueImpl(JDWP::RefTypeId ref_type_id, JDWP::Obje } } else { if (f->IsStatic()) { - LOG(WARNING) << "Ignoring non-nullptr receiver for ObjectReference.SetValues on static field " - << PrettyField(f); + LOG(WARNING) << "Ignoring non-nullptr receiver for ObjectReference.GetValues" + << " on static field " << PrettyField(f); } } if (f->IsStatic()) { o = f->GetDeclaringClass(); } + JValue field_value(GetArtFieldValue(f, o)); JDWP::JdwpTag tag = BasicTagFromDescriptor(f->GetTypeDescriptor()); - JValue field_value; - if (tag == JDWP::JT_VOID) { - LOG(FATAL) << "Unknown tag: " << tag; - } else if (!IsPrimitiveTag(tag)) { - field_value.SetL(f->GetObject(o)); - } else if (tag == JDWP::JT_DOUBLE || tag == JDWP::JT_LONG) { - field_value.SetJ(f->Get64(o)); - } else { - field_value.SetI(f->Get32(o)); - } Dbg::OutputJValue(tag, &field_value, pReply); - return JDWP::ERR_NONE; } @@ -1830,6 +1865,76 @@ JDWP::JdwpError Dbg::GetStaticFieldValue(JDWP::RefTypeId ref_type_id, JDWP::Fiel return GetFieldValueImpl(ref_type_id, 0, field_id, pReply, true); } +static JDWP::JdwpError SetArtFieldValue(ArtField* f, mirror::Object* o, uint64_t value, int width) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Primitive::Type fieldType = f->GetTypeAsPrimitiveType(); + // Debugging only happens at runtime so we know we are not running in a transaction. + static constexpr bool kNoTransactionMode = false; + switch (fieldType) { + case Primitive::kPrimBoolean: + CHECK_EQ(width, 1); + f->SetBoolean(o, static_cast(value)); + return JDWP::ERR_NONE; + + case Primitive::kPrimByte: + CHECK_EQ(width, 1); + f->SetByte(o, static_cast(value)); + return JDWP::ERR_NONE; + + case Primitive::kPrimChar: + CHECK_EQ(width, 2); + f->SetChar(o, static_cast(value)); + return JDWP::ERR_NONE; + + case Primitive::kPrimShort: + CHECK_EQ(width, 2); + f->SetShort(o, static_cast(value)); + return JDWP::ERR_NONE; + + case Primitive::kPrimInt: + case Primitive::kPrimFloat: + CHECK_EQ(width, 4); + // Int and Float must be treated as 32-bit values in JDWP. + f->SetInt(o, static_cast(value)); + return JDWP::ERR_NONE; + + case Primitive::kPrimLong: + case Primitive::kPrimDouble: + CHECK_EQ(width, 8); + // Long and Double must be treated as 64-bit values in JDWP. + f->SetLong(o, value); + return JDWP::ERR_NONE; + + case Primitive::kPrimNot: { + JDWP::JdwpError error; + mirror::Object* v = Dbg::GetObjectRegistry()->Get(value, &error); + if (error != JDWP::ERR_NONE) { + return JDWP::ERR_INVALID_OBJECT; + } + if (v != nullptr) { + mirror::Class* field_type; + { + StackHandleScope<2> hs(Thread::Current()); + HandleWrapper h_v(hs.NewHandleWrapper(&v)); + HandleWrapper h_o(hs.NewHandleWrapper(&o)); + field_type = f->GetType(); + } + if (!field_type->IsAssignableFrom(v->GetClass())) { + return JDWP::ERR_INVALID_OBJECT; + } + } + f->SetObject(o, v); + return JDWP::ERR_NONE; + } + + case Primitive::kPrimVoid: + LOG(FATAL) << "Attempt to write to field of type 'void'"; + UNREACHABLE(); + } + LOG(FATAL) << "Attempt to write to field of unknown type"; + UNREACHABLE(); +} + static JDWP::JdwpError SetFieldValueImpl(JDWP::ObjectId object_id, JDWP::FieldId field_id, uint64_t value, int width, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -1848,47 +1953,14 @@ static JDWP::JdwpError SetFieldValueImpl(JDWP::ObjectId object_id, JDWP::FieldId } } else { if (f->IsStatic()) { - LOG(WARNING) << "Ignoring non-nullptr receiver for ObjectReference.SetValues on static field " << PrettyField(f); + LOG(WARNING) << "Ignoring non-nullptr receiver for ObjectReference.SetValues" + << " on static field " << PrettyField(f); } } if (f->IsStatic()) { o = f->GetDeclaringClass(); } - - JDWP::JdwpTag tag = BasicTagFromDescriptor(f->GetTypeDescriptor()); - - if (IsPrimitiveTag(tag)) { - if (tag == JDWP::JT_DOUBLE || tag == JDWP::JT_LONG) { - CHECK_EQ(width, 8); - // Debugging can't use transactional mode (runtime only). - f->Set64(o, value); - } else { - CHECK_LE(width, 4); - // Debugging can't use transactional mode (runtime only). - f->Set32(o, value); - } - } else { - mirror::Object* v = Dbg::GetObjectRegistry()->Get(value, &error); - if (error != JDWP::ERR_NONE) { - return JDWP::ERR_INVALID_OBJECT; - } - if (v != nullptr) { - mirror::Class* field_type; - { - StackHandleScope<2> hs(Thread::Current()); - HandleWrapper h_v(hs.NewHandleWrapper(&v)); - HandleWrapper h_o(hs.NewHandleWrapper(&o)); - field_type = f->GetType(); - } - if (!field_type->IsAssignableFrom(v->GetClass())) { - return JDWP::ERR_INVALID_OBJECT; - } - } - // Debugging can't use transactional mode (runtime only). - f->SetObject(o, v); - } - - return JDWP::ERR_NONE; + return SetArtFieldValue(f, o, value, width); } JDWP::JdwpError Dbg::SetFieldValue(JDWP::ObjectId object_id, JDWP::FieldId field_id, uint64_t value, -- 2.11.0