Skip to content

Commit

Permalink
[wasm][debugger] Inspect static class (#56740)
Browse files Browse the repository at this point in the history
* Trying to fix 45104

* Implementing getting property  and checking failures.

* Fix android compilation
  • Loading branch information
thaystg committed Aug 3, 2021
1 parent 28ce2cc commit 9be8c62
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 72 deletions.
129 changes: 68 additions & 61 deletions src/mono/mono/component/debugger-agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -7617,67 +7617,67 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
g_free (name);
break;
}
case CMD_ASSEMBLY_GET_METADATA_BLOB: {
MonoImage* image = ass->image;
if (ass->dynamic) {
return ERR_NOT_IMPLEMENTED;
}
buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
break;
}
case CMD_ASSEMBLY_GET_IS_DYNAMIC: {
buffer_add_byte (buf, ass->dynamic);
break;
}
case CMD_ASSEMBLY_GET_PDB_BLOB: {
MonoImage* image = ass->image;
MonoDebugHandle* handle = mono_debug_get_handle (image);
if (!handle) {
return ERR_INVALID_ARGUMENT;
}
MonoPPDBFile* ppdb = handle->ppdb;
if (ppdb) {
image = mono_ppdb_get_image (ppdb);
buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
} else {
buffer_add_byte_array (buf, NULL, 0);
}
break;
}
case CMD_ASSEMBLY_GET_TYPE_FROM_TOKEN: {
if (ass->dynamic) {
return ERR_NOT_IMPLEMENTED;
}
guint32 token = decode_int (p, &p, end);
ERROR_DECL (error);
error_init (error);
MonoClass* mono_class = mono_class_get_checked (ass->image, token, error);
if (!is_ok (error)) {
add_error_string (buf, mono_error_get_message (error));
mono_error_cleanup (error);
return ERR_INVALID_ARGUMENT;
}
buffer_add_typeid (buf, domain, mono_class);
mono_error_cleanup (error);
break;
}
case CMD_ASSEMBLY_GET_METHOD_FROM_TOKEN: {
if (ass->dynamic) {
return ERR_NOT_IMPLEMENTED;
}
guint32 token = decode_int (p, &p, end);
ERROR_DECL (error);
error_init (error);
MonoMethod* mono_method = mono_get_method_checked (ass->image, token, NULL, NULL, error);
if (!is_ok (error)) {
add_error_string (buf, mono_error_get_message (error));
mono_error_cleanup (error);
return ERR_INVALID_ARGUMENT;
}
buffer_add_methodid (buf, domain, mono_method);
mono_error_cleanup (error);
break;
}
case CMD_ASSEMBLY_GET_METADATA_BLOB: {
MonoImage* image = ass->image;
if (ass->dynamic) {
return ERR_NOT_IMPLEMENTED;
}
buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
break;
}
case CMD_ASSEMBLY_GET_IS_DYNAMIC: {
buffer_add_byte (buf, ass->dynamic);
break;
}
case CMD_ASSEMBLY_GET_PDB_BLOB: {
MonoImage* image = ass->image;
MonoDebugHandle* handle = mono_debug_get_handle (image);
if (!handle) {
return ERR_INVALID_ARGUMENT;
}
MonoPPDBFile* ppdb = handle->ppdb;
if (ppdb) {
image = mono_ppdb_get_image (ppdb);
buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
} else {
buffer_add_byte_array (buf, NULL, 0);
}
break;
}
case CMD_ASSEMBLY_GET_TYPE_FROM_TOKEN: {
if (ass->dynamic) {
return ERR_NOT_IMPLEMENTED;
}
guint32 token = decode_int (p, &p, end);
ERROR_DECL (error);
error_init (error);
MonoClass* mono_class = mono_class_get_checked (ass->image, token, error);
if (!is_ok (error)) {
add_error_string (buf, mono_error_get_message (error));
mono_error_cleanup (error);
return ERR_INVALID_ARGUMENT;
}
buffer_add_typeid (buf, domain, mono_class);
mono_error_cleanup (error);
break;
}
case CMD_ASSEMBLY_GET_METHOD_FROM_TOKEN: {
if (ass->dynamic) {
return ERR_NOT_IMPLEMENTED;
}
guint32 token = decode_int (p, &p, end);
ERROR_DECL (error);
error_init (error);
MonoMethod* mono_method = mono_get_method_checked (ass->image, token, NULL, NULL, error);
if (!is_ok (error)) {
add_error_string (buf, mono_error_get_message (error));
mono_error_cleanup (error);
return ERR_INVALID_ARGUMENT;
}
buffer_add_methodid (buf, domain, mono_method);
mono_error_cleanup (error);
break;
}
case CMD_ASSEMBLY_HAS_DEBUG_INFO: {
buffer_add_byte (buf, !ass->dynamic && mono_debug_image_has_debug_info (ass->image));
break;
Expand Down Expand Up @@ -8377,6 +8377,13 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint
}
break;
}
case MDBGPROT_CMD_TYPE_INITIALIZE: {
MonoVTable *vtable = mono_class_vtable_checked (klass, error);
goto_if_nok (error, loader_error);
mono_runtime_class_init_full (vtable, error);
goto_if_nok (error, loader_error);
break;
}
default:
err = ERR_NOT_IMPLEMENTED;
goto exit;
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/component/debugger-protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ typedef enum {
MDBGPROT_CMD_TYPE_CREATE_INSTANCE = 19,
MDBGPROT_CMD_TYPE_GET_VALUE_SIZE = 20,
MDBGPROT_CMD_TYPE_GET_VALUES_ICORDBG = 21,
MDBGPROT_CMD_TYPE_GET_PARENTS = 22
MDBGPROT_CMD_TYPE_GET_PARENTS = 22,
MDBGPROT_CMD_TYPE_INITIALIZE = 23
} MdbgProtCmdType;

