Experimental fix to allow for JDWP connections with different ID sizes

This commit is contained in:
baldurk
2018-04-25 19:07:34 +01:00
parent 460ab48645
commit becfe157b4
4 changed files with 192 additions and 46 deletions
+1 -1
View File
@@ -309,7 +309,7 @@ bool InjectLibraries(const std::string &deviceID, Network::Socket *sock)
// look up onCreate in the most derived class - since we can't guarantee that the base
// application.app.onCreate() will get called.
methodID onCreate = conn.GetMethod(thisClass.Object, "onCreate", "()V");
methodID onCreate = conn.GetMethod(thisClass.RefType, "onCreate", "()V");
if(onCreate == 0)
{
+55 -18
View File
@@ -211,13 +211,28 @@ enum class Error : uint16_t
struct CommandData;
// we abstract the objectID size away, and always treat it as a uint64 (if it's actually 4 bytes, we
// just only read/write the lower 4 bytes).
struct objectID
// different IDs in JDWP can be different sizes, but we want to basically treat them all the same.
// For that reason we have a templated struct (jdwpID) which has all the functions we need, we
// instantiate it for each *unique* ID type, and then further typedef for other IDs that are the
// same.
// we abstract the actual size away, and always treat an ID as a uint64 (if it's actually 4 bytes,
// we just only read/write the lower 4 bytes).
enum class IDType
{
field,
method,
object,
refType,
frame
};
template <IDType>
struct jdwpID
{
public:
objectID() = default;
objectID(uint64_t v) { data.u64 = v; }
jdwpID() = default;
jdwpID(uint64_t v) { data.u64 = v; }
operator uint64_t() const { return size == 4 ? data.u32 : data.u64; }
static int32_t getSize() { return size; }
static void setSize(int32_t s)
@@ -243,21 +258,24 @@ private:
static int32_t size;
};
// all object types are the same and we don't care too much about type safety, so we just typedef
// them.
typedef jdwpID<IDType::object> objectID;
typedef objectID threadID;
typedef objectID threadGroupID;
typedef objectID stringID;
typedef objectID classLoaderID;
typedef objectID classObjectID;
typedef objectID arrayID;
typedef objectID referenceTypeID;
typedef objectID classID;
typedef objectID interfaceID;
typedef objectID arrayTypeID;
typedef objectID methodID;
typedef objectID fieldID;
typedef objectID frameID;
// docs are weird - the protocol says referenceTypeID size is "same as objectID", but it has a
// separate ID size. To be safe, keep it separate.
typedef jdwpID<IDType::refType> referenceTypeID;
typedef referenceTypeID classID;
typedef referenceTypeID interfaceID;
typedef referenceTypeID arrayTypeID;
typedef jdwpID<IDType::method> methodID;
typedef jdwpID<IDType::field> fieldID;
typedef jdwpID<IDType::frame> frameID;
struct taggedObjectID
{
@@ -275,6 +293,7 @@ struct value
byte Byte;
char Char;
objectID Object;
referenceTypeID RefType;
float Float;
double Double;
int32_t Int;
@@ -423,10 +442,6 @@ CommandData &CommandData::Read(std::string &str);
template <>
CommandData &CommandData::Write(const std::string &str);
template <>
CommandData &CommandData::Read(objectID &id);
template <>
CommandData &CommandData::Write(const objectID &id);
template <>
CommandData &CommandData::Read(taggedObjectID &id);
template <>
CommandData &CommandData::Write(const taggedObjectID &id);
@@ -439,6 +454,28 @@ CommandData &CommandData::Read(Location &loc);
template <>
CommandData &CommandData::Write(const Location &loc);
// objectID variants
template <>
CommandData &CommandData::Read(objectID &id);
template <>
CommandData &CommandData::Write(const objectID &id);
template <>
CommandData &CommandData::Read(referenceTypeID &id);
template <>
CommandData &CommandData::Write(const referenceTypeID &id);
template <>
CommandData &CommandData::Read(methodID &id);
template <>
CommandData &CommandData::Write(const methodID &id);
template <>
CommandData &CommandData::Read(fieldID &id);
template <>
CommandData &CommandData::Write(const fieldID &id);
template <>
CommandData &CommandData::Read(frameID &id);
template <>
CommandData &CommandData::Write(const frameID &id);
typedef std::function<bool(const Event &evData)> EventFilterFunction;
// A JDWP connection, with high-level helper functions that implement the protocol underneath
+46 -10
View File
@@ -123,25 +123,61 @@ void Connection::SetupIDSizes()
.Read(frameIDSize)
.Done();
// we only support sizes that are all the same
if(fieldIDSize != methodIDSize || fieldIDSize != objectIDSize ||
fieldIDSize != referenceTypeIDSize || fieldIDSize != frameIDSize)
if(objectIDSize != referenceTypeIDSize)
{
RDCLOG("Field ID sizes (%d %d %d %d %d) are not the same. Unsupported!", fieldIDSize,
methodIDSize, objectIDSize, referenceTypeIDSize, frameIDSize);
error = true;
return;
RDCWARN("objectID (%d) is not the same size as referenceTypeID (%d). Could cause problems!",
objectIDSize, referenceTypeIDSize);
}
// we also only support 4 or 8 bytes
// we only support 4 or 8 bytes
if(fieldIDSize != 4 && fieldIDSize != 8)
{
RDCLOG("Field ID size %d is unsupported!", fieldIDSize);
RDCLOG("fieldID size %d is unsupported!", fieldIDSize);
error = true;
return;
}
objectID::setSize(fieldIDSize);
fieldID::setSize(fieldIDSize);
// we only support 4 or 8 bytes
if(methodIDSize != 4 && methodIDSize != 8)
{
RDCLOG("methodID size %d is unsupported!", methodIDSize);
error = true;
return;
}
methodID::setSize(methodIDSize);
// we only support 4 or 8 bytes
if(objectIDSize != 4 && objectIDSize != 8)
{
RDCLOG("objectID size %d is unsupported!", objectIDSize);
error = true;
return;
}
objectID::setSize(objectIDSize);
// we only support 4 or 8 bytes
if(referenceTypeIDSize != 4 && referenceTypeIDSize != 8)
{
RDCLOG("referenceTypeID size %d is unsupported!", referenceTypeIDSize);
error = true;
return;
}
referenceTypeID::setSize(referenceTypeIDSize);
// we only support 4 or 8 bytes
if(frameIDSize != 4 && frameIDSize != 8)
{
RDCLOG("frameID size %d is unsupported!", frameIDSize);
error = true;
return;
}
frameID::setSize(frameIDSize);
}
void Connection::Suspend()
+90 -17
View File
@@ -33,6 +33,10 @@ namespace JDWP
{
uint32_t Command::idalloc = 42;
int32_t objectID::size = 8;
int32_t referenceTypeID::size = 8;
int32_t methodID::size = 8;
int32_t fieldID::size = 8;
int32_t frameID::size = 8;
uint32_t Command::Send(StreamWriter &writer)
{
@@ -129,23 +133,6 @@ CommandData &CommandData::Write(const std::string &str)
return *this;
}
template <>
CommandData &CommandData::Read(objectID &id)
{
ReadBytes(&id, objectID::getSize());
id.EndianSwap();
return *this;
}
template <>
CommandData &CommandData::Write(const objectID &id)
{
objectID tmp = id;
tmp.EndianSwap();
WriteBytes(&tmp, objectID::getSize());
return *this;
}
template <>
CommandData &CommandData::Read(taggedObjectID &id)
{
@@ -235,4 +222,90 @@ CommandData &CommandData::Write(const Location &loc)
Write(loc.index);
return *this;
}
// objectID variants
template <>
CommandData &CommandData::Read(objectID &id)
{
ReadBytes(&id, objectID::getSize());
id.EndianSwap();
return *this;
}
template <>
CommandData &CommandData::Write(const objectID &id)
{
objectID tmp = id;
tmp.EndianSwap();
WriteBytes(&tmp, objectID::getSize());
return *this;
}
template <>
CommandData &CommandData::Read(referenceTypeID &id)
{
ReadBytes(&id, referenceTypeID::getSize());
id.EndianSwap();
return *this;
}
template <>
CommandData &CommandData::Write(const referenceTypeID &id)
{
referenceTypeID tmp = id;
tmp.EndianSwap();
WriteBytes(&tmp, referenceTypeID::getSize());
return *this;
}
template <>
CommandData &CommandData::Read(methodID &id)
{
ReadBytes(&id, methodID::getSize());
id.EndianSwap();
return *this;
}
template <>
CommandData &CommandData::Write(const methodID &id)
{
methodID tmp = id;
tmp.EndianSwap();
WriteBytes(&tmp, methodID::getSize());
return *this;
}
template <>
CommandData &CommandData::Read(fieldID &id)
{
ReadBytes(&id, fieldID::getSize());
id.EndianSwap();
return *this;
}
template <>
CommandData &CommandData::Write(const fieldID &id)
{
fieldID tmp = id;
tmp.EndianSwap();
WriteBytes(&tmp, fieldID::getSize());
return *this;
}
template <>
CommandData &CommandData::Read(frameID &id)
{
ReadBytes(&id, frameID::getSize());
id.EndianSwap();
return *this;
}
template <>
CommandData &CommandData::Write(const frameID &id)
{
frameID tmp = id;
tmp.EndianSwap();
WriteBytes(&tmp, frameID::getSize());
return *this;
}
};