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 *
grp_make_entry(unsigned section,unsigned group,const char * name)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
grp_data_hashfunc(const void * keyp)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
grp_compare_function(const void * l,const void * r)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
_dwarf_grp_destroy_free_node(void * nodep)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
_dwarf_insert_in_group_map(Dwarf_Debug dbg,unsigned groupnum,unsigned section_index,const char * name,Dwarf_Error * error)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
_dwarf_section_get_target_group_from_map(Dwarf_Debug dbg,unsigned obj_section_index,unsigned * groupnumber_out,UNUSEDARG Dwarf_Error * error)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. */
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)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
grp_walk_map(const void * nodep,const DW_VISIT which,UNUSEDARG const int depth)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
map_sort_compar(const void * l,const void * r)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 */
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)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
_dwarf_dwo_groupnumber_given_name(const char * name,unsigned * grpnum_out)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
grp_walk_for_name(const void * nodep,const DW_VISIT which,UNUSEDARG const int depth)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
_dwarf_section_in_group_by_name(Dwarf_Debug dbg,const char * scn_name,unsigned groupnum)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
_dwarf_destroy_group_map(Dwarf_Debug dbg)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