Skip to content

[Mono]: Include IL pdb signature, age and path in EventPipe module events. #56907

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

Merged
Show file tree
Hide file tree
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
116 changes: 62 additions & 54 deletions src/mono/mono/eventpipe/ep-rt-mono.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <mono/metadata/debug-internals.h>
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/cil-coff.h>
#include <mono/metadata/mono-endian.h>
#include <mono/mini/mini-runtime.h>
#include <mono/sgen/sgen-conf.h>
#include <mono/sgen/sgen-tagged-pointer.h>
Expand Down Expand Up @@ -166,7 +168,8 @@ typedef struct _EventPipeSampleProfileStackWalkData {

// Event data types.
struct _ModuleEventData {
uint8_t signature [EP_GUID_SIZE];
uint8_t module_il_pdb_signature [EP_GUID_SIZE];
uint8_t module_native_pdb_signature [EP_GUID_SIZE];
uint64_t domain_id;
uint64_t module_id;
uint64_t assembly_id;
Expand Down Expand Up @@ -1299,35 +1302,15 @@ eventpipe_fire_assembly_events (
EP_ASSERT (assembly != NULL);
EP_ASSERT (assembly_events_func != NULL);

uint64_t domain_id = (uint64_t)domain;
uint64_t module_id = (uint64_t)assembly->image;
uint64_t assembly_id = (uint64_t)assembly;

// TODO: Extract all module IL/Native paths and pdb metadata when available.
const char *module_il_path = "";
const char *module_il_pdb_path = "";
const char *module_native_path = "";
const char *module_native_pdb_path = "";
uint8_t signature [EP_GUID_SIZE] = { 0 };
uint32_t module_il_pdb_age = 0;
uint32_t module_native_pdb_age = 0;

uint32_t reserved_flags = 0;
uint64_t binding_id = 0;

// Native methods are part of JIT table and already emitted.
// TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well?

// Netcore has a 1:1 between assemblies and modules, so its always a manifest module.
uint32_t module_flags = MODULE_FLAGS_MANIFEST_MODULE;
if (assembly->image) {
if (assembly->image->dynamic)
module_flags |= MODULE_FLAGS_DYNAMIC_MODULE;
if (assembly->image->aot_module)
module_flags |= MODULE_FLAGS_NATIVE_MODULE;
uint64_t binding_id = 0;

module_il_path = assembly->image->filename ? assembly->image->filename : "";
}
ModuleEventData module_data;
memset (&module_data, 0, sizeof (module_data));

get_module_event_data (assembly->image, &module_data);

uint32_t assembly_flags = 0;
if (assembly->dynamic)
Expand All @@ -1340,22 +1323,22 @@ eventpipe_fire_assembly_events (
char *assembly_name = mono_stringify_assembly_name (&assembly->aname);

assembly_events_func (
domain_id,
assembly_id,
module_data.domain_id,
module_data.assembly_id,
assembly_flags,
binding_id,
(const ep_char8_t*)assembly_name,
module_id,
module_flags,
reserved_flags,
(const ep_char8_t *)module_il_path,
(const ep_char8_t *)module_native_path,
signature,
module_il_pdb_age,
(const ep_char8_t *)module_il_pdb_path,
signature,
module_native_pdb_age,
(const ep_char8_t *)module_native_pdb_path,
module_data.module_id,
module_data.module_flags,
module_data.reserved_flags,
(const ep_char8_t *)module_data.module_il_path,
(const ep_char8_t *)module_data.module_native_path,
module_data.module_il_pdb_signature,
module_data.module_il_pdb_age,
(const ep_char8_t *)module_data.module_il_pdb_path,
module_data.module_native_pdb_signature,
module_data.module_native_pdb_age,
(const ep_char8_t *)module_data.module_native_pdb_path,
NULL);

g_free (assembly_name);
Expand Down Expand Up @@ -2683,35 +2666,60 @@ get_module_event_data (
MonoImage *image,
ModuleEventData *module_data)
{
if (image && module_data) {
memset (module_data->signature, 0, EP_GUID_SIZE);
if (module_data) {
memset (module_data->module_il_pdb_signature, 0, EP_GUID_SIZE);
memset (module_data->module_native_pdb_signature, 0, EP_GUID_SIZE);

// Under netcore we only have root domain.
MonoDomain *root_domain = mono_get_root_domain ();

module_data->domain_id = (uint64_t)root_domain;
module_data->module_id = (uint64_t)image;
module_data->assembly_id = (uint64_t)image->assembly;
module_data->assembly_id = image ? (uint64_t)image->assembly : 0;

// TODO: Extract all module IL/Native paths and pdb metadata when available.
module_data->module_il_path = "";
module_data->module_il_pdb_path = "";
// TODO: Extract all module native paths and pdb metadata when available.
module_data->module_native_path = "";
module_data->module_native_pdb_path = "";

module_data->module_il_pdb_age = 0;
module_data->module_native_pdb_age = 0;

module_data->reserved_flags = 0;

// Netcore has a 1:1 between assemblies and modules, so its always a manifest module.
module_data->module_flags = MODULE_FLAGS_MANIFEST_MODULE;
if (image->dynamic)
if (image && image->dynamic)
module_data->module_flags |= MODULE_FLAGS_DYNAMIC_MODULE;
if (image->aot_module)
if (image && image->aot_module)
module_data->module_flags |= MODULE_FLAGS_NATIVE_MODULE;

module_data->module_il_path = image->filename ? image->filename : "";
module_data->module_il_path = image && image->filename ? image->filename : "";

if (image && image->image_info) {
MonoPEDirEntry *debug_dir_entry = (MonoPEDirEntry *)&image->image_info->cli_header.datadir.pe_debug;
if (debug_dir_entry->size) {
ImageDebugDirectory debug_dir;
memset (&debug_dir, 0, sizeof (debug_dir));

uint32_t offset = mono_cli_rva_image_map (image, debug_dir_entry->rva);
for (uint32_t idx = 0; idx < debug_dir_entry->size / sizeof (ImageDebugDirectory); ++idx) {
uint8_t *data = (uint8_t *) ((ImageDebugDirectory *) (image->raw_data + offset) + idx);
debug_dir.major_version = read16 (data + 8);
debug_dir.minor_version = read16 (data + 10);
debug_dir.type = read32 (data + 12);
debug_dir.pointer = read32 (data + 24);

if (debug_dir.type == DEBUG_DIR_ENTRY_CODEVIEW && debug_dir.major_version == 0x100 && debug_dir.minor_version == 0x504d) {
data = (uint8_t *)(image->raw_data + debug_dir.pointer);
int32_t signature = read32 (data);
if (signature == 0x53445352) {
memcpy (module_data->module_il_pdb_signature, data + 4, EP_GUID_SIZE);
module_data->module_il_pdb_age = read32 (data + 20);
module_data->module_il_pdb_path = (const char *)(data + 24);
break;
}
}
}
}
}
}

return true;
Expand All @@ -2734,10 +2742,10 @@ ep_rt_mono_write_event_module_load (MonoImage *image)
module_data.module_il_path,
module_data.module_native_path,
clr_instance_get_id (),
module_data.signature,
module_data.module_il_pdb_signature,
module_data.module_il_pdb_age,
module_data.module_il_pdb_path,
module_data.signature,
module_data.module_native_pdb_signature,
module_data.module_native_pdb_age,
module_data.module_native_pdb_path,
NULL,
Expand Down Expand Up @@ -2777,10 +2785,10 @@ ep_rt_mono_write_event_module_unload (MonoImage *image)
module_data.module_il_path,
module_data.module_native_path,
clr_instance_get_id (),
module_data.signature,
module_data.module_il_pdb_signature,
module_data.module_il_pdb_age,
module_data.module_il_pdb_path,
module_data.signature,
module_data.module_native_pdb_signature,
module_data.module_native_pdb_age,
module_data.module_native_pdb_path,
NULL,
Expand Down
7 changes: 4 additions & 3 deletions src/mono/mono/metadata/mono-endian.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define _MONO_METADATA_ENDIAN_H_ 1

#include <glib.h>
#include <mono/utils/mono-compiler.h>

typedef union {
guint32 ival;
Expand All @@ -28,9 +29,9 @@ typedef union {

# if NO_UNALIGNED_ACCESS

guint16 mono_read16 (const unsigned char *x);
guint32 mono_read32 (const unsigned char *x);
guint64 mono_read64 (const unsigned char *x);
MONO_COMPONENT_API guint16 mono_read16 (const unsigned char *x);
MONO_COMPONENT_API guint32 mono_read32 (const unsigned char *x);
MONO_COMPONENT_API guint64 mono_read64 (const unsigned char *x);

#define read16(x) (mono_read16 ((const unsigned char *)(x)))
#define read32(x) (mono_read32 ((const unsigned char *)(x)))
Expand Down