Merge pull request #2274 from esdrubal/udpclientreceive
[mono.git] / mono / sgen / sgen-debug.c
1 /*
2  * sgen-debug.c: Collector debugging
3  *
4  * Author:
5  *      Paolo Molaro (lupus@ximian.com)
6  *  Rodrigo Kumpera (kumpera@gmail.com)
7  *
8  * Copyright 2005-2011 Novell, Inc (http://www.novell.com)
9  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
10  * Copyright 2011 Xamarin, Inc.
11  * Copyright (C) 2012 Xamarin Inc
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License 2.0 as published by the Free Software Foundation;
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License 2.0 along with this library; if not, write to the Free
24  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26
27 #include "config.h"
28 #ifdef HAVE_SGEN_GC
29
30 #include <string.h>
31
32 #include "mono/sgen/sgen-gc.h"
33 #include "mono/sgen/sgen-cardtable.h"
34 #include "mono/sgen/sgen-protocol.h"
35 #include "mono/sgen/sgen-memory-governor.h"
36 #include "mono/sgen/sgen-pinning.h"
37 #include "mono/sgen/sgen-client.h"
38
39 #define LOAD_VTABLE     SGEN_LOAD_VTABLE
40
41 #define object_is_forwarded     SGEN_OBJECT_IS_FORWARDED
42 #define object_is_pinned        SGEN_OBJECT_IS_PINNED
43 #define safe_object_get_size    sgen_safe_object_get_size
44
45 void describe_ptr (char *ptr);
46 void check_object (GCObject *obj);
47
48 /*
49  * ######################################################################
50  * ########  Collector debugging
51  * ######################################################################
52  */
53
54 static const char*descriptor_types [] = {
55         "INVALID",
56         "run length",
57         "bitmap",
58         "small pointer-free",
59         "complex",
60         "vector",
61         "complex arrray",
62         "complex pointer-free"
63 };
64
65 static char* describe_nursery_ptr (char *ptr, gboolean need_setup);
66
67 static void
68 describe_pointer (char *ptr, gboolean need_setup)
69 {
70         GCVTable vtable;
71         SgenDescriptor desc;
72         int type;
73         char *start;
74         char *forwarded;
75         mword size;
76
77  restart:
78         if (sgen_ptr_in_nursery (ptr)) {
79                 start = describe_nursery_ptr (ptr, need_setup);
80                 if (!start)
81                         return;
82                 ptr = start;
83                 vtable = LOAD_VTABLE ((GCObject*)ptr);
84         } else {
85                 if (sgen_ptr_is_in_los (ptr, &start)) {
86                         if (ptr == start)
87                                 printf ("Pointer is the start of object %p in LOS space.\n", start);
88                         else
89                                 printf ("Pointer is at offset 0x%x of object %p in LOS space.\n", (int)(ptr - start), start);
90                         ptr = start;
91                         mono_sgen_los_describe_pointer (ptr);
92                         vtable = LOAD_VTABLE ((GCObject*)ptr);
93                 } else if (major_collector.ptr_is_in_non_pinned_space (ptr, &start)) {
94                         if (ptr == start)
95                                 printf ("Pointer is the start of object %p in oldspace.\n", start);
96                         else if (start)
97                                 printf ("Pointer is at offset 0x%x of object %p in oldspace.\n", (int)(ptr - start), start);
98                         else
99                                 printf ("Pointer inside oldspace.\n");
100                         if (start)
101                                 ptr = start;
102                         vtable = (GCVTable)major_collector.describe_pointer (ptr);
103                 } else if (major_collector.ptr_is_from_pinned_alloc (ptr)) {
104                         // FIXME: Handle pointers to the inside of objects
105                         printf ("Pointer is inside a pinned chunk.\n");
106                         vtable = LOAD_VTABLE ((GCObject*)ptr);
107                 } else {
108                         printf ("Pointer unknown.\n");
109                         return;
110                 }
111         }
112
113         if (object_is_pinned (ptr))
114                 printf ("Object is pinned.\n");
115
116         if ((forwarded = (char *)object_is_forwarded (ptr))) {
117                 printf ("Object is forwarded to %p:\n", forwarded);
118                 ptr = forwarded;
119                 goto restart;
120         }
121
122         printf ("VTable: %p\n", vtable);
123         if (vtable == NULL) {
124                 printf ("VTable is invalid (empty).\n");
125                 goto invalid_vtable;
126         }
127         if (sgen_ptr_in_nursery (vtable)) {
128                 printf ("VTable is invalid (points inside nursery).\n");
129                 goto invalid_vtable;
130         }
131         printf ("Class: %s.%s\n", sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
132
133         desc = sgen_vtable_get_descriptor (vtable);
134         printf ("Descriptor: %lx\n", (long)desc);
135
136         type = desc & DESC_TYPE_MASK;
137         printf ("Descriptor type: %d (%s)\n", type, descriptor_types [type]);
138
139         size = sgen_safe_object_get_size ((GCObject*)ptr);
140         printf ("Size: %d\n", (int)size);
141
142  invalid_vtable:
143         ;
144         sgen_client_describe_invalid_pointer ((GCObject *) ptr);
145 }
146
147 void
148 describe_ptr (char *ptr)
149 {
150         describe_pointer (ptr, TRUE);
151 }
152
153 static gboolean missing_remsets;
154
155 /*
156  * We let a missing remset slide if the target object is pinned,
157  * because the store might have happened but the remset not yet added,
158  * but in that case the target must be pinned.  We might theoretically
159  * miss some missing remsets this way, but it's very unlikely.
160  */
161 #undef HANDLE_PTR
162 #define HANDLE_PTR(ptr,obj)     do {    \
163         if (*(ptr) && sgen_ptr_in_nursery ((char*)*(ptr))) { \
164                 if (!sgen_get_remset ()->find_address ((char*)(ptr)) && !sgen_cement_lookup (*(ptr))) { \
165                         GCVTable __vt = SGEN_LOAD_VTABLE (obj); \
166                         SGEN_LOG (0, "Oldspace->newspace reference %p at offset %zd in object %p (%s.%s) not found in remsets.", *(ptr), (char*)(ptr) - (char*)(obj), (obj), sgen_client_vtable_get_namespace (__vt), sgen_client_vtable_get_name (__vt)); \
167                         binary_protocol_missing_remset ((obj), __vt, (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \
168                         if (!object_is_pinned (*(ptr)))                                                         \
169                                 missing_remsets = TRUE;                                                                 \
170                 }                                                                                                                               \
171         }                                                                                                                                       \
172         } while (0)
173
174 /*
175  * Check that each object reference which points into the nursery can
176  * be found in the remembered sets.
177  */
178 static void
179 check_consistency_callback (GCObject *obj, size_t size, void *dummy)
180 {
181         char *start = (char*)obj;
182         GCVTable vt = LOAD_VTABLE (obj);
183         SgenDescriptor desc = sgen_vtable_get_descriptor (vt);
184         SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", start, vt, sgen_client_vtable_get_name (vt));
185
186 #include "sgen-scan-object.h"
187 }
188
189 /*
190  * Perform consistency check of the heap.
191  *
192  * Assumes the world is stopped.
193  */
194 void
195 sgen_check_consistency (void)
196 {
197         // Need to add more checks
198
199         missing_remsets = FALSE;
200
201         SGEN_LOG (1, "Begin heap consistency check...");
202
203         // Check that oldspace->newspace pointers are registered with the collector
204         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)check_consistency_callback, NULL);
205
206         sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_consistency_callback, NULL);
207
208         SGEN_LOG (1, "Heap consistency check done.");
209
210         if (!binary_protocol_is_enabled ())
211                 g_assert (!missing_remsets);
212 }
213
214 static gboolean
215 is_major_or_los_object_marked (GCObject *obj)
216 {
217         if (sgen_safe_object_get_size ((GCObject*)obj) > SGEN_MAX_SMALL_OBJ_SIZE) {
218                 return sgen_los_object_is_pinned (obj);
219         } else {
220                 return sgen_get_major_collector ()->is_object_live (obj);
221         }
222 }
223
224 #undef HANDLE_PTR
225 #define HANDLE_PTR(ptr,obj)     do {    \
226         if (*(ptr) && !sgen_ptr_in_nursery ((char*)*(ptr)) && !is_major_or_los_object_marked ((GCObject*)*(ptr))) { \
227                 if (!sgen_get_remset ()->find_address_with_cards (start, cards, (char*)(ptr))) { \
228                         GCVTable __vt = SGEN_LOAD_VTABLE (obj); \
229                         SGEN_LOG (0, "major->major reference %p at offset %zd in object %p (%s.%s) not found in remsets.", *(ptr), (char*)(ptr) - (char*)(obj), (obj), sgen_client_vtable_get_namespace (__vt), sgen_client_vtable_get_name (__vt)); \
230                         binary_protocol_missing_remset ((obj), __vt, (int) ((char*)(ptr) - (char*)(obj)), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \
231                         missing_remsets = TRUE;                         \
232                 }                                                                                                                               \
233         }                                                                                                                                       \
234         } while (0)
235
236 static void
237 check_mod_union_callback (GCObject *obj, size_t size, void *dummy)
238 {
239         char *start = (char*)obj;
240         gboolean in_los = (gboolean) (size_t) dummy;
241         GCVTable vt = LOAD_VTABLE (obj);
242         SgenDescriptor desc = sgen_vtable_get_descriptor (vt);
243         guint8 *cards;
244         SGEN_LOG (8, "Scanning object %p, vtable: %p (%s)", obj, vt, sgen_client_vtable_get_name (vt));
245
246         if (!is_major_or_los_object_marked (obj))
247                 return;
248
249         if (in_los)
250                 cards = sgen_los_header_for_object (obj)->cardtable_mod_union;
251         else
252                 cards = sgen_get_major_collector ()->get_cardtable_mod_union_for_reference (start);
253
254         SGEN_ASSERT (0, cards, "we must have mod union for marked major objects");
255
256 #include "sgen-scan-object.h"
257 }
258
259 void
260 sgen_check_mod_union_consistency (void)
261 {
262         missing_remsets = FALSE;
263
264         major_collector.iterate_objects (ITERATE_OBJECTS_ALL, (IterateObjectCallbackFunc)check_mod_union_callback, (void*)FALSE);
265
266         sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_mod_union_callback, (void*)TRUE);
267
268         if (!binary_protocol_is_enabled ())
269                 g_assert (!missing_remsets);
270 }
271
272 #undef HANDLE_PTR
273 #define HANDLE_PTR(ptr,obj)     do {                                    \
274                 if (*(ptr) && !LOAD_VTABLE (*(ptr)))                                            \
275                         g_error ("Could not load vtable for obj %p slot %zd (size %zd)", obj, (char*)ptr - (char*)obj, (size_t)safe_object_get_size ((GCObject*)obj)); \
276         } while (0)
277
278 static void
279 check_major_refs_callback (GCObject *obj, size_t size, void *dummy)
280 {
281         char *start = (char*)obj;
282         SgenDescriptor desc = sgen_obj_get_descriptor (obj);
283
284 #include "sgen-scan-object.h"
285 }
286
287 void
288 sgen_check_major_refs (void)
289 {
290         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)check_major_refs_callback, NULL);
291         sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_major_refs_callback, NULL);
292 }
293
294 /* Check that the reference is valid */
295 #undef HANDLE_PTR
296 #define HANDLE_PTR(ptr,obj)     do {    \
297                 if (*(ptr)) {   \
298                         g_assert (sgen_client_vtable_get_namespace (SGEN_LOAD_VTABLE_UNCHECKED (*(ptr))));      \
299                 }       \
300         } while (0)
301
302 /*
303  * check_object:
304  *
305  *   Perform consistency check on an object. Currently we only check that the
306  * reference fields are valid.
307  */
308 void
309 check_object (GCObject *obj)
310 {
311         char *start = (char*)obj;
312         SgenDescriptor desc;
313
314         if (!start)
315                 return;
316
317         desc = sgen_obj_get_descriptor (obj);
318
319 #include "sgen-scan-object.h"
320 }
321
322
323 static GCObject **valid_nursery_objects;
324 static int valid_nursery_object_count;
325 static gboolean broken_heap;
326
327 static void 
328 setup_mono_sgen_scan_area_with_callback (GCObject *object, size_t size, void *data)
329 {
330         valid_nursery_objects [valid_nursery_object_count++] = object;
331 }
332
333 static void
334 setup_valid_nursery_objects (void)
335 {
336         if (!valid_nursery_objects)
337                 valid_nursery_objects = (GCObject **)sgen_alloc_os_memory (DEFAULT_NURSERY_SIZE, (SgenAllocFlags)(SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE), "debugging data");
338         valid_nursery_object_count = 0;
339         sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, setup_mono_sgen_scan_area_with_callback, NULL, FALSE, FALSE);
340 }
341
342 static gboolean
343 find_object_in_nursery_dump (char *object)
344 {
345         int first = 0, last = valid_nursery_object_count;
346         while (first < last) {
347                 int middle = first + ((last - first) >> 1);
348                 if (object == (char*)valid_nursery_objects [middle])
349                         return TRUE;
350
351                 if (object < (char*)valid_nursery_objects [middle])
352                         last = middle;
353                 else
354                         first = middle + 1;
355         }
356         g_assert (first == last);
357         return FALSE;
358 }
359
360 static void
361 iterate_valid_nursery_objects (IterateObjectCallbackFunc callback, void *data)
362 {
363         int i;
364         for (i = 0; i < valid_nursery_object_count; ++i) {
365                 GCObject *obj = valid_nursery_objects [i];
366                 callback (obj, safe_object_get_size (obj), data);
367         }
368 }
369
370 static char*
371 describe_nursery_ptr (char *ptr, gboolean need_setup)
372 {
373         int i;
374
375         if (need_setup)
376                 setup_valid_nursery_objects ();
377
378         for (i = 0; i < valid_nursery_object_count - 1; ++i) {
379                 if ((char*)valid_nursery_objects [i + 1] > ptr)
380                         break;
381         }
382
383         if (i >= valid_nursery_object_count || (char*)valid_nursery_objects [i] + safe_object_get_size (valid_nursery_objects [i]) < ptr) {
384                 SGEN_LOG (0, "nursery-ptr (unalloc'd-memory)");
385                 return NULL;
386         } else {
387                 GCObject *obj = valid_nursery_objects [i];
388                 if ((char*)obj == ptr)
389                         SGEN_LOG (0, "nursery-ptr %p", obj);
390                 else
391                         SGEN_LOG (0, "nursery-ptr %p (interior-ptr offset %zd)", obj, ptr - (char*)obj);
392                 return (char*)obj;
393         }
394 }
395
396 static gboolean
397 is_valid_object_pointer (char *object)
398 {
399         if (sgen_ptr_in_nursery (object))
400                 return find_object_in_nursery_dump (object);
401         
402         if (sgen_los_is_valid_object (object))
403                 return TRUE;
404
405         if (major_collector.is_valid_object (object))
406                 return TRUE;
407         return FALSE;
408 }
409
410 static void
411 bad_pointer_spew (char *obj, char **slot)
412 {
413         char *ptr = *slot;
414         GCVTable vtable = LOAD_VTABLE ((GCObject*)obj);
415
416         SGEN_LOG (0, "Invalid object pointer %p at offset %zd in object %p (%s.%s):", ptr,
417                         (char*)slot - obj,
418                         obj, sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
419         describe_pointer (ptr, FALSE);
420         broken_heap = TRUE;
421 }
422
423 static void
424 missing_remset_spew (char *obj, char **slot)
425 {
426         char *ptr = *slot;
427         GCVTable vtable = LOAD_VTABLE ((GCObject*)obj);
428
429         SGEN_LOG (0, "Oldspace->newspace reference %p at offset %zd in object %p (%s.%s) not found in remsets.",
430                         ptr, (char*)slot - obj, obj, 
431                         sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
432
433         broken_heap = TRUE;
434 }
435
436 /*
437 FIXME Flag missing remsets due to pinning as non fatal
438 */
439 #undef HANDLE_PTR
440 #define HANDLE_PTR(ptr,obj)     do {    \
441                 if (*(char**)ptr) {     \
442                         if (!is_valid_object_pointer (*(char**)ptr)) {  \
443                                 bad_pointer_spew ((char*)obj, (char**)ptr);     \
444                         } else if (!sgen_ptr_in_nursery (obj) && sgen_ptr_in_nursery ((char*)*ptr)) {   \
445                                 if (!sgen_get_remset ()->find_address ((char*)(ptr)) && !sgen_cement_lookup (*(ptr)) && (!allow_missing_pinned || !SGEN_OBJECT_IS_PINNED (*(ptr)))) \
446                                 missing_remset_spew ((char*)obj, (char**)ptr);  \
447                         }       \
448         } \
449         } while (0)
450
451 static void
452 verify_object_pointers_callback (GCObject *obj, size_t size, void *data)
453 {
454         char *start = (char*)obj;
455         gboolean allow_missing_pinned = (gboolean) (size_t) data;
456         SgenDescriptor desc = sgen_obj_get_descriptor (obj);
457
458 #include "sgen-scan-object.h"
459 }
460
461 /*
462 FIXME:
463 -This heap checker is racy regarding inlined write barriers and other JIT tricks that
464 depend on OP_DUMMY_USE.
465 */
466 void
467 sgen_check_whole_heap (gboolean allow_missing_pinned)
468 {
469         setup_valid_nursery_objects ();
470
471         broken_heap = FALSE;
472         sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned, FALSE, TRUE);
473         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned);
474         sgen_los_iterate_objects (verify_object_pointers_callback, (void*) (size_t) allow_missing_pinned);
475
476         g_assert (!broken_heap);
477 }
478
479 static gboolean
480 ptr_in_heap (char *object)
481 {
482         if (sgen_ptr_in_nursery (object))
483                 return TRUE;
484         
485         if (sgen_los_is_valid_object (object))
486                 return TRUE;
487
488         if (major_collector.is_valid_object (object))
489                 return TRUE;
490         return FALSE;
491 }
492
493 /*
494  * sgen_check_objref:
495  *   Do consistency checks on the object reference OBJ. Assert on failure.
496  */
497 void
498 sgen_check_objref (char *obj)
499 {
500         g_assert (ptr_in_heap (obj));
501 }
502
503 static void
504 find_pinning_ref_from_thread (char *obj, size_t size)
505 {
506 #ifndef SGEN_WITHOUT_MONO
507         int j;
508         SgenThreadInfo *info;
509         char *endobj = obj + size;
510
511         FOREACH_THREAD (info) {
512                 char **start = (char**)info->client_info.stack_start;
513                 if (info->client_info.skip || info->client_info.gc_disabled)
514                         continue;
515                 while (start < (char**)info->client_info.stack_end) {
516                         if (*start >= obj && *start < endobj)
517                                 SGEN_LOG (0, "Object %p referenced in thread %p (id %p) at %p, stack: %p-%p", obj, info, (gpointer)mono_thread_info_get_tid (info), start, info->client_info.stack_start, info->client_info.stack_end);
518                         start++;
519                 }
520
521                 for (j = 0; j < ARCH_NUM_REGS; ++j) {
522 #ifdef USE_MONO_CTX
523                         mword w = ((mword*)&info->client_info.ctx) [j];
524 #else
525                         mword w = (mword)&info->client_info.regs [j];
526 #endif
527
528                         if (w >= (mword)obj && w < (mword)obj + size)
529                                 SGEN_LOG (0, "Object %p referenced in saved reg %d of thread %p (id %p)", obj, j, info, (gpointer)mono_thread_info_get_tid (info));
530                 } END_FOREACH_THREAD
531         }
532 #endif
533 }
534
535 /*
536  * Debugging function: find in the conservative roots where @obj is being pinned.
537  */
538 static G_GNUC_UNUSED void
539 find_pinning_reference (char *obj, size_t size)
540 {
541         char **start;
542         RootRecord *root;
543         char *endobj = obj + size;
544
545         SGEN_HASH_TABLE_FOREACH (&roots_hash [ROOT_TYPE_NORMAL], char **, start, RootRecord *, root) {
546                 /* if desc is non-null it has precise info */
547                 if (!root->root_desc) {
548                         while (start < (char**)root->end_root) {
549                                 if (*start >= obj && *start < endobj) {
550                                         SGEN_LOG (0, "Object %p referenced in pinned roots %p-%p\n", obj, start, root->end_root);
551                                 }
552                                 start++;
553                         }
554                 }
555         } SGEN_HASH_TABLE_FOREACH_END;
556
557         find_pinning_ref_from_thread (obj, size);
558 }
559
560 #undef HANDLE_PTR
561 #define HANDLE_PTR(ptr,obj)     do {                                    \
562                 char* __target = *(char**)ptr;                          \
563                 if (__target) {                                         \
564                         if (sgen_ptr_in_nursery (__target)) {           \
565                                 g_assert (!SGEN_OBJECT_IS_FORWARDED (__target)); \
566                         } else {                                        \
567                                 mword __size = sgen_safe_object_get_size ((GCObject*)__target); \
568                                 if (__size <= SGEN_MAX_SMALL_OBJ_SIZE)  \
569                                         g_assert (major_collector.is_object_live ((GCObject*)__target)); \
570                                 else                                    \
571                                         g_assert (sgen_los_object_is_pinned ((GCObject*)__target)); \
572                         }                                               \
573                 }                                                       \
574         } while (0)
575
576 static void
577 check_marked_callback (GCObject *obj, size_t size, void *dummy)
578 {
579         char *start = (char*)obj;
580         gboolean flag = (gboolean) (size_t) dummy;
581         SgenDescriptor desc;
582
583         if (sgen_ptr_in_nursery (start)) {
584                 if (flag)
585                         SGEN_ASSERT (0, SGEN_OBJECT_IS_PINNED (obj), "All objects remaining in the nursery must be pinned");
586         } else if (flag) {
587                 if (!sgen_los_object_is_pinned (obj))
588                         return;
589         } else {
590                 if (!major_collector.is_object_live (obj))
591                         return;
592         }
593
594         desc = sgen_obj_get_descriptor_safe (obj);
595
596 #include "sgen-scan-object.h"
597 }
598
599 void
600 sgen_check_heap_marked (gboolean nursery_must_be_pinned)
601 {
602         setup_valid_nursery_objects ();
603
604         iterate_valid_nursery_objects (check_marked_callback, (void*)(size_t)nursery_must_be_pinned);
605         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, check_marked_callback, (void*)FALSE);
606         sgen_los_iterate_objects (check_marked_callback, (void*)TRUE);
607 }
608
609 static void
610 check_nursery_objects_pinned_callback (char *obj, size_t size, void *data /* ScanCopyContext *ctx */)
611 {
612         gboolean pinned = (gboolean) (size_t) data;
613
614         g_assert (!SGEN_OBJECT_IS_FORWARDED (obj));
615         if (pinned)
616                 g_assert (SGEN_OBJECT_IS_PINNED (obj));
617         else
618                 g_assert (!SGEN_OBJECT_IS_PINNED (obj));
619 }
620
621 void
622 sgen_check_nursery_objects_pinned (gboolean pinned)
623 {
624         sgen_clear_nursery_fragments ();
625         sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
626                         (IterateObjectCallbackFunc)check_nursery_objects_pinned_callback, (void*) (size_t) pinned /* (void*)&ctx */, FALSE, TRUE);
627 }
628
629 static void
630 verify_scan_starts (char *start, char *end)
631 {
632         size_t i;
633
634         for (i = 0; i < nursery_section->num_scan_start; ++i) {
635                 char *addr = nursery_section->scan_starts [i];
636                 if (addr > start && addr < end)
637                         SGEN_LOG (0, "NFC-BAD SCAN START [%zu] %p for obj [%p %p]", i, addr, start, end);
638         }
639 }
640
641 void
642 sgen_debug_verify_nursery (gboolean do_dump_nursery_content)
643 {
644         char *start, *end, *cur, *hole_start;
645
646         if (nursery_canaries_enabled ())
647                 SGEN_LOG (0, "Checking nursery canaries...");
648
649         /*This cleans up unused fragments */
650         sgen_nursery_allocator_prepare_for_pinning ();
651
652         hole_start = start = cur = sgen_get_nursery_start ();
653         end = sgen_get_nursery_end ();
654
655         while (cur < end) {
656                 size_t ss, size;
657                 gboolean is_array_fill;
658
659                 if (!*(void**)cur) {
660                         cur += sizeof (void*);
661                         continue;
662                 }
663
664                 if (object_is_forwarded (cur))
665                         SGEN_LOG (0, "FORWARDED OBJ %p", cur);
666                 else if (object_is_pinned (cur))
667                         SGEN_LOG (0, "PINNED OBJ %p", cur);
668
669                 ss = safe_object_get_size ((GCObject*)cur);
670                 size = SGEN_ALIGN_UP (ss);
671                 verify_scan_starts (cur, cur + size);
672                 is_array_fill = sgen_client_object_is_array_fill ((GCObject*)cur);
673                 if (do_dump_nursery_content) {
674                         GCVTable vtable = SGEN_LOAD_VTABLE ((GCObject*)cur);
675                         if (cur > hole_start)
676                                 SGEN_LOG (0, "HOLE [%p %p %d]", hole_start, cur, (int)(cur - hole_start));
677                         SGEN_LOG (0, "OBJ  [%p %p %d %d %s.%s %d]", cur, cur + size, (int)size, (int)ss,
678                                         sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable),
679                                         is_array_fill);
680                 }
681                 if (nursery_canaries_enabled () && !is_array_fill) {
682                         CHECK_CANARY_FOR_OBJECT ((GCObject*)cur, TRUE);
683                         CANARIFY_SIZE (size);
684                 }
685                 cur += size;
686                 hole_start = cur;
687         }
688 }
689
690 /*
691  * Checks that no objects in the nursery are fowarded or pinned.  This
692  * is a precondition to restarting the mutator while doing a
693  * concurrent collection.  Note that we don't clear fragments because
694  * we depend on that having happened earlier.
695  */
696 void
697 sgen_debug_check_nursery_is_clean (void)
698 {
699         char *end, *cur;
700
701         cur = sgen_get_nursery_start ();
702         end = sgen_get_nursery_end ();
703
704         while (cur < end) {
705                 size_t size;
706
707                 if (!*(void**)cur) {
708                         cur += sizeof (void*);
709                         continue;
710                 }
711
712                 g_assert (!object_is_forwarded (cur));
713                 g_assert (!object_is_pinned (cur));
714
715                 size = SGEN_ALIGN_UP (safe_object_get_size ((GCObject*)cur));
716                 verify_scan_starts (cur, cur + size);
717
718                 cur += size;
719         }
720 }
721
722 static gboolean scan_object_for_specific_ref_precise = TRUE;
723
724 #undef HANDLE_PTR
725 #define HANDLE_PTR(ptr,obj) do {                                        \
726                 if ((GCObject*)*(ptr) == key) {                         \
727                         GCVTable vtable = SGEN_LOAD_VTABLE (*(ptr));    \
728                         g_print ("found ref to %p in object %p (%s.%s) at offset %zd\n", \
729                                         key, (obj), sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable), ((char*)(ptr) - (char*)(obj))); \
730                 }                                                       \
731         } while (0)
732
733 static void
734 scan_object_for_specific_ref (GCObject *obj, GCObject *key)
735 {
736         GCObject *forwarded;
737
738         if ((forwarded = SGEN_OBJECT_IS_FORWARDED (obj)))
739                 obj = forwarded;
740
741         if (scan_object_for_specific_ref_precise) {
742                 char *start = (char*)obj;
743                 SgenDescriptor desc = sgen_obj_get_descriptor_safe (obj);
744                 #include "sgen-scan-object.h"
745         } else {
746                 mword *words = (mword*)obj;
747                 size_t size = safe_object_get_size (obj);
748                 int i;
749                 for (i = 0; i < size / sizeof (mword); ++i) {
750                         if (words [i] == (mword)key) {
751                                 GCVTable vtable = SGEN_LOAD_VTABLE (obj);
752                                 g_print ("found possible ref to %p in object %p (%s.%s) at offset %zd\n",
753                                                 key, obj, sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable), i * sizeof (mword));
754                         }
755                 }
756         }
757 }
758
759 static void
760 scan_object_for_specific_ref_callback (GCObject *obj, size_t size, GCObject *key)
761 {
762         scan_object_for_specific_ref (obj, key);
763 }
764
765 static void
766 check_root_obj_specific_ref (RootRecord *root, GCObject *key, GCObject *obj)
767 {
768         if (key != obj)
769                 return;
770         g_print ("found ref to %p in root record %p\n", key, root);
771 }
772
773 static GCObject *check_key = NULL;
774 static RootRecord *check_root = NULL;
775
776 static void
777 check_root_obj_specific_ref_from_marker (GCObject **obj, void *gc_data)
778 {
779         check_root_obj_specific_ref (check_root, check_key, *obj);
780 }
781
782 static void
783 scan_roots_for_specific_ref (GCObject *key, int root_type)
784 {
785         void **start_root;
786         RootRecord *root;
787         check_key = key;
788
789         SGEN_HASH_TABLE_FOREACH (&roots_hash [root_type], void **, start_root, RootRecord *, root) {
790                 SgenDescriptor desc = root->root_desc;
791
792                 check_root = root;
793
794                 switch (desc & ROOT_DESC_TYPE_MASK) {
795                 case ROOT_DESC_BITMAP:
796                         desc >>= ROOT_DESC_TYPE_SHIFT;
797                         while (desc) {
798                                 if (desc & 1)
799                                         check_root_obj_specific_ref (root, key, (GCObject *)*start_root);
800                                 desc >>= 1;
801                                 start_root++;
802                         }
803                         return;
804                 case ROOT_DESC_COMPLEX: {
805                         gsize *bitmap_data = (gsize *)sgen_get_complex_descriptor_bitmap (desc);
806                         int bwords = (int) ((*bitmap_data) - 1);
807                         void **start_run = start_root;
808                         bitmap_data++;
809                         while (bwords-- > 0) {
810                                 gsize bmap = *bitmap_data++;
811                                 void **objptr = start_run;
812                                 while (bmap) {
813                                         if (bmap & 1)
814                                                 check_root_obj_specific_ref (root, key, (GCObject *)*objptr);
815                                         bmap >>= 1;
816                                         ++objptr;
817                                 }
818                                 start_run += GC_BITS_PER_WORD;
819                         }
820                         break;
821                 }
822                 case ROOT_DESC_USER: {
823                         SgenUserRootMarkFunc marker = sgen_get_user_descriptor_func (desc);
824                         marker (start_root, check_root_obj_specific_ref_from_marker, NULL);
825                         break;
826                 }
827                 case ROOT_DESC_RUN_LEN:
828                         g_assert_not_reached ();
829                 default:
830                         g_assert_not_reached ();
831                 }
832         } SGEN_HASH_TABLE_FOREACH_END;
833
834         check_key = NULL;
835         check_root = NULL;
836 }
837
838 void
839 mono_gc_scan_for_specific_ref (GCObject *key, gboolean precise)
840 {
841         void **ptr;
842         RootRecord *root;
843
844         scan_object_for_specific_ref_precise = precise;
845
846         sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
847                         (IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key, TRUE, FALSE);
848
849         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key);
850
851         sgen_los_iterate_objects ((IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key);
852
853         scan_roots_for_specific_ref (key, ROOT_TYPE_NORMAL);
854         scan_roots_for_specific_ref (key, ROOT_TYPE_WBARRIER);
855
856         SGEN_HASH_TABLE_FOREACH (&roots_hash [ROOT_TYPE_PINNED], void **, ptr, RootRecord *, root) {
857                 while (ptr < (void**)root->end_root) {
858                         check_root_obj_specific_ref (root, (GCObject *)*ptr, key);
859                         ++ptr;
860                 }
861         } SGEN_HASH_TABLE_FOREACH_END;
862
863         if (sgen_is_world_stopped ())
864                 find_pinning_ref_from_thread ((char*)key, sizeof (GCObject));
865 }
866
867 #ifndef SGEN_WITHOUT_MONO
868
869 static MonoDomain *check_domain = NULL;
870
871 static void
872 check_obj_not_in_domain (MonoObject **o)
873 {
874         g_assert (((*o))->vtable->domain != check_domain);
875 }
876
877
878 static void
879 check_obj_not_in_domain_callback (GCObject **o, void *gc_data)
880 {
881         g_assert ((*o)->vtable->domain != check_domain);
882 }
883
884 void
885 sgen_scan_for_registered_roots_in_domain (MonoDomain *domain, int root_type)
886 {
887         void **start_root;
888         RootRecord *root;
889         check_domain = domain;
890         SGEN_HASH_TABLE_FOREACH (&roots_hash [root_type], void **, start_root, RootRecord *, root) {
891                 SgenDescriptor desc = root->root_desc;
892
893                 /* The MonoDomain struct is allowed to hold
894                    references to objects in its own domain. */
895                 if (start_root == (void**)domain)
896                         continue;
897
898                 switch (desc & ROOT_DESC_TYPE_MASK) {
899                 case ROOT_DESC_BITMAP:
900                         desc >>= ROOT_DESC_TYPE_SHIFT;
901                         while (desc) {
902                                 if ((desc & 1) && *start_root)
903                                         check_obj_not_in_domain ((MonoObject **)*start_root);
904                                 desc >>= 1;
905                                 start_root++;
906                         }
907                         break;
908                 case ROOT_DESC_COMPLEX: {
909                         gsize *bitmap_data = (gsize *)sgen_get_complex_descriptor_bitmap (desc);
910                         int bwords = (int)((*bitmap_data) - 1);
911                         void **start_run = start_root;
912                         bitmap_data++;
913                         while (bwords-- > 0) {
914                                 gsize bmap = *bitmap_data++;
915                                 void **objptr = start_run;
916                                 while (bmap) {
917                                         if ((bmap & 1) && *objptr)
918                                                 check_obj_not_in_domain ((MonoObject **)*objptr);
919                                         bmap >>= 1;
920                                         ++objptr;
921                                 }
922                                 start_run += GC_BITS_PER_WORD;
923                         }
924                         break;
925                 }
926                 case ROOT_DESC_USER: {
927                         SgenUserRootMarkFunc marker = sgen_get_user_descriptor_func (desc);
928                         marker (start_root, check_obj_not_in_domain_callback, NULL);
929                         break;
930                 }
931                 case ROOT_DESC_RUN_LEN:
932                         g_assert_not_reached ();
933                 default:
934                         g_assert_not_reached ();
935                 }
936         } SGEN_HASH_TABLE_FOREACH_END;
937
938         check_domain = NULL;
939 }
940
941 static gboolean
942 is_xdomain_ref_allowed (GCObject **ptr, GCObject *obj, MonoDomain *domain)
943 {
944         MonoObject *o = (MonoObject*)(obj);
945         MonoObject *ref = *ptr;
946         size_t offset = (char*)(ptr) - (char*)o;
947
948         if (o->vtable->klass == mono_defaults.thread_class && offset == G_STRUCT_OFFSET (MonoThread, internal_thread))
949                 return TRUE;
950         if (o->vtable->klass == mono_defaults.internal_thread_class && offset == G_STRUCT_OFFSET (MonoInternalThread, current_appcontext))
951                 return TRUE;
952
953 #ifndef DISABLE_REMOTING
954         if (mono_defaults.real_proxy_class->supertypes && mono_class_has_parent_fast (o->vtable->klass, mono_defaults.real_proxy_class) &&
955                         offset == G_STRUCT_OFFSET (MonoRealProxy, unwrapped_server))
956                 return TRUE;
957 #endif
958         /* Thread.cached_culture_info */
959         if (!strcmp (ref->vtable->klass->name_space, "System.Globalization") &&
960                         !strcmp (ref->vtable->klass->name, "CultureInfo") &&
961                         !strcmp(o->vtable->klass->name_space, "System") &&
962                         !strcmp(o->vtable->klass->name, "Object[]"))
963                 return TRUE;
964         /*
965          *  at System.IO.MemoryStream.InternalConstructor (byte[],int,int,bool,bool) [0x0004d] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.IO/MemoryStream.cs:121
966          * at System.IO.MemoryStream..ctor (byte[]) [0x00017] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.IO/MemoryStream.cs:81
967          * at (wrapper remoting-invoke-with-check) System.IO.MemoryStream..ctor (byte[]) <IL 0x00020, 0xffffffff>
968          * at System.Runtime.Remoting.Messaging.CADMethodCallMessage.GetArguments () [0x0000d] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.Runtime.Remoting.Messaging/CADMessages.cs:327
969          * at System.Runtime.Remoting.Messaging.MethodCall..ctor (System.Runtime.Remoting.Messaging.CADMethodCallMessage) [0x00017] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.Runtime.Remoting.Messaging/MethodCall.cs:87
970          * at System.AppDomain.ProcessMessageInDomain (byte[],System.Runtime.Remoting.Messaging.CADMethodCallMessage,byte[]&,System.Runtime.Remoting.Messaging.CADMethodReturnMessage&) [0x00018] in /home/schani/Work/novell/trunk/mcs/class/corlib/System/AppDomain.cs:1213
971          * at (wrapper remoting-invoke-with-check) System.AppDomain.ProcessMessageInDomain (byte[],System.Runtime.Remoting.Messaging.CADMethodCallMessage,byte[]&,System.Runtime.Remoting.Messaging.CADMethodReturnMessage&) <IL 0x0003d, 0xffffffff>
972          * at System.Runtime.Remoting.Channels.CrossAppDomainSink.ProcessMessageInDomain (byte[],System.Runtime.Remoting.Messaging.CADMethodCallMessage) [0x00008] in /home/schani/Work/novell/trunk/mcs/class/corlib/System.Runtime.Remoting.Channels/CrossAppDomainChannel.cs:198
973          * at (wrapper runtime-invoke) object.runtime_invoke_CrossAppDomainSink/ProcessMessageRes_object_object (object,intptr,intptr,intptr) <IL 0x0004c, 0xffffffff>
974          */
975         if (!strcmp (ref->vtable->klass->name_space, "System") &&
976                         !strcmp (ref->vtable->klass->name, "Byte[]") &&
977                         !strcmp (o->vtable->klass->name_space, "System.IO") &&
978                         !strcmp (o->vtable->klass->name, "MemoryStream"))
979                 return TRUE;
980         return FALSE;
981 }
982
983 static void
984 check_reference_for_xdomain (GCObject **ptr, GCObject *obj, MonoDomain *domain)
985 {
986         MonoObject *ref = *ptr;
987         size_t offset = (char*)(ptr) - (char*)obj;
988         MonoClass *klass;
989         MonoClassField *field;
990         char *str;
991
992         if (!ref || ref->vtable->domain == domain)
993                 return;
994         if (is_xdomain_ref_allowed (ptr, obj, domain))
995                 return;
996
997         field = NULL;
998         for (klass = obj->vtable->klass; klass; klass = klass->parent) {
999                 int i;
1000
1001                 for (i = 0; i < klass->field.count; ++i) {
1002                         if (klass->fields[i].offset == offset) {
1003                                 field = &klass->fields[i];
1004                                 break;
1005                         }
1006                 }
1007                 if (field)
1008                         break;
1009         }
1010
1011         if (ref->vtable->klass == mono_defaults.string_class)
1012                 str = mono_string_to_utf8 ((MonoString*)ref);
1013         else
1014                 str = NULL;
1015         g_print ("xdomain reference in %p (%s.%s) at offset %d (%s) to %p (%s.%s) (%s)  -  pointed to by:\n",
1016                         obj, obj->vtable->klass->name_space, obj->vtable->klass->name,
1017                         offset, field ? field->name : "",
1018                         ref, ref->vtable->klass->name_space, ref->vtable->klass->name, str ? str : "");
1019         mono_gc_scan_for_specific_ref (obj, TRUE);
1020         if (str)
1021                 g_free (str);
1022 }
1023
1024 #undef HANDLE_PTR
1025 #define HANDLE_PTR(ptr,obj)     check_reference_for_xdomain ((ptr), (obj), domain)
1026
1027 static void
1028 scan_object_for_xdomain_refs (GCObject *obj, mword size, void *data)
1029 {
1030         char *start = (char*)obj;
1031         MonoVTable *vt = SGEN_LOAD_VTABLE (obj);
1032         MonoDomain *domain = vt->domain;
1033         SgenDescriptor desc = sgen_vtable_get_descriptor (vt);
1034
1035         #include "sgen-scan-object.h"
1036 }
1037
1038 void
1039 sgen_check_for_xdomain_refs (void)
1040 {
1041         LOSObject *bigobj;
1042
1043         sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
1044                         (IterateObjectCallbackFunc)scan_object_for_xdomain_refs, NULL, FALSE, TRUE);
1045
1046         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, (IterateObjectCallbackFunc)scan_object_for_xdomain_refs, NULL);
1047
1048         for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
1049                 scan_object_for_xdomain_refs ((GCObject*)bigobj->data, sgen_los_object_size (bigobj), NULL);
1050 }
1051
1052 #endif
1053
1054 /* If not null, dump the heap after each collection into this file */
1055 static FILE *heap_dump_file = NULL;
1056
1057 void
1058 sgen_dump_occupied (char *start, char *end, char *section_start)
1059 {
1060         fprintf (heap_dump_file, "<occupied offset=\"%zd\" size=\"%zd\"/>\n", start - section_start, end - start);
1061 }
1062
1063 void
1064 sgen_dump_section (GCMemSection *section, const char *type)
1065 {
1066         char *start = section->data;
1067         char *end = section->data + section->size;
1068         char *occ_start = NULL;
1069
1070         fprintf (heap_dump_file, "<section type=\"%s\" size=\"%lu\">\n", type, (unsigned long)section->size);
1071
1072         while (start < end) {
1073                 guint size;
1074                 //GCVTable vt;
1075                 //MonoClass *class;
1076
1077                 if (!*(void**)start) {
1078                         if (occ_start) {
1079                                 sgen_dump_occupied (occ_start, start, section->data);
1080                                 occ_start = NULL;
1081                         }
1082                         start += sizeof (void*); /* should be ALLOC_ALIGN, really */
1083                         continue;
1084                 }
1085                 g_assert (start < section->next_data);
1086
1087                 if (!occ_start)
1088                         occ_start = start;
1089
1090                 //vt = SGEN_LOAD_VTABLE (start);
1091                 //class = vt->klass;
1092
1093                 size = SGEN_ALIGN_UP (safe_object_get_size ((GCObject*) start));
1094
1095                 /*
1096                 fprintf (heap_dump_file, "<object offset=\"%d\" class=\"%s.%s\" size=\"%d\"/>\n",
1097                                 start - section->data,
1098                                 vt->klass->name_space, vt->klass->name,
1099                                 size);
1100                 */
1101
1102                 start += size;
1103         }
1104         if (occ_start)
1105                 sgen_dump_occupied (occ_start, start, section->data);
1106
1107         fprintf (heap_dump_file, "</section>\n");
1108 }
1109
1110 static void
1111 dump_object (GCObject *obj, gboolean dump_location)
1112 {
1113 #ifndef SGEN_WITHOUT_MONO
1114         static char class_name [1024];
1115
1116         MonoClass *klass = mono_object_class (obj);
1117         int i, j;
1118
1119         /*
1120          * Python's XML parser is too stupid to parse angle brackets
1121          * in strings, so we just ignore them;
1122          */
1123         i = j = 0;
1124         while (klass->name [i] && j < sizeof (class_name) - 1) {
1125                 if (!strchr ("<>\"", klass->name [i]))
1126                         class_name [j++] = klass->name [i];
1127                 ++i;
1128         }
1129         g_assert (j < sizeof (class_name));
1130         class_name [j] = 0;
1131
1132         fprintf (heap_dump_file, "<object class=\"%s.%s\" size=\"%zd\"",
1133                         klass->name_space, class_name,
1134                         safe_object_get_size (obj));
1135         if (dump_location) {
1136                 const char *location;
1137                 if (sgen_ptr_in_nursery (obj))
1138                         location = "nursery";
1139                 else if (safe_object_get_size (obj) <= SGEN_MAX_SMALL_OBJ_SIZE)
1140                         location = "major";
1141                 else
1142                         location = "LOS";
1143                 fprintf (heap_dump_file, " location=\"%s\"", location);
1144         }
1145         fprintf (heap_dump_file, "/>\n");
1146 #endif
1147 }
1148
1149 void
1150 sgen_debug_enable_heap_dump (const char *filename)
1151 {
1152         heap_dump_file = fopen (filename, "w");
1153         if (heap_dump_file) {
1154                 fprintf (heap_dump_file, "<sgen-dump>\n");
1155                 sgen_pin_stats_enable ();
1156         }
1157 }
1158
1159 void
1160 sgen_debug_dump_heap (const char *type, int num, const char *reason)
1161 {
1162         SgenPointerQueue *pinned_objects;
1163         LOSObject *bigobj;
1164         int i;
1165
1166         if (!heap_dump_file)
1167                 return;
1168
1169         fprintf (heap_dump_file, "<collection type=\"%s\" num=\"%d\"", type, num);
1170         if (reason)
1171                 fprintf (heap_dump_file, " reason=\"%s\"", reason);
1172         fprintf (heap_dump_file, ">\n");
1173 #ifndef SGEN_WITHOUT_MONO
1174         fprintf (heap_dump_file, "<other-mem-usage type=\"mempools\" size=\"%ld\"/>\n", mono_mempool_get_bytes_allocated ());
1175 #endif
1176         sgen_dump_internal_mem_usage (heap_dump_file);
1177         fprintf (heap_dump_file, "<pinned type=\"stack\" bytes=\"%zu\"/>\n", sgen_pin_stats_get_pinned_byte_count (PIN_TYPE_STACK));
1178         /* fprintf (heap_dump_file, "<pinned type=\"static-data\" bytes=\"%d\"/>\n", pinned_byte_counts [PIN_TYPE_STATIC_DATA]); */
1179         fprintf (heap_dump_file, "<pinned type=\"other\" bytes=\"%zu\"/>\n", sgen_pin_stats_get_pinned_byte_count (PIN_TYPE_OTHER));
1180
1181         fprintf (heap_dump_file, "<pinned-objects>\n");
1182         pinned_objects = sgen_pin_stats_get_object_list ();
1183         for (i = 0; i < pinned_objects->next_slot; ++i)
1184                 dump_object ((GCObject *)pinned_objects->data [i], TRUE);
1185         fprintf (heap_dump_file, "</pinned-objects>\n");
1186
1187         sgen_dump_section (nursery_section, "nursery");
1188
1189         major_collector.dump_heap (heap_dump_file);
1190
1191         fprintf (heap_dump_file, "<los>\n");
1192         for (bigobj = los_object_list; bigobj; bigobj = bigobj->next)
1193                 dump_object ((GCObject*)bigobj->data, FALSE);
1194         fprintf (heap_dump_file, "</los>\n");
1195
1196         fprintf (heap_dump_file, "</collection>\n");
1197 }
1198
1199 static GCObject *found_obj;
1200
1201 static void
1202 find_object_for_ptr_callback (GCObject *obj, size_t size, void *user_data)
1203 {
1204         char *ptr = (char *)user_data;
1205
1206         if (ptr >= (char*)obj && ptr < (char*)obj + size) {
1207                 g_assert (!found_obj);
1208                 found_obj = obj;
1209         }
1210 }
1211
1212 /* for use in the debugger */
1213 GCObject*
1214 sgen_find_object_for_ptr (char *ptr)
1215 {
1216         if (ptr >= nursery_section->data && ptr < nursery_section->end_data) {
1217                 found_obj = NULL;
1218                 sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
1219                                 find_object_for_ptr_callback, ptr, TRUE, FALSE);
1220                 if (found_obj)
1221                         return found_obj;
1222         }
1223
1224         found_obj = NULL;
1225         sgen_los_iterate_objects (find_object_for_ptr_callback, ptr);
1226         if (found_obj)
1227                 return found_obj;
1228
1229         /*
1230          * Very inefficient, but this is debugging code, supposed to
1231          * be called from gdb, so we don't care.
1232          */
1233         found_obj = NULL;
1234         major_collector.iterate_objects (ITERATE_OBJECTS_SWEEP_ALL, find_object_for_ptr_callback, ptr);
1235         return found_obj;
1236 }
1237
1238 #endif /*HAVE_SGEN_GC*/