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., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
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