xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_xu_index.c (revision 28ab0ca48b3e331cbbb231b1c8325f9f24f9af95)
1 /*
2   Copyright (C) 2014-2019 David Anderson. All Rights Reserved.
3 
4   This program is free software; you can redistribute it and/or modify it
5   under the terms of version 2.1 of the GNU Lesser General Public License
6   as published by the Free Software Foundation.
7 
8   This program is distributed in the hope that it would be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 
12   Further, this software is distributed without any warranty that it is
13   free of the rightful claim of any third person regarding infringement
14   or the like.  Any license provided herein, whether implied or
15   otherwise, applies only to this software file.  Patent licenses, if
16   any, provided herein do not apply to combinations of this program with
17   other software, or any other product whatsoever.
18 
19   You should have received a copy of the GNU Lesser General Public
20   License along with this program; if not, write the Free Software
21   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
22   USA.
23 
24 */
25 
26 /*  The file and functions have  'xu' because
27     the .debug_cu_index and .debug_tu_index
28     sections have the same layout and this deals with both.
29 
30     This is DebugFission, part of DWARF5.
31 
32     It allows fast section access in a .dwp object file
33     with debug-information to locate offsets
34     within and between sections.
35 
36     See the DWARF5 Standard: section 7.3.5 and
37     examples in Appendix F.3.
38 
39     A note about the index field from the index table.
40     See DWARF5 7.5.3.5.
41     The index table array index values are [1,S)
42     These value ae used to call functions requestiong
43     values from the offset table and size table.
44 
45     Inside the code in this file we subtract 1 and use
46     0 origin as that is how we arranged the
47     table access here.
48     A zero in the index table is an unused signature
49     table signature and unused index.
50 
51     By subtracting one and arranging things properly
52     in the offset table and size table we can refer
53     to the tables in an identical simple fashion
54     These tables are thus U rows and N columns.
55     Technically the Offset table physically
56     row zero is a separate set of numbers translating
57     the column number to a DW_SECT* value
58     so callers can request specific bases(offsets)
59     and sizes from the offset and size tables.
60     But we change things a little internally so both
61     tables look zero-origin.
62 */
63 #include "config.h"
64 #include <stdio.h>
65 #ifdef HAVE_STDLIB_H
66 #include <stdlib.h>
67 #endif /* HAVE_STDLIB_H */
68 #include "dwarf_incl.h"
69 #include "dwarf_alloc.h"
70 #include "dwarf_error.h"
71 #include "dwarf_util.h"
72 #include "dwarf_xu_index.h"
73 #include "dwarfstring.h"
74 
75 #define  HASHSIGNATURELEN 8
76 #define  LEN32BIT   4
77 
78 #define TRUE 1
79 #define FALSE 0
80 
81 /* The following actually assumes (as used here)
82     that t is 8 bytes (integer) while s is
83     also 8 bytes (Dwarf_Sig8 struct). */
84 #ifdef WORDS_BIGENDIAN
85 #define ASNAR(t,s,l)                   \
86     do {                                    \
87         unsigned tbyte = sizeof(t) - l;     \
88         if (sizeof(t) < l) {                \
89             _dwarf_error(dbg,error,DW_DLE_XU_HASH_INDEX_ERROR); \
90             return DW_DLV_ERROR;             \
91         }                                   \
92         t = 0;                              \
93         dbg->de_copy_word(((char *)&t)+tbyte ,&s[0],l);\
94     } while (0)
95 #else /* LITTLE ENDIAN */
96 #define ASNAR(t,s,l)                 \
97     do {                                \
98         t = 0;                          \
99         if (sizeof(t) < l) {            \
100             _dwarf_error(dbg,error,DW_DLE_XU_HASH_INDEX_ERROR); \
101             return DW_DLV_ERROR;         \
102         }                               \
103         dbg->de_copy_word(&t,&s[0],l);  \
104     } while (0)
105 #endif /* end LITTLE- BIG-ENDIAN */
106 
107 /* zerohashkey used as all-zero-bits for comparison. */
108 static const Dwarf_Sig8 zerohashkey;
109 
110 #if 0
111 static void
112 dump_bytes(char * msg,Dwarf_Small * start, long len)
113 {
114     Dwarf_Small *end = start + len;
115     Dwarf_Small *cur = start;
116 
117     printf("%s ",msg);
118     for (; cur < end; cur++) {
119         printf("%02x ", *cur);
120     }
121     printf("\n");
122 }
123 #endif
124 
125 /*  Precondition: headerline_offset + N*32 is within
126     the section. */
127 static int
128 fill_in_offsets_headerline(Dwarf_Debug dbg,
129     Dwarf_Xu_Index_Header xuhdr,
130     Dwarf_Unsigned headerline_offset,
131     Dwarf_Unsigned num_sects,
132     Dwarf_Error *err)
133 {
134     Dwarf_Small *section_start = xuhdr->gx_section_data;
135     Dwarf_Small *section_end = xuhdr->gx_section_data+
136         xuhdr->gx_section_length;
137     Dwarf_Small *data = 0;
138     unsigned i = 0;
139 
140     data = section_start +headerline_offset;
141     for( ; i < num_sects ; ++i) {
142         Dwarf_Unsigned v = 0;
143 
144         READ_UNALIGNED_CK(dbg,v, Dwarf_Unsigned,
145             data,LEN32BIT,
146             err,section_end);
147         data += LEN32BIT;
148         if (v > DW_SECT_RNGLISTS) {
149             dwarfstring s;
150 
151             dwarfstring_constructor(&s);
152             dwarfstring_append_printf_u(&s,
153                 "ERROR: DW_DLE_XU_NAME_COL_ERROR  The "
154                 "section number of %u ",v);
155             dwarfstring_append(&s," is too high. "
156                 "There sections 1-8 are listed in "
157                 "DWARF5 table 7.1.");
158             _dwarf_error_string(dbg, err, DW_DLE_XU_NAME_COL_ERROR,
159                 dwarfstring_string(&s));
160             dwarfstring_destructor(&s);
161             return DW_DLV_ERROR;
162         }
163         xuhdr->gx_section_id[i] = v;
164     }
165     return DW_DLV_OK;
166 }
167 
168 
169 /*  Read in a cu or tu section and
170     return overview information.
171 
172     For libdwarf-internal lookups
173     dwarf_init*() calls
174     dwarf_get_xu_index_header() when
175     the object file is opened and
176     dwarf_xu_header_free() is called
177     by dwarf_finish(), there is
178     no need for users to do this.
179 
180     If one wants to call the various
181     tu/cu functions oneself (possibly to print the
182     .debug_cu_index or .debug_tu_index sections).
183     then you will need to call dwarf_get_xu_index_header()
184     and eventually dwarf_xu_header_free().
185 
186     The libdwarf-internal data is kept in Dwarf_Debug
187     fields de_cu_hashindex_data/de_tu_hashindex_data.
188 */
189 int
190 dwarf_get_xu_index_header(Dwarf_Debug dbg,
191     /* Pass in section_type "tu" or "cu" */
192     const char *     section_type,
193     Dwarf_Xu_Index_Header * xuptr,
194     Dwarf_Unsigned * version,
195     Dwarf_Unsigned * number_of_columns, /* L section count.*/
196     Dwarf_Unsigned * number_of_CUs,     /* U unit count    */
197     Dwarf_Unsigned * number_of_slots,   /* S slot count    */
198     /*  Standard says S > U DWARF5 sec 7.3.5.3 */
199     const char    ** section_name,
200     Dwarf_Error    * error)
201 {
202     Dwarf_Xu_Index_Header indexptr = 0;
203     int res = DW_DLV_ERROR;
204     struct Dwarf_Section_s *sect = 0;
205     Dwarf_Unsigned local_version = 0;
206     Dwarf_Unsigned num_secs  = 0;
207     Dwarf_Unsigned num_CUs  = 0;
208     Dwarf_Unsigned num_slots  = 0;
209     Dwarf_Small *data = 0;
210     Dwarf_Unsigned tables_end_offset = 0;
211     Dwarf_Unsigned hash_tab_offset = 0;
212     Dwarf_Unsigned indexes_tab_offset = 0;
213     Dwarf_Unsigned section_offsets_tab_offset = 0;
214     Dwarf_Unsigned section_offsets_headerline_offset = 0;
215     Dwarf_Unsigned section_sizes_tab_offset = 0;
216     unsigned datalen32 = LEN32BIT;
217     Dwarf_Small *section_end = 0;
218 
219     if (!strcmp(section_type,"cu") ) {
220         sect = &dbg->de_debug_cu_index;
221     } else if (!strcmp(section_type,"tu") ) {
222         sect = &dbg->de_debug_tu_index;
223     } else {
224         _dwarf_error(dbg, error, DW_DLE_XU_TYPE_ARG_ERROR);
225         return DW_DLV_ERROR;
226     }
227     if (!sect->dss_size) {
228         return DW_DLV_NO_ENTRY;
229     }
230     if (!sect->dss_data) {
231         res = _dwarf_load_section(dbg, sect,error);
232         if (res != DW_DLV_OK) {
233             return res;
234         }
235     }
236 
237     data = sect->dss_data;
238     section_end = data + sect->dss_size;
239 
240     if (sect->dss_size < (4*datalen32) ) {
241         dwarfstring m;
242 
243         dwarfstring_constructor(&m);
244         dwarfstring_append_printf_s(&m,
245             "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: "
246             "The size of the %s ",(char *)section_type);
247         dwarfstring_append_printf_u(&m,
248             " is just %u bytes, much to small to be "
249             " a correct section",sect->dss_size);
250         _dwarf_error_string(dbg, error,
251             DW_DLE_ERRONEOUS_XU_INDEX_SECTION,
252             dwarfstring_string(&m));
253         dwarfstring_destructor(&m);
254         return DW_DLV_ERROR;
255     }
256     READ_UNALIGNED_CK(dbg,local_version, Dwarf_Unsigned,
257         data,datalen32,
258         error,section_end);
259     data += datalen32;
260 
261     /* reading N */
262     READ_UNALIGNED_CK(dbg,num_secs, Dwarf_Unsigned,
263         data,datalen32,
264         error,section_end);
265     data += datalen32;
266     /* reading U */
267     READ_UNALIGNED_CK(dbg,num_CUs, Dwarf_Unsigned,
268         data,datalen32,
269         error,section_end);
270     data += datalen32;
271     /* reading S */
272     READ_UNALIGNED_CK(dbg,num_slots, Dwarf_Unsigned,
273         data,datalen32,
274         error,section_end);
275     hash_tab_offset = datalen32*4;
276     indexes_tab_offset = hash_tab_offset +
277         (num_slots * HASHSIGNATURELEN);
278     /*  Look for corrupt section data. */
279     if (num_slots > sect->dss_size) {
280         dwarfstring m;
281 
282         dwarfstring_constructor(&m);
283         dwarfstring_append_printf_s(&m,
284             "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: "
285             "The size of the %s ",(char *)section_type);
286         dwarfstring_append_printf_u(&m,
287             " is just %u bytes,",sect->dss_size);
288         dwarfstring_append_printf_u(&m,
289             "while the number of slots (S) is %u. "
290             "which is clearly wrong",num_slots );
291         _dwarf_error_string(dbg, error,
292             DW_DLE_ERRONEOUS_XU_INDEX_SECTION,
293             dwarfstring_string(&m));
294         dwarfstring_destructor(&m);
295         return DW_DLV_ERROR;
296     }
297     if ( (4*num_slots) > sect->dss_size) {
298         dwarfstring m;
299 
300         dwarfstring_constructor(&m);
301         dwarfstring_append_printf_s(&m,
302             "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: "
303             "The size of the %s ",(char *)section_type);
304         dwarfstring_append_printf_u(&m,
305             " is just %u bytes,",sect->dss_size);
306         dwarfstring_append_printf_u(&m,
307             "while the number of slots bytes (S) is at least %u. "
308             "which is clearly wrong",num_slots*4);
309         _dwarf_error_string(dbg, error,
310             DW_DLE_ERRONEOUS_XU_INDEX_SECTION,
311             dwarfstring_string(&m));
312         dwarfstring_destructor(&m);
313         return DW_DLV_ERROR;
314     }
315 
316     /*  This offset is to  1 row of N columns, each 32bit. */
317     section_offsets_headerline_offset = indexes_tab_offset +
318         (num_slots *datalen32);
319     /*  Now we can make the real table part index normally.
320         This offset is to  U row of N columns, each 32bit. */
321     section_offsets_tab_offset = section_offsets_headerline_offset
322         + (num_secs*datalen32);
323     if ( num_secs > sect->dss_size) {
324         dwarfstring m;
325 
326         dwarfstring_constructor(&m);
327         dwarfstring_append_printf_s(&m,
328             "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: "
329             "The size of the %s ",(char *)section_type);
330         dwarfstring_append_printf_u(&m,
331             " is just %u bytes,",sect->dss_size);
332         dwarfstring_append_printf_u(&m,
333             "while the number of sections/columns (S) is %u. "
334             "which is clearly wrong",num_secs );
335         _dwarf_error_string(dbg, error,
336             DW_DLE_ERRONEOUS_XU_INDEX_SECTION,
337             dwarfstring_string(&m));
338         dwarfstring_destructor(&m);
339         return DW_DLV_ERROR;
340     }
341     if ( (datalen32*num_secs) > sect->dss_size) {
342         dwarfstring m;
343 
344         dwarfstring_constructor(&m);
345         dwarfstring_append_printf_s(&m,
346             "DW_DLE_ERRONEOUS_XU_INDEX_SECTION: "
347             "The size of the %s ",(char *)section_type);
348         dwarfstring_append_printf_u(&m,
349             " is just %u bytes,",sect->dss_size);
350         dwarfstring_append_printf_u(&m,
351             "while the number of sections/columns bytes (S)"
352             " is at least %u. "
353             "which is clearly wrong",num_secs*4);
354         _dwarf_error_string(dbg, error,
355             DW_DLE_ERRONEOUS_XU_INDEX_SECTION,
356             dwarfstring_string(&m));
357         dwarfstring_destructor(&m);
358         return DW_DLV_ERROR;
359     }
360     section_sizes_tab_offset = section_offsets_tab_offset +
361         (num_CUs *num_secs* datalen32) ;
362     tables_end_offset = section_sizes_tab_offset +
363         (num_CUs * num_secs * datalen32);
364     if ( tables_end_offset > sect->dss_size) {
365         /* Something is badly wrong here. */
366         dwarfstring m;
367 
368         dwarfstring_constructor(&m);
369         dwarfstring_append_printf_u(&m,"ERROR: "
370             "DW_DLE_ERRONEOUS_XU_INDEX_SECTION as the end offset "
371             "0x%lx is greater than ",tables_end_offset);
372         dwarfstring_append_printf_u(&m,"the section size "
373             "0x%lx.",sect->dss_size);
374         _dwarf_error_string(dbg, error,
375             DW_DLE_ERRONEOUS_XU_INDEX_SECTION,
376             dwarfstring_string(&m));
377         dwarfstring_destructor(&m);
378         return DW_DLV_ERROR;
379     }
380     indexptr = (Dwarf_Xu_Index_Header)
381         _dwarf_get_alloc(dbg,DW_DLA_XU_INDEX,1);
382     if (indexptr == NULL) {
383         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
384         return (DW_DLV_ERROR);
385     }
386     /*  Only "cu" or "tu" allowed, that is checked above.
387         But for safety we just copy the allowed bytes*/
388     indexptr->gx_type[0] = section_type[0];
389     indexptr->gx_type[1] = section_type[1];
390     indexptr->gx_type[2] = 0;
391     indexptr->gx_dbg = dbg;
392     indexptr->gx_section_length = sect->dss_size;
393     indexptr->gx_section_data   = sect->dss_data;
394     indexptr->gx_section_name   = sect->dss_name;
395     indexptr->gx_version        = local_version;
396     indexptr->gx_column_count_sections = num_secs;
397     indexptr->gx_units_in_index = num_CUs;
398     indexptr->gx_slots_in_hash  = num_slots;
399     indexptr->gx_hash_table_offset  =  hash_tab_offset;
400     indexptr->gx_index_table_offset = indexes_tab_offset;
401     indexptr->gx_section_offsets_headerline_offset=
402         section_offsets_headerline_offset;
403     indexptr->gx_section_offsets_offset= section_offsets_tab_offset;
404     indexptr->gx_section_sizes_offset  = section_sizes_tab_offset;
405     res = fill_in_offsets_headerline(dbg,indexptr,
406         section_offsets_headerline_offset,
407         num_secs,error);
408     if (res != DW_DLV_OK) {
409         return res;
410     }
411     *xuptr             =     indexptr;
412     *version           = indexptr->gx_version;
413     *number_of_columns = indexptr->gx_column_count_sections;
414     *number_of_CUs     = indexptr->gx_units_in_index;
415     *number_of_slots   = indexptr->gx_slots_in_hash;
416     *section_name      = indexptr->gx_section_name;
417     return DW_DLV_OK;
418 }
419 
420 
421 
422 int dwarf_get_xu_index_section_type(Dwarf_Xu_Index_Header xuhdr,
423     /*  the function returns a pointer to
424         the immutable string "tu" or "cu" via
425         this arg. Do not free.  */
426     const char ** typename,
427     /*  the function returns a pointer to
428         the immutable section name. Do not free.
429         .debug_cu_index or .debug_tu_index */
430     const char ** sectionname,
431     UNUSEDARG Dwarf_Error * err)
432 {
433     *typename    = &xuhdr->gx_type[0];
434     *sectionname = xuhdr->gx_section_name;
435     return DW_DLV_OK;
436 }
437 
438 /*  Index values 0 to S-1 are valid. */
439 int dwarf_get_xu_hash_entry(Dwarf_Xu_Index_Header xuhdr,
440     Dwarf_Unsigned    index,
441     /* returns the hash value. 64 bits. */
442     Dwarf_Sig8     *  hash_value,
443 
444     /* returns the index into rows of offset/size tables. */
445     Dwarf_Unsigned *  index_to_sections,
446     Dwarf_Error *     err)
447 {
448     Dwarf_Debug dbg = xuhdr->gx_dbg;
449     Dwarf_Small *hashtab = xuhdr->gx_section_data +
450         xuhdr->gx_hash_table_offset;
451     Dwarf_Small *indextab = xuhdr->gx_section_data +
452         xuhdr->gx_index_table_offset;
453     Dwarf_Small *indexentry = 0;
454     Dwarf_Small *hashentry = 0;
455     Dwarf_Sig8 hashval;
456     Dwarf_Unsigned indexval = 0;
457     Dwarf_Small *section_end = xuhdr->gx_section_data +
458         xuhdr->gx_section_length;
459 
460     hashval  = zerohashkey;
461     if (xuhdr->gx_slots_in_hash > 0) {
462         if (index >= xuhdr->gx_slots_in_hash) {
463             dwarfstring m;
464 
465             dwarfstring_constructor(&m);
466             dwarfstring_append_printf_u(&m,
467                 "DW_DLE_XU_HASH_ROW_ERROR the index passed in, "
468                 " %u, is greater than the number of slots "
469                 " in the hash table.",index);
470             _dwarf_error_string(dbg, err,  DW_DLE_XU_HASH_ROW_ERROR,
471                 dwarfstring_string(&m));
472             dwarfstring_destructor(&m);
473             return DW_DLV_ERROR;
474         }
475         hashentry = hashtab + (index * HASHSIGNATURELEN);
476         memcpy(&hashval,hashentry,sizeof(hashval));
477     } else {
478         _dwarf_error_string(dbg, err,  DW_DLE_XU_HASH_ROW_ERROR,
479             "DW_DLE_XU_HASH_ROW_ERROR the number of slots is zero"
480             " which seems wrong.");
481         return DW_DLV_ERROR;
482     }
483 
484     indexentry = indextab + (index * LEN32BIT);
485     memcpy(hash_value,&hashval,sizeof(hashval));
486     READ_UNALIGNED_CK(dbg,indexval,Dwarf_Unsigned, indexentry,
487         LEN32BIT,
488         err,section_end);
489     indexentry += LEN32BIT;
490     if (indexval > xuhdr->gx_units_in_index) {
491         _dwarf_error(dbg, err,  DW_DLE_XU_HASH_INDEX_ERROR);
492         return DW_DLV_ERROR;
493     }
494 
495     *index_to_sections = indexval;
496     return DW_DLV_OK;
497 }
498 
499 
500 static const char * dwp_secnames[] = {
501 "No name for zero",
502 "DW_SECT_INFO"        /* 1 */ /*".debug_info.dwo"*/,
503 "DW_SECT_TYPES"       /* 2 */ /*".debug_types.dwo"*/,
504 "DW_SECT_ABBREV"      /* 3 */ /*".debug_abbrev.dwo"*/,
505 "DW_SECT_LINE"        /* 4 */ /*".debug_line.dwo"*/,
506 "DW_SECT_LOC"         /* 5 */ /*".debug_loc.dwo"*/,
507 "DW_SECT_STR_OFFSETS" /* 6 */ /*".debug_str_offsets.dwo"*/,
508 "DW_SECT_MACRO"       /* 7 */ /*".debug_macro.dwo"*/,
509 "DW_SECT_RNGLISTS"       /* 8 */ /*".debug_rnglists.dwo"*/,
510 "No name > 8",
511 };
512 
513 /*  Row 0 of the Table of Section Offsets,
514     columns 0 to L-1,  are the section id's,
515     and names, such as DW_SECT_INFO (ie, 1)  */
516 int
517 dwarf_get_xu_section_names(Dwarf_Xu_Index_Header xuhdr,
518     Dwarf_Unsigned  column_index,
519     Dwarf_Unsigned* number,
520     const char **   name,
521     Dwarf_Error *   err)
522 {
523     Dwarf_Unsigned sec_num = 0;
524     Dwarf_Debug dbg = xuhdr->gx_dbg;
525 
526     if( column_index >= xuhdr->gx_column_count_sections) {
527         dwarfstring s;
528 
529         dwarfstring_constructor(&s);
530         dwarfstring_append_printf_u(&s,
531             "ERROR: DW_DLE_XU_NAME_COL_ERROR as the "
532             "column index of %u ",column_index);
533         dwarfstring_append_printf_u(&s," is too high. "
534             "There are %u sections.",
535             xuhdr->gx_column_count_sections);
536         _dwarf_error_string(dbg, err, DW_DLE_XU_NAME_COL_ERROR,
537             dwarfstring_string(&s));
538         dwarfstring_destructor(&s);
539         return DW_DLV_ERROR;
540     }
541     sec_num = xuhdr->gx_section_id[column_index];
542     if (sec_num < 1) {
543         return DW_DLV_NO_ENTRY;
544     }
545     *number = sec_num;
546     *name =  dwp_secnames[sec_num];
547     return DW_DLV_OK;
548 }
549 
550 
551 /*  Rows 0 to U-1
552     col 0 to L-1
553     are section offset and length values from
554     the Table of Section Offsets and Table of Section Sizes.
555     The formally the table of section offsets is a header
556     line of the section offsets we subtract 1 from
557     the incoming irow_index as our tables are
558     now zero origin. */
559 int
560 dwarf_get_xu_section_offset(Dwarf_Xu_Index_Header xuhdr,
561     Dwarf_Unsigned  irow_index,
562     Dwarf_Unsigned  column_index,
563     Dwarf_Unsigned* sec_offset,
564     Dwarf_Unsigned* sec_size,
565     Dwarf_Error *   err)
566 {
567     /* We use zero origin in the arrays, Users see
568         one origin from the hash table. */
569     Dwarf_Debug dbg = xuhdr->gx_dbg;
570     /* get to base of tables first. */
571     Dwarf_Small *offsetrow =  xuhdr->gx_section_offsets_offset +
572         xuhdr->gx_section_data;
573     Dwarf_Small *sizerow =  xuhdr->gx_section_sizes_offset +
574         xuhdr->gx_section_data;
575     Dwarf_Small *offsetentry = 0;
576     Dwarf_Small *sizeentry =  0;
577     Dwarf_Unsigned offset = 0;
578     Dwarf_Unsigned size = 0;
579     Dwarf_Unsigned column_count = xuhdr->gx_column_count_sections;
580     Dwarf_Small *section_end = xuhdr->gx_section_data +
581         xuhdr->gx_section_length;
582     Dwarf_Unsigned row_index = irow_index-1;
583 
584     if(!irow_index) {
585         dwarfstring s;
586 
587         dwarfstring_constructor(&s);
588         dwarfstring_append(&s,
589             "ERROR: DW_DLE_ERRONEOUS_XU_INDEX_SECTION "
590             "The row index passed to dwarf_get_xu_section_offset() "
591             "is zero, which is not a valid row in "
592             " the offset-table or the size table as we think"
593             " of them as 1-origin.");
594         _dwarf_error_string(dbg, err, DW_DLE_XU_NAME_COL_ERROR,
595             dwarfstring_string(&s));
596         dwarfstring_destructor(&s);
597         return DW_DLV_ERROR;
598     }
599     if( row_index >= xuhdr->gx_units_in_index) {
600         dwarfstring s;
601 
602         dwarfstring_constructor(&s);
603         dwarfstring_append_printf_u(&s,
604             "ERROR: DW_DLE_XU_NAME_COL_ERROR as the "
605             "row index of %u ",row_index);
606         dwarfstring_append_printf_u(&s," is too high. "
607             "Valid units must be < %u ",xuhdr->gx_units_in_index);
608         _dwarf_error_string(dbg, err, DW_DLE_XU_NAME_COL_ERROR,
609             dwarfstring_string(&s));
610         dwarfstring_destructor(&s);
611         return DW_DLV_ERROR;
612     }
613 
614     if( column_index >=  xuhdr->gx_column_count_sections) {
615         dwarfstring s;
616 
617         dwarfstring_constructor(&s);
618         dwarfstring_append_printf_u(&s,
619             "ERROR: DW_DLE_XU_NAME_COL_ERROR as the "
620             "column index of %u ",column_index);
621         dwarfstring_append_printf_u(&s," is too high. "
622             "Valid column indexes  must be < %u ",
623             xuhdr->gx_column_count_sections);
624         _dwarf_error_string(dbg, err, DW_DLE_XU_NAME_COL_ERROR,
625             dwarfstring_string(&s));
626         dwarfstring_destructor(&s);
627         return DW_DLV_ERROR;
628     }
629     /*  As noted above we have hidden the extra initial
630         row from the offsets table so it is just
631         0 to U-1. */
632     offsetrow = offsetrow + (row_index*column_count * LEN32BIT);
633     offsetentry = offsetrow + (column_index *  LEN32BIT);
634 
635     sizerow = sizerow + (row_index*column_count * LEN32BIT);
636     sizeentry = sizerow + (column_index *  LEN32BIT);
637 
638     {
639         READ_UNALIGNED_CK(dbg,offset,Dwarf_Unsigned,
640             offsetentry,
641             LEN32BIT,err,section_end);
642         offsetentry += LEN32BIT;
643 
644         READ_UNALIGNED_CK(dbg,size,Dwarf_Unsigned,
645             sizeentry,
646             LEN32BIT,err,section_end);
647         sizeentry += LEN32BIT;
648     }
649     *sec_offset = offset;
650     *sec_size =  size;
651     return DW_DLV_OK;
652 }
653 
654 
655 static int
656 _dwarf_search_fission_for_key(UNUSEDARG Dwarf_Debug dbg,
657     Dwarf_Xu_Index_Header xuhdr,
658     Dwarf_Sig8 *key_in,
659     Dwarf_Unsigned * percu_index_out,
660     Dwarf_Error *error)
661 {
662     Dwarf_Unsigned key = 0;
663     Dwarf_Unsigned primary_hash = 0;
664     Dwarf_Unsigned hashprime = 0;
665     Dwarf_Unsigned slots =  xuhdr->gx_slots_in_hash;
666     Dwarf_Unsigned mask = slots -1;
667     Dwarf_Sig8 hashentry_key;
668     Dwarf_Unsigned percu_index = 0;
669 
670     hashentry_key = zerohashkey;
671     /*  Look for corrupt section data. */
672     if (slots > xuhdr->gx_section_length) {
673         dwarfstring s;
674 
675         dwarfstring_constructor(&s);
676         dwarfstring_append_printf_u(&s,
677             "ERROR: DW_DLE_XU_NAME_COL_ERROR as the "
678             "slots count of %u ",slots);
679         dwarfstring_append_printf_u(&s," is too high. "
680             "given the section length of %u\n",
681             xuhdr->gx_section_length);
682         _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR,
683             dwarfstring_string(&s));
684         dwarfstring_destructor(&s);
685         return DW_DLV_ERROR;
686     }
687     if ( (4*slots) > xuhdr->gx_section_length) {
688         dwarfstring s;
689 
690         dwarfstring_constructor(&s);
691         dwarfstring_append_printf_u(&s,
692             "ERROR: DW_DLE_XU_NAME_COL_ERROR as the "
693             "slots count *4 of %u ",slots*4);
694         dwarfstring_append_printf_u(&s," is too high. "
695             "given the section length of %u\n",
696             xuhdr->gx_section_length);
697         _dwarf_error_string(dbg, error, DW_DLE_XU_NAME_COL_ERROR,
698             dwarfstring_string(&s));
699         dwarfstring_destructor(&s);
700         return DW_DLV_ERROR;
701     }
702     if (sizeof (key) != sizeof(key_in)) {
703         /* The hash won't work right in this case */
704         _dwarf_error(dbg, error, DW_DLE_XU_HASH_ROW_ERROR);
705     }
706     ASNAR(key,key_in,sizeof(*key_in));
707     primary_hash = key & mask;
708     hashprime =  (((key >>32) &mask) |1);
709     while (1) {
710         int res = 0;
711 
712         res = dwarf_get_xu_hash_entry(xuhdr,
713             primary_hash,&hashentry_key,
714             &percu_index,error);
715         if (res != DW_DLV_OK) {
716             return res;
717         }
718         if (percu_index == 0 &&
719             !memcmp(&hashentry_key,&zerohashkey,sizeof(Dwarf_Sig8))) {
720             return DW_DLV_NO_ENTRY;
721         }
722         if (!memcmp(key_in,&hashentry_key,sizeof(Dwarf_Sig8))) {
723             /* FOUND */
724             *percu_index_out = percu_index;
725             return  DW_DLV_OK;
726         }
727         primary_hash = (primary_hash + hashprime) % slots;
728     }
729     /* ASSERT: Cannot get here. */
730     return DW_DLV_NO_ENTRY;
731 }
732 
733 /* Slow. Consider tsearch. */
734 /* For type units and for CUs. */
735 /* We're finding an index entry refers
736    to a global offset in some CU
737    and hence is unique in the target. */
738 static int
739 _dwarf_search_fission_for_offset(Dwarf_Debug dbg,
740     Dwarf_Xu_Index_Header xuhdr,
741     Dwarf_Unsigned offset,
742     Dwarf_Unsigned dfp_sect_num, /* DW_SECT_INFO or TYPES */
743     Dwarf_Unsigned * percu_index_out,
744     Dwarf_Sig8 * key_out,
745     Dwarf_Error *error)
746 {
747     Dwarf_Unsigned i = 0;
748     Dwarf_Unsigned m = 0;
749     int secnum_index = -1;  /* N index */
750     int res = 0;
751 
752     for ( i = 0; i< xuhdr->gx_column_count_sections; i++) {
753         /*  We could put the secnums array into xuhdr
754             if looping here is too slow. */
755         const char *name = 0;
756         Dwarf_Unsigned num = 0;
757         res = dwarf_get_xu_section_names(xuhdr,i,&num,&name,error);
758         if (res != DW_DLV_OK) {
759             return res;
760         }
761         if (num == dfp_sect_num) {
762             secnum_index = i;
763             break;
764         }
765     }
766     if (secnum_index == -1) {
767         _dwarf_error(dbg,error,DW_DLE_FISSION_SECNUM_ERR);
768         return DW_DLV_ERROR;
769     }
770     for ( m = 0; m < xuhdr->gx_slots_in_hash; ++m) {
771         Dwarf_Sig8 hash;
772         Dwarf_Unsigned indexn = 0;
773         Dwarf_Unsigned sec_offset = 0;
774         Dwarf_Unsigned sec_size = 0;
775 
776         res = dwarf_get_xu_hash_entry(xuhdr,m,&hash,&indexn,error);
777         if (res != DW_DLV_OK) {
778             return res;
779         }
780         if (indexn == 0 &&
781             !memcmp(&hash,&zerohashkey,sizeof(Dwarf_Sig8))) {
782             /* Empty slot. */
783             continue;
784         }
785 
786         res = dwarf_get_xu_section_offset(xuhdr,
787             indexn,secnum_index,&sec_offset,&sec_size,error);
788         if (res != DW_DLV_OK) {
789             return res;
790         }
791         if (sec_offset != offset) {
792             continue;
793         }
794         *percu_index_out = indexn;
795         *key_out = hash;
796         return DW_DLV_OK;
797     }
798     return DW_DLV_NO_ENTRY;
799 }
800 
801 static int
802 _dwarf_get_xuhdr(Dwarf_Debug dbg,
803    const char *sigtype,
804    Dwarf_Xu_Index_Header *xuout,
805    Dwarf_Error *error)
806 {
807    if (!strcmp(sigtype,"tu")) {
808         if (!dbg->de_tu_hashindex_data) {
809             return DW_DLV_NO_ENTRY;
810         }
811         *xuout = dbg->de_tu_hashindex_data;
812     } else if (!strcmp(sigtype,"cu")) {
813         if (!dbg->de_cu_hashindex_data) {
814             return DW_DLV_NO_ENTRY;
815         }
816         *xuout = dbg->de_cu_hashindex_data;
817     } else {
818         _dwarf_error(dbg,error,DW_DLE_SIG_TYPE_WRONG_STRING);
819         return DW_DLV_ERROR;
820     }
821     return DW_DLV_OK;
822 
823 }
824 
825 static int
826 transform_xu_to_dfp(Dwarf_Xu_Index_Header xuhdr,
827     Dwarf_Unsigned percu_index,
828     Dwarf_Sig8 *key,
829     const char *sig_type,
830     Dwarf_Debug_Fission_Per_CU *  percu_out,
831     Dwarf_Error *error)
832 {
833     unsigned i = 0;
834     unsigned l = 0;
835     unsigned n = 1;
836     unsigned max_cols = xuhdr->gx_column_count_sections;  /* L */
837     unsigned secnums[DW_FISSION_SECT_COUNT];
838     int res;
839     for ( i = 0; i< max_cols; i++) {
840         /*  We could put the secnums array into xuhdr
841             if recreating it is too slow. */
842         const char *name = 0;
843         Dwarf_Unsigned num = 0;
844         res = dwarf_get_xu_section_names(xuhdr,i,&num,&name,error);
845         if (res != DW_DLV_OK) {
846             return res;
847         }
848         secnums[i] = num;
849     }
850     n = percu_index;
851     for(l = 0; l < max_cols; ++l) {  /* L */
852         Dwarf_Unsigned sec_off = 0;
853         Dwarf_Unsigned sec_size = 0;
854         unsigned l_as_sect = secnums[l];
855         res = dwarf_get_xu_section_offset(xuhdr,n,l,
856             &sec_off,&sec_size,error);
857         if (res != DW_DLV_OK) {
858             return res;
859         }
860         percu_out->pcu_offset[l_as_sect] = sec_off;
861         percu_out->pcu_size[l_as_sect] = sec_size;
862     }
863     percu_out->pcu_type = sig_type;
864     percu_out->pcu_index = percu_index;
865     percu_out->pcu_hash = *key;
866     return DW_DLV_OK;
867 }
868 
869 /*  This should only be called for a CU, never a TU.
870     For a TU the type hash is known while reading
871     the TU Header.  Not so for a CU. */
872 int
873 _dwarf_get_debugfission_for_offset(Dwarf_Debug dbg,
874     Dwarf_Off    offset_wanted,
875     const char * key_type, /*  "cu" or "tu" */
876     struct Dwarf_Debug_Fission_Per_CU_s *  percu_out,
877     Dwarf_Error *error)
878 {
879     Dwarf_Xu_Index_Header xuhdr = 0;
880     int sres = 0;
881     Dwarf_Unsigned percu_index = 0;
882     Dwarf_Unsigned sect_index_base = 0;
883     Dwarf_Sig8 key;
884 
885     sect_index_base = DW_SECT_INFO;
886     key = zerohashkey;
887     sres = _dwarf_get_xuhdr(dbg,key_type, &xuhdr,error);
888     if (sres != DW_DLV_OK) {
889         return sres;
890     }
891     sres = _dwarf_search_fission_for_offset(dbg,
892         xuhdr,offset_wanted, sect_index_base, &percu_index,
893         &key,
894         error);
895     if (sres != DW_DLV_OK) {
896         return sres;
897     }
898     sres = transform_xu_to_dfp(xuhdr,percu_index,&key,
899         key_type,percu_out, error);
900     return sres;
901 
902 }
903 int
904 dwarf_get_debugfission_for_key(Dwarf_Debug dbg,
905     Dwarf_Sig8 *  key  /* pointer to hash signature */,
906     const char * key_type  /*  "cu" or "tu" */,
907     Dwarf_Debug_Fission_Per_CU *  percu_out,
908     Dwarf_Error *  error )
909 {
910     int sres = 0;
911     Dwarf_Unsigned percu_index = 0;
912     Dwarf_Xu_Index_Header xuhdr = 0;
913 
914     sres = _dwarf_load_debug_info(dbg,error);
915     if (sres == DW_DLV_ERROR) {
916         return sres;
917     }
918     sres = _dwarf_load_debug_types(dbg,error);
919     if (sres == DW_DLV_ERROR) {
920         return sres;
921     }
922     /*  Returns already existing xuhdr */
923     sres = _dwarf_get_xuhdr(dbg,key_type, &xuhdr,error);
924     if (sres != DW_DLV_OK) {
925         return sres;
926     }
927     /*  Search in that xu data. */
928     sres = _dwarf_search_fission_for_key(dbg,
929         xuhdr,key,&percu_index,error);
930     if (sres != DW_DLV_OK) {
931         return sres;
932     }
933     sres = transform_xu_to_dfp(xuhdr,percu_index,key,
934         key_type,percu_out,error);
935     return sres;
936 }
937 
938 void
939 dwarf_xu_header_free(Dwarf_Xu_Index_Header indexptr)
940 {
941     if(indexptr) {
942         Dwarf_Debug dbg = indexptr->gx_dbg;
943         dwarf_dealloc(dbg,indexptr,DW_DLA_XU_INDEX);
944     }
945 }
946