3 * Support for the portable PDB symbol
8 * Mono Project (http://www.mono-project.com)
10 * Copyright 2015 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include <mono/metadata/metadata.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/debug-helpers.h>
23 #include <mono/metadata/mono-debug.h>
24 #include <mono/metadata/debug-internals.h>
25 #include <mono/metadata/mono-endian.h>
26 #include <mono/metadata/metadata-internals.h>
27 #include <mono/metadata/class-internals.h>
28 #include <mono/metadata/cil-coff.h>
29 #include <mono/utils/bsearch.h>
30 #include <mono/utils/mono-logger-internals.h>
32 #include "debug-mono-ppdb.h"
34 struct _MonoPPDBFile
{
37 GHashTable
*method_hash
;
40 /* IMAGE_DEBUG_DIRECTORY structure */
43 gint32 characteristics
;
44 gint32 time_date_stamp
;
51 } ImageDebugDirectory
;
57 } CodeviewDebugDirectory
;
62 guint64 referenced_tables
;
66 MONO_HAS_CUSTOM_DEBUG_METHODDEF
= 0,
67 MONO_HAS_CUSTOM_DEBUG_MODULE
= 7,
68 MONO_HAS_CUSTOM_DEBUG_BITS
= 5,
69 MONO_HAS_CUSTOM_DEBUG_MASK
= 0x1f
73 get_pe_debug_guid (MonoImage
*image
, guint8
*out_guid
, gint32
*out_age
, gint32
*out_timestamp
)
75 MonoPEDirEntry
*debug_dir_entry
;
76 ImageDebugDirectory
*debug_dir
;
78 debug_dir_entry
= &image
->image_info
->cli_header
.datadir
.pe_debug
;
79 if (!debug_dir_entry
->size
)
82 int offset
= mono_cli_rva_image_map (image
, debug_dir_entry
->rva
);
83 debug_dir
= (ImageDebugDirectory
*)(m_image_get_raw_data (image
) + offset
);
84 if (debug_dir
->type
== 2 && debug_dir
->major_version
== 0x100 && debug_dir
->minor_version
== 0x504d) {
85 /* This is a 'CODEVIEW' debug directory */
86 CodeviewDebugDirectory
*dir
= (CodeviewDebugDirectory
*)(m_image_get_raw_data (image
) + debug_dir
->pointer
);
88 if (dir
->signature
== 0x53445352) {
89 memcpy (out_guid
, dir
->guid
, 16);
91 *out_timestamp
= debug_dir
->time_date_stamp
;
99 doc_free (gpointer key
)
101 MonoDebugSourceInfo
*info
= (MonoDebugSourceInfo
*)key
;
103 g_free (info
->source_file
);
108 create_ppdb_file (MonoImage
*ppdb_image
)
112 ppdb
= g_new0 (MonoPPDBFile
, 1);
113 ppdb
->image
= ppdb_image
;
114 ppdb
->doc_hash
= g_hash_table_new_full (NULL
, NULL
, NULL
, (GDestroyNotify
) doc_free
);
115 ppdb
->method_hash
= g_hash_table_new_full (NULL
, NULL
, NULL
, (GDestroyNotify
) g_free
);
120 mono_ppdb_load_file (MonoImage
*image
, const guint8
*raw_contents
, int size
)
122 MonoImage
*ppdb_image
= NULL
;
123 const char *filename
;
124 char *s
, *ppdb_filename
;
125 MonoImageOpenStatus status
;
130 if (image
->tables
[MONO_TABLE_DOCUMENT
].rows
) {
132 mono_image_addref (image
);
133 return create_ppdb_file (image
);
136 if (!get_pe_debug_guid (image
, pe_guid
, &pe_age
, &pe_timestamp
)) {
137 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Image '%s' has no debug directory.", image
->name
);
142 if (size
> 4 && strncmp ((char*)raw_contents
, "BSJB", 4) == 0)
143 ppdb_image
= mono_image_open_from_data_internal ((char*)raw_contents
, size
, TRUE
, &status
, FALSE
, TRUE
, NULL
);
145 /* ppdb files drop the .exe/.dll extension */
146 filename
= mono_image_get_filename (image
);
147 if (strlen (filename
) > 4 && (!strcmp (filename
+ strlen (filename
) - 4, ".exe") || !strcmp (filename
+ strlen (filename
) - 4, ".dll"))) {
148 s
= g_strdup (filename
);
149 s
[strlen (filename
) - 4] = '\0';
150 ppdb_filename
= g_strdup_printf ("%s.pdb", s
);
153 ppdb_filename
= g_strdup_printf ("%s.pdb", filename
);
156 ppdb_image
= mono_image_open_metadata_only (ppdb_filename
, &status
);
158 g_free (ppdb_filename
);
164 * Check that the images match.
165 * The same id is stored in the Debug Directory of the PE file, and in the
166 * #Pdb stream in the ppdb file.
168 PdbStreamHeader
*pdb_stream
= (PdbStreamHeader
*)ppdb_image
->heap_pdb
.data
;
170 g_assert (pdb_stream
);
172 /* The pdb id is a concentation of the pe guid and the timestamp */
173 if (memcmp (pe_guid
, pdb_stream
->guid
, 16) != 0 || memcmp (&pe_timestamp
, pdb_stream
->guid
+ 16, 4) != 0) {
174 g_warning ("Symbol file %s doesn't match image %s", ppdb_image
->name
,
176 mono_image_close (ppdb_image
);
180 return create_ppdb_file (ppdb_image
);
184 mono_ppdb_close (MonoDebugHandle
*handle
)
186 MonoPPDBFile
*ppdb
= handle
->ppdb
;
188 mono_image_close (ppdb
->image
);
189 g_hash_table_destroy (ppdb
->doc_hash
);
190 g_hash_table_destroy (ppdb
->method_hash
);
194 MonoDebugMethodInfo
*
195 mono_ppdb_lookup_method (MonoDebugHandle
*handle
, MonoMethod
*method
)
197 MonoDebugMethodInfo
*minfo
;
198 MonoPPDBFile
*ppdb
= handle
->ppdb
;
200 if (handle
->image
!= mono_class_get_image (mono_method_get_class (method
)))
203 mono_debugger_lock ();
205 minfo
= (MonoDebugMethodInfo
*)g_hash_table_lookup (ppdb
->method_hash
, method
);
207 mono_debugger_unlock ();
211 minfo
= g_new0 (MonoDebugMethodInfo
, 1);
213 minfo
->method
= method
;
214 minfo
->handle
= handle
;
216 g_hash_table_insert (ppdb
->method_hash
, method
, minfo
);
218 mono_debugger_unlock ();
223 static MonoDebugSourceInfo
*
224 get_docinfo (MonoPPDBFile
*ppdb
, MonoImage
*image
, int docidx
)
226 MonoTableInfo
*tables
= image
->tables
;
227 guint32 cols
[MONO_DOCUMENT_SIZE
];
230 const char *part_ptr
;
231 int size
, part_size
, partidx
, nparts
;
234 MonoDebugSourceInfo
*res
, *cached
;
236 mono_debugger_lock ();
237 cached
= (MonoDebugSourceInfo
*)g_hash_table_lookup (ppdb
->doc_hash
, GUINT_TO_POINTER (docidx
));
238 mono_debugger_unlock ();
242 mono_metadata_decode_row (&tables
[MONO_TABLE_DOCUMENT
], docidx
-1, cols
, MONO_DOCUMENT_SIZE
);
244 ptr
= mono_metadata_blob_heap (image
, cols
[MONO_DOCUMENT_NAME
]);
245 size
= mono_metadata_decode_blob_size (ptr
, &ptr
);
252 s
= g_string_new ("");
255 while (ptr
< start
+ size
) {
256 partidx
= mono_metadata_decode_value (ptr
, &ptr
);
258 g_string_append_c (s
, sep
);
260 part_ptr
= mono_metadata_blob_heap (image
, partidx
);
261 part_size
= mono_metadata_decode_blob_size (part_ptr
, &part_ptr
);
264 g_string_append_len (s
, part_ptr
, part_size
);
269 res
= g_new0 (MonoDebugSourceInfo
, 1);
270 res
->source_file
= g_string_free (s
, FALSE
);
272 res
->hash
= (guint8
*)mono_metadata_blob_heap (image
, cols
[MONO_DOCUMENT_HASH
]);
274 mono_debugger_lock ();
275 cached
= (MonoDebugSourceInfo
*)g_hash_table_lookup (ppdb
->doc_hash
, GUINT_TO_POINTER (docidx
));
277 g_hash_table_insert (ppdb
->doc_hash
, GUINT_TO_POINTER (docidx
), res
);
282 mono_debugger_unlock ();
287 get_docname (MonoPPDBFile
*ppdb
, MonoImage
*image
, int docidx
)
289 MonoDebugSourceInfo
*info
;
291 info
= get_docinfo (ppdb
, image
, docidx
);
292 return g_strdup (info
->source_file
);
296 * mono_ppdb_lookup_location:
297 * \param minfo A \c MonoDebugMethodInfo which can be retrieved by mono_debug_lookup_method().
298 * \param offset IL offset within the corresponding method's CIL code.
300 * This function is similar to mono_debug_lookup_location(), but we
301 * already looked up the method and also already did the
302 * native address -> IL offset mapping.
304 MonoDebugSourceLocation
*
305 mono_ppdb_lookup_location (MonoDebugMethodInfo
*minfo
, uint32_t offset
)
307 MonoPPDBFile
*ppdb
= minfo
->handle
->ppdb
;
308 MonoImage
*image
= ppdb
->image
;
309 MonoMethod
*method
= minfo
->method
;
310 MonoTableInfo
*tables
= image
->tables
;
311 guint32 cols
[MONO_METHODBODY_SIZE
];
315 int idx
, size
, docidx
, iloffset
, delta_il
, delta_lines
, delta_cols
, start_line
, start_col
, adv_line
, adv_col
;
316 gboolean first
= TRUE
, first_non_hidden
= TRUE
;
317 MonoDebugSourceLocation
*location
;
322 idx
= mono_metadata_token_index (method
->token
);
324 mono_metadata_decode_row (&tables
[MONO_TABLE_METHODBODY
], idx
-1, cols
, MONO_METHODBODY_SIZE
);
326 docidx
= cols
[MONO_METHODBODY_DOCUMENT
];
328 if (!cols
[MONO_METHODBODY_SEQ_POINTS
])
330 ptr
= mono_metadata_blob_heap (image
, cols
[MONO_METHODBODY_SEQ_POINTS
]);
331 size
= mono_metadata_decode_blob_size (ptr
, &ptr
);
336 mono_metadata_decode_value (ptr
, &ptr
);
338 docidx
= mono_metadata_decode_value (ptr
, &ptr
);
339 docname
= get_docname (ppdb
, image
, docidx
);
345 delta_il
= mono_metadata_decode_value (ptr
, &ptr
);
346 if (!first
&& delta_il
== 0) {
347 /* document-record */
348 docidx
= mono_metadata_decode_value (ptr
, &ptr
);
349 docname
= get_docname (ppdb
, image
, docidx
);
352 if (!first
&& iloffset
+ delta_il
> offset
)
354 iloffset
+= delta_il
;
357 delta_lines
= mono_metadata_decode_value (ptr
, &ptr
);
358 if (delta_lines
== 0)
359 delta_cols
= mono_metadata_decode_value (ptr
, &ptr
);
361 delta_cols
= mono_metadata_decode_signed_value (ptr
, &ptr
);
362 if (delta_lines
== 0 && delta_cols
== 0)
363 /* hidden-sequence-point-record */
365 if (first_non_hidden
) {
366 start_line
= mono_metadata_decode_value (ptr
, &ptr
);
367 start_col
= mono_metadata_decode_value (ptr
, &ptr
);
369 adv_line
= mono_metadata_decode_signed_value (ptr
, &ptr
);
370 adv_col
= mono_metadata_decode_signed_value (ptr
, &ptr
);
371 start_line
+= adv_line
;
372 start_col
+= adv_col
;
374 first_non_hidden
= FALSE
;
377 location
= g_new0 (MonoDebugSourceLocation
, 1);
378 location
->source_file
= docname
;
379 location
->row
= start_line
;
380 location
->column
= start_col
;
381 location
->il_offset
= iloffset
;
387 mono_ppdb_get_image (MonoPPDBFile
*ppdb
)
393 mono_ppdb_get_seq_points (MonoDebugMethodInfo
*minfo
, char **source_file
, GPtrArray
**source_file_list
, int **source_files
, MonoSymSeqPoint
**seq_points
, int *n_seq_points
)
395 MonoPPDBFile
*ppdb
= minfo
->handle
->ppdb
;
396 MonoImage
*image
= ppdb
->image
;
397 MonoMethod
*method
= minfo
->method
;
398 MonoTableInfo
*tables
= image
->tables
;
399 guint32 cols
[MONO_METHODBODY_SIZE
];
402 MonoDebugSourceInfo
*docinfo
;
403 int i
, method_idx
, size
, docidx
, iloffset
, delta_il
, delta_lines
, delta_cols
, start_line
, start_col
, adv_line
, adv_col
;
404 gboolean first
= TRUE
, first_non_hidden
= TRUE
;
407 GPtrArray
*sfiles
= NULL
;
408 GPtrArray
*sindexes
= NULL
;
412 if (source_file_list
)
413 *source_file_list
= NULL
;
415 *source_files
= NULL
;
421 if (source_file_list
)
422 *source_file_list
= sfiles
= g_ptr_array_new ();
424 sindexes
= g_ptr_array_new ();
429 method_idx
= mono_metadata_token_index (method
->token
);
431 MonoTableInfo
*methodbody_table
= &tables
[MONO_TABLE_METHODBODY
];
432 if (G_UNLIKELY (method_idx
- 1 >= methodbody_table
->rows
)) {
433 char *method_name
= mono_method_full_name (method
, FALSE
);
434 g_error ("Method idx %d is greater than number of rows (%d) in PPDB MethodDebugInformation table, for method %s in '%s'. Likely a malformed PDB file.",
435 method_idx
- 1, methodbody_table
->rows
, method_name
, image
->name
);
436 g_free (method_name
);
438 mono_metadata_decode_row (methodbody_table
, method_idx
- 1, cols
, MONO_METHODBODY_SIZE
);
440 docidx
= cols
[MONO_METHODBODY_DOCUMENT
];
442 if (!cols
[MONO_METHODBODY_SEQ_POINTS
])
445 ptr
= mono_metadata_blob_heap (image
, cols
[MONO_METHODBODY_SEQ_POINTS
]);
446 size
= mono_metadata_decode_blob_size (ptr
, &ptr
);
449 sps
= g_array_new (FALSE
, TRUE
, sizeof (MonoSymSeqPoint
));
453 mono_metadata_decode_value (ptr
, &ptr
);
455 docidx
= mono_metadata_decode_value (ptr
, &ptr
);
456 docinfo
= get_docinfo (ppdb
, image
, docidx
);
459 g_ptr_array_add (sfiles
, docinfo
);
462 *source_file
= g_strdup (docinfo
->source_file
);
468 delta_il
= mono_metadata_decode_value (ptr
, &ptr
);
469 if (!first
&& delta_il
== 0) {
470 /* subsequent-document-record */
471 docidx
= mono_metadata_decode_value (ptr
, &ptr
);
472 docinfo
= get_docinfo (ppdb
, image
, docidx
);
474 g_ptr_array_add (sfiles
, docinfo
);
477 iloffset
+= delta_il
;
480 delta_lines
= mono_metadata_decode_value (ptr
, &ptr
);
481 if (delta_lines
== 0)
482 delta_cols
= mono_metadata_decode_value (ptr
, &ptr
);
484 delta_cols
= mono_metadata_decode_signed_value (ptr
, &ptr
);
486 if (delta_lines
== 0 && delta_cols
== 0) {
487 /* Hidden sequence point */
491 if (first_non_hidden
) {
492 start_line
= mono_metadata_decode_value (ptr
, &ptr
);
493 start_col
= mono_metadata_decode_value (ptr
, &ptr
);
495 adv_line
= mono_metadata_decode_signed_value (ptr
, &ptr
);
496 adv_col
= mono_metadata_decode_signed_value (ptr
, &ptr
);
497 start_line
+= adv_line
;
498 start_col
+= adv_col
;
500 first_non_hidden
= FALSE
;
502 memset (&sp
, 0, sizeof (sp
));
503 sp
.il_offset
= iloffset
;
504 sp
.line
= start_line
;
505 sp
.column
= start_col
;
506 sp
.end_line
= start_line
+ delta_lines
;
507 sp
.end_column
= start_col
+ delta_cols
;
509 g_array_append_val (sps
, sp
);
511 g_ptr_array_add (sindexes
, GUINT_TO_POINTER (sfiles
->len
- 1));
515 *n_seq_points
= sps
->len
;
516 g_assert (seq_points
);
517 *seq_points
= g_new (MonoSymSeqPoint
, sps
->len
);
518 memcpy (*seq_points
, sps
->data
, sps
->len
* sizeof (MonoSymSeqPoint
));
522 *source_files
= g_new (int, sps
->len
);
523 for (i
= 0; i
< sps
->len
; ++i
)
524 (*source_files
)[i
] = GPOINTER_TO_INT (g_ptr_array_index (sindexes
, i
));
525 g_ptr_array_free (sindexes
, TRUE
);
528 g_array_free (sps
, TRUE
);
532 mono_ppdb_lookup_locals (MonoDebugMethodInfo
*minfo
)
534 MonoPPDBFile
*ppdb
= minfo
->handle
->ppdb
;
535 MonoImage
*image
= ppdb
->image
;
536 MonoTableInfo
*tables
= image
->tables
;
537 MonoMethod
*method
= minfo
->method
;
538 guint32 cols
[MONO_LOCALSCOPE_SIZE
];
539 guint32 locals_cols
[MONO_LOCALVARIABLE_SIZE
];
540 int i
, lindex
, sindex
, method_idx
, start_scope_idx
, scope_idx
, locals_idx
, locals_end_idx
, nscopes
;
541 MonoDebugLocalsInfo
*res
;
542 MonoMethodSignature
*sig
;
547 sig
= mono_method_signature_internal (method
);
551 method_idx
= mono_metadata_token_index (method
->token
);
553 start_scope_idx
= mono_metadata_localscope_from_methoddef (image
, method_idx
);
555 if (!start_scope_idx
)
558 /* Compute number of locals and scopes */
559 scope_idx
= start_scope_idx
;
560 mono_metadata_decode_row (&tables
[MONO_TABLE_LOCALSCOPE
], scope_idx
-1, cols
, MONO_LOCALSCOPE_SIZE
);
561 locals_idx
= cols
[MONO_LOCALSCOPE_VARIABLELIST
];
563 // https://github.com/dotnet/roslyn/blob/2ae8d5fed96ab3f1164031f9b4ac827f53289159/docs/specs/PortablePdb-Metadata.md#LocalScopeTable
565 // The variableList attribute in the pdb metadata table is a contiguous array that starts at a
566 // given offset (locals_idx) above and
569 // continues to the smaller of:
571 // the last row of the LocalVariable table
572 // the next run of LocalVariables, found by inspecting the VariableList of the next row in this LocalScope table.
574 // this endpoint becomes locals_end_idx below
576 // March to the last scope that is in this method
577 while (scope_idx
<= tables
[MONO_TABLE_LOCALSCOPE
].rows
) {
578 mono_metadata_decode_row (&tables
[MONO_TABLE_LOCALSCOPE
], scope_idx
-1, cols
, MONO_LOCALSCOPE_SIZE
);
579 if (cols
[MONO_LOCALSCOPE_METHOD
] != method_idx
)
583 // The number of scopes is the difference in the indices
584 // for the first and last scopes
585 nscopes
= scope_idx
- start_scope_idx
;
587 // Ends with "the last row of the LocalVariable table"
588 // this happens if the above loop marched one past the end
590 if (scope_idx
> tables
[MONO_TABLE_LOCALSCOPE
].rows
) {
591 locals_end_idx
= tables
[MONO_TABLE_LOCALVARIABLE
].rows
+ 1;
593 // Ends with "the next run of LocalVariables,
594 // found by inspecting the VariableList of the next row in this LocalScope table."
595 locals_end_idx
= cols
[MONO_LOCALSCOPE_VARIABLELIST
];
598 res
= g_new0 (MonoDebugLocalsInfo
, 1);
599 res
->num_blocks
= nscopes
;
600 res
->code_blocks
= g_new0 (MonoDebugCodeBlock
, res
->num_blocks
);
601 res
->num_locals
= locals_end_idx
- locals_idx
;
602 res
->locals
= g_new0 (MonoDebugLocalVar
, res
->num_locals
);
605 for (sindex
= 0; sindex
< nscopes
; ++sindex
) {
606 scope_idx
= start_scope_idx
+ sindex
;
607 mono_metadata_decode_row (&tables
[MONO_TABLE_LOCALSCOPE
], scope_idx
-1, cols
, MONO_LOCALSCOPE_SIZE
);
609 locals_idx
= cols
[MONO_LOCALSCOPE_VARIABLELIST
];
610 if (scope_idx
== tables
[MONO_TABLE_LOCALSCOPE
].rows
) {
611 locals_end_idx
= tables
[MONO_TABLE_LOCALVARIABLE
].rows
+ 1;
613 locals_end_idx
= mono_metadata_decode_row_col (&tables
[MONO_TABLE_LOCALSCOPE
], scope_idx
-1 + 1, MONO_LOCALSCOPE_VARIABLELIST
);
616 res
->code_blocks
[sindex
].start_offset
= cols
[MONO_LOCALSCOPE_STARTOFFSET
];
617 res
->code_blocks
[sindex
].end_offset
= cols
[MONO_LOCALSCOPE_STARTOFFSET
] + cols
[MONO_LOCALSCOPE_LENGTH
];
619 //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);
621 for (i
= locals_idx
; i
< locals_end_idx
; ++i
) {
622 mono_metadata_decode_row (&tables
[MONO_TABLE_LOCALVARIABLE
], i
- 1, locals_cols
, MONO_LOCALVARIABLE_SIZE
);
624 res
->locals
[lindex
].name
= g_strdup (mono_metadata_string_heap (image
, locals_cols
[MONO_LOCALVARIABLE_NAME
]));
625 res
->locals
[lindex
].index
= locals_cols
[MONO_LOCALVARIABLE_INDEX
];
626 res
->locals
[lindex
].block
= &res
->code_blocks
[sindex
];
629 //printf ("\t %s %d\n", mono_metadata_string_heap (image, locals_cols [MONO_LOCALVARIABLE_NAME]), locals_cols [MONO_LOCALVARIABLE_INDEX]);
637 * We use this to pass context information to the row locator
640 int idx
; /* The index that we are trying to locate */
641 int col_idx
; /* The index in the row where idx may be stored */
642 MonoTableInfo
*t
; /* pointer to the table */
647 table_locator (const void *a
, const void *b
)
649 locator_t
*loc
= (locator_t
*)a
;
650 const char *bb
= (const char *)b
;
651 guint32 table_index
= (bb
- loc
->t
->base
) / loc
->t
->row_size
;
654 col
= mono_metadata_decode_row_col(loc
->t
, table_index
, loc
->col_idx
);
656 if (loc
->idx
== col
) {
657 loc
->result
= table_index
;
667 compare_guid (guint8
* guid1
, guint8
* guid2
)
669 for (int i
= 0; i
< 16; i
++) {
670 if (guid1
[i
] != guid2
[i
])
676 // for parent_type see HasCustomDebugInformation table at
677 // https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PortablePdb-Metadata.md
679 lookup_custom_debug_information (MonoImage
* image
, guint32 token
, uint8_t parent_type
, guint8
* guid
)
681 MonoTableInfo
*tables
= image
->tables
;
682 MonoTableInfo
*table
= &tables
[MONO_TABLE_CUSTOMDEBUGINFORMATION
];
688 loc
.idx
= (mono_metadata_token_index (token
) << MONO_HAS_CUSTOM_DEBUG_BITS
) | parent_type
;
689 loc
.col_idx
= MONO_CUSTOMDEBUGINFORMATION_PARENT
;
692 if (!mono_binary_search (&loc
, table
->base
, table
->rows
, table
->row_size
, table_locator
))
694 // Great we found one of possibly many CustomDebugInformations of this entity they are distinguished by KIND guid
695 // First try on this index found by binary search...(it's most likeley to be only one and binary search found the one we want)
696 if (compare_guid (guid
, (guint8
*)mono_metadata_guid_heap (image
, mono_metadata_decode_row_col (table
, loc
.result
, MONO_CUSTOMDEBUGINFORMATION_KIND
))))
697 return mono_metadata_blob_heap (image
, mono_metadata_decode_row_col (table
, loc
.result
, MONO_CUSTOMDEBUGINFORMATION_VALUE
));
699 // Move forward from binary found index, until parent token differs
700 for (int i
= loc
.result
+ 1; i
< table
->rows
; i
++)
702 if (mono_metadata_decode_row_col (table
, i
, MONO_CUSTOMDEBUGINFORMATION_PARENT
) != loc
.idx
)
704 if (compare_guid (guid
, (guint8
*)mono_metadata_guid_heap (image
, mono_metadata_decode_row_col (table
, i
, MONO_CUSTOMDEBUGINFORMATION_KIND
))))
705 return mono_metadata_blob_heap (image
, mono_metadata_decode_row_col (table
, i
, MONO_CUSTOMDEBUGINFORMATION_VALUE
));
708 // Move backward from binary found index, until parent token differs
709 for (int i
= loc
.result
- 1; i
>= 0; i
--) {
710 if (mono_metadata_decode_row_col (table
, i
, MONO_CUSTOMDEBUGINFORMATION_PARENT
) != loc
.idx
)
712 if (compare_guid (guid
, (guint8
*)mono_metadata_guid_heap (image
, mono_metadata_decode_row_col (table
, i
, MONO_CUSTOMDEBUGINFORMATION_KIND
))))
713 return mono_metadata_blob_heap (image
, mono_metadata_decode_row_col (table
, i
, MONO_CUSTOMDEBUGINFORMATION_VALUE
));
718 MonoDebugMethodAsyncInfo
*
719 mono_ppdb_lookup_method_async_debug_info (MonoDebugMethodInfo
*minfo
)
721 MonoMethod
*method
= minfo
->method
;
722 MonoPPDBFile
*ppdb
= minfo
->handle
->ppdb
;
723 MonoImage
*image
= ppdb
->image
;
725 // Guid is taken from Roslyn source code:
726 // https://github.com/dotnet/roslyn/blob/1ad4b58/src/Dependencies/CodeAnalysis.Metadata/PortableCustomDebugInfoKinds.cs#L9
727 guint8 async_method_stepping_information_guid
[16] = { 0xC5, 0x2A, 0xFD, 0x54, 0x25, 0xE9, 0x1A, 0x40, 0x9C, 0x2A, 0xF9, 0x4F, 0x17, 0x10, 0x72, 0xF8 };
728 char const *blob
= lookup_custom_debug_information (image
, method
->token
, MONO_HAS_CUSTOM_DEBUG_METHODDEF
, async_method_stepping_information_guid
);
731 int blob_len
= mono_metadata_decode_blob_size (blob
, &blob
);
732 MonoDebugMethodAsyncInfo
* res
= g_new0 (MonoDebugMethodAsyncInfo
, 1);
733 char const *pointer
= blob
;
735 // Format of this blob is taken from Roslyn source code:
736 // https://github.com/dotnet/roslyn/blob/1ad4b58/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs#L566
738 pointer
+= 4;//catch_handler_offset
739 while (pointer
- blob
< blob_len
) {
741 pointer
+= 8;//yield_offsets+resume_offsets
742 mono_metadata_decode_value (pointer
, &pointer
);//move_next_method_token
744 g_assert(pointer
- blob
== blob_len
); //Check that we used all blob data
745 pointer
= blob
; //reset pointer after we figured num_awaits
747 res
->yield_offsets
= g_new (uint32_t, res
->num_awaits
);
748 res
->resume_offsets
= g_new (uint32_t, res
->num_awaits
);
749 res
->move_next_method_token
= g_new (uint32_t, res
->num_awaits
);
751 res
->catch_handler_offset
= read32 (pointer
); pointer
+= 4;
752 for (int i
= 0; i
< res
->num_awaits
; i
++) {
753 res
->yield_offsets
[i
] = read32 (pointer
); pointer
+= 4;
754 res
->resume_offsets
[i
] = read32 (pointer
); pointer
+= 4;
755 res
->move_next_method_token
[i
] = mono_metadata_decode_value (pointer
, &pointer
);
761 mono_ppdb_get_sourcelink (MonoDebugHandle
*handle
)
763 MonoPPDBFile
*ppdb
= handle
->ppdb
;
764 MonoImage
*image
= ppdb
->image
;
767 guint8 sourcelink_guid
[16] = { 0x56, 0x05, 0x11, 0xCC, 0x91, 0xA0, 0x38, 0x4D, 0x9F, 0xEC, 0x25, 0xAB, 0x9A, 0x35, 0x1A, 0x6A };
768 /* The module table only has 1 row */
769 char const *blob
= lookup_custom_debug_information (image
, 1, MONO_HAS_CUSTOM_DEBUG_MODULE
, sourcelink_guid
);
772 int blob_len
= mono_metadata_decode_blob_size (blob
, &blob
);
773 res
= g_malloc (blob_len
+ 1);
774 memcpy (res
, blob
, blob_len
);
775 res
[blob_len
] = '\0';