Xamarin Public Jenkins (auto-signing) 5ee9b766e6 Imported Upstream version 6.6.0.114
Former-commit-id: 48b5c9fe44a9601c58e1ebb3fff2b1a50e94a508
2019-10-07 08:58:42 +00:00

2886 lines
83 KiB
C#

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace Mono.Debugger.Soft
{
public class VersionInfo {
public string VMVersion {
get; set;
}
public int MajorVersion {
get; set;
}
public int MinorVersion {
get; set;
}
/*
* Check that this version is at least major:minor
*/
public bool AtLeast (int major, int minor) {
if ((MajorVersion > major) || ((MajorVersion == major && MinorVersion >= minor)))
return true;
else
return false;
}
}
struct SourceInfo {
public string source_file;
public byte[] hash;
}
class DebugInfo {
public int max_il_offset;
public int[] il_offsets;
public int[] line_numbers;
public int[] column_numbers;
public int[] end_line_numbers;
public int[] end_column_numbers;
public SourceInfo[] source_files;
}
struct FrameInfo {
public long id;
public long method;
public int il_offset;
public StackFrameFlags flags;
}
class TypeInfo {
public string ns, name, full_name;
public long assembly, module, base_type, element_type;
public int token, rank, attributes;
public bool is_byref, is_pointer, is_primitive, is_valuetype, is_enum;
public bool is_gtd, is_generic_type;
public long[] nested;
public long gtd;
public long[] type_args;
}
struct IfaceMapInfo {
public long iface_id;
public long[] iface_methods;
public long[] target_methods;
}
class MethodInfo {
public int attributes, iattributes, token;
public bool is_gmd, is_generic_method;
public long gmd;
public long[] type_args;
}
class MethodBodyInfo {
public byte[] il;
public ExceptionClauseInfo[] clauses;
}
struct ExceptionClauseInfo {
public ExceptionClauseFlags flags;
public int try_offset;
public int try_length;
public int handler_offset;
public int handler_length;
public int filter_offset;
public long catch_type_id;
}
[Flags]
enum ExceptionClauseFlags {
None = 0x0,
Filter = 0x1,
Finally = 0x2,
Fault = 0x4,
}
struct ParamInfo {
public int call_conv;
public int param_count;
public int generic_param_count;
public long ret_type;
public long[] param_types;
public string[] param_names;
}
struct LocalsInfo {
public long[] types;
public string[] names;
public int[] live_range_start;
public int[] live_range_end;
public int[] scopes_start;
public int[] scopes_end;
}
struct PropInfo {
public long id;
public string name;
public long get_method, set_method;
public int attrs;
}
class CattrNamedArgInfo {
public bool is_property;
public long id;
public ValueImpl value;
}
class CattrInfo {
public long ctor_id;
public ValueImpl[] ctor_args;
public CattrNamedArgInfo[] named_args;
}
class ThreadInfo {
public bool is_thread_pool;
}
struct ObjectRefInfo {
public long type_id;
public long domain_id;
}
enum ValueTypeId {
VALUE_TYPE_ID_NULL = 0xf0,
VALUE_TYPE_ID_TYPE = 0xf1,
VALUE_TYPE_ID_PARENT_VTYPE = 0xf2,
VALUE_TYPE_ID_FIXED_ARRAY = 0xf3
}
[Flags]
enum InvokeFlags {
NONE = 0,
DISABLE_BREAKPOINTS = 1,
SINGLE_THREADED = 2,
OUT_THIS = 4,
OUT_ARGS = 8,
VIRTUAL = 16,
}
enum ElementType {
End = 0x00,
Void = 0x01,
Boolean = 0x02,
Char = 0x03,
I1 = 0x04,
U1 = 0x05,
I2 = 0x06,
U2 = 0x07,
I4 = 0x08,
U4 = 0x09,
I8 = 0x0a,
U8 = 0x0b,
R4 = 0x0c,
R8 = 0x0d,
String = 0x0e,
Ptr = 0x0f,
ByRef = 0x10,
ValueType = 0x11,
Class = 0x12,
Var = 0x13,
Array = 0x14,
GenericInst = 0x15,
TypedByRef = 0x16,
I = 0x18,
U = 0x19,
FnPtr = 0x1b,
Object = 0x1c,
SzArray = 0x1d,
MVar = 0x1e,
CModReqD = 0x1f,
CModOpt = 0x20,
Internal = 0x21,
Modifier = 0x40,
Sentinel = 0x41,
Pinned = 0x45,
Type = 0x50,
Boxed = 0x51,
Enum = 0x55
}
class ValueImpl {
public ElementType Type; /* or one of the VALUE_TYPE_ID constants */
public long Objid;
public object Value;
public long Klass; // For ElementType.ValueType
public ValueImpl[] Fields; // for ElementType.ValueType
public bool IsEnum; // For ElementType.ValueType
public long Id; /* For VALUE_TYPE_ID_TYPE */
public int Index; /* For VALUE_TYPE_PARENT_VTYPE */
public int FixedSize;
}
class ModuleInfo {
public string Name, ScopeName, FQName, Guid, SourceLink;
public long Assembly;
}
class FieldMirrorInfo {
public string Name;
public long Parent, TypeId;
public int Attrs;
}
enum TokenType {
STRING = 0,
TYPE = 1,
FIELD = 2,
METHOD = 3,
UNKNOWN = 4
}
[Flags]
enum StackFrameFlags {
NONE = 0,
DEBUGGER_INVOKE = 1,
NATIVE_TRANSITION = 2
}
class ResolvedToken {
public TokenType Type;
public string Str;
public long Id;
}
class Modifier {
}
class CountModifier : Modifier {
public int Count {
get; set;
}
}
class LocationModifier : Modifier {
public long Method {
get; set;
}
public long Location {
get; set;
}
}
class StepModifier : Modifier {
public long Thread {
get; set;
}
public int Depth {
get; set;
}
public int Size {
get; set;
}
public int Filter {
get; set;
}
}
class ThreadModifier : Modifier {
public long Thread {
get; set;
}
}
class ExceptionModifier : Modifier {
public long Type {
get; set;
}
public bool Caught {
get; set;
}
public bool Uncaught {
get; set;
}
public bool Subclasses {
get; set;
}
public bool NotFilteredFeature {
get; set;
}
public bool EverythingElse {
get; set;
}
}
class AssemblyModifier : Modifier {
public long[] Assemblies {
get; set;
}
}
class SourceFileModifier : Modifier {
public string[] SourceFiles {
get; set;
}
}
class TypeNameModifier : Modifier {
public string[] TypeNames {
get; set;
}
}
class EventInfo {
public EventType EventType {
get; set;
}
public int ReqId {
get; set;
}
public SuspendPolicy SuspendPolicy {
get; set;
}
public long ThreadId {
get; set;
}
public long Id {
get; set;
}
public long Location {
get; set;
}
public int Level {
get; set;
}
public string Category {
get; set;
}
public string Message {
get; set;
}
public int ExitCode {
get; set;
}
public string Dump {
get; set;
}
public ulong Hash {
get; set;
}
public EventInfo (EventType type, int req_id) {
EventType = type;
ReqId = req_id;
}
}
public enum ErrorCode {
NONE = 0,
INVALID_OBJECT = 20,
INVALID_FIELDID = 25,
INVALID_FRAMEID = 30,
NOT_IMPLEMENTED = 100,
NOT_SUSPENDED = 101,
INVALID_ARGUMENT = 102,
ERR_UNLOADED = 103,
ERR_NO_INVOCATION = 104,
ABSENT_INFORMATION = 105,
NO_SEQ_POINT_AT_IL_OFFSET = 106,
INVOKE_ABORTED = 107
}
public class ErrorHandlerEventArgs : EventArgs {
public ErrorCode ErrorCode {
get; set;
}
}
/*
* Represents the connection to the debuggee
*/
public abstract class Connection
{
/*
* The protocol and the packet format is based on JDWP, the differences
* are in the set of supported events, and the commands.
*/
internal const string HANDSHAKE_STRING = "DWP-Handshake";
internal const int HEADER_LENGTH = 11;
static readonly bool EnableConnectionLogging = !String.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MONO_SDB_LOG"));
static int ConnectionId;
readonly StreamWriter LoggingStream;
/*
* Th version of the wire-protocol implemented by the library. The library
* and the debuggee can communicate if they implement the same major version.
* If they implement a different minor version, they can communicate, but some
* features might not be available. This allows older clients to communicate
* with newer runtimes, and vice versa.
*/
internal const int MAJOR_VERSION = 2;
internal const int MINOR_VERSION = 54;
enum WPSuspendPolicy {
NONE = 0,
EVENT_THREAD = 1,
ALL = 2
}
enum CommandSet {
VM = 1,
OBJECT_REF = 9,
STRING_REF = 10,
THREAD = 11,
ARRAY_REF = 13,
EVENT_REQUEST = 15,
STACK_FRAME = 16,
APPDOMAIN = 20,
ASSEMBLY = 21,
METHOD = 22,
TYPE = 23,
MODULE = 24,
FIELD = 25,
EVENT = 64,
POINTER = 65
}
enum EventKind {
VM_START = 0,
VM_DEATH = 1,
THREAD_START = 2,
THREAD_DEATH = 3,
APPDOMAIN_CREATE = 4, // Not in JDI
APPDOMAIN_UNLOAD = 5, // Not in JDI
METHOD_ENTRY = 6,
METHOD_EXIT = 7,
ASSEMBLY_LOAD = 8,
ASSEMBLY_UNLOAD = 9,
BREAKPOINT = 10,
STEP = 11,
TYPE_LOAD = 12,
EXCEPTION = 13,
KEEPALIVE = 14,
USER_BREAK = 15,
USER_LOG = 16,
CRASH = 17
}
enum ModifierKind {
COUNT = 1,
THREAD_ONLY = 3,
LOCATION_ONLY = 7,
EXCEPTION_ONLY = 8,
STEP = 10,
ASSEMBLY_ONLY = 11,
SOURCE_FILE_ONLY = 12,
TYPE_NAME_ONLY = 13
}
enum CmdVM {
VERSION = 1,
ALL_THREADS = 2,
SUSPEND = 3,
RESUME = 4,
EXIT = 5,
DISPOSE = 6,
INVOKE_METHOD = 7,
SET_PROTOCOL_VERSION = 8,
ABORT_INVOKE = 9,
SET_KEEPALIVE = 10,
GET_TYPES_FOR_SOURCE_FILE = 11,
GET_TYPES = 12,
INVOKE_METHODS = 13,
START_BUFFERING = 14,
STOP_BUFFERING = 15
}
enum CmdEvent {
COMPOSITE = 100
}
enum CmdThread {
GET_FRAME_INFO = 1,
GET_NAME = 2,
GET_STATE = 3,
GET_INFO = 4,
/* FIXME: Merge into GET_INFO when the major protocol version is increased */
GET_ID = 5,
/* Ditto */
GET_TID = 6,
SET_IP = 7,
GET_ELAPSED_TIME = 8
}
enum CmdEventRequest {
SET = 1,
CLEAR = 2,
CLEAR_ALL_BREAKPOINTS = 3
}
enum CmdAppDomain {
GET_ROOT_DOMAIN = 1,
GET_FRIENDLY_NAME = 2,
GET_ASSEMBLIES = 3,
GET_ENTRY_ASSEMBLY = 4,
CREATE_STRING = 5,
GET_CORLIB = 6,
CREATE_BOXED_VALUE = 7,
CREATE_BYTE_ARRAY = 8,
}
enum CmdAssembly {
GET_LOCATION = 1,
GET_ENTRY_POINT = 2,
GET_MANIFEST_MODULE = 3,
GET_OBJECT = 4,
GET_TYPE = 5,
GET_NAME = 6,
GET_DOMAIN = 7,
GET_METADATA_BLOB = 8,
GET_IS_DYNAMIC = 9,
GET_PDB_BLOB = 10,
GET_TYPE_FROM_TOKEN = 11,
GET_METHOD_FROM_TOKEN = 12,
HAS_DEBUG_INFO = 13,
}
enum CmdModule {
GET_INFO = 1,
}
enum CmdMethod {
GET_NAME = 1,
GET_DECLARING_TYPE = 2,
GET_DEBUG_INFO = 3,
GET_PARAM_INFO = 4,
GET_LOCALS_INFO = 5,
GET_INFO = 6,
GET_BODY = 7,
RESOLVE_TOKEN = 8,
GET_CATTRS = 9,
MAKE_GENERIC_METHOD = 10
}
enum CmdType {
GET_INFO = 1,
GET_METHODS = 2,
GET_FIELDS = 3,
GET_VALUES = 4,
GET_OBJECT = 5,
GET_SOURCE_FILES = 6,
SET_VALUES = 7,
IS_ASSIGNABLE_FROM = 8,
GET_PROPERTIES = 9,
GET_CATTRS = 10,
GET_FIELD_CATTRS = 11,
GET_PROPERTY_CATTRS = 12,
/* FIXME: Merge into GET_SOURCE_FILES when the major protocol version is increased */
GET_SOURCE_FILES_2 = 13,
/* FIXME: Merge into GET_VALUES when the major protocol version is increased */
GET_VALUES_2 = 14,
CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15,
GET_INTERFACES = 16,
GET_INTERFACE_MAP = 17,
IS_INITIALIZED = 18,
CREATE_INSTANCE = 19,
GET_VALUE_SIZE = 20
}
enum CmdField {
GET_INFO = 1
}
[Flags]
enum BindingFlagsExtensions {
BINDING_FLAGS_IGNORE_CASE = 0x70000000,
}
enum MemberListTypeExtensions {
CaseSensitive = 1,
CaseInsensitive = 2
}
enum CmdStackFrame {
GET_VALUES = 1,
GET_THIS = 2,
SET_VALUES = 3,
GET_DOMAIN = 4,
SET_THIS = 5,
}
enum CmdArrayRef {
GET_LENGTH = 1,
GET_VALUES = 2,
SET_VALUES = 3
}
enum CmdStringRef {
GET_VALUE = 1,
GET_LENGTH = 2,
GET_CHARS = 3
}
enum CmdPointer {
GET_VALUE = 1
}
enum CmdObjectRef {
GET_TYPE = 1,
GET_VALUES = 2,
IS_COLLECTED = 3,
GET_ADDRESS = 4,
GET_DOMAIN = 5,
SET_VALUES = 6,
GET_INFO = 7,
}
class Header {
public int id;
public int command_set;
public int command;
public int flags;
}
internal static int GetPacketLength (byte[] header) {
int offset = 0;
return decode_int (header, ref offset);
}
internal static bool IsReplyPacket (byte[] packet) {
int offset = 8;
return decode_byte (packet, ref offset) == 0x80;
}
internal static int GetPacketId (byte[] packet) {
int offset = 4;
return decode_int (packet, ref offset);
}
static int decode_byte (byte[] packet, ref int offset) {
return packet [offset++];
}
static byte[] decode_bytes (byte[] packet, ref int offset, int length)
{
if (length + offset > packet.Length)
throw new ArgumentOutOfRangeException ();
var bytes = new byte[length];
Array.Copy (packet, offset, bytes, 0, length);
offset += length;
return bytes;
}
static int decode_short (byte[] packet, ref int offset) {
int res = ((int)packet [offset] << 8) | (int)packet [offset + 1];
offset += 2;
return res;
}
static int decode_int (byte[] packet, ref int offset) {
int res = ((int)packet [offset] << 24) | ((int)packet [offset + 1] << 16) | ((int)packet [offset + 2] << 8) | (int)packet [offset + 3];
offset += 4;
return res;
}
static long decode_id (byte[] packet, ref int offset) {
return decode_int (packet, ref offset);
}
static long decode_long (byte[] packet, ref int offset) {
uint high = (uint)decode_int (packet, ref offset);
uint low = (uint)decode_int (packet, ref offset);
return (long)(((ulong)high << 32) | (ulong)low);
}
internal static SuspendPolicy decode_suspend_policy (int suspend_policy) {
switch ((WPSuspendPolicy)suspend_policy) {
case WPSuspendPolicy.NONE:
return SuspendPolicy.None;
case WPSuspendPolicy.EVENT_THREAD:
return SuspendPolicy.EventThread;
case WPSuspendPolicy.ALL:
return SuspendPolicy.All;
default:
throw new NotImplementedException ();
}
}
static Header decode_command_header (byte[] packet) {
int offset = 0;
Header res = new Header ();
decode_int (packet, ref offset);
res.id = decode_int (packet, ref offset);
res.flags = decode_byte (packet, ref offset);
res.command_set = decode_byte (packet, ref offset);
res.command = decode_byte (packet, ref offset);
return res;
}
static void encode_byte (byte[] buf, int b, ref int offset) {
buf [offset] = (byte)b;
offset ++;
}
static void encode_int (byte[] buf, int i, ref int offset) {
buf [offset] = (byte)((i >> 24) & 0xff);
buf [offset + 1] = (byte)((i >> 16) & 0xff);
buf [offset + 2] = (byte)((i >> 8) & 0xff);
buf [offset + 3] = (byte)((i >> 0) & 0xff);
offset += 4;
}
static void encode_id (byte[] buf, long id, ref int offset) {
encode_int (buf, (int)id, ref offset);
}
static void encode_long (byte[] buf, long l, ref int offset) {
encode_int (buf, (int)((l >> 32) & 0xffffffff), ref offset);
encode_int (buf, (int)(l & 0xffffffff), ref offset);
}
internal static byte[] EncodePacket (int id, int commandSet, int command, byte[] data, int dataLen) {
byte[] buf = new byte [dataLen + 11];
int offset = 0;
encode_int (buf, buf.Length, ref offset);
encode_int (buf, id, ref offset);
encode_byte (buf, 0, ref offset);
encode_byte (buf, commandSet, ref offset);
encode_byte (buf, command, ref offset);
for (int i = 0; i < dataLen; ++i)
buf [offset + i] = data [i];
return buf;
}
class PacketReader {
Connection connection;
byte[] packet;
int offset;
public PacketReader (Connection connection, byte[] packet) {
this.connection = connection;
this.packet = packet;
// For event packets
Header header = decode_command_header (packet);
CommandSet = (CommandSet)header.command_set;
Command = header.command;
// For reply packets
offset = 0;
ReadInt (); // length
ReadInt (); // id
ReadByte (); // flags
ErrorCode = ReadShort ();
}
public CommandSet CommandSet {
get; set;
}
public int Command {
get; set;
}
public int ErrorCode {
get; set;
}
public int Offset {
get {
return offset;
}
}
public int ReadByte () {
return decode_byte (packet, ref offset);
}
public int ReadShort () {
return decode_short (packet, ref offset);
}
public int ReadInt () {
return decode_int (packet, ref offset);
}
public long ReadId () {
return decode_id (packet, ref offset);
}
public long ReadLong () {
return decode_long (packet, ref offset);
}
public float ReadFloat () {
float f = DataConverter.FloatFromBE (packet, offset);
offset += 4;
return f;
}
public double ReadDouble () {
double d = DataConverter.DoubleFromBE (packet, offset);
offset += 8;
return d;
}
public string ReadString () {
int len = decode_int (packet, ref offset);
string res = new String (Encoding.UTF8.GetChars (packet, offset, len));
offset += len;
return res;
}
public string ReadUTF16String () {
int len = decode_int (packet, ref offset);
string res = new String (Encoding.Unicode.GetChars (packet, offset, len));
offset += len;
return res;
}
public ValueImpl ReadValue () {
ElementType etype = (ElementType)ReadByte ();
switch (etype) {
case ElementType.Void:
return new ValueImpl { Type = etype };
case ElementType.I1:
return new ValueImpl { Type = etype, Value = (sbyte)ReadInt () };
case ElementType.U1:
return new ValueImpl { Type = etype, Value = (byte)ReadInt () };
case ElementType.Boolean:
return new ValueImpl { Type = etype, Value = ReadInt () != 0 };
case ElementType.I2:
return new ValueImpl { Type = etype, Value = (short)ReadInt () };
case ElementType.U2:
return new ValueImpl { Type = etype, Value = (ushort)ReadInt () };
case ElementType.Char:
return new ValueImpl { Type = etype, Value = (char)ReadInt () };
case ElementType.I4:
return new ValueImpl { Type = etype, Value = ReadInt () };
case ElementType.U4:
return new ValueImpl { Type = etype, Value = (uint)ReadInt () };
case ElementType.I8:
return new ValueImpl { Type = etype, Value = ReadLong () };
case ElementType.U8:
return new ValueImpl { Type = etype, Value = (ulong)ReadLong () };
case ElementType.R4:
return new ValueImpl { Type = etype, Value = ReadFloat () };
case ElementType.R8:
return new ValueImpl { Type = etype, Value = ReadDouble () };
case ElementType.I:
case ElementType.U:
// FIXME: The client and the debuggee might have different word sizes
return new ValueImpl { Type = etype, Value = ReadLong () };
case ElementType.Ptr:
long value = ReadLong ();
if (connection.Version.AtLeast (2, 46)) {
long pointerClass = ReadId ();
return new ValueImpl { Type = etype, Klass = pointerClass, Value = value };
} else {
return new ValueImpl { Type = etype, Value = value };
}
case ElementType.String:
case ElementType.SzArray:
case ElementType.Class:
case ElementType.Array:
case ElementType.Object:
long objid = ReadId ();
return new ValueImpl () { Type = etype, Objid = objid };
case ElementType.ValueType:
bool is_enum = ReadByte () == 1;
long klass = ReadId ();
long nfields = ReadInt ();
ValueImpl[] fields = new ValueImpl [nfields];
for (int i = 0; i < nfields; ++i)
fields [i] = ReadValue ();
return new ValueImpl () { Type = etype, Klass = klass, Fields = fields, IsEnum = is_enum };
case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
return new ValueImpl { Type = etype };
case (ElementType)ValueTypeId.VALUE_TYPE_ID_TYPE:
return new ValueImpl () { Type = etype, Id = ReadId () };
case (ElementType)ValueTypeId.VALUE_TYPE_ID_PARENT_VTYPE:
return new ValueImpl () { Type = etype, Index = ReadInt () };
case (ElementType)ValueTypeId.VALUE_TYPE_ID_FIXED_ARRAY:
return ReadValueFixedSize ();
default:
throw new NotImplementedException ("Unable to handle type " + etype);
}
}
ValueImpl ReadValueFixedSize () {
var lenFixedSize = 1;
ElementType etype = (ElementType)ReadByte ();
lenFixedSize = ReadInt ();
switch (etype) {
case ElementType.I1: {
var val = new sbyte[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = (sbyte)ReadInt ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.U1: {
var val = new byte[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = (byte)ReadInt ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.Boolean: {
var val = new bool[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = (ReadInt () != 0);
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.I2: {
var val = new short[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = (short)ReadInt ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.U2: {
var val = new ushort[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = (ushort)ReadInt ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.Char: {
var val = new char[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = (char)ReadInt ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.I4: {
var val = new int[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = ReadInt ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.U4: {
var val = new uint[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = (uint)ReadInt ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.I8: {
var val = new long[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = ReadLong ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.U8: {
var val = new ulong[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = (ulong) ReadLong ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.R4: {
var val = new float[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = ReadFloat ();
return new ValueImpl { Type = etype, Value = val };
}
case ElementType.R8: {
var val = new double[lenFixedSize];
for (int i = 0; i < lenFixedSize; i++)
val[i] = ReadDouble ();
return new ValueImpl { Type = etype, Value = val };
}
}
throw new NotImplementedException ("Unable to handle type " + etype);
}
public long[] ReadIds (int n) {
long[] res = new long [n];
for (int i = 0; i < n; ++i)
res [i] = ReadId ();
return res;
}
public byte[] ReadByteArray () {
var length = ReadInt ();
return decode_bytes (packet, ref offset, length);
}
public bool ReadBool () {
return ReadByte () != 0;
}
}
class PacketWriter {
byte[] data;
int offset;
public PacketWriter () {
data = new byte [1024];
offset = 0;
}
void MakeRoom (int size) {
if (offset + size >= data.Length) {
int new_len = data.Length * 2;
while (new_len < offset + size) {
new_len *= 2;
}
byte[] new_data = new byte [new_len];
Array.Copy (data, new_data, data.Length);
data = new_data;
}
}
public PacketWriter WriteByte (byte val) {
MakeRoom (1);
encode_byte (data, val, ref offset);
return this;
}
public PacketWriter WriteInt (int val) {
MakeRoom (4);
encode_int (data, val, ref offset);
return this;
}
public PacketWriter WriteId (long id) {
MakeRoom (8);
encode_id (data, id, ref offset);
return this;
}
public PacketWriter WriteLong (long val) {
MakeRoom (8);
encode_long (data, val, ref offset);
return this;
}
public PacketWriter WriteFloat (float f) {
MakeRoom (8);
byte[] b = DataConverter.GetBytesBE (f);
for (int i = 0; i < 4; ++i)
data [offset + i] = b [i];
offset += 4;
return this;
}
public PacketWriter WriteDouble (double d) {
MakeRoom (8);
byte[] b = DataConverter.GetBytesBE (d);
for (int i = 0; i < 8; ++i)
data [offset + i] = b [i];
offset += 8;
return this;
}
public PacketWriter WriteInts (int[] ids) {
for (int i = 0; i < ids.Length; ++i)
WriteInt (ids [i]);
return this;
}
public PacketWriter WriteIds (long[] ids) {
for (int i = 0; i < ids.Length; ++i)
WriteId (ids [i]);
return this;
}
public PacketWriter WriteString (string s) {
if (s == null)
return WriteInt (-1);
byte[] b = Encoding.UTF8.GetBytes (s);
MakeRoom (4);
encode_int (data, b.Length, ref offset);
MakeRoom (b.Length);
Buffer.BlockCopy (b, 0, data, offset, b.Length);
offset += b.Length;
return this;
}
public PacketWriter WriteBytes (byte[] b) {
if (b == null)
return WriteInt (-1);
MakeRoom (4);
encode_int (data, b.Length, ref offset);
MakeRoom (b.Length);
Buffer.BlockCopy (b, 0, data, offset, b.Length);
offset += b.Length;
return this;
}
public PacketWriter WriteBool (bool val) {
WriteByte (val ? (byte)1 : (byte)0);
return this;
}
public PacketWriter WriteValue (ValueImpl v) {
ElementType t;
if (v.Value != null)
t = TypeCodeToElementType (Type.GetTypeCode (v.Value.GetType ()), v.Value.GetType ());
else
t = v.Type;
if (v.FixedSize > 1 && t != ElementType.ValueType) {
WriteFixedSizeValue (v);
return this;
}
WriteByte ((byte)t);
switch (t) {
case ElementType.Boolean:
WriteInt ((bool)v.Value ? 1 : 0);
break;
case ElementType.Char:
WriteInt ((int)(char)v.Value);
break;
case ElementType.I1:
WriteInt ((int)(sbyte)v.Value);
break;
case ElementType.U1:
WriteInt ((int)(byte)v.Value);
break;
case ElementType.I2:
WriteInt ((int)(short)v.Value);
break;
case ElementType.U2:
WriteInt ((int)(ushort)v.Value);
break;
case ElementType.I4:
WriteInt ((int)(int)v.Value);
break;
case ElementType.U4:
WriteInt ((int)(uint)v.Value);
break;
case ElementType.I8:
WriteLong ((long)(long)v.Value);
break;
case ElementType.U8:
WriteLong ((long)(ulong)v.Value);
break;
case ElementType.R4:
WriteFloat ((float)v.Value);
break;
case ElementType.R8:
WriteDouble ((double)v.Value);
break;
case ElementType.String:
case ElementType.SzArray:
case ElementType.Class:
case ElementType.Array:
case ElementType.Object:
WriteId (v.Objid);
break;
case ElementType.ValueType:
// FIXME:
if (v.IsEnum)
throw new NotImplementedException ();
WriteByte (0);
WriteId (v.Klass);
WriteInt (v.Fields.Length);
for (int i = 0; i < v.Fields.Length; ++i)
WriteValue (v.Fields [i]);
break;
case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
break;
default:
throw new NotImplementedException ();
}
return this;
}
PacketWriter WriteFixedSizeValue (ValueImpl v) {
ElementType t;
if (v.Value != null)
t = TypeCodeToElementType (Type.GetTypeCode (v.Value.GetType ()), v.Value.GetType ());
else
t = v.Type;
WriteByte ((byte) ValueTypeId.VALUE_TYPE_ID_FIXED_ARRAY);
WriteByte ((byte)t);
WriteInt (v.FixedSize);
for (int j = 0 ; j < v.FixedSize; j++) {
switch (t) {
case ElementType.Boolean:
WriteInt (((bool[])v.Value)[j]? 1 : 0);
break;
case ElementType.Char:
WriteInt ((int)((char[])v.Value)[j]);
break;
case ElementType.I1:
WriteInt ((int)((sbyte[])v.Value)[j]);
break;
case ElementType.U1:
WriteInt ((int)((byte[])v.Value)[j]);
break;
case ElementType.I2:
WriteInt ((int)((short[])v.Value)[j]);
break;
case ElementType.U2:
WriteInt ((int)((ushort[])v.Value)[j]);
break;
case ElementType.I4:
WriteInt ((int)((int[])v.Value)[j]);
break;
case ElementType.U4:
WriteInt ((int)((uint[])v.Value)[j]);
break;
case ElementType.I8:
WriteLong ((long)((long[])v.Value)[j]);
break;
case ElementType.U8:
WriteLong ((long)((ulong[])v.Value)[j]);
break;
case ElementType.R4:
WriteFloat (((float[])v.Value)[j]);
break;
case ElementType.R8:
WriteDouble (((double[])v.Value)[j]);
break;
default:
throw new NotImplementedException ();
}
}
return this;
}
public PacketWriter WriteValues (ValueImpl[] values) {
for (int i = 0; i < values.Length; ++i)
WriteValue (values [i]);
return this;
}
public byte[] Data {
get {
return data;
}
}
public int Offset {
get {
return offset;
}
}
}
delegate void ReplyCallback (int packet_id, byte[] packet);
bool closed;
Thread receiver_thread;
Dictionary<int, byte[]> reply_packets;
Dictionary<int, ReplyCallback> reply_cbs;
Dictionary<int, int> reply_cb_counts;
object reply_packets_monitor;
internal event EventHandler<ErrorHandlerEventArgs> ErrorHandler;
protected Connection () {
closed = false;
reply_packets = new Dictionary<int, byte[]> ();
reply_cbs = new Dictionary<int, ReplyCallback> ();
reply_cb_counts = new Dictionary<int, int> ();
reply_packets_monitor = new Object ();
if (EnableConnectionLogging) {
var path = Environment.GetEnvironmentVariable ("MONO_SDB_LOG");
if (path.Contains ("{0}")) {
//C:\SomeDir\sdbLog{0}.txt -> C:\SomeDir\sdbLog1.txt
LoggingStream = new StreamWriter (string.Format (path, ConnectionId++), false);
} else if (Path.HasExtension (path)) {
//C:\SomeDir\sdbLog.txt -> C:\SomeDir\sdbLog1.txt
LoggingStream = new StreamWriter (Path.GetDirectoryName (path) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension (path) + ConnectionId++ + "." + Path.GetExtension (path), false);
} else {
//C:\SomeDir\sdbLog -> C:\SomeDir\sdbLog1
LoggingStream = new StreamWriter (path + ConnectionId++, false);
}
}
}
protected abstract int TransportReceive (byte[] buf, int buf_offset, int len);
protected abstract int TransportSend (byte[] buf, int buf_offset, int len);
protected abstract void TransportSetTimeouts (int send_timeout, int receive_timeout);
protected abstract void TransportClose ();
// Shutdown breaks all communication, resuming blocking waits
protected abstract void TransportShutdown ();
internal VersionInfo Version;
int Receive (byte[] buf, int buf_offset, int len) {
int offset = 0;
while (offset < len) {
int n = TransportReceive (buf, buf_offset + offset, len - offset);
if (n == 0)
return offset;
offset += n;
}
return offset;
}
// Do the wire protocol handshake
internal void Connect () {
byte[] buf = new byte [HANDSHAKE_STRING.Length];
char[] cbuf = new char [buf.Length];
// FIXME: Add a timeout
int n = Receive (buf, 0, buf.Length);
if (n == 0)
throw new IOException ("DWP Handshake failed.");
for (int i = 0; i < buf.Length; ++i)
cbuf [i] = (char)buf [i];
if (new String (cbuf) != HANDSHAKE_STRING)
throw new IOException ("DWP Handshake failed.");
TransportSend (buf, 0, buf.Length);
receiver_thread = new Thread (new ThreadStart (receiver_thread_main));
receiver_thread.Name = "SDB Receiver";
receiver_thread.IsBackground = true;
receiver_thread.Start ();
Version = VM_GetVersion ();
//
// Tell the debuggee our protocol version, so newer debuggees can work
// with older clients
//
//
// Older debuggees might not support this request
EventHandler<ErrorHandlerEventArgs> OrigErrorHandler = ErrorHandler;
ErrorHandler = null;
ErrorHandler += delegate (object sender, ErrorHandlerEventArgs args) {
throw new NotSupportedException ();
};
try {
VM_SetProtocolVersion (MAJOR_VERSION, MINOR_VERSION);
} catch (NotSupportedException) {
}
ErrorHandler = OrigErrorHandler;
}
internal byte[] ReadPacket () {
// FIXME: Throw ClosedConnectionException () if the connection is closed
// FIXME: Throw ClosedConnectionException () if another thread closes the connection
// FIXME: Locking
byte[] header = new byte [HEADER_LENGTH];
int len = Receive (header, 0, header.Length);
if (len == 0)
return new byte [0];
if (len != HEADER_LENGTH) {
// FIXME:
throw new IOException ("Packet of length " + len + " is read.");
}
int packetLength = GetPacketLength (header);
if (packetLength < 11)
throw new IOException ("Invalid packet length.");
if (packetLength == 11) {
return header;
} else {
byte[] buf = new byte [packetLength];
for (int i = 0; i < header.Length; ++i)
buf [i] = header [i];
len = Receive (buf, header.Length, packetLength - header.Length);
if (len != packetLength - header.Length)
throw new IOException ();
return buf;
}
}
internal void WritePacket (byte[] packet) {
// FIXME: Throw ClosedConnectionException () if the connection is closed
// FIXME: Throw ClosedConnectionException () if another thread closes the connection
// FIXME: Locking
TransportSend (packet, 0, packet.Length);
}
internal void WritePackets (List<byte[]> packets) {
// FIXME: Throw ClosedConnectionException () if the connection is closed
// FIXME: Throw ClosedConnectionException () if another thread closes the connection
// FIXME: Locking
int len = 0;
for (int i = 0; i < packets.Count; ++i)
len += packets [i].Length;
byte[] data = new byte [len];
int pos = 0;
for (int i = 0; i < packets.Count; ++i) {
Buffer.BlockCopy (packets [i], 0, data, pos, packets [i].Length);
pos += packets [i].Length;
}
TransportSend (data, 0, data.Length);
}
internal void Close () {
closed = true;
TransportShutdown ();
}
internal bool IsClosed {
get {
return closed;
}
}
bool disconnected;
VMCrashException crashed;
internal ManualResetEvent DisconnectedEvent = new ManualResetEvent (false);
void receiver_thread_main () {
while (!closed) {
try {
bool res = ReceivePacket ();
if (!res) {
break;
}
} catch (ThreadAbortException) {
break;
} catch (VMCrashException ex) {
crashed = ex;
break;
} catch (Exception ex) {
if (!closed) {
Console.WriteLine (ex);
}
break;
}
}
lock (reply_packets_monitor) {
disconnected = true;
DisconnectedEvent.Set ();
Monitor.PulseAll (reply_packets_monitor);
TransportClose ();
}
EventHandler.VMDisconnect (0, 0, null);
}
void disconnected_check () {
if (!disconnected)
return;
else if (crashed != null)
throw crashed;
else
throw new VMDisconnectedException ();
}
bool ReceivePacket () {
byte[] packet = ReadPacket ();
if (packet.Length == 0) {
return false;
}
if (IsReplyPacket (packet)) {
int id = GetPacketId (packet);
ReplyCallback cb = null;
lock (reply_packets_monitor) {
reply_cbs.TryGetValue (id, out cb);
if (cb == null) {
reply_packets [id] = packet;
Monitor.PulseAll (reply_packets_monitor);
} else {
int c = reply_cb_counts [id];
c --;
if (c == 0) {
reply_cbs.Remove (id);
reply_cb_counts.Remove (id);
}
}
}
if (cb != null)
cb.Invoke (id, packet);
} else {
PacketReader r = new PacketReader (this, packet);
if (r.CommandSet == CommandSet.EVENT && r.Command == (int)CmdEvent.COMPOSITE) {
int spolicy = r.ReadByte ();
int nevents = r.ReadInt ();
SuspendPolicy suspend_policy = decode_suspend_policy (spolicy);
EventInfo[] events = new EventInfo [nevents];
for (int i = 0; i < nevents; ++i) {
EventKind kind = (EventKind)r.ReadByte ();
int req_id = r.ReadInt ();
EventType etype = (EventType)kind;
long thread_id = r.ReadId ();
if (kind == EventKind.VM_START) {
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id };
//EventHandler.VMStart (req_id, thread_id, null);
} else if (kind == EventKind.VM_DEATH) {
int exit_code = 0;
if (Version.AtLeast (2, 27))
exit_code = r.ReadInt ();
//EventHandler.VMDeath (req_id, 0, null);
events [i] = new EventInfo (etype, req_id) { ExitCode = exit_code };
} else if (kind == EventKind.CRASH) {
ulong hash = (ulong) r.ReadLong ();
string dump = r.ReadString ();
events [i] = new EventInfo (etype, req_id) { Dump = dump, Hash = hash};
} else if (kind == EventKind.THREAD_START) {
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = thread_id };
//EventHandler.ThreadStart (req_id, thread_id, thread_id);
} else if (kind == EventKind.THREAD_DEATH) {
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = thread_id };
//EventHandler.ThreadDeath (req_id, thread_id, thread_id);
} else if (kind == EventKind.ASSEMBLY_LOAD) {
long id = r.ReadId ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
//EventHandler.AssemblyLoad (req_id, thread_id, id);
} else if (kind == EventKind.ASSEMBLY_UNLOAD) {
long id = r.ReadId ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
//EventHandler.AssemblyUnload (req_id, thread_id, id);
} else if (kind == EventKind.TYPE_LOAD) {
long id = r.ReadId ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
//EventHandler.TypeLoad (req_id, thread_id, id);
} else if (kind == EventKind.METHOD_ENTRY) {
long id = r.ReadId ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
//EventHandler.MethodEntry (req_id, thread_id, id);
} else if (kind == EventKind.METHOD_EXIT) {
long id = r.ReadId ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
//EventHandler.MethodExit (req_id, thread_id, id);
} else if (kind == EventKind.BREAKPOINT) {
long id = r.ReadId ();
long loc = r.ReadLong ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id, Location = loc };
//EventHandler.Breakpoint (req_id, thread_id, id, loc);
} else if (kind == EventKind.STEP) {
long id = r.ReadId ();
long loc = r.ReadLong ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id, Location = loc };
//EventHandler.Step (req_id, thread_id, id, loc);
} else if (kind == EventKind.EXCEPTION) {
long id = r.ReadId ();
long loc = 0; // FIXME
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id, Location = loc };
//EventHandler.Exception (req_id, thread_id, id, loc);
} else if (kind == EventKind.APPDOMAIN_CREATE) {
long id = r.ReadId ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
//EventHandler.AppDomainCreate (req_id, thread_id, id);
} else if (kind == EventKind.APPDOMAIN_UNLOAD) {
long id = r.ReadId ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id };
//EventHandler.AppDomainUnload (req_id, thread_id, id);
} else if (kind == EventKind.USER_BREAK) {
long id = 0;
long loc = 0;
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Id = id, Location = loc };
//EventHandler.Exception (req_id, thread_id, id, loc);
} else if (kind == EventKind.USER_LOG) {
int level = r.ReadInt ();
string category = r.ReadString ();
string message = r.ReadString ();
events [i] = new EventInfo (etype, req_id) { ThreadId = thread_id, Level = level, Category = category, Message = message };
//EventHandler.Exception (req_id, thread_id, id, loc);
} else if (kind == EventKind.KEEPALIVE) {
events [i] = new EventInfo (etype, req_id) { };
} else {
throw new NotImplementedException ("Unknown event kind: " + kind);
}
}
EventHandler.Events (suspend_policy, events);
}
}
return true;
}
internal IEventHandler EventHandler {
get; set;
}
static String CommandString (CommandSet command_set, int command)
{
string cmd;
switch (command_set) {
case CommandSet.VM:
cmd = ((CmdVM)command).ToString ();
break;
case CommandSet.OBJECT_REF:
cmd = ((CmdObjectRef)command).ToString ();
break;
case CommandSet.STRING_REF:
cmd = ((CmdStringRef)command).ToString ();
break;
case CommandSet.THREAD:
cmd = ((CmdThread)command).ToString ();
break;
case CommandSet.ARRAY_REF:
cmd = ((CmdArrayRef)command).ToString ();
break;
case CommandSet.EVENT_REQUEST:
cmd = ((CmdEventRequest)command).ToString ();
break;
case CommandSet.STACK_FRAME:
cmd = ((CmdStackFrame)command).ToString ();
break;
case CommandSet.APPDOMAIN:
cmd = ((CmdAppDomain)command).ToString ();
break;
case CommandSet.ASSEMBLY:
cmd = ((CmdAssembly)command).ToString ();
break;
case CommandSet.METHOD:
cmd = ((CmdMethod)command).ToString ();
break;
case CommandSet.TYPE:
cmd = ((CmdType)command).ToString ();
break;
case CommandSet.MODULE:
cmd = ((CmdModule)command).ToString ();
break;
case CommandSet.FIELD:
cmd = ((CmdField)command).ToString ();
break;
case CommandSet.EVENT:
cmd = ((CmdEvent)command).ToString ();
break;
default:
cmd = command.ToString ();
break;
}
return string.Format ("[{0} {1}]", command_set, cmd);
}
long total_protocol_ticks;
void LogPacket (int packet_id, byte[] encoded_packet, byte[] reply_packet, CommandSet command_set, int command, Stopwatch watch) {
watch.Stop ();
total_protocol_ticks += watch.ElapsedTicks;
var ts = TimeSpan.FromTicks (total_protocol_ticks);
string msg = string.Format ("Packet: {0} sent: {1} received: {2} ms: {3} total ms: {4} {5}",
packet_id, encoded_packet.Length, reply_packet.Length, watch.ElapsedMilliseconds,
(ts.Seconds * 1000) + ts.Milliseconds,
CommandString (command_set, command));
LoggingStream.WriteLine (msg);
LoggingStream.Flush ();
}
bool buffer_packets;
List<byte[]> buffered_packets = new List<byte[]> ();
//
// Start buffering request/response packets on both the client and the debuggee side.
// Packets sent between StartBuffering ()/StopBuffering () must be async, i.e. sent
// using Send () and not SendReceive ().
//
public void StartBuffering () {
buffer_packets = true;
if (Version.AtLeast (2, 34))
VM_StartBuffering ();
}
public void StopBuffering () {
if (Version.AtLeast (2, 34))
VM_StopBuffering ();
buffer_packets = false;
WritePackets (buffered_packets);
if (EnableConnectionLogging) {
LoggingStream.WriteLine (String.Format ("Sent {0} packets.", buffered_packets.Count));
LoggingStream.Flush ();
}
buffered_packets.Clear ();
}
/* Send a request and call cb when a result is received */
int Send (CommandSet command_set, int command, PacketWriter packet, Action<PacketReader> cb, int count) {
int id = IdGenerator;
Stopwatch watch = null;
if (EnableConnectionLogging)
watch = Stopwatch.StartNew ();
byte[] encoded_packet;
if (packet == null)
encoded_packet = EncodePacket (id, (int)command_set, command, null, 0);
else
encoded_packet = EncodePacket (id, (int)command_set, command, packet.Data, packet.Offset);
if (cb != null) {
lock (reply_packets_monitor) {
reply_cbs [id] = delegate (int packet_id, byte[] p) {
if (EnableConnectionLogging)
LogPacket (packet_id, encoded_packet, p, command_set, command, watch);
/* Run the callback on a tp thread to avoid blocking the receive thread */
PacketReader r = new PacketReader (this, p);
cb.BeginInvoke (r, null, null);
};
reply_cb_counts [id] = count;
}
}
if (buffer_packets)
buffered_packets.Add (encoded_packet);
else
WritePacket (encoded_packet);
return id;
}
// Send a request without waiting for an answer
void Send (CommandSet command_set, int command) {
Send (command_set, command, null, null, 0);
}
PacketReader SendReceive (CommandSet command_set, int command, PacketWriter packet) {
int id = IdGenerator;
Stopwatch watch = null;
disconnected_check ();
if (EnableConnectionLogging)
watch = Stopwatch.StartNew ();
byte[] encoded_packet;
if (packet == null)
encoded_packet = EncodePacket (id, (int)command_set, command, null, 0);
else
encoded_packet = EncodePacket (id, (int)command_set, command, packet.Data, packet.Offset);
WritePacket (encoded_packet);
int packetId = id;
/* Wait for the reply packet */
while (true) {
lock (reply_packets_monitor) {
byte[] reply;
if (reply_packets.TryGetValue (packetId, out reply)) {
reply_packets.Remove (packetId);
PacketReader r = new PacketReader (this, reply);
if (EnableConnectionLogging)
LogPacket (packetId, encoded_packet, reply, command_set, command, watch);
if (r.ErrorCode != 0) {
if (ErrorHandler != null)
ErrorHandler (this, new ErrorHandlerEventArgs () { ErrorCode = (ErrorCode)r.ErrorCode });
throw new NotImplementedException ("No error handler set.");
} else {
return r;
}
} else {
disconnected_check ();
Monitor.Wait (reply_packets_monitor);
}
}
}
}
PacketReader SendReceive (CommandSet command_set, int command) {
return SendReceive (command_set, command, null);
}
int packet_id_generator;
int IdGenerator {
get {
return Interlocked.Increment (ref packet_id_generator);
}
}
CattrInfo[] ReadCattrs (PacketReader r) {
CattrInfo[] res = new CattrInfo [r.ReadInt ()];
for (int i = 0; i < res.Length; ++i) {
CattrInfo info = new CattrInfo ();
info.ctor_id = r.ReadId ();
info.ctor_args = new ValueImpl [r.ReadInt ()];
for (int j = 0; j < info.ctor_args.Length; ++j) {
info.ctor_args [j] = r.ReadValue ();
}
info.named_args = new CattrNamedArgInfo [r.ReadInt ()];
for (int j = 0; j < info.named_args.Length; ++j) {
CattrNamedArgInfo arg = new CattrNamedArgInfo ();
int arg_type = r.ReadByte ();
arg.is_property = arg_type == 0x54;
// 2.12 is the only version we can guarantee the server will send a field id
// It was added in https://github.com/mono/mono/commit/db0b932cd6c3c93976479ae3f6b5b2a885f681de
// In between 2.11 and 2.12
if (arg.is_property)
arg.id = r.ReadId ();
else if (Version.AtLeast (2, 12))
arg.id = r.ReadId ();
arg.value = r.ReadValue ();
info.named_args [j] = arg;
}
res [i] = info;
}
return res;
}
static ElementType TypeCodeToElementType (TypeCode c, Type t) {
switch (c) {
case TypeCode.Boolean:
return ElementType.Boolean;
case TypeCode.Char:
return ElementType.Char;
case TypeCode.SByte:
return ElementType.I1;
case TypeCode.Byte:
return ElementType.U1;
case TypeCode.Int16:
return ElementType.I2;
case TypeCode.UInt16:
return ElementType.U2;
case TypeCode.Int32:
return ElementType.I4;
case TypeCode.UInt32:
return ElementType.U4;
case TypeCode.Int64:
return ElementType.I8;
case TypeCode.UInt64:
return ElementType.U8;
case TypeCode.Single:
return ElementType.R4;
case TypeCode.Double:
return ElementType.R8;
case TypeCode.Object:
return TypeCodeToElementType(Type.GetTypeCode (t.GetElementType()), t.GetElementType());
default:
throw new NotImplementedException ();
}
}
/*
* Implementation of debugger commands
*/
internal VersionInfo VM_GetVersion () {
var res = SendReceive (CommandSet.VM, (int)CmdVM.VERSION, null);
VersionInfo info = new VersionInfo ();
info.VMVersion = res.ReadString ();
info.MajorVersion = res.ReadInt ();
info.MinorVersion = res.ReadInt ();
return info;
}
internal void VM_SetProtocolVersion (int major, int minor) {
SendReceive (CommandSet.VM, (int)CmdVM.SET_PROTOCOL_VERSION, new PacketWriter ().WriteInt (major).WriteInt (minor));
}
internal void VM_GetThreads (Action<long[]> resultCallaback) {
Send (CommandSet.VM, (int)CmdVM.ALL_THREADS, null, (res) => {
int len = res.ReadInt ();
long[] arr = new long [len];
for (int i = 0; i < len; ++i)
arr [i] = res.ReadId ();
resultCallaback(arr);
}, 1);
}
internal void VM_Suspend () {
SendReceive (CommandSet.VM, (int)CmdVM.SUSPEND);
}
internal void VM_Resume () {
SendReceive (CommandSet.VM, (int)CmdVM.RESUME);
}
internal void VM_Exit (int exitCode) {
SendReceive (CommandSet.VM, (int)CmdVM.EXIT, new PacketWriter ().WriteInt (exitCode));
}
internal void VM_Dispose () {
SendReceive (CommandSet.VM, (int)CmdVM.DISPOSE);
}
internal ValueImpl VM_InvokeMethod (long thread, long method, ValueImpl this_arg, ValueImpl[] arguments, InvokeFlags flags, out ValueImpl exc) {
exc = null;
PacketReader r = SendReceive (CommandSet.VM, (int)CmdVM.INVOKE_METHOD, new PacketWriter ().WriteId (thread).WriteInt ((int)flags).WriteId (method).WriteValue (this_arg).WriteInt (arguments.Length).WriteValues (arguments));
if (r.ReadByte () == 0) {
exc = r.ReadValue ();
return null;
} else {
return r.ReadValue ();
}
}
internal delegate void InvokeMethodCallback (ValueImpl v, ValueImpl exc, ValueImpl out_this, ValueImpl[] out_args, ErrorCode error, object state);
void read_invoke_res (PacketReader r, out ValueImpl v, out ValueImpl exc, out ValueImpl out_this, out ValueImpl[] out_args) {
int resflags = r.ReadByte ();
v = null;
exc = null;
out_this = null;
out_args = null;
if (resflags == 0) {
exc = r.ReadValue ();
} else {
v = r.ReadValue ();
if ((resflags & 2) != 0)
out_this = r.ReadValue ();
if ((resflags & 4) != 0) {
int nargs = r.ReadInt ();
out_args = new ValueImpl [nargs];
for (int i = 0; i < nargs; ++i)
out_args [i] = r.ReadValue ();
}
}
}
internal int VM_BeginInvokeMethod (long thread, long method, ValueImpl this_arg, ValueImpl[] arguments, InvokeFlags flags, InvokeMethodCallback callback, object state) {
return Send (CommandSet.VM, (int)CmdVM.INVOKE_METHOD, new PacketWriter ().WriteId (thread).WriteInt ((int)flags).WriteId (method).WriteValue (this_arg).WriteInt (arguments.Length).WriteValues (arguments), delegate (PacketReader r) {
ValueImpl v, exc, out_this = null;
ValueImpl[] out_args = null;
if (r.ErrorCode != 0) {
callback (null, null, null, null, (ErrorCode)r.ErrorCode, state);
} else {
read_invoke_res (r, out v, out exc, out out_this, out out_args);
callback (v, exc, out_this, out_args, 0, state);
}
}, 1);
}
internal int VM_BeginInvokeMethods (long thread, long[] methods, ValueImpl this_arg, List<ValueImpl[]> arguments, InvokeFlags flags, InvokeMethodCallback callback, object state) {
// FIXME: Merge this with INVOKE_METHOD
var w = new PacketWriter ();
w.WriteId (thread);
w.WriteInt ((int)flags);
w.WriteInt (methods.Length);
for (int i = 0; i < methods.Length; ++i) {
w.WriteId (methods [i]);
w.WriteValue (this_arg);
w.WriteInt (arguments [i].Length);
w.WriteValues (arguments [i]);
}
return Send (CommandSet.VM, (int)CmdVM.INVOKE_METHODS, w, delegate (PacketReader r) {
ValueImpl v, exc, out_this = null;
ValueImpl[] out_args = null;
if (r.ErrorCode != 0) {
callback (null, null, null, null, (ErrorCode)r.ErrorCode, state);
} else {
read_invoke_res (r, out v, out exc, out out_this, out out_args);
callback (v, exc, out_this, out_args, 0, state);
}
}, methods.Length);
}
internal void VM_AbortInvoke (long thread, int id)
{
SendReceive (CommandSet.VM, (int)CmdVM.ABORT_INVOKE, new PacketWriter ().WriteId (thread).WriteInt (id));
}
internal void SetSocketTimeouts (int send_timeout, int receive_timeout, int keepalive_interval)
{
TransportSetTimeouts (send_timeout, receive_timeout);
SendReceive (CommandSet.VM, (int)CmdVM.SET_KEEPALIVE, new PacketWriter ().WriteId (keepalive_interval));
}
internal long[] VM_GetTypesForSourceFile (string fname, bool ignoreCase) {
var res = SendReceive (CommandSet.VM, (int)CmdVM.GET_TYPES_FOR_SOURCE_FILE, new PacketWriter ().WriteString (fname).WriteBool (ignoreCase));
int count = res.ReadInt ();
long[] types = new long [count];
for (int i = 0; i < count; ++i)
types [i] = res.ReadId ();
return types;
}
internal long[] VM_GetTypes (string name, bool ignoreCase) {
var res = SendReceive (CommandSet.VM, (int)CmdVM.GET_TYPES, new PacketWriter ().WriteString (name).WriteBool (ignoreCase));
int count = res.ReadInt ();
long[] types = new long [count];
for (int i = 0; i < count; ++i)
types [i] = res.ReadId ();
return types;
}
internal void VM_StartBuffering () {
Send (CommandSet.VM, (int)CmdVM.START_BUFFERING);
}
internal void VM_StopBuffering () {
Send (CommandSet.VM, (int)CmdVM.STOP_BUFFERING);
}
/*
* DOMAIN
*/
internal long RootDomain {
get {
return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ROOT_DOMAIN, null).ReadId ();
}
}
internal string Domain_GetName (long id) {
return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_FRIENDLY_NAME, new PacketWriter ().WriteId (id)).ReadString ();
}
internal long[] Domain_GetAssemblies (long id) {
var res = SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ASSEMBLIES, new PacketWriter ().WriteId (id));
int count = res.ReadInt ();
long[] assemblies = new long [count];
for (int i = 0; i < count; ++i)
assemblies [i] = res.ReadId ();
return assemblies;
}
internal long Domain_GetEntryAssembly (long id) {
return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_ENTRY_ASSEMBLY, new PacketWriter ().WriteId (id)).ReadId ();
}
internal long Domain_GetCorlib (long id) {
return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.GET_CORLIB, new PacketWriter ().WriteId (id)).ReadId ();
}
internal long Domain_CreateString (long id, string s) {
return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.CREATE_STRING, new PacketWriter ().WriteId (id).WriteString (s)).ReadId ();
}
internal long Domain_CreateByteArray (long id, byte [] bytes) {
var w = new PacketWriter ().WriteId (id);
w.WriteBytes (bytes);
return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.CREATE_BYTE_ARRAY, w).ReadId ();
}
internal long Domain_CreateBoxedValue (long id, long type_id, ValueImpl v) {
return SendReceive (CommandSet.APPDOMAIN, (int)CmdAppDomain.CREATE_BOXED_VALUE, new PacketWriter ().WriteId (id).WriteId (type_id).WriteValue (v)).ReadId ();
}
/*
* METHOD
*/
internal string Method_GetName (long id) {
return SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_NAME, new PacketWriter ().WriteId (id)).ReadString ();
}
internal long Method_GetDeclaringType (long id) {
return SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_DECLARING_TYPE, new PacketWriter ().WriteId (id)).ReadId ();
}
internal DebugInfo Method_GetDebugInfo (long id) {
var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_DEBUG_INFO, new PacketWriter ().WriteId (id));
DebugInfo info = new DebugInfo ();
info.max_il_offset = res.ReadInt ();
SourceInfo[] sources = null;
if (Version.AtLeast (2, 13)) {
int n = res.ReadInt ();
sources = new SourceInfo [n];
for (int i = 0; i < n; ++i) {
sources [i].source_file = res.ReadString ();
if (Version.AtLeast (2, 14)) {
sources [i].hash = new byte [16];
for (int j = 0; j < 16; ++j)
sources [i].hash [j] = (byte)res.ReadByte ();
}
}
} else {
sources = new SourceInfo [1];
sources [0].source_file = res.ReadString ();
}
int n_il_offsets = res.ReadInt ();
info.il_offsets = new int [n_il_offsets];
info.line_numbers = new int [n_il_offsets];
info.source_files = new SourceInfo [n_il_offsets];
info.column_numbers = new int [n_il_offsets];
info.end_line_numbers = new int [n_il_offsets];
info.end_column_numbers = new int [n_il_offsets];
for (int i = 0; i < n_il_offsets; ++i) {
info.il_offsets [i] = res.ReadInt ();
info.line_numbers [i] = res.ReadInt ();
if (Version.AtLeast (2, 12)) {
int idx = res.ReadInt ();
info.source_files [i] = idx >= 0 ? sources [idx] : default (SourceInfo);
} else {
info.source_files [i] = sources [0];
}
if (Version.AtLeast (2, 19))
info.column_numbers [i] = res.ReadInt ();
else
info.column_numbers [i] = 0;
if (Version.AtLeast (2, 32)) {
info.end_line_numbers [i] = res.ReadInt ();
info.end_column_numbers [i] = res.ReadInt ();
} else {
info.end_column_numbers [i] = -1;
info.end_column_numbers [i] = -1;
}
}
return info;
}
internal ParamInfo Method_GetParamInfo (long id) {
var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_PARAM_INFO, new PacketWriter ().WriteId (id));
ParamInfo info = new ParamInfo ();
info.call_conv = res.ReadInt ();
info.param_count = res.ReadInt ();
info.generic_param_count = res.ReadInt ();
info.ret_type = res.ReadId ();
info.param_types = new long [info.param_count];
for (int i = 0; i < info.param_count; ++i)
info.param_types [i] = res.ReadId ();
info.param_names = new string [info.param_count];
for (int i = 0; i < info.param_count; ++i)
info.param_names [i] = res.ReadString ();
return info;
}
internal LocalsInfo Method_GetLocalsInfo (long id) {
var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_LOCALS_INFO, new PacketWriter ().WriteId (id));
LocalsInfo info = new LocalsInfo ();
if (Version.AtLeast (2, 43)) {
int nscopes = res.ReadInt ();
info.scopes_start = new int [nscopes];
info.scopes_end = new int [nscopes];
int last_start = 0;
for (int i = 0; i < nscopes; ++i) {
info.scopes_start [i] = last_start + res.ReadInt ();
info.scopes_end [i] = info.scopes_start [i] + res.ReadInt ();
last_start = info.scopes_start [i];
}
}
int nlocals = res.ReadInt ();
info.types = new long [nlocals];
for (int i = 0; i < nlocals; ++i)
info.types [i] = res.ReadId ();
info.names = new string [nlocals];
for (int i = 0; i < nlocals; ++i)
info.names [i] = res.ReadString ();
info.live_range_start = new int [nlocals];
info.live_range_end = new int [nlocals];
for (int i = 0; i < nlocals; ++i) {
info.live_range_start [i] = res.ReadInt ();
info.live_range_end [i] = res.ReadInt ();
}
return info;
}
internal MethodInfo Method_GetInfo (long id) {
var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_INFO, new PacketWriter ().WriteId (id));
MethodInfo info = new MethodInfo ();
info.attributes = res.ReadInt ();
info.iattributes = res.ReadInt ();
info.token = res.ReadInt ();
if (Version.AtLeast (2, 12)) {
int attrs = res.ReadByte ();
if ((attrs & (1 << 0)) != 0)
info.is_gmd = true;
if ((attrs & (1 << 1)) != 0)
info.is_generic_method = true;
info.gmd = res.ReadId ();
if (Version.AtLeast (2, 15)) {
if (info.is_generic_method) {
int n = res.ReadInt ();
info.type_args = res.ReadIds (n);
}
}
}
return info;
}
internal MethodBodyInfo Method_GetBody (long id) {
var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_BODY, new PacketWriter ().WriteId (id));
MethodBodyInfo info = new MethodBodyInfo ();
info.il = new byte [res.ReadInt ()];
for (int i = 0; i < info.il.Length; ++i)
info.il [i] = (byte)res.ReadByte ();
if (Version.AtLeast (2, 18)) {
info.clauses = new ExceptionClauseInfo [res.ReadInt ()];
for (int i = 0; i < info.clauses.Length; ++i) {
var clause = new ExceptionClauseInfo {
flags = (ExceptionClauseFlags) res.ReadInt (),
try_offset = res.ReadInt (),
try_length = res.ReadInt (),
handler_offset = res.ReadInt (),
handler_length = res.ReadInt (),
};
if (clause.flags == ExceptionClauseFlags.None)
clause.catch_type_id = res.ReadId ();
else if (clause.flags == ExceptionClauseFlags.Filter)
clause.filter_offset = res.ReadInt ();
info.clauses [i] = clause;
}
} else
info.clauses = new ExceptionClauseInfo [0];
return info;
}
internal ResolvedToken Method_ResolveToken (long id, int token) {
var res = SendReceive (CommandSet.METHOD, (int)CmdMethod.RESOLVE_TOKEN, new PacketWriter ().WriteId (id).WriteInt (token));
TokenType type = (TokenType)res.ReadByte ();
switch (type) {
case TokenType.STRING:
return new ResolvedToken () { Type = type, Str = res.ReadString () };
case TokenType.TYPE:
case TokenType.METHOD:
case TokenType.FIELD:
return new ResolvedToken () { Type = type, Id = res.ReadId () };
case TokenType.UNKNOWN:
return new ResolvedToken () { Type = type };
default:
throw new NotImplementedException ();
}
}
internal CattrInfo[] Method_GetCustomAttributes (long id, long attr_type_id, bool inherit) {
PacketReader r = SendReceive (CommandSet.METHOD, (int)CmdMethod.GET_CATTRS, new PacketWriter ().WriteId (id).WriteId (attr_type_id));
return ReadCattrs (r);
}
internal long Method_MakeGenericMethod (long id, long[] args) {
PacketReader r = SendReceive (CommandSet.METHOD, (int)CmdMethod.MAKE_GENERIC_METHOD, new PacketWriter ().WriteId (id).WriteInt (args.Length).WriteIds (args));
return r.ReadId ();
}
/*
* THREAD
*/
internal string Thread_GetName (long id) {
return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_NAME, new PacketWriter ().WriteId (id)).ReadString ();
}
internal long Thread_GetElapsedTime (long id) {
return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_ELAPSED_TIME, new PacketWriter ().WriteId (id)).ReadLong ();
}
internal void Thread_GetFrameInfo (long id, int start_frame, int length, Action<FrameInfo[]> resultCallaback) {
Send (CommandSet.THREAD, (int)CmdThread.GET_FRAME_INFO, new PacketWriter ().WriteId (id).WriteInt (start_frame).WriteInt (length), (res) => {
int count = res.ReadInt ();
var frames = new FrameInfo[count];
for (int i = 0; i < count; ++i) {
var f = new FrameInfo ();
f.id = res.ReadInt ();
f.method = res.ReadId ();
f.il_offset = res.ReadInt ();
f.flags = (StackFrameFlags)res.ReadByte ();
frames [i] = f;
}
resultCallaback (frames);
}, 1);
}
internal int Thread_GetState (long id) {
return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_STATE, new PacketWriter ().WriteId (id)).ReadInt ();
}
internal ThreadInfo Thread_GetInfo (long id) {
PacketReader r = SendReceive (CommandSet.THREAD, (int)CmdThread.GET_INFO, new PacketWriter ().WriteId (id));
ThreadInfo res = new ThreadInfo () { is_thread_pool = r.ReadByte () > 0 ? true : false };
return res;
}
internal long Thread_GetId (long id) {
return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_ID, new PacketWriter ().WriteId (id)).ReadLong ();
}
internal long Thread_GetTID (long id) {
return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_TID, new PacketWriter ().WriteId (id)).ReadLong ();
}
internal void Thread_SetIP (long id, long method_id, long il_offset) {
SendReceive (CommandSet.THREAD, (int)CmdThread.SET_IP, new PacketWriter ().WriteId (id).WriteId (method_id).WriteLong (il_offset));
}
/*
* MODULE
*/
internal ModuleInfo Module_GetInfo (long id) {
PacketReader r = SendReceive (CommandSet.MODULE, (int)CmdModule.GET_INFO, new PacketWriter ().WriteId (id));
ModuleInfo info = new ModuleInfo { Name = r.ReadString (), ScopeName = r.ReadString (), FQName = r.ReadString (), Guid = r.ReadString (), Assembly = r.ReadId () };
if (Version.AtLeast (2, 48))
info.SourceLink = r.ReadString ();
return info;
}
/*
* ASSEMBLY
*/
internal string Assembly_GetLocation (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_LOCATION, new PacketWriter ().WriteId (id)).ReadString ();
}
internal long Assembly_GetEntryPoint (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_ENTRY_POINT, new PacketWriter ().WriteId (id)).ReadId ();
}
internal long Assembly_GetManifestModule (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_MANIFEST_MODULE, new PacketWriter ().WriteId (id)).ReadId ();
}
internal long Assembly_GetObject (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_OBJECT, new PacketWriter ().WriteId (id)).ReadId ();
}
internal long Assembly_GetType (long id, string name, bool ignoreCase) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_TYPE, new PacketWriter ().WriteId (id).WriteString (name).WriteBool (ignoreCase)).ReadId ();
}
internal string Assembly_GetName (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_NAME, new PacketWriter ().WriteId (id)).ReadString ();
}
internal long Assembly_GetIdDomain (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_DOMAIN, new PacketWriter ().WriteId (id)).ReadId ();
}
internal byte[] Assembly_GetMetadataBlob (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_METADATA_BLOB, new PacketWriter ().WriteId (id)).ReadByteArray ();
}
internal bool Assembly_IsDynamic (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int) CmdAssembly.GET_IS_DYNAMIC, new PacketWriter ().WriteId (id)).ReadBool ();
}
internal byte[] Assembly_GetPdbBlob (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_PDB_BLOB, new PacketWriter ().WriteId (id)).ReadByteArray ();
}
internal long Assembly_GetType (long id, uint token) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_TYPE_FROM_TOKEN, new PacketWriter ().WriteId (id).WriteInt ((int)token)).ReadId ();
}
internal long Assembly_GetMethod (long id, uint token) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.GET_METHOD_FROM_TOKEN, new PacketWriter ().WriteId (id).WriteInt ((int)token)).ReadId ();
}
internal bool Assembly_HasDebugInfo (long id) {
return SendReceive (CommandSet.ASSEMBLY, (int)CmdAssembly.HAS_DEBUG_INFO, new PacketWriter ().WriteId (id)).ReadBool ();
}
/*
* TYPE
*/
internal TypeInfo Type_GetInfo (long id) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_INFO, new PacketWriter ().WriteId (id));
TypeInfo res = new TypeInfo ();
res.ns = r.ReadString ();
res.name = r.ReadString ();
res.full_name = r.ReadString ();
res.assembly = r.ReadId ();
res.module = r.ReadId ();
res.base_type = r.ReadId ();
res.element_type = r.ReadId ();
res.token = r.ReadInt ();
res.rank = r.ReadByte ();
res.attributes = r.ReadInt ();
int b = r.ReadByte ();
res.is_byref = (b & 1) != 0;
res.is_pointer = (b & 2) != 0;
res.is_primitive = (b & 4) != 0;
res.is_valuetype = (b & 8) != 0;
res.is_enum = (b & 16) != 0;
res.is_gtd = (b & 32) != 0;
res.is_generic_type = (b & 64) != 0;
int nested_len = r.ReadInt ();
res.nested = new long [nested_len];
for (int i = 0; i < nested_len; ++i)
res.nested [i] = r.ReadId ();
if (Version.AtLeast (2, 12))
res.gtd = r.ReadId ();
if (Version.AtLeast (2, 15) && res.is_generic_type) {
int n = r.ReadInt ();
res.type_args = r.ReadIds (n);
}
return res;
}
internal long[] Type_GetMethods (long id) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_METHODS, new PacketWriter ().WriteId (id));
int n = r.ReadInt ();
long[] res = new long [n];
for (int i = 0; i < n; ++i)
res [i] = r.ReadId ();
return res;
}
internal long[] Type_GetFields (long id, out string[] names, out long[] types, out int[] attrs) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_FIELDS, new PacketWriter ().WriteId (id));
int n = r.ReadInt ();
long[] res = new long [n];
names = new string [n];
types = new long [n];
attrs = new int [n];
for (int i = 0; i < n; ++i) {
res [i] = r.ReadId ();
names [i] = r.ReadString ();
types [i] = r.ReadId ();
attrs [i] = r.ReadInt ();
}
return res;
}
internal PropInfo[] Type_GetProperties (long id) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_PROPERTIES, new PacketWriter ().WriteId (id));
int n = r.ReadInt ();
PropInfo[] res = new PropInfo [n];
for (int i = 0; i < n; ++i) {
res [i] = new PropInfo ();
res [i].id = r.ReadId ();
res [i].name = r.ReadString ();
res [i].get_method = r.ReadId ();
res [i].set_method = r.ReadId ();
res [i].attrs = r.ReadInt ();
}
return res;
}
internal long Type_GetObject (long id) {
return SendReceive (CommandSet.TYPE, (int)CmdType.GET_OBJECT, new PacketWriter ().WriteId (id)).ReadId ();
}
internal ValueImpl[] Type_GetValues (long id, long[] fields, long thread_id) {
int len = fields.Length;
PacketReader r;
if (thread_id != 0 && Version.AtLeast(2, 3))
r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_VALUES_2, new PacketWriter ().WriteId (id).WriteId (thread_id).WriteInt (len).WriteIds (fields));
else
r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (len).WriteIds (fields));
ValueImpl[] res = new ValueImpl [len];
for (int i = 0; i < len; ++i)
res [i] = r.ReadValue ();
return res;
}
internal void Type_SetValues (long id, long[] fields, ValueImpl[] values) {
SendReceive (CommandSet.TYPE, (int)CmdType.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (fields.Length).WriteIds (fields).WriteValues (values));
}
internal string[] Type_GetSourceFiles (long id, bool return_full_paths) {
var r = SendReceive (CommandSet.TYPE, return_full_paths ? (int)CmdType.GET_SOURCE_FILES_2 : (int)CmdType.GET_SOURCE_FILES, new PacketWriter ().WriteId (id));
int len = r.ReadInt ();
string[] res = new string [len];
for (int i = 0; i < len; ++i)
res [i] = r.ReadString ();
return res;
}
internal bool Type_IsAssignableFrom (long id, long c_id) {
return SendReceive (CommandSet.TYPE, (int)CmdType.IS_ASSIGNABLE_FROM, new PacketWriter ().WriteId (id).WriteId (c_id)).ReadByte () > 0;
}
internal CattrInfo[] Type_GetCustomAttributes (long id, long attr_type_id, bool inherit) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_CATTRS, new PacketWriter ().WriteId (id).WriteId (attr_type_id));
return ReadCattrs (r);
}
internal CattrInfo[] Type_GetFieldCustomAttributes (long id, long field_id, long attr_type_id, bool inherit) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_FIELD_CATTRS, new PacketWriter ().WriteId (id).WriteId (field_id).WriteId (attr_type_id));
return ReadCattrs (r);
}
internal CattrInfo[] Type_GetPropertyCustomAttributes (long id, long field_id, long attr_type_id, bool inherit) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_PROPERTY_CATTRS, new PacketWriter ().WriteId (id).WriteId (field_id).WriteId (attr_type_id));
return ReadCattrs (r);
}
public long[] Type_GetMethodsByNameFlags (long id, string name, int flags, bool ignoreCase) {
flags |= ignoreCase ? (int)BindingFlagsExtensions.BINDING_FLAGS_IGNORE_CASE : 0;
int listType = ignoreCase ? (int)MemberListTypeExtensions.CaseInsensitive : (int)MemberListTypeExtensions.CaseSensitive;
var w = new PacketWriter ().WriteId (id).WriteString (name).WriteInt (flags);
if (Version.AtLeast (2, 48))
w.WriteInt (listType);
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.CMD_TYPE_GET_METHODS_BY_NAME_FLAGS, w);
int len = r.ReadInt ();
long[] res = new long [len];
for (int i = 0; i < len; ++i)
res [i] = r.ReadId ();
return res;
}
internal long[] Type_GetInterfaces (long id) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_INTERFACES, new PacketWriter ().WriteId (id));
int len = r.ReadInt ();
return r.ReadIds (len);
}
internal IfaceMapInfo[] Type_GetInterfaceMap (long id, long[] ids) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_INTERFACE_MAP, new PacketWriter ().WriteId (id).WriteInt (ids.Length).WriteIds (ids));
var res = new IfaceMapInfo [ids.Length];
for (int i = 0; i < ids.Length; ++i) {
int n = r.ReadInt ();
res [i].iface_id = ids [i];
res [i].iface_methods = r.ReadIds (n);
res [i].target_methods = r.ReadIds (n);
}
return res;
}
internal bool Type_IsInitialized (long id) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.IS_INITIALIZED, new PacketWriter ().WriteId (id));
return r.ReadInt () == 1;
}
internal long Type_CreateInstance (long id) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.CREATE_INSTANCE, new PacketWriter ().WriteId (id));
return r.ReadId ();
}
internal int Type_GetValueSize (long id) {
PacketReader r = SendReceive (CommandSet.TYPE, (int)CmdType.GET_VALUE_SIZE, new PacketWriter ().WriteId (id));
return r.ReadInt ();
}
/*
* FIELD
*/
internal FieldMirrorInfo Field_GetInfo (long id) {
PacketReader r = SendReceive (CommandSet.FIELD, (int)CmdField.GET_INFO, new PacketWriter ().WriteId (id));
FieldMirrorInfo info = new FieldMirrorInfo { Name = r.ReadString (), Parent = r.ReadId (), TypeId = r.ReadId (), Attrs = r.ReadInt () };
return info;
}
/*
* EVENTS
*/
internal int EnableEvent (EventType etype, SuspendPolicy suspend_policy, List<Modifier> mods) {
var w = new PacketWriter ().WriteByte ((byte)etype).WriteByte ((byte)suspend_policy);
if (mods != null) {
if (mods.Count > 255)
throw new NotImplementedException ();
w.WriteByte ((byte)mods.Count);
foreach (Modifier mod in mods) {
if (mod is CountModifier) {
w.WriteByte ((byte)ModifierKind.COUNT);
w.WriteInt ((mod as CountModifier).Count);
} else if (mod is LocationModifier) {
w.WriteByte ((byte)ModifierKind.LOCATION_ONLY);
w.WriteId ((mod as LocationModifier).Method);
w.WriteLong ((mod as LocationModifier).Location);
} else if (mod is StepModifier) {
w.WriteByte ((byte)ModifierKind.STEP);
w.WriteId ((mod as StepModifier).Thread);
w.WriteInt ((mod as StepModifier).Size);
w.WriteInt ((mod as StepModifier).Depth);
if (Version.AtLeast (2, 16))
w.WriteInt ((mod as StepModifier).Filter);
} else if (mod is ThreadModifier) {
w.WriteByte ((byte)ModifierKind.THREAD_ONLY);
w.WriteId ((mod as ThreadModifier).Thread);
} else if (mod is ExceptionModifier) {
var em = mod as ExceptionModifier;
w.WriteByte ((byte)ModifierKind.EXCEPTION_ONLY);
w.WriteId (em.Type);
if (Version.MajorVersion > 2 || Version.MinorVersion > 0) {
/* This is only supported in protocol version 2.1 */
w.WriteBool (em.Caught);
w.WriteBool (em.Uncaught);
} else if (!em.Caught || !em.Uncaught) {
throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
}
if (Version.MajorVersion > 2 || Version.MinorVersion > 24) {
w.WriteBool (em.Subclasses);
} else if (!em.Subclasses) {
throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
}
if (Version.MajorVersion > 2 || Version.MinorVersion >= 54) {
w.WriteBool (em.NotFilteredFeature);
w.WriteBool (em.EverythingElse);
}
} else if (mod is AssemblyModifier) {
w.WriteByte ((byte)ModifierKind.ASSEMBLY_ONLY);
var amod = (mod as AssemblyModifier);
w.WriteInt (amod.Assemblies.Length);
foreach (var id in amod.Assemblies)
w.WriteId (id);
} else if (mod is SourceFileModifier) {
w.WriteByte ((byte)ModifierKind.SOURCE_FILE_ONLY);
var smod = (mod as SourceFileModifier);
w.WriteInt (smod.SourceFiles.Length);
foreach (var s in smod.SourceFiles)
w.WriteString (s);
} else if (mod is TypeNameModifier) {
w.WriteByte ((byte)ModifierKind.TYPE_NAME_ONLY);
var tmod = (mod as TypeNameModifier);
w.WriteInt (tmod.TypeNames.Length);
foreach (var s in tmod.TypeNames)
w.WriteString (s);
} else {
throw new NotImplementedException ();
}
}
} else {
w.WriteByte (0);
}
return SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.SET, w).ReadInt ();
}
internal void ClearEventRequest (EventType etype, int req_id) {
SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.CLEAR, new PacketWriter ().WriteByte ((byte)etype).WriteInt (req_id));
}
internal void ClearAllBreakpoints () {
SendReceive (CommandSet.EVENT_REQUEST, (int)CmdEventRequest.CLEAR_ALL_BREAKPOINTS, new PacketWriter ());
}
/*
* STACK FRAME
*/
internal ValueImpl StackFrame_GetThis (long thread_id, long id) {
PacketReader r = SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.GET_THIS, new PacketWriter ().WriteId (thread_id).WriteId (id));
return r.ReadValue ();
}
internal ValueImpl[] StackFrame_GetValues (long thread_id, long id, int[] pos) {
/* pos < 0 -> argument at pos (-pos) - 1 */
/* pos >= 0 -> local at pos */
int len = pos.Length;
PacketReader r = SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.GET_VALUES, new PacketWriter ().WriteId (thread_id).WriteId (id).WriteInt (len).WriteInts (pos));
ValueImpl[] res = new ValueImpl [len];
for (int i = 0; i < len; ++i)
res [i] = r.ReadValue ();
return res;
}
internal void StackFrame_SetValues (long thread_id, long id, int[] pos, ValueImpl[] values) {
/* pos < 0 -> argument at pos (-pos) - 1 */
/* pos >= 0 -> local at pos */
int len = pos.Length;
SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.SET_VALUES, new PacketWriter ().WriteId (thread_id).WriteId (id).WriteInt (len).WriteInts (pos).WriteValues (values));
}
internal long StackFrame_GetDomain (long thread_id, long id) {
return SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.GET_DOMAIN, new PacketWriter ().WriteId (thread_id).WriteId (id)).ReadId ();
}
internal void StackFrame_SetThis (long thread_id, long id, ValueImpl value) {
SendReceive (CommandSet.STACK_FRAME, (int)CmdStackFrame.SET_THIS, new PacketWriter ().WriteId (thread_id).WriteId (id).WriteValue (value));
}
/*
* ARRAYS
*/
internal int[] Array_GetLength (long id, out int rank, out int[] lower_bounds) {
var r = SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.GET_LENGTH, new PacketWriter ().WriteId (id));
rank = r.ReadInt ();
int[] res = new int [rank];
lower_bounds = new int [rank];
for (int i = 0; i < rank; ++i) {
res [i] = r.ReadInt ();
lower_bounds [i] = r.ReadInt ();
}
return res;
}
internal ValueImpl[] Array_GetValues (long id, int index, int len) {
var r = SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (index).WriteInt (len));
ValueImpl[] res = new ValueImpl [len];
for (int i = 0; i < len; ++i)
res [i] = r.ReadValue ();
return res;
}
internal void Array_SetValues (long id, int index, ValueImpl[] values) {
SendReceive (CommandSet.ARRAY_REF, (int)CmdArrayRef.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (index).WriteInt (values.Length).WriteValues (values));
}
/*
* STRINGS
*/
internal string String_GetValue (long id) {
var r = SendReceive (CommandSet.STRING_REF, (int)CmdStringRef.GET_VALUE, new PacketWriter ().WriteId (id));
bool is_utf16 = false;
if (Version.AtLeast (2, 41))
is_utf16 = r.ReadByte () == 1;
if (is_utf16)
return r.ReadUTF16String ();
else
return r.ReadString ();
}
internal int String_GetLength (long id) {
return (int)SendReceive (CommandSet.STRING_REF, (int)CmdStringRef.GET_LENGTH, new PacketWriter ().WriteId (id)).ReadLong ();
}
internal char[] String_GetChars (long id, int index, int length) {
var r = SendReceive (CommandSet.STRING_REF, (int)CmdStringRef.GET_CHARS, new PacketWriter ().WriteId (id).WriteLong (index).WriteLong (length));
var res = new char [length];
for (int i = 0; i < length; ++i)
res [i] = (char)r.ReadShort ();
return res;
}
/*
* POINTERS
*/
internal ValueImpl Pointer_GetValue (long address, TypeMirror type)
{
return SendReceive (CommandSet.POINTER, (int)CmdPointer.GET_VALUE, new PacketWriter ().WriteLong (address).WriteId (type.Id)).ReadValue ();
}
/*
* OBJECTS
*/
internal long Object_GetType (long id) {
return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_TYPE, new PacketWriter ().WriteId (id)).ReadId ();
}
internal long Object_GetDomain (long id) {
return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_DOMAIN, new PacketWriter ().WriteId (id)).ReadId ();
}
internal ValueImpl[] Object_GetValues (long id, long[] fields) {
int len = fields.Length;
PacketReader r = SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_VALUES, new PacketWriter ().WriteId (id).WriteInt (len).WriteIds (fields));
ValueImpl[] res = new ValueImpl [len];
for (int i = 0; i < len; ++i)
res [i] = r.ReadValue ();
return res;
}
internal void Object_SetValues (long id, long[] fields, ValueImpl[] values) {
SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.SET_VALUES, new PacketWriter ().WriteId (id).WriteInt (fields.Length).WriteIds (fields).WriteValues (values));
}
internal bool Object_IsCollected (long id) {
return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.IS_COLLECTED, new PacketWriter ().WriteId (id)).ReadInt () == 1;
}
internal long Object_GetAddress (long id) {
return SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_ADDRESS, new PacketWriter ().WriteId (id)).ReadLong ();
}
internal ObjectRefInfo Object_GetInfo (long id) {
ObjectRefInfo res = new ObjectRefInfo ();
PacketReader r = SendReceive (CommandSet.OBJECT_REF, (int)CmdObjectRef.GET_INFO, new PacketWriter ().WriteId (id));
res.type_id = r.ReadId ();
res.domain_id = r.ReadId ();
return res;
}
public void ForceDisconnect ()
{
closed = true;
disconnected = true;
DisconnectedEvent.Set ();
TransportClose ();
}
}
class TcpConnection : Connection
{
Socket socket;
internal TcpConnection (Socket socket)
{
this.socket = socket;
//socket.SetSocketOption (SocketOptionLevel.IP, SocketOptionName.NoDelay, 1);
}
internal EndPoint EndPoint {
get {
return socket.RemoteEndPoint;
}
}
protected override int TransportSend (byte[] buf, int buf_offset, int len)
{
return socket.Send (buf, buf_offset, len, SocketFlags.None);
}
protected override int TransportReceive (byte[] buf, int buf_offset, int len)
{
return socket.Receive (buf, buf_offset, len, SocketFlags.None);
}
protected override void TransportSetTimeouts (int send_timeout, int receive_timeout)
{
socket.SendTimeout = send_timeout;
socket.ReceiveTimeout = receive_timeout;
}
protected override void TransportClose ()
{
socket.Close ();
}
protected override void TransportShutdown ()
{
socket.Shutdown (SocketShutdown.Both);
}
}
/* This is the interface exposed by the debugger towards the debugger agent */
interface IEventHandler
{
void Events (SuspendPolicy suspend_policy, EventInfo[] events);
void VMDisconnect (int req_id, long thread_id, string vm_uri);
}
}