Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm][debugger] Correct the endian swapping and string implementation #61386

Merged
merged 5 commits into from
Nov 10, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 47 additions & 112 deletions src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Microsoft.CodeAnalysis.CSharp;
using System.Reflection;
using System.Text;
using System.Runtime.CompilerServices;

namespace Microsoft.WebAssembly.Diagnostics
{
Expand Down Expand Up @@ -385,20 +386,6 @@ public MonoBinaryReader(Stream stream, bool hasError = false) : base(stream)
HasError = hasError;
}

internal static unsafe void PutBytesBE (byte *dest, byte *src, int count)
{
int i = 0;

if (BitConverter.IsLittleEndian){
dest += count;
for (; i < count; i++)
*(--dest) = *src++;
} else {
for (; i < count; i++)
*dest++ = *src++;
}
}

public override string ReadString()
{
var valueLen = ReadInt32();
Expand All @@ -407,108 +394,58 @@ public override string ReadString()

return new string(Encoding.UTF8.GetChars(value, 0, valueLen));
}
public unsafe long ReadLong()
{
byte[] data = new byte[8];
Read(data, 0, 8);

long ret;
fixed (byte *src = &data[0]){
PutBytesBE ((byte *) &ret, src, 8);
}

return ret;
}
public override unsafe sbyte ReadSByte()
{
byte[] data = new byte[4];
Read(data, 0, 4);
// SDB encodes these as 4 bytes
public override sbyte ReadSByte() => (sbyte)ReadInt32();
public byte ReadUByte() => (byte)ReadUInt32();
public ushort ReadUShort() => (ushort)ReadUInt32();
public override int ReadInt32() => ReadBigEndian<int>();

int ret;
fixed (byte *src = &data[0]){
PutBytesBE ((byte *) &ret, src, 4);
}
return (sbyte)ret;
}

public unsafe byte ReadUByte()
{
byte[] data = new byte[4];
Read(data, 0, 4);

int ret;
fixed (byte *src = &data[0]){
PutBytesBE ((byte *) &ret, src, 4);
}
return (byte)ret;
}

public override unsafe int ReadInt32()
{
byte[] data = new byte[4];
Read(data, 0, 4);
int ret;
fixed (byte *src = &data[0]){
PutBytesBE ((byte *) &ret, src, 4);
}
return ret;
}
public override double ReadDouble() => ReadBigEndian<double>();
public override uint ReadUInt32() => ReadBigEndian<uint>();
public override float ReadSingle() => ReadBigEndian<float>();
public override ulong ReadUInt64() => ReadBigEndian<ulong>();
public override long ReadInt64() => ReadBigEndian<long>();

public override unsafe double ReadDouble()
protected unsafe T ReadBigEndian<T>() where T : struct
{
byte[] data = new byte[8];
Read(data, 0, 8);

double ret;
fixed (byte *src = &data[0]){
PutBytesBE ((byte *) &ret, src, 8);
}
return ret;
}

public override unsafe uint ReadUInt32()
{
byte[] data = new byte[4];
Read(data, 0, 4);

uint ret;
fixed (byte *src = &data[0]){
PutBytesBE ((byte *) &ret, src, 4);
Span<byte> data = stackalloc byte[Unsafe.SizeOf<T>()];
T ret = default;
Read(data);
if (BitConverter.IsLittleEndian)
{
data.Reverse();
}
data.CopyTo(new Span<byte>(Unsafe.AsPointer(ref ret), data.Length));
return ret;
}
public unsafe ushort ReadUShort()
{
byte[] data = new byte[4];
Read(data, 0, 4);

uint ret;
fixed (byte *src = &data[0]){
PutBytesBE ((byte *) &ret, src, 4);
}
return (ushort)ret;
}
}

