BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mono / metadata / 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  *
12  * Permission is hereby granted, free of charge, to any person obtaining
13  * a copy of this software and associated documentation files (the
14  * "Software"), to deal in the Software without restriction, including
15  * without limitation the rights to use, copy, modify, merge, publish,
16  * distribute, sublicense, and/or sell copies of the Software, and to
17  * permit persons to whom the Software is furnished to do so, subject to
18  * the following conditions:
19  * 
20  * The above copyright notice and this permission notice shall be
21  * included in all copies or substantial portions of the Software.
22  * 
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30  */
31
32 #include "config.h"
33 #ifdef HAVE_SGEN_GC
34
35 #include "metadata/sgen-gc.h"
36 #include "metadata/sgen-cardtable.h"
37 #include "metadata/sgen-ssb.h"
38 #include "metadata/sgen-protocol.h"
39
40 #define LOAD_VTABLE     SGEN_LOAD_VTABLE
41
42 #define object_is_forwarded     SGEN_OBJECT_IS_FORWARDED
43 #define object_is_pinned        SGEN_OBJECT_IS_PINNED
44 #define safe_object_get_size    sgen_safe_object_get_size
45
46 void describe_ptr (char *ptr);
47 void check_object (char *start);
48
49 /*
50  * ######################################################################
51  * ########  Collector debugging
52  * ######################################################################
53  */
54
55 const char*descriptor_types [] = {
56         "run_length",
57         "small_bitmap",
58         "string",
59         "complex",
60         "vector",
61         "array",
62         "large_bitmap",
63         "complex_arr"
64 };
65
66 void
67 describe_ptr (char *ptr)
68 {
69         MonoVTable *vtable;
70         mword desc;
71         int type;
72         char *start;
73
74         if (sgen_ptr_in_nursery (ptr)) {
75                 printf ("Pointer inside nursery.\n");
76         } else {
77                 if (sgen_ptr_is_in_los (ptr, &start)) {
78                         if (ptr == start)
79                                 printf ("Pointer is the start of object %p in LOS space.\n", start);
80                         else
81                                 printf ("Pointer is at offset 0x%x of object %p in LOS space.\n", (int)(ptr - start), start);
82                         ptr = start;
83                 } else if (major_collector.ptr_is_in_non_pinned_space (ptr)) {
84                         printf ("Pointer inside oldspace.\n");
85                 } else if (major_collector.obj_is_from_pinned_alloc (ptr)) {
86                         printf ("Pointer is inside a pinned chunk.\n");
87                 } else {
88                         printf ("Pointer unknown.\n");
89                         return;
90                 }
91         }
92
93         if (object_is_pinned (ptr))
94                 printf ("Object is pinned.\n");
95
96         if (object_is_forwarded (ptr))
97                 printf ("Object is forwared.\n");
98
99         // FIXME: Handle pointers to the inside of objects
100         vtable = (MonoVTable*)LOAD_VTABLE (ptr);
101
102         printf ("VTable: %p\n", vtable);
103         if (vtable == NULL) {
104                 printf ("VTable is invalid (empty).\n");
105                 return;
106         }
107         if (sgen_ptr_in_nursery (vtable)) {
108                 printf ("VTable is invalid (points inside nursery).\n");
109                 return;
110         }
111         printf ("Class: %s\n", vtable->klass->name);
112
113         desc = ((GCVTable*)vtable)->desc;
114         printf ("Descriptor: %lx\n", (long)desc);
115
116         type = desc & 0x7;
117         printf ("Descriptor type: %d (%s)\n", type, descriptor_types [type]);
118 }
119
120 static gboolean missing_remsets;
121
122 /*
123  * We let a missing remset slide if the target object is pinned,
124  * because the store might have happened but the remset not yet added,
125  * but in that case the target must be pinned.  We might theoretically
126  * miss some missing remsets this way, but it's very unlikely.
127  */
128 #undef HANDLE_PTR
129 #define HANDLE_PTR(ptr,obj)     do {    \
130         if (*(ptr) && sgen_ptr_in_nursery ((char*)*(ptr))) { \
131                 if (!sgen_get_remset ()->find_address ((char*)(ptr))) { \
132                         fprintf (gc_debug_file, "Oldspace->newspace reference %p at offset %td 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); \
133                         binary_protocol_missing_remset ((obj), (gpointer)LOAD_VTABLE ((obj)), (char*)(ptr) - (char*)(obj), *(ptr), (gpointer)LOAD_VTABLE(*(ptr)), object_is_pinned (*(ptr))); \
134                         if (!object_is_pinned (*(ptr)))                                                         \
135                                 missing_remsets = TRUE;                                                                 \
136                 }                                                                                                                               \
137         }                                                                                                                                       \
138         } while (0)
139
140 /*
141  * Check that each object reference which points into the nursery can
142  * be found in the remembered sets.
143  */
144 static void
145 check_consistency_callback (char *start, size_t size, void *dummy)
146 {
147         GCVTable *vt = (GCVTable*)LOAD_VTABLE (start);
148         DEBUG (8, fprintf (gc_debug_file, "Scanning object %p, vtable: %p (%s)\n", start, vt, vt->klass->name));
149
150 #define SCAN_OBJECT_ACTION
151 #include "sgen-scan-object.h"
152 }
153
154 /*
155  * Perform consistency check of the heap.
156  *
157  * Assumes the world is stopped.
158  */
159 void
160 sgen_check_consistency (void)
161 {
162         // Need to add more checks
163
164         missing_remsets = FALSE;
165
166         DEBUG (1, fprintf (gc_debug_file, "Begin heap consistency check...\n"));
167
168         // Check that oldspace->newspace pointers are registered with the collector
169         major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)check_consistency_callback, NULL);
170
171         sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_consistency_callback, NULL);
172
173         DEBUG (1, fprintf (gc_debug_file, "Heap consistency check done.\n"));
174
175         if (!binary_protocol_is_enabled ())
176                 g_assert (!missing_remsets);
177 }
178
179
180 #undef HANDLE_PTR
181 #define HANDLE_PTR(ptr,obj)     do {                                    \
182                 if (*(ptr) && !LOAD_VTABLE (*(ptr)))                                            \
183                         g_error ("Could not load vtable for obj %p slot %d (size %d)", obj, (char*)ptr - (char*)obj, safe_object_get_size ((MonoObject*)obj));          \
184         } while (0)
185
186 static void
187 check_major_refs_callback (char *start, size_t size, void *dummy)
188 {
189 #define SCAN_OBJECT_ACTION
190 #include "sgen-scan-object.h"
191 }
192
193 void
194 sgen_check_major_refs (void)
195 {
196         major_collector.iterate_objects (TRUE, TRUE, (IterateObjectCallbackFunc)check_major_refs_callback, NULL);
197         sgen_los_iterate_objects ((IterateObjectCallbackFunc)check_major_refs_callback, NULL);
198 }
199
200 /* Check that the reference is valid */
201 #undef HANDLE_PTR
202 #define HANDLE_PTR(ptr,obj)     do {    \
203                 if (*(ptr)) {   \
204                         g_assert (sgen_safe_name (*(ptr)) != NULL);     \
205                 }       \
206         } while (0)
207
208 /*
209  * check_object:
210  *
211  *   Perform consistency check on an object. Currently we only check that the
212  * reference fields are valid.
213  */
214 void
215 check_object (char *start)
216 {
217         if (!start)
218                 return;
219
220 #include "sgen-scan-object.h"
221 }
222
223 #endif /*HAVE_SGEN_GC*/