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

[mono][debugger] Implementing mscordbi to support iCorDebug on mono runtime #47639

Merged
merged 67 commits into from
Mar 12, 2021

Conversation

thaystg
Copy link
Member

@thaystg thaystg commented Jan 29, 2021

There are some things hardcoded yet, because we still need to decide how we will launch the process and decide the debugger port.
Using a dbgshim changed to accept mono runtime as a coreclr runtime with this version is possible to:

  • Watch simple variables
  • Watch string variables
  • Watch array variables
  • Watch object variables
  • Watch this
  • Step over / step into / step out
  • Stop / Continue
  • Evaluate static methods (with and without parameters)

For this implementation we decided to use metadata reader from coreclr, this is great because I could reuse a lot of code from mscordbi of coreclr.
I'm also using the log infrastructure from coreclr, if we start vsdbg-ui and set these parameters on environment:
COMPlus_LogFile=c:\thays\example.txt
COMPlus_LogToFile=1
COMPlus_LogLevel=8
COMPlus_LogFacility=0x00000200
COMPlus_LogEnable=1

We will see the log message with the icordebug messages which are not implemented. This may help to continue the implementation.

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@ghost
Copy link

ghost commented Jan 30, 2021

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

There are some things hardcoded yet, because we still need to decide how we will launch the process and decide the debugger port.
Using a dbgshim changed to accept mono runtime as a coreclr runtime with this version is possible to:

  • Watch simple variables
  • Watch string variables
  • Watch array variables
  • Watch object variables
  • Watch this
  • Step over / step into / step out
  • Stop / Continue
  • Evaluate static methods (with and without parameters)

For this implementation we decided to use metadata reader from coreclr, this is great because I could reuse a lot of code from mscordbi of coreclr.
I'm also using the log infrastructure from coreclr, if we start vsdbg-ui and set these parameters on environment:
COMPlus_LogFile=c:\thays\example.txt
COMPlus_LogToFile=1
COMPlus_LogLevel=8
COMPlus_LogFacility=0x00000200
COMPlus_LogEnable=1

We will see the log message with the icordebug messages which are not implemented. This may help to continue the implementation.

TODO: delete objects, count references and delete when it gets on 0.

Author: thaystg
Assignees: -
Labels:

area-Debugger-mono

Milestone: -

@thaystg thaystg marked this pull request as ready for review February 19, 2021 20:10
@lambdageek
Copy link
Member

@dotnet/dotnet-diag Could we get help reviewing this PR:

  1. It's implementing ICorDebug - are we're implementing the right behavior
  2. This is using the CoreCLR metadata subsystem - are we using it correctly?

case MDBGPROT_CMD_VM_READ_MEMORY: {
guint8* memory = (guint8*) decode_long (p, &p, end);
int size = decode_int (p, &p, end);
buffer_add_byte_array (buf, memory, size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need segfault protection like in mono/mono#15612

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If final user tries to evaluate an arbitraty address we would need to protect, but I wouldn't like to use this because icordebug uses this(ReadMemory) a lot, and create a file to check memory address would be really slow... I'm planning to study how coreclr checks if it is a valid memory. But I was not planning to do it in this PR, do you think I should add the segfault protection for now and then remove when I have a better solution?

Copy link
Member

@lambdageek lambdageek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🎉

There are a few things that could be changed, but all of them are ok for follow-up PRs.

src/mono/dbi/cordb-process.h Outdated Show resolved Hide resolved
arrayType->GetClass(&eleClass);
eleClass->GetToken(&eleToken);
}
hash = (long)(pow(2, eleToken & 0xffffff) * pow(3, type) * pow(5, eleType)); //TODO: define a better hash
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could look at mono_metadata_type_hash.

Actually the general suggestion here is to define a separate hash function for CordbType and CordbClass rather than scattering it piece by piece in the Find functions

Comment on lines +44 to +46
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL arm64)
set(CLR_CMAKE_HOST_UNIX_ARM64 1)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL i686)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL i686 OR CMAKE_SYSTEM_PROCESSOR STREQUAL x86)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akoeplinger @ViktorHofer is this ok?

The intention is to build a piece of CoreCLR for Mono's new cordb library - Is it the case that during the mono build we use slightly different system names?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this happening? the values we use in src/mono/CMakeLists.txt are upper-cased (ARM64 and X86) so I'm not sure this is really what you want?

