none
CLR Profiler: How to get ASSEMBLYMETADATA from AssemblyID or FunctionID? RRS feed

  • Question

  • TL;DR:
    I need an AssemblyToken for an already loaded assembly, all I have (to start with) is a FunctionID.  How do I get from FunctionID to AssemblyToken of an already loaded assembly?  I have a profiler loaded so I can monitor any profiler events.

    In order to instrument a method with a call to a [mscorlib]System.SomeClass::SomeMethod() I need a method signature.  In order to have a method signature I need to have an AssemblyToken.  I can get an AssemblyToken with IMetaDataEmit::DefineAssemblyRef but that requires an ASSEMBLYMETADATA.

    Now I can create an ASSEMBLYMETADATA and fill it in by hand except that I do not know the version of the assembly that is currently loaded.  In the case of mscorlib, it might be 4.0.0.0 or it might be 2.0.0.0, or it might be some other version in the future.

    At the time I am instrumenting the method I have a FunctionID of the function I am instrumenting but that seems like it wouldn't be terribly useful.  Another option would be to handle the AssemblyLoadFinished callback and keep my eye out for mscorlib getting loaded.  In this case I would have an AssemblyID.

    What I need though is an ASSEMBLYMETADATA object or at least the version information found within it.  I have been poking around the API for a while but I am struggling to find a path to get from FunctionID or AssemblyID to an ASSEMBLYMETADATA.

    If I can get a hold of an mdAssembly or mdAssemblyRef then I would be able to get an ASSEMBLYMETADATA but it is my understanding that those are tokens generated by calling DefineAssemblyRef, which requires the ASSEMBLYMETADATA to populate.

    Wednesday, February 20, 2013 7:40 PM

Answers

  • Hi, Micah.

    "A user may have both .NET 4.0.0.0 installed as well as .NET 2.0.0.0 installed but only one of the two will be loaded into any given process (as far as I know).  "

    Actually, it's possible for both to be loaded into the same process.  (See http://blogs.msdn.com/b/davbr/archive/2010/08/25/profilers-in-process-side-by-side-clr-instances-and-a-free-test-harness.aspx.)

    Once a module loads, you can use ICorProfilerInfo::GetModuleMetadata to retrieve an IMetaDataImport scoped to that module (from which you can then query metadata-stuff related to that module).  Note that profapi methods do not have a side-effect that sets the current scope in some kind of global sense.  That's a metadata interface concept, not a profapi concept.

    Thanks,
    Dave

    • Marked as answer by Micah Zoltu Thursday, February 22, 2018 4:01 PM
    Monday, April 8, 2013 3:55 PM

