xref: /illumos-gate/usr/src/lib/libdwarf/common/pro_arange.c (revision 2aeafac3612e19716bf8164f89c3c9196342979c)
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 */
58 Dwarf_Unsigned
59 dwarf_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 */
76 Dwarf_Unsigned
77 dwarf_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 
116 int
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