xref: /titanic_44/usr/src/tools/ctf/dwarf/common/dwarf_global.c (revision f05d7fc81533be643136e12ce92516d1d4292921)
1 /*
2 
3   Copyright (C) 2000, 2002 Silicon Graphics, Inc.  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., 59 Temple Place - Suite 330, Boston MA 02111-1307,
23   USA.
24 
25   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
26   Mountain View, CA 94043, or:
27 
28   http://www.sgi.com
29 
30   For further information regarding this notice, see:
31 
32   http://oss.sgi.com/projects/GenInfo/NoticeExplan
33 
34 */
35 
36 
37 
38 #include "config.h"
39 #include "dwarf_incl.h"
40 #include <stdio.h>
41 #include "dwarf_global.h"
42 
43 int
44 dwarf_get_globals(Dwarf_Debug dbg,
45 		  Dwarf_Global ** globals,
46 		  Dwarf_Signed * return_count, Dwarf_Error * error)
47 {
48     int res;
49 
50     res =
51        _dwarf_load_section(dbg,
52 			   dbg->de_debug_pubnames_index,
53 			   &dbg->de_debug_pubnames,
54 			   error);
55     if (res != DW_DLV_OK) {
56         return res;
57     }
58 
59 
60 
61     return _dwarf_internal_get_pubnames_like_data(dbg,
62 						  dbg->
63 						  de_debug_pubnames,
64 						  dbg->
65 						  de_debug_pubnames_size,
66 						  globals, return_count,
67 						  error,
68 						  DW_DLA_GLOBAL_CONTEXT,
69 						  DW_DLE_PUBNAMES_LENGTH_BAD,
70 						  DW_DLE_PUBNAMES_VERSION_ERROR);
71 
72 }
73 
74 
75 /* Sweeps the complete  section.
76 */
77 int
78 _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg,
79 				       Dwarf_Small * section_data_ptr,
80 				       Dwarf_Unsigned section_length,
81 				       Dwarf_Global ** globals,
82 				       Dwarf_Signed * return_count,
83 				       Dwarf_Error * error,
84 				       int allocation_code,
85 				       int length_err_num,
86 				       int version_err_num)
87 {
88 
89 
90     Dwarf_Small *pubnames_like_ptr;
91 
92 
93 
94     /*
95        Points to the context for the current set of global names, and
96        contains information to identify the compilation-unit that the
97        set refers to. */
98     Dwarf_Global_Context pubnames_context;
99 
100     Dwarf_Half version;
101 
102     /*
103        Offset from the start of compilation-unit for the current
104        global. */
105     Dwarf_Off die_offset_in_cu;
106 
107     Dwarf_Unsigned global_count = 0;
108 
109     /* Points to the current global read. */
110     Dwarf_Global global;
111 
112     /*
113        Used to chain the Dwarf_Global_s structs for creating contiguous
114        list of pointers to the structs. */
115     Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;
116 
117     /* Points to contiguous block of Dwarf_Global's to be returned. */
118     Dwarf_Global *ret_globals;
119 
120     /* Temporary counter. */
121     Dwarf_Unsigned i;
122 
123 
124 
125 
126     if (dbg == NULL) {
127 	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
128 	return (DW_DLV_ERROR);
129     }
130     /* We will eventually need the .debug_info data. Load it now. */
131     if(!dbg->de_debug_info) {
132         int res = _dwarf_load_debug_info(dbg,error);
133         if(res != DW_DLV_OK) {
134               return res;
135         }
136     }
137 
138     if (section_data_ptr == NULL) {
139 	return (DW_DLV_NO_ENTRY);
140     }
141 
142     pubnames_like_ptr = section_data_ptr;
143     do {
144 	Dwarf_Unsigned length;
145 	int local_extension_size;
146 	int local_length_size;
147 
148 	/* Some compilers emit padding at the end of each cu's
149 	   area. pubnames_ptr_past_end_cu records the true
150            area end for this cu's data.  Essentially the
151 	   length in the header and the  0 terminator of the
152            data are redundant information. The dwarf2/3
153 	   spec does not mention what to do if the length
154            is past the 0 terminator. So we take any bytes
155 	   left after the 0 as padding and ignore them. */
156         Dwarf_Small *pubnames_ptr_past_end_cu = 0;
157 
158 
159 	pubnames_context = (Dwarf_Global_Context)
160 	    _dwarf_get_alloc(dbg, allocation_code, 1);
161 	if (pubnames_context == NULL) {
162 	    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
163 	    return (DW_DLV_ERROR);
164 	}
165 	/* READ_AREA_LENGTH updates pubnames_like_ptr for consumed
166 	   bytes */
167 	READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
168 			 pubnames_like_ptr, local_length_size,
169 			 local_extension_size);
170 	pubnames_context->pu_length_size = local_length_size;
171 	pubnames_context->pu_extension_size = local_extension_size;
172 	pubnames_context->pu_dbg = dbg;
173 
174         pubnames_ptr_past_end_cu  = pubnames_like_ptr + length;
175 
176 	READ_UNALIGNED(dbg, version, Dwarf_Half,
177 		       pubnames_like_ptr, sizeof(Dwarf_Half));
178 	pubnames_like_ptr += sizeof(Dwarf_Half);
179 	if (version != CURRENT_VERSION_STAMP) {
180 	    _dwarf_error(dbg, error, version_err_num);
181 	    return (DW_DLV_ERROR);
182 	}
183 
184 	/* offset of CU header in debug section */
185 	READ_UNALIGNED(dbg, pubnames_context->pu_offset_of_cu_header,
186 		       Dwarf_Off, pubnames_like_ptr,
187 		       pubnames_context->pu_length_size);
188 	pubnames_like_ptr += pubnames_context->pu_length_size;
189 
190 
191 	READ_UNALIGNED(dbg, pubnames_context->pu_info_length,
192 		       Dwarf_Unsigned, pubnames_like_ptr,
193 		       pubnames_context->pu_length_size);
194 	pubnames_like_ptr += pubnames_context->pu_length_size;
195 
196 	if (pubnames_like_ptr > (section_data_ptr + section_length)) {
197 	    _dwarf_error(dbg, error, length_err_num);
198 	    return (DW_DLV_ERROR);
199 	}
200 
201 	/* read initial offset (of DIE within CU) of a pubname, final
202 	   entry is not a pair, just a zero offset */
203 	READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off,
204 		       pubnames_like_ptr,
205 		       pubnames_context->pu_length_size);
206 	pubnames_like_ptr += pubnames_context->pu_length_size;
207 
208 	/* loop thru pairs. DIE off with CU followed by string */
209 	while (die_offset_in_cu != 0) {
210 
211 	    /* Already read offset, pubnames_like_ptr now points to the
212 	       string */
213 	    global =
214 		(Dwarf_Global) _dwarf_get_alloc(dbg, DW_DLA_GLOBAL, 1);
215 	    if (global == NULL) {
216 		_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
217 		return (DW_DLV_ERROR);
218 	    }
219 	    global_count++;
220 
221 	    global->gl_context = pubnames_context;
222 
223 	    global->gl_named_die_offset_within_cu = die_offset_in_cu;
224 
225 	    global->gl_name = pubnames_like_ptr;
226 
227 	    pubnames_like_ptr = pubnames_like_ptr +
228 		strlen((char *) pubnames_like_ptr) + 1;
229 
230 
231 	    /* finish off current entry chain */
232 	    curr_chain =
233 		(Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
234 	    if (curr_chain == NULL) {
235 		_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
236 		return (DW_DLV_ERROR);
237 	    }
238 
239 	    /* Put current global on singly_linked list. */
240 	    curr_chain->ch_item = (Dwarf_Global) global;
241 
242 	    if (head_chain == NULL)
243 		head_chain = prev_chain = curr_chain;
244 	    else {
245 		prev_chain->ch_next = curr_chain;
246 		prev_chain = curr_chain;
247 	    }
248 
249 	    /* read offset for the *next* entry */
250 	    READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off,
251 			   pubnames_like_ptr,
252 			   pubnames_context->pu_length_size);
253 
254 	    pubnames_like_ptr += pubnames_context->pu_length_size;
255 	    if (pubnames_like_ptr > (section_data_ptr + section_length)) {
256 		_dwarf_error(dbg, error, length_err_num);
257 		return (DW_DLV_ERROR);
258 	    }
259 	}
260 	/* ASSERT: die_offset_in_cu == 0 */
261 	if(pubnames_like_ptr > pubnames_ptr_past_end_cu) {
262 	   /* This is some kind of error. This simply cannot happen.
263 	      The encoding is wrong or the length in the header
264 	      for this cu's contribution is wrong. */
265 	   _dwarf_error(dbg, error, length_err_num);
266 	   return (DW_DLV_ERROR);
267 
268         }
269 	/* If there is some kind of padding at the end of
270            the section, as emitted by some compilers,
271 	   skip over that padding and simply ignore the bytes
272 	   thus passed-over.   With most compilers,
273 	     pubnames_like_ptr == pubnames_ptr_past_end_cu
274 	   at this point */
275 	pubnames_like_ptr =  pubnames_ptr_past_end_cu;
276 
277     } while (pubnames_like_ptr < (section_data_ptr + section_length));
278 
279     /* Points to contiguous block of Dwarf_Global's. */
280     ret_globals = (Dwarf_Global *)
281 	_dwarf_get_alloc(dbg, DW_DLA_LIST, global_count);
282     if (ret_globals == NULL) {
283 	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
284 	return (DW_DLV_ERROR);
285     }
286 
287     /*
288        Store pointers to Dwarf_Global_s structs in contiguous block,
289        and deallocate the chain. */
290     curr_chain = head_chain;
291     for (i = 0; i < global_count; i++) {
292 	*(ret_globals + i) = curr_chain->ch_item;
293 	prev_chain = curr_chain;
294 	curr_chain = curr_chain->ch_next;
295 	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
296     }
297 
298     *globals = ret_globals;
299     *return_count = (global_count);
300     return DW_DLV_OK;
301 }
302 
303 /*
304 	Given a pubnames entry (or other like section entry)
305 	return thru the ret_name pointer
306 	a pointer to the string which is the entry name.
307 
308 */
309 int
310 dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error)
311 {
312     if (glob == NULL) {
313 	_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
314 	return (DW_DLV_ERROR);
315     }
316 
317     *ret_name = (char *) (glob->gl_name);
318     return DW_DLV_OK;
319 }
320 
321 
322 /*
323 	Given a pubnames entry (or other like section entry)
324 	return thru the ret_off pointer the
325 	global offset of the DIE for this entry.
326 	The global offset is the offset within the .debug_info
327 	section as a whole.
328 */
329 int
330 dwarf_global_die_offset(Dwarf_Global global,
331 			Dwarf_Off * ret_off, Dwarf_Error * error)
332 {
333     if (global == NULL) {
334 	_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
335 	return (DW_DLV_ERROR);
336     }
337 
338     if (global->gl_context == NULL) {
339 	_dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
340 	return (DW_DLV_ERROR);
341     }
342 
343     *ret_off = (global->gl_named_die_offset_within_cu +
344 		global->gl_context->pu_offset_of_cu_header);
345     return DW_DLV_OK;
346 }
347 
348 /*
349 	Given a pubnames entry (or other like section entry)
350 	return thru the ret_off pointer the
351 	offset of the compilation unit header of the
352         compilation unit the global is part of.
353 
354 	In early versions of this, the value returned was
355         the offset of the compilation unit die, and
356 	other cu-local die offsets were faked so adding this to
357         such a cu-local offset got a true section offset.
358         Now things do as they say (adding *cu_header_offset to
359         a cu-local offset gets the section offset).
360 
361 */
362 int
363 dwarf_global_cu_offset(Dwarf_Global global,
364 		       Dwarf_Off * cu_header_offset,
365 		       Dwarf_Error * error)
366 {
367     Dwarf_Global_Context con;
368 
369     if (global == NULL) {
370 	_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
371 	return (DW_DLV_ERROR);
372     }
373 
374     con = global->gl_context;
375 
376     if (con == NULL) {
377 	_dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
378 	return (DW_DLV_ERROR);
379     }
380 
381     /* In early libdwarf, this incorrectly returned the offset of the
382        CU DIE. Now correctly returns the header offset. */
383     *cu_header_offset = con->pu_offset_of_cu_header;
384 
385     return DW_DLV_OK;
386 }
387 
388 /*
389   Give back the pubnames entry (or any other like section)
390   name, symbol DIE offset, and the cu-DIE offset.
391 */
392 int
393 dwarf_global_name_offsets(Dwarf_Global global,
394 			  char **ret_name,
395 			  Dwarf_Off * die_offset,
396 			  Dwarf_Off * cu_die_offset,
397 			  Dwarf_Error * error)
398 {
399     Dwarf_Global_Context con;
400     Dwarf_Debug dbg;
401     Dwarf_Off off;
402 
403     if (global == NULL) {
404 	_dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
405 	return (DW_DLV_ERROR);
406     }
407 
408     con = global->gl_context;
409 
410     if (con == NULL) {
411 	_dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
412 	return (DW_DLV_ERROR);
413     }
414 
415     off = con->pu_offset_of_cu_header;
416     if (die_offset != NULL) {
417 	*die_offset = global->gl_named_die_offset_within_cu + off;
418     }
419 
420     dbg = con->pu_dbg;
421     if (dbg == NULL) {
422 	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
423 	return (DW_DLV_ERROR);
424     }
425 
426     if (cu_die_offset != NULL) {
427  	int res = _dwarf_load_debug_info(dbg,error);
428 	if(res != DW_DLV_OK) {
429 	   return res;
430 	}
431 	*cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off);
432     }
433 
434     *ret_name = (char *) global->gl_name;
435 
436     return DW_DLV_OK;
437 }
438 
439 /*
440 	We have the offset to a CU header.
441 	Return thru outFileOffset the offset of the CU DIE.
442 
443 	New June, 2001.
444 	Used by SGI debuggers.
445 	No error is possible.
446 */
447 
448 /* ARGSUSED */
449 int
450 dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
451 					       Dwarf_Off
452 					       in_cu_header_offset,
453 					       Dwarf_Off *
454 					       out_cu_die_offset,
455 					       Dwarf_Error * err)
456 {
457     Dwarf_Off len =
458 	_dwarf_length_of_cu_header(dbg, in_cu_header_offset);
459 
460     Dwarf_Off newoff = in_cu_header_offset + len;
461 
462     *out_cu_die_offset = newoff;
463     return DW_DLV_OK;
464 }
465