2 * seq-points-data.c: Sequence Points functions
5 * Marcos Henrich (marcos.henrich@xamarin.com)
7 * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
10 #include "seq-points-data.h"
15 /* When has_debug_data is set to false only il and native deltas are saved */
16 gboolean has_debug_data;
17 /* When alloc_data is set to true data allocation/deallocation is managed by this structure */
19 } SeqPointInfoInflated;
22 encode_var_int (guint8 *buf, guint8 **out_buf, int val)
27 guint8 byte = val & 0x7f;
28 g_assert (size < 4 && "value has more than 28 bits");
42 decode_var_int (guint8* buf, guint8 **out_buf)
48 b = *(p++); low = (b & 0x7f) ; if(!(b & 0x80)) goto done;
49 b = *(p++); low |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done;
50 b = *(p++); low |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done;
51 b = *(p++); low |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done;
53 g_assert (FALSE && "value has more than 28 bits");
64 encode_zig_zag (int val)
66 return (val << 1) ^ (val >> 31);
70 decode_zig_zag (guint32 val)
73 return (n >> 1) ^ (-(n & 1));
76 static SeqPointInfoInflated
77 seq_point_info_inflate (MonoSeqPointInfo *info)
79 SeqPointInfoInflated info_inflated;
80 guint8 *ptr = (guint8*) info;
83 value = decode_var_int (ptr, &ptr);
85 info_inflated.len = value >> 2;
86 info_inflated.has_debug_data = (value & 1) != 0;
87 info_inflated.alloc_data = (value & 2) != 0;
89 if (info_inflated.alloc_data)
90 info_inflated.data = ptr;
92 memcpy (&info_inflated.data, ptr, sizeof (guint8*));
98 mono_seq_point_info_new (int len, gboolean alloc_data, guint8 *data, gboolean has_debug_data, int *out_size)
100 MonoSeqPointInfo *info;
113 buffer_len = encode_var_int (buffer, NULL, value);
115 *out_size = data_size = buffer_len + (alloc_data? len : sizeof (guint8*));
116 info_ptr = g_new0 (guint8, data_size);
117 info = (MonoSeqPointInfo*) info_ptr;
119 memcpy (info_ptr, buffer, buffer_len);
120 info_ptr += buffer_len;
123 memcpy (info_ptr, data, len);
125 memcpy (info_ptr, &data, sizeof (guint8*));
131 mono_seq_point_info_free (gpointer ptr)
133 MonoSeqPointInfo* info = (MonoSeqPointInfo*) ptr;
138 seq_point_read (SeqPoint* seq_point, guint8* ptr, guint8* buffer_ptr, gboolean has_debug_data)
143 value = decode_var_int (ptr, &ptr);
144 seq_point->il_offset += decode_zig_zag (value);
146 value = decode_var_int (ptr, &ptr);
147 seq_point->native_offset += decode_zig_zag (value);
149 if (has_debug_data) {
150 value = decode_var_int (ptr, &ptr);
151 seq_point->flags = value;
153 if (seq_point->flags & MONO_SEQ_POINT_FLAG_EXIT_IL)
154 seq_point->il_offset = METHOD_EXIT_IL_OFFSET;
156 value = decode_var_int (ptr, &ptr);
157 seq_point->next_len = value;
159 if (seq_point->next_len) {
160 // store next offset and skip it
161 seq_point->next_offset = ptr - buffer_ptr;
162 for (i = 0; i < seq_point->next_len; ++i)
163 decode_var_int (ptr, &ptr);
171 mono_seq_point_info_add_seq_point (GByteArray* array, SeqPoint *sp, SeqPoint *last_seq_point, GSList *next, gboolean has_debug_data)
173 int il_delta, native_delta;
179 if (!has_debug_data &&
180 (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET))
183 il_delta = sp->il_offset - last_seq_point->il_offset;
184 native_delta = sp->native_offset - last_seq_point->native_offset;
188 if (has_debug_data && sp->il_offset == METHOD_EXIT_IL_OFFSET) {
190 flags |= MONO_SEQ_POINT_FLAG_EXIT_IL;
193 len = encode_var_int (buffer, NULL, encode_zig_zag (il_delta));
194 g_byte_array_append (array, buffer, len);
196 len = encode_var_int (buffer, NULL, encode_zig_zag (native_delta));
197 g_byte_array_append (array, buffer, len);
199 if (has_debug_data) {
200 sp->next_offset = array->len;
201 sp->next_len = g_slist_length (next);
203 len = encode_var_int (buffer, NULL, flags);
204 g_byte_array_append (array, buffer, len);
206 len = encode_var_int (buffer, NULL, sp->next_len);
207 g_byte_array_append (array, buffer, len);
209 for (l = next; l; l = l->next) {
210 int next_index = GPOINTER_TO_UINT (l->data);
212 int len = encode_var_int (buffer, NULL, next_index);
213 g_byte_array_append (array, buffer, len);
221 mono_seq_point_find_next_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
224 mono_seq_point_iterator_init (&it, info);
225 while (mono_seq_point_iterator_next (&it)) {
226 if (it.seq_point.native_offset >= native_offset) {
227 memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
236 mono_seq_point_find_prev_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
238 SeqPoint prev_seq_point;
239 gboolean is_first = TRUE;
241 mono_seq_point_iterator_init (&it, info);
242 while (mono_seq_point_iterator_next (&it) && it.seq_point.native_offset <= native_offset) {
243 memcpy (&prev_seq_point, &it.seq_point, sizeof (SeqPoint));
247 if (!is_first && prev_seq_point.native_offset <= native_offset) {
248 memcpy (seq_point, &prev_seq_point, sizeof (SeqPoint));
256 mono_seq_point_find_by_il_offset (MonoSeqPointInfo* info, int il_offset, SeqPoint* seq_point)
259 mono_seq_point_iterator_init (&it, info);
260 while (mono_seq_point_iterator_next (&it)) {
261 if (it.seq_point.il_offset == il_offset) {
262 memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
271 mono_seq_point_init_next (MonoSeqPointInfo* info, SeqPoint sp, SeqPoint* next)
276 GArray* seq_points = g_array_new (FALSE, TRUE, sizeof (SeqPoint));
277 SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
279 g_assert (info_inflated.has_debug_data);
281 mono_seq_point_iterator_init (&it, info);
282 while (mono_seq_point_iterator_next (&it))
283 g_array_append_vals (seq_points, &it.seq_point, 1);
285 ptr = info_inflated.data + sp.next_offset;
286 for (i = 0; i < sp.next_len; i++) {
288 next_index = decode_var_int (ptr, &ptr);
289 g_assert (next_index < seq_points->len);
290 memcpy (&next[i], seq_points->data + next_index * sizeof (SeqPoint), sizeof (SeqPoint));
293 g_array_free (seq_points, TRUE);
297 mono_seq_point_iterator_next (SeqPointIterator* it)
299 if (it->ptr >= it->end)
302 it->ptr += seq_point_read (&it->seq_point, it->ptr, it->begin, it->has_debug_data);
308 mono_seq_point_iterator_init (SeqPointIterator* it, MonoSeqPointInfo* info)
310 SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
311 it->ptr = info_inflated.data;
312 it->begin = info_inflated.data;
313 it->end = it->begin + info_inflated.len;
314 it->has_debug_data = info_inflated.has_debug_data;
315 memset(&it->seq_point, 0, sizeof(SeqPoint));
319 mono_seq_point_info_write (MonoSeqPointInfo* info, guint8* buffer)
321 guint8* buffer0 = buffer;
322 SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
324 encode_var_int (buffer, &buffer, info_inflated.has_debug_data);
326 //Write sequence points
327 encode_var_int (buffer, &buffer, info_inflated.len);
328 memcpy (buffer, info_inflated.data, info_inflated.len);
329 buffer += info_inflated.len;
331 return buffer - buffer0;
335 mono_seq_point_info_read (MonoSeqPointInfo** info, guint8* buffer, gboolean copy)
337 guint8* buffer0 = buffer;
339 gboolean has_debug_data;
341 has_debug_data = decode_var_int (buffer, &buffer);
343 size = decode_var_int (buffer, &buffer);
344 (*info) = mono_seq_point_info_new (size, copy, buffer, has_debug_data, &info_size);
347 return buffer - buffer0;
351 * Returns the maximum size of mono_seq_point_info_write.
354 mono_seq_point_info_get_write_size (MonoSeqPointInfo* info)
356 SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
358 //4 is the maximum size required to store the size of the data.
359 //1 is the byte used to store has_debug_data.
360 int size = 4 + 1 + info_inflated.len;
366 * SeqPointData struct and functions
367 * This is used to store/load/use sequence point from a file
371 mono_seq_point_data_init (SeqPointData *data, int entry_capacity)
373 data->entry_count = 0;
374 data->entry_capacity = entry_capacity;
375 data->entries = (SeqPointDataEntry *)g_malloc (sizeof (SeqPointDataEntry) * entry_capacity);
379 mono_seq_point_data_free (SeqPointData *data)
382 for (i=0; i<data->entry_count; i++) {
383 if (data->entries [i].free_seq_points)
384 g_free (data->entries [i].seq_points);
386 g_free (data->entries);
390 mono_seq_point_data_read (SeqPointData *data, char *path)
392 guint8 *buffer, *buffer_orig;
397 f = fopen (path, "r");
401 fseek(f, 0, SEEK_END);
403 fseek(f, 0, SEEK_SET);
405 buffer_orig = buffer = (guint8 *)g_malloc (fsize + 1);
406 fread(buffer_orig, fsize, 1, f);
409 entry_count = decode_var_int (buffer, &buffer);
410 mono_seq_point_data_init (data, entry_count);
411 data->entry_count = entry_count;
413 for (i=0; i<entry_count; i++) {
414 data->entries [i].method_token = decode_var_int (buffer, &buffer);
415 data->entries [i].method_index = decode_var_int (buffer, &buffer);
416 buffer += mono_seq_point_info_read (&data->entries [i].seq_points, buffer, TRUE);
417 data->entries [i].free_seq_points = TRUE;
420 g_free (buffer_orig);
425 mono_seq_point_data_write (SeqPointData *data, char *path)
427 guint8 *buffer, *buffer_orig;
431 f = fopen (path, "w+");
435 for (i=0; i<data->entry_count; i++) {
436 size += mono_seq_point_info_get_write_size (data->entries [i].seq_points);
438 // Add size of entry_count and native_base_offsets
439 size += 4 + data->entry_count * 4;
441 buffer_orig = buffer = (guint8 *)g_malloc (size);
443 encode_var_int (buffer, &buffer, data->entry_count);
445 for (i=0; i<data->entry_count; i++) {
446 encode_var_int (buffer, &buffer, data->entries [i].method_token);
447 encode_var_int (buffer, &buffer, data->entries [i].method_index);
448 buffer += mono_seq_point_info_write (data->entries [i].seq_points, buffer);
451 fwrite (buffer_orig, 1, buffer - buffer_orig, f);
452 g_free (buffer_orig);
458 mono_seq_point_data_add (SeqPointData *data, guint32 method_token, guint32 method_index, MonoSeqPointInfo* info)
462 g_assert (data->entry_count < data->entry_capacity);
463 i = data->entry_count++;
464 data->entries [i].seq_points = info;
465 data->entries [i].method_token = method_token;
466 data->entries [i].method_index = method_index;
467 data->entries [i].free_seq_points = FALSE;
471 mono_seq_point_data_get (SeqPointData *data, guint32 method_token, guint32 method_index, MonoSeqPointInfo** info)
475 for (i=0; i<data->entry_count; i++) {
476 if (data->entries [i].method_token == method_token && (method_index == 0xffffff || data->entries [i].method_index == method_index)) {
477 (*info) = data->entries [i].seq_points;
485 mono_seq_point_data_get_il_offset (char *path, guint32 method_token, guint32 method_index, guint32 native_offset, guint32 *il_offset)
487 SeqPointData sp_data;
488 MonoSeqPointInfo *seq_points;
491 if (!mono_seq_point_data_read (&sp_data, path))
494 if (!mono_seq_point_data_get (&sp_data, method_token, method_index, &seq_points))
497 if (!mono_seq_point_find_prev_by_native_offset (seq_points, native_offset, &sp))
500 *il_offset = sp.il_offset;