Copy link
Member Author

@thaystg thaystg Mar 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if you can see the errors in this commit: a1cb8e6

These were the CI failures without this change:
Build Linux arm Debug AllSubsets_Mono
Build Linux arm64 Debug AllSubsets_Mono_LLVMJIT
Build Linux arm64 Release AllSubsets_Mono_LLVMAOT
Mono Product Build Linux arm64 debug
Mono Product Build Linux arm64 release
Mono llvmaot Product Build Linux arm64 release

Comment on lines 9 to 19
set(CMAKE_C_FLAGS_CHECKED "")
set(CMAKE_CXX_FLAGS_CHECKED "")
set(CMAKE_EXE_LINKER_FLAGS_CHECKED "")
set(CMAKE_SHARED_LINKER_FLAGS_CHECKED "")

set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "")
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would like a comment here what this is for (CoreCLR's checked build, I guess?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need to set these _DEBUG, _RELEASE, _RELWITHDEBINFO variants of the flags? those should already be set by CMake and I'd like to not clear them out here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunatelly I don't remember, I will remove and wait for CI.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akoeplinger, I removed, now do you think it's okay to merge?

union CordbContent
{
int16_t charValue;
int8_t booleanValue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: byteValue might be a better name

{
int16_t charValue;
int8_t booleanValue;
int32_t intValue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that the same union member is used for 32-bit integer values (when it's an System.Int32 or UInt32 value) and for debugger ids (for classes, strings, arrays). Maybe add a debuggerId member that is also an int32_t.

Also in all the places this is used it's paired witha CorElementType, right? Any reason not to store them together in a tagged union:

class CordbTaggedValue {
  CorElementType m_type;
  union {
    int8_t byteValue; 
    ...
  } m_value;
  CordbTaggedValue (CorElementType t) {}
public:
  static CordbTaggedValue ByteValue(int8_t x) { CordbTaggedValue v (ELEMENT_TYPE_I1); v.m_value.byteValue = x; return v; }
  static CordbTaggedValue BoolValue(bool b) { CordbTaggedValue v (ELEMENT_TYPE_BOOLEAN); v.m_value.byteValue = b; return v; }
  ...
public:
  CordbTaggedValue (const CordbTaggedValue&) = default;
  CordbTaggedValue& operator=(const CordbTaggedValue&) = default;
}

(not completely sure about this, it might be too hard to work with. up to you. and no need to change in this PR; can be followup).

Comment on lines +19 to +20
chains[0] = new CordbChain(conn, m_pThread, CHAIN_PROCESS_START, false);
chains[1] = new CordbChain(conn, m_pThread, CHAIN_ENTER_MANAGED, true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs EX_TRY/CATCH

(There are other places, too, in this file and others - I just looked for new and check if the function is one of the COM methods)

if (m_pCordbType)
{
m_pCordbType->QueryInterface(IID_ICorDebugType, (void**)ppType);
goto __Exit;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to break up CordbReferenceValue::GetExactType into some helper functions and use else if instead of goto. Also you can reorganize this to be a little bit simpler: the top three cases are: m_pCordbType != nullptr, m_pClass != nullptr), m_debuggerId != -1, and after those you can switch on m_type

CorElementType type = (CorElementType)m_dbgprot_decode_byte(pReply->p, &pReply->p, pReply->end);
CordbContent value;

if ((MdbgProtValueTypeId)type == MDBGPROT_VALUE_TYPE_ID_NULL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the null case can be several helper functions.

break;
}
case MDBGPROT_CMD_VM_SET_USING_ICORDBG: {
agent_config.using_icordbg = TRUE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this for some reason, but I don't know why. I see it's used to change some of the protocol encoding. Can't we encode this in the protocol version in some way? (Or will that break the old sdb-based debugging?)

(if that's not reasonable, we could extend CMD_VM_SET_PROTOCOL_VERSION to include a "client is icordbg" flag if the major/minor is new enough. and then send "false" from debugger-libs)

@thaystg thaystg merged commit fe8bc17 into dotnet:main Mar 12, 2021
@jkotas jkotas mentioned this pull request Mar 14, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Apr 11, 2021
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.