From 5414074587ae221c7c677a3158ccebb617349e1a Mon Sep 17 00:00:00 2001 From: Gabriel Corona Date: Mon, 13 Jan 2014 11:56:17 +0100 Subject: [PATCH] [mc] Use libdw for functions and local variables --- src/mc/mc_checkpoint.c | 1 + src/mc/mc_dwarf.c | 145 +++++++++++++++++++++++++++++++++++------ src/mc/mc_global.c | 64 +++++++++++------- src/mc/mc_private.h | 13 ++-- 4 files changed, 173 insertions(+), 50 deletions(-) diff --git a/src/mc/mc_checkpoint.c b/src/mc/mc_checkpoint.c index 69312bc946..2ffc60ded7 100644 --- a/src/mc/mc_checkpoint.c +++ b/src/mc/mc_checkpoint.c @@ -250,6 +250,7 @@ mc_object_info_t MC_find_object_info(memory_map_t maps, char* name) { result->end_got_plt = NULL; MC_find_object_address(maps, result); MC_get_plt_section(result); + result->location_list = MC_dwarf_get_location_list(result->file_name); MC_dwarf_get_variables(result); return result; } diff --git a/src/mc/mc_dwarf.c b/src/mc/mc_dwarf.c index d547d57410..1a69987860 100644 --- a/src/mc/mc_dwarf.c +++ b/src/mc/mc_dwarf.c @@ -33,11 +33,13 @@ static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit); /** \brief Checks if a given tag is a (known) type tag. */ static int MC_dwarf_tag_type(int tag); -static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit); +static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame); static void MC_dwarf_handle_type_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit); -static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit); -static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit); +static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame); +static void MC_dwarf_handle_variable_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame); +static dw_location_t MC_dwarf_get_expression(Dwarf_Op* expr, size_t len); static Dwarf_Die* MC_dwarf_resolve_die(Dwarf_Die* die, int attribute); +static char* MC_dwarf_at_type(Dwarf_Die* die); const char* MC_dwarf_attrname(int attr) { switch (attr) { @@ -72,6 +74,72 @@ static const char* MC_dwarf_attr_string(Dwarf_Die* die, int attribute) { } } +/** \brief Get the linkage name (DW_AT_linkage_name or DW_AR_MIPS_linkage_name) + * of a DIE. */ +static const char* MC_dwarf_at_linkage_name(Dwarf_Die* die) { + const char* name = MC_dwarf_attr_string(die, DW_AT_linkage_name); + if (!name) + name = MC_dwarf_attr_string(die, DW_AT_MIPS_linkage_name); + return name; +} + +static dw_location_t MC_dwarf_resolve_location_list(mc_object_info_t info, Dwarf_Word offset) { + char *key = bprintf("%ld", (long) offset); + dw_location_t loc = xbt_new0(s_dw_location_t, 1); + loc->type = e_dw_loclist; + loc->location.loclist = (xbt_dynar_t)xbt_dict_get_or_null(info->location_list, key); + if (!loc->location.loclist) + XBT_INFO("Key not found in loclist"); + xbt_free(key); + return loc; +} + +static dw_location_t MC_dwarf_get_location(Dwarf_Die* die, Dwarf_Attribute* attr, mc_object_info_t info) { + int form = dwarf_whatform(attr); + switch (form) { + case DW_FORM_exprloc: + case DW_FORM_block1: // not in the spec + case DW_FORM_block2: + case DW_FORM_block4: + case DW_FORM_block: + { + Dwarf_Op* expr; + size_t len; + if (dwarf_getlocation(attr, &expr, &len)) + xbt_die("Could not read location expression"); + return MC_dwarf_get_expression(expr, len); + } + case DW_FORM_sec_offset: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + { + Dwarf_Word offset; + if (!dwarf_formudata(attr, &offset)) + return MC_dwarf_resolve_location_list(info, offset); + else + xbt_die("Location list not found"); + } + break; + default: + xbt_die("Unexpected form %i list for location in attribute %s of <%p>%s", + form, + MC_dwarf_attrname(attr->code), + (void*) dwarf_dieoffset(die), + MC_dwarf_attr_string(die, DW_AT_name)); + return NULL; + } +} + +static dw_location_t MC_dwarf_at_location(Dwarf_Die* die, int attribute, mc_object_info_t info) { + if(!dwarf_hasattr_integrate(die, attribute)) + return xbt_new0(s_dw_location_t, 1); + + Dwarf_Attribute attr; + dwarf_attr_integrate(die, attribute, &attr); + return MC_dwarf_get_location(die, &attr, info); +} + // Return a new string for the type (NULL if none) static char* MC_dwarf_at_type(Dwarf_Die* die) { Dwarf_Attribute attr; @@ -87,8 +155,21 @@ static char* MC_dwarf_at_type(Dwarf_Die* die) { else return NULL; } +static uint64_t MC_dwarf_attr_addr(Dwarf_Die* die, int attribute) { + Dwarf_Attribute attr; + if(dwarf_attr_integrate(die, attribute, &attr)==NULL) + return 0; + Dwarf_Addr value; + if (dwarf_formaddr(&attr, &value) == 0) + return (uint64_t) value; + else + return 0; +} + static uint64_t MC_dwarf_attr_uint(Dwarf_Die* die, int attribute, uint64_t default_value) { Dwarf_Attribute attr; + if (dwarf_attr_integrate(die, attribute, &attr)==NULL) + return default_value; Dwarf_Word value; return dwarf_formudata(dwarf_attr_integrate(die, attribute, &attr), &value) == 0 ? (uint64_t) value : default_value; } @@ -296,6 +377,10 @@ static void MC_dwarf_add_members(mc_object_info_t info, Dwarf_Die* die, Dwarf_Di MC_dwarf_fill_member_location(type, member, &child); + if (!member->dw_type_id) { + xbt_die("Missing type for member %s of <%p>%s", member->name, type->id, type->name); + } + xbt_dynar_push(type->members, &member); } } @@ -569,6 +654,7 @@ static dw_variable_t MC_die_to_variable(mc_object_info_t info, Dwarf_Die* die, D break; } case DW_FORM_sec_offset: // type loclistptr + case DW_FORM_data4: xbt_die("Do not handle loclist locations yet"); break; default: @@ -579,31 +665,47 @@ static dw_variable_t MC_die_to_variable(mc_object_info_t info, Dwarf_Die* die, D return variable; } -static void MC_dwarf_handle_variable_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) { - dw_variable_t variable = MC_die_to_variable(info, die, unit, NULL); +static void MC_dwarf_handle_variable_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame) { + dw_variable_t variable = MC_die_to_variable(info, die, unit, frame); if(variable==NULL) return; - if(variable->global) - MC_dwarf_register_global_variable(info, variable); - else - xbt_die("Unexpected non global variable <%p>%s", - (void*) dwarf_dieoffset(die), - MC_dwarf_attr_string(die, DW_AT_name) - ); + 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) { + dw_frame_t frame = xbt_new0(s_dw_frame_t, 1); + + frame->start = dwarf_dieoffset(die); + + const char* name = MC_dwarf_at_linkage_name(die); + if (name==NULL) + name = MC_dwarf_attr_string(die, DW_AT_name); + frame->name = xbt_strdup(name); -static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) { + // 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 = (void*) MC_dwarf_attr_addr(die, DW_AT_high_pc); + frame->low_pc = (void*) MC_dwarf_attr_addr(die, DW_AT_low_pc); + frame->frame_base = MC_dwarf_at_location(die, DW_AT_frame_base, info); + frame->end = -1; // This one is now useless: + + // Handle children: + MC_dwarf_handle_children(info, die, unit, frame); + + // Register it: + xbt_dict_set(info->local_variables, frame->name, frame, NULL); +} + +static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame) { Dwarf_Die child; int res; for (res=dwarf_child(die, &child); res==0; res=dwarf_siblingof(&child,&child)) { - MC_dwarf_handle_die(info, &child, unit); + MC_dwarf_handle_die(info, &child, unit, frame); } } -static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) { +static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame) { int tag = dwarf_tag(die); - switch (tag) { case DW_TAG_array_type: case DW_TAG_class_type: @@ -631,16 +733,16 @@ static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die break; case DW_TAG_inlined_subroutine: case DW_TAG_subprogram: - // Skip recursive processing + MC_dwarf_handle_subprogram_die(info, die, unit, frame); return; + // case DW_TAG_formal_parameter: case DW_TAG_variable: - if (MC_USE_LIBDW_NON_FUNCTION_VARIABLES) - MC_dwarf_handle_variable_die(info, die, unit); + MC_dwarf_handle_variable_die(info, die, unit, frame); break; } // Recursive processing of children DIE: - MC_dwarf_handle_children(info, die, unit); + MC_dwarf_handle_children(info, die, unit, frame); } void MC_dwarf_get_variables_libdw(mc_object_info_t info) { @@ -659,7 +761,7 @@ void MC_dwarf_get_variables_libdw(mc_object_info_t info) { while (dwarf_nextcu (dwarf, offset, &next_offset, &length, NULL, NULL, NULL) == 0) { Dwarf_Die die; if(dwarf_offdie(dwarf, offset+length, &die)!=NULL) { - MC_dwarf_handle_die(info, &die, &die); + MC_dwarf_handle_die(info, &die, &die, NULL); } offset = next_offset; } @@ -667,3 +769,4 @@ void MC_dwarf_get_variables_libdw(mc_object_info_t info) { dwarf_end(dwarf); close(fd); } + diff --git a/src/mc/mc_global.c b/src/mc/mc_global.c index 92766b3dbd..e6cd34b9f2 100644 --- a/src/mc/mc_global.c +++ b/src/mc/mc_global.c @@ -171,7 +171,7 @@ void dw_variable_free(dw_variable_t v){ } } -static void dw_variable_free_voidp(void *t){ +void dw_variable_free_voidp(void *t){ dw_variable_free((dw_variable_t) * (void **) t); } @@ -198,6 +198,7 @@ void MC_free_object_info(mc_object_info_t* info) { xbt_dict_free(&(*info)->local_variables); xbt_dynar_free(&(*info)->global_variables); xbt_dict_free(&(*info)->types); + xbt_dict_free(&((*info)->location_list)); xbt_free(info); info = NULL; } @@ -345,7 +346,7 @@ static dw_location_t MC_dwarf_get_location(xbt_dict_t location_list, char *expr) * @return A map from the offset in the list (in hexadecimal string) * into a location list (dynar of dw_location_entry_t). */ -static xbt_dict_t MC_dwarf_get_location_list(const char *elf_file){ +xbt_dict_t MC_dwarf_get_location_list(const char *elf_file){ char *command = bprintf("LANG=C objdump -Wo %s", elf_file); @@ -532,15 +533,23 @@ static int MC_dwarf_get_variable_index(xbt_dynar_t variables, char* var, void *a } +void MC_dwarf_get_variables_legacy(mc_object_info_t info); + /** \brief Fill DWARf debug infomations (types, frames, variables ...). */ void MC_dwarf_get_variables(mc_object_info_t info) { - if(MC_USE_LIBDW_TYPES) + if (MC_USE_LIBDW) { MC_dwarf_get_variables_libdw(info); + MC_post_process_types(info); + } else { + MC_dwarf_get_variables_legacy(info); + } +} + +void MC_dwarf_get_variables_legacy(mc_object_info_t info) { + mc_object_info_t result = info; const char *elf_file = info->file_name; - xbt_dict_t location_list = MC_dwarf_get_location_list(elf_file); - char *command = bprintf("LANG=C objdump -Wi %s", elf_file); FILE *fp = popen(command, "r"); @@ -561,7 +570,7 @@ void MC_dwarf_get_variables(mc_object_info_t info) { size_t n = 0; int global_variable = 0, parent = 0, new_frame = 0, new_variable = 1, size = 0, is_pointer = 0, struct_decl = 0, member_end = 0, - enumeration_size = 0, subrange = 0, union_decl = 0, offset = 0, index = 0; + enumeration_size = 0, subrange = 0, union_decl = 0, offset = 0; xbt_dynar_t split = NULL, split2 = NULL; @@ -664,7 +673,7 @@ void MC_dwarf_get_variables(mc_object_info_t info) { if(strcmp(location_type, "list)") == 0){ /* Search location in location list */ - frame->frame_base = MC_dwarf_get_location(location_list, xbt_dynar_get_as(split, 3, char *)); + frame->frame_base = MC_dwarf_get_location(info->location_list, xbt_dynar_get_as(split, 3, char *)); }else{ @@ -720,11 +729,6 @@ void MC_dwarf_get_variables(mc_object_info_t info) { the list of variables of the frame (local variable) or to the list of global variables (global variables). */ - if (MC_USE_LIBDW_NON_FUNCTION_VARIABLES && parent==1) { - read = xbt_getline(&line, &n, fp); - continue; - } - dw_variable_t var = NULL; parent_value = strdup(xbt_dynar_get_as(split, 0, char *)); @@ -790,7 +794,7 @@ void MC_dwarf_get_variables(mc_object_info_t info) { location_type = xbt_dynar_get_as(split, xbt_dynar_length(split) - 1, char *); if(strcmp(location_type, "list)") == 0){ /* Search location in location list */ - var->address.location = MC_dwarf_get_location(location_list, xbt_dynar_get_as(split, 3, char *)); + var->address.location = MC_dwarf_get_location(info->location_list, xbt_dynar_get_as(split, 3, char *)); }else{ xbt_str_strip_spaces(line); split2 = xbt_str_split(line, "("); @@ -856,16 +860,12 @@ void MC_dwarf_get_variables(mc_object_info_t info) { if(new_variable == 1){ + var->global = global_variable; + var->type_origin = strdup(type_origin); if(!global_variable){ variable_frame = xbt_dict_get_or_null(*local_variables, current_frame); - var->type_origin = strdup(type_origin); - var->global = 0; - index = MC_dwarf_get_variable_index(variable_frame->variables, var->name, NULL); - if(index != -1) - xbt_dynar_insert_at(variable_frame->variables, index, &var); + MC_dwarf_register_non_global_variable(info, variable_frame, var); }else{ - var->type_origin = strdup(type_origin); - var->global = 1; MC_dwarf_register_global_variable(info, var); } @@ -923,13 +923,13 @@ void MC_dwarf_get_variables(mc_object_info_t info) { } - }else if(!MC_USE_LIBDW_TYPES&&(strcmp(node_type, "(DW_TAG_base_type)") == 0 + }else if(strcmp(node_type, "(DW_TAG_base_type)") == 0 || strcmp(node_type, "(DW_TAG_enumeration_type)") == 0 || strcmp(node_type, "(DW_TAG_typedef)") == 0 || strcmp(node_type, "(DW_TAG_const_type)") == 0 || strcmp(node_type, "(DW_TAG_subroutine_type)") == 0 || strcmp(node_type, "(DW_TAG_volatile_type)") == 0 - || (is_pointer = !strcmp(node_type, "(DW_TAG_pointer_type)")))){ + || (is_pointer = !strcmp(node_type, "(DW_TAG_pointer_type)"))){ /* Create the and add it to the types dictionnary */ @@ -1282,11 +1282,8 @@ void MC_dwarf_get_variables(mc_object_info_t info) { xbt_dict_free(&subprograms_origin); xbt_free(line); xbt_free(command); - xbt_dict_free(&location_list); pclose(fp); - - MC_post_process_types(info); } void MC_dwarf_register_global_variable(mc_object_info_t info, dw_variable_t variable) { @@ -1296,6 +1293,23 @@ void MC_dwarf_register_global_variable(mc_object_info_t info, dw_variable_t vari // TODO, else ? } +void MC_dwarf_register_non_global_variable(mc_object_info_t info, dw_frame_t frame, dw_variable_t variable) { + xbt_assert(frame, "Frame is NULL"); + int index = MC_dwarf_get_variable_index(frame->variables, variable->name, NULL); + if (index != -1) + xbt_dynar_insert_at(frame->variables, index, &variable); + // TODO, else ? +} + +void MC_dwarf_register_variable(mc_object_info_t info, dw_frame_t frame, dw_variable_t variable) { + if(variable->global) + MC_dwarf_register_global_variable(info, variable); + else if(frame==NULL) + xbt_die("No frame for this local variable"); + else + MC_dwarf_register_non_global_variable(info, frame, variable); +} + static void MC_post_process_array_size(mc_object_info_t info, dw_type_t type) { xbt_assert(type->dw_type_id, "No base type for array <%p>%s", type->id, type->name); dw_type_t subtype = xbt_dict_get_or_null(info->types, type->dw_type_id); diff --git a/src/mc/mc_private.h b/src/mc/mc_private.h index 5984272b60..0498fbb1de 100644 --- a/src/mc/mc_private.h +++ b/src/mc/mc_private.h @@ -330,12 +330,14 @@ typedef struct s_mc_object_info { xbt_dict_t local_variables; // xbt_dict_t xbt_dynar_t global_variables; // xbt_dynar_t xbt_dict_t types; // xbt_dict_t + xbt_dict_t location_list; // Location list (probably temporary) } s_mc_object_info_t, *mc_object_info_t; mc_object_info_t MC_new_object_info(void); mc_object_info_t MC_find_object_info(memory_map_t maps, char* name); void MC_free_object_info(mc_object_info_t* p); +xbt_dict_t MC_dwarf_get_location_list(const char *elf_file); void MC_dwarf_get_variables(mc_object_info_t info); void MC_dwarf_get_variables_libdw(mc_object_info_t info); const char* MC_dwarf_attrname(int attr); @@ -417,8 +419,6 @@ typedef struct s_dw_variable{ }address; }s_dw_variable_t, *dw_variable_t; -void MC_dwarf_register_global_variable(mc_object_info_t info, dw_variable_t variable); - typedef struct s_dw_frame{ char *name; void *low_pc; @@ -431,6 +431,12 @@ typedef struct s_dw_frame{ void dw_type_free(dw_type_t t); void dw_variable_free(dw_variable_t v); +void dw_variable_free_voidp(void *t); + +void MC_dwarf_register_global_variable(mc_object_info_t info, dw_variable_t variable); +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); /********************************** DWARF **********************************/ @@ -447,8 +453,7 @@ typedef struct s_local_variable{ int region; }s_local_variable_t, *local_variable_t; -#define MC_USE_LIBDW_TYPES 1 -#define MC_USE_LIBDW_NON_FUNCTION_VARIABLES 1 +#define MC_USE_LIBDW (getenv("MC_USE_OBJDUMP") == NULL) #endif -- 2.20.1