Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Remove dead code for ignoring variables
[simgrid.git] / src / mc / mc_hash.c
1 /* Copyright (c) 2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <stdint.h>
8 #include <stdbool.h>
9
10 #include "mc_private.h"
11 #include "mc/datatypes.h"
12 #include <mc/mc.h>
13
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_hash, mc,
15                                 "Logging specific to mc_hash");
16
17 // This is djb2:
18 typedef uint64_t mc_hash_t;
19 #define MC_HASH_INIT ((uint64_t)5381)
20
21 // #define MC_HASH(hash, value) hash = (((hash << 5) + hash) + (uint64_t) value)
22 #define MC_HASH(hash, value) \
23   { hash = (((hash << 5) + hash) + (uint64_t) value);\
24   XBT_DEBUG("%s:%i: %"PRIx64" -> %"PRIx64, __FILE__, __LINE__, (uint64_t) value, hash); }
25
26 // ***** Hash state
27
28 typedef struct s_mc_hashing_state {
29   // Set of pointers/addresses already processed (avoid loops):
30   mc_address_set_t handled_addresses;
31 } mc_hashing_state;
32
33 void mc_hash_state_init(mc_hashing_state* state);
34 void mc_hash_state_destroy(mc_hashing_state* state);
35
36 void mc_hash_state_init(mc_hashing_state* state) {
37   state->handled_addresses = mc_address_set_new();
38 }
39
40 void mc_hash_state_destroy(mc_hashing_state* state) {
41    mc_address_set_free(&state->handled_addresses);
42 }
43
44 // TODO, detect and avoid loops
45
46 static bool mc_ignored(const void* address, size_t size) {
47   mc_heap_ignore_region_t region;
48   unsigned int cursor = 0;
49   const void* end = (char*) address + size;
50   xbt_dynar_foreach(mc_heap_comparison_ignore, cursor, region) {
51    void* istart = region->address;
52    void* iend   = (char*) region->address + region->size;
53
54    if(address>=istart && address<iend && end>=istart && end<iend)
55      return true;
56   }
57
58   return false;
59 }
60
61 static void mc_hash_binary(mc_hash_t *hash, const void* s, size_t len) {
62   const char* p = (const void*) s;
63   int i;
64   for(i=0; i!=len; ++i) {
65     MC_HASH(*hash, p[i]);
66   }
67 }
68
69 /** \brief Compute a hash for a given value of a given type
70  *
71  *  We try to be very conservative (do not hash too ambiguous things).
72  *
73  *  \param address address of the variable
74  *  \param type type of the variable
75  * */
76 static void mc_hash_value(mc_hash_t* hash, mc_hashing_state* state, mc_object_info_t info, const void* address, dw_type_t type) {
77   top:
78
79   switch(type->type){
80   // Simple case, hash this has binary:
81   case DW_TAG_base_type:
82   case DW_TAG_enumeration_type:
83   {
84     if(mc_ignored(address, 1))
85       return;
86     mc_hash_binary(hash, address, type->byte_size);
87     return;
88   }
89
90   case DW_TAG_array_type:
91   {
92     if(mc_ignored(address, type->byte_size))
93       return;
94
95     long element_count = type->element_count;
96     dw_type_t subtype = type->subtype;
97     if(subtype==NULL) {
98       XBT_DEBUG("Hash array without subtype");
99       return;
100     }
101     int i;
102     for(i=0; i!=element_count; ++i) {
103       XBT_DEBUG("Hash array element %i", i);
104       void* subaddress = ((char*)address)+i*subtype->byte_size;
105       mc_hash_value(hash, state, info, subaddress, subtype);
106     }
107     return;
108   }
109
110   // Get the raw type:
111   case DW_TAG_typedef:
112   case DW_TAG_volatile_type:
113   case DW_TAG_const_type:
114   case DW_TAG_restrict_type:
115   {
116     type = type->subtype;
117     if(type==NULL)
118       return;
119     else
120       goto top;
121   }
122
123   case DW_TAG_structure_type:
124   case DW_TAG_class_type:
125   {
126     if(mc_ignored(address, type->byte_size))
127       return;
128
129     unsigned int cursor = 0;
130     dw_type_t member;
131     xbt_dynar_foreach(type->members, cursor, member){
132       XBT_DEBUG("Hash struct member %s", member->name);
133       if(type->subtype==NULL)
134         return;
135        mc_hash_value(hash, state, info, ((char*)address) + member->offset, type->subtype);
136     }
137     return;
138   }
139
140   // Pointer, we hash a single value but it might be an array.
141   case DW_TAG_pointer_type:
142   case DW_TAG_reference_type:
143   case DW_TAG_rvalue_reference_type:
144   {
145     if(mc_ignored(address, 1))
146       return;
147
148     void* pointed = *(void**)address;
149     if(pointed==NULL) {
150       XBT_DEBUG("Hashed pinter is NULL");
151       return;
152     }
153
154     // Avoid loops:
155     if(mc_address_test(state->handled_addresses, pointed)) {
156       XBT_DEBUG("Hashed pointed data %p already hashed", pointed);
157       return;
158     }
159     mc_address_add(state->handled_addresses, pointed);
160
161     // Anything outside the R/W segments and the heap is not hashed:
162     bool valid_pointer = (pointed >= (void*) mc_binary_info->start_rw && pointed <= (void*) mc_binary_info->end_rw)
163         || (pointed >= (void*) mc_libsimgrid_info->start_rw && pointed <= (void*) mc_libsimgrid_info->end_rw)
164         || (pointed >= std_heap && pointed < (void*) ((const char*)std_heap + STD_HEAP_SIZE));
165     if(!valid_pointer) {
166       XBT_DEBUG("Hashed pointed data %p is in an ignored range", pointed);
167       return;
168     }
169
170     if(type->subtype==NULL) {
171       XBT_DEBUG("Missing type for %p (type=%s)", pointed, type->dw_type_id);
172       return;
173     }
174
175     address = pointed;
176     type = type->subtype;
177     goto top;
178   }
179
180   // Skip this:
181   case DW_TAG_union_type:
182   case DW_TAG_subroutine_type:
183   default:
184     return;
185   }
186 }
187
188
189 static void mc_hash_object_globals(mc_hash_t *hash, mc_hashing_state* state, mc_object_info_t info) {
190   unsigned int cursor = 0;
191   dw_variable_t variable;
192   xbt_dynar_foreach(info->global_variables, cursor, variable) {
193     XBT_DEBUG("Hash global variable %s", variable->name);
194
195     if(variable->type_origin == NULL) {
196       // Nothing
197       continue;
198     }
199
200     dw_type_t type = xbt_dict_get_or_null(info->types, variable->type_origin);
201     if(type==NULL) {
202       // Nothing
203       continue;
204     }
205
206     const char* address = variable->address.address;
207     bool valid_pointer = (address >= mc_binary_info->start_rw && address <= mc_binary_info->end_rw)
208         || (address >= mc_libsimgrid_info->start_rw && address <= mc_libsimgrid_info->end_rw)
209         || (address >= (const char*) std_heap && address < (const char *)std_heap + STD_HEAP_SIZE);
210     if(!valid_pointer) continue;
211
212     mc_hash_value(hash, state, info, variable->address.address, type);
213   }
214 }
215
216 static void mc_hash_stack_frame(
217   mc_hash_t *hash,
218     mc_object_info_t info, unw_cursor_t* unw_cursor, dw_frame_t frame, char* frame_pointer, mc_hashing_state* state
219     ) {
220
221   // return; // TEMP
222
223   unsigned int cursor = 0;
224   dw_variable_t variable;
225   xbt_dynar_foreach(frame->variables, cursor, variable){
226
227     if(variable->type_origin==NULL) {
228       XBT_DEBUG("Hash local variable %s without type", variable->name);
229       continue;
230     }
231     if(variable->address.location == NULL) {
232       XBT_DEBUG("Hash local variable %s without location", variable->name);
233       continue;
234     }
235
236     XBT_DEBUG("Hash local variable %s", variable->name);
237
238     void* variable_address = (void*) MC_dwarf_resolve_location(unw_cursor, variable->address.location, frame_pointer);
239
240     dw_type_t type = xbt_dict_get_or_null(info->types, variable->type_origin);
241     if(type==NULL) {
242       XBT_DEBUG("Hash local variable %s without loctypeation", variable->name);
243       continue;
244     }
245
246     mc_hash_value(hash, state, info, variable_address, type);
247   }
248 }
249
250 /** \brief Find the frame base of a given frame
251  *
252  *  \param ip         Instruction pointer
253  *  \param frame
254  *  \param unw_cursor
255  */
256 void* mc_find_frame_base(unw_word_t ip, dw_frame_t frame, unw_cursor_t* unw_cursor) {
257   switch(frame->frame_base->type) {
258   case e_dw_loclist:
259   {
260     int loclist_cursor;
261     for(loclist_cursor=0; loclist_cursor < xbt_dynar_length(frame->frame_base->location.loclist); loclist_cursor++){
262       dw_location_entry_t entry = xbt_dynar_get_as(frame->frame_base->location.loclist, loclist_cursor, dw_location_entry_t);
263       if((ip >= entry->lowpc) && (ip < entry->highpc)){
264         return (void*) MC_dwarf_resolve_location(unw_cursor, entry->location, NULL);
265       }
266     }
267     return NULL;
268   }
269   // Not handled:
270   default:
271     return NULL;
272   }
273 }
274
275 static void mc_hash_stack(mc_hash_t *hash, stack_region_t stack, mc_hashing_state* state) {
276
277   unw_cursor_t cursor;
278   if(unw_init_local(&cursor, (unw_context_t *)stack->context)){
279     xbt_die("unw_init_local failed");
280   }
281
282   MC_HASH(*hash, (long)stack->address);
283
284   long count = 0;
285
286   int ret;
287   for(ret=1; ret >= 0; ret = unw_step(&cursor)) {
288
289     // Find the frame name:
290     unw_word_t off;
291     char frame_name[256];
292     if(unw_get_proc_name(&cursor, frame_name, sizeof (frame_name), &off)!=0) {
293       continue;
294     }
295
296     XBT_DEBUG("Frame #%i %s", (int) count, frame_name);
297
298     // Stop before context switch with maestro
299     if(!strcmp(frame_name, "smx_ctx_sysv_wrapper")) {
300       break;
301     }
302
303     ++count;
304
305     unw_word_t ip, sp;
306     if(unw_get_reg(&cursor, UNW_REG_IP, &ip))
307       continue;
308     if(unw_get_reg(&cursor, UNW_REG_SP, &sp))
309       continue;
310
311     MC_HASH(*hash, ip);
312
313     // Find the object info:
314     mc_object_info_t info;
315     if((long)ip >= (long) mc_libsimgrid_info->start_exec && (long)ip < (long) mc_libsimgrid_info->end_exec)
316       info = mc_libsimgrid_info;
317     else if((long)ip >= (long) mc_binary_info->start_exec && (long)ip < (long) mc_binary_info->end_exec)
318       info = mc_binary_info;
319     else
320       continue;
321
322     // Find the frame:
323     dw_frame_t frame = xbt_dict_get_or_null(info->local_variables, frame_name);
324     if(frame==NULL)
325       continue;
326
327     long true_ip = (long)frame->low_pc + (long)off;
328
329     // Find the fame base:
330     void* frame_base = mc_find_frame_base(true_ip, frame, &cursor);
331     if(frame_base==NULL)
332       continue;
333
334     mc_hash_stack_frame(hash, info, &cursor, frame, frame_base, state);
335   }
336
337   MC_HASH(*hash, count);
338 }
339
340 static void mc_hash_stacks(mc_hash_t *hash, mc_hashing_state* state) {
341   unsigned int cursor = 0;
342   stack_region_t current_stack;
343
344   MC_HASH(*hash, xbt_dynar_length(stacks_areas));
345
346   int i=0;
347   xbt_dynar_foreach(stacks_areas, cursor, current_stack){
348     XBT_DEBUG("Stack %i", i);
349     mc_hash_stack(hash, current_stack, state);
350     ++i;
351   }
352 }
353
354 uint64_t mc_hash_processes_state(int num_state) {
355   XBT_DEBUG("START hash %i", num_state);
356
357   mc_hashing_state state;
358   mc_hash_state_init(&state);
359
360   mc_hash_t hash = MC_HASH_INIT;
361
362   MC_HASH(hash, xbt_swag_size(simix_global->process_list)); // process count
363   mc_hash_object_globals(&hash, &state, mc_binary_info);
364   // mc_hash_object_globals(&hash, &state, mc_libsimgrid_info);
365   mc_hash_stacks(&hash, &state);
366
367   mc_hash_state_destroy(&state);
368
369   XBT_DEBUG("END hash %i", num_state);
370   return hash;
371 }