xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_gdbindex.c (revision a92282e44f968185a6bba094d1e5fece2da819cf)
1 /*
2 
3   Copyright (C) 2014-2019 David Anderson. All Rights Reserved.
4 
5   This program is free software; you can redistribute it and/or modify it
6   under the terms of version 2.1 of the GNU Lesser General Public License
7   as published by the Free Software Foundation.
8 
9   This program is distributed in the hope that it would be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13   Further, this software is distributed without any warranty that it is
14   free of the rightful claim of any third person regarding infringement
15   or the like.  Any license provided herein, whether implied or
16   otherwise, applies only to this software file.  Patent licenses, if
17   any, provided herein do not apply to combinations of this program with
18   other software, or any other product whatsoever.
19 
20   You should have received a copy of the GNU Lesser General Public
21   License along with this program; if not, write the Free Software
22   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
23   USA.
24 
25 */
26 
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif /* HAVE_STDLIB_H */
32 #include "dwarf_incl.h"
33 #include "dwarf_alloc.h"
34 #include "dwarf_error.h"
35 #include "dwarf_util.h"
36 #include "memcpy_swap.h"
37 #include "dwarf_gdbindex.h"
38 
39 #define TRUE 1
40 #define FALSE 0
41 
42 /*  The dwarf_util macro READ_UNALIGNED
43     cannot be directly used because
44     gdb defines the section contents of
45     .gdb_index as little-endian always.
46 */
47 
48 #if WORDS_BIGENDIAN   /* meaning on this host */
49 #define READ_GDBINDEX(dest,desttype, source, length)                     \
50     do {                                                                 \
51         BIGGEST_UINT _ltmp = 0;                                          \
52         _dwarf_memcpy_swap_bytes((((char *)(&_ltmp)) + sizeof(_ltmp) - length), \
53             source, length) ;                                            \
54         dest = (desttype)_ltmp;                                          \
55     } while (0)
56 #else /* little-endian on this host */
57 #define READ_GDBINDEX(dest,desttype, source, length)                     \
58     do {                                                                 \
59         BIGGEST_UINT _ltmp = 0;                                          \
60         memcpy(((char *)(&_ltmp)) ,            \
61             source, length) ;                                            \
62         dest = (desttype)_ltmp;                                          \
63     } while (0)
64 
65 #endif
66 
67 
68 struct gi_fileheader_s {
69     char gfs [4][6];
70 };
71 
72 struct dwarf_64bitpair {
73     gdbindex_64 offset;
74     gdbindex_64 length;
75 };
76 
77 static int
78 set_base(Dwarf_Debug dbg,
79     struct Dwarf_Gdbindex_array_instance_s * hdr,
80     Dwarf_Small *start,
81     Dwarf_Small *end,
82     /* entrylen is the length of a single struct as seen in the object. */
83     Dwarf_Unsigned entrylen,
84     /* The size of each field in the struct in the object. */
85     Dwarf_Unsigned fieldlen,
86     enum gdbindex_type_e type,
87     Dwarf_Error * err)
88 {
89 
90     if (type == git_std || type == git_cuvec) {
91         /*  cuvec is sort of a fake as a simple
92             section, but a useful one. */
93         Dwarf_Unsigned count = 0;
94         if( end < start) {
95             _dwarf_error(dbg, err,DW_DLE_GDB_INDEX_COUNT_ERROR);
96             return DW_DLV_ERROR;
97         }
98         count = end - start;
99         count = count / entrylen;
100         hdr->dg_type = type;
101         hdr->dg_base = start;
102         hdr->dg_count = count;
103         hdr->dg_entry_length = entrylen;
104         hdr->dg_fieldlen = fieldlen;
105     } else {
106         /* address area. */
107         /* 64bit, 64bit, offset. Then 32bit pad. */
108         Dwarf_Unsigned count = 0;
109         hdr->dg_base = start;
110         if( end < start) {
111             _dwarf_error(dbg, err,DW_DLE_GDB_INDEX_COUNT_ADDR_ERROR);
112             return DW_DLV_ERROR;
113         }
114         /* entry length includes pad. */
115         hdr->dg_entry_length = 2*sizeof(gdbindex_64) +
116             DWARF_32BIT_SIZE;
117         count = end - start;
118         count = count / hdr->dg_entry_length;
119         hdr->dg_count = count;
120         /*  The dg_fieldlen is a fake, the fields are not
121             all the same length. */
122         hdr->dg_fieldlen = DWARF_32BIT_SIZE;
123         hdr->dg_type = type;
124     }
125     return DW_DLV_OK;
126 }
127 
128 int
129 dwarf_gdbindex_header(Dwarf_Debug dbg,
130     Dwarf_Gdbindex * gdbindexptr,
131     Dwarf_Unsigned * version,
132     Dwarf_Unsigned * cu_list_offset,
133     Dwarf_Unsigned * types_cu_list_offset,
134     Dwarf_Unsigned * address_area_offset,
135     Dwarf_Unsigned * symbol_table_offset,
136     Dwarf_Unsigned * constant_pool_offset,
137     Dwarf_Unsigned * section_size,
138     Dwarf_Unsigned * unused_reserved,
139     const char    ** section_name,
140     Dwarf_Error    * error)
141 {
142 
143     struct gi_fileheader_s header;
144     Dwarf_Gdbindex indexptr = 0;
145     int res = DW_DLV_ERROR;
146 
147     if (!dbg->de_debug_gdbindex.dss_size) {
148         return DW_DLV_NO_ENTRY;
149     }
150     if (!dbg->de_debug_gdbindex.dss_data) {
151         res = _dwarf_load_section(dbg, &dbg->de_debug_gdbindex,error);
152         if (res != DW_DLV_OK) {
153             return res;
154         }
155     }
156 
157     if (dbg->de_debug_gdbindex.dss_size <
158         sizeof(struct gi_fileheader_s) ) {
159         _dwarf_error(dbg, error, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION);
160         return (DW_DLV_ERROR);
161     }
162     memcpy(&header,dbg->de_debug_gdbindex.dss_data,
163         sizeof(struct gi_fileheader_s));
164     indexptr = (Dwarf_Gdbindex)_dwarf_get_alloc(dbg,DW_DLA_GDBINDEX,1);
165     if (indexptr == NULL) {
166         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
167         return (DW_DLV_ERROR);
168     }
169 
170     indexptr->gi_dbg = dbg;
171     indexptr->gi_section_data = dbg->de_debug_gdbindex.dss_data;
172     indexptr->gi_section_length = dbg->de_debug_gdbindex.dss_size;
173     READ_GDBINDEX(indexptr->gi_version ,Dwarf_Unsigned,
174         dbg->de_debug_gdbindex.dss_data,
175         DWARF_32BIT_SIZE);
176     READ_GDBINDEX(indexptr->gi_cu_list_offset ,Dwarf_Unsigned,
177         dbg->de_debug_gdbindex.dss_data + DWARF_32BIT_SIZE,
178         DWARF_32BIT_SIZE);
179     READ_GDBINDEX(indexptr->gi_types_cu_list_offset ,Dwarf_Unsigned,
180         dbg->de_debug_gdbindex.dss_data + 2*DWARF_32BIT_SIZE,
181         DWARF_32BIT_SIZE);
182     READ_GDBINDEX(indexptr->gi_address_area_offset ,Dwarf_Unsigned,
183         dbg->de_debug_gdbindex.dss_data + 3*DWARF_32BIT_SIZE,
184         DWARF_32BIT_SIZE);
185     READ_GDBINDEX(indexptr->gi_symbol_table_offset ,Dwarf_Unsigned,
186         dbg->de_debug_gdbindex.dss_data + 4*DWARF_32BIT_SIZE,
187         DWARF_32BIT_SIZE);
188     READ_GDBINDEX(indexptr->gi_constant_pool_offset ,Dwarf_Unsigned,
189         dbg->de_debug_gdbindex.dss_data + 5*DWARF_32BIT_SIZE,
190         DWARF_32BIT_SIZE);
191 
192     res = set_base(dbg,&indexptr->gi_culisthdr,
193         dbg->de_debug_gdbindex.dss_data + indexptr->gi_cu_list_offset,
194         dbg->de_debug_gdbindex.dss_data + indexptr->gi_types_cu_list_offset,
195         2*sizeof(gdbindex_64),
196         sizeof(gdbindex_64),
197         git_std,error);
198     if (res == DW_DLV_ERROR) {
199         return res;
200     }
201     res = set_base(dbg,&indexptr->gi_typesculisthdr,
202         dbg->de_debug_gdbindex.dss_data + indexptr->gi_types_cu_list_offset,
203         dbg->de_debug_gdbindex.dss_data + indexptr->gi_address_area_offset,
204         3*sizeof(gdbindex_64),
205         sizeof(gdbindex_64),
206         git_std,error);
207     if (res == DW_DLV_ERROR) {
208         return res;
209     }
210     res = set_base(dbg,&indexptr->gi_addressareahdr,
211         dbg->de_debug_gdbindex.dss_data + indexptr->gi_address_area_offset,
212         dbg->de_debug_gdbindex.dss_data + indexptr->gi_symbol_table_offset,
213         3*sizeof(gdbindex_64),
214         sizeof(gdbindex_64),
215         git_address,error);
216     if (res == DW_DLV_ERROR) {
217         return res;
218     }
219     res = set_base(dbg,&indexptr->gi_symboltablehdr,
220         dbg->de_debug_gdbindex.dss_data + indexptr->gi_symbol_table_offset,
221         dbg->de_debug_gdbindex.dss_data + indexptr->gi_constant_pool_offset,
222         2*DWARF_32BIT_SIZE,
223         DWARF_32BIT_SIZE,
224         git_std,error);
225     if (res == DW_DLV_ERROR) {
226         return res;
227     }
228     res = set_base(dbg,&indexptr->gi_cuvectorhdr,
229         dbg->de_debug_gdbindex.dss_data + indexptr->gi_constant_pool_offset,
230         /*  There is no real single vector size.
231             but we'll use the entire rest as if there was. */
232         dbg->de_debug_gdbindex.dss_data + indexptr->gi_section_length,
233         DWARF_32BIT_SIZE,
234         DWARF_32BIT_SIZE,
235         git_cuvec,error);
236     if (res == DW_DLV_ERROR) {
237         return res;
238     }
239 
240     /* Really just pointing to constant pool area. */
241     indexptr->gi_string_pool = dbg->de_debug_gdbindex.dss_data +
242         indexptr->gi_constant_pool_offset;
243     *gdbindexptr          = indexptr;
244     *version              = indexptr->gi_version;
245     *cu_list_offset       = indexptr->gi_cu_list_offset;
246     *types_cu_list_offset = indexptr->gi_types_cu_list_offset;
247     *address_area_offset  = indexptr->gi_address_area_offset;
248     *symbol_table_offset  = indexptr->gi_symbol_table_offset;
249     *constant_pool_offset = indexptr->gi_constant_pool_offset;
250     *section_size         = indexptr->gi_section_length;
251     *unused_reserved = 0;
252     *section_name  =        dbg->de_debug_gdbindex.dss_name;
253     return DW_DLV_OK;
254 
255 
256 }
257 
258 
259 int
260 dwarf_gdbindex_culist_array(Dwarf_Gdbindex gdbindexptr,
261     Dwarf_Unsigned       * list_length,
262     UNUSEDARG Dwarf_Error          * error)
263 {
264     *list_length = gdbindexptr->gi_culisthdr.dg_count;
265     return DW_DLV_OK;
266 }
267 
268 /*  entryindex: 0 to list_length-1 */
269 int
270 dwarf_gdbindex_culist_entry(Dwarf_Gdbindex gdbindexptr,
271     Dwarf_Unsigned   entryindex,
272     Dwarf_Unsigned * cu_offset,
273     Dwarf_Unsigned * cu_length,
274     Dwarf_Error    * error)
275 {
276     Dwarf_Unsigned max =  gdbindexptr->gi_culisthdr.dg_count;
277     Dwarf_Small * base = 0;
278     Dwarf_Unsigned offset = 0;
279     Dwarf_Unsigned length = 0;
280     unsigned fieldlen = gdbindexptr->gi_culisthdr.dg_fieldlen;
281 
282     if (entryindex >= max) {
283         _dwarf_error(gdbindexptr->gi_dbg, error,DW_DLE_GDB_INDEX_INDEX_ERROR);
284         return DW_DLV_ERROR;
285     }
286     base = gdbindexptr->gi_culisthdr.dg_base;
287     base += entryindex*gdbindexptr->gi_culisthdr.dg_entry_length;
288 
289     READ_GDBINDEX(offset ,Dwarf_Unsigned,
290         base,
291         fieldlen);
292     READ_GDBINDEX(length ,Dwarf_Unsigned,
293         base+ fieldlen,
294         fieldlen);
295     *cu_offset = offset;
296     *cu_length = length;
297     return DW_DLV_OK;
298 }
299 
300 int
301 dwarf_gdbindex_types_culist_array(Dwarf_Gdbindex gdbindexptr,
302     Dwarf_Unsigned       * list_length,
303     UNUSEDARG Dwarf_Error          * error)
304 {
305     *list_length = gdbindexptr->gi_typesculisthdr.dg_count;
306     return DW_DLV_OK;
307 }
308 
309 /*  entryindex: 0 to list_length-1 */
310 int
311 dwarf_gdbindex_types_culist_entry(Dwarf_Gdbindex gdbindexptr,
312     Dwarf_Unsigned   entryindex,
313     Dwarf_Unsigned * t_offset,
314     Dwarf_Unsigned * t_length,
315     Dwarf_Unsigned * t_signature,
316     Dwarf_Error    * error)
317 {
318     Dwarf_Unsigned max =  gdbindexptr->gi_typesculisthdr.dg_count;
319     Dwarf_Small * base = 0;
320     Dwarf_Unsigned offset = 0;
321     Dwarf_Unsigned length = 0;
322     Dwarf_Unsigned signature = 0;
323     unsigned fieldlen = gdbindexptr->gi_typesculisthdr.dg_fieldlen;
324 
325     if (entryindex >= max) {
326         _dwarf_error(gdbindexptr->gi_dbg, error,DW_DLE_GDB_INDEX_INDEX_ERROR);
327         return DW_DLV_ERROR;
328     }
329     base = gdbindexptr->gi_typesculisthdr.dg_base;
330     base += entryindex*gdbindexptr->gi_typesculisthdr.dg_entry_length;
331 
332     READ_GDBINDEX(offset ,Dwarf_Unsigned,
333         base,
334         fieldlen);
335     READ_GDBINDEX(length ,Dwarf_Unsigned,
336         base+ (1*fieldlen),
337         fieldlen);
338     READ_GDBINDEX(signature ,Dwarf_Unsigned,
339         base+ (2*fieldlen),
340         fieldlen);
341     *t_offset = offset;
342     *t_length = length;
343     *t_signature = signature;
344     return DW_DLV_OK;
345 }
346 
347 int
348 dwarf_gdbindex_addressarea(Dwarf_Gdbindex gdbindexptr,
349     Dwarf_Unsigned            * list_length,
350     UNUSEDARG Dwarf_Error               * error)
351 {
352     *list_length = gdbindexptr->gi_addressareahdr.dg_count;
353     return DW_DLV_OK;
354 }
355 
356 /*    entryindex: 0 to addressarea_list_length-1 */
357 int
358 dwarf_gdbindex_addressarea_entry(
359     Dwarf_Gdbindex   gdbindexptr,
360     Dwarf_Unsigned   entryindex,
361     Dwarf_Unsigned * low_address,
362     Dwarf_Unsigned * high_address,
363     Dwarf_Unsigned * cu_index,
364     Dwarf_Error    * error)
365 {
366     Dwarf_Unsigned max =  gdbindexptr->gi_addressareahdr.dg_count;
367     Dwarf_Small * base = 0;
368     Dwarf_Unsigned lowaddr = 0;
369     Dwarf_Unsigned highaddr = 0;
370     Dwarf_Unsigned cuindex = 0;
371 
372     if (entryindex >= max) {
373         _dwarf_error(gdbindexptr->gi_dbg, error,DW_DLE_GDB_INDEX_INDEX_ERROR);
374         return DW_DLV_ERROR;
375     }
376     base = gdbindexptr->gi_addressareahdr.dg_base;
377     base += entryindex*gdbindexptr->gi_addressareahdr.dg_entry_length;
378 
379     READ_GDBINDEX(lowaddr ,Dwarf_Unsigned,
380         base,
381         sizeof(gdbindex_64));
382     READ_GDBINDEX(highaddr ,Dwarf_Unsigned,
383         base+ (1*sizeof(gdbindex_64)),
384         sizeof(gdbindex_64));
385     READ_GDBINDEX(cuindex ,Dwarf_Unsigned,
386         base+ (2*sizeof(gdbindex_64)),
387         DWARF_32BIT_SIZE);
388     *low_address = lowaddr;
389     *high_address = highaddr;
390     *cu_index = cuindex;
391     return DW_DLV_OK;
392 }
393 
394 int
395 dwarf_gdbindex_symboltable_array(Dwarf_Gdbindex gdbindexptr,
396     Dwarf_Unsigned            * list_length,
397     UNUSEDARG Dwarf_Error               * error)
398 {
399     *list_length = gdbindexptr->gi_symboltablehdr.dg_count;
400     return DW_DLV_OK;
401 }
402 
403 /*  entryindex: 0 to symtab_list_length-1 */
404 int
405 dwarf_gdbindex_symboltable_entry(
406     Dwarf_Gdbindex   gdbindexptr,
407     Dwarf_Unsigned   entryindex,
408     Dwarf_Unsigned * string_offset,
409     Dwarf_Unsigned * cu_vector_offset,
410     Dwarf_Error    * error)
411 {
412     Dwarf_Unsigned max =  gdbindexptr->gi_symboltablehdr.dg_count;
413     Dwarf_Small * base = 0;
414     Dwarf_Unsigned symoffset = 0;
415     Dwarf_Unsigned cuoffset = 0;
416     unsigned fieldlen = gdbindexptr->gi_symboltablehdr.dg_fieldlen;
417 
418     if (entryindex >= max) {
419         _dwarf_error(gdbindexptr->gi_dbg, error,DW_DLE_GDB_INDEX_INDEX_ERROR);
420         return DW_DLV_ERROR;
421     }
422     base = gdbindexptr->gi_symboltablehdr.dg_base;
423     base += entryindex*gdbindexptr->gi_symboltablehdr.dg_entry_length;
424 
425     READ_GDBINDEX(symoffset ,Dwarf_Unsigned,
426         base,
427         fieldlen);
428     READ_GDBINDEX(cuoffset ,Dwarf_Unsigned,
429         base + fieldlen,
430         fieldlen);
431     *string_offset = symoffset;
432     *cu_vector_offset = cuoffset;
433     return DW_DLV_OK;
434 }
435 
436 int
437 dwarf_gdbindex_cuvector_length(Dwarf_Gdbindex gdbindex,
438     Dwarf_Unsigned   cuvector_offset,
439     Dwarf_Unsigned * innercount,
440     Dwarf_Error    * error)
441 {
442     Dwarf_Small *base = gdbindex->gi_cuvectorhdr.dg_base;
443     Dwarf_Small *end = gdbindex->gi_section_data + gdbindex->gi_section_length;
444     Dwarf_Unsigned val = 0;
445     unsigned fieldlen =  gdbindex->gi_cuvectorhdr.dg_entry_length;
446 
447     base += cuvector_offset;
448     if ((base + fieldlen) >= end) {
449         _dwarf_error(gdbindex->gi_dbg, error,DW_DLE_GDB_INDEX_INDEX_ERROR);
450         return DW_DLV_ERROR;
451     }
452 
453     READ_GDBINDEX(val,Dwarf_Unsigned,
454         base,
455         fieldlen);
456     *innercount = val;
457     return DW_DLV_OK;
458 }
459 
460 int
461 dwarf_gdbindex_cuvector_inner_attributes(Dwarf_Gdbindex gdbindexptr,
462     Dwarf_Unsigned   cuvector_offset,
463     Dwarf_Unsigned   innerindex,
464     /* The attr_value is a field of bits. For expanded version
465         use  dwarf_gdbindex_instance_expand_value() */
466     Dwarf_Unsigned * attributes,
467     Dwarf_Error    * error)
468 {
469     Dwarf_Small *base = gdbindexptr->gi_cuvectorhdr.dg_base;
470     Dwarf_Small *end = gdbindexptr->gi_section_data +
471         gdbindexptr->gi_section_length;
472     Dwarf_Unsigned val = 0;
473     unsigned fieldlen = gdbindexptr->gi_cuvectorhdr.dg_entry_length;
474 
475     base += cuvector_offset;
476     if ((base+fieldlen) >= end) {
477         _dwarf_error(gdbindexptr->gi_dbg, error,DW_DLE_GDB_INDEX_INDEX_ERROR);
478         return DW_DLV_ERROR;
479     }
480     base += fieldlen;
481     base += innerindex*fieldlen;
482 
483     READ_GDBINDEX(val ,Dwarf_Unsigned,
484         base,
485         fieldlen);
486     *attributes = val;
487     return DW_DLV_OK;
488 }
489 
490 
491 int
492 dwarf_gdbindex_cuvector_instance_expand_value(
493     UNUSEDARG Dwarf_Gdbindex gdbindexptr,
494     Dwarf_Unsigned   value,
495     Dwarf_Unsigned * cu_index,
496     Dwarf_Unsigned * reserved1,
497     Dwarf_Unsigned * symbol_kind,
498     Dwarf_Unsigned * is_static,
499     UNUSEDARG Dwarf_Error    * error)
500 {
501     *cu_index =    value         & 0xffffff;
502     *reserved1 =   (value >> 24) & 0xf;
503     *symbol_kind = (value >> 28) & 0x7;
504     *is_static =   (value >> 31) & 1;
505     return DW_DLV_OK;
506 }
507 
508 
509 /*  The strings in the pool follow (in memory) the cu index
510     set and are NUL terminated. */
511 int
512 dwarf_gdbindex_string_by_offset(Dwarf_Gdbindex gdbindexptr,
513     Dwarf_Unsigned   stringoffsetinpool,
514     const char    ** string_ptr,
515     UNUSEDARG Dwarf_Error   *  error)
516 {
517     Dwarf_Small *pooldata = 0;
518     Dwarf_Small *section_end = 0;
519     Dwarf_Small *stringitself = 0;
520 
521     /*  If gdbindexptr NULL or gdbindexptr->gi_dbg is NULL
522         this is not going to go very well. Ugh. FIXME */
523     pooldata = gdbindexptr->gi_section_data +
524         gdbindexptr->gi_constant_pool_offset;
525     section_end = gdbindexptr->gi_section_data +
526         gdbindexptr->gi_section_length;
527     stringitself = pooldata + stringoffsetinpool;
528     if (stringitself > section_end) {
529         _dwarf_error(gdbindexptr->gi_dbg, error,DW_DLE_GDB_INDEX_INDEX_ERROR);
530         return DW_DLV_ERROR;
531     }
532     *string_ptr = (const char *)stringitself;
533     return DW_DLV_OK;
534 }
535 
536 
537 
538 
539 void
540 dwarf_gdbindex_free(Dwarf_Gdbindex indexptr)
541 {
542     if(indexptr) {
543         Dwarf_Debug dbg = indexptr->gi_dbg;
544         dwarf_dealloc(dbg,indexptr,DW_DLA_GDBINDEX);
545     }
546 }
547