xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_groups.c (revision 3cac7b0d73edf3f2674ad0f64d1fff3d2e59ae8c)
1 /*
2   Copyright (C) 2017-2018 David Anderson. All Rights Reserved.
3 
4   This program is free software; you can redistribute it
5   and/or modify it under the terms of version 2.1 of the
6   GNU Lesser General Public License as published by the Free
7   Software Foundation.
8 
9   This program is distributed in the hope that it would be
10   useful, but WITHOUT ANY WARRANTY; without even the implied
11   warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12   PURPOSE.
13 
14   Further, this software is distributed without any warranty
15   that it is free of the rightful claim of any third person
16   regarding infringement or the like.  Any license provided
17   herein, whether implied or otherwise, applies only to this
18   software file.  Patent licenses, if any, provided herein
19   do not apply to combinations of this program with other
20   software, or any other product whatsoever.
21 
22   You should have received a copy of the GNU Lesser General
23   Public License along with this program; if not, write the
24   Free Software Foundation, Inc., 51 Franklin Street - Fifth
25   Floor, Boston MA 02110-1301, USA.
26 
27 */
28 
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif /* HAVE_STDLIB_H */
34 #ifdef HAVE_STDINT_H
35 #include <stdint.h> /* For uintptr_t */
36 #endif /* HAVE_STDINT_H */
37 #include "dwarf_incl.h"
38 #include "dwarf_error.h"
39 #include "dwarf_tsearch.h"
40 
41 #define TRUE  1
42 #define FALSE 0
43 
44 #define HASHSEARCH
45 
46 /*  It has not escaped our attention that the section-group
47     tsearch hash table could
48     be replaced by a simple array with space for each possible
49     section number, each element being the group number.
50     This would be much simpler than what follows here. */
51 
52 /*  Each section number can appear in at most one record in the hash
53     because each section belongs in only one group.
54     Each group number appears as often as appropriate. */
55 
56 struct Dwarf_Group_Map_Entry_s {
57     unsigned  gm_key;  /* section number */
58     unsigned  gm_group_number; /* What group number is. */
59 
60     /*  The name is from static storage or from elf,
61         so there is nothing to free on record delete. */
62     const char * gm_section_name;
63 };
64 
65 static void *
66 grp_make_entry(unsigned section, unsigned group,const char *name)
67 {
68     struct Dwarf_Group_Map_Entry_s *e = 0;
69     e = calloc(1,sizeof(struct Dwarf_Group_Map_Entry_s));
70     if(e) {
71         e->gm_key =    section;
72         e->gm_group_number = group;
73         e->gm_section_name = name;
74     }
75     return e;
76 }
77 
78 
79 static DW_TSHASHTYPE
80 grp_data_hashfunc(const void *keyp)
81 {
82     const struct Dwarf_Group_Map_Entry_s * enp = keyp;
83     DW_TSHASHTYPE hashv = 0;
84 
85     hashv = enp->gm_key;
86     return hashv;
87 }
88 
89 static int
90 grp_compare_function(const void *l, const void *r)
91 {
92     const struct Dwarf_Group_Map_Entry_s * lp = l;
93     const struct Dwarf_Group_Map_Entry_s * rp = r;
94 
95     if (lp->gm_key < rp->gm_key) {
96         return -1;
97     }
98     if (lp->gm_key > rp->gm_key) {
99         return 1;
100     }
101 
102     /* match. */
103     return 0;
104 }
105 
106 static void
107 _dwarf_grp_destroy_free_node(void*nodep)
108 {
109     struct Dwarf_Group_Map_Entry_s * enp = nodep;
110     free(enp);
111     return;
112 }
113 
114 int
115 _dwarf_insert_in_group_map(Dwarf_Debug dbg,
116     unsigned groupnum,
117     unsigned section_index,
118     const char *name,
119     Dwarf_Error * error)
120 {
121     struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers;
122 
123     void *entry2 = 0;
124     struct Dwarf_Group_Map_Entry_s * entry3 = 0;
125 
126     if (!grp->gd_map) {
127         /*  Number of sections is a kind of decent guess
128             as to how much space would be useful. */
129         dwarf_initialize_search_hash(&grp->gd_map,
130             grp_data_hashfunc,grp->gd_number_of_sections);
131         if (!grp->gd_map) {
132             /*  It's really an error I suppose. */
133             return DW_DLV_NO_ENTRY;
134         }
135     }
136     entry3 = grp_make_entry(section_index,groupnum,name);
137     if (!entry3) {
138         _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_ALLOC);
139         return DW_DLV_ERROR;
140     }
141     entry2 = dwarf_tsearch(entry3,&grp->gd_map,grp_compare_function);
142     if (!entry2) {
143         free(entry3);
144         _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_ALLOC);
145         return DW_DLV_ERROR;
146     } else {
147         struct Dwarf_Group_Map_Entry_s *re = 0;
148         re = *(struct Dwarf_Group_Map_Entry_s **)entry2;
149         if (re != entry3) {
150             free(entry3);
151             _dwarf_error(dbg, error, DW_DLE_GROUP_MAP_DUPLICATE);
152             return DW_DLV_ERROR;
153         } else {
154             ++grp->gd_map_entry_count;
155             /* OK. Added. Fall thru */
156         }
157     }
158     return DW_DLV_OK;
159 }
160 
161 int
162 _dwarf_section_get_target_group_from_map(Dwarf_Debug dbg,
163     unsigned   obj_section_index,
164     unsigned * groupnumber_out,
165     UNUSEDARG Dwarf_Error    * error)
166 {
167     struct Dwarf_Group_Map_Entry_s entry;
168     struct Dwarf_Group_Map_Entry_s *entry2;
169     struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers;
170 
171     if (!grp->gd_map) {
172         return DW_DLV_NO_ENTRY;
173     }
174     entry.gm_key = obj_section_index;
175     entry.gm_group_number = 0; /* FAKE */
176     entry.gm_section_name = ""; /* FAKE */
177 
178     entry2 = dwarf_tfind(&entry, &grp->gd_map,grp_compare_function);
179     if (entry2) {
180         struct Dwarf_Group_Map_Entry_s *e2 =
181             *(struct Dwarf_Group_Map_Entry_s **)entry2;;
182         *groupnumber_out = e2->gm_group_number;
183         return DW_DLV_OK;
184     }
185     return DW_DLV_NO_ENTRY;
186 }
187 
188 
189 
190 
191 /*  New May 2017.  So users can find out what groups (dwo or COMDAT)
192     are in the object and how much to allocate so one can get the
193     group-section map data. */
194 int dwarf_sec_group_sizes(Dwarf_Debug dbg,
195     Dwarf_Unsigned * section_count_out,
196     Dwarf_Unsigned * group_count_out,
197     Dwarf_Unsigned * selected_group_out,
198     Dwarf_Unsigned * map_entry_count_out,
199     UNUSEDARG Dwarf_Error    * error)
200 {
201     struct Dwarf_Group_Data_s *grp = &dbg->de_groupnumbers;
202 
203     *section_count_out   = grp->gd_number_of_sections;
204     *group_count_out     = grp->gd_number_of_groups;
205     *selected_group_out  = dbg->de_groupnumber;
206     *map_entry_count_out = grp->gd_map_entry_count;
207     return DW_DLV_OK;
208 }
209 
210 
211 static Dwarf_Unsigned map_reccount = 0;
212 static struct temp_map_struc_s {
213     Dwarf_Unsigned section;
214     Dwarf_Unsigned group;
215     const char *name;
216 } *temp_map_data;
217 
218 
219 static void
220 grp_walk_map(const void *nodep,
221     const DW_VISIT which,
222     UNUSEDARG const int depth)
223 {
224     struct Dwarf_Group_Map_Entry_s *re = 0;
225 
226     re = *(struct Dwarf_Group_Map_Entry_s **)nodep;
227     if (which == dwarf_postorder || which == dwarf_endorder) {
228         return;
229     }
230     temp_map_data[map_reccount].group   = re->gm_group_number;
231     temp_map_data[map_reccount].section = re->gm_key;
232     temp_map_data[map_reccount].name = re->gm_section_name;
233     map_reccount += 1;
234 }
235 
236 /* Looks better sorted by group then sec num. */
237 static int
238 map_sort_compar(const void*l, const void*r)
239 {
240     struct temp_map_struc_s *lv = (struct temp_map_struc_s *)l;
241     struct temp_map_struc_s *rv = (struct temp_map_struc_s *)r;
242 
243     if (lv->group < rv->group) {
244         return -1;
245     }
246     if (lv->group > rv->group) {
247         return 1;
248     }
249     if (lv->section < rv->section) {
250         return -1;
251     }
252     if (lv->section > rv->section) {
253         return 1;
254     }
255     /* Should never get here! */
256     return 0;
257 
258 }
259 
260 /*  New May 2017. Reveals the map between group numbers
261     and section numbers.
262     Caller must allocate the arrays with space for 'map_entry_count'
263     values and this function fills in the array entries.
264     Output ordered by group number and section number.
265     */
266 int dwarf_sec_group_map(Dwarf_Debug dbg,
267     Dwarf_Unsigned   map_entry_count,
268     Dwarf_Unsigned * group_numbers_array,
269     Dwarf_Unsigned * sec_numbers_array,
270     const char    ** sec_names_array,
271     Dwarf_Error    * error)
272 {
273     Dwarf_Unsigned i = 0;
274     struct Dwarf_Group_Data_s *grp = 0;
275 
276     if(temp_map_data) {
277         _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR);
278         return DW_DLV_ERROR;
279     }
280     map_reccount = 0;
281     grp = &dbg->de_groupnumbers;
282     if (map_entry_count < grp->gd_map_entry_count) {
283         _dwarf_error(dbg,error,DW_DLE_GROUP_COUNT_ERROR);
284         return DW_DLV_ERROR;
285     }
286     temp_map_data = calloc(map_entry_count,sizeof(struct temp_map_struc_s));
287     if(!temp_map_data) {
288         _dwarf_error(dbg,error,DW_DLE_GROUP_MAP_ALLOC);
289         return DW_DLV_ERROR;
290     }
291     dwarf_twalk(grp->gd_map,grp_walk_map);
292     if (map_reccount != grp->gd_map_entry_count) {
293         /*  Impossible. */
294         _dwarf_error(dbg,error,DW_DLE_GROUP_INTERNAL_ERROR);
295         return DW_DLV_ERROR;
296     }
297 
298     qsort(temp_map_data,map_reccount,sizeof(struct temp_map_struc_s),
299         map_sort_compar);
300     for (i =0 ; i < map_reccount; ++i) {
301         sec_numbers_array[i] = temp_map_data[i].section;
302         group_numbers_array[i] = temp_map_data[i].group;
303         sec_names_array[i] = temp_map_data[i].name;
304     }
305     free(temp_map_data);
306     map_reccount = 0;
307     temp_map_data = 0;
308     return DW_DLV_OK;
309 }
310 
311 static const char *dwo_secnames[] = {
312 ".debug_info.dwo",
313 ".debug_types.dwo",
314 ".debug_abbrev.dwo",
315 ".debug_line.dwo",
316 ".debug_loc.dwo",
317 ".debug_str.dwo",
318 ".debug_loclists.dwo",
319 ".debug_rnglists.dwo",
320 ".debug_str_offsets.dwo",
321 ".debug_macro.dwo",
322 ".debug_cu_index",
323 ".debug_tu_index",
324 0 };
325 
326 /*  Assumption: dwo sections are never in a COMDAT group
327     (groupnumber >2)
328     and by definition here are never group 1.
329     Assumption: the map of COMDAT groups (not necessarily all
330     sections, but at least all COMDAT) is complete. */
331 int
332 _dwarf_dwo_groupnumber_given_name(
333     const char *name,
334     unsigned *grpnum_out)
335 {
336     const char **s = 0;
337 
338     for (s = dwo_secnames; *s; s++) {
339         if(!strcmp(name,*s)) {
340             *grpnum_out = DW_GROUPNUMBER_DWO;
341             return DW_DLV_OK;
342         }
343     }
344     return DW_DLV_NO_ENTRY;
345 }
346 
347 static unsigned target_group = 0;
348 static int found_name_in_group = 0;
349 const char *lookfor_name = 0;
350 
351 static void
352 grp_walk_for_name(const void *nodep,
353     const DW_VISIT which,
354     UNUSEDARG const int depth)
355 {
356     struct Dwarf_Group_Map_Entry_s *re = 0;
357 
358     re = *(struct Dwarf_Group_Map_Entry_s **)nodep;
359     if (which == dwarf_postorder || which == dwarf_endorder) {
360         return;
361     }
362     if (re->gm_group_number == target_group) {
363         if(!strcmp(lookfor_name,re->gm_section_name)) {
364             found_name_in_group = TRUE;
365         }
366     }
367 }
368 
369 
370 /* returns TRUE or FALSE */
371 int
372 _dwarf_section_in_group_by_name(Dwarf_Debug dbg,
373     const char * scn_name,
374     unsigned groupnum)
375 {
376     struct Dwarf_Group_Data_s *grp = 0;
377 
378     grp = &dbg->de_groupnumbers;
379     found_name_in_group = FALSE;
380     target_group = groupnum;
381     lookfor_name = scn_name;
382     dwarf_twalk(grp->gd_map,grp_walk_for_name);
383     return found_name_in_group;
384 }
385 
386 void
387 _dwarf_destroy_group_map(Dwarf_Debug dbg)
388 {
389     dwarf_tdestroy(dbg->de_groupnumbers.gd_map,_dwarf_grp_destroy_free_node);
390     dbg->de_groupnumbers.gd_map = 0;
391 }
392