+ case DW_TAG_base_type:
+ if(type->name!=NULL && strcmp(type->name, "char") == 0){ /* String, hence random (arbitrary ?) size */
+ if(real_area1 == real_area2)
+ return -1;
+ else
+ return (memcmp(area1, area2, area_size) != 0);
+ }else{
+ if(area_size != -1 && type->byte_size != area_size)
+ return -1;
+ else{
+ return (memcmp(area1, area2, type->byte_size) != 0);
+ }
+ }
+ break;
+ case DW_TAG_enumeration_type:
+ if(area_size != -1 && type->byte_size != area_size)
+ return -1;
+ else
+ return (memcmp(area1, area2, type->byte_size) != 0);
+ break;
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_volatile_type:
+ return compare_heap_area_with_type(state, real_area1, real_area2, area1, area2, snapshot1, snapshot2, previous, type->subtype, area_size, check_ignore, pointer_level);
+ break;
+ case DW_TAG_array_type:
+ subtype = type->subtype;
+ switch(subtype->type){
+ case DW_TAG_unspecified_type:
+ return 1;
+
+ case DW_TAG_base_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_class_type:
+ case DW_TAG_union_type:
+ if(subtype->full_type)
+ subtype = subtype->full_type;
+ elm_size = subtype->byte_size;
+ break;
+ // TODO, just remove the type indirection?
+ case DW_TAG_const_type:
+ case DW_TAG_typedef:
+ case DW_TAG_volatile_type:
+ subsubtype = subtype->subtype;
+ if(subsubtype->full_type)
+ subsubtype = subsubtype->full_type;
+ elm_size = subsubtype->byte_size;
+ break;
+ default :
+ return 0;
+ break;
+ }
+ for(i=0; i<type->element_count; i++){
+ // TODO, add support for variable stride (DW_AT_byte_stride)
+ res = compare_heap_area_with_type(state, (char *)real_area1 + (i*elm_size), (char *)real_area2 + (i*elm_size), (char *)area1 + (i*elm_size), (char *)area2 + (i*elm_size), snapshot1, snapshot2, previous, type->subtype, subtype->byte_size, check_ignore, pointer_level);
+ if(res == 1)
+ return res;
+ }
+ break;
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_pointer_type:
+ if(type->subtype && type->subtype->type == DW_TAG_subroutine_type){
+ addr_pointed1 = *((void **)(area1));
+ addr_pointed2 = *((void **)(area2));
+ return (addr_pointed1 != addr_pointed2);;
+ }else{
+ pointer_level++;
+ if(pointer_level > 1){ /* Array of pointers */
+ for(i=0; i<(area_size/sizeof(void *)); i++){
+ addr_pointed1 = *((void **)((char *)area1 + (i*sizeof(void *))));
+ addr_pointed2 = *((void **)((char *)area2 + (i*sizeof(void *))));
+ if(addr_pointed1 > state->s_heap && (char *)addr_pointed1 < (char*) state->s_heap + STD_HEAP_SIZE && addr_pointed2 > state->s_heap && (char *)addr_pointed2 < (char*) state->s_heap + STD_HEAP_SIZE)
+ res = compare_heap_area(addr_pointed1, addr_pointed2, snapshot1, snapshot2, previous, type->subtype, pointer_level);
+ else
+ res = (addr_pointed1 != addr_pointed2);
+ if(res == 1)
+ return res;
+ }
+ }else{
+ addr_pointed1 = *((void **)(area1));
+ addr_pointed2 = *((void **)(area2));
+ if(addr_pointed1 > state->s_heap && (char *)addr_pointed1 < (char*) state->s_heap + STD_HEAP_SIZE && addr_pointed2 > state->s_heap && (char *)addr_pointed2 < (char*) state->s_heap + STD_HEAP_SIZE)
+ return compare_heap_area(addr_pointed1, addr_pointed2, snapshot1, snapshot2, previous, type->subtype, pointer_level);
+ else
+ return (addr_pointed1 != addr_pointed2);
+ }
+ }
+ break;
+ case DW_TAG_structure_type:
+ case DW_TAG_class_type:
+ if(type->full_type)
+ type = type->full_type;
+ if(area_size != -1 && type->byte_size != area_size){
+ if(area_size>type->byte_size && area_size%type->byte_size == 0){
+ for(i=0; i<(area_size/type->byte_size); i++){
+ res = compare_heap_area_with_type(state, (char *)real_area1 + (i*type->byte_size), (char *)real_area2 + (i*type->byte_size), (char *)area1 + (i*type->byte_size), (char *)area2 + (i*type->byte_size), snapshot1, snapshot2, previous, type, -1, check_ignore, 0);
+ if(res == 1)
+ return res;
+ }
+ }else{
+ return -1;
+ }
+ }else{
+ cursor = 0;
+ xbt_dynar_foreach(type->members, cursor, member){
+ // TODO, optimize this? (for the offset case)
+ char* real_member1 = mc_member_resolve(real_area1, type, member, snapshot1);
+ char* real_member2 = mc_member_resolve(real_area2, type, member, snapshot2);
+ char* member1 = mc_translate_address((uintptr_t)real_member1, snapshot1);
+ char* member2 = mc_translate_address((uintptr_t)real_member2, snapshot2);
+ res = compare_heap_area_with_type(state, real_member1, real_member2, member1, member2, snapshot1, snapshot2, previous, member->subtype, -1, check_ignore, 0);
+ if(res == 1){
+ return res;
+ }
+ }
+ }
+ break;
+ case DW_TAG_union_type:
+ return compare_heap_area_without_type(state, real_area1, real_area2, area1, area2, snapshot1, snapshot2, previous, type->byte_size, check_ignore);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+
+}
+
+/** Infer the type of a part of the block from the type of the block
+ *
+ * TODO, handle DW_TAG_array_type as well as arrays of the object ((*p)[5], p[5])
+ *
+ * TODO, handle subfields ((*p).bar.foo, (*p)[5].bar…)
+ *
+ * @param type_id DWARF type ID of the root address
+ * @param area_size
+ * @return DWARF type ID for given offset
+ */
+static dw_type_t get_offset_type(void* real_base_address, dw_type_t type, int offset, int area_size, mc_snapshot_t snapshot){
+
+ // Beginning of the block, the infered variable type if the type of the block:
+ if(offset==0)
+ return type;
+
+ switch(type->type){
+ case DW_TAG_structure_type :
+ case DW_TAG_class_type:
+ if(type->full_type)
+ type = type->full_type;
+
+ if(area_size != -1 && type->byte_size != area_size){
+ if(area_size>type->byte_size && area_size%type->byte_size == 0)
+ return type;
+ else
+ return NULL;
+ }else{
+ unsigned int cursor = 0;
+ dw_type_t member;
+ xbt_dynar_foreach(type->members, cursor, member){
+
+ if(!member->location.size) {
+ // We have the offset, use it directly (shortcut):
+ if(member->offset == offset)
+ return member->subtype;
+ } else {
+ char* real_member = mc_member_resolve(real_base_address, type, member, snapshot);
+ if(real_member - (char*)real_base_address == offset)
+ return member->subtype;
+ }
+
+ }
+ return NULL;
+ }
+ break;
+ default:
+ /* FIXME : other cases ? */
+ return NULL;
+ break;
+ }
+}
+
+/**
+ *
+ * @param area1 Process address for state 1
+ * @param area2 Process address for state 2
+ * @param snapshot1 Snapshot of state 1
+ * @param snapshot2 Snapshot of state 2
+ * @param previous Pairs of blocks already compared on the current path (or NULL)
+ * @param type_id Type of variable
+ * @param pointer_level
+ * @return 0 (same), 1 (different), -1
+ */
+int compare_heap_area(void *area1, void* area2, mc_snapshot_t snapshot1, mc_snapshot_t snapshot2, xbt_dynar_t previous, dw_type_t type, int pointer_level){
+
+ struct s_mm_diff* state = mm_diff_info;
+
+ int res_compare;
+ ssize_t block1, frag1, block2, frag2;
+ ssize_t size;
+ int check_ignore = 0;
+
+ void *addr_block1, *addr_block2, *addr_frag1, *addr_frag2, *real_addr_block1, *real_addr_block2, *real_addr_frag1, *real_addr_frag2;
+ void *area1_to_compare, *area2_to_compare;
+ int type_size = -1;
+ int offset1 =0, offset2 = 0;
+ int new_size1 = -1, new_size2 = -1;
+ dw_type_t new_type1 = NULL, new_type2 = NULL;
+
+ int match_pairs = 0;
+
+ if(previous == NULL){
+ previous = xbt_dynar_new(sizeof(heap_area_pair_t), heap_area_pair_free_voidp);
+ match_pairs = 1;
+ }
+
+ // Get block number:
+ block1 = ((char*)area1 - (char*)((xbt_mheap_t)state->s_heap)->heapbase) / BLOCKSIZE + 1;
+ block2 = ((char*)area2 - (char*)((xbt_mheap_t)state->s_heap)->heapbase) / BLOCKSIZE + 1;
+
+ // If either block is a stack block:
+ if(is_block_stack((int)block1) && is_block_stack((int)block2)){
+ add_heap_area_pair(previous, block1, -1, block2, -1);
+ if(match_pairs){
+ match_equals(state, previous);
+ xbt_dynar_free(&previous);
+ }
+ return 0;
+ }
+
+ // If either block is not in the expected area of memory:
+ if(((char *)area1 < (char*)((xbt_mheap_t)state->s_heap)->heapbase) || (block1 > state->heapsize1) || (block1 < 1)
+ || ((char *)area2 < (char*)((xbt_mheap_t)state->s_heap)->heapbase) || (block2 > state->heapsize2) || (block2 < 1)){
+ if(match_pairs){
+ xbt_dynar_free(&previous);
+ }
+ return 1;
+ }
+
+ // Snapshot address of the block:
+ addr_block1 = ((void*) (((ADDR2UINT(block1)) - 1) * BLOCKSIZE + (char*)state->heapbase1));
+ addr_block2 = ((void*) (((ADDR2UINT(block2)) - 1) * BLOCKSIZE + (char*)state->heapbase2));
+
+ // Process address of the block:
+ real_addr_block1 = ((void*) (((ADDR2UINT(block1)) - 1) * BLOCKSIZE + (char*)((xbt_mheap_t)state->s_heap)->heapbase));
+ real_addr_block2 = ((void*) (((ADDR2UINT(block2)) - 1) * BLOCKSIZE + (char*)((xbt_mheap_t)state->s_heap)->heapbase));
+
+ if(type){
+
+ if(type->full_type)
+ type = type->full_type;
+
+ // This assume that for "boring" types (volatile ...) byte_size is absent:
+ while(type->byte_size == 0 && type->subtype!=NULL)
+ type = type->subtype;
+
+ // Find type_size:
+ if((type->type == DW_TAG_pointer_type) || ((type->type == DW_TAG_base_type) && type->name!=NULL && (!strcmp(type->name, "char"))))
+ type_size = -1;
+ else
+ type_size = type->byte_size;
+
+ }