mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 09:30:44 +00:00
309 lines
7.3 KiB
C++
309 lines
7.3 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2019-2025 Baldur Karlsson
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "jdwp.h"
|
|
|
|
// The handshake and packet spec is defined in:
|
|
// https://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp-spec.html
|
|
// This gives the overall structure of each packet, plus the format of the 'basic' types like
|
|
// objectID, value, location, etc.
|
|
|
|
namespace JDWP
|
|
{
|
|
uint32_t Command::idalloc = 42;
|
|
|
|
uint32_t Command::Send(StreamWriter &writer)
|
|
{
|
|
id = idalloc++;
|
|
length = 11 + (uint32_t)data.size();
|
|
|
|
uint32_t tmp = EndianSwap(length);
|
|
writer.Write(tmp);
|
|
tmp = EndianSwap(id);
|
|
writer.Write(tmp);
|
|
|
|
// no need to endian swap these
|
|
byte flags = 0;
|
|
writer.Write(flags);
|
|
writer.Write(commandset);
|
|
writer.Write(command);
|
|
|
|
// already endian swapped
|
|
writer.Write(data.data(), data.size());
|
|
|
|
writer.Flush();
|
|
|
|
return id;
|
|
}
|
|
|
|
void Command::Recv(StreamReader &reader)
|
|
{
|
|
reader.Read(length);
|
|
length = EndianSwap(length);
|
|
reader.Read(id);
|
|
id = EndianSwap(id);
|
|
|
|
byte flags = 0;
|
|
reader.Read(flags);
|
|
if(flags == 0x80)
|
|
{
|
|
commandset = CommandSet::Unknown;
|
|
command = 0;
|
|
uint16_t errInt = 0;
|
|
reader.Read(errInt);
|
|
error = (Error)EndianSwap(errInt);
|
|
}
|
|
else
|
|
{
|
|
reader.Read(commandset);
|
|
reader.Read(command);
|
|
error = Error::None;
|
|
}
|
|
|
|
data.clear();
|
|
if(length >= 11)
|
|
{
|
|
data.resize(length - 11);
|
|
reader.Read(&data[0], data.size());
|
|
}
|
|
}
|
|
|
|
CommandData Command::GetData()
|
|
{
|
|
return CommandData(data);
|
|
}
|
|
|
|
void CommandData::ReadBytes(void *bytes, size_t length)
|
|
{
|
|
// read the data if there's enough, otherwise set to 0s.
|
|
if(offs + length <= data.size())
|
|
memcpy(bytes, data.data() + offs, length);
|
|
else
|
|
memset(bytes, 0, length);
|
|
|
|
// always increment the offset so we can see how much we over-read in Done().
|
|
offs += length;
|
|
}
|
|
|
|
void CommandData::WriteBytes(const void *bytes, size_t length)
|
|
{
|
|
data.append((const byte *)bytes, length);
|
|
}
|
|
|
|
template <>
|
|
CommandData &CommandData::Read(rdcstr &str)
|
|
{
|
|
uint32_t length = 0;
|
|
Read(length);
|
|
str.resize(length);
|
|
ReadBytes(&str[0], length);
|
|
return *this;
|
|
}
|
|
|
|
template <>
|
|
CommandData &CommandData::Write(const rdcstr &str)
|
|
{
|
|
uint32_t length = (uint32_t)str.size();
|
|
Write(length);
|
|
WriteBytes(str.c_str(), str.size());
|
|
return *this;
|
|
}
|
|
|
|
template <>
|
|
CommandData &CommandData::Read(taggedObjectID &id)
|
|
{
|
|
Read((byte &)id.tag);
|
|
Read(id.id);
|
|
return *this;
|
|
}
|
|
|
|
template <>
|
|
CommandData &CommandData::Write(const taggedObjectID &id)
|
|
{
|
|
Write((const byte &)id.tag);
|
|
Write(id.id);
|
|
return *this;
|
|
}
|
|
|
|
template <>
|
|
CommandData &CommandData::Read(value &val)
|
|
{
|
|
Read((byte &)val.tag);
|
|
switch(val.tag)
|
|
{
|
|
case Tag::Unknown: break;
|
|
case Tag::Array: Read(val.Array); break;
|
|
case Tag::Byte: Read(val.Byte); break;
|
|
case Tag::Char: Read(val.Char); break;
|
|
case Tag::Object: Read(val.Object); break;
|
|
case Tag::Float: Read(val.Float); break;
|
|
case Tag::Double: Read(val.Double); break;
|
|
case Tag::Int: Read(val.Int); break;
|
|
case Tag::Long: Read(val.Long); break;
|
|
case Tag::Short: Read(val.Short); break;
|
|
case Tag::Void: break;
|
|
case Tag::Boolean: Read(val.Bool); break;
|
|
case Tag::String: Read(val.String); break;
|
|
case Tag::Thread: Read(val.Thread); break;
|
|
case Tag::ThreadGroup: Read(val.ThreadGroup); break;
|
|
case Tag::ClassLoader: Read(val.ClassLoader); break;
|
|
case Tag::ClassObject: Read(val.ClassObject); break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <>
|
|
CommandData &CommandData::Write(const value &val)
|
|
{
|
|
Write((const byte &)val.tag);
|
|
switch(val.tag)
|
|
{
|
|
case Tag::Unknown: break;
|
|
case Tag::Array: Write(val.Array); break;
|
|
case Tag::Byte: Write(val.Byte); break;
|
|
case Tag::Char: Write(val.Char); break;
|
|
case Tag::Object: Write(val.Object); break;
|
|
case Tag::Float: Write(val.Float); break;
|
|
case Tag::Double: Write(val.Double); break;
|
|
case Tag::Int: Write(val.Int); break;
|
|
case Tag::Long: Write(val.Long); break;
|
|
case Tag::Short: Write(val.Short); break;
|
|
case Tag::Void: break;
|
|
case Tag::Boolean: Write(val.Bool); break;
|
|
case Tag::String: Write(val.String); break;
|
|
case Tag::Thread: Write(val.Thread); break;
|
|
case Tag::ThreadGroup: Write(val.ThreadGroup); break;
|
|
case Tag::ClassLoader: Write(val.ClassLoader); break;
|
|
case Tag::ClassObject: Write(val.ClassObject); break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <>
|
|
CommandData &CommandData::Read(Location &loc)
|
|
{
|
|
Read((byte &)loc.tag);
|
|
Read(loc.clss);
|
|
Read(loc.meth);
|
|
Read(loc.index);
|
|
return *this;
|
|
}
|
|
|
|
template <>
|
|
CommandData &CommandData::Write(const Location &loc)
|
|
{
|
|
Write((const byte &)loc.tag);
|
|
Write(loc.clss);
|
|
Write(loc.meth);
|
|
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;
|
|
}
|
|
};
|