2 * debug-mono-ppdb.c: Support for the portable PDB symbol
7 * Mono Project (http://www.mono-project.com)
9 * Copyright 2015 Xamarin Inc (http://www.xamarin.com)
17 #include <mono/metadata/metadata.h>
18 #include <mono/metadata/tabledefs.h>
19 #include <mono/metadata/tokentype.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/mono-debug.h>
22 #include <mono/metadata/debug-mono-symfile.h>
23 #include <mono/metadata/mono-debug-debugger.h>
24 #include <mono/metadata/mono-endian.h>
25 #include <mono/metadata/metadata-internals.h>
26 #include <mono/metadata/class-internals.h>
28 #include "debug-mono-ppdb.h"
30 struct _MonoPPDBFile {
32 GHashTable *doc_cache;
36 mono_ppdb_load_file (MonoImage *image)
38 MonoImage *ppdb_image;
40 char *s, *ppdb_filename;
41 MonoImageOpenStatus status;
42 MonoTableInfo *tables;
43 guint32 cols [MONO_MODULE_SIZE];
44 const char *guid, *ppdb_guid;
47 /* ppdb files drop the .exe/.dll extension */
48 filename = mono_image_get_filename (image);
49 if (strlen (filename) > 4 && (!strcmp (filename + strlen (filename) - 4, ".exe"))) {
50 s = g_strdup (filename);
51 s [strlen (filename) - 4] = '\0';
52 ppdb_filename = g_strdup_printf ("%s.pdb", s);
55 ppdb_filename = g_strdup_printf ("%s.pdb", filename);
58 ppdb_image = mono_image_open_metadata_only (ppdb_filename, &status);
62 /* Check that the images match */
63 tables = image->tables;
64 g_assert (tables [MONO_TABLE_MODULE].rows);
65 mono_metadata_decode_row (&tables [MONO_TABLE_MODULE], 0, cols, MONO_MODULE_SIZE);
66 guid = mono_metadata_guid_heap (image, cols [MONO_MODULE_MVID]);
68 tables = ppdb_image->tables;
69 g_assert (tables [MONO_TABLE_MODULE].rows);
70 mono_metadata_decode_row (&tables [MONO_TABLE_MODULE], 0, cols, MONO_MODULE_SIZE);
71 ppdb_guid = mono_metadata_guid_heap (ppdb_image, cols [MONO_MODULE_MVID]);
73 if (memcmp (guid, ppdb_guid, 16) != 0) {
74 g_warning ("Symbol file %s doesn't match image %s", ppdb_image->name,
76 mono_image_close (ppdb_image);
80 ppdb = g_new0 (MonoPPDBFile, 1);
81 ppdb->image = ppdb_image;
87 mono_ppdb_close (MonoDebugHandle *handle)
89 MonoPPDBFile *ppdb = handle->ppdb;
91 mono_image_close (ppdb->image);
93 g_hash_table_destroy (ppdb->doc_cache);
98 mono_ppdb_lookup_method (MonoDebugHandle *handle, MonoMethod *method)
100 MonoDebugMethodInfo *minfo;
102 if (handle->image != mono_class_get_image (mono_method_get_class (method)))
107 // FIXME: Methods without tokens
109 minfo = g_new0 (MonoDebugMethodInfo, 1);
111 minfo->method = method;
112 minfo->handle = handle;
117 static MonoDebugSourceInfo*
118 get_docinfo (MonoPPDBFile *ppdb, MonoImage *image, int docidx)
120 MonoTableInfo *tables = image->tables;
121 guint32 cols [MONO_DOCUMENT_SIZE];
124 const char *part_ptr;
125 int size, part_size, partidx, nparts;
128 MonoDebugSourceInfo *res;
132 mono_metadata_decode_row (&tables [MONO_TABLE_DOCUMENT], docidx-1, cols, MONO_DOCUMENT_SIZE);
134 ptr = mono_metadata_blob_heap (image, cols [MONO_DOCUMENT_NAME]);
135 size = mono_metadata_decode_blob_size (ptr, &ptr);
142 s = g_string_new ("");
145 while (ptr < start + size) {
146 partidx = mono_metadata_decode_value (ptr, &ptr);
148 g_string_append_c (s, sep);
150 part_ptr = mono_metadata_blob_heap (image, partidx);
151 part_size = mono_metadata_decode_blob_size (part_ptr, &part_ptr);
154 g_string_append_len (s, part_ptr, part_size);
159 res = g_new0 (MonoDebugSourceInfo, 1);
160 res->source_file = g_string_free (s, FALSE);
162 res->hash = (guint8*)mono_metadata_blob_heap (image, cols [MONO_DOCUMENT_HASH]);
168 get_docname (MonoPPDBFile *ppdb, MonoImage *image, int docidx)
170 MonoDebugSourceInfo *info;
172 info = get_docinfo (ppdb, image, docidx);
173 return g_strdup (info->source_file);
177 * mono_ppdb_lookup_location:
178 * @minfo: A `MonoDebugMethodInfo' which can be retrieved by
179 * mono_debug_lookup_method().
180 * @offset: IL offset within the corresponding method's CIL code.
182 * This function is similar to mono_debug_lookup_location(), but we
183 * already looked up the method and also already did the
184 * `native address -> IL offset' mapping.
186 MonoDebugSourceLocation *
187 mono_ppdb_lookup_location (MonoDebugMethodInfo *minfo, uint32_t offset)
189 MonoPPDBFile *ppdb = minfo->handle->ppdb;
190 MonoImage *image = ppdb->image;
191 MonoMethod *method = minfo->method;
192 MonoTableInfo *tables = image->tables;
193 guint32 cols [MONO_METHODBODY_SIZE];
197 int idx, size, docidx, iloffset, delta_il, delta_lines, delta_cols, start_line, start_col, adv_line, adv_col;
198 MonoDebugSourceLocation *location;
200 g_assert (method->token);
202 idx = mono_metadata_token_index (method->token);
204 mono_metadata_decode_row (&tables [MONO_TABLE_METHODBODY], idx-1, cols, MONO_METHODBODY_SIZE);
207 g_assert (cols [MONO_METHODBODY_SEQ_POINTS]);
209 ptr = mono_metadata_blob_heap (image, cols [MONO_METHODBODY_SEQ_POINTS]);
210 size = mono_metadata_decode_blob_size (ptr, &ptr);
214 docidx = mono_metadata_decode_value (ptr, &ptr);
215 docname = get_docname (ppdb, image, docidx);
216 iloffset = mono_metadata_decode_value (ptr, &ptr);
217 delta_lines = mono_metadata_decode_value (ptr, &ptr);
218 if (delta_lines == 0)
219 delta_cols = mono_metadata_decode_value (ptr, &ptr);
221 delta_cols = mono_metadata_decode_signed_value (ptr, &ptr);
222 start_line = mono_metadata_decode_value (ptr, &ptr);
223 start_col = mono_metadata_decode_value (ptr, &ptr);
226 if (iloffset > offset)
229 delta_il = mono_metadata_decode_value (ptr, &ptr);
232 g_assert_not_reached ();
234 delta_lines = mono_metadata_decode_value (ptr, &ptr);
235 if (delta_lines == 0)
236 delta_cols = mono_metadata_decode_value (ptr, &ptr);
238 delta_cols = mono_metadata_decode_signed_value (ptr, &ptr);
239 if (delta_lines == 0 && delta_cols == 0)
241 g_assert_not_reached ();
242 adv_line = mono_metadata_decode_signed_value (ptr, &ptr);
243 adv_col = mono_metadata_decode_signed_value (ptr, &ptr);
245 if (iloffset + delta_il > offset)
248 iloffset += delta_il;
249 start_line += adv_line;
250 start_col += adv_col;
253 location = g_new0 (MonoDebugSourceLocation, 1);
254 location->source_file = docname;
255 location->row = start_line;
256 location->il_offset = iloffset;
262 mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points)
264 MonoPPDBFile *ppdb = minfo->handle->ppdb;
265 MonoImage *image = ppdb->image;
266 MonoMethod *method = minfo->method;
267 MonoTableInfo *tables = image->tables;
268 guint32 cols [MONO_METHODBODY_SIZE];
271 MonoDebugSourceInfo *docinfo;
272 int i, method_idx, size, docidx, iloffset, delta_il, delta_lines, delta_cols, start_line, start_col, adv_line, adv_col;
275 GPtrArray *sfiles = NULL;
276 GPtrArray *sindexes = NULL;
280 if (source_file_list)
281 *source_file_list = NULL;
283 *source_files = NULL;
289 if (source_file_list)
290 *source_file_list = sfiles = g_ptr_array_new ();
292 sindexes = g_ptr_array_new ();
297 method_idx = mono_metadata_token_index (method->token);
299 mono_metadata_decode_row (&tables [MONO_TABLE_METHODBODY], method_idx-1, cols, MONO_METHODBODY_SIZE);
301 if (!cols [MONO_METHODBODY_SEQ_POINTS])
304 ptr = mono_metadata_blob_heap (image, cols [MONO_METHODBODY_SEQ_POINTS]);
305 size = mono_metadata_decode_blob_size (ptr, &ptr);
308 sps = g_array_new (FALSE, TRUE, sizeof (MonoSymSeqPoint));
311 docidx = mono_metadata_decode_value (ptr, &ptr);
312 docinfo = get_docinfo (ppdb, image, docidx);
313 iloffset = mono_metadata_decode_value (ptr, &ptr);
314 delta_lines = mono_metadata_decode_value (ptr, &ptr);
315 if (delta_lines == 0)
316 delta_cols = mono_metadata_decode_value (ptr, &ptr);
318 delta_cols = mono_metadata_decode_signed_value (ptr, &ptr);
319 start_line = mono_metadata_decode_value (ptr, &ptr);
320 start_col = mono_metadata_decode_value (ptr, &ptr);
323 g_ptr_array_add (sfiles, docinfo);
325 g_ptr_array_add (sindexes, GUINT_TO_POINTER (sfiles->len - 1));
327 memset (&sp, 0, sizeof (sp));
328 sp.il_offset = iloffset;
329 sp.line = start_line;
330 sp.column = start_col;
331 sp.end_line = start_line + delta_lines;
332 sp.end_column = start_col + delta_cols;
334 g_array_append_val (sps, sp);
337 delta_il = mono_metadata_decode_value (ptr, &ptr);
339 /* subsequent-document-record */
340 docidx = mono_metadata_decode_value (ptr, &ptr);
341 docinfo = get_docinfo (ppdb, image, docidx);
343 g_ptr_array_add (sfiles, docinfo);
346 delta_lines = mono_metadata_decode_value (ptr, &ptr);
347 if (delta_lines == 0)
348 delta_cols = mono_metadata_decode_value (ptr, &ptr);
350 delta_cols = mono_metadata_decode_signed_value (ptr, &ptr);
352 if (delta_lines == 0 && delta_cols == 0) {
353 /* Hidden sequence point */
354 // FIXME: This seems to be followed by garbage
358 adv_line = mono_metadata_decode_signed_value (ptr, &ptr);
359 adv_col = mono_metadata_decode_signed_value (ptr, &ptr);
361 iloffset += delta_il;
362 start_line += adv_line;
363 start_col += adv_col;
365 memset (&sp, 0, sizeof (sp));
366 sp.il_offset = iloffset;
367 sp.line = start_line;
368 sp.column = start_col;
369 sp.end_line = start_line + delta_lines;
370 sp.end_column = start_col + delta_cols;
372 g_array_append_val (sps, sp);
374 g_ptr_array_add (sindexes, GUINT_TO_POINTER (sfiles->len - 1));
378 *n_seq_points = sps->len;
379 g_assert (seq_points);
380 *seq_points = g_new (MonoSymSeqPoint, sps->len);
381 memcpy (*seq_points, sps->data, sps->len * sizeof (MonoSymSeqPoint));
385 *source_file = g_strdup (((MonoDebugSourceInfo*)g_ptr_array_index (sfiles, 0))->source_file);
387 *source_files = g_new (int, sps->len);
388 for (i = 0; i < sps->len; ++i)
389 (*source_files)[i] = GPOINTER_TO_INT (g_ptr_array_index (sindexes, i));
390 g_ptr_array_free (sindexes, TRUE);
393 g_array_free (sps, TRUE);
397 mono_ppdb_lookup_locals (MonoDebugMethodInfo *minfo)
399 MonoPPDBFile *ppdb = minfo->handle->ppdb;
400 MonoImage *image = ppdb->image;
401 MonoTableInfo *tables = image->tables;
402 MonoMethod *method = minfo->method;
403 guint32 cols [MONO_LOCALSCOPE_SIZE];
404 guint32 locals_cols [MONO_LOCALVARIABLE_SIZE];
405 int i, lindex, sindex, method_idx, start_scope_idx, scope_idx, locals_idx, locals_end_idx, nscopes;
406 MonoDebugLocalsInfo *res;
407 MonoMethodSignature *sig;
412 sig = mono_method_signature (method);
416 method_idx = mono_metadata_token_index (method->token);
418 start_scope_idx = mono_metadata_localscope_from_methoddef (image, method_idx);
420 if (!start_scope_idx)
423 /* Compute number of locals and scopes */
424 scope_idx = start_scope_idx;
425 mono_metadata_decode_row (&tables [MONO_TABLE_LOCALSCOPE], scope_idx-1, cols, MONO_LOCALSCOPE_SIZE);
426 locals_idx = cols [MONO_LOCALSCOPE_VARIABLELIST];
428 mono_metadata_decode_row (&tables [MONO_TABLE_LOCALSCOPE], scope_idx-1, cols, MONO_LOCALSCOPE_SIZE);
429 if (cols [MONO_LOCALSCOPE_METHOD] != method_idx)
433 nscopes = scope_idx - start_scope_idx;
434 if (scope_idx == tables [MONO_TABLE_LOCALSCOPE].rows) {
436 g_assert_not_reached ();
439 locals_end_idx = cols [MONO_LOCALSCOPE_VARIABLELIST];
442 res = g_new0 (MonoDebugLocalsInfo, 1);
443 res->num_blocks = nscopes;
444 res->code_blocks = g_new0 (MonoDebugCodeBlock, res->num_blocks);
445 res->num_locals = locals_end_idx - locals_idx;
446 res->locals = g_new0 (MonoDebugLocalVar, res->num_locals);
449 for (sindex = 0; sindex < nscopes; ++sindex) {
450 scope_idx = start_scope_idx + sindex;
451 mono_metadata_decode_row (&tables [MONO_TABLE_LOCALSCOPE], scope_idx-1, cols, MONO_LOCALSCOPE_SIZE);
453 locals_idx = cols [MONO_LOCALSCOPE_VARIABLELIST];
454 if (scope_idx == tables [MONO_TABLE_LOCALSCOPE].rows) {
456 g_assert_not_reached ();
458 locals_end_idx = mono_metadata_decode_row_col (&tables [MONO_TABLE_LOCALSCOPE], scope_idx-1 + 1, MONO_LOCALSCOPE_VARIABLELIST);
461 res->code_blocks [sindex].start_offset = cols [MONO_LOCALSCOPE_STARTOFFSET];
462 res->code_blocks [sindex].end_offset = cols [MONO_LOCALSCOPE_STARTOFFSET] + cols [MONO_LOCALSCOPE_LENGTH];
464 //printf ("Scope: %s %d %d %d-%d\n", mono_method_full_name (method, 1), cols [MONO_LOCALSCOPE_STARTOFFSET], cols [MONO_LOCALSCOPE_LENGTH], locals_idx, locals_end_idx);
466 for (i = locals_idx; i < locals_end_idx; ++i) {
467 mono_metadata_decode_row (&tables [MONO_TABLE_LOCALVARIABLE], i - 1, locals_cols, MONO_LOCALVARIABLE_SIZE);
469 res->locals [lindex].name = g_strdup (mono_metadata_string_heap (image, locals_cols [MONO_LOCALVARIABLE_NAME]));
470 res->locals [lindex].index = locals_cols [MONO_LOCALVARIABLE_INDEX];
471 res->locals [lindex].block = &res->code_blocks [sindex];
474 //printf ("\t %s %d\n", mono_metadata_string_heap (image, locals_cols [MONO_LOCALVARIABLE_NAME]), locals_cols [MONO_LOCALVARIABLE_INDEX]);