typedef enum {
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/object-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -1599,7 +1599,7 @@ mono_class_try_get_vtable (MonoClass *klass);
gboolean
mono_runtime_run_module_cctor (MonoImage *image, MonoError *error);

gboolean
MONO_COMPONENT_API gboolean
mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error);

void
Expand Down
10 changes: 6 additions & 4 deletions src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -453,14 +453,16 @@ public VarInfo[] GetLiveVarsAt(int offset)

internal class TypeInfo
{
private AssemblyInfo assembly;
internal AssemblyInfo assembly;
private TypeDefinition type;
private List<MethodInfo> methods;
public int Token { get; }

public TypeInfo(AssemblyInfo assembly, TypeDefinition type)
public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type)
{
this.assembly = assembly;
var metadataReader = assembly.asmMetadataReader;
Token = MetadataTokens.GetToken(metadataReader, typeHandle);
this.type = type;
methods = new List<MethodInfo>();
Name = metadataReader.GetString(type.Name);
Expand Down Expand Up @@ -594,7 +596,7 @@ SourceFile FindSource(DocumentHandle doc, int rowid, string documentName)
{
var typeDefinition = asmMetadataReader.GetTypeDefinition(type);

var typeInfo = new TypeInfo(this, typeDefinition);
var typeInfo = new TypeInfo(this, type, typeDefinition);
typesByName[typeInfo.FullName] = typeInfo;
if (pdbMetadataReader != null)
{
Expand Down Expand Up @@ -876,7 +878,7 @@ public object ToScriptSource(int executionContextId, object executionContextAuxD

internal class DebugStore
{
private List<AssemblyInfo> assemblies = new List<AssemblyInfo>();
internal List<AssemblyInfo> assemblies = new List<AssemblyInfo>();
private readonly HttpClient client;
private readonly ILogger logger;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,57 @@ public async Task<JObject> GetValueFromObject(JToken objRet, CancellationToken t
}
return null;
}

public async Task<JObject> TryToRunOnLoadedClasses(string varName, CancellationToken token)
{
string classNameToFind = "";
string[] parts = varName.Split(".");
var typeId = -1;
foreach (string part in parts)
{
if (classNameToFind.Length > 0)
classNameToFind += ".";
classNameToFind += part.Trim();
if (typeId != -1)
{
var fields = await proxy.SdbHelper.GetTypeFields(sessionId, typeId, token);
foreach (var field in fields)
{
if (field.Name == part.Trim())
{
var isInitialized = await proxy.SdbHelper.TypeIsInitialized(sessionId, typeId, token);
if (isInitialized == 0)
{
isInitialized = await proxy.SdbHelper.TypeInitialize(sessionId, typeId, token);
}
var valueRet = await proxy.SdbHelper.GetFieldValue(sessionId, typeId, field.Id, token);
return await GetValueFromObject(valueRet, token);
}
}
var methodId = await proxy.SdbHelper.GetPropertyMethodIdByName(sessionId, typeId, part.Trim(), token);
if (methodId != -1)
{
var commandParamsObj = new MemoryStream();
var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj);
commandParamsObjWriter.Write(0); //param count
var retMethod = await proxy.SdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, "methodRet", token);
return await GetValueFromObject(retMethod, token);
}
}
var store = await proxy.LoadStore(sessionId, token);
foreach (var asm in store.assemblies)
{
var type = asm.GetTypeByName(classNameToFind);
if (type != null)
{
var assemblyId = await proxy.SdbHelper.GetAssemblyId(sessionId, type.assembly.Name, token);
typeId = await proxy.SdbHelper.GetTypeIdFromToken(sessionId, assemblyId, type.Token, token);
}
}
}
return null;
}

// Checks Locals, followed by `this`
public async Task<JObject> Resolve(string varName, CancellationToken token)
{
Expand Down Expand Up @@ -140,7 +191,8 @@ public async Task<JObject> Resolve(string varName, CancellationToken token)
}
else
{
return null;
rootObject = await TryToRunOnLoadedClasses(varName, token);
return rootObject;
}
}
}
Expand Down Expand Up @@ -177,8 +229,8 @@ public async Task<JObject> Resolve(InvocationExpressionSyntax method, Dictionary
var typeName = await proxy.SdbHelper.GetTypeName(sessionId, typeId[0], token);
throw new Exception($"Method '{methodName}' not found in type '{typeName}'");
}
var command_params_obj = new MemoryStream();
var commandParamsObjWriter = new MonoBinaryWriter(command_params_obj);
var commandParamsObj = new MemoryStream();
var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj);
commandParamsObjWriter.WriteObj(objectId, proxy.SdbHelper);
if (method.ArgumentList != null)
{
Expand All @@ -197,7 +249,7 @@ public async Task<JObject> Resolve(InvocationExpressionSyntax method, Dictionary
return null;
}
}
var retMethod = await proxy.SdbHelper.InvokeMethod(sessionId, command_params_obj.ToArray(), methodId, "methodRet", token);
var retMethod = await proxy.SdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, "methodRet", token);
return await GetValueFromObject(retMethod, token);
}
}
Expand Down
73 changes: 72 additions & 1 deletion src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ internal enum CmdType {
CreateInstance = 19,
GetValueSize = 20,
GetValuesICorDbg = 21,
GetParents = 22
GetParents = 22,
Initialize = 23,
}

