diff options
Diffstat (limited to 'usr/src/lib/libdwarf/common/dwarf_groups.c')
-rw-r--r-- | usr/src/lib/libdwarf/common/dwarf_groups.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/usr/src/lib/libdwarf/common/dwarf_groups.c b/usr/src/lib/libdwarf/common/dwarf_groups.c new file mode 100644 index 0000000000..57eca96df6 --- /dev/null +++ b/usr/src/lib/libdwarf/common/dwarf_groups.c @@ -0,0 +1,391 @@ +/* + Copyright (C) 2017-2018 David Anderson. All Rights Reserved. + + This program is free software; you can redistribute it + and/or modify it under the terms of version 2.1 of the + GNU Lesser General Public License as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General + Public License along with this program; if not, write the + Free Software Foundation, Inc., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. + +*/ + +#include "config.h" +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif /* HAVE_STDLIB_H */ +#ifdef HAVE_STDINT_H +#include <stdint.h> /* For uintptr_t */ +#endif /* HAVE_STDINT_H */ +#include "dwarf_incl.h" +#include "dwarf_error.h" +#include "dwarf_tsearch.h" + +#define TRUE 1 +#define FALSE 0 + +#define HASHSEARCH + +/* It has not escaped our attention that the section-group + tsearch hash table could + be replaced by a simple array with space for each possible + section number, each element being the group number. + This would be much simpler than what follows here. */ + +/* Each section number can appear in at most one record in the hash + because each section belongs in only one group. + Each group number appears as often as appropriate. */ + +struct Dwarf_Group_Map_Entry_s { + unsigned gm_key; /* section number */ + unsigned gm_group_number; /* What group number is. */ + + /* The name is from static storage or from elf, + so there is nothing to free on record delete. */ + const char * gm_section_name; +}; + +static void * +grp_make_entry(unsigned section, unsigned group,const char *name) +{ + struct Dwarf_Group_Map_Entry_s *e = 0; + e = calloc(1,sizeof(struct Dwarf_Group_Map_Entry_s)); + if(e) { + e->gm_key = section; + e->gm_group_number = group; + e->gm_section_name = name; + } + return e; +} + + +static DW_TSHASHTYPE +grp_data_hashfunc(const void *keyp) +{ + const struct Dwarf_Group_Map_Entry_s * enp = keyp; + DW_TSHASHTYPE hashv = 0; + + hashv = enp->gm_key; + return hashv; +} + +static int +grp_compare_function(const void *l, const void *r) +{ + const struct Dwarf_Group_Map_Entry_s * lp = l; + const struct Dwarf_Group_Map_Entry_s * rp = r; + + if (lp->gm_key < rp->gm_key) { + return -1; + } + if (lp->gm_key > rp->gm_key) { + return 1; + } + + /* match. */ + return 0; +} + +static void +_dwarf_grp_destroy_free_node(void*nodep) +{ + struct Dwarf_Group_Map_Entry_s * enp = nodep; + free(enp); + return; +} + +int +_dwarf_insert_in_group_map(Dwarf_Debug dbg, + unsigned groupnum, + unsigned section_index, + const char *name, + Dwarf_Error * error) +{ + struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers; + + void *entry2 = 0; + struct Dwarf_Group_Map_Entry_s * entry3 = 0; + + if (!grp->gd_map) { + /* Number of sections is a kind of decent guess + as to how much space would be useful. */ + dwarf_initialize_search_hash(&grp->gd_map, + grp_data_hashfunc,grp->gd_number_of_sections); + if (!grp->gd_map) { + /* It's really an error I suppose. */ + return DW_DLV_NO_ENTRY; + } + } + entry3 = grp_make_entry(section_index,groupnum,name); + if (!entry3) { + _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_ALLOC); + return DW_DLV_ERROR; + } + entry2 = dwarf_tsearch(entry3,&grp->gd_map,grp_compare_function); + if (!entry2) { + free(entry3); + _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_ALLOC); + return DW_DLV_ERROR; + } else { + struct Dwarf_Group_Map_Entry_s *re = 0; + re = *(struct Dwarf_Group_Map_Entry_s **)entry2; + if (re != entry3) { + free(entry3); + _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_DUPLICATE); + return DW_DLV_ERROR; + } else { + ++grp->gd_map_entry_count; + /* OK. Added. Fall thru */ + } + } + return DW_DLV_OK; +} + +int +_dwarf_section_get_target_group_from_map(Dwarf_Debug dbg, + unsigned obj_section_index, + unsigned * groupnumber_out, + UNUSEDARG Dwarf_Error * error) +{ + struct Dwarf_Group_Map_Entry_s entry; + struct Dwarf_Group_Map_Entry_s *entry2; + struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers; + + if (!grp->gd_map) { + return DW_DLV_NO_ENTRY; + } + entry.gm_key = obj_section_index; + entry.gm_group_number = 0; /* FAKE */ + entry.gm_section_name = ""; /* FAKE */ + + entry2 = dwarf_tfind(&entry, &grp->gd_map,grp_compare_function); + if (entry2) { + struct Dwarf_Group_Map_Entry_s *e2 = + *(struct Dwarf_Group_Map_Entry_s **)entry2;; + *groupnumber_out = e2->gm_group_number; + return DW_DLV_OK; + } + return DW_DLV_NO_ENTRY; +} + + + + +/* New May 2017. So users can find out what groups (dwo or COMDAT) + are in the object and how much to allocate so one can get the + group-section map data. */ +int dwarf_sec_group_sizes(Dwarf_Debug dbg, + Dwarf_Unsigned * section_count_out, + Dwarf_Unsigned * group_count_out, + Dwarf_Unsigned * selected_group_out, + Dwarf_Unsigned * map_entry_count_out, + UNUSEDARG Dwarf_Error * error) +{ + struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers; + + *section_count_out = grp->gd_number_of_sections; + *group_count_out = grp->gd_number_of_groups; + *selected_group_out = dbg->de_groupnumber; + *map_entry_count_out = grp->gd_map_entry_count; + return DW_DLV_OK; +} + + +static Dwarf_Unsigned map_reccount = 0; +static struct temp_map_struc_s { + Dwarf_Unsigned section; + Dwarf_Unsigned group; + const char *name; +} *temp_map_data; + + +static void +grp_walk_map(const void *nodep, + const DW_VISIT which, + UNUSEDARG const int depth) +{ + struct Dwarf_Group_Map_Entry_s *re = 0; + + re = *(struct Dwarf_Group_Map_Entry_s **)nodep; + if (which == dwarf_postorder || which == dwarf_endorder) { + return; + } + temp_map_data[map_reccount].group = re->gm_group_number; + temp_map_data[map_reccount].section = re->gm_key; + temp_map_data[map_reccount].name = re->gm_section_name; + map_reccount += 1; +} + +/* Looks better sorted by group then sec num. */ +static int +map_sort_compar(const void*l, const void*r) +{ + struct temp_map_struc_s *lv = (struct temp_map_struc_s *)l; + struct temp_map_struc_s *rv = (struct temp_map_struc_s *)r; + + if (lv->group < rv->group) { + return -1; + } + if (lv->group > rv->group) { + return 1; + } + if (lv->section < rv->section) { + return -1; + } + if (lv->section > rv->section) { + return 1; + } + /* Should never get here! */ + return 0; + +} + +/* New May 2017. Reveals the map between group numbers + and section numbers. + Caller must allocate the arrays with space for 'map_entry_count' + values and this function fills in the array entries. + Output ordered by group number and section number. + */ +int dwarf_sec_group_map(Dwarf_Debug dbg, + Dwarf_Unsigned map_entry_count, + Dwarf_Unsigned * group_numbers_array, + Dwarf_Unsigned * sec_numbers_array, + const char ** sec_names_array, + Dwarf_Error * error) +{ + Dwarf_Unsigned i = 0; + struct Dwarf_Group_Data_s *grp = 0; + + if(temp_map_data) { + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + map_reccount = 0; + grp = &dbg->de_groupnumbers; + if (map_entry_count < grp->gd_map_entry_count) { + _dwarf_error(dbg,error,DW_DLE_GROUP_COUNT_ERROR); + return DW_DLV_ERROR; + } + temp_map_data = calloc(map_entry_count,sizeof(struct temp_map_struc_s)); + if(!temp_map_data) { + _dwarf_error(dbg,error,DW_DLE_GROUP_MAP_ALLOC); + return DW_DLV_ERROR; + } + dwarf_twalk(grp->gd_map,grp_walk_map); + if (map_reccount != grp->gd_map_entry_count) { + /* Impossible. */ + _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR); + return DW_DLV_ERROR; + } + + qsort(temp_map_data,map_reccount,sizeof(struct temp_map_struc_s), + map_sort_compar); + for (i =0 ; i < map_reccount; ++i) { + sec_numbers_array[i] = temp_map_data[i].section; + group_numbers_array[i] = temp_map_data[i].group; + sec_names_array[i] = temp_map_data[i].name; + } + free(temp_map_data); + map_reccount = 0; + temp_map_data = 0; + return DW_DLV_OK; +} + +static const char *dwo_secnames[] = { +".debug_info.dwo", +".debug_types.dwo", +".debug_abbrev.dwo", +".debug_line.dwo", +".debug_loc.dwo", +".debug_str.dwo", +".debug_loclists.dwo", +".debug_rnglists.dwo", +".debug_str_offsets.dwo", +".debug_macro.dwo", +".debug_cu_index", +".debug_tu_index", +0 }; + +/* Assumption: dwo sections are never in a COMDAT group + (groupnumber >2) + and by definition here are never group 1. + Assumption: the map of COMDAT groups (not necessarily all + sections, but at least all COMDAT) is complete. */ +int +_dwarf_dwo_groupnumber_given_name( + const char *name, + unsigned *grpnum_out) +{ + const char **s = 0; + + for (s = dwo_secnames; *s; s++) { + if(!strcmp(name,*s)) { + *grpnum_out = DW_GROUPNUMBER_DWO; + return DW_DLV_OK; + } + } + return DW_DLV_NO_ENTRY; +} + +static unsigned target_group = 0; +static int found_name_in_group = 0; +const char *lookfor_name = 0; + +static void +grp_walk_for_name(const void *nodep, + const DW_VISIT which, + UNUSEDARG const int depth) +{ + struct Dwarf_Group_Map_Entry_s *re = 0; + + re = *(struct Dwarf_Group_Map_Entry_s **)nodep; + if (which == dwarf_postorder || which == dwarf_endorder) { + return; + } + if (re->gm_group_number == target_group) { + if(!strcmp(lookfor_name,re->gm_section_name)) { + found_name_in_group = TRUE; + } + } +} + + +/* returns TRUE or FALSE */ +int +_dwarf_section_in_group_by_name(Dwarf_Debug dbg, + const char * scn_name, + unsigned groupnum) +{ + struct Dwarf_Group_Data_s *grp = 0; + + grp = &dbg->de_groupnumbers; + found_name_in_group = FALSE; + target_group = groupnum; + lookfor_name = scn_name; + dwarf_twalk(grp->gd_map,grp_walk_for_name); + return found_name_in_group; +} + +void +_dwarf_destroy_group_map(Dwarf_Debug dbg) +{ + dwarf_tdestroy(dbg->de_groupnumbers.gd_map,_dwarf_grp_destroy_free_node); + dbg->de_groupnumbers.gd_map = 0; +} |