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
dwarf_add_arange(Dwarf_P_Debug dbg,Dwarf_Addr begin_address,Dwarf_Unsigned length,Dwarf_Signed symbol_index,Dwarf_Error * error)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
dwarf_add_arange_b(Dwarf_P_Debug dbg,Dwarf_Addr begin_address,Dwarf_Unsigned length,Dwarf_Unsigned symbol_index,Dwarf_Unsigned end_symbol_index,Dwarf_Addr offset_from_end_sym,Dwarf_Error * error)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
dwarf_add_arange_c(Dwarf_P_Debug dbg,Dwarf_Addr begin_address,Dwarf_Unsigned length,Dwarf_Unsigned symbol_index,Dwarf_Unsigned end_symbol_index,Dwarf_Addr offset_from_end_sym,Dwarf_Error * error)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
_dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg,Dwarf_Signed * nbufs,Dwarf_Error * error)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