internal enum CmdArray {
Expand Down Expand Up @@ -929,6 +930,41 @@ public async Task<bool> ClearSingleStep(SessionId sessionId, int req_id, Cancell
return false;
}

public async Task<JObject> GetFieldValue(SessionId sessionId, int typeId, int fieldId, CancellationToken token)
{
var ret = new List<FieldTypeClass>();
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.Write(typeId);
commandParamsWriter.Write(1);
commandParamsWriter.Write(fieldId);

var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetValues, commandParams, token);
return await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "", false, -1, token);
}

public async Task<int> TypeIsInitialized(SessionId sessionId, int typeId, CancellationToken token)
{
var ret = new List<FieldTypeClass>();
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.Write(typeId);

var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.IsInitialized, commandParams, token);
return retDebuggerCmdReader.ReadInt32();
}

public async Task<int> TypeInitialize(SessionId sessionId, int typeId, CancellationToken token)
{
var ret = new List<FieldTypeClass>();
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.Write(typeId);

var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.Initialize, commandParams, token);
return retDebuggerCmdReader.ReadInt32();
}

public async Task<List<FieldTypeClass>> GetTypeFields(SessionId sessionId, int type_id, CancellationToken token)
{
var ret = new List<FieldTypeClass>();
Expand Down Expand Up @@ -1128,6 +1164,17 @@ public async Task<string> GetClassNameFromObject(SessionId sessionId, int object
return await GetTypeName(sessionId, type_id[0], token);
}

public async Task<int> GetTypeIdFromToken(SessionId sessionId, int assemblyId, int typeToken, CancellationToken token)
{
var ret = new List<string>();
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.Write((int)assemblyId);
commandParamsWriter.Write((int)typeToken);
var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdAssembly>(sessionId, CmdAssembly.GetTypeFromToken, commandParams, token);
return retDebuggerCmdReader.ReadInt32();
}

public async Task<int> GetMethodIdByName(SessionId sessionId, int type_id, string method_name, CancellationToken token)
{
var ret = new List<string>();
Expand Down Expand Up @@ -1191,6 +1238,30 @@ public async Task<JObject> InvokeMethod(SessionId sessionId, byte[] valueTypeBuf
retDebuggerCmdReader.ReadByte(); //number of objects returned.
return await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, varName, false, -1, token);
}

public async Task<int> GetPropertyMethodIdByName(SessionId sessionId, int typeId, string propertyName, CancellationToken token)
{
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.Write(typeId);

var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetProperties, commandParams, token);
var nProperties = retDebuggerCmdReader.ReadInt32();
for (int i = 0 ; i < nProperties; i++)
{
retDebuggerCmdReader.ReadInt32(); //propertyId
string propertyNameStr = retDebuggerCmdReader.ReadString();
var getMethodId = retDebuggerCmdReader.ReadInt32();
retDebuggerCmdReader.ReadInt32(); //setmethod
var attrs = retDebuggerCmdReader.ReadInt32(); //attrs
if (propertyNameStr == propertyName)
{
return getMethodId;
}
}
return -1;
}

public async Task<JArray> CreateJArrayForProperties(SessionId sessionId, int typeId, byte[] object_buffer, JArray attributes, bool isAutoExpandable, string objectId, bool isOwn, CancellationToken token)
{
JArray ret = new JArray();
Expand Down
Loading

0 comments on commit 9be8c62

Please sign in to comment.