3 * Sequence Points functions
6 * Marcos Henrich (marcos.henrich@xamarin.com)
8 * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
11 #include "seq-points-data.h"
16 /* When has_debug_data is set to false only il and native deltas are saved */
17 gboolean has_debug_data
;
18 /* When alloc_data is set to true data allocation/deallocation is managed by this structure */
20 } SeqPointInfoInflated
;
23 encode_var_int (guint8
*buf
, guint8
**out_buf
, int val
)
28 guint8 byte
= val
& 0x7f;
29 g_assert (size
< 4 && "value has more than 28 bits");
43 decode_var_int (guint8
* buf
, guint8
**out_buf
)
49 b
= *(p
++); low
= (b
& 0x7f) ; if(!(b
& 0x80)) goto done
;
50 b
= *(p
++); low
|= (b
& 0x7f) << 7; if(!(b
& 0x80)) goto done
;
51 b
= *(p
++); low
|= (b
& 0x7f) << 14; if(!(b
& 0x80)) goto done
;
52 b
= *(p
++); low
|= (b
& 0x7f) << 21; if(!(b
& 0x80)) goto done
;
54 g_assert (FALSE
&& "value has more than 28 bits");
65 encode_zig_zag (int val
)
67 return (val
<< 1) ^ (val
>> 31);
71 decode_zig_zag (guint32 val
)
74 return (n
>> 1) ^ (-(n
& 1));
77 static SeqPointInfoInflated
78 seq_point_info_inflate (MonoSeqPointInfo
*info
)
80 SeqPointInfoInflated info_inflated
;
81 guint8
*ptr
= (guint8
*) info
;
84 value
= decode_var_int (ptr
, &ptr
);
86 info_inflated
.len
= value
>> 2;
87 info_inflated
.has_debug_data
= (value
& 1) != 0;
88 info_inflated
.alloc_data
= (value
& 2) != 0;
90 if (info_inflated
.alloc_data
)
91 info_inflated
.data
= ptr
;
93 memcpy (&info_inflated
.data
, ptr
, sizeof (guint8
*));
99 mono_seq_point_info_new (int len
, gboolean alloc_data
, guint8
*data
, gboolean has_debug_data
, int *out_size
)
101 MonoSeqPointInfo
*info
;
114 buffer_len
= encode_var_int (buffer
, NULL
, value
);
116 *out_size
= data_size
= buffer_len
+ (alloc_data
? len
: sizeof (guint8
*));
117 info_ptr
= g_new0 (guint8
, data_size
);
118 info
= (MonoSeqPointInfo
*) info_ptr
;
120 memcpy (info_ptr
, buffer
, buffer_len
);
121 info_ptr
+= buffer_len
;
124 memcpy (info_ptr
, data
, len
);
126 memcpy (info_ptr
, &data
, sizeof (guint8
*));
132 mono_seq_point_info_free (gpointer ptr
)
134 MonoSeqPointInfo
* info
= (MonoSeqPointInfo
*) ptr
;
139 seq_point_read (SeqPoint
* seq_point
, guint8
* ptr
, guint8
* buffer_ptr
, gboolean has_debug_data
)
144 value
= decode_var_int (ptr
, &ptr
);
145 seq_point
->il_offset
+= decode_zig_zag (value
);
147 value
= decode_var_int (ptr
, &ptr
);
148 seq_point
->native_offset
+= decode_zig_zag (value
);
150 if (has_debug_data
) {
151 value
= decode_var_int (ptr
, &ptr
);
152 seq_point
->flags
= value
;
154 if (seq_point
->flags
& MONO_SEQ_POINT_FLAG_EXIT_IL
)
155 seq_point
->il_offset
= METHOD_EXIT_IL_OFFSET
;
157 value
= decode_var_int (ptr
, &ptr
);
158 seq_point
->next_len
= value
;
160 if (seq_point
->next_len
) {
161 // store next offset and skip it
162 seq_point
->next_offset
= ptr
- buffer_ptr
;
163 for (i
= 0; i
< seq_point
->next_len
; ++i
)
164 decode_var_int (ptr
, &ptr
);
172 mono_seq_point_info_add_seq_point (GByteArray
* array
, SeqPoint
*sp
, SeqPoint
*last_seq_point
, GSList
*next
, gboolean has_debug_data
)
174 int il_delta
, native_delta
;
180 if (!has_debug_data
&&
181 (sp
->il_offset
== METHOD_ENTRY_IL_OFFSET
|| sp
->il_offset
== METHOD_EXIT_IL_OFFSET
))
184 il_delta
= sp
->il_offset
- last_seq_point
->il_offset
;
185 native_delta
= sp
->native_offset
- last_seq_point
->native_offset
;
189 if (has_debug_data
&& sp
->il_offset
== METHOD_EXIT_IL_OFFSET
) {
191 flags
|= MONO_SEQ_POINT_FLAG_EXIT_IL
;
194 len
= encode_var_int (buffer
, NULL
, encode_zig_zag (il_delta
));
195 g_byte_array_append (array
, buffer
, len
);
197 len
= encode_var_int (buffer
, NULL
, encode_zig_zag (native_delta
));
198 g_byte_array_append (array
, buffer
, len
);
200 if (has_debug_data
) {
201 sp
->next_offset
= array
->len
;
202 sp
->next_len
= g_slist_length (next
);
204 len
= encode_var_int (buffer
, NULL
, flags
);
205 g_byte_array_append (array
, buffer
, len
);
207 len
= encode_var_int (buffer
, NULL
, sp
->next_len
);
208 g_byte_array_append (array
, buffer
, len
);
210 for (l
= next
; l
; l
= l
->next
) {
211 int next_index
= GPOINTER_TO_UINT (l
->data
);
213 int len
= encode_var_int (buffer
, NULL
, next_index
);
214 g_byte_array_append (array
, buffer
, len
);
222 mono_seq_point_find_next_by_native_offset (MonoSeqPointInfo
* info
, int native_offset
, SeqPoint
* seq_point
)
225 mono_seq_point_iterator_init (&it
, info
);
226 while (mono_seq_point_iterator_next (&it
)) {
227 if (it
.seq_point
.native_offset
>= native_offset
) {
228 memcpy (seq_point
, &it
.seq_point
, sizeof (SeqPoint
));
237 mono_seq_point_find_prev_by_native_offset (MonoSeqPointInfo
* info
, int native_offset
, SeqPoint
* seq_point
)
239 SeqPoint prev_seq_point
;
240 gboolean is_first
= TRUE
;
242 mono_seq_point_iterator_init (&it
, info
);
243 while (mono_seq_point_iterator_next (&it
) && it
.seq_point
.native_offset
<= native_offset
) {
244 memcpy (&prev_seq_point
, &it
.seq_point
, sizeof (SeqPoint
));
248 if (!is_first
&& prev_seq_point
.native_offset
<= native_offset
) {
249 memcpy (seq_point
, &prev_seq_point
, sizeof (SeqPoint
));
257 mono_seq_point_find_by_il_offset (MonoSeqPointInfo
* info
, int il_offset
, SeqPoint
* seq_point
)
260 mono_seq_point_iterator_init (&it
, info
);
261 while (mono_seq_point_iterator_next (&it
)) {
262 if (it
.seq_point
.il_offset
== il_offset
) {
263 memcpy (seq_point
, &it
.seq_point
, sizeof (SeqPoint
));
272 mono_seq_point_init_next (MonoSeqPointInfo
* info
, SeqPoint sp
, SeqPoint
* next
)
277 GArray
* seq_points
= g_array_new (FALSE
, TRUE
, sizeof (SeqPoint
));
278 SeqPointInfoInflated info_inflated
= seq_point_info_inflate (info
);
280 g_assert (info_inflated
.has_debug_data
);
282 mono_seq_point_iterator_init (&it
, info
);
283 while (mono_seq_point_iterator_next (&it
))
284 g_array_append_vals (seq_points
, &it
.seq_point
, 1);
286 ptr
= info_inflated
.data
+ sp
.next_offset
;
287 for (i
= 0; i
< sp
.next_len
; i
++) {
289 next_index
= decode_var_int (ptr
, &ptr
);
290 g_assert (next_index
< seq_points
->len
);
291 memcpy (&next
[i
], seq_points
->data
+ next_index
* sizeof (SeqPoint
), sizeof (SeqPoint
));
294 g_array_free (seq_points
, TRUE
);
298 mono_seq_point_iterator_next (SeqPointIterator
* it
)
300 if (it
->ptr
>= it
->end
)
303 it
->ptr
+= seq_point_read (&it
->seq_point
, it
->ptr
, it
->begin
, it
->has_debug_data
);
309 mono_seq_point_iterator_init (SeqPointIterator
* it
, MonoSeqPointInfo
* info
)
311 SeqPointInfoInflated info_inflated
= seq_point_info_inflate (info
);
312 it
->ptr
= info_inflated
.data
;
313 it
->begin
= info_inflated
.data
;
314 it
->end
= it
->begin
+ info_inflated
.len
;
315 it
->has_debug_data
= info_inflated
.has_debug_data
;
316 memset(&it
->seq_point
, 0, sizeof(SeqPoint
));
320 mono_seq_point_info_write (MonoSeqPointInfo
* info
, guint8
* buffer
)
322 guint8
* buffer0
= buffer
;
323 SeqPointInfoInflated info_inflated
= seq_point_info_inflate (info
);
325 encode_var_int (buffer
, &buffer
, info_inflated
.has_debug_data
);
327 //Write sequence points
328 encode_var_int (buffer
, &buffer
, info_inflated
.len
);
329 memcpy (buffer
, info_inflated
.data
, info_inflated
.len
);
330 buffer
+= info_inflated
.len
;
332 return buffer
- buffer0
;
336 mono_seq_point_info_read (MonoSeqPointInfo
** info
, guint8
* buffer
, gboolean copy
)
338 guint8
* buffer0
= buffer
;
340 gboolean has_debug_data
;
342 has_debug_data
= decode_var_int (buffer
, &buffer
);
344 size
= decode_var_int (buffer
, &buffer
);
345 (*info
) = mono_seq_point_info_new (size
, copy
, buffer
, has_debug_data
, &info_size
);
348 return buffer
- buffer0
;
352 * Returns the maximum size of mono_seq_point_info_write.
355 mono_seq_point_info_get_write_size (MonoSeqPointInfo
* info
)
357 SeqPointInfoInflated info_inflated
= seq_point_info_inflate (info
);
359 //4 is the maximum size required to store the size of the data.
360 //1 is the byte used to store has_debug_data.
361 int size
= 4 + 1 + info_inflated
.len
;
367 * SeqPointData struct and functions
368 * This is used to store/load/use sequence point from a file
372 mono_seq_point_data_init (SeqPointData
*data
, int entry_capacity
)
374 data
->entry_count
= 0;
375 data
->entry_capacity
= entry_capacity
;
376 data
->entries
= (SeqPointDataEntry
*)g_malloc (sizeof (SeqPointDataEntry
) * entry_capacity
);
380 mono_seq_point_data_free (SeqPointData
*data
)
383 for (i
=0; i
<data
->entry_count
; i
++) {
384 if (data
->entries
[i
].free_seq_points
)
385 g_free (data
->entries
[i
].seq_points
);
387 g_free (data
->entries
);
391 mono_seq_point_data_read (SeqPointData
*data
, char *path
)
393 guint8
*buffer
, *buffer_orig
;
398 f
= fopen (path
, "r");
402 fseek(f
, 0, SEEK_END
);
404 fseek(f
, 0, SEEK_SET
);
406 buffer_orig
= buffer
= (guint8
*)g_malloc (fsize
+ 1);
407 fread(buffer_orig
, fsize
, 1, f
);
410 entry_count
= decode_var_int (buffer
, &buffer
);
411 mono_seq_point_data_init (data
, entry_count
);
412 data
->entry_count
= entry_count
;
414 for (i
=0; i
<entry_count
; i
++) {
415 data
->entries
[i
].method_token
= decode_var_int (buffer
, &buffer
);
416 data
->entries
[i
].method_index
= decode_var_int (buffer
, &buffer
);
417 buffer
+= mono_seq_point_info_read (&data
->entries
[i
].seq_points
, buffer
, TRUE
);
418 data
->entries
[i
].free_seq_points
= TRUE
;
421 g_free (buffer_orig
);
426 mono_seq_point_data_write (SeqPointData
*data
, char *path
)
428 guint8
*buffer
, *buffer_orig
;
432 f
= fopen (path
, "w+");
436 for (i
=0; i
<data
->entry_count
; i
++) {
437 size
+= mono_seq_point_info_get_write_size (data
->entries
[i
].seq_points
);
439 // Add size of entry_count and native_base_offsets
440 size
+= 4 + data
->entry_count
* 4;
442 buffer_orig
= buffer
= (guint8
*)g_malloc (size
);
444 encode_var_int (buffer
, &buffer
, data
->entry_count
);
446 for (i
=0; i
<data
->entry_count
; i
++) {
447 encode_var_int (buffer
, &buffer
, data
->entries
[i
].method_token
);
448 encode_var_int (buffer
, &buffer
, data
->entries
[i
].method_index
);
449 buffer
+= mono_seq_point_info_write (data
->entries
[i
].seq_points
, buffer
);
452 fwrite (buffer_orig
, 1, buffer
- buffer_orig
, f
);
453 g_free (buffer_orig
);
460 mono_seq_point_data_add (SeqPointData
*data
, guint32 method_token
, guint32 method_index
, MonoSeqPointInfo
* info
)
464 g_assert (data
->entry_count
< data
->entry_capacity
);
465 i
= data
->entry_count
++;
466 data
->entries
[i
].seq_points
= info
;
467 data
->entries
[i
].method_token
= method_token
;
468 data
->entries
[i
].method_index
= method_index
;
469 data
->entries
[i
].free_seq_points
= FALSE
;
473 mono_seq_point_data_get (SeqPointData
*data
, guint32 method_token
, guint32 method_index
, MonoSeqPointInfo
** info
)
477 for (i
=0; i
<data
->entry_count
; i
++) {
478 if (data
->entries
[i
].method_token
== method_token
&& (method_index
== 0xffffff || data
->entries
[i
].method_index
== method_index
)) {
479 (*info
) = data
->entries
[i
].seq_points
;
487 mono_seq_point_data_get_il_offset (char *path
, guint32 method_token
, guint32 method_index
, guint32 native_offset
, guint32
*il_offset
)
489 SeqPointData sp_data
;
490 MonoSeqPointInfo
*seq_points
;
493 if (!mono_seq_point_data_read (&sp_data
, path
))
496 if (!mono_seq_point_data_get (&sp_data
, method_token
, method_index
, &seq_points
))
499 if (!mono_seq_point_find_prev_by_native_offset (seq_points
, native_offset
, &sp
))
502 *il_offset
= sp
.il_offset
;