xref: /illumos-gate/usr/src/lib/libdwarf/common/pro_arange.c (revision 2ad530425ac9cd3f429e64463a85f6f58703061c)
1 /*
2 
3   Copyright (C) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
4   Portions Copyright 2011-2019 David Anderson.  All Rights Reserved.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of version 2.1 of the GNU Lesser General Public License
8   as published by the Free Software Foundation.
9 
10   This program is distributed in the hope that it would be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14   Further, this software is distributed without any warranty that it is
15   free of the rightful claim of any third person regarding infringement
16   or the like.  Any license provided herein, whether implied or
17   otherwise, applies only to this software file.  Patent licenses, if
18   any, provided herein do not apply to combinations of this program with
19   other software, or any other product whatsoever.
20 
21   You should have received a copy of the GNU Lesser General Public
22   License along with this program; if not, write the Free Software
23   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
24   USA.
25 
26 */
27 
28 #include "config.h"
29 #include "libdwarfdefs.h"
30 #include <stdio.h>
31 #include <string.h>
32 #ifdef HAVE_ELFACCESS_H
33 #include <elfaccess.h>
34 #endif
35 #include "pro_incl.h"
36 #include <stddef.h>
37 #include "dwarf.h"
38 #include "libdwarf.h"
39 #include "pro_opaque.h"
40 #include "pro_error.h"
41 #include "pro_alloc.h"
42 #include "pro_arange.h"
43 #include "pro_section.h"
44 #include "pro_reloc.h"
45 
46 
47 #define SIZEOFT32 4
48 
49 /*  This function adds another address range
50     to the list of address ranges for the
51     given Dwarf_P_Debug.  It returns 0 on error,
52     and 1 otherwise.  */
53 Dwarf_Unsigned
54 dwarf_add_arange(Dwarf_P_Debug dbg,
55     Dwarf_Addr begin_address,
56     Dwarf_Unsigned length,
57     Dwarf_Signed symbol_index, Dwarf_Error * error)
58 {
59     int res = 0;
60 
61     res = dwarf_add_arange_b(dbg, begin_address, length, symbol_index,
62         /* end_symbol_index */ 0,
63         /* offset_from_end_sym */ 0,
64         error);
65     if (res != DW_DLV_OK) {
66         return 0;
67     }
68     return 1;
69 
70 }
71 
72 /*  This function adds another address range
73     to the list of address ranges for the
74     given Dwarf_P_Debug.  It returns DW_DLV_ERROR on error,
75     and DW_DLV_OK otherwise.  */
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,
83     Dwarf_Error * error)
84 {
85     int res = 0;
86 
87     res = dwarf_add_arange_c(dbg,begin_address,length,
88         symbol_index, end_symbol_index,
89         offset_from_end_sym,error);
90     if (res != DW_DLV_OK) {
91         return 0;
92     }
93     return 1;
94 }
95 int
96 dwarf_add_arange_c(Dwarf_P_Debug dbg,
97     Dwarf_Addr begin_address,
98     Dwarf_Unsigned length,
99     Dwarf_Unsigned symbol_index,
100     Dwarf_Unsigned end_symbol_index,
101     Dwarf_Addr offset_from_end_sym,
102     Dwarf_Error * error)
103 {
104     Dwarf_P_Arange arange;
105 
106     if (dbg == NULL) {
107         _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
108         return DW_DLV_ERROR;
109     }
110 
111     arange = (Dwarf_P_Arange)
112         _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Arange_s));
113     if (arange == NULL) {
114         _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
115         return DW_DLV_ERROR;
116     }
117 
118     arange->ag_begin_address = begin_address;
119     arange->ag_length = length;
120     arange->ag_symbol_index = symbol_index;
121     arange->ag_end_symbol_index = end_symbol_index;
122     arange->ag_end_symbol_offset = offset_from_end_sym;
123 
124     if (dbg->de_arange == NULL)
125         dbg->de_arange = dbg->de_last_arange = arange;
126     else {
127         dbg->de_last_arange->ag_next = arange;
128         dbg->de_last_arange = arange;
129     }
130     dbg->de_arange_count++;
131     return DW_DLV_OK;
132 }
133 
134 
135 int
136 _dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg,
137     Dwarf_Signed *nbufs, Dwarf_Error * error)
138 {
139     /* Total num of bytes in .debug_aranges section. */
140     Dwarf_Unsigned arange_num_bytes = 0;
141 
142     /*  Adjustment to align the start of the actual address ranges on a
143         boundary aligned with twice the address size. */
144     Dwarf_Small remainder = 0;
145 
146     /*  Total number of bytes excluding the length field. */
147     Dwarf_Unsigned adjusted_length = 0;
148 
149     /*  Points to first byte of .debug_aranges buffer. */
150     Dwarf_Small *arange = 0;
151 
152     /*  Fills in the .debug_aranges buffer. */
153     Dwarf_Small *arange_ptr = 0;
154 
155     /*  Scans the list of address ranges provided by user. */
156     Dwarf_P_Arange given_arange = 0;
157 
158     /*  Used to fill in 0. */
159     const Dwarf_Signed big_zero = 0;
160 
161     int extension_word_size = dbg->de_64bit_extension ? 4 : 0;
162     int offset_size = dbg->de_dwarf_offset_size;
163     int upointer_size = dbg->de_pointer_size;
164 
165     /*  All dwarf versions so far use 2 here. */
166     Dwarf_Half version = 2;
167     int res = 0;
168 
169 
170     /* ***** BEGIN CODE ***** */
171 
172     /* Size of the .debug_aranges section header. */
173     arange_num_bytes = extension_word_size +
174         offset_size +       /* Size of length field.  */
175         DWARF_HALF_SIZE +    /* Size of version field. */
176         offset_size +            /* Size of .debug_info offset. */
177         sizeof(Dwarf_Small) +   /* Size of address size field. */
178         sizeof(Dwarf_Small);    /* Size of segment size field. */
179 
180     /*  Adjust the size so that the set of aranges begins on a boundary
181         that aligned with twice the address size.  This is a Libdwarf
182         requirement. */
183     remainder = arange_num_bytes % (2 * upointer_size);
184     if (remainder != 0)
185         arange_num_bytes += (2 * upointer_size) - remainder;
186 
187 
188     /* Add the bytes for the actual address ranges. */
189     arange_num_bytes += upointer_size * 2 * (dbg->de_arange_count + 1);
190 
191     GET_CHUNK(dbg, dbg->de_elf_sects[DEBUG_ARANGES],
192         arange, (unsigned long) arange_num_bytes, error);
193     arange_ptr = arange;
194     if (extension_word_size) {
195         DISTINGUISHED_VALUE_ARRAY(v4);
196         WRITE_UNALIGNED(dbg, (void *) arange_ptr,
197             (const void *)&v4[0] ,
198             SIZEOFT32, extension_word_size);
199         arange_ptr += extension_word_size;
200     }
201 
202     /* Write the total length of .debug_aranges section. */
203     adjusted_length = arange_num_bytes - offset_size
204         - extension_word_size;
205     {
206         Dwarf_Unsigned du = adjusted_length;
207 
208         WRITE_UNALIGNED(dbg, (void *) arange_ptr,
209             (const void *) &du, sizeof(du), offset_size);
210         arange_ptr += offset_size;
211     }
212 
213     /* Write the version as 2 bytes. */
214     {
215         Dwarf_Half verstamp = version;
216 
217         WRITE_UNALIGNED(dbg, (void *) arange_ptr,
218             (const void *) &verstamp,
219             sizeof(verstamp), DWARF_HALF_SIZE);
220         arange_ptr += DWARF_HALF_SIZE;
221     }
222 
223 
224     /* Write the .debug_info offset.  This is always 0. */
225     WRITE_UNALIGNED(dbg, (void *) arange_ptr,
226         (const void *) &big_zero,
227         sizeof(big_zero), offset_size);
228     arange_ptr += offset_size;
229 
230     {
231         unsigned long count = dbg->de_arange_count + 1;
232         int res2 = 0;
233         Dwarf_P_Per_Reloc_Sect p_reloc =
234             &dbg->de_reloc_sect[DEBUG_ARANGES];
235 
236         if (dbg->de_relocate_pair_by_symbol) {
237             count = (3 * dbg->de_arange_count) + 1;
238         }
239         /*  The following is a small optimization: not needed for
240             correctness.  Does nothing if
241             preloc->pr_first_block is non-null */
242         res2 = _dwarf_pro_pre_alloc_specific_reloc_slots(dbg,
243             p_reloc, count);
244         if (res2 != DW_DLV_OK) {
245             _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
246             return DW_DLV_ERROR;
247         }
248     }
249 
250     /* reloc for .debug_info */
251     res = dbg->de_relocate_by_name_symbol(dbg,
252         DEBUG_ARANGES,
253         extension_word_size +
254         offset_size + DWARF_HALF_SIZE,
255         dbg->de_sect_name_idx[DEBUG_INFO],
256         dwarf_drt_data_reloc, offset_size);
257     if (res == DW_DLV_NO_ENTRY) {
258         return res;
259     }
260     if (res == DW_DLV_ERROR) {
261         _dwarf_p_error(dbg, error,DW_DLE_RELOCS_ERROR);
262         return res;
263     }
264 
265     /* Write the size of addresses. */
266     *arange_ptr = dbg->de_pointer_size;
267     arange_ptr++;
268 
269     /*  Write the size of segment addresses. This is zero for MIPS
270         architectures. */
271     *arange_ptr = 0;
272     arange_ptr++;
273 
274     /*  Skip over the padding to align the start of the actual address
275         ranges to twice the address size. */
276     if (remainder != 0)
277         arange_ptr += (2 * upointer_size) - remainder;
278 
279 
280 
281 
282 
283     /*  The arange address, length are pointer-size fields of the target
284         machine. */
285     for (given_arange = dbg->de_arange; given_arange != NULL;
286         given_arange = given_arange->ag_next) {
287 
288         /* Write relocation record for beginning of address range. */
289         res = dbg->de_relocate_by_name_symbol(dbg, DEBUG_ARANGES,
290             arange_ptr - arange,       /* r_offset */
291             (long) given_arange->ag_symbol_index,
292             dwarf_drt_data_reloc, upointer_size);
293         if (res != DW_DLV_OK) {
294             _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
295             return DW_DLV_ERROR;
296         }
297 
298         /* Copy beginning address of range. */
299         WRITE_UNALIGNED(dbg, (void *) arange_ptr,
300             (const void *) &given_arange->ag_begin_address,
301             sizeof(given_arange->ag_begin_address),
302             upointer_size);
303         arange_ptr += upointer_size;
304 
305         if (dbg->de_relocate_pair_by_symbol &&
306             given_arange->ag_end_symbol_index != 0 &&
307             given_arange->ag_length == 0) {
308             /*  symbolic reloc, need reloc for length What if we really
309                 know the length? If so, should use the other part of
310                 'if'. */
311             Dwarf_Unsigned val;
312 
313             res = dbg->de_relocate_pair_by_symbol(dbg,
314                 DEBUG_ARANGES,
315                 arange_ptr - arange,   /* r_offset */
316                 given_arange->ag_symbol_index,
317                 given_arange->ag_end_symbol_index,
318                 dwarf_drt_first_of_length_pair,
319                 upointer_size);
320             if (res != DW_DLV_OK) {
321                 _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
322                 return DW_DLV_ERROR;
323             }
324 
325             /*  arange pre-calc so assem text can do .word end - begin
326                 + val (gets val from stream) */
327             val = given_arange->ag_end_symbol_offset -
328                 given_arange->ag_begin_address;
329             WRITE_UNALIGNED(dbg, (void *) arange_ptr,
330                 (const void *) &val,
331                 sizeof(val), upointer_size);
332             arange_ptr += upointer_size;
333 
334         } else {
335             /* plain old length to copy, no relocation at all */
336             WRITE_UNALIGNED(dbg, (void *) arange_ptr,
337                 (const void *) &given_arange->ag_length,
338                 sizeof(given_arange->ag_length),
339                 upointer_size);
340             arange_ptr += upointer_size;
341         }
342     }
343 
344     WRITE_UNALIGNED(dbg, (void *) arange_ptr,
345         (const void *) &big_zero,
346         sizeof(big_zero), upointer_size);
347 
348     arange_ptr += upointer_size;
349     WRITE_UNALIGNED(dbg, (void *) arange_ptr,
350         (const void *) &big_zero,
351         sizeof(big_zero), upointer_size);
352     *nbufs =  dbg->de_n_debug_sect;
353     return DW_DLV_OK;
354 }
355