1 /* 2 Copyright (C) 2008-2020 David Anderson. All Rights Reserved. 3 Portions Copyright 2012 SN Systems Ltd. All rights reserved. 4 5 This program is free software; you can redistribute it 6 and/or modify it under the terms of version 2.1 of the 7 GNU Lesser General Public License as published by the Free 8 Software Foundation. 9 10 This program is distributed in the hope that it would be 11 useful, but WITHOUT ANY WARRANTY; without even the implied 12 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 PURPOSE. 14 15 Further, this software is distributed without any warranty 16 that it is free of the rightful claim of any third person 17 regarding infringement or the like. Any license provided 18 herein, whether implied or otherwise, applies only to this 19 software file. Patent licenses, if any, provided herein 20 do not apply to combinations of this program with other 21 software, or any other product whatsoever. 22 23 You should have received a copy of the GNU Lesser General 24 Public License along with this program; if not, write the 25 Free Software Foundation, Inc., 51 Franklin Street - Fifth 26 Floor, Boston MA 02110-1301, USA. 27 28 */ 29 30 #include "config.h" 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include "dwarf_incl.h" 34 #include "dwarf_alloc.h" 35 #include "dwarf_error.h" 36 #include "dwarf_util.h" 37 #include "dwarfstring.h" 38 39 struct ranges_entry { 40 struct ranges_entry *next; 41 Dwarf_Ranges cur; 42 }; 43 44 45 static void 46 free_allocated_ranges( struct ranges_entry *base) 47 { 48 struct ranges_entry *cur = 0; 49 struct ranges_entry *next = 0; 50 for ( cur = base ; cur ; cur = next ) { 51 next = cur->next; 52 free(cur); 53 } 54 } 55 56 /* We encapsulate the macro use so we can 57 free local malloc resources that would otherwise 58 leak. See the call points below. */ 59 static int 60 read_unaligned_addr_check(Dwarf_Debug dbg, 61 Dwarf_Addr *addr_out, 62 Dwarf_Small *rangeptr, 63 unsigned address_size, 64 Dwarf_Error *error, 65 Dwarf_Small *section_end) 66 { 67 Dwarf_Addr a = 0; 68 69 READ_UNALIGNED_CK(dbg,a, 70 Dwarf_Addr, rangeptr, 71 address_size, 72 error,section_end); 73 *addr_out = a; 74 return DW_DLV_OK; 75 } 76 /* As of DWARF5 the ranges section each range list set has 77 a range-list-table header. See "7.28 Range List Table" 78 in the DWARF5 standard. 79 For DWARF5 the offset should be the offset of 80 the range-list-table-header for that range list. 81 For DWARF3 and DWARF4 the offset has to be that 82 of a range list. 83 */ 84 /* Ranges and pc values can be in a split dwarf object. 85 In that case the appropriate values need to be 86 incremented by data from the executable in 87 the compilation unit with the same dwo_id. 88 89 We return an error which is on the incoming dbg, not 90 the possibly-tied-dbg localdbg. 91 If incoming die is NULL there is no context, so do not look 92 for a tied file, and address_size is the size 93 of the overall object, not the address_size of the context. */ 94 #define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff) 95 int dwarf_get_ranges_a(Dwarf_Debug dbg, 96 Dwarf_Off rangesoffset, 97 Dwarf_Die die, 98 Dwarf_Ranges ** rangesbuf, 99 Dwarf_Signed * listlen, 100 Dwarf_Unsigned * bytecount, 101 Dwarf_Error * error) 102 { 103 Dwarf_Small *rangeptr = 0; 104 Dwarf_Small *beginrangeptr = 0; 105 Dwarf_Small *section_end = 0; 106 unsigned entry_count = 0; 107 struct ranges_entry *base = 0; 108 struct ranges_entry *last = 0; 109 struct ranges_entry *curre = 0; 110 Dwarf_Ranges * ranges_data_out = 0; 111 unsigned copyindex = 0; 112 Dwarf_Half address_size = 0; 113 int res = DW_DLV_ERROR; 114 Dwarf_Unsigned ranges_base = 0; 115 Dwarf_Unsigned addr_base = 0; 116 Dwarf_Debug localdbg = dbg; 117 Dwarf_Error localerror = 0; 118 Dwarf_Half die_version = 3; /* default for dwarf_get_ranges() */ 119 UNUSEDARG Dwarf_Half offset_size = 4; 120 Dwarf_CU_Context cucontext = 0; 121 122 if (!dbg) { 123 _dwarf_error(NULL, error, DW_DLE_DBG_NULL); 124 return DW_DLV_ERROR; 125 } 126 address_size = localdbg->de_pointer_size; /* default */ 127 if (die) { 128 /* If we wind up using the tied file the die_version 129 had better match! It cannot be other than a match. */ 130 /* Can return DW_DLV_ERROR, not DW_DLV_NO_ENTRY. 131 Add err code if error. Version comes from the 132 cu context, not the DIE itself. */ 133 res = dwarf_get_version_of_die(die,&die_version, 134 &offset_size); 135 if (res == DW_DLV_ERROR) { 136 _dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); 137 return DW_DLV_ERROR; 138 } 139 if (!die->di_cu_context) { 140 _dwarf_error(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); 141 return DW_DLV_ERROR; 142 } 143 cucontext = die->di_cu_context; 144 /* The DW4 ranges base was never used in GNU 145 but did get emitted. 146 http://llvm.1065342.n5.nabble.com/DebugInfo-DW-AT-GNU-ranges-base-in-non-fission-td64194.html 147 */ 148 #if 0 149 if (cucontext->cc_unit_type != DW_UT_skeleton && 150 cucontext->cc_version_stamp != DW_CU_VERSION4 && 151 cucontext->cc_ranges_base_present) { 152 /* Never needed. See DW_AT_GNU_ranges_base 153 in find_cu_die_base_fields() in dwarf_die_deliv.c */ 154 ranges_base = cucontext->cc_ranges_base; 155 } 156 #endif 157 address_size = cucontext->cc_address_size; 158 } 159 160 /* If tied object exists, 161 base object is DWP and tied object is the 162 skeleton/executabl CU containing a skeleton CU 163 with DW_AT_addr_base/DW_AT_GNU_addr_base and 164 DW_AT_rnglists_base/DW_AT_GNU_ranges base. */ 165 if (die &&dbg->de_tied_data.td_tied_object) { 166 167 int restied = 0; 168 169 /* dwo/dwp CU may have (DW5 pg 63) 170 DW_AT_name 171 DW_AT_language 172 DW_AT_macros 173 DW_AT_producer 174 DW_AT_identifier_case 175 DW_AT_main_subprogram 176 DW_AT_entry_pc 177 DW_AT_ranges if DW5 offset of header (see 178 ranges_base/rnglists_base below), 179 else of ranges 180 DW_AT_GNU_pubnames 181 DW_AT_stmt_list, a trivial stmt list with 182 the list of directories and file names 183 where needed for Type Units (DW5 pg 64) 184 and must have 185 DW_AT_[GNU_]dwo_id 186 and inherited from skeleton: 187 DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, 188 DW_AT_stmt_list, DW_AT_comp_dir, 189 DW_AT_use_UTF8, DW_AT_str_offsets_base, 190 DW_AT_addr_base and DW_AT_rnglists_base. 191 192 skeleton CU may have (DW5 pg 62) 193 DW_AT_[GNU_]addr_base possibly needed by dwp 194 DW_AT_str_offsets_base possibly needed by dwp 195 DW_AT_GNU_ranges_base (GNU)possibly needed by dwp 196 DW_AT_rnglists_base (DWARF5)possibly needed by dwp 197 DW_AT_low_pc 198 DW_AT_high_pc 199 DW_AT_ranges 200 DW_AT_str_offsets_base 201 DW_AT_[GNU_]dwo_name 202 DW_AT_stmt_list 203 DW_AT_comp_dir 204 DW_AT_use_UTF8 205 and must have 206 DW_AT_[GNU_]dwo_id 207 .debug_ranges does not 208 exist in the DWP, it is only in the executable. 209 */ 210 restied = _dwarf_get_ranges_base_attr_from_tied(dbg, 211 cucontext, 212 &ranges_base, 213 &addr_base, 214 error); 215 if (restied == DW_DLV_ERROR ) { 216 if(!error) { 217 return restied; 218 } 219 dwarf_dealloc(localdbg,*error,DW_DLA_ERROR); 220 *error = 0; 221 /* Nothing else to do. Look in original dbg. */ 222 } else if (restied == DW_DLV_NO_ENTRY ) { 223 /* Nothing else to do. Look in original dbg. */ 224 } else { 225 /* Ranges are never in a split dwarf object. 226 In the base object 227 instead. Use the tied_object */ 228 localdbg = dbg->de_tied_data.td_tied_object; 229 } 230 } 231 #if 0 232 FIXME Implement debug_rnglists! 233 /* de_debug_ranges is DW 3,4. 234 de_debug_rnglists is DW5. */ 235 if (die_version >= DW_CU_VERSION5) { 236 res = _dwarf_load_section(localdbg, 237 &localdbg->de_debug_rngslists,&localerror); 238 } else { 239 res = _dwarf_load_section(localdbg, 240 &localdbg->de_debug_ranges,&localerror); 241 } 242 #endif 243 res = _dwarf_load_section(localdbg, &localdbg->de_debug_ranges,&localerror); 244 if (res == DW_DLV_ERROR) { 245 _dwarf_error_mv_s_to_t(localdbg,&localerror,dbg,error); 246 return res; 247 } else if (res == DW_DLV_NO_ENTRY) { 248 return res; 249 } 250 251 /* Be safe in case adding rangesoffset and rangebase 252 overflows. */ 253 if (rangesoffset == localdbg->de_debug_ranges.dss_size) { 254 return DW_DLV_NO_ENTRY; 255 } 256 if (rangesoffset > localdbg->de_debug_ranges.dss_size) { 257 dwarfstring m; 258 259 dwarfstring_constructor(&m); 260 dwarfstring_append_printf_u(&m, 261 "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " 262 " rangesoffset is 0x%lx ",rangesoffset); 263 dwarfstring_append_printf_u(&m, 264 " and section size is 0x%lx.", 265 localdbg->de_debug_ranges.dss_size); 266 _dwarf_error_string(dbg, error, 267 DW_DLE_DEBUG_RANGES_OFFSET_BAD, 268 dwarfstring_string(&m)); 269 dwarfstring_destructor(&m); 270 return DW_DLV_ERROR; 271 } 272 if (ranges_base >= localdbg->de_debug_ranges.dss_size) { 273 dwarfstring m; 274 275 dwarfstring_constructor(&m); 276 dwarfstring_append_printf_u(&m, 277 "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " 278 " ranges base is 0x%lx ",ranges_base); 279 dwarfstring_append_printf_u(&m, 280 " and section size is 0x%lx.", 281 localdbg->de_debug_ranges.dss_size); 282 _dwarf_error_string(dbg, error, 283 DW_DLE_DEBUG_RANGES_OFFSET_BAD, 284 dwarfstring_string(&m)); 285 dwarfstring_destructor(&m); 286 return DW_DLV_ERROR; 287 } 288 if ((rangesoffset +ranges_base) >= 289 localdbg->de_debug_ranges.dss_size) { 290 dwarfstring m; 291 292 dwarfstring_constructor(&m); 293 dwarfstring_append_printf_u(&m, 294 "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " 295 " ranges base+offset is 0x%lx ", 296 ranges_base+rangesoffset); 297 dwarfstring_append_printf_u(&m, 298 " and section size is 0x%lx.", 299 localdbg->de_debug_ranges.dss_size); 300 _dwarf_error_string(dbg, error, 301 DW_DLE_DEBUG_RANGES_OFFSET_BAD, 302 dwarfstring_string(&m)); 303 dwarfstring_destructor(&m); 304 return DW_DLV_ERROR; 305 } 306 307 /* tied address_size must match the dwo address_size */ 308 section_end = localdbg->de_debug_ranges.dss_data + 309 localdbg->de_debug_ranges.dss_size; 310 rangeptr = localdbg->de_debug_ranges.dss_data + 311 rangesoffset + ranges_base; 312 beginrangeptr = rangeptr; 313 314 for (;;) { 315 struct ranges_entry * re = 0; 316 317 if (rangeptr == section_end) { 318 break; 319 } 320 if (rangeptr > section_end) { 321 dwarfstring m; 322 323 free_allocated_ranges(base); 324 dwarfstring_constructor(&m); 325 dwarfstring_append(&m, 326 "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " 327 " ranges pointer ran off the end " 328 "of the section"); 329 _dwarf_error_string(dbg, error, 330 DW_DLE_DEBUG_RANGES_OFFSET_BAD, 331 dwarfstring_string(&m)); 332 dwarfstring_destructor(&m); 333 return DW_DLV_ERROR; 334 } 335 re = calloc(sizeof(struct ranges_entry),1); 336 if (!re) { 337 free_allocated_ranges(base); 338 _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); 339 return DW_DLV_ERROR; 340 } 341 if ((rangeptr + (2*address_size)) > section_end) { 342 free(re); 343 free_allocated_ranges(base); 344 _dwarf_error_string(dbg, error, 345 DW_DLE_DEBUG_RANGES_OFFSET_BAD, 346 "DW_DLE_DEBUG_RANGES_OFFSET_BAD: " 347 " Not at the end of the ranges section " 348 " but there is not enough room in the section " 349 " for the next ranges entry"); 350 return DW_DLV_ERROR; 351 } 352 entry_count++; 353 res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr1, 354 rangeptr, address_size,error,section_end); 355 if (res != DW_DLV_OK) { 356 free(re); 357 free_allocated_ranges(base); 358 return res; 359 } 360 rangeptr += address_size; 361 res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr2, 362 rangeptr, address_size,error,section_end); 363 if (res != DW_DLV_OK) { 364 free(re); 365 free_allocated_ranges(base); 366 return res; 367 } 368 rangeptr += address_size; 369 if (!base) { 370 base = re; 371 last = re; 372 } else { 373 last->next = re; 374 last = re; 375 } 376 if (re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) { 377 re->cur.dwr_type = DW_RANGES_END; 378 break; 379 } else if (re->cur.dwr_addr1 == MAX_ADDR) { 380 re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION; 381 } else { 382 re->cur.dwr_type = DW_RANGES_ENTRY; 383 } 384 } 385 386 /* We return ranges on dbg, so use that to allocate. */ 387 ranges_data_out = (Dwarf_Ranges *) 388 _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count); 389 if (!ranges_data_out) { 390 /* Error, apply to original, not local dbg. */ 391 free_allocated_ranges(base); 392 _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); 393 return (DW_DLV_ERROR); 394 } 395 curre = base; 396 *rangesbuf = ranges_data_out; 397 *listlen = entry_count; 398 for (copyindex = 0; curre && (copyindex < entry_count); 399 ++copyindex,++ranges_data_out) { 400 401 *ranges_data_out = curre->cur; 402 curre = curre->next; 403 } 404 /* ASSERT: curre == NULL */ 405 free_allocated_ranges(base); 406 base = 0; 407 /* Callers will often not care about the bytes used. */ 408 if (bytecount) { 409 *bytecount = rangeptr - beginrangeptr; 410 } 411 return DW_DLV_OK; 412 } 413 414 int dwarf_get_ranges(Dwarf_Debug dbg, 415 Dwarf_Off rangesoffset, 416 Dwarf_Ranges ** rangesbuf, 417 Dwarf_Signed * listlen, 418 Dwarf_Unsigned * bytecount, 419 Dwarf_Error * error) 420 { 421 Dwarf_Die die = 0; 422 int res = dwarf_get_ranges_a(dbg,rangesoffset,die, 423 rangesbuf,listlen,bytecount,error); 424 return res; 425 } 426 427 void 428 dwarf_ranges_dealloc(Dwarf_Debug dbg, Dwarf_Ranges * rangesbuf, 429 UNUSEDARG Dwarf_Signed rangecount) 430 { 431 dwarf_dealloc(dbg,rangesbuf, DW_DLA_RANGES); 432 } 433