1/*
2
3  Copyright (C) 2000,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#include "config.h"
39#include "libdwarfdefs.h"
40#include <stdio.h>
41#include <string.h>
42#ifdef HAVE_ELFACCESS_H
43#include <elfaccess.h>
44#endif
45#include "pro_incl.h"
46#include "pro_arange.h"
47#include "pro_section.h"
48#include "pro_reloc.h"
49
50
51
52/*
53    This function adds another address range
54    to the list of address ranges for the
55    given Dwarf_P_Debug.  It returns 0 on error,
56    and 1 otherwise.
57*/
58Dwarf_Unsigned
59dwarf_add_arange(Dwarf_P_Debug dbg,
60		 Dwarf_Addr begin_address,
61		 Dwarf_Unsigned length,
62		 Dwarf_Signed symbol_index, Dwarf_Error * error)
63{
64    return dwarf_add_arange_b(dbg, begin_address, length, symbol_index,
65			      /* end_symbol_index */ 0,
66			      /* offset_from_end_sym */ 0,
67			      error);
68}
69
70/*
71    This function adds another address range
72    to the list of address ranges for the
73    given Dwarf_P_Debug.  It returns 0 on error,
74    and 1 otherwise.
75*/
76Dwarf_Unsigned
77dwarf_add_arange_b(Dwarf_P_Debug dbg,
78		   Dwarf_Addr begin_address,
79		   Dwarf_Unsigned length,
80		   Dwarf_Unsigned symbol_index,
81		   Dwarf_Unsigned end_symbol_index,
82		   Dwarf_Addr offset_from_end_sym, Dwarf_Error * error)
83{
84    Dwarf_P_Arange arange;
85
86    if (dbg == NULL) {
87	_dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
88	return (0);
89    }
90
91    arange = (Dwarf_P_Arange)
92	_dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Arange_s));
93    if (arange == NULL) {
94	_dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
95	return (0);
96    }
97
98    arange->ag_begin_address = begin_address;
99    arange->ag_length = length;
100    arange->ag_symbol_index = symbol_index;
101    arange->ag_end_symbol_index = end_symbol_index;
102    arange->ag_end_symbol_offset = offset_from_end_sym;
103
104    if (dbg->de_arange == NULL)
105	dbg->de_arange = dbg->de_last_arange = arange;
106    else {
107	dbg->de_last_arange->ag_next = arange;
108	dbg->de_last_arange = arange;
109    }
110    dbg->de_arange_count++;
111
112    return (1);
113}
114
115
116int
117_dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg, Dwarf_Error * error)
118{
119    /* Total num of bytes in .debug_aranges section. */
120    Dwarf_Unsigned arange_num_bytes;
121
122    /*
123       Adjustment to align the start of the actual address ranges on a
124       boundary aligned with twice the address size. */
125    Dwarf_Small remainder;
126
127    /* Total number of bytes excluding the length field. */
128    Dwarf_Unsigned adjusted_length;
129
130    /* Points to first byte of .debug_aranges buffer. */
131    Dwarf_Small *arange;
132
133    /* Fills in the .debug_aranges buffer. */
134    Dwarf_Small *arange_ptr;
135
136    /* Scans the list of address ranges provided by user. */
137    Dwarf_P_Arange given_arange;
138
139    /* Used to fill in 0. */
140    const Dwarf_Signed big_zero = 0;
141
142    int extension_word_size = dbg->de_64bit_extension ? 4 : 0;
143    int uword_size = dbg->de_offset_size;
144    int upointer_size = dbg->de_pointer_size;
145    int res;
146
147
148    /* ***** BEGIN CODE ***** */
149
150    /* Size of the .debug_aranges section header. */
151    arange_num_bytes = extension_word_size + uword_size +	/* Size
152								   of
153								   length
154								   field.
155								 */
156	sizeof(Dwarf_Half) +	/* Size of version field. */
157	uword_size +		/* Size of .debug_info offset. */
158	sizeof(Dwarf_Small) +	/* Size of address size field. */
159	sizeof(Dwarf_Small);	/* Size of segment size field. */
160
161    /*
162       Adjust the size so that the set of aranges begins on a boundary
163       that aligned with twice the address size.  This is a Libdwarf
164       requirement. */
165    remainder = arange_num_bytes % (2 * upointer_size);
166    if (remainder != 0)
167	arange_num_bytes += (2 * upointer_size) - remainder;
168
169
170    /* Add the bytes for the actual address ranges. */
171    arange_num_bytes += upointer_size * 2 * (dbg->de_arange_count + 1);
172
173    GET_CHUNK(dbg, dbg->de_elf_sects[DEBUG_ARANGES],
174	      arange, (unsigned long) arange_num_bytes, error);
175    arange_ptr = arange;
176    if (arange == NULL) {
177	_dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
178	return (0);
179    }
180    if (extension_word_size) {
181	Dwarf_Word x = DISTINGUISHED_VALUE;
182
183	WRITE_UNALIGNED(dbg, (void *) arange_ptr,
184			(const void *) &x,
185			sizeof(x), extension_word_size);
186	arange_ptr += extension_word_size;
187    }
188
189    /* Write the total length of .debug_aranges section. */
190    adjusted_length = arange_num_bytes - uword_size
191	- extension_word_size;
192    {
193	Dwarf_Unsigned du = adjusted_length;
194
195	WRITE_UNALIGNED(dbg, (void *) arange_ptr,
196			(const void *) &du, sizeof(du), uword_size);
197	arange_ptr += uword_size;
198    }
199
200    /* Write the version as 2 bytes. */
201    {
202	Dwarf_Half verstamp = CURRENT_VERSION_STAMP;
203
204	WRITE_UNALIGNED(dbg, (void *) arange_ptr,
205			(const void *) &verstamp,
206			sizeof(verstamp), sizeof(Dwarf_Half));
207	arange_ptr += sizeof(Dwarf_Half);
208    }
209
210
211    /* Write the .debug_info offset.  This is always 0. */
212    WRITE_UNALIGNED(dbg, (void *) arange_ptr,
213		    (const void *) &big_zero,
214		    sizeof(big_zero), uword_size);
215    arange_ptr += uword_size;
216
217    {
218	unsigned long count = dbg->de_arange_count + 1;
219	int res;
220
221	if (dbg->de_reloc_pair) {
222	    count = (3 * dbg->de_arange_count) + 1;
223	}
224	/* the following is a small optimization: not needed for
225	   correctness */
226	res = _dwarf_pro_pre_alloc_n_reloc_slots(dbg,
227						 DEBUG_ARANGES, count);
228	if (res != DW_DLV_OK) {
229	    {
230		_dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
231		return (0);
232	    }
233	}
234    }
235
236    /* reloc for .debug_info */
237    res = dbg->de_reloc_name(dbg,
238			     DEBUG_ARANGES,
239			     extension_word_size +
240			     uword_size + sizeof(Dwarf_Half),
241			     dbg->de_sect_name_idx[DEBUG_INFO],
242			     dwarf_drt_data_reloc, uword_size);
243
244    /* Write the size of addresses. */
245    *arange_ptr = dbg->de_pointer_size;
246    arange_ptr++;
247
248    /*
249       Write the size of segment addresses. This is zero for MIPS
250       architectures. */
251    *arange_ptr = 0;
252    arange_ptr++;
253
254    /*
255       Skip over the padding to align the start of the actual address
256       ranges to twice the address size. */
257    if (remainder != 0)
258	arange_ptr += (2 * upointer_size) - remainder;
259
260
261
262
263
264    /* The arange address, length are pointer-size fields of the target
265       machine. */
266    for (given_arange = dbg->de_arange; given_arange != NULL;
267	 given_arange = given_arange->ag_next) {
268
269	/* Write relocation record for beginning of address range. */
270	res = dbg->de_reloc_name(dbg, DEBUG_ARANGES, arange_ptr - arange,	/* r_offset
271										 */
272				 (long) given_arange->ag_symbol_index,
273				 dwarf_drt_data_reloc, upointer_size);
274	if (res != DW_DLV_OK) {
275	    {
276		_dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
277		return (0);
278	    }
279	}
280
281	/* Copy beginning address of range. */
282	WRITE_UNALIGNED(dbg, (void *) arange_ptr,
283			(const void *) &given_arange->ag_begin_address,
284			sizeof(given_arange->ag_begin_address),
285			upointer_size);
286	arange_ptr += upointer_size;
287
288	if (dbg->de_reloc_pair &&
289	    given_arange->ag_end_symbol_index != 0 &&
290	    given_arange->ag_length == 0) {
291	    /* symbolic reloc, need reloc for length What if we really
292	       know the length? If so, should use the other part of
293	       'if'. */
294	    Dwarf_Unsigned val;
295
296	    res = dbg->de_reloc_pair(dbg, DEBUG_ARANGES, arange_ptr - arange,	/* r_offset
297										 */
298				     given_arange->ag_symbol_index,
299				     given_arange->ag_end_symbol_index,
300				     dwarf_drt_first_of_length_pair,
301				     upointer_size);
302	    if (res != DW_DLV_OK) {
303		{
304		    _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
305		    return (0);
306		}
307	    }
308
309	    /* arrange pre-calc so assem text can do .word end - begin
310	       + val (gets val from stream) */
311	    val = given_arange->ag_end_symbol_offset -
312		given_arange->ag_begin_address;
313	    WRITE_UNALIGNED(dbg, (void *) arange_ptr,
314			    (const void *) &val,
315			    sizeof(val), upointer_size);
316	    arange_ptr += upointer_size;
317
318	} else {
319	    /* plain old length to copy, no relocation at all */
320	    WRITE_UNALIGNED(dbg, (void *) arange_ptr,
321			    (const void *) &given_arange->ag_length,
322			    sizeof(given_arange->ag_length),
323			    upointer_size);
324	    arange_ptr += upointer_size;
325	}
326    }
327
328    WRITE_UNALIGNED(dbg, (void *) arange_ptr,
329		    (const void *) &big_zero,
330		    sizeof(big_zero), upointer_size);
331
332    arange_ptr += upointer_size;
333    WRITE_UNALIGNED(dbg, (void *) arange_ptr,
334		    (const void *) &big_zero,
335		    sizeof(big_zero), upointer_size);
336    return (int) dbg->de_n_debug_sect;
337}
338