All replies

  • What is the term AssemblyToken?

    Please post the MSDN document here, thank you.

    And in addition, maybe this code snippet can help you: http://visual-profiler.googlecode.com/svn-history/r23/trunk/VisualProfilerBackend/AssemblyMetadata.cpp

    Have a nice day.


    Ghost,
    Call me ghost for short, Thanks
    To get the better answer, it should be a better question.

    Thursday, February 21, 2013 5:17 PM
  • Hi Micah,

    You can get an ASSEMBLYMETADATA struct by using 

    IMetadataAssemblyImport::GetAssemblyProps.

     

    You can use

    IMetadataImport::OpenScope and simply pass in the string of the assembly you wish it inspect.Do a QI (query interface) on the returned interface for IMetadataAssemblyImport.

     

    After acquiring the IMetadataAssemblyImport interface use IMetadataAssemblyImport::GetAssemblyFromScope to get the the assemblyDef token.

     

    Then, make a call to IMetadataAssemblyImport::GetAssemblyProps, pass in the assemblyDefToken and it returns an ASSEMBLYMETADATA struct.

    See the relevant MSDN docs below:

    IMetadataAssemblyImport::GetAssemblyProps

     

    IMetadataAssemblyImport::GetAssemblyFromScope

    http://msdn.microsoft.com/en-us/library/ms230138.aspx

    IMetadataAssemblyImport::GetAssemblyProps

    http://msdn.microsoft.com/en-us/library/ms230191.aspx

     Hope that helps!

     

    Monday, February 25, 2013 11:08 PM
  • There does not appear to be an IMetaDataImport::OpenScope method.  There is an IMetaDataDispenser::OpenScope, did you mean that?  If so, that appears to require a path to an assembly.  Does it allow me to give it a name to an assembly in the GAC (without a path)?  If so, how does it choose which version to open (mscorlib v2.0.0.0 vs v4.0.0.0)?

    Monday, February 25, 2013 11:23 PM
  • Where I said AssemblyToken I meant mdAssembly.

    I checked out the code you linked but I am uncertain it would work for me.  You do IMetaDataImport::QueryInterface to get an IMetaDataAssemblyImport.  Once you have that you call IMetaDataAssemblyImport::GetAssemblyFromScope to get the mdAssembly token for the assembly in the current scope.  However, I believe that the assembly that is "in scope" will be the assembly of the currently JIT compiling method rather than assembly I want to query for.  I could be wrong on this however since the documentation is very sparse on this subject.

    In the call before that you call ICorProfilerInfo::GetAssemblyInfo, does that set the scope for future calls to IMetaDataAssemblyImport?  That seems like a very important side effect and I feel like it would be unlikely if that method did that without any documentation of such a side effect.

    Monday, February 25, 2013 11:36 PM
  • Yes sorry. I mean IMetadataDispenser::OpenScope.

    I don't believe you can specify an assembly in the GAC with OpenScope. Instead, if you want the GAC to be visible you have to muck with your registry for the GAC to show up in your file explorer. Then you can just can just use the path to the specific version of mscorlib that you want. (Should be under C:\windows\assembly\GAC_MSIL)

    Here's an example of how to do that:

    http://stackoverflow.com/questions/714907/how-to-extract-an-assembly-from-the-gac

    Does that help?

    Tuesday, February 26, 2013 1:16 AM
  • Unfortunately I need to know what version is loaded into the application being profiled.  A user may have both .NET 4.0.0.0 installed as well as .NET 2.0.0.0 installed but only one of the two will be loaded into any given process (as far as I know).  I need a way to find out which was actually loaded.
    Tuesday, February 26, 2013 1:50 AM
  • Not sure if your doing a native application that's out of process. You can use the .NET debugger interfaces to poke into the live process, enumerate the AppDomains, and in each appdomain you can enumerate the assemblies.

    Each assembly will have a name that specifies the exact path of where that assembly was loaded from.

    Here's the order you would use the following interfaces:

    ICorDebug::CreateProcess

    http://msdn.microsoft.com/en-us/library/ms232508.aspx

    ICorDebugProcess::EnumerateAppdomains

    http://msdn.microsoft.com/en-us/library/ms232960.aspx

    ICorDebugAppdomain

    http://msdn.microsoft.com/en-us/library/ms232464.aspx

    ICorDebugAppdomain::EnumerateAssemblies

    http://msdn.microsoft.com/en-us/library/ms231441.aspx

    ICorDebugAssembly

    http://msdn.microsoft.com/en-us/library/ms231936.aspx

    The easier thing to do would be to use the managed reflection API to do this System.Appdomain.GetAssemblies

    http://msdn.microsoft.com/en-us/library/system.appdomain.getassemblies.aspx

    Tuesday, February 26, 2013 2:24 AM
  • Could you not monitor what modules are being loaded using ICorProfilerCallback::ModuleAttachedToAssembly and look for mscorlib?
    Wednesday, February 27, 2013 9:23 PM
  • I am using the profiling API, not the debugging API.  Since I need the mdAssembly token before the first method is JIT compiled I can't use managed code and I believe this also would mean that I can't use the debugging API.
    Wednesday, March 6, 2013 5:14 PM
  • Hi, Micah.

    "A user may have both .NET 4.0.0.0 installed as well as .NET 2.0.0.0 installed but only one of the two will be loaded into any given process (as far as I know).  "

    Actually, it's possible for both to be loaded into the same process.  (See http://blogs.msdn.com/b/davbr/archive/2010/08/25/profilers-in-process-side-by-side-clr-instances-and-a-free-test-harness.aspx.)

    Once a module loads, you can use ICorProfilerInfo::GetModuleMetadata to retrieve an IMetaDataImport scoped to that module (from which you can then query metadata-stuff related to that module).  Note that profapi methods do not have a side-effect that sets the current scope in some kind of global sense.  That's a metadata interface concept, not a profapi concept.

    Thanks,
    Dave

    • Marked as answer by Micah Zoltu Thursday, February 22, 2018 4:01 PM
    Monday, April 8, 2013 3:55 PM
  • Hi Micah,

    Did you find the solution? I also need to get assembly metadata from AssemblyID? 



    Hitesh

    Thursday, February 22, 2018 1:08 PM
  • Unfortunately I don't remember what my final solution was.  :/  You may want to try the solution David Broman proposed, that sounds like it would have worked.  :)
    Thursday, February 22, 2018 4:02 PM