Return values for locals, so "locals" can show them.
Also implement a couple of other JDWP commands so jdb can show the length
of arrays and the value of strings.
Change-Id: Ib2a4dc2ee784ee10bdb924e91b0150aa8a96845d
diff --git a/src/context.h b/src/context.h
index b4a8b65..75eb8ca 100644
--- a/src/context.h
+++ b/src/context.h
@@ -3,6 +3,7 @@
#ifndef ART_SRC_CONTEXT_H_
#define ART_SRC_CONTEXT_H_
+#include <stddef.h>
#include <stdint.h>
namespace art {
@@ -34,6 +35,42 @@
virtual void DoLongJump() = 0;
};
+class VmapTable {
+ public:
+ VmapTable(const uint16_t* table) : table_(table) {
+ }
+
+ uint16_t operator[](size_t i) const {
+ return table_[i + 1];
+ }
+
+ size_t size() const {
+ return table_[0];
+ }
+
+ // Is register 'reg' in the context or on the stack?
+ bool IsInContext(size_t reg, uint32_t& vmap_offset) const {
+ vmap_offset = 0xEBAD0FF5;
+ // TODO: take advantage of the registers being ordered
+ for (size_t i = 0; i < size(); ++i) {
+ // Stop if we find what we are are looking for...
+ if (table_[i + 1] == reg) {
+ vmap_offset = i;
+ return true;
+ }
+ // ...or the INVALID_VREG that marks lr.
+ // TODO: x86?
+ if (table_[i + 1] == 0xffff) {
+ break;
+ }
+ }
+ return false;
+ }
+
+ private:
+ const uint16_t* table_;
+};
+
} // namespace art
#endif // ART_SRC_CONTEXT_H_
diff --git a/src/debugger.cc b/src/debugger.cc
index 1ad8cc2..976fb89 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -21,6 +21,7 @@
#include <set>
#include "class_linker.h"
+#include "context.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "stack_indirect_reference_table.h"
@@ -551,8 +552,9 @@
}
int Dbg::GetArrayLength(JDWP::ObjectId arrayId) {
- UNIMPLEMENTED(FATAL);
- return 0;
+ Object* o = gRegistry->Get<Object*>(arrayId);
+ Array* a = o->AsArray();
+ return a->GetLength();
}
uint8_t Dbg::GetArrayElementTag(JDWP::ObjectId arrayId) {
@@ -689,17 +691,14 @@
/*
* Reverse Eclipse hack.
*/
-static uint16_t DemangleSlot(uint16_t slot, Method** sp) {
- int newSlot = slot;
+static uint16_t DemangleSlot(uint16_t slot, Frame& f) {
if (slot == kEclipseWorkaroundSlot) {
- newSlot = 0;
+ return 0;
} else if (slot == 0) {
- Frame f;
- f.SetSP(sp);
Method* m = f.GetMethod();
- newSlot = m->NumRegisters() - m->NumIns();
+ return m->NumRegisters() - m->NumIns();
}
- return newSlot;
+ return slot;
}
void Dbg::OutputDeclaredFields(JDWP::RefTypeId refTypeId, bool withGeneric, JDWP::ExpandBuf* pReply) {
@@ -811,10 +810,10 @@
static void Callback(void* context, uint16_t slot, uint32_t startAddress, uint32_t endAddress, const char *name, const char *descriptor, const char *signature) {
DebugCallbackContext* pContext = reinterpret_cast<DebugCallbackContext*>(context);
- slot = MangleSlot(slot, name);
-
LOG(VERBOSE) << StringPrintf(" %2d: %d(%d) '%s' '%s' '%s' slot=%d", pContext->numItems, startAddress, endAddress - startAddress, name, descriptor, signature, slot);
+ slot = MangleSlot(slot, name);
+
expandBufAdd8BE(pContext->pReply, startAddress);
expandBufAddUtf8String(pContext->pReply, name);
expandBufAddUtf8String(pContext->pReply, descriptor);
@@ -875,9 +874,9 @@
UNIMPLEMENTED(FATAL);
}
-char* Dbg::StringToUtf8(JDWP::ObjectId strId) {
- UNIMPLEMENTED(FATAL);
- return NULL;
+std::string Dbg::StringToUtf8(JDWP::ObjectId strId) {
+ String* s = gRegistry->Get<String*>(strId);
+ return s->ToModifiedUtf8();
}
Thread* DecodeThread(JDWP::ObjectId threadId) {
@@ -1119,61 +1118,70 @@
void Dbg::GetLocalValue(JDWP::ObjectId threadId, JDWP::FrameId frameId, int slot, JDWP::JdwpTag tag, uint8_t* buf, size_t expectedLen) {
Method** sp = reinterpret_cast<Method**>(frameId);
- slot = DemangleSlot(slot, sp);
+ Frame f;
+ f.SetSP(sp);
+ uint16_t reg = DemangleSlot(slot, f);
+ Method* m = f.GetMethod();
+
+ const VmapTable vmap_table(m->GetVmapTableRaw());
+ uint32_t vmap_offset;
+ if (vmap_table.IsInContext(reg, vmap_offset)) {
+ UNIMPLEMENTED(FATAL) << "don't know how to pull locals from callee save frames: " << vmap_offset;
+ }
switch (tag) {
case JDWP::JT_BOOLEAN:
{
- UNIMPLEMENTED(WARNING) << "get boolean local " << slot;
CHECK_EQ(expectedLen, 1U);
- uint32_t intVal = 0; // framePtr[slot];
+ uint32_t intVal = static_cast<uint32_t>(f.GetVReg(m, reg));
+ LOG(WARNING) << "get boolean local " << reg << " = " << intVal;
JDWP::Set1(buf+1, intVal != 0);
}
break;
case JDWP::JT_BYTE:
{
- UNIMPLEMENTED(WARNING) << "get byte local " << slot;
CHECK_EQ(expectedLen, 1U);
- uint32_t intVal = 0; // framePtr[slot];
+ uint32_t intVal = static_cast<uint32_t>(f.GetVReg(m, reg));
+ LOG(WARNING) << "get byte local " << reg << " = " << intVal;
JDWP::Set1(buf+1, intVal);
}
break;
case JDWP::JT_SHORT:
case JDWP::JT_CHAR:
{
- UNIMPLEMENTED(WARNING) << "get 16-bit local " << slot;
CHECK_EQ(expectedLen, 2U);
- uint32_t intVal = 0; // framePtr[slot];
+ uint32_t intVal = static_cast<uint32_t>(f.GetVReg(m, reg));
+ LOG(WARNING) << "get short/char local " << reg << " = " << intVal;
JDWP::Set2BE(buf+1, intVal);
}
break;
case JDWP::JT_INT:
case JDWP::JT_FLOAT:
{
- UNIMPLEMENTED(WARNING) << "get 32-bit local " << slot;
CHECK_EQ(expectedLen, 4U);
- uint32_t intVal = 0; // framePtr[slot];
+ uint32_t intVal = static_cast<uint32_t>(f.GetVReg(m, reg));
+ LOG(WARNING) << "get int/float local " << reg << " = " << intVal;
JDWP::Set4BE(buf+1, intVal);
}
break;
case JDWP::JT_ARRAY:
{
- UNIMPLEMENTED(WARNING) << "get array local " << slot;
CHECK_EQ(expectedLen, sizeof(JDWP::ObjectId));
- Object* o = NULL; // (Object*)framePtr[slot];
+ Object* o = reinterpret_cast<Object*>(f.GetVReg(m, reg));
+ LOG(WARNING) << "get array local " << reg << " = " << o;
if (o != NULL && !Heap::IsHeapAddress(o)) {
- LOG(FATAL) << "slot " << slot << " expected to hold array: " << o;
+ LOG(FATAL) << "reg " << reg << " expected to hold array: " << o;
}
JDWP::SetObjectId(buf+1, gRegistry->Add(o));
}
break;
case JDWP::JT_OBJECT:
{
- UNIMPLEMENTED(WARNING) << "get object local " << slot;
CHECK_EQ(expectedLen, sizeof(JDWP::ObjectId));
- Object* o = NULL; // (Object*)framePtr[slot];
+ Object* o = reinterpret_cast<Object*>(f.GetVReg(m, reg));
+ LOG(WARNING) << "get object local " << reg << " = " << o;
if (o != NULL && !Heap::IsHeapAddress(o)) {
- LOG(FATAL) << "slot " << slot << " expected to hold object: " << o;
+ LOG(FATAL) << "reg " << reg << " expected to hold object: " << o;
}
tag = TagFromObject(o);
JDWP::SetObjectId(buf+1, gRegistry->Add(o));
@@ -1182,9 +1190,9 @@
case JDWP::JT_DOUBLE:
case JDWP::JT_LONG:
{
- UNIMPLEMENTED(WARNING) << "get 64-bit local " << slot;
+ UNIMPLEMENTED(WARNING) << "get 64-bit local " << reg;
CHECK_EQ(expectedLen, 8U);
- uint64_t longVal = 0; // memcpy(&longVal, &framePtr[slot], 8);
+ uint64_t longVal = 0; // memcpy(&longVal, &framePtr[reg], 8);
JDWP::Set8BE(buf+1, longVal);
}
break;
diff --git a/src/debugger.h b/src/debugger.h
index 538ebba..ec20458 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -171,7 +171,7 @@
static void GetStaticFieldValue(JDWP::RefTypeId refTypeId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply);
static void SetStaticFieldValue(JDWP::RefTypeId refTypeId, JDWP::FieldId fieldId, uint64_t rawValue, int width);
- static char* StringToUtf8(JDWP::ObjectId strId);
+ static std::string StringToUtf8(JDWP::ObjectId strId);
/*
* Thread, ThreadGroup, Frame
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 3d00930..c0a44e0 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -157,9 +157,7 @@
/* show detailed debug output */
if (resultTag == JT_STRING && exceptObjId == 0) {
if (resultValue != 0) {
- char* str = Dbg::StringToUtf8(resultValue);
- LOG(VERBOSE) << StringPrintf(" string '%s'", str);
- free(str);
+ LOG(VERBOSE) << " string '" << Dbg::StringToUtf8(resultValue) << "'";
} else {
LOG(VERBOSE) << " string (null)";
}
@@ -875,12 +873,11 @@
*/
static JdwpError handleSR_Value(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
ObjectId stringObject = ReadObjectId(&buf);
- char* str = Dbg::StringToUtf8(stringObject);
+ std::string str(Dbg::StringToUtf8(stringObject));
- LOG(VERBOSE) << StringPrintf(" Req for str %llx --> '%s'", stringObject, str);
+ LOG(VERBOSE) << StringPrintf(" Req for str %llx --> '%s'", stringObject, str.c_str());
- expandBufAddUtf8String(pReply, str);
- free(str);
+ expandBufAddUtf8String(pReply, str.c_str());
return ERR_NONE;
}
diff --git a/src/object.h b/src/object.h
index 91fca63..85542d2 100644
--- a/src/object.h
+++ b/src/object.h
@@ -808,22 +808,7 @@
SetMappingTable(reinterpret_cast<const uint32_t*>(mapping_table_offset));
}
- const uint16_t* GetVmapTable() const {
- const uint16_t* vmap = GetVmapTableRaw();
- if (vmap == NULL) {
- return vmap;
- }
- return vmap + 1;
- }
-
- uint16_t GetVmapTableLength() const {
- const uint16_t* vmap = GetVmapTableRaw();
- if (vmap == NULL) {
- return 0;
- }
- return *vmap;
- }
-
+ // Callers should wrap the uint16_t* in a VmapTable instance for convenient access.
const uint16_t* GetVmapTableRaw() const {
return GetFieldPtr<const uint16_t*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), false);
}
diff --git a/src/thread.cc b/src/thread.cc
index 8dc81c2..b6962f9 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1431,29 +1431,15 @@
verifier::PcToReferenceMap map(m);
const uint8_t* reg_bitmap = map.FindBitMap(m->ToDexPC(pc));
CHECK(reg_bitmap != NULL);
- const uint16_t* vmap = m->GetVmapTable();
+ const VmapTable vmap_table(m->GetVmapTableRaw());
// For all dex registers in the bitmap
size_t num_regs = std::min(map.RegWidth() * 8, static_cast<size_t>(m->NumRegisters()));
for (size_t reg = 0; reg < num_regs; ++reg) {
// Does this register hold a reference?
if (TestBitmap(reg, reg_bitmap)) {
- // Is the reference in the context or on the stack?
- bool in_context = false;
- uint32_t vmap_offset = 0xEBAD0FF5;
- // TODO: take advantage of the registers being ordered
- for (int i = 0; i < m->GetVmapTableLength(); i++) {
- // stop if we find what we are are looking for or the INVALID_VREG that marks lr
- if (vmap[i] == 0xffff) {
- break;
- }
- if (vmap[i] == reg) {
- in_context = true;
- vmap_offset = i;
- break;
- }
- }
+ uint32_t vmap_offset;
Object* ref;
- if (in_context) {
+ if (vmap_table.IsInContext(reg, vmap_offset)) {
// Compute the register we need to load from the context
uint32_t spill_mask = m->GetCoreSpillMask();
CHECK_LT(vmap_offset, static_cast<uint32_t>(__builtin_popcount(spill_mask)));