internal class MonoBinaryWriter : BinaryWriter
{
public MonoBinaryWriter(Stream stream) : base(stream) {}
public void WriteString(string val)
{
Write(val.Length);
Write(val.ToCharArray());
}
public void WriteLong(long val)

public override void Write(string val)
{
Write((int)((val >> 32) & 0xffffffff));
Write((int)((val >> 0) & 0xffffffff));
var bytes = Encoding.UTF8.GetBytes(val);
lewing marked this conversation as resolved.
Show resolved Hide resolved
Write(bytes.Length);
Write(bytes);
}
public override void Write(int val)

public override void Write(long val) => WriteBigEndian<long>(val);
public override void Write(int val) => WriteBigEndian<int>(val);

protected unsafe void WriteBigEndian<T>(T val) where T : struct
{
byte[] bytes = BitConverter.GetBytes(val);
Array.Reverse(bytes, 0, bytes.Length);
Write(bytes);
Span<byte> data = stackalloc byte[Unsafe.SizeOf<T>()];
new Span<byte>(Unsafe.AsPointer(ref val), data.Length).CopyTo(data);
if (BitConverter.IsLittleEndian)
{
data.Reverse();
}
base.Write(data);
}

public void WriteObj(DotnetObjectId objectId, MonoSDBHelper SdbHelper)
{
if (objectId.Scheme == "object")
Expand Down Expand Up @@ -878,7 +815,7 @@ public async Task<int> CreateString(SessionId sessionId, string value, Cancellat
var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdAppDomain>(sessionId, CmdAppDomain.GetRootDomain, commandParams, token);
var root_domain = retDebuggerCmdReader.ReadInt32();
commandParamsWriter.Write(root_domain);
commandParamsWriter.WriteString(value);
commandParamsWriter.Write(value);
retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdAppDomain>(sessionId, CmdAppDomain.CreateString, commandParams, token);
return retDebuggerCmdReader.ReadInt32();
}
Expand Down Expand Up @@ -989,7 +926,7 @@ public async Task<int> GetAssemblyId(SessionId sessionId, string asm_name, Cance
{
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.WriteString(asm_name);
commandParamsWriter.Write(asm_name);

var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdVM>(sessionId, CmdVM.GetAssemblyByName, commandParams, token);
return retDebuggerCmdReader.ReadInt32();
Expand Down Expand Up @@ -1124,7 +1061,7 @@ public async Task<int> SetBreakpoint(SessionId sessionId, int methodId, long il_
commandParamsWriter.Write((byte)1);
commandParamsWriter.Write((byte)ModifierKind.LocationOnly);
commandParamsWriter.Write(methodId);
commandParamsWriter.WriteLong(il_offset);
commandParamsWriter.Write(il_offset);
var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdEventRequest>(sessionId, CmdEventRequest.Set, commandParams, token);
return retDebuggerCmdReader.ReadInt32();
}
Expand Down Expand Up @@ -1509,7 +1446,7 @@ public async Task<int> GetMethodIdByName(SessionId sessionId, int type_id, strin
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.Write((int)type_id);
commandParamsWriter.WriteString(method_name);
commandParamsWriter.Write(method_name);
commandParamsWriter.Write((int)(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static));
commandParamsWriter.Write((int)1); //case sensitive
var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetMethodsByNameFlags, commandParams, token);
Expand Down Expand Up @@ -1645,7 +1582,7 @@ public async Task<JObject> GetPointerContent(SessionId sessionId, int pointerId,
var ret = new List<string>();
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.WriteLong(pointerValues[pointerId].address);
commandParamsWriter.Write(pointerValues[pointerId].address);
commandParamsWriter.Write(pointerValues[pointerId].typeId);
var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdPointer>(sessionId, CmdPointer.GetValue, commandParams, token);
var varName = pointerValues[pointerId].varName;
Expand Down Expand Up @@ -1744,7 +1681,7 @@ public async Task<JObject> CreateJObjectForPtr(SessionId sessionId, ElementType
{
string type;
string value;
long valueAddress = retDebuggerCmdReader.ReadLong();
long valueAddress = retDebuggerCmdReader.ReadInt64();
var typeId = retDebuggerCmdReader.ReadInt32();
var className = "";
if (etype == ElementType.FnPtr)
Expand Down Expand Up @@ -1955,7 +1892,7 @@ public async Task<JObject> CreateJObjectForVariableValue(SessionId sessionId, Mo
}
case ElementType.R4:
{
float value = BitConverter.Int32BitsToSingle(retDebuggerCmdReader.ReadInt32());
float value = retDebuggerCmdReader.ReadSingle();
ret = CreateJObjectForNumber<float>(value);
break;
}
Expand All @@ -1967,15 +1904,13 @@ public async Task<JObject> CreateJObjectForVariableValue(SessionId sessionId, Mo
}
case ElementType.I8:
{
long value = retDebuggerCmdReader.ReadLong();
long value = retDebuggerCmdReader.ReadInt64();
ret = CreateJObjectForNumber<long>(value);
break;
}
case ElementType.U8:
{
ulong high = (ulong) retDebuggerCmdReader.ReadInt32();
ulong low = (ulong) retDebuggerCmdReader.ReadInt32();
var value = ((high << 32) | low);
ulong value = retDebuggerCmdReader.ReadUInt64();
ret = CreateJObjectForNumber<ulong>(value);
break;
}
Expand Down Expand Up @@ -2257,7 +2192,7 @@ public async Task<int> GetTypeByName(SessionId sessionId, string typeToSearch, C
{
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.WriteString(typeToSearch);
commandParamsWriter.Write(typeToSearch);
var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdVM>(sessionId, CmdVM.GetTypes, commandParams, token);
var count = retDebuggerCmdReader.ReadInt32(); //count ret
return retDebuggerCmdReader.ReadInt32();
Expand Down