1/*
2
3  Copyright (C) 2000,2002,2004 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., 1500 Crittenden Lane,
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
39#include "config.h"
40#include "dwarf_incl.h"
41#include <stdio.h>
42#include "dwarf_arange.h"
43#include "dwarf_global.h"	/* for _dwarf_fixup_* */
44
45
46/*
47    This function returns the count of the number of
48    aranges in the .debug_aranges section.  It sets
49    aranges to point to a block of Dwarf_Arange's
50    describing the arange's.  It returns DW_DLV_ERROR
51    on error.
52
53    Must be identical in most aspects to
54	dwarf_get_aranges_addr_offsets!
55*/
56int
57dwarf_get_aranges(Dwarf_Debug dbg,
58		  Dwarf_Arange ** aranges,
59		  Dwarf_Signed * returned_count, Dwarf_Error * error)
60{
61    /* Sweeps the .debug_aranges section. */
62    Dwarf_Small *arange_ptr;
63
64    /*
65       Start of arange header.  Used for rounding offset of arange_ptr
66       to twice the tuple size.  Libdwarf requirement. */
67    Dwarf_Small *header_ptr;
68
69
70    /* Version of .debug_aranges header. */
71    Dwarf_Half version;
72
73    /* Offset of current set of aranges into .debug_info. */
74    Dwarf_Off info_offset;
75
76    /* Size in bytes of addresses in target. */
77    Dwarf_Small address_size;
78
79    /* Size in bytes of segment offsets in target. */
80    Dwarf_Small segment_size;
81
82    Dwarf_Small remainder;
83
84    /* Count of total number of aranges. */
85    Dwarf_Unsigned arange_count = 0;
86
87    /* Start address of arange. */
88    Dwarf_Addr range_address;
89
90    /* Length of arange. */
91    Dwarf_Unsigned range_length;
92
93    Dwarf_Arange arange, *arange_block;
94
95    Dwarf_Unsigned i;
96
97    /* Used to chain Dwarf_Aranges structs. */
98    Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;
99
100    int res;
101
102    /* ***** BEGIN CODE ***** */
103
104    if (dbg == NULL) {
105	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
106	return (DW_DLV_ERROR);
107    }
108
109    res =
110	_dwarf_load_section(dbg,
111			    dbg->de_debug_aranges_index,
112			    &dbg->de_debug_aranges, error);
113    if (res != DW_DLV_OK) {
114	return res;
115    }
116
117    arange_ptr = dbg->de_debug_aranges;
118    do {
119	/* Length of current set of aranges. */
120	Dwarf_Unsigned length;
121	Dwarf_Small *arange_ptr_past_end = 0;
122
123	int local_length_size;
124
125	 /*REFERENCED*/		/* Not used in this instance of the
126				   macro */
127	int local_extension_size;
128
129	header_ptr = arange_ptr;
130
131	/* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
132	READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
133			 arange_ptr, local_length_size,
134			 local_extension_size);
135	arange_ptr_past_end = arange_ptr + length;
136
137
138	READ_UNALIGNED(dbg, version, Dwarf_Half,
139		       arange_ptr, sizeof(Dwarf_Half));
140	arange_ptr += sizeof(Dwarf_Half);
141	length = length - sizeof(Dwarf_Half);
142	if (version != CURRENT_VERSION_STAMP) {
143	    _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
144	    return (DW_DLV_ERROR);
145	}
146
147	READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
148		       arange_ptr, local_length_size);
149	arange_ptr += local_length_size;
150	length = length - local_length_size;
151	if (info_offset >= dbg->de_debug_info_size) {
152	    FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
153				   "arange info offset.a");
154	    if (info_offset >= dbg->de_debug_info_size) {
155		_dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
156		return (DW_DLV_ERROR);
157	    }
158	}
159
160	address_size = *(Dwarf_Small *) arange_ptr;
161	if (address_size != dbg->de_pointer_size) {
162	    /* Internal error of some kind */
163	    _dwarf_error(dbg, error, DW_DLE_BADBITC);
164	    return (DW_DLV_ERROR);
165	}
166	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
167	length = length - sizeof(Dwarf_Small);
168
169	segment_size = *(Dwarf_Small *) arange_ptr;
170	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
171	length = length - sizeof(Dwarf_Small);
172	if (segment_size != 0) {
173	    _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
174	    return (DW_DLV_ERROR);
175	}
176
177	/* Round arange_ptr offset to next multiple of address_size. */
178	remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
179	    (2 * address_size);
180	if (remainder != 0) {
181	    arange_ptr = arange_ptr + (2 * address_size) - remainder;
182	    length = length - ((2 * address_size) - remainder);
183	}
184
185	do {
186	    READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
187			   arange_ptr, address_size);
188	    arange_ptr += address_size;
189	    length = length - address_size;
190
191	    READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
192			   arange_ptr, address_size);
193	    arange_ptr += address_size;
194	    length = length - address_size;
195
196	    if (range_address != 0 || range_length != 0) {
197
198		arange = (Dwarf_Arange)
199		    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
200		if (arange == NULL) {
201		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
202		    return (DW_DLV_ERROR);
203		}
204
205		arange->ar_address = range_address;
206		arange->ar_length = range_length;
207		arange->ar_info_offset = info_offset;
208		arange->ar_dbg = dbg;
209		arange_count++;
210
211		curr_chain = (Dwarf_Chain)
212		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
213		if (curr_chain == NULL) {
214		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
215		    return (DW_DLV_ERROR);
216		}
217
218		curr_chain->ch_item = arange;
219		if (head_chain == NULL)
220		    head_chain = prev_chain = curr_chain;
221		else {
222		    prev_chain->ch_next = curr_chain;
223		    prev_chain = curr_chain;
224		}
225	    }
226	} while (range_address != 0 || range_length != 0);
227
228	/* A compiler could emit some padding bytes here. dwarf2/3
229	   (dwarf3 draft8 sec 7.20) does not clearly make extra padding
230	   bytes illegal. */
231	if (arange_ptr_past_end < arange_ptr) {
232	    _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD);
233	    return (DW_DLV_ERROR);
234	}
235	/* For most compilers, arange_ptr == arange_ptr_past_end at
236	   this point. But not if there were padding bytes */
237	arange_ptr = arange_ptr_past_end;
238
239    } while (arange_ptr <
240	     dbg->de_debug_aranges + dbg->de_debug_aranges_size);
241
242    if (arange_ptr !=
243	dbg->de_debug_aranges + dbg->de_debug_aranges_size) {
244	_dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
245	return (DW_DLV_ERROR);
246    }
247
248    arange_block = (Dwarf_Arange *)
249	_dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
250    if (arange_block == NULL) {
251	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
252	return (DW_DLV_ERROR);
253    }
254
255    curr_chain = head_chain;
256    for (i = 0; i < arange_count; i++) {
257	*(arange_block + i) = curr_chain->ch_item;
258	prev_chain = curr_chain;
259	curr_chain = curr_chain->ch_next;
260	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
261    }
262
263    *aranges = arange_block;
264    *returned_count = (arange_count);
265    return DW_DLV_OK;
266}
267
268/*
269    This function returns DW_DLV_OK if it succeeds
270    and DW_DLV_ERR or DW_DLV_OK otherwise.
271    count is set to the number of addresses in the
272    .debug_aranges section.
273    For each address, the corresponding element in
274    an array is set to the address itself(aranges) and
275    the section offset (offsets).
276    Must be identical in most aspects to
277	dwarf_get_aranges!
278*/
279int
280_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
281				Dwarf_Addr ** addrs,
282				Dwarf_Off ** offsets,
283				Dwarf_Signed * count,
284				Dwarf_Error * error)
285{
286    /* Sweeps the .debug_aranges section. */
287    Dwarf_Small *arange_ptr;
288    Dwarf_Small *arange_start_ptr;
289
290    /*
291       Start of arange header.  Used for rounding offset of arange_ptr
292       to twice the tuple size.  Libdwarf requirement. */
293    Dwarf_Small *header_ptr;
294
295    /* Length of current set of aranges. */
296    Dwarf_Unsigned length;
297
298    /* Version of .debug_aranges header. */
299    Dwarf_Half version;
300
301    /* Offset of current set of aranges into .debug_info. */
302    Dwarf_Off info_offset;
303
304    /* Size in bytes of addresses in target. */
305    Dwarf_Small address_size;
306
307    /* Size in bytes of segment offsets in target. */
308    Dwarf_Small segment_size;
309
310    Dwarf_Small remainder;
311
312    /* Count of total number of aranges. */
313    Dwarf_Unsigned arange_count = 0;
314
315    /* Start address of arange. */
316    Dwarf_Addr range_address;
317
318    /* Length of arange. */
319    Dwarf_Unsigned range_length;
320
321    Dwarf_Arange arange;
322
323    Dwarf_Unsigned i;
324
325    /* Used to chain Dwarf_Aranges structs. */
326    Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;
327
328    Dwarf_Addr *arange_addrs;
329    Dwarf_Off *arange_offsets;
330
331    int res;
332
333    /* ***** BEGIN CODE ***** */
334
335    if (error != NULL)
336	*error = NULL;
337
338    if (dbg == NULL) {
339	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
340	return (DW_DLV_ERROR);
341    }
342
343    res =
344	_dwarf_load_section(dbg,
345			    dbg->de_debug_aranges_index,
346			    &dbg->de_debug_aranges, error);
347    if (res != DW_DLV_OK) {
348	return res;
349    }
350
351    arange_ptr = dbg->de_debug_aranges;
352    do {
353	int local_length_size;
354
355	 /*REFERENCED*/		/* not used in this instance of the
356				   macro */
357	int local_extension_size;
358
359	header_ptr = arange_ptr;
360
361
362	/* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
363	READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
364			 arange_ptr, local_length_size,
365			 local_extension_size);
366
367
368	READ_UNALIGNED(dbg, version, Dwarf_Half,
369		       arange_ptr, sizeof(Dwarf_Half));
370	arange_ptr += sizeof(Dwarf_Half);
371	length = length - sizeof(Dwarf_Half);
372	if (version != CURRENT_VERSION_STAMP) {
373	    _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
374	    return (DW_DLV_ERROR);
375	}
376
377	READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
378		       arange_ptr, local_length_size);
379	arange_ptr += local_length_size;
380	length = length - local_length_size;
381	if (info_offset >= dbg->de_debug_info_size) {
382	    FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
383				   "arange info offset.b");
384	    if (info_offset >= dbg->de_debug_info_size) {
385
386		_dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
387		return (DW_DLV_ERROR);
388	    }
389	}
390
391	address_size = *(Dwarf_Small *) arange_ptr;
392	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
393	length = length - sizeof(Dwarf_Small);
394
395	segment_size = *(Dwarf_Small *) arange_ptr;
396	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
397	length = length - sizeof(Dwarf_Small);
398	if (segment_size != 0) {
399	    _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
400	    return (DW_DLV_ERROR);
401	}
402
403	/* Round arange_ptr offset to next multiple of address_size. */
404	remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
405	    (2 * address_size);
406	if (remainder != 0) {
407	    arange_ptr = arange_ptr + (2 * address_size) - remainder;
408	    length = length - ((2 * address_size) - remainder);
409	}
410
411	do {
412	    arange_start_ptr = arange_ptr;
413	    READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
414			   arange_ptr, dbg->de_pointer_size);
415	    arange_ptr += dbg->de_pointer_size;
416	    length = length - dbg->de_pointer_size;
417
418	    READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
419			   arange_ptr, local_length_size);
420	    arange_ptr += local_length_size;
421	    length = length - local_length_size;
422
423	    if (range_address != 0 || range_length != 0) {
424
425		arange = (Dwarf_Arange)
426		    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
427		if (arange == NULL) {
428		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
429		    return (DW_DLV_ERROR);
430		}
431
432		arange->ar_address = range_address;
433		arange->ar_length = range_length;
434		arange->ar_info_offset =
435		    arange_start_ptr - dbg->de_debug_aranges;
436		arange->ar_dbg = dbg;
437		arange_count++;
438
439		curr_chain = (Dwarf_Chain)
440		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
441		if (curr_chain == NULL) {
442		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
443		    return (DW_DLV_ERROR);
444		}
445
446		curr_chain->ch_item = arange;
447		if (head_chain == NULL)
448		    head_chain = prev_chain = curr_chain;
449		else {
450		    prev_chain->ch_next = curr_chain;
451		    prev_chain = curr_chain;
452		}
453	    }
454	} while (range_address != 0 || range_length != 0);
455
456	if (length != 0) {
457	    _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD);
458	    return (DW_DLV_ERROR);
459	}
460
461    } while (arange_ptr <
462	     dbg->de_debug_aranges + dbg->de_debug_aranges_size);
463
464    if (arange_ptr !=
465	dbg->de_debug_aranges + dbg->de_debug_aranges_size) {
466	_dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
467	return (DW_DLV_ERROR);
468    }
469
470    arange_addrs = (Dwarf_Addr *)
471	_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
472    if (arange_addrs == NULL) {
473	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
474	return (DW_DLV_ERROR);
475    }
476    arange_offsets = (Dwarf_Off *)
477	_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
478    if (arange_offsets == NULL) {
479	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
480	return (DW_DLV_ERROR);
481    }
482
483    curr_chain = head_chain;
484    for (i = 0; i < arange_count; i++) {
485	Dwarf_Arange ar = curr_chain->ch_item;
486
487	arange_addrs[i] = ar->ar_address;
488	arange_offsets[i] = ar->ar_info_offset;
489	prev_chain = curr_chain;
490	curr_chain = curr_chain->ch_next;
491	dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
492	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
493    }
494    *count = arange_count;
495    *offsets = arange_offsets;
496    *addrs = arange_addrs;
497    return (DW_DLV_OK);
498}
499
500
501/*
502    This function takes a pointer to a block
503    of Dwarf_Arange's, and a count of the
504    length of the block.  It checks if the
505    given address is within the range of an
506    address range in the block.  If yes, it
507    returns the appropriate Dwarf_Arange.
508    Otherwise, it returns DW_DLV_ERROR.
509*/
510int
511dwarf_get_arange(Dwarf_Arange * aranges,
512		 Dwarf_Unsigned arange_count,
513		 Dwarf_Addr address,
514		 Dwarf_Arange * returned_arange, Dwarf_Error * error)
515{
516    Dwarf_Arange curr_arange;
517    Dwarf_Unsigned i;
518
519    if (aranges == NULL) {
520	_dwarf_error(NULL, error, DW_DLE_ARANGES_NULL);
521	return (DW_DLV_ERROR);
522    }
523
524    for (i = 0; i < arange_count; i++) {
525	curr_arange = *(aranges + i);
526	if (address >= curr_arange->ar_address &&
527	    address <
528	    curr_arange->ar_address + curr_arange->ar_length) {
529	    *returned_arange = curr_arange;
530	    return (DW_DLV_OK);
531	}
532    }
533
534    return (DW_DLV_NO_ENTRY);
535}
536
537
538/*
539    This function takes an Dwarf_Arange,
540    and returns the offset of the first
541    die in the compilation-unit that the
542    arange belongs to.  Returns DW_DLV_ERROR
543    on error.
544*/
545int
546dwarf_get_cu_die_offset(Dwarf_Arange arange,
547			Dwarf_Off * returned_offset,
548			Dwarf_Error * error)
549{
550    Dwarf_Debug dbg;
551    Dwarf_Off offset;
552
553    if (arange == NULL) {
554	_dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
555	return (DW_DLV_ERROR);
556    }
557
558
559    dbg = arange->ar_dbg;
560
561
562    offset = arange->ar_info_offset;
563    if (!dbg->de_debug_info) {
564	int res = _dwarf_load_debug_info(dbg, error);
565
566	if (res != DW_DLV_OK) {
567	    return res;
568	}
569    }
570
571    *returned_offset = offset + _dwarf_length_of_cu_header(dbg, offset);
572    return DW_DLV_OK;
573}
574
575/*
576    This function takes an Dwarf_Arange,
577    and returns the offset of the CU header
578    in the compilation-unit that the
579    arange belongs to.  Returns DW_DLV_ERROR
580    on error.
581*/
582int
583dwarf_get_arange_cu_header_offset(Dwarf_Arange arange,
584				  Dwarf_Off * cu_header_offset_returned,
585				  Dwarf_Error * error)
586{
587    if (arange == NULL) {
588	_dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
589	return (DW_DLV_ERROR);
590    }
591
592    *cu_header_offset_returned = arange->ar_info_offset;
593    return DW_DLV_OK;
594}
595
596
597
598/*
599    This function takes a Dwarf_Arange, and returns
600    true if it is not NULL.  It also stores the start
601    address of the range in *start, the length of the
602    range in *length, and the offset of the first die
603    in the compilation-unit in *cu_die_offset.  It
604    returns false on error.
605*/
606int
607dwarf_get_arange_info(Dwarf_Arange arange,
608		      Dwarf_Addr * start,
609		      Dwarf_Unsigned * length,
610		      Dwarf_Off * cu_die_offset, Dwarf_Error * error)
611{
612    if (arange == NULL) {
613	_dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
614	return (DW_DLV_ERROR);
615    }
616
617    if (start != NULL)
618	*start = arange->ar_address;
619    if (length != NULL)
620	*length = arange->ar_length;
621    if (cu_die_offset != NULL) {
622	Dwarf_Debug dbg = arange->ar_dbg;
623	Dwarf_Off offset = arange->ar_info_offset;
624
625	if (!dbg->de_debug_info) {
626	    int res = _dwarf_load_debug_info(dbg, error);
627
628	    if (res != DW_DLV_OK) {
629		return res;
630	    }
631	}
632
633	*cu_die_offset =
634	    offset + _dwarf_length_of_cu_header(dbg, offset);
635    }
636    return (DW_DLV_OK);
637}
638