}
static void local_variable_free(local_variable_t v){
- xbt_free(v->frame);
xbt_free(v->name);
xbt_free(v);
}
}
-/** \brief Fill/llokup the "subtype" field.
+/** \brief Fill/lookup the "subtype" field.
*/
static void MC_resolve_subtype(mc_object_info_t info, dw_type_t type) {
type->subtype = subtype;
}
- // TODO, support "switch type" (looking up the type in another lib) when possible
}
void MC_post_process_types(mc_object_info_t info) {
}
}
-/** \brief Fills the position of the .bss and .data sections. */
+/** \brief Fills the position of the segments (executable, read-only, read/write).
+ *
+ * TODO, use dl_iterate_phdr to be more robust
+ * */
void MC_find_object_address(memory_map_t maps, mc_object_info_t result) {
unsigned int i = 0;
result->start_rw = reg.start_addr;
result->end_rw = reg.end_addr;
// .bss is usually after the .data:
- // TODO, use dl_iterate_phdr to be more robust
s_map_region_t* next = &(maps->regions[i+1]);
if(next->pathname == NULL && (next->prot & PROT_WRITE) && next->start_addr == reg.end_addr) {
result->end_rw = maps->regions[i+1].end_addr;
/************************************* Take Snapshot ************************************/
/****************************************************************************************/
+/** \brief Checks whether the variable is in scope for a given IP.
+ *
+ * A variable may be defined only from a given value of IP.
+ *
+ * \param var Variable description
+ * \param frame Scope description
+ * \param ip Instruction pointer
+ * \return true if the variable is valid
+ * */
static bool mc_valid_variable(dw_variable_t var, dw_frame_t frame, const void* ip) {
// The variable is not yet valid:
if((const void*)((const char*) frame->low_pc + var->start_scope) > ip)
return true;
}
+static void mc_fill_local_variables_values(mc_stack_frame_t stack_frame, dw_frame_t scope, xbt_dynar_t result) {
+ void* ip = (void*) stack_frame->ip;
+ if(ip < scope->low_pc || ip>= scope->high_pc)
+ return;
+
+ unsigned cursor = 0;
+ dw_variable_t current_variable;
+ xbt_dynar_foreach(scope->variables, cursor, current_variable){
+
+ if(!mc_valid_variable(current_variable, stack_frame->frame, (void*) stack_frame->ip))
+ continue;
+
+ int region_type;
+ if((long)stack_frame->ip > (long)mc_libsimgrid_info->start_exec)
+ region_type = 1;
+ else
+ region_type = 2;
+
+ local_variable_t new_var = xbt_new0(s_local_variable_t, 1);
+ new_var->subprogram = stack_frame->frame;
+ new_var->ip = stack_frame->ip;
+ new_var->name = xbt_strdup(current_variable->name);
+ new_var->type = current_variable->type;
+ new_var->region= region_type;
+
+ /* if(current_variable->address!=NULL) {
+ new_var->address = current_variable->address;
+ } else */
+ if(current_variable->locations.size != 0){
+ new_var->address = (void*) mc_dwarf_resolve_locations(¤t_variable->locations,
+ current_variable->object_info,
+ &(stack_frame->unw_cursor), (void*)stack_frame->frame_base, NULL);
+ }
+
+ xbt_dynar_push(result, &new_var);
+ }
+
+ // Recursive processing of nested scopes:
+ dw_frame_t nested_scope = NULL;
+ xbt_dynar_foreach(scope->scopes, cursor, nested_scope) {
+ mc_fill_local_variables_values(stack_frame, nested_scope, result);
+ }
+}
+
static xbt_dynar_t MC_get_local_variables_values(xbt_dynar_t stack_frames){
unsigned cursor1 = 0;
xbt_dynar_t variables = xbt_dynar_new(sizeof(local_variable_t), local_variable_free_voidp);
xbt_dynar_foreach(stack_frames,cursor1,stack_frame) {
-
- unsigned cursor2 = 0;
- dw_variable_t current_variable;
- xbt_dynar_foreach(stack_frame->frame->variables, cursor2, current_variable){
-
- if(!mc_valid_variable(current_variable, stack_frame->frame, (void*) stack_frame->ip))
- continue;
-
- int region_type;
- if((long)stack_frame->ip > (long)mc_libsimgrid_info->start_exec)
- region_type = 1;
- else
- region_type = 2;
-
- local_variable_t new_var = xbt_new0(s_local_variable_t, 1);
- new_var->frame = xbt_strdup(stack_frame->frame_name);
- new_var->ip = stack_frame->ip;
- new_var->name = xbt_strdup(current_variable->name);
- new_var->type = current_variable->type;
- new_var->region= region_type;
-
- /* if(current_variable->address!=NULL) {
- new_var->address = current_variable->address;
- } else */
- if(current_variable->locations.size != 0){
- new_var->address = (void*) mc_dwarf_resolve_locations(¤t_variable->locations,
- &(stack_frame->unw_cursor), (void*)stack_frame->frame_base, NULL);
- }
-
- xbt_dynar_push(variables, &new_var);
-
- }
+ mc_fill_local_variables_values(stack_frame, stack_frame->frame, variables);
}
return variables;
-
}
static void MC_stack_frame_free_voipd(void *s){
if(frame) {
stack_frame->frame_name = xbt_strdup(frame->name);
- stack_frame->frame_base = (unw_word_t)mc_find_frame_base(frame, &c);
+ stack_frame->frame_base = (unw_word_t)mc_find_frame_base(frame, frame->object_info, &c);
} else {
stack_frame->frame_base = 0;
}
while(cursor < xbt_dynar_length(stack1->local_variables)){
current_var1 = (local_variable_t)xbt_dynar_get_as(stack1->local_variables, cursor, local_variable_t);
current_var2 = (local_variable_t)xbt_dynar_get_as(stack2->local_variables, cursor, local_variable_t);
- if(strcmp(current_var1->name, current_var2->name) != 0 || strcmp(current_var1->frame, current_var2->frame) != 0 || current_var1->ip != current_var2->ip){
+ if(strcmp(current_var1->name, current_var2->name) != 0 || current_var1->subprogram != current_var1->subprogram || current_var1->ip != current_var2->ip){
xbt_dynar_free(&compared_pointers);
- XBT_VERB("Different name of variable (%s - %s) or frame (%s - %s) or ip (%lu - %lu)", current_var1->name, current_var2->name, current_var1->frame, current_var2->frame, current_var1->ip, current_var2->ip);
+ // TODO, fix current_varX->subprogram->name to include name if DW_TAG_inlined_subprogram
+ XBT_VERB("Different name of variable (%s - %s) or frame (%s - %s) or ip (%lu - %lu)", current_var1->name, current_var2->name, current_var1->subprogram->name, current_var2->subprogram->name, current_var1->ip, current_var2->ip);
return 1;
}
offset1 = (char *)current_var1->address - (char *)std_heap;
offset2 = (char *)current_var2->address - (char *)std_heap;
- XBT_DEBUG("Compare local variable %s of frame %s", current_var1->name, current_var1->frame);
+ // TODO, fix current_varX->subprogram->name to include name if DW_TAG_inlined_subprogram
+ XBT_DEBUG("Compare local variable %s of frame %s", current_var1->subprogram->name, current_var1->subprogram->name);
if(current_var1->region == 1) {
res = compare_areas_with_type( (char *)heap1 + offset1, (char *)heap2 + offset2, snapshot1, snapshot2, subtype, 0, 2, start_data_binary, 0);
}
if(res == 1){
- XBT_VERB("Local variable %s (%p - %p) in frame %s is different between snapshots", current_var1->name,(char *)heap1 + offset1, (char *)heap2 + offset2, current_var1->frame);
+ // TODO, fix current_varX->subprogram->name to include name if DW_TAG_inlined_subprogram
+ XBT_VERB("Local variable %s (%p - %p) in frame %s is different between snapshots", current_var1->name,(char *)heap1 + offset1, (char *)heap2 + offset2, current_var1->subprogram->name);
xbt_dynar_free(&compared_pointers);
compared_pointers = NULL;
return res;
case DW_TAG_lexical_block:
case DW_TAG_try_block:
+ case DW_TAG_catch_block:
case DW_TAG_inlined_subroutine:
+ case DW_TAG_with_stmt:
return mc_tag_scope;
case DW_TAG_namespace:
#define MC_DW_CLASS_MACPTR 9
#define MC_DW_CLASS_RANGELISTPTR 10
+/** \brief Find the DWARF data class for a given DWARF data form
+ *
+ * This mapping is defined in the DWARF spec.
+ *
+ * \param form The form (values taken from the DWARF spec)
+ * \return An internal representation for the corresponding class
+ * */
static int MC_dwarf_form_get_class(int form) {
switch(form) {
case DW_FORM_addr:
/** \brief Get an attribute of a given DIE as a string
*
- * \param the DIE
+ * \param die the DIE
* \param attribute attribute
* \return value of the given attribute of the given DIE
*/
-static const char* MC_dwarf_attr_string(Dwarf_Die* die, int attribute) {
+static const char* MC_dwarf_attr_integrate_string(Dwarf_Die* die, int attribute) {
Dwarf_Attribute attr;
if (!dwarf_attr_integrate(die, attribute, &attr)) {
return NULL;
/** \brief Get the linkage name of a DIE.
*
- * Use either DW_AT_linkage_name or DW_AR_MIPS_linkage_name.
+ * Use either DW_AT_linkage_name or DW_AT_MIPS_linkage_name.
+ * DW_AT_linkage_name is standardized since DWARF 4.
+ * Before this version of DWARF, the MIPS extensions
+ * DW_AT_MIPS_linkage_name is used (at least by GCC).
*
- * \param DIE
+ * \param the DIE
* \return linkage name of the given DIE (or NULL)
* */
static const char* MC_dwarf_at_linkage_name(Dwarf_Die* die) {
- const char* name = MC_dwarf_attr_string(die, DW_AT_linkage_name);
+ const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_linkage_name);
if (!name)
- name = MC_dwarf_attr_string(die, DW_AT_MIPS_linkage_name);
+ name = MC_dwarf_attr_integrate_string(die, DW_AT_MIPS_linkage_name);
return name;
}
-static char* MC_dwarf_at_type(Dwarf_Die* die) {
+static Dwarf_Off MC_dwarf_attr_dieoffset(Dwarf_Die* die, int attribute) {
Dwarf_Attribute attr;
- if (dwarf_hasattr_integrate(die, DW_AT_type)) {
- dwarf_attr_integrate(die, DW_AT_type, &attr);
- Dwarf_Die subtype_die;
- if (dwarf_formref_die(&attr, &subtype_die)==NULL) {
- xbt_die("Could not find DIE for type");
- }
- Dwarf_Off subtype_global_offset = dwarf_dieoffset(&subtype_die);
- return bprintf("%" PRIx64 , subtype_global_offset);
- }
- else return NULL;
+ if (dwarf_hasattr_integrate(die, attribute)) {
+ dwarf_attr_integrate(die, attribute, &attr);
+ Dwarf_Die subtype_die;
+ if (dwarf_formref_die(&attr, &subtype_die)==NULL) {
+ xbt_die("Could not find DIE");
+ }
+ return dwarf_dieoffset(&subtype_die);
+ }
+ else return 0;
}
-static uint64_t MC_dwarf_attr_addr(Dwarf_Die* die, int attribute) {
+static Dwarf_Off MC_dwarf_attr_integrate_dieoffset(Dwarf_Die* die, int attribute) {
+ Dwarf_Attribute attr;
+ if (dwarf_hasattr_integrate(die, attribute)) {
+ dwarf_attr_integrate(die, DW_AT_type, &attr);
+ Dwarf_Die subtype_die;
+ if (dwarf_formref_die(&attr, &subtype_die)==NULL) {
+ xbt_die("Could not find DIE");
+ }
+ return dwarf_dieoffset(&subtype_die);
+ }
+ else return 0;
+}
+
+/** \brief Find the type/subtype (DW_AT_type) for a DIE
+ *
+ * \param dit the DIE
+ * \return DW_AT_type reference as a global offset in hexadecimal (or NULL)
+ */
+static char* MC_dwarf_at_type(Dwarf_Die* die) {
+ Dwarf_Off offset = MC_dwarf_attr_integrate_dieoffset(die, DW_AT_type);
+ return offset == 0 ? NULL : bprintf("%" PRIx64 , offset);
+}
+
+static uint64_t MC_dwarf_attr_integrate_addr(Dwarf_Die* die, int attribute) {
Dwarf_Attribute attr;
if(dwarf_attr_integrate(die, attribute, &attr)==NULL)
return 0;
return 0;
}
-static uint64_t MC_dwarf_attr_uint(Dwarf_Die* die, int attribute, uint64_t default_value) {
+static uint64_t MC_dwarf_attr_integrate_uint(Dwarf_Die* die, int attribute, uint64_t default_value) {
Dwarf_Attribute attr;
if (dwarf_attr_integrate(die, attribute, &attr)==NULL)
return default_value;
return dwarf_formudata(dwarf_attr_integrate(die, attribute, &attr), &value) == 0 ? (uint64_t) value : default_value;
}
-static bool MC_dwarf_attr_flag(Dwarf_Die* die, int attribute, int integrate) {
+static bool MC_dwarf_attr_flag(Dwarf_Die* die, int attribute, bool integrate) {
Dwarf_Attribute attr;
if ((integrate ? dwarf_attr_integrate(die, attribute, &attr)
: dwarf_attr(die, attribute, &attr))==0)
return result;
}
+/** \brief Find the default lower bound for a given language
+ *
+ * The default lower bound of an array (when DW_TAG_lower_bound
+ * is missing) depends on the language of the compilation unit.
+ *
+ * \param lang Language of the compilation unit (values defined in the DWARF spec)
+ * \return Default lower bound of an array in this compilation unit
+ * */
static uint64_t MC_dwarf_default_lower_bound(int lang) {
switch(lang) {
case DW_LANG_C:
case DW_LANG_Cobol85:
return 1;
default:
- xbt_die("No default MT_TAG_lower_bound for language %i and none given", lang);
+ xbt_die("No default DW_TAG_lower_bound for language %i and none given", lang);
return 0;
}
}
+/** \brief Finds the number of elements in a DW_TAG_subrange_type or DW_TAG_enumeration_type DIE
+ *
+ * \param die the DIE
+ * \param unit DIE of the compilation unit
+ * \return number of elements in the range
+ * */
static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit) {
xbt_assert(dwarf_tag(die)==DW_TAG_enumeration_type ||dwarf_tag(die)==DW_TAG_subrange_type,
"MC_dwarf_subrange_element_count called with DIE of type %s", MC_dwarf_die_tagname(die));
// Use DW_TAG_count if present:
if (dwarf_hasattr_integrate(die, DW_AT_count)) {
- return MC_dwarf_attr_uint(die, DW_AT_count, 0);
+ return MC_dwarf_attr_integrate_uint(die, DW_AT_count, 0);
}
// Otherwise compute DW_TAG_upper_bound-DW_TAG_lower_bound + 1:
// This is not really 0, but the code expects this (we do not know):
return 0;
}
- uint64_t upper_bound = MC_dwarf_attr_uint(die, DW_AT_upper_bound, -1);
+ uint64_t upper_bound = MC_dwarf_attr_integrate_uint(die, DW_AT_upper_bound, -1);
uint64_t lower_bound = 0;
if (dwarf_hasattr_integrate(die, DW_AT_lower_bound)) {
- lower_bound = MC_dwarf_attr_uint(die, DW_AT_lower_bound, -1);
+ lower_bound = MC_dwarf_attr_integrate_uint(die, DW_AT_lower_bound, -1);
} else {
lower_bound = MC_dwarf_default_lower_bound(dwarf_srclang(unit));
}
return upper_bound - lower_bound + 1;
}
+/** \brief Finds the number of elements in a array type (DW_TAG_array_type)
+ *
+ * The compilation unit might be needed because the default lower
+ * bound depends on the language of the compilation unit.
+ *
+ * \param die the DIE of the DW_TAG_array_type
+ * \param unit the DIE of the compilation unit
+ * \return number of elements in this array type
+ * */
static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit) {
xbt_assert(dwarf_tag(die)==DW_TAG_array_type,
"MC_dwarf_array_element_count called with DIE of type %s", MC_dwarf_die_tagname(die));
// ***** dw_type_t
+/** \brief Initialize the location of a member of a type
+ * (DW_AT_data_member_location of a DW_TAG_member).
+ *
+ * \param type a type (struct, class)
+ * \param member the member of the type
+ * \param child DIE of the member (DW_TAG_member)
+ */
static void MC_dwarf_fill_member_location(dw_type_t type, dw_type_t member, Dwarf_Die* child) {
if (dwarf_hasattr(child, DW_AT_data_bit_offset)) {
xbt_die("Can't groke DW_AT_data_bit_offset.");
if (dwarf_getlocation(&attr, &expr, &len)) {
xbt_die(
"Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%p>%s",
- MC_dwarf_attr_string(child, DW_AT_name),
+ MC_dwarf_attr_integrate_string(child, DW_AT_name),
type->id, type->name);
}
if (len==1 && expr[0].atom == DW_OP_plus_uconst) {
member->offset = offset;
else
xbt_die("Cannot get %s location <%p>%s",
- MC_dwarf_attr_string(child, DW_AT_name),
+ MC_dwarf_attr_integrate_string(child, DW_AT_name),
type->id, type->name);
break;
}
dw_type_free((dw_type_t) * (void **) t);
}
+/** \brief Populate the list of members of a type
+ *
+ * \param info ELF object containing the type DIE
+ * \param die DIE of the type
+ * \param unit DIE of the compilation unit containing the type DIE
+ * \param type the type
+ */
static void MC_dwarf_add_members(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_type_t type) {
int res;
Dwarf_Die child;
// Global Offset:
member->id = (void *) dwarf_dieoffset(&child);
- const char* name = MC_dwarf_attr_string(&child, DW_AT_name);
+ const char* name = MC_dwarf_attr_integrate_string(&child, DW_AT_name);
if(name)
member->name = xbt_strdup(name);
else
member->name = NULL;
- member->byte_size = MC_dwarf_attr_uint(&child, DW_AT_byte_size, 0);
+ member->byte_size = MC_dwarf_attr_integrate_uint(&child, DW_AT_byte_size, 0);
member->element_count = -1;
member->dw_type_id = MC_dwarf_at_type(&child);
member->members = NULL;
prefix = "";
}
- const char* name = MC_dwarf_attr_string(die, DW_AT_name);
+ const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
if (name!=NULL) {
type->name = namespace ? bprintf("%s%s::%s", prefix, namespace, name) : bprintf("%s%s", prefix, name);
}
// Computation of the byte_size;
if (dwarf_hasattr_integrate(die, DW_AT_byte_size))
- type->byte_size = MC_dwarf_attr_uint(die, DW_AT_byte_size, 0);
+ type->byte_size = MC_dwarf_attr_integrate_uint(die, DW_AT_byte_size, 0);
else if (type->type == DW_TAG_array_type || type->type==DW_TAG_structure_type || type->type==DW_TAG_class_type) {
Dwarf_Word size;
if (dwarf_aggregate_size(die, &size)==0) {
char* key = bprintf("%" PRIx64, (uint64_t) type->id);
xbt_dict_set(info->types, key, type, NULL);
+ xbt_free(key);
if(type->name && type->byte_size!=0) {
xbt_dict_set(info->full_types_by_name, type->name, type, NULL);
dw_variable_t variable = xbt_new0(s_dw_variable_t, 1);
variable->dwarf_offset = dwarf_dieoffset(die);
variable->global = frame == NULL; // Can be override base on DW_AT_location
+ variable->object_info = info;
- const char* name = MC_dwarf_attr_string(die, DW_AT_name);
+ const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
variable->name = xbt_strdup(name);
variable->type_origin = MC_dwarf_at_type(die);
if (len==1 && expr[0].atom == DW_OP_addr) {
variable->global = 1;
Dwarf_Off offset = expr[0].number;
- // TODO, Why is this different base on the object?
- Dwarf_Off base = strcmp(info->file_name, xbt_binary_name) !=0 ? (Dwarf_Off) info->start_exec : 0;
+ Dwarf_Off base = (Dwarf_Off) MC_object_base_address(info);
variable->address = (void*) (base + offset);
} else {
mc_dwarf_location_list_init_from_expression(&variable->locations, len, expr);
MC_dwarf_register_variable(info, frame, variable);
}
-static void MC_dwarf_handle_subprogram_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t parent_frame, const char* namespace) {
+static void mc_frame_free_voipd(dw_frame_t* p) {
+ mc_frame_free(*p);
+ *p = NULL;
+}
+
+static void MC_dwarf_handle_scope_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t parent_frame, const char* namespace) {
+ // TODO, handle DW_TAG_type/DW_TAG_location for DW_TAG_with_stmt
+ int tag = dwarf_tag(die);
+ mc_tag_class klass = MC_dwarf_tag_classify(tag);
// (Template) Subprogram declaration:
- if (MC_dwarf_attr_flag(die, DW_AT_declaration, false))
+ if(klass==mc_tag_subprogram && MC_dwarf_attr_flag(die, DW_AT_declaration, false))
return;
+ if(klass==mc_tag_scope)
+ xbt_assert(parent_frame, "No parent scope for this scope");
+
dw_frame_t frame = xbt_new0(s_dw_frame_t, 1);
- frame->start = dwarf_dieoffset(die);
+ frame->tag = tag;
+ frame->id = dwarf_dieoffset(die);
+ frame->object_info = info;
- const char* name = MC_dwarf_attr_string(die, DW_AT_name);
- frame->name = namespace ? bprintf("%s::%s", namespace, name) : xbt_strdup(name);
+ if(klass==mc_tag_subprogram) {
+ const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
+ frame->name = namespace ? bprintf("%s::%s", namespace, name) : xbt_strdup(name);
+ }
+
+ frame->abstract_origin_id = MC_dwarf_attr_dieoffset(die, DW_AT_abstract_origin);
// This is the base address for DWARF addresses.
// Relocated addresses are offset from this base address.
// See DWARF4 spec 7.5
- void* base = info->flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
+ void* base = MC_object_base_address(info);
// Variables are filled in the (recursive) call of MC_dwarf_handle_children:
frame->variables = xbt_dynar_new(sizeof(dw_variable_t), dw_variable_free_voidp);
- frame->high_pc = ((char*) base) + MC_dwarf_attr_addr(die, DW_AT_high_pc);
- frame->low_pc = ((char*) base) + MC_dwarf_attr_addr(die, DW_AT_low_pc);
+ frame->low_pc = ((char*) base) + MC_dwarf_attr_integrate_addr(die, DW_AT_low_pc);
- Dwarf_Attribute attr_frame_base;
- if (dwarf_attr_integrate(die, DW_AT_frame_base, &attr_frame_base))
- mc_dwarf_location_list_init(&frame->frame_base, info, die, &attr_frame_base);
+ // DW_AT_high_pc:
+ {
+ Dwarf_Attribute attr;
+ if(dwarf_attr_integrate(die, DW_AT_high_pc, &attr)) {
+ uint64_t high_pc;
+ Dwarf_Addr value;
+ if (dwarf_formaddr(&attr, &value) == 0)
+ high_pc = (uint64_t) value;
+ else
+ high_pc = 0;
+
+ int form = dwarf_whatform(&attr);
+ int klass = MC_dwarf_form_get_class(form);
+ if (klass == MC_DW_CLASS_CONSTANT)
+ frame->high_pc = (void*) ((Dwarf_Off)frame->low_pc + high_pc);
+ else if(klass == MC_DW_CLASS_ADDRESS)
+ frame->high_pc = ((char*) base) + high_pc;
+ else
+ xbt_die("Unexpected class for DW_AT_high_pc");
+ } else {
+ frame->high_pc = 0;
+ }
+ }
+
+ if(klass==mc_tag_subprogram) {
+ Dwarf_Attribute attr_frame_base;
+ if (dwarf_attr_integrate(die, DW_AT_frame_base, &attr_frame_base))
+ mc_dwarf_location_list_init(&frame->frame_base, info, die, &attr_frame_base);
+ }
- frame->end = -1; // This one is now useless:
+ frame->scopes = xbt_dynar_new(sizeof(dw_frame_t), (void_f_pvoid_t) mc_frame_free_voipd);
// Register it:
- const char* key = bprintf("%" PRIx64, (uint64_t) frame->start);
- xbt_dict_set(info->subprograms, key, frame, NULL);
+ if(klass==mc_tag_subprogram) {
+ char* key = bprintf("%" PRIx64, (uint64_t) frame->id);
+ xbt_dict_set(info->subprograms, key, frame, NULL);
+ xbt_free(key);
+ } else if(klass==mc_tag_scope) {
+ xbt_dynar_push(parent_frame->scopes, &frame);
+ }
// Handle children:
MC_dwarf_handle_children(info, die, unit, frame, namespace);
static void mc_dwarf_handle_namespace_die(
mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame, const char* namespace) {
- const char* name = MC_dwarf_attr_string(die, DW_AT_name);
+ const char* name = MC_dwarf_attr_integrate_string(die, DW_AT_name);
if(frame)
xbt_die("Unexpected namespace in a subprogram");
char* new_namespace = namespace == NULL ? xbt_strdup(name)
: bprintf("%s::%s", namespace, name);
MC_dwarf_handle_children(info, die, unit, frame, new_namespace);
+ xbt_free(new_namespace);
}
static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame, const char* namespace) {
+ // For each child DIE:
Dwarf_Die child;
int res;
for (res=dwarf_child(die, &child); res==0; res=dwarf_siblingof(&child,&child)) {
MC_dwarf_handle_type_die(info, die, unit, frame, namespace);
break;
- // Program:
+ // Subprogram or scope:
case mc_tag_subprogram:
- MC_dwarf_handle_subprogram_die(info, die, unit, frame, namespace);
+ case mc_tag_scope:
+ MC_dwarf_handle_scope_die(info, die, unit, frame, namespace);
return;
// Variable:
MC_dwarf_handle_variable_die(info, die, unit, frame, namespace);
break;
- // Scope:
- case mc_tag_scope:
- // TODO
- break;
-
case mc_tag_namespace:
mc_dwarf_handle_namespace_die(info, die, unit, frame, namespace);
break;
}
}
+/** \brief Populate the debugging informations of the given ELF object
+ *
+ * Read the DWARf information of the EFFL object and populate the
+ * lists of types, variables, functions.
+ */
void MC_dwarf_get_variables(mc_object_info_t info) {
int fd = open(info->file_name, O_RDONLY);
if (fd<0) {
xbt_die("Your program must be compiled with -g");
}
+ // For each compilation unit:
Dwarf_Off offset = 0;
Dwarf_Off next_offset = 0;
size_t length;
while (dwarf_nextcu (dwarf, offset, &next_offset, &length, NULL, NULL, NULL) == 0) {
Dwarf_Die unit_die;
-
if(dwarf_offdie(dwarf, offset+length, &unit_die)!=NULL) {
+
+ // For each child DIE:
Dwarf_Die child;
int res;
for (res=dwarf_child(&unit_die, &child); res==0; res=dwarf_siblingof(&child,&child)) {
MC_dwarf_handle_die(info, &child, &unit_die, NULL, NULL);
}
+
}
offset = next_offset;
}
break;
}
- // Push the CFA (Call Frame Addresse):
+ // Push the CFA (Canonical Frame Addresse):
case DW_OP_call_frame_cfa:
{
- unw_word_t res;
-
- int register_id =
-#if defined(UNW_TARGET_X86_64)
- UNW_X86_64_CFA
-#elif defined(UNW_TARGET_X86)
- UNW_X86_CFA
-#else
- -1;
-#endif
- ;
- if(register_id<0)
- xbt_die("Support for CFA not implemented for this achitecture.");
+ // UNW_X86_64_CFA does not return the CFA DWARF expects
+ // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
+ // unwind it once in order to find the parent SP:
if(!state->cursor)
return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
- unw_get_reg(state->cursor, register_id, &res);
- error = mc_dwarf_push_value(state, res + op->number);
+ // Get frame:
+ unw_cursor_t cursor = *(state->cursor);
+ unw_step(&cursor);
+
+ unw_word_t res;
+ unw_get_reg(&cursor, UNW_TDEP_SP, &res);
+ error = mc_dwarf_push_value(state, res);
break;
}
break;
}
+
// Constants:
case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3:
break;
case DW_OP_addr:
+ if(!state->object_info)
+ return MC_EXPRESSION_E_NO_BASE_ADDRESS;
+ if(state->stack_size==MC_EXPRESSION_STACK_SIZE)
+ return MC_EXPRESSION_E_STACK_OVERFLOW;
+ error = mc_dwarf_push_value(state, (Dwarf_Off)MC_object_base_address(state->object_info) + op->number);
+ break;
+
case DW_OP_const1u:
case DW_OP_const2u:
case DW_OP_const4u:
/** \brief Resolve a location expression
* \deprecated Use mc_dwarf_resolve_expression
*/
-Dwarf_Off mc_dwarf_resolve_location(mc_expression_t expression, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot) {
+Dwarf_Off mc_dwarf_resolve_location(mc_expression_t expression, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot) {
s_mc_expression_state_t state;
memset(&state, 0, sizeof(s_mc_expression_state_t));
state.frame_base = frame_pointer_address;
state.cursor = c;
state.snapshot = snapshot;
+ state.object_info = object_info;
if(mc_dwarf_execute_expression(expression->size, expression->ops, &state))
xbt_die("Error evaluating DWARF expression");
return (Dwarf_Off) state.stack[state.stack_size-1];
}
-Dwarf_Off mc_dwarf_resolve_locations(mc_location_list_t locations, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot) {
+Dwarf_Off mc_dwarf_resolve_locations(mc_location_list_t locations, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot) {
unw_word_t ip;
if(c) {
mc_expression_t expression = locations->locations + i;
if( (expression->lowpc==NULL && expression->highpc==NULL)
|| (c && ip >= (unw_word_t) expression->lowpc && ip < (unw_word_t) expression->highpc)) {
- return mc_dwarf_resolve_location(expression, c, frame_pointer_address, snapshot);
+ return mc_dwarf_resolve_location(expression, object_info, c, frame_pointer_address, snapshot);
}
}
xbt_die("Could not resolve location");
* \param frame
* \param unw_cursor
*/
-void* mc_find_frame_base(dw_frame_t frame, unw_cursor_t* unw_cursor) {
- return (void*) mc_dwarf_resolve_locations(&frame->frame_base, unw_cursor, NULL, NULL);
+void* mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info, unw_cursor_t* unw_cursor) {
+ return (void*) mc_dwarf_resolve_locations(&frame->frame_base, object_info, unw_cursor, NULL, NULL);
}
void mc_dwarf_expression_clear(mc_expression_t expression) {
xbt_free(frame->name);
mc_dwarf_location_list_clear(&(frame->frame_base));
xbt_dynar_free(&(frame->variables));
+ xbt_dynar_free(&(frame->scopes));
xbt_free(frame);
}
// ***** Helpers
void* MC_object_base_address(mc_object_info_t info) {
+ if(info->flags & MC_OBJECT_INFO_EXECUTABLE)
+ return 0;
void* result = info->start_exec;
if(info->start_rw!=NULL && result > (void*) info->start_rw) result = info->start_rw;
if(info->start_ro!=NULL && result > (void*) info->start_ro) result = info->start_ro;
int k = i + ((j-i)/2);
if(ip < base[k].low_pc) {
j = k-1;
- } else if(ip > base[k].high_pc) {
+ } else if(ip >= base[k].high_pc) {
i = k+1;
} else {
return base[k].function;
}
}
+static void mc_post_process_scope(mc_object_info_t info, dw_frame_t scope) {
+
+ if(scope->tag == DW_TAG_inlined_subroutine) {
+
+ // Attach correct namespaced name in inlined subroutine:
+ char* key = bprintf("%" PRIx64, (uint64_t) scope->abstract_origin_id);
+ dw_frame_t abstract_origin = xbt_dict_get_or_null(info->subprograms, key);
+ xbt_assert(abstract_origin, "Could not lookup abstract origin %s", key);
+ xbt_free(key);
+ scope->name = xbt_strdup(abstract_origin->name);
+
+ }
+
+ // Direct:
+ unsigned cursor = 0;
+ dw_variable_t variable = NULL;
+ xbt_dynar_foreach(scope->variables, cursor, variable) {
+ if(variable->type_origin) {
+ variable->type = xbt_dict_get_or_null(info->types, variable->type_origin);
+ }
+ }
+
+ // Recursive post-processing of nested-scopes:
+ dw_frame_t nested_scope = NULL;
+ xbt_dynar_foreach(scope->scopes, cursor, nested_scope)
+ mc_post_process_scope(info, nested_scope);
+
+}
+
static void MC_post_process_functions(mc_object_info_t info) {
xbt_dict_cursor_t cursor;
char* key;
- dw_frame_t function = NULL;
- xbt_dict_foreach(info->subprograms, cursor, key, function) {
- unsigned cursor2 = 0;
- dw_variable_t variable = NULL;
- xbt_dynar_foreach(function->variables, cursor2, variable) {
- if(variable->type_origin) {
- variable->type = xbt_dict_get_or_null(info->types, variable->type_origin);
- }
- }
+ dw_frame_t subprogram = NULL;
+ xbt_dict_foreach(info->subprograms, cursor, key, subprogram) {
+ mc_post_process_scope(info, subprogram);
}
}
/*************************************************************************/
-/** \brief Finds a frame (DW_TAG_subprogram) from an DWARF offset in the rangd of this subprogram
- *
- * The offset can be an offset of a child DW_TAG_variable.
- */
-static dw_frame_t MC_dwarf_get_frame_by_offset(xbt_dict_t all_variables, unsigned long int offset){
-
- xbt_dict_cursor_t cursor = NULL;
- char *name;
- dw_frame_t res;
-
- xbt_dict_foreach(all_variables, cursor, name, res) {
- if(offset >= res->start && offset < res->end){
- xbt_dict_cursor_free(&cursor);
- return res;
- }
- }
-
- xbt_dict_cursor_free(&cursor);
- return NULL;
-
-}
-
-static dw_variable_t MC_dwarf_get_variable_by_name(dw_frame_t frame, char *var){
-
- unsigned int cursor = 0;
- dw_variable_t current_var;
-
- xbt_dynar_foreach(frame->variables, cursor, current_var){
- if(strcmp(var, current_var->name) == 0)
- return current_var;
- }
-
- return NULL;
-}
-
static int MC_dwarf_get_variable_index(xbt_dynar_t variables, char* var, void *address){
if(xbt_dynar_is_empty(variables))
MC_UNSET_RAW_MEM;
}
-static void MC_ignore_local_variable_in_object(const char *var_name, const char *frame_name, mc_object_info_t info) {
- xbt_dict_cursor_t cursor2;
- dw_frame_t frame;
- int start, end;
- int cursor = 0;
- dw_variable_t current_var;
- char* key;
- xbt_dict_foreach(info->subprograms, cursor2, key, frame) {
+/** \brief Ignore a local variable in a scope
+ *
+ * Ignore all instances of variables with a given name in
+ * any (possibly inlined) subprogram with a given namespaced
+ * name.
+ *
+ * \param var_name Name of the local variable (or parameter to ignore)
+ * \param subprogram_name Name of the subprogram fo ignore (NULL for any)
+ * \param subprogram (possibly inlined) Subprogram of the scope
+ * \param scope Current scope
+ */
+static void mc_ignore_local_variable_in_scope(
+ const char *var_name, const char *subprogram_name,
+ dw_frame_t subprogram, dw_frame_t scope) {
+ // Processing of direct variables:
- if(frame_name && strcmp(frame_name, frame->name))
- continue;
+ // If the current subprogram matche the given name:
+ if(subprogram_name==NULL || strcmp(subprogram_name, subprogram->name)==0) {
- start = 0;
- end = xbt_dynar_length(frame->variables) - 1;
+ // Try to find the variable and remove it:
+ int start = 0;
+ int end = xbt_dynar_length(scope->variables) - 1;
+
+ // Dichotomic search:
while(start <= end){
- cursor = (start + end) / 2;
- current_var = (dw_variable_t)xbt_dynar_get_as(frame->variables, cursor, dw_variable_t);
+ int cursor = (start + end) / 2;
+ dw_variable_t current_var = (dw_variable_t)xbt_dynar_get_as(scope->variables, cursor, dw_variable_t);
int compare = strcmp(current_var->name, var_name);
if(compare == 0){
- xbt_dynar_remove_at(frame->variables, cursor, NULL);
+ // Variable found, remove it:
+ xbt_dynar_remove_at(scope->variables, cursor, NULL);
+
+ // and start again:
start = 0;
- end = xbt_dynar_length(frame->variables) - 1;
+ end = xbt_dynar_length(scope->variables) - 1;
}else if(compare < 0){
start = cursor + 1;
}else{
end = cursor - 1;
}
}
+
+ }
+
+ // And recursive processing in nested scopes:
+ unsigned cursor = 0;
+ dw_frame_t nested_scope = NULL;
+ xbt_dynar_foreach(scope->scopes, cursor, nested_scope) {
+ // The new scope may be an inlined subroutine, in this case we want to use its
+ // namespaced name in recursive calls:
+ dw_frame_t nested_subprogram = nested_scope->tag == DW_TAG_inlined_subroutine ? nested_scope : subprogram;
+
+ mc_ignore_local_variable_in_scope(var_name, subprogram_name, nested_subprogram, nested_scope);
+ }
+}
+
+static void MC_ignore_local_variable_in_object(const char *var_name, const char *subprogram_name, mc_object_info_t info) {
+ xbt_dict_cursor_t cursor2;
+ dw_frame_t frame;
+ char* key;
+ xbt_dict_foreach(info->subprograms, cursor2, key, frame) {
+ mc_ignore_local_variable_in_scope(var_name, subprogram_name, frame, frame);
}
}
XBT_DEBUG("Hash local variable %s", variable->name);
- void* variable_address = (void*) mc_dwarf_resolve_locations(&variable->locations, unw_cursor, frame_pointer, NULL);
+ void* variable_address = (void*) mc_dwarf_resolve_locations(
+ &variable->locations, variable->object_info, unw_cursor, frame_pointer, NULL);
dw_type_t type = variable->type;
if(type==NULL) {
mc_hash_value(hash, state, info, variable_address, type);
}
+
+ // TODO, handle nested scopes
}
static void mc_hash_stack(mc_hash_t *hash, mc_snapshot_stack_t stack, mc_hashing_state* state) {
mc_snapshot_t MC_take_snapshot(int num_state);
void MC_restore_snapshot(mc_snapshot_t);
void MC_free_snapshot(mc_snapshot_t);
+
+/** \brief Translate a pointer from process address space to snapshot address space
+ *
+ * The address space contains snapshot of the main/application memory:
+ * this function finds the address in a given snaphot for a given
+ * real/application address.
+ *
+ * For read only memory regions and other regions which are not int the
+ * snapshot, the address is not changed.
+ *
+ * \param addr Application address
+ * \param snapshot The snapshot of interest (if NULL no translation is done)
+ * \return Translated address in the snapshot address space
+ * */
void* mc_translate_address(uintptr_t addr, mc_snapshot_t snapshot);
+
+/** \brief Translate a pointer from the snapshot address space to the application address space
+ *
+ * This is the inverse of mc_translate_address.
+ *
+ * \param addr Address in the snapshot address space
+ * \param snapsot Snapshot of interest (if NULL no translation is done)
+ * \return Translated address in the application address space
+ */
uintptr_t mc_untranslate_address(void* addr, mc_snapshot_t snapshot);
extern xbt_dynar_t mc_checkpoint_ignore;
mc_expression_t locations;
} s_mc_location_list_t, *mc_location_list_t;
-Dwarf_Off mc_dwarf_resolve_location(mc_expression_t expression, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot);
-Dwarf_Off mc_dwarf_resolve_locations(mc_location_list_t locations, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot);
+Dwarf_Off mc_dwarf_resolve_location(mc_expression_t expression, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot);
+Dwarf_Off mc_dwarf_resolve_locations(mc_location_list_t locations, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot);
void mc_dwarf_expression_clear(mc_expression_t expression);
void mc_dwarf_expression_init(mc_expression_t expression, size_t len, Dwarf_Op* ops);
void* address;
size_t start_scope;
+ mc_object_info_t object_info;
}s_dw_variable_t, *dw_variable_t;
struct s_dw_frame{
+ int tag;
char *name;
void *low_pc;
void *high_pc;
s_mc_location_list_t frame_base;
xbt_dynar_t /* <dw_variable_t> */ variables; /* Cannot use dict, there may be several variables with the same name (in different lexical blocks)*/
- unsigned long int start; /* DWARF offset of the subprogram */
- unsigned long int end; /* Dwarf offset of the next sibling */
+ unsigned long int id; /* DWARF offset of the subprogram */
+ xbt_dynar_t /* <dw_frame_t> */ scopes;
+ Dwarf_Off abstract_origin_id;
+ mc_object_info_t object_info;
};
struct s_mc_function_index_item {
void MC_register_variable(mc_object_info_t info, dw_frame_t frame, dw_variable_t variable);
void MC_dwarf_register_non_global_variable(mc_object_info_t info, dw_frame_t frame, dw_variable_t variable);
void MC_dwarf_register_variable(mc_object_info_t info, dw_frame_t frame, dw_variable_t variable);
+
+/** Find the DWARF offset for this ELF object
+ *
+ * An offset is applied to address found in DWARF:
+ *
+ * <ul>
+ * <li>for an executable obejct, addresses are virtual address
+ * (there is no offset) i.e. \f$\text{virtual address} = \{dwarf address}\f$;</li>
+ * <li>for a shared object, the addreses are offset from the begining
+ * of the shared object (the base address of the mapped shared
+ * object must be used as offset
+ * i.e. \f$\text{virtual address} = \text{shared object base address}
+ * + \text{dwarf address}\f$.</li>
+ *
+ */
void* MC_object_base_address(mc_object_info_t info);
/********************************** DWARF **********************************/
#define MC_EXPRESSION_E_STACK_UNDERFLOW 3
#define MC_EXPRESSION_E_MISSING_STACK_CONTEXT 4
#define MC_EXPRESSION_E_MISSING_FRAME_BASE 5
+#define MC_EXPRESSION_E_NO_BASE_ADDRESS 6
typedef struct s_mc_expression_state {
uintptr_t stack[MC_EXPRESSION_STACK_SIZE];
unw_cursor_t* cursor;
void* frame_base;
mc_snapshot_t snapshot;
+ mc_object_info_t object_info;
} s_mc_expression_state_t, *mc_expression_state_t;
int mc_dwarf_execute_expression(size_t n, const Dwarf_Op* ops, mc_expression_state_t state);
-void* mc_find_frame_base(dw_frame_t frame, unw_cursor_t* unw_cursor);
+void* mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info, unw_cursor_t* unw_cursor);
/********************************** Miscellaneous **********************************/
typedef struct s_local_variable{
- char *frame;
+ dw_frame_t subprogram;
unsigned long ip;
char *name;
dw_type_t type;
dw_variable_t var = find_local_variable(subprogram, variable);
assert(var);
- void* frame_base = mc_find_frame_base(subprogram, cursor);
- xbt_assert((void*)mc_dwarf_resolve_locations(&var->locations, cursor, frame_base, NULL) == address,
+ void* frame_base = mc_find_frame_base(subprogram, info, cursor);
+ xbt_assert((void*)mc_dwarf_resolve_locations(&var->locations, info, cursor, frame_base, NULL) == address,
"Bad resolution of local variable %s of %s", variable, function);
}
state->stack_size = 0;
Dwarf_Op ops[15];
- ops[0].atom = DW_OP_addr;
+ ops[0].atom = DW_OP_const8u;
ops[0].number = a;
- ops[1].atom = DW_OP_addr;
+ ops[1].atom = DW_OP_const8u;
ops[1].number = b;
ops[2].atom = op;
assert(state->stack_size==1);
assert(state->stack[state->stack_size-1]==21);
- ops[0].atom = DW_OP_addr;
+ ops[0].atom = DW_OP_const8u;
ops[0].number = a;
assert(mc_dwarf_execute_expression(1, ops, state) == MC_EXPRESSION_OK);
assert(state->stack_size==2);
assert(state->stack[state->stack_size-1]== a + 21);
state->stack_size = 0;
- ops[0].atom = DW_OP_addr;
+ ops[0].atom = DW_OP_const8u;
ops[0].number = a;
ops[1].atom = DW_OP_dup;
ops[2].atom = DW_OP_plus;
assert(state->stack[state->stack_size-1]== a + a);
state->stack_size = 0;
- ops[0].atom = DW_OP_addr;
+ ops[0].atom = DW_OP_const8u;
ops[0].number = a;
- ops[1].atom = DW_OP_addr;
+ ops[1].atom = DW_OP_const8u;
ops[1].number = b;
ops[2].atom = DW_OP_over;
assert(mc_dwarf_execute_expression(3, ops, state) == MC_EXPRESSION_OK);
assert(state->stack[state->stack_size-3]== a);
state->stack_size = 0;
- ops[0].atom = DW_OP_addr;
+ ops[0].atom = DW_OP_const8u;
ops[0].number = a;
- ops[1].atom = DW_OP_addr;
+ ops[1].atom = DW_OP_const8u;
ops[1].number = b;
ops[2].atom = DW_OP_swap;
assert(mc_dwarf_execute_expression(3, ops, state) == MC_EXPRESSION_OK);
uintptr_t foo = 42;
Dwarf_Op ops[60];
- ops[0].atom = DW_OP_addr;
+ ops[0].atom = DW_OP_const8u;
ops[0].number = (Dwarf_Word) &foo;
ops[1].atom = DW_OP_deref;
state->stack_size = 0;