xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_global.c (revision 33c72b7598992897b94815b1f47b7b8077e53808)
1 /*
2 
3   Copyright (C) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
4   Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of version 2.1 of the GNU Lesser General Public License
8   as published by the Free Software Foundation.
9 
10   This program is distributed in the hope that it would be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14   Further, this software is distributed without any warranty that it is
15   free of the rightful claim of any third person regarding infringement
16   or the like.  Any license provided herein, whether implied or
17   otherwise, applies only to this software file.  Patent licenses, if
18   any, provided herein do not apply to combinations of this program with
19   other software, or any other product whatsoever.
20 
21   You should have received a copy of the GNU Lesser General Public
22   License along with this program; if not, write the Free Software
23   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
24   USA.
25 
26   Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
27   Mountain View, CA 94043, or:
28 
29   http://www.sgi.com
30 
31   For further information regarding this notice, see:
32 
33   http://oss.sgi.com/projects/GenInfo/NoticeExplan
34 
35 */
36 /* The address of the Free Software Foundation is
37    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
38    Boston, MA 02110-1301, USA.
39    SGI has moved from the Crittenden Lane address.
40 */
41 
42 
43 
44 
45 #include "config.h"
46 #include "dwarf_incl.h"
47 #include <stdio.h>
48 #include "dwarf_global.h"
49 
50 
51 #ifdef __sgi  /* __sgi should only be defined for IRIX/MIPS. */
52 /* The 'fixup' here intended for IRIX targets only.
53    With a  2+GB Elf64 IRIX executable (under 4GB in size),
54    some DIE offsets wrongly
55    got the 32bit upper bit sign extended.  For the cu-header
56    offset in the .debug_pubnames section  and in the
57    .debug_aranges section.
58    the 'varp' here is a pointer to an offset into .debug_info.
59    We fix up the offset here if it seems advisable..
60 
61    As of June 2005 we have identified a series of mistakes
62    in ldx64 that can cause this (64 bit values getting passed
63    thru 32-bit signed knothole).
64 */
65 void
66 _dwarf_fix_up_offset_irix(Dwarf_Debug dbg,
67     Dwarf_Unsigned * varp, char *caller_site_name)
68 {
69 
70     Dwarf_Unsigned var = *varp;
71 
72 #define UPPER33 0xffffffff80000000LL
73 #define LOWER32         0xffffffffLL
74     /* Restrict the hack to the known case. Upper 32 bits erroneously
75        sign extended from lower 32 upper bit. */
76     if ((var & UPPER33) == UPPER33) {
77         var &= LOWER32;
78         /* Apply the fix. Dreadful hack. */
79         *varp = var;
80     }
81 #undef UPPER33
82 #undef LOWER32
83     return;
84 }
85 #endif
86 
87 
88 int
89 dwarf_get_globals(Dwarf_Debug dbg,
90     Dwarf_Global ** globals,
91     Dwarf_Signed * return_count, Dwarf_Error * error)
92 {
93     int res = _dwarf_load_section(dbg, &dbg->de_debug_pubnames,error);
94     if (res != DW_DLV_OK) {
95         return res;
96     }
97 
98     return _dwarf_internal_get_pubnames_like_data(dbg,
99         dbg->de_debug_pubnames.dss_data,
100         dbg->de_debug_pubnames.dss_size,
101         globals,
102         return_count,
103         error,
104         DW_DLA_GLOBAL_CONTEXT,
105         DW_DLA_GLOBAL,
106         DW_DLE_PUBNAMES_LENGTH_BAD,
107         DW_DLE_PUBNAMES_VERSION_ERROR);
108 
109 }
110 
111 /* Deallocating fully requires deallocating the list
112    and all entries.  But some internal data is
113    not exposed, so we need a function with internal knowledge.
114 */
115 
116 void
117 dwarf_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl,
118     Dwarf_Signed count)
119 {
120     _dwarf_internal_globals_dealloc(dbg, dwgl,
121         count,
122         DW_DLA_GLOBAL_CONTEXT,
123         DW_DLA_GLOBAL, DW_DLA_LIST);
124     return;
125 }
126 
127 void
128 _dwarf_internal_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl,
129     Dwarf_Signed count,
130     int context_code,
131     int global_code, int list_code)
132 {
133     Dwarf_Signed i;
134     struct Dwarf_Global_Context_s *gcp = 0;
135     struct Dwarf_Global_Context_s *lastgcp = 0;
136 
137     for (i = 0; i < count; i++) {
138         Dwarf_Global dgb = dwgl[i];
139 
140         gcp = dgb->gl_context;
141 
142         if (lastgcp != gcp) {
143             lastgcp = gcp;
144             dwarf_dealloc(dbg, gcp, context_code);
145         }
146         dwarf_dealloc(dbg, dgb, global_code);
147     }
148     dwarf_dealloc(dbg, dwgl, list_code);
149     return;
150 }
151 
152 
153 /* Sweeps the complete  section.
154 */
155 int
156 _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg,
157     Dwarf_Small * section_data_ptr,
158     Dwarf_Unsigned section_length,
159     Dwarf_Global ** globals,
160     Dwarf_Signed * return_count,
161     Dwarf_Error * error,
162     int context_code,
163     int global_code,
164     int length_err_num,
165     int version_err_num)
166 {
167 
168 
169     Dwarf_Small *pubnames_like_ptr = 0;
170 
171 
172 
173     /* Points to the context for the current set of global names, and
174        contains information to identify the compilation-unit that the
175        set refers to. */
176     Dwarf_Global_Context pubnames_context = 0;
177 
178     Dwarf_Half version = 0;
179 
180     /*
181        Offset from the start of compilation-unit for the current
182        global. */
183     Dwarf_Off die_offset_in_cu = 0;
184 
185     Dwarf_Unsigned global_count = 0;
186 
187     /* Points to the current global read. */
188     Dwarf_Global global = 0;
189 
190     /* Used to chain the Dwarf_Global_s structs for creating contiguous
191        list of pointers to the structs. */
192     Dwarf_Chain curr_chain = 0;
193     Dwarf_Chain prev_chain = 0;
194     Dwarf_Chain head_chain = 0;
195 
196     /* Points to contiguous block of Dwarf_Global's to be returned. */
197     Dwarf_Global *ret_globals = 0;
198 
199     /* Temporary counter. */
200     Dwarf_Unsigned i = 0;
201 
202 
203 
204 
205     if (dbg == NULL) {
206         _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
207         return (DW_DLV_ERROR);
208     }
209     /* We will eventually need the .debug_info data. Load it now. */
210     if (!dbg->de_debug_info.dss_data) {
211         int res = _dwarf_load_debug_info(dbg, error);
212 
213         if (res != DW_DLV_OK) {
214             return res;
215         }
216     }
217 
218     if (section_data_ptr == NULL) {
219         return (DW_DLV_NO_ENTRY);
220     }
221 
222     pubnames_like_ptr = section_data_ptr;
223     do {
224         Dwarf_Unsigned length = 0;
225         int local_extension_size = 0;
226         int local_length_size = 0;
227 
228         /* Some compilers emit padding at the end of each cu's area.
229            pubnames_ptr_past_end_cu records the true area end for this
230            cu's data.  Essentially the length in the header and the 0
231            terminator of the data are redundant information. The
232            dwarf2/3 spec does not mention what to do if the length is
233            past the 0 terminator. So we take any bytes left after the 0
234            as padding and ignore them. */
235         Dwarf_Small *pubnames_ptr_past_end_cu = 0;
236 
237 
238         pubnames_context = (Dwarf_Global_Context)
239             _dwarf_get_alloc(dbg, context_code, 1);
240         if (pubnames_context == NULL) {
241             _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
242         return (DW_DLV_ERROR);
243         }
244         /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed
245            bytes. */
246         READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
247             pubnames_like_ptr, local_length_size,
248             local_extension_size);
249         pubnames_context->pu_length_size = local_length_size;
250         pubnames_context->pu_extension_size = local_extension_size;
251         pubnames_context->pu_dbg = dbg;
252 
253         pubnames_ptr_past_end_cu = pubnames_like_ptr + length;
254 
255         READ_UNALIGNED(dbg, version, Dwarf_Half,
256                        pubnames_like_ptr, sizeof(Dwarf_Half));
257         pubnames_like_ptr += sizeof(Dwarf_Half);
258         if (version != CURRENT_VERSION_STAMP) {
259             _dwarf_error(dbg, error, version_err_num);
260             return (DW_DLV_ERROR);
261         }
262 
263         /* Offset of CU header in debug section. */
264         READ_UNALIGNED(dbg, pubnames_context->pu_offset_of_cu_header,
265                        Dwarf_Off, pubnames_like_ptr,
266                        pubnames_context->pu_length_size);
267         pubnames_like_ptr += pubnames_context->pu_length_size;
268 
269         FIX_UP_OFFSET_IRIX_BUG(dbg,
270                                pubnames_context->pu_offset_of_cu_header,
271                                "pubnames cu header offset");
272 
273 
274         READ_UNALIGNED(dbg, pubnames_context->pu_info_length,
275                        Dwarf_Unsigned, pubnames_like_ptr,
276                        pubnames_context->pu_length_size);
277         pubnames_like_ptr += pubnames_context->pu_length_size;
278 
279         if (pubnames_like_ptr > (section_data_ptr + section_length)) {
280             _dwarf_error(dbg, error, length_err_num);
281             return (DW_DLV_ERROR);
282         }
283 
284         /* Read initial offset (of DIE within CU) of a pubname, final
285            entry is not a pair, just a zero offset. */
286         READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off,
287                        pubnames_like_ptr,
288                        pubnames_context->pu_length_size);
289         pubnames_like_ptr += pubnames_context->pu_length_size;
290         FIX_UP_OFFSET_IRIX_BUG(dbg,
291                                die_offset_in_cu, "offset of die in cu");
292 
293         /* Loop thru pairs. DIE off with CU followed by string. */
294         while (die_offset_in_cu != 0) {
295 
296             /* Already read offset, pubnames_like_ptr now points to the
297                string. */
298             global =
299                 (Dwarf_Global) _dwarf_get_alloc(dbg, global_code, 1);
300             if (global == NULL) {
301                 _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
302                 return (DW_DLV_ERROR);
303             }
304             global_count++;
305 
306             global->gl_context = pubnames_context;
307 
308             global->gl_named_die_offset_within_cu = die_offset_in_cu;
309 
310             global->gl_name = pubnames_like_ptr;
311 
312             pubnames_like_ptr = pubnames_like_ptr +
313                 strlen((char *) pubnames_like_ptr) + 1;
314 
315 
316             /* finish off current entry chain */
317             curr_chain =
318                 (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
319             if (curr_chain == NULL) {
320                 _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
321                 return (DW_DLV_ERROR);
322             }
323 
324             /* Put current global on singly_linked list. */
325             curr_chain->ch_item = (Dwarf_Global) global;
326 
327             if (head_chain == NULL)
328                 head_chain = prev_chain = curr_chain;
329             else {
330                 prev_chain->ch_next = curr_chain;
331                 prev_chain = curr_chain;
332             }
333 
334             /* read offset for the *next* entry */
335             READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off,
336                            pubnames_like_ptr,
337                            pubnames_context->pu_length_size);
338 
339             pubnames_like_ptr += pubnames_context->pu_length_size;
340             FIX_UP_OFFSET_IRIX_BUG(dbg,
341                                    die_offset_in_cu,
342                                    "offset of next die in cu");
343 
344             if (pubnames_like_ptr > (section_data_ptr + section_length)) {
345                 _dwarf_error(dbg, error, length_err_num);
346                 return (DW_DLV_ERROR);
347             }
348         }
349         /* ASSERT: die_offset_in_cu == 0 */
350         if (pubnames_like_ptr > pubnames_ptr_past_end_cu) {
351             /* This is some kind of error. This simply cannot happen.
352             The encoding is wrong or the length in the header for
353             this cu's contribution is wrong. */
354             _dwarf_error(dbg, error, length_err_num);
355             return (DW_DLV_ERROR);
356         }
357         /* If there is some kind of padding at the end of the section,
358            as emitted by some compilers, skip over that padding and
359            simply ignore the bytes thus passed-over.  With most
360            compilers, pubnames_like_ptr == pubnames_ptr_past_end_cu at
361            this point */
362         pubnames_like_ptr = pubnames_ptr_past_end_cu;
363 
364     } while (pubnames_like_ptr < (section_data_ptr + section_length));
365 
366     /* Points to contiguous block of Dwarf_Global's. */
367     ret_globals = (Dwarf_Global *)
368         _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count);
369     if (ret_globals == NULL) {
370         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
371         return (DW_DLV_ERROR);
372     }
373 
374     /*
375        Store pointers to Dwarf_Global_s structs in contiguous block,
376        and deallocate the chain. */
377     curr_chain = head_chain;
378     for (i = 0; i < global_count; i++) {
379         *(ret_globals + i) = curr_chain->ch_item;
380         prev_chain = curr_chain;
381         curr_chain = curr_chain->ch_next;
382         dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
383     }
384 
385     *globals = ret_globals;
386     *return_count = (Dwarf_Signed) global_count;
387     return DW_DLV_OK;
388 }
389 
390 
391 /*
392         Given a pubnames entry (or other like section entry)
393         return thru the ret_name pointer
394         a pointer to the string which is the entry name.
395 
396 */
397 int
398 dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error)
399 {
400     if (glob == NULL) {
401         _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
402         return (DW_DLV_ERROR);
403     }
404 
405     *ret_name = (char *) (glob->gl_name);
406     return DW_DLV_OK;
407 }
408 
409 
410 /*
411         Given a pubnames entry (or other like section entry)
412         return thru the ret_off pointer the
413         global offset of the DIE for this entry.
414         The global offset is the offset within the .debug_info
415         section as a whole.
416 */
417 int
418 dwarf_global_die_offset(Dwarf_Global global,
419                         Dwarf_Off * ret_off, Dwarf_Error * error)
420 {
421     if (global == NULL) {
422         _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
423         return (DW_DLV_ERROR);
424     }
425 
426     if (global->gl_context == NULL) {
427         _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
428         return (DW_DLV_ERROR);
429     }
430 
431     *ret_off = (global->gl_named_die_offset_within_cu +
432                 global->gl_context->pu_offset_of_cu_header);
433     return DW_DLV_OK;
434 }
435 
436 /*
437         Given a pubnames entry (or other like section entry)
438         return thru the ret_off pointer the
439         offset of the compilation unit header of the
440         compilation unit the global is part of.
441 
442         In early versions of this, the value returned was
443         the offset of the compilation unit die, and
444         other cu-local die offsets were faked so adding this to
445         such a cu-local offset got a true section offset.
446         Now things do as they say (adding *cu_header_offset to
447         a cu-local offset gets the section offset).
448 
449 */
450 int
451 dwarf_global_cu_offset(Dwarf_Global global,
452                        Dwarf_Off * cu_header_offset,
453                        Dwarf_Error * error)
454 {
455     Dwarf_Global_Context con = 0;
456 
457     if (global == NULL) {
458         _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
459         return (DW_DLV_ERROR);
460     }
461 
462     con = global->gl_context;
463 
464     if (con == NULL) {
465         _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
466         return (DW_DLV_ERROR);
467     }
468 
469     /* In early libdwarf, this incorrectly returned the offset of the
470        CU DIE. Now correctly returns the header offset. */
471     *cu_header_offset = con->pu_offset_of_cu_header;
472 
473     return DW_DLV_OK;
474 }
475 
476 /*
477   Give back the pubnames entry (or any other like section)
478   name, symbol DIE offset, and the cu-DIE offset.
479 
480   Various errors are possible.
481 
482   The string pointer returned thru ret_name is not
483   dwarf_get_alloc()ed, so no dwarf_dealloc()
484   DW_DLA_STRING should be applied to it.
485 
486 */
487 int
488 dwarf_global_name_offsets(Dwarf_Global global,
489                           char **ret_name,
490                           Dwarf_Off * die_offset,
491                           Dwarf_Off * cu_die_offset,
492                           Dwarf_Error * error)
493 {
494     Dwarf_Global_Context con = 0;
495     Dwarf_Debug dbg = 0;
496     Dwarf_Off off = 0;
497 
498     if (global == NULL) {
499         _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
500         return (DW_DLV_ERROR);
501     }
502 
503     con = global->gl_context;
504 
505     if (con == NULL) {
506         _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
507         return (DW_DLV_ERROR);
508     }
509 
510     off = con->pu_offset_of_cu_header;
511     /* The offset had better not be too close to the end. If it is,
512        _dwarf_length_of_cu_header() will step off the end and therefore
513        must not be used. 10 is a meaningless heuristic, but no CU
514        header is that small so it is safe. An erroneous offset is due
515        to a bug in the tool chain. A bug like this has been seen on
516        IRIX with MIPSpro 7.3.1.3 and an executable > 2GB in size and
517        with 2 million pubnames entries. */
518 #define MIN_CU_HDR_SIZE 10
519     dbg = con->pu_dbg;
520     if (dbg == NULL) {
521         _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
522         return (DW_DLV_ERROR);
523     }
524     if (dbg->de_debug_info.dss_size &&
525         ((off + MIN_CU_HDR_SIZE) >= dbg->de_debug_info.dss_size)) {
526         _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD);
527         return (DW_DLV_ERROR);
528     }
529 #undef MIN_CU_HDR_SIZE
530     if (die_offset != NULL) {
531         *die_offset = global->gl_named_die_offset_within_cu + off;
532     }
533 
534     *ret_name = (char *) global->gl_name;
535 
536     if (cu_die_offset != NULL) {
537         int res = _dwarf_load_debug_info(dbg, error);
538 
539         if (res != DW_DLV_OK) {
540             return res;
541         }
542         /* The offset had better not be too close to the end. If it is,
543            _dwarf_length_of_cu_header() will step off the end and
544            therefore must not be used. 10 is a meaningless heuristic,
545            but no CU header is that small so it is safe. */
546         if ((off + 10) >= dbg->de_debug_info.dss_size) {
547             _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD);
548             return (DW_DLV_ERROR);
549         }
550         *cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off);
551     }
552 
553 
554     return DW_DLV_OK;
555 }
556 
557 /*
558         We have the offset to a CU header.
559         Return thru outFileOffset the offset of the CU DIE.
560 
561         New June, 2001.
562         Used by SGI debuggers.
563         No error is possible.
564 
565         See also dwarf_CU_dieoffset_given_die().
566 */
567 
568 /* ARGSUSED */
569 int
570 dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
571     Dwarf_Off in_cu_header_offset,
572     Dwarf_Off * out_cu_die_offset,
573     Dwarf_Error * err)
574 {
575     Dwarf_Off len =
576         _dwarf_length_of_cu_header(dbg, in_cu_header_offset);
577 
578     Dwarf_Off newoff = in_cu_header_offset + len;
579 
580     *out_cu_die_offset = newoff;
581     return DW_DLV_OK;
582 }
583 /* dwarf_CU_dieoffset_given_die returns
584    the global debug_info section offset of the CU die
585    that is the CU containing the given (passed-in) die.
586    This information makes it possible for a consumer to
587    find and print context information for any die.
588 
589    Use dwarf_offdie() passing in the offset this returns
590    to get a die pointer to the CU die.
591  */
592 int
593 dwarf_CU_dieoffset_given_die(Dwarf_Die die,
594     Dwarf_Off*       return_offset,
595     Dwarf_Error*     error)
596 {
597     Dwarf_Off  dieoff = 0;
598     Dwarf_CU_Context cucontext = 0;
599 
600     CHECK_DIE(die, DW_DLV_ERROR);
601     cucontext = die->di_cu_context;
602     dieoff =  cucontext->cc_debug_info_offset;
603     /* The following call cannot fail, so no error check. */
604     dwarf_get_cu_die_offset_given_cu_header_offset(
605        cucontext->cc_dbg, dieoff, return_offset,error);
606     return DW_DLV_OK;
607 }
608