diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | mono/metadata/ChangeLog | 6 | ||||
-rw-r--r-- | mono/metadata/sgen-gc.c | 55 | ||||
-rw-r--r-- | mono/metadata/sgen-protocol.c | 154 | ||||
-rw-r--r-- | mono/metadata/sgen-protocol.h | 92 | ||||
-rw-r--r-- | tools/sgen-grep-binprot.c | 202 |
6 files changed, 509 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog index 3d5980ea388..a31366f688a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2010-03-02 Mark Probst <mark.probst@gmail.com> + + * tools/sgen-grep-binprot.c: Tool for searching through the binary + protocol files generated by SGen. + 2010-02-26 Miguel de Icaza <miguel@novell.com> * Make the scripts default to 4.0 now. diff --git a/mono/metadata/ChangeLog b/mono/metadata/ChangeLog index c346b706ca9..56830937be5 100644 --- a/mono/metadata/ChangeLog +++ b/mono/metadata/ChangeLog @@ -1,3 +1,9 @@ +2010-03-02 Mark Probst <mark.probst@gmail.com> + + * sgen-gc.c, sgen-protocol.c, sgen-protocol.h: New facility for + writing binary log files (can be enabled by #define'ing + BINARY_PROTOCOL) for better debugging of timing-dependent bugs or + bugs in longer running programs. Mon Mar 1 19:35:32 CET 2010 Paolo Molaro <lupus@ximian.com> diff --git a/mono/metadata/sgen-gc.c b/mono/metadata/sgen-gc.c index 07f6c360ab5..9dba6169df9 100644 --- a/mono/metadata/sgen-gc.c +++ b/mono/metadata/sgen-gc.c @@ -1675,11 +1675,15 @@ mono_gc_scan_for_specific_ref (MonoObject *key) } } +//#define BINARY_PROTOCOL +#include "sgen-protocol.c" + static gboolean need_remove_object_for_domain (char *start, MonoDomain *domain) { if (mono_object_domain (start) == domain) { DEBUG (1, fprintf (gc_debug_file, "Need to cleanup object %p\n", start)); + binary_protocol_cleanup (start, (gpointer)LOAD_VTABLE (start), safe_object_get_size ((MonoObject*)start)); return TRUE; } return FALSE; @@ -1920,6 +1924,7 @@ add_to_global_remset (gpointer ptr, gboolean root) RememberedSet *rs; DEBUG (8, fprintf (gc_debug_file, "Adding global remset for %p\n", ptr)); + binary_protocol_global_remset (ptr, *(gpointer*)ptr, (gpointer)LOAD_VTABLE (*(gpointer*)ptr)); g_assert (!root); g_assert (!ptr_in_nursery (ptr) && ptr_in_nursery (*(gpointer*)ptr)); @@ -2063,6 +2068,7 @@ copy_object (char *obj, char *from_space_start, char *from_space_end) */ if (G_UNLIKELY (objsize > MAX_SMALL_OBJ_SIZE || obj_is_from_pinned_alloc (obj))) { DEBUG (9, fprintf (gc_debug_file, " (marked LOS/Pinned %p (%s), size: %zd)\n", obj, safe_name (obj), objsize)); + binary_protocol_pin (obj, (gpointer)LOAD_VTABLE (obj), safe_object_get_size ((MonoObject*)obj)); pin_object (obj); HEAVY_STAT (++stat_copy_object_failed_large_pinned); return obj; @@ -2082,6 +2088,7 @@ copy_object (char *obj, char *from_space_start, char *from_space_end) copy: DEBUG (9, fprintf (gc_debug_file, " (to %p, %s size: %zd)\n", to_space_bumper, ((MonoObject*)obj)->vtable->klass->name, objsize)); + binary_protocol_copy (obj, to_space_bumper, ((MonoObject*)obj)->vtable, objsize); HEAVY_STAT (++num_objects_copied); @@ -2294,6 +2301,7 @@ pin_objects_from_addresses (GCMemSection *section, void **start, void **end, voi DEBUG (8, fprintf (gc_debug_file, "Pinned try match %p (%s), size %zd\n", last_obj, safe_name (last_obj), last_obj_size)); if (addr >= search_start && (char*)addr < (char*)last_obj + last_obj_size) { DEBUG (4, fprintf (gc_debug_file, "Pinned object %p, vtable %p (%s), count %d\n", search_start, *(void**)search_start, safe_name (search_start), count)); + binary_protocol_pin (search_start, (gpointer)LOAD_VTABLE (search_start), safe_object_get_size (search_start)); pin_object (search_start); if (heap_dump_file) pin_stats_register_object (search_start, last_obj_size); @@ -2784,6 +2792,7 @@ add_nursery_frag (size_t frag_size, char* frag_start, char* frag_end) { Fragment *fragment; DEBUG (4, fprintf (gc_debug_file, "Found empty fragment: %p-%p, size: %zd\n", frag_start, frag_end, frag_size)); + binary_protocol_empty (frag_start, frag_size); /* memsetting just the first chunk start is bound to provide better cache locality */ if (nursery_clear_policy == CLEAR_AT_GC) memset (frag_start, 0, frag_size); @@ -3076,8 +3085,10 @@ build_section_fragments (GCMemSection *section) section->scan_starts [((char*)frag_end - (char*)section->data)/SCAN_START_SIZE] = frag_end; } frag_size = frag_end - frag_start; - if (frag_size) + if (frag_size) { + binary_protocol_empty (frag_start, frag_size); memset (frag_start, 0, frag_size); + } frag_size = safe_object_get_size ((MonoObject*)pin_queue [i]); frag_size += ALLOC_ALIGN - 1; frag_size &= ~(ALLOC_ALIGN - 1); @@ -3086,8 +3097,10 @@ build_section_fragments (GCMemSection *section) } frag_end = section->end_data; frag_size = frag_end - frag_start; - if (frag_size) + if (frag_size) { + binary_protocol_empty (frag_start, frag_size); memset (frag_start, 0, frag_size); + } } static void @@ -3287,6 +3300,7 @@ collect_nursery (size_t requested_size) TV_DECLARE (btv); init_stats (); + binary_protocol_collection (GENERATION_NURSERY); check_scan_starts (); degraded_mode = 0; @@ -3438,6 +3452,7 @@ major_collection (const char *reason) int num_major_sections_saved, save_target, allowance_target; init_stats (); + binary_protocol_collection (GENERATION_OLD); check_scan_starts (); degraded_mode = 0; @@ -3885,6 +3900,7 @@ mark_pinned_from_addresses (PinnedChunk *chunk, void **start, void **end) ptr = (void**)addr; /* if the vtable is inside the chunk it's on the freelist, so skip */ if (*ptr && (*ptr < (void*)chunk->start_data || *ptr > (void*)((char*)chunk + chunk->num_pages * FREELIST_PAGESIZE))) { + binary_protocol_pin (addr, (gpointer)LOAD_VTABLE (addr), safe_object_get_size ((MonoObject*)addr)); pin_object (addr); if (heap_dump_file) pin_stats_register_object ((char*) addr, safe_object_get_size ((MonoObject*) addr)); @@ -4190,6 +4206,7 @@ free_large_object (LOSObject *obj) { size_t size = obj->size; DEBUG (4, fprintf (gc_debug_file, "Freed large object %p, size %zd\n", obj->data, obj->size)); + binary_protocol_empty (obj->data, obj->size); los_memory_usage -= size; size += sizeof (LOSObject); @@ -4241,6 +4258,7 @@ alloc_large_inner (MonoVTable *vtable, size_t size) los_memory_usage += size; los_num_objects++; DEBUG (4, fprintf (gc_debug_file, "Allocated large object %p, vtable: %p (%s), size: %zd\n", obj->data, vtable, vtable->klass->name, size)); + binary_protocol_alloc (obj->data, vtable, size); return obj->data; } @@ -4373,6 +4391,7 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size) */ DEBUG (6, fprintf (gc_debug_file, "Allocated object %p, vtable: %p (%s), size: %zd\n", p, vtable, vtable->klass->name, size)); + binary_protocol_alloc (p , vtable, size); g_assert (*p == NULL); *p = vtable; @@ -4475,6 +4494,7 @@ mono_gc_alloc_obj_nolock (MonoVTable *vtable, size_t size) } DEBUG (6, fprintf (gc_debug_file, "Allocated object %p, vtable: %p (%s), size: %zd\n", p, vtable, vtable->klass->name, size)); + binary_protocol_alloc (p, vtable, size); *p = vtable; return p; @@ -4510,6 +4530,7 @@ mono_gc_try_alloc_obj_nolock (MonoVTable *vtable, size_t size) HEAVY_STAT (++stat_objects_alloced); DEBUG (6, fprintf (gc_debug_file, "Allocated object %p, vtable: %p (%s), size: %zd\n", p, vtable, vtable->klass->name, size)); + binary_protocol_alloc (p, vtable, size); g_assert (*p == NULL); *p = vtable; @@ -4632,6 +4653,7 @@ mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size) memset (p, 0, size); } DEBUG (6, fprintf (gc_debug_file, "Allocated pinned object %p, vtable: %p (%s), size: %zd\n", p, vtable, vtable->klass->name, size)); + binary_protocol_alloc (p, vtable, size); *p = vtable; UNLOCK_GC; return p; @@ -5383,6 +5405,7 @@ update_current_thread_stack (void *start) { void *ptr = cur_thread_regs; SgenThreadInfo *info = thread_info_lookup (ARCH_GET_THREAD ()); + info->stack_start = align_pointer (&ptr); g_assert (info->stack_start >= info->stack_start_limit && info->stack_start < info->stack_end); ARCH_STORE_REGS (ptr); @@ -5482,6 +5505,7 @@ restart_threads_until_none_in_managed_allocator (void) continue; if (!info->stack_start || info->in_critical_region || is_ip_in_managed_allocator (info->stopped_domain, info->stopped_ip)) { + binary_protocol_thread_restart ((gpointer)info->id); result = pthread_kill (info->id, restart_signal_num); if (result == 0) { ++restart_count; @@ -5759,8 +5783,11 @@ handle_remset (mword *p, void *start_nursery, void *end_nursery, gboolean global ptr = (void**)(*p); //__builtin_prefetch (ptr); if (((void*)ptr < start_nursery || (void*)ptr >= end_nursery)) { + gpointer old = *ptr; *ptr = copy_object (*ptr, start_nursery, end_nursery); DEBUG (9, fprintf (gc_debug_file, "Overwrote remset at %p with %p\n", ptr, *ptr)); + if (old) + binary_protocol_ptr_update (ptr, old, *ptr, (gpointer)LOAD_VTABLE (*ptr), safe_object_get_size (*ptr)); if (!global && *ptr >= start_nursery && *ptr < end_nursery) { /* * If the object is pinned, each reference to it from nonpinned objects @@ -6149,6 +6176,8 @@ gc_register_current_thread (void *addr) info->stopped_domain = NULL; info->stopped_regs = NULL; + binary_protocol_thread_register ((gpointer)info->id); + #ifdef HAVE_KW_THREAD tlab_next_addr = &tlab_next; store_remset_buffer_index_addr = &store_remset_buffer_index; @@ -6222,6 +6251,8 @@ unregister_current_thread (void) RememberedSet *rset; ARCH_THREAD_TYPE id = ARCH_GET_THREAD (); + binary_protocol_thread_unregister ((gpointer)id); + hash = HASH_PTHREAD_T (id) % THREAD_HASH_SIZE; p = thread_table [hash]; assert (p); @@ -6565,6 +6596,10 @@ mono_gc_wbarrier_generic_nostore (gpointer ptr) #endif LOCK_GC; + + if (*(gpointer*)ptr) + binary_protocol_wbarrier (ptr, *(gpointer*)ptr, (gpointer)LOAD_VTABLE (*(gpointer*)ptr)); + if (ptr_in_nursery (ptr) || ptr_on_stack (ptr) || !ptr_in_nursery (*(gpointer*)ptr)) { DEBUG (8, fprintf (gc_debug_file, "Skipping remset at %p\n", ptr)); UNLOCK_GC; @@ -6923,9 +6958,11 @@ static gboolean missing_remsets; #undef HANDLE_PTR #define HANDLE_PTR(ptr,obj) do { \ if (*(ptr) && (char*)*(ptr) >= nursery_start && (char*)*(ptr) < nursery_next) { \ - if (!object_is_pinned (*(ptr)) && !find_in_remsets ((char*)(ptr))) { \ + if (!find_in_remsets ((char*)(ptr))) { \ fprintf (gc_debug_file, "Oldspace->newspace reference %p at offset %zd in object %p (%s.%s) not found in remsets.\n", *(ptr), (char*)(ptr) - (char*)(obj), (obj), ((MonoObject*)(obj))->vtable->klass->name_space, ((MonoObject*)(obj))->vtable->klass->name); \ - missing_remsets = TRUE; \ + binary_protocol_missing_remset ((obj), (gpointer)LOAD_VTABLE ((obj)), (char*)(ptr) - (char*)(obj), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \ + if (!object_is_pinned (*(ptr))) \ + missing_remsets = TRUE; \ } \ } \ } while (0) @@ -6983,7 +7020,10 @@ check_consistency (void) DEBUG (1, fprintf (gc_debug_file, "Heap consistency check done.\n")); - g_assert (!missing_remsets); +#ifdef BINARY_PROTOCOL + if (!binary_protocol_file) +#endif + g_assert (!missing_remsets); } /* Check that the reference is valid */ @@ -7235,6 +7275,11 @@ mono_gc_base_init (void) heap_dump_file = fopen (filename, "w"); if (heap_dump_file) fprintf (heap_dump_file, "<sgen-dump>\n"); +#ifdef BINARY_PROTOCOL + } else if (g_str_has_prefix (opt, "binary-protocol=")) { + char *filename = strchr (opt, '=') + 1; + binary_protocol_file = fopen (filename, "w"); +#endif } else { fprintf (stderr, "Invalid format for the MONO_GC_DEBUG env variable: '%s'\n", env); fprintf (stderr, "The format is: MONO_GC_DEBUG=[l[:filename]|<option>]+ where l is a debug level 0-9.\n"); diff --git a/mono/metadata/sgen-protocol.c b/mono/metadata/sgen-protocol.c new file mode 100644 index 00000000000..c6966412907 --- /dev/null +++ b/mono/metadata/sgen-protocol.c @@ -0,0 +1,154 @@ +#ifdef BINARY_PROTOCOL + +#include "sgen-protocol.h" + +/* If not null, dump binary protocol to this file */ +static FILE *binary_protocol_file = NULL; + +#define BINARY_PROTOCOL_BUFFER_SIZE 65536 + +static unsigned char binary_protocol_buffer [BINARY_PROTOCOL_BUFFER_SIZE]; +static int binary_protocol_buffer_index = 0; + +static void +flush_binary_protocol_buffer (void) +{ + if (!binary_protocol_file) + return; + if (binary_protocol_buffer_index == 0) + return; + + fwrite (binary_protocol_buffer, 1, binary_protocol_buffer_index, binary_protocol_file); + fflush (binary_protocol_file); + + binary_protocol_buffer_index = 0; +} + +static void +protocol_entry (unsigned char type, gpointer data, int size) +{ + if (!binary_protocol_file) + return; + if (binary_protocol_buffer_index + 1 + size > BINARY_PROTOCOL_BUFFER_SIZE) + flush_binary_protocol_buffer (); + + binary_protocol_buffer [binary_protocol_buffer_index++] = type; + memcpy (binary_protocol_buffer + binary_protocol_buffer_index, data, size); + binary_protocol_buffer_index += size; + + g_assert (binary_protocol_buffer_index <= BINARY_PROTOCOL_BUFFER_SIZE); +} + +static void +binary_protocol_collection (int generation) +{ + SGenProtocolCollection entry = { generation }; + flush_binary_protocol_buffer (); + protocol_entry (SGEN_PROTOCOL_COLLECTION, &entry, sizeof (SGenProtocolCollection)); +} + +static void +binary_protocol_alloc (gpointer obj, gpointer vtable, int size) +{ + SGenProtocolAlloc entry = { obj, vtable, size }; + protocol_entry (SGEN_PROTOCOL_ALLOC, &entry, sizeof (SGenProtocolAlloc)); +} + +static void +binary_protocol_copy (gpointer from, gpointer to, gpointer vtable, int size) +{ + SGenProtocolCopy entry = { from, to, vtable, size }; + protocol_entry (SGEN_PROTOCOL_COPY, &entry, sizeof (SGenProtocolCopy)); +} + +static void +binary_protocol_pin (gpointer obj, gpointer vtable, int size) +{ + SGenProtocolPin entry = { obj, vtable, size }; + protocol_entry (SGEN_PROTOCOL_PIN, &entry, sizeof (SGenProtocolPin)); +} + +static void +binary_protocol_wbarrier (gpointer ptr, gpointer value, gpointer value_vtable) +{ + SGenProtocolWBarrier entry = { ptr, value, value_vtable }; + protocol_entry (SGEN_PROTOCOL_WBARRIER, &entry, sizeof (SGenProtocolWBarrier)); +} + +static void +binary_protocol_global_remset (gpointer ptr, gpointer value, gpointer value_vtable) +{ + SGenProtocolGlobalRemset entry = { ptr, value, value_vtable }; + protocol_entry (SGEN_PROTOCOL_GLOBAL_REMSET, &entry, sizeof (SGenProtocolGlobalRemset)); +} + +static void +binary_protocol_ptr_update (gpointer ptr, gpointer old_value, gpointer new_value, gpointer vtable, int size) +{ + SGenProtocolPtrUpdate entry = { ptr, old_value, new_value, vtable, size }; + protocol_entry (SGEN_PROTOCOL_PTR_UPDATE, &entry, sizeof (SGenProtocolPtrUpdate)); +} + +static void +binary_protocol_cleanup (gpointer ptr, gpointer vtable, int size) +{ + SGenProtocolCleanup entry = { ptr, vtable, size }; + protocol_entry (SGEN_PROTOCOL_CLEANUP, &entry, sizeof (SGenProtocolCleanup)); +} + +static void +binary_protocol_empty (gpointer start, int size) +{ + SGenProtocolEmpty entry = { start, size }; + protocol_entry (SGEN_PROTOCOL_EMPTY, &entry, sizeof (SGenProtocolEmpty)); +} + +static void +binary_protocol_thread_restart (gpointer thread) +{ + SGenProtocolThreadRestart entry = { thread }; + protocol_entry (SGEN_PROTOCOL_THREAD_RESTART, &entry, sizeof (SGenProtocolThreadRestart)); + +} + +static void +binary_protocol_thread_register (gpointer thread) +{ + SGenProtocolThreadRegister entry = { thread }; + protocol_entry (SGEN_PROTOCOL_THREAD_REGISTER, &entry, sizeof (SGenProtocolThreadRegister)); + +} + +static void +binary_protocol_thread_unregister (gpointer thread) +{ + SGenProtocolThreadUnregister entry = { thread }; + protocol_entry (SGEN_PROTOCOL_THREAD_UNREGISTER, &entry, sizeof (SGenProtocolThreadUnregister)); + +} + +static void +binary_protocol_missing_remset (gpointer obj, gpointer obj_vtable, int offset, gpointer value, gpointer value_vtable, int value_pinned) +{ + SGenProtocolMissingRemset entry = { obj, obj_vtable, offset, value, value_vtable, value_pinned }; + protocol_entry (SGEN_PROTOCOL_MISSING_REMSET, &entry, sizeof (SGenProtocolMissingRemset)); + +} + +#else + +#define binary_protocol_collection(generation) +#define binary_protocol_alloc(obj, vtable, size) +#define binary_protocol_copy(from, to, vtable, size) +#define binary_protocol_pin(obj, vtable, size) +#define binary_protocol_wbarrier(ptr, value, value_vtable) +#define binary_protocol_global_remset(ptr, value, value_vtable) +#define binary_protocol_ptr_update(ptr, old_value, new_value, vtable, size) +#define binary_protocol_cleanup(ptr, vtable, size) +#define binary_protocol_empty(start, size) +#define binary_protocol_thread_restart(thread) +#define binary_protocol_thread_register(thread) +#define binary_protocol_thread_unregister(thread) +#define binary_protocol_missing_remset(obj, obj_vtable, offset, value, value_vtable, value_pinned) + +#endif diff --git a/mono/metadata/sgen-protocol.h b/mono/metadata/sgen-protocol.h new file mode 100644 index 00000000000..1574a2f5f90 --- /dev/null +++ b/mono/metadata/sgen-protocol.h @@ -0,0 +1,92 @@ +enum { + SGEN_PROTOCOL_COLLECTION, + SGEN_PROTOCOL_ALLOC, + SGEN_PROTOCOL_COPY, + SGEN_PROTOCOL_PIN, + SGEN_PROTOCOL_WBARRIER, + SGEN_PROTOCOL_GLOBAL_REMSET, + SGEN_PROTOCOL_PTR_UPDATE, + SGEN_PROTOCOL_CLEANUP, + SGEN_PROTOCOL_EMPTY, + SGEN_PROTOCOL_THREAD_RESTART, + SGEN_PROTOCOL_THREAD_REGISTER, + SGEN_PROTOCOL_THREAD_UNREGISTER, + SGEN_PROTOCOL_MISSING_REMSET +}; + +typedef struct { + int generation; +} SGenProtocolCollection; + +typedef struct { + gpointer obj; + gpointer vtable; + int size; +} SGenProtocolAlloc; + +typedef struct { + gpointer from; + gpointer to; + gpointer vtable; + int size; +} SGenProtocolCopy; + +typedef struct { + gpointer obj; + gpointer vtable; + int size; +} SGenProtocolPin; + +typedef struct { + gpointer ptr; + gpointer value; + gpointer value_vtable; +} SGenProtocolWBarrier; + +typedef struct { + gpointer ptr; + gpointer value; + gpointer value_vtable; +} SGenProtocolGlobalRemset; + +typedef struct { + gpointer ptr; + gpointer old_value; + gpointer new_value; + gpointer vtable; + int size; +} SGenProtocolPtrUpdate; + +typedef struct { + gpointer ptr; + gpointer vtable; + int size; +} SGenProtocolCleanup; + +typedef struct { + gpointer start; + int size; +} SGenProtocolEmpty; + +typedef struct { + gpointer thread; +} SGenProtocolThreadRestart; + +typedef struct { + gpointer thread; +} SGenProtocolThreadRegister; + +typedef struct { + gpointer thread; +} SGenProtocolThreadUnregister; + +typedef struct { + gpointer obj; + gpointer obj_vtable; + int offset; + gpointer value; + gpointer value_vtable; + int value_pinned; +} SGenProtocolMissingRemset; + +/* missing: finalizers, dislinks, roots, non-store wbarriers */ diff --git a/tools/sgen-grep-binprot.c b/tools/sgen-grep-binprot.c new file mode 100644 index 00000000000..849433ddc9e --- /dev/null +++ b/tools/sgen-grep-binprot.c @@ -0,0 +1,202 @@ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <glib.h> + +#include "../mono/metadata/sgen-protocol.h" + +#define SGEN_PROTOCOL_EOF 255 + +static int +read_entry (FILE *in, void **data) +{ + unsigned char type; + int size; + + if (fread (&type, 1, 1, in) != 1) + return SGEN_PROTOCOL_EOF; + switch (type) { + case SGEN_PROTOCOL_COLLECTION: size = sizeof (SGenProtocolCollection); break; + case SGEN_PROTOCOL_ALLOC: size = sizeof (SGenProtocolAlloc); break; + case SGEN_PROTOCOL_COPY: size = sizeof (SGenProtocolCopy); break; + case SGEN_PROTOCOL_PIN: size = sizeof (SGenProtocolPin); break; + case SGEN_PROTOCOL_WBARRIER: size = sizeof (SGenProtocolWBarrier); break; + case SGEN_PROTOCOL_GLOBAL_REMSET: size = sizeof (SGenProtocolGlobalRemset); break; + case SGEN_PROTOCOL_PTR_UPDATE: size = sizeof (SGenProtocolPtrUpdate); break; + case SGEN_PROTOCOL_CLEANUP: size = sizeof (SGenProtocolCleanup); break; + case SGEN_PROTOCOL_EMPTY: size = sizeof (SGenProtocolEmpty); break; + case SGEN_PROTOCOL_THREAD_RESTART: size = sizeof (SGenProtocolThreadRestart); break; + case SGEN_PROTOCOL_THREAD_REGISTER: size = sizeof (SGenProtocolThreadRegister); break; + case SGEN_PROTOCOL_THREAD_UNREGISTER: size = sizeof (SGenProtocolThreadUnregister); break; + case SGEN_PROTOCOL_MISSING_REMSET: size = sizeof (SGenProtocolMissingRemset); break; + default: assert (0); + } + + *data = malloc (size); + if (fread (*data, size, 1, in) != 1) + assert (0); + + return (int)type; +} + +static void +print_entry (int type, void *data) +{ + switch (type) { + case SGEN_PROTOCOL_COLLECTION: { + SGenProtocolCollection *entry = data; + printf ("collection generation %d\n", entry->generation); + break; + } + case SGEN_PROTOCOL_ALLOC: { + SGenProtocolAlloc *entry = data; + printf ("alloc obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size); + break; + } + case SGEN_PROTOCOL_COPY: { + SGenProtocolCopy *entry = data; + printf ("copy from %p to %p vtable %p size %d\n", entry->from, entry->to, entry->vtable, entry->size); + break; + } + case SGEN_PROTOCOL_PIN: { + SGenProtocolPin *entry = data; + printf ("pin obj %p vtable %p size %d\n", entry->obj, entry->vtable, entry->size); + break; + } + case SGEN_PROTOCOL_WBARRIER: { + SGenProtocolWBarrier *entry = data; + printf ("wbarrier ptr %p value %p value_vtable %p\n", entry->ptr, entry->value, entry->value_vtable); + break; + } + case SGEN_PROTOCOL_GLOBAL_REMSET: { + SGenProtocolGlobalRemset *entry = data; + printf ("global_remset ptr %p value %p value_vtable %p\n", entry->ptr, entry->value, entry->value_vtable); + break; + } + case SGEN_PROTOCOL_PTR_UPDATE: { + SGenProtocolPtrUpdate *entry = data; + printf ("ptr_update ptr %p old_value %p new_value %p vtable %p size %d\n", + entry->ptr, entry->old_value, entry->new_value, entry->vtable, entry->size); + break; + } + case SGEN_PROTOCOL_CLEANUP: { + SGenProtocolCleanup *entry = data; + printf ("cleanup ptr %p vtable %p size %d\n", entry->ptr, entry->vtable, entry->size); + break; + } + case SGEN_PROTOCOL_EMPTY: { + SGenProtocolEmpty *entry = data; + printf ("empty start %p size %d\n", entry->start, entry->size); + break; + } + case SGEN_PROTOCOL_THREAD_RESTART: { + SGenProtocolThreadRestart *entry = data; + printf ("thread_restart thread %p\n", entry->thread); + break; + } + case SGEN_PROTOCOL_THREAD_REGISTER: { + SGenProtocolThreadRegister *entry = data; + printf ("thread_register thread %p\n", entry->thread); + break; + } + case SGEN_PROTOCOL_THREAD_UNREGISTER: { + SGenProtocolThreadUnregister *entry = data; + printf ("thread_unregister thread %p\n", entry->thread); + break; + } + case SGEN_PROTOCOL_MISSING_REMSET: { + SGenProtocolMissingRemset *entry = data; + printf ("missing_remset obj %p obj_vtable %p offset %d value %p value_vtable %p value_pinned %d\n", + entry->obj, entry->obj_vtable, entry->offset, entry->value, entry->value_vtable, entry->value_pinned); + break; + } + default: + assert (0); + } +} + +static gboolean +matches_interval (gpointer ptr, gpointer start, int size) +{ + return ptr >= start && (char*)ptr < (char*)start + size; +} + +static gboolean +is_match (gpointer ptr, int type, void *data) +{ + switch (type) { + case SGEN_PROTOCOL_COLLECTION: + case SGEN_PROTOCOL_THREAD_RESTART: + case SGEN_PROTOCOL_THREAD_REGISTER: + case SGEN_PROTOCOL_THREAD_UNREGISTER: + return TRUE; + case SGEN_PROTOCOL_ALLOC: { + SGenProtocolAlloc *entry = data; + return matches_interval (ptr, entry->obj, entry->size); + } + case SGEN_PROTOCOL_COPY: { + SGenProtocolCopy *entry = data; + return matches_interval (ptr, entry->from, entry->size) || matches_interval (ptr, entry->to, entry->size); + } + case SGEN_PROTOCOL_PIN: { + SGenProtocolPin *entry = data; + return matches_interval (ptr, entry->obj, entry->size); + } + case SGEN_PROTOCOL_WBARRIER: { + SGenProtocolWBarrier *entry = data; + return ptr == entry->ptr || ptr == entry->value; + } + case SGEN_PROTOCOL_GLOBAL_REMSET: { + SGenProtocolGlobalRemset *entry = data; + return ptr == entry->ptr || ptr == entry->value; + } + case SGEN_PROTOCOL_PTR_UPDATE: { + SGenProtocolPtrUpdate *entry = data; + return ptr == entry->ptr || + matches_interval (ptr, entry->old_value, entry->size) || + matches_interval (ptr, entry->new_value, entry->size); + } + case SGEN_PROTOCOL_CLEANUP: { + SGenProtocolCleanup *entry = data; + return matches_interval (ptr, entry->ptr, entry->size); + } + case SGEN_PROTOCOL_EMPTY: { + SGenProtocolEmpty *entry = data; + return matches_interval (ptr, entry->start, entry->size); + } + case SGEN_PROTOCOL_MISSING_REMSET: { + SGenProtocolMissingRemset *entry = data; + return ptr == entry->obj || ptr == entry->value || ptr == (char*)entry->obj + entry->offset; + } + default: + assert (0); + } +} + +int +main (int argc, char *argv[]) +{ + int type; + void *data; + int num_nums = argc - 1; + int i; + long nums [num_nums]; + + for (i = 0; i < num_nums; ++i) + nums [i] = strtol (argv [i + 1], NULL, 16); + + while ((type = read_entry (stdin, &data)) != SGEN_PROTOCOL_EOF) { + gboolean match = FALSE; + for (i = 0; i < num_nums; ++i) { + if (is_match ((gpointer) nums [i], type, data)) { + match = TRUE; + break; + } + } + if (match) + print_entry (type, data); + free (data); + } + + return 0; +} |