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