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 4 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
149 changes: 45 additions & 104 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,17 +386,17 @@ public MonoBinaryReader(Stream stream, bool hasError = false) : base(stream)
HasError = hasError;
}

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

if (BitConverter.IsLittleEndian){
dest += count;
for (; i < count; i++)
*(--dest) = *src++;
} else {
for (; i < count; i++)
*dest++ = *src++;
// SDB is big endian
if (BitConverter.IsLittleEndian)
{
for (int i = 0; i < src.Length; i++)
dest [src.Length - i - 1] = src [i];
}
else
{
src.CopyTo(dest);
}
}

Expand All @@ -407,108 +408,50 @@ 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);

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

public unsafe byte ReadUByte()
{
byte[] data = new byte[4];
Read(data, 0, 4);
public override unsafe double ReadDouble() => Read<double>();
public override unsafe uint ReadUInt32() => Read<uint>();
public override unsafe float ReadSingle() => Read<float>();
public override unsafe ulong ReadUInt64() => Read<ulong>();
public override unsafe long ReadInt64() => Read<long>();

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

public override unsafe int ReadInt32()
protected unsafe T Read<T>() where T : struct
{
byte[] data = new byte[4];
Read(data, 0, 4);
int ret;
fixed (byte *src = &data[0]){
PutBytesBE ((byte *) &ret, src, 4);
}
Span<byte> data = stackalloc byte[Unsafe.SizeOf<T>()];
T ret = default;
Read(data);
SwapForBE(new Span<byte>(Unsafe.AsPointer(ref ret), data.Length), data);
lewing marked this conversation as resolved.
Show resolved Hide resolved
return ret;
}

public override unsafe double ReadDouble()
{
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);
}
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)
{
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 unsafe void Write(long val) => WriteType<long>(val);
public override unsafe void Write(int val) => WriteType<int>(val);

protected unsafe void WriteType<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>()];
MonoBinaryReader.SwapForBE(data, new Span<byte>(Unsafe.AsPointer(ref val), data.Length));
base.Write(data);
}

public void WriteObj(DotnetObjectId objectId, MonoSDBHelper SdbHelper)
{
if (objectId.Scheme == "object")
Expand Down Expand Up @@ -1124,7 +1067,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 @@ -1645,7 +1588,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 +1687,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 +1898,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 +1910,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