1 /* 2 Copyright (c) 2020, David Anderson 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with 6 or without modification, are permitted provided that the 7 following conditions are met: 8 9 Redistributions of source code must retain the above 10 copyright notice, this list of conditions and the following 11 disclaimer. 12 13 Redistributions in binary form must reproduce the above 14 copyright notice, this list of conditions and the following 15 disclaimer in the documentation and/or other materials 16 provided with the distribution. 17 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 19 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "config.h" 34 #include <stdio.h> 35 #include <stdlib.h> 36 #ifdef HAVE_STDLIB_H 37 #include <stdlib.h> 38 #endif /* HAVE_STDLIB_H */ 39 #include "dwarf_incl.h" 40 #include "dwarf_alloc.h" 41 #include "dwarf_error.h" 42 #include "dwarf_util.h" 43 #include "dwarfstring.h" 44 #include "dwarf_rnglists.h" 45 46 #define SIZEOFT8 1 47 #define SIZEOFT16 2 48 #define SIZEOFT32 4 49 #define SIZEOFT64 8 50 #define TRUE 1 51 #define FALSE 0 52 53 54 /* Used in case of error reading the 55 rnglists headers (not referring to Dwarf_Rnglists_Head 56 here), to clean up. */ 57 static void 58 free_rnglists_chain(Dwarf_Debug dbg, Dwarf_Chain head) 59 { 60 Dwarf_Chain cur = head; 61 Dwarf_Chain next = 0; 62 63 if(!head) { 64 return; 65 } 66 for( ;cur; cur = next) { 67 next = cur->ch_next; 68 if (cur->ch_item) { 69 free(cur->ch_item); 70 cur->ch_item = 0; 71 dwarf_dealloc(dbg,cur,DW_DLA_CHAIN); 72 } 73 } 74 } 75 76 static int 77 read_single_rle_entry(Dwarf_Debug dbg, 78 Dwarf_Small *data, 79 Dwarf_Unsigned dataoffset, 80 Dwarf_Small *enddata, 81 unsigned address_size, 82 unsigned *bytes_count_out, 83 unsigned *entry_kind, 84 Dwarf_Unsigned *entry_operand1, 85 Dwarf_Unsigned *entry_operand2, 86 Dwarf_Error* err) 87 { 88 Dwarf_Unsigned count = 0; 89 unsigned leblen = 0; 90 unsigned code = 0; 91 Dwarf_Unsigned val1 = 0; 92 Dwarf_Unsigned val2 = 0; 93 94 code = *data; 95 ++data; 96 ++count; 97 switch(code) { 98 case DW_RLE_end_of_list: break; 99 case DW_RLE_base_addressx:{ 100 DECODE_LEB128_UWORD_LEN_CK(data,val1,leblen, 101 dbg,err,enddata); 102 count += leblen; 103 } 104 break; 105 case DW_RLE_startx_endx: 106 case DW_RLE_startx_length: 107 case DW_RLE_offset_pair: { 108 DECODE_LEB128_UWORD_LEN_CK(data,val1,leblen, 109 dbg,err,enddata); 110 count += leblen; 111 DECODE_LEB128_UWORD_LEN_CK(data,val2,leblen, 112 dbg,err,enddata); 113 count += leblen; 114 } 115 break; 116 case DW_RLE_base_address: { 117 READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, 118 data,address_size,err,enddata); 119 data += address_size; 120 count += address_size; 121 } 122 break; 123 case DW_RLE_start_end: { 124 READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, 125 data,address_size,err,enddata); 126 data += address_size; 127 count += address_size; 128 READ_UNALIGNED_CK(dbg,val2, Dwarf_Unsigned, 129 data,address_size,err,enddata); 130 data += address_size; 131 count += address_size; 132 } 133 break; 134 case DW_RLE_start_length: { 135 READ_UNALIGNED_CK(dbg,val1, Dwarf_Unsigned, 136 data,address_size,err,enddata); 137 data += address_size; 138 count += address_size; 139 DECODE_LEB128_UWORD_LEN_CK(data,val2,leblen, 140 dbg,err,enddata); 141 count += leblen; 142 } 143 break; 144 default: { 145 dwarfstring m; 146 147 dwarfstring_constructor(&m); 148 dwarfstring_append_printf_u(&m, 149 "DW_DLE_RNGLISTS_ERROR: " 150 "The rangelists entry at .debug_rnglists" 151 " offset 0x%x" ,dataoffset); 152 dwarfstring_append_printf_u(&m, 153 " has code 0x%x which is unknown",code); 154 _dwarf_error_string(dbg,err,DW_DLE_RNGLISTS_ERROR, 155 dwarfstring_string(&m)); 156 dwarfstring_destructor(&m); 157 return DW_DLV_ERROR; 158 } 159 break; 160 } 161 *bytes_count_out = count; 162 *entry_kind = code; 163 *entry_operand1 = val1; 164 *entry_operand2 = val2; 165 return DW_DLV_OK; 166 } 167 168 /* Reads the header. Determines the 169 various offsets, including offset 170 of the next header. Does no memory 171 allocations here. */ 172 static int 173 internal_read_header(Dwarf_Debug dbg, 174 Dwarf_Unsigned contextnum, 175 Dwarf_Unsigned sectionlength, 176 Dwarf_Small *data, 177 Dwarf_Small *end_data, 178 Dwarf_Unsigned offset, 179 Dwarf_Rnglists_Context buildhere, 180 Dwarf_Unsigned *next_offset, 181 Dwarf_Error *error) 182 { 183 Dwarf_Small *startdata = data; 184 Dwarf_Unsigned arealen = 0; 185 int length_size = 0; 186 int exten_size = 0; 187 Dwarf_Unsigned version = 0; 188 unsigned address_size = 0; 189 unsigned segment_selector_size= 0; 190 Dwarf_Unsigned offset_entry_count = 0; 191 Dwarf_Unsigned localoff = 0; 192 Dwarf_Unsigned lists_len = 0; 193 194 READ_AREA_LENGTH_CK(dbg,arealen,Dwarf_Unsigned, 195 data,length_size,exten_size, 196 error, 197 sectionlength,end_data); 198 if (arealen > sectionlength) { 199 dwarfstring m; 200 dwarfstring_constructor(&m); 201 dwarfstring_append_printf_u(&m, 202 "DW_DLE_SECTION_SIZE_ERROR: A .debug_rnglists " 203 "area size of 0x%x ",arealen); 204 dwarfstring_append_printf_u(&m, 205 "at offset 0x%x ",offset); 206 dwarfstring_append_printf_u(&m, 207 "is larger than the entire section size of " 208 "0x%x. Corrupt DWARF.",sectionlength); 209 _dwarf_error_string(dbg,error,DW_DLE_SECTION_SIZE_ERROR, 210 dwarfstring_string(&m)); 211 dwarfstring_destructor(&m); 212 return DW_DLV_ERROR; 213 } 214 215 buildhere->rc_length = arealen +length_size+exten_size; 216 buildhere->rc_dbg = dbg; 217 buildhere->rc_index = contextnum; 218 buildhere->rc_header_offset = offset; 219 buildhere->rc_offset_size = length_size; 220 buildhere->rc_extension_size = exten_size; 221 READ_UNALIGNED_CK(dbg,version,Dwarf_Unsigned,data, 222 SIZEOFT16,error,end_data); 223 if (version != DW_CU_VERSION5) { 224 dwarfstring m; 225 dwarfstring_constructor(&m); 226 dwarfstring_append_printf_u(&m, 227 "DW_DLE_VERSION_STAMP_ERROR: The version should be 5 " 228 "but we find %u instead.",version); 229 _dwarf_error_string(dbg,error,DW_DLE_VERSION_STAMP_ERROR, 230 dwarfstring_string(&m)); 231 dwarfstring_destructor(&m); 232 return DW_DLV_ERROR; 233 } 234 buildhere->rc_version = version; 235 data += SIZEOFT16; 236 237 READ_UNALIGNED_CK(dbg,address_size,unsigned,data, 238 SIZEOFT8,error,end_data); 239 if (version != DW_CU_VERSION5) { 240 dwarfstring m; 241 dwarfstring_constructor(&m); 242 dwarfstring_append_printf_u(&m, 243 "DW_DLE_VERSION_STAMP_ERROR: The version should be 5 " 244 "but we find %u instead.",version); 245 _dwarf_error_string(dbg,error,DW_DLE_VERSION_STAMP_ERROR, 246 dwarfstring_string(&m)); 247 dwarfstring_destructor(&m); 248 return DW_DLV_ERROR; 249 } 250 if (address_size != 4 && address_size != 8 && 251 address_size != 2) { 252 dwarfstring m; 253 dwarfstring_constructor(&m); 254 dwarfstring_append_printf_u(&m, 255 " DW_DLE_ADDRESS_SIZE_ERROR: The address size " 256 "of %u is not supported.",address_size); 257 _dwarf_error_string(dbg,error,DW_DLE_ADDRESS_SIZE_ERROR, 258 dwarfstring_string(&m)); 259 dwarfstring_destructor(&m); 260 return DW_DLV_ERROR; 261 } 262 buildhere->rc_address_size = address_size; 263 data++; 264 265 READ_UNALIGNED_CK(dbg,segment_selector_size,unsigned,data, 266 SIZEOFT8,error,end_data); 267 buildhere->rc_segment_selector_size = segment_selector_size; 268 data++; 269 270 READ_UNALIGNED_CK(dbg,offset_entry_count,Dwarf_Unsigned,data, 271 SIZEOFT32,error,end_data); 272 buildhere->rc_offset_entry_count = offset_entry_count; 273 data += SIZEOFT32; 274 if (offset_entry_count ){ 275 buildhere->rc_offsets_array = data; 276 } 277 localoff = data - startdata; 278 lists_len = address_size *offset_entry_count; 279 280 data += lists_len; 281 282 buildhere->rc_offsets_off_in_sect = offset+localoff; 283 buildhere->rc_first_rnglist_offset = offset+localoff+ 284 lists_len; 285 buildhere->rc_rnglists_header = startdata; 286 buildhere->rc_endaddr = startdata +buildhere->rc_length; 287 buildhere->rc_past_last_rnglist_offset = 288 buildhere->rc_header_offset +buildhere->rc_length; 289 *next_offset = buildhere->rc_past_last_rnglist_offset; 290 return DW_DLV_OK; 291 } 292 293 294 /* We return a pointer to an array of contexts 295 (not context pointers through *cxt if 296 we succeed and are returning DW_DLV_OK. 297 We never return DW_DLV_NO_ENTRY here. */ 298 static int 299 internal_load_rnglists_contexts(Dwarf_Debug dbg, 300 Dwarf_Rnglists_Context **cxt, 301 Dwarf_Unsigned *count, 302 Dwarf_Error *error) 303 { 304 Dwarf_Unsigned offset = 0; 305 Dwarf_Unsigned nextoffset = 0; 306 Dwarf_Small * data = dbg->de_debug_rnglists.dss_data; 307 Dwarf_Unsigned section_size = dbg->de_debug_rnglists.dss_size; 308 Dwarf_Small * startdata = data; 309 Dwarf_Small * end_data = data +section_size; 310 Dwarf_Chain curr_chain = 0; 311 Dwarf_Chain prev_chain = 0; 312 Dwarf_Chain head_chain = 0; 313 int res = 0; 314 Dwarf_Unsigned chainlength = 0; 315 Dwarf_Rnglists_Context *fullarray = 0; 316 Dwarf_Unsigned i = 0; 317 318 for( ; data < end_data ; ) { 319 Dwarf_Rnglists_Context newcontext = 0; 320 321 /* sizeof the context struct, not sizeof a pointer */ 322 newcontext = malloc(sizeof(*newcontext)); 323 if (!newcontext) { 324 free_rnglists_chain(dbg,head_chain); 325 _dwarf_error_string(dbg,error, 326 DW_DLE_ALLOC_FAIL, 327 "DW_DLE_ALLOC_FAIL: Allocation of " 328 "Rnglists_Context failed"); 329 return DW_DLV_ERROR; 330 } 331 memset(newcontext,0,sizeof(*newcontext)); 332 res = internal_read_header(dbg,chainlength, 333 section_size, 334 data,end_data,offset, 335 newcontext,&nextoffset,error); 336 if (res == DW_DLV_ERROR) { 337 free(newcontext); 338 free_rnglists_chain(dbg,head_chain); 339 } 340 curr_chain = (Dwarf_Chain) 341 _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); 342 if (curr_chain == NULL) { 343 free_rnglists_chain(dbg,head_chain); 344 _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, 345 "DW_DLE_ALLOC_FAIL: allocating Rnglists_Context" 346 " chain entry"); 347 return DW_DLV_ERROR; 348 } 349 curr_chain->ch_item = newcontext; 350 ++chainlength; 351 if (head_chain == NULL) { 352 head_chain = prev_chain = curr_chain; 353 } else { 354 prev_chain->ch_next = curr_chain; 355 prev_chain = curr_chain; 356 } 357 data = startdata+nextoffset; 358 offset = nextoffset; 359 } 360 fullarray= (Dwarf_Rnglists_Context *)malloc( 361 chainlength *sizeof(Dwarf_Rnglists_Context /*pointer*/)); 362 if (!fullarray) { 363 free_rnglists_chain(dbg,head_chain); 364 _dwarf_error_string(dbg,error, 365 DW_DLE_ALLOC_FAIL,"Allocation of " 366 "Rnglists_Context pointer array failed"); 367 return DW_DLV_ERROR; 368 } 369 curr_chain = head_chain; 370 for( i = 0; i < chainlength; ++i) { 371 fullarray[i] = (Dwarf_Rnglists_Context)curr_chain->ch_item; 372 curr_chain->ch_item = 0; 373 prev_chain = curr_chain; 374 curr_chain = curr_chain->ch_next; 375 dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); 376 } 377 /* ASSERT: the chain is entirely dealloc'd 378 and the array of pointers points to 379 individually malloc'd Dwarf_Rnglists_Context_s */ 380 *cxt = fullarray; 381 *count = chainlength; 382 return DW_DLV_OK; 383 } 384 385 386 387 /* Used by dwarfdump to print raw rnglists data. 388 Loads all the .debug_rnglists[.dwo] headers and 389 returns DW_DLV_NO_ENTRY if the section 390 is missing or empty. 391 Intended to be done quite early and 392 done exactly once. 393 Harmless to do more than once. 394 With DW_DLV_OK it returns the number of 395 rnglists headers in the section through 396 rnglists_count. */ 397 int dwarf_load_rnglists( 398 Dwarf_Debug dbg, 399 Dwarf_Unsigned *rnglists_count, 400 UNUSEDARG Dwarf_Error *error) 401 { 402 int res = DW_DLV_ERROR; 403 Dwarf_Rnglists_Context *cxt = 0; 404 Dwarf_Unsigned count = 0; 405 406 if (dbg->de_rnglists_context) { 407 if (rnglists_count) { 408 *rnglists_count = dbg->de_rnglists_context_count; 409 } 410 } 411 if (!dbg->de_debug_rnglists.dss_size) { 412 /* nothing there. */ 413 return DW_DLV_NO_ENTRY; 414 } 415 if (!dbg->de_debug_rnglists.dss_data) { 416 res = _dwarf_load_section(dbg, &dbg->de_debug_rnglists, 417 error); 418 if (res != DW_DLV_OK) { 419 return res; 420 } 421 } 422 res = internal_load_rnglists_contexts(dbg,&cxt,&count,error); 423 if (res == DW_DLV_ERROR) { 424 return res; 425 } 426 dbg->de_rnglists_context = cxt; 427 dbg->de_rnglists_context_count = count; 428 if (rnglists_count) { 429 *rnglists_count = count; 430 } 431 return DW_DLV_OK; 432 } 433 434 /* Frees the memory in use in all rnglists contexts. 435 Done by dwarf_finish() */ 436 void 437 _dwarf_dealloc_rnglists_context(Dwarf_Debug dbg) 438 { 439 Dwarf_Unsigned i = 0; 440 Dwarf_Rnglists_Context * rngcon = 0; 441 442 if (!dbg->de_rnglists_context) { 443 return; 444 } 445 rngcon = dbg->de_rnglists_context; 446 for( ; i < dbg->de_rnglists_context_count; ++i,++rngcon) { 447 Dwarf_Rnglists_Context con = *rngcon; 448 con->rc_offsets_array = 0; 449 con->rc_offset_entry_count = 0; 450 free(con); 451 } 452 free(dbg->de_rnglists_context); 453 dbg->de_rnglists_context = 0; 454 dbg->de_rnglists_context_count = 0; 455 } 456 457 /* Used by dwarfdump to print raw rnglists data. */ 458 int 459 dwarf_get_rnglist_offset_index_value( 460 Dwarf_Debug dbg, 461 Dwarf_Unsigned context_index, 462 Dwarf_Unsigned offsetentry_index, 463 Dwarf_Unsigned * offset_value_out, 464 Dwarf_Unsigned * global_offset_value_out, 465 Dwarf_Error *error) 466 { 467 Dwarf_Rnglists_Context con = 0; 468 unsigned offset_len = 0; 469 Dwarf_Small *offsetptr = 0; 470 Dwarf_Unsigned targetoffset = 0; 471 472 if (!dbg->de_rnglists_context_count) { 473 return DW_DLV_NO_ENTRY; 474 } 475 if (context_index >= dbg->de_rnglists_context_count) { 476 return DW_DLV_NO_ENTRY; 477 } 478 con = dbg->de_rnglists_context[context_index]; 479 480 if (offsetentry_index >= con->rc_offset_entry_count) { 481 return DW_DLV_NO_ENTRY; 482 } 483 offset_len = con->rc_offset_size; 484 offsetptr = con->rc_offsets_array + 485 (offsetentry_index*offset_len); 486 READ_UNALIGNED_CK(dbg,targetoffset,Dwarf_Unsigned, 487 offsetptr, 488 offset_len,error,con->rc_endaddr); 489 if (offset_value_out) { 490 *offset_value_out = targetoffset; 491 } 492 if (global_offset_value_out) { 493 *global_offset_value_out = targetoffset + 494 con->rc_offsets_off_in_sect; 495 } 496 return DW_DLV_OK; 497 } 498 499 /* Used by dwarfdump to print basic data from the 500 data generated to look at a specific rangelist 501 as returned by dwarf_rnglists_index_get_rle_head() 502 or dwarf_rnglists_offset_get_rle_head. */ 503 int dwarf_get_rnglist_head_basics( 504 Dwarf_Rnglists_Head head, 505 Dwarf_Unsigned * rle_count, 506 Dwarf_Unsigned * rle_version, 507 Dwarf_Unsigned * rnglists_index_returned, 508 Dwarf_Unsigned * bytes_total_in_rle, 509 Dwarf_Half * offset_size, 510 Dwarf_Half * address_size, 511 Dwarf_Half * segment_selector_size, 512 Dwarf_Unsigned * overall_offset_of_this_context, 513 Dwarf_Unsigned * total_length_of_this_context, 514 Dwarf_Unsigned * offset_table_offset, 515 Dwarf_Unsigned * offset_table_entrycount, 516 Dwarf_Bool * rnglists_base_present, 517 Dwarf_Unsigned * rnglists_base, 518 Dwarf_Bool * rnglists_base_address_present, 519 Dwarf_Unsigned * rnglists_base_address, 520 Dwarf_Bool * rnglists_debug_addr_base_present, 521 Dwarf_Unsigned * rnglists_debug_addr_base, 522 UNUSEDARG Dwarf_Error *error) 523 { 524 Dwarf_Rnglists_Context rngcontext = 0; 525 *rle_count = head->rh_count; 526 *rle_version = head->rh_version; 527 *rnglists_index_returned = head->rh_index; 528 *bytes_total_in_rle = head->rh_bytes_total; 529 *offset_size = head->rh_offset_size; 530 *address_size = head->rh_address_size; 531 *segment_selector_size = head->rh_segment_selector_size; 532 rngcontext = head->rh_localcontext; 533 if (rngcontext) { 534 *overall_offset_of_this_context = rngcontext->rc_header_offset; 535 *total_length_of_this_context = rngcontext->rc_length; 536 *offset_table_offset = rngcontext->rc_offsets_off_in_sect; 537 *offset_table_entrycount = rngcontext->rc_offset_entry_count; 538 } 539 *rnglists_base_present = head->rh_at_rnglists_base_present; 540 *rnglists_base= head->rh_at_rnglists_base; 541 542 *rnglists_base_address_present = head->rh_cu_base_address_present; 543 *rnglists_base_address= head->rh_cu_base_address; 544 545 *rnglists_debug_addr_base_present = head->rh_cu_addr_base_present; 546 *rnglists_debug_addr_base = head->rh_cu_addr_base; 547 return DW_DLV_OK; 548 } 549 550 /* Used by dwarfdump to print raw rnglists data. 551 Enables printing of details about the Range List Table 552 Headers, one header per call. Index starting at 0. 553 Returns DW_DLV_NO_ENTRY if index is too high for the table. 554 A .debug_rnglists section may contain any number 555 of Range List Table Headers with their details. */ 556 int dwarf_get_rnglist_context_basics( 557 Dwarf_Debug dbg, 558 Dwarf_Unsigned context_index, 559 Dwarf_Unsigned * header_offset, 560 Dwarf_Small * offset_size, 561 Dwarf_Small * extension_size, 562 unsigned * version, /* 5 */ 563 Dwarf_Small * address_size, 564 Dwarf_Small * segment_selector_size, 565 Dwarf_Unsigned * offset_entry_count, 566 Dwarf_Unsigned * offset_of_offset_array, 567 Dwarf_Unsigned * offset_of_first_rangeentry, 568 Dwarf_Unsigned * offset_past_last_rangeentry, 569 UNUSEDARG Dwarf_Error *error) 570 { 571 Dwarf_Rnglists_Context con = 0; 572 if (!dbg->de_rnglists_context_count) { 573 return DW_DLV_NO_ENTRY; 574 } 575 if (context_index >= dbg->de_rnglists_context_count) { 576 return DW_DLV_NO_ENTRY; 577 } 578 con = dbg->de_rnglists_context[context_index]; 579 580 if (header_offset) { 581 *header_offset = con->rc_header_offset; 582 } 583 if (offset_size) { 584 *offset_size = con->rc_offset_size; 585 } 586 if (offset_size) { 587 *extension_size = con->rc_extension_size; 588 } 589 if (version) { 590 *version = con->rc_version; 591 } 592 if (address_size) { 593 *address_size = con->rc_address_size; 594 } 595 if (segment_selector_size) { 596 *segment_selector_size = con->rc_segment_selector_size; 597 } 598 if (offset_entry_count) { 599 *offset_entry_count = con->rc_offset_entry_count; 600 } 601 if (offset_of_offset_array) { 602 *offset_of_offset_array = con->rc_offsets_off_in_sect; 603 } 604 if (offset_of_first_rangeentry) { 605 *offset_of_first_rangeentry = con->rc_first_rnglist_offset; 606 } 607 if (offset_past_last_rangeentry) { 608 *offset_past_last_rangeentry = 609 con->rc_past_last_rnglist_offset; 610 } 611 return DW_DLV_OK; 612 } 613 614 /* Used by dwarfdump to print raw rnglists data. 615 entry offset is offset_of_first_rangeentry. 616 Stop when the returned *next_entry_offset 617 is == offset_past_last_rangentry (from 618 dwarf_get_rnglist_context_plus). 619 This only makes sense within those ranges. 620 This retrieves raw detail from the section, 621 no base values or anything are added. 622 So this returns raw individual entries 623 for a single rnglist header, meaning a 624 a single Dwarf_Rnglists_Context. */ 625 int dwarf_get_rnglist_rle( 626 Dwarf_Debug dbg, 627 Dwarf_Unsigned contextnumber, 628 Dwarf_Unsigned entry_offset, 629 Dwarf_Unsigned endoffset, 630 unsigned *entrylen, 631 unsigned *entry_kind, 632 Dwarf_Unsigned *entry_operand1, 633 Dwarf_Unsigned *entry_operand2, 634 Dwarf_Error *err) 635 { 636 Dwarf_Rnglists_Context con = 0; 637 Dwarf_Small *data = 0; 638 Dwarf_Small *enddata = 0; 639 int res = 0; 640 unsigned address_size = 0; 641 642 if (!dbg->de_rnglists_context_count) { 643 return DW_DLV_NO_ENTRY; 644 } 645 data = dbg->de_debug_rnglists.dss_data + 646 entry_offset; 647 enddata = dbg->de_debug_rnglists.dss_data + 648 endoffset; 649 if (contextnumber >= dbg->de_rnglists_context_count) { 650 return DW_DLV_NO_ENTRY; 651 } 652 653 con = dbg->de_rnglists_context[contextnumber]; 654 address_size = con->rc_address_size; 655 656 res = read_single_rle_entry(dbg, 657 data,entry_offset,enddata, 658 address_size,entrylen, 659 entry_kind, entry_operand1, entry_operand2, 660 err); 661 return res; 662 } 663 664 665 static int 666 _dwarf_which_rnglists_context(Dwarf_Debug dbg, 667 Dwarf_CU_Context ctx, 668 Dwarf_Unsigned rnglist_offset, 669 Dwarf_Unsigned *index, 670 Dwarf_Error *error) 671 { 672 Dwarf_Unsigned count; 673 Dwarf_Rnglists_Context *array; 674 Dwarf_Unsigned i = 0; 675 676 array = dbg->de_rnglists_context; 677 count = dbg->de_rnglists_context_count; 678 /* Using the slow way, a simple linear search. */ 679 if (!ctx->cc_rnglists_base_present) { 680 /* We look at the location of each rnglist context 681 to find one with the offset the DIE gave us. */ 682 for ( i = 0 ; i < count; ++i) { 683 Dwarf_Rnglists_Context rcx = array[i]; 684 Dwarf_Unsigned rcxoff = rcx->rc_header_offset; 685 Dwarf_Unsigned rcxend = rcxoff + 686 rcx->rc_length; 687 688 if (rnglist_offset < rcxoff){ 689 continue; 690 } 691 if (rnglist_offset < rcxend ){ 692 *index = i; 693 return DW_DLV_OK; 694 } 695 } 696 { 697 dwarfstring m; 698 699 dwarfstring_constructor(&m); 700 dwarfstring_append_printf_u(&m, 701 "DW_DLE_RNGLISTS_ERROR: rnglist ran off end " 702 " finding target offset of" 703 " 0x%" DW_PR_XZEROS DW_PR_DUx ,rnglist_offset); 704 dwarfstring_append(&m, 705 " Not found anywhere in .debug_rnglists " 706 "data. Corrupted data?"); 707 _dwarf_error_string(dbg,error, 708 DW_DLE_RNGLISTS_ERROR, 709 dwarfstring_string(&m)); 710 dwarfstring_destructor(&m); 711 return DW_DLV_ERROR; 712 } 713 } else { 714 /* We have a DW_AT_rnglists_base (cc_rangelists_base), 715 let's use it. */ 716 Dwarf_Unsigned lookfor = 0;; 717 718 lookfor = ctx->cc_rnglists_base; 719 for ( i = 0 ; i < count; ++i) { 720 dwarfstring m; 721 722 Dwarf_Rnglists_Context rcx = array[i]; 723 if (rcx->rc_offsets_off_in_sect == lookfor){ 724 *index = i; 725 return DW_DLV_OK; 726 } 727 if (rcx->rc_offsets_off_in_sect < lookfor){ 728 continue; 729 } 730 731 dwarfstring_constructor(&m); 732 dwarfstring_append_printf_u(&m, 733 "DW_DLE_RNGLISTS_ERROR: rnglists base of " 734 " 0x%" DW_PR_XZEROS DW_PR_DUx ,lookfor); 735 dwarfstring_append_printf_u(&m, 736 " was not found though we are now at base " 737 " 0x%" DW_PR_XZEROS DW_PR_DUx , 738 rcx->rc_offsets_off_in_sect); 739 _dwarf_error_string(dbg,error, 740 DW_DLE_RNGLISTS_ERROR, 741 dwarfstring_string(&m)); 742 dwarfstring_destructor(&m); 743 return DW_DLV_ERROR; 744 } 745 { 746 dwarfstring m; 747 748 dwarfstring_constructor(&m); 749 dwarfstring_append_printf_u(&m, 750 "DW_DLE_RNGLISTS_ERROR: rnglist base of " 751 " 0x%" DW_PR_XZEROS DW_PR_DUx ,lookfor); 752 dwarfstring_append(&m, 753 " was not found anywhere in .debug_rnglists " 754 "data. Corrupted data?"); 755 _dwarf_error_string(dbg,error, 756 DW_DLE_RNGLISTS_ERROR, 757 dwarfstring_string(&m)); 758 dwarfstring_destructor(&m); 759 return DW_DLV_ERROR; 760 } 761 } 762 return DW_DLV_ERROR; 763 } 764 765 int 766 dwarf_dealloc_rnglists_head(Dwarf_Rnglists_Head h) 767 { 768 Dwarf_Debug dbg = h->rh_dbg; 769 770 dwarf_dealloc(dbg,h,DW_DLA_RNGLISTS_HEAD); 771 return DW_DLV_OK; 772 } 773 774 /* Caller will eventually free as appropriate. */ 775 static int 776 alloc_rle_and_append_to_list(Dwarf_Debug dbg, 777 Dwarf_Rnglists_Head rctx, 778 Dwarf_Rnglists_Entry *e_out, 779 Dwarf_Error *error) 780 { 781 Dwarf_Rnglists_Entry e = 0; 782 783 e = malloc(sizeof(struct Dwarf_Rnglists_Entry_s)); 784 if (!e) { 785 _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, 786 "DW_DLE_ALLOC_FAIL: Out of memory in " 787 "building list of rnglists entries on a DIE."); 788 return DW_DLV_ERROR; 789 } 790 memset(e,0,sizeof(struct Dwarf_Rnglists_Entry_s)); 791 if (rctx->rh_first) { 792 rctx->rh_last->rle_next = e; 793 rctx->rh_last = e; 794 } else { 795 rctx->rh_first = e; 796 rctx->rh_last = e; 797 } 798 rctx->rh_count++; 799 *e_out = e; 800 return DW_DLV_OK; 801 } 802 803 /* Read the group of rangelists entries, and 804 finally build an array of Dwarf_Rnglists_Entry 805 records. Attach to rctx here. 806 Since on error the caller will destruct the rctx 807 and we ensure to attach allocations there 808 the caller will destruct the allocations here 809 in case we return DW_DLV_ERROR*/ 810 static int 811 build_array_of_rle(Dwarf_Debug dbg, 812 Dwarf_Rnglists_Head rctx, 813 Dwarf_Error *error) 814 { 815 int res = 0; 816 Dwarf_Small * data = rctx->rh_rlepointer; 817 Dwarf_Unsigned dataoffset = rctx->rh_rlearea_offset; 818 Dwarf_Small *enddata = rctx->rh_end_data_area; 819 unsigned address_size = rctx->rh_address_size; 820 Dwarf_Unsigned bytescounttotal= 0; 821 Dwarf_Unsigned latestbaseaddr = 0; 822 unsigned foundbaseaddr = FALSE; 823 int done = FALSE; 824 825 if (rctx->rh_cu_base_address_present) { 826 /* The CU DIE had DW_AT_low_pc 827 and it is a base address. */ 828 latestbaseaddr = rctx->rh_cu_base_address; 829 foundbaseaddr = TRUE; 830 } 831 for( ; !done ; ) { 832 unsigned entrylen = 0; 833 unsigned code = 0; 834 Dwarf_Unsigned val1 = 0; 835 Dwarf_Unsigned val2 = 0; 836 Dwarf_Addr addr1= 0; 837 Dwarf_Addr addr2 = 0; 838 Dwarf_Rnglists_Entry e = 0; 839 840 res = read_single_rle_entry(dbg, 841 data,dataoffset, enddata, 842 address_size,&entrylen, 843 &code,&val1, &val2,error); 844 if (res != DW_DLV_OK) { 845 return res; 846 } 847 res = alloc_rle_and_append_to_list(dbg,rctx,&e,error); 848 if (res != DW_DLV_OK) { 849 return res; 850 } 851 e->rle_code = code, 852 e->rle_entrylen = entrylen; 853 e->rle_raw1 = val1; 854 e->rle_raw2 = val2; 855 bytescounttotal += entrylen; 856 data += entrylen; 857 if (code == DW_RLE_end_of_list) { 858 done = TRUE; 859 break; 860 } 861 switch(code) { 862 case DW_RLE_base_addressx: 863 foundbaseaddr = TRUE; 864 res = _dwarf_extract_address_from_debug_addr( 865 dbg,rctx->rh_context,val1, 866 &addr1,error); 867 if (res != DW_DLV_OK) { 868 return res; 869 } 870 e->rle_cooked1 = addr1; 871 latestbaseaddr = addr1; 872 break; 873 case DW_RLE_startx_endx: 874 res = _dwarf_extract_address_from_debug_addr( 875 dbg,rctx->rh_context,val1, 876 &addr1,error); 877 if (res != DW_DLV_OK) { 878 return res; 879 } 880 res = _dwarf_extract_address_from_debug_addr( 881 dbg,rctx->rh_context,val2, 882 &addr2,error); 883 if (res != DW_DLV_OK) { 884 return res; 885 } 886 e->rle_cooked1 = addr1; 887 e->rle_cooked2 = addr2; 888 break; 889 case DW_RLE_startx_length: 890 res = _dwarf_extract_address_from_debug_addr( 891 dbg,rctx->rh_context,val1, 892 &addr1,error); 893 if (res != DW_DLV_OK) { 894 return res; 895 } 896 e->rle_cooked1 = addr1; 897 e->rle_cooked2 = val2+addr1; 898 break; 899 case DW_RLE_offset_pair: 900 if(foundbaseaddr) { 901 e->rle_cooked1 = val1+latestbaseaddr; 902 e->rle_cooked2 = val2+latestbaseaddr; 903 } else { 904 e->rle_cooked1 = val1+rctx->rh_cu_base_address; 905 e->rle_cooked2 = val2+rctx->rh_cu_base_address; 906 } 907 break; 908 case DW_RLE_base_address: 909 foundbaseaddr = TRUE; 910 latestbaseaddr = val1; 911 e->rle_cooked1 = val1; 912 break; 913 case DW_RLE_start_end: 914 e->rle_cooked1 = val1; 915 e->rle_cooked2 = val2; 916 break; 917 case DW_RLE_start_length: 918 e->rle_cooked1 = val1; 919 e->rle_cooked2 = val2+val1; 920 break; 921 default: { 922 dwarfstring m; 923 924 dwarfstring_constructor(&m); 925 dwarfstring_append_printf_u(&m, 926 " DW_DLE_RNGLISTS_ERROR: " 927 " The .debug_rnglists " 928 " rangelist code 0x%x is unknown, " 929 " DWARF5 is corrupted.",code); 930 _dwarf_error_string(dbg, error, 931 DW_DLE_RNGLISTS_ERROR, 932 dwarfstring_string(&m)); 933 dwarfstring_destructor(&m); 934 return DW_DLV_ERROR; 935 } 936 } 937 } 938 if (rctx->rh_count > 0) { 939 Dwarf_Rnglists_Entry* array = 0; 940 Dwarf_Rnglists_Entry cur = 0; 941 Dwarf_Unsigned i = 0; 942 943 /* Creating an array of pointers. */ 944 array = (Dwarf_Rnglists_Entry*)malloc( 945 rctx->rh_count *sizeof(Dwarf_Rnglists_Entry)); 946 if (!array) { 947 _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, 948 "DW_DLE_ALLOC_FAIL: Out of memory in " 949 "turning list of rnglists entries on a DIE" 950 "into a pointer array"); 951 return DW_DLV_ERROR; 952 } 953 cur = rctx->rh_first; 954 for ( ; i < rctx->rh_count; ++i) { 955 array[i] = cur; 956 cur = cur->rle_next; 957 } 958 rctx->rh_rnglists = array; 959 rctx->rh_first = 0; 960 rctx->rh_last = 0; 961 } 962 rctx->rh_bytes_total = bytescounttotal; 963 return DW_DLV_OK; 964 } 965 966 /* Build a head with all the relevent Entries 967 attached. 968 */ 969 int 970 dwarf_rnglists_get_rle_head( 971 Dwarf_Attribute attr, 972 Dwarf_Half theform, 973 Dwarf_Unsigned attr_val, 974 Dwarf_Rnglists_Head *head_out, 975 Dwarf_Unsigned *entries_count_out, 976 Dwarf_Unsigned *global_offset_of_rle_set, 977 Dwarf_Error *error) 978 { 979 int res = 0; 980 Dwarf_Unsigned rnglists_contextnum = 0; 981 Dwarf_Small *table_base = 0; 982 Dwarf_Small *table_entry = 0; 983 Dwarf_Small *enddata = 0; 984 Dwarf_Rnglists_Context *array = 0; 985 Dwarf_Rnglists_Context rctx = 0; 986 Dwarf_Unsigned entrycount = 0; 987 unsigned offsetsize = 0; 988 Dwarf_Unsigned rle_global_offset = 0; 989 Dwarf_Rnglists_Head lhead = 0; 990 Dwarf_CU_Context ctx = 0; 991 struct Dwarf_Rnglists_Head_s shead; 992 Dwarf_Unsigned offset_in_rnglists = 0; 993 Dwarf_Debug dbg = 0; 994 Dwarf_Bool is_rnglistx = FALSE; 995 996 memset(&shead,0,sizeof(shead)); 997 ctx = attr->ar_cu_context; 998 dbg = ctx->cc_dbg; 999 array = dbg->de_rnglists_context; 1000 if (theform == DW_FORM_rnglistx) { 1001 is_rnglistx = TRUE; 1002 } 1003 /* ASSERT: the 3 pointers just set are non-null */ 1004 /* the context cc_rnglists_base gives the offset 1005 of the array. of offsets (if cc_rnglists_base_present) */ 1006 offset_in_rnglists = attr_val; 1007 if (is_rnglistx) { 1008 if (ctx->cc_rnglists_base_present) { 1009 offset_in_rnglists = ctx->cc_rnglists_base; 1010 1011 } else { 1012 /* FIXME: check in tied file for a cc_rnglists_base */ 1013 dwarfstring m; 1014 1015 dwarfstring_constructor(&m); 1016 dwarfstring_append_printf_u(&m, 1017 "DW_DLE_RNGLISTS_ERROR: rnglists table index of" 1018 " %u" ,attr_val); 1019 dwarfstring_append(&m, 1020 " is unusable unless it is in a tied file." 1021 " libdwarf is incomplete. FIXME"); 1022 _dwarf_error_string(dbg,error,DW_DLE_RNGLISTS_ERROR, 1023 dwarfstring_string(&m)); 1024 dwarfstring_destructor(&m); 1025 return DW_DLV_ERROR; 1026 } 1027 } else { 1028 offset_in_rnglists = attr_val; 1029 } 1030 res = _dwarf_which_rnglists_context(dbg,ctx, 1031 offset_in_rnglists, 1032 &rnglists_contextnum,error); 1033 if (res != DW_DLV_OK) { 1034 return res; 1035 } 1036 rctx = array[rnglists_contextnum]; 1037 table_base = rctx->rc_offsets_array; 1038 entrycount = rctx->rc_offset_entry_count; 1039 offsetsize = rctx->rc_offset_size; 1040 enddata = rctx->rc_endaddr; 1041 1042 if (is_rnglistx && attr_val >= entrycount) { 1043 dwarfstring m; 1044 1045 dwarfstring_constructor(&m); 1046 dwarfstring_append_printf_u(&m, 1047 "DW_DLE_RNGLISTS_ERROR: rnglists table index of" 1048 " %u" ,attr_val); 1049 dwarfstring_append_printf_u(&m, 1050 " too large for table of %u " 1051 "entries.",entrycount); 1052 _dwarf_error_string(dbg,error, 1053 DW_DLE_RNGLISTS_ERROR, 1054 dwarfstring_string(&m)); 1055 dwarfstring_destructor(&m); 1056 return DW_DLV_ERROR; 1057 } 1058 shead.rh_context = ctx; 1059 shead.rh_localcontext = rctx; 1060 shead.rh_index = rnglists_contextnum; 1061 shead.rh_version = rctx->rc_version; 1062 shead.rh_offset_size = offsetsize; 1063 shead.rh_address_size = rctx->rc_address_size; 1064 shead.rh_segment_selector_size = 1065 rctx->rc_segment_selector_size; 1066 1067 /* DW_AT_rnglists_base from CU */ 1068 shead.rh_at_rnglists_base_present = 1069 ctx->cc_rnglists_base_present; 1070 shead.rh_at_rnglists_base = ctx->cc_rnglists_base; 1071 1072 /* DW_AT_low_pc, if present. From CU */ 1073 shead.rh_cu_base_address_present = ctx->cc_low_pc_present; 1074 shead.rh_cu_base_address = ctx->cc_low_pc; 1075 1076 /* base address DW_AT_addr_base of our part of 1077 .debug_addr, from CU */ 1078 shead.rh_cu_addr_base = ctx->cc_addr_base; 1079 shead.rh_cu_addr_base_present = ctx->cc_addr_base_present; 1080 if (is_rnglistx) { 1081 Dwarf_Unsigned table_entryval = 0; 1082 1083 table_entry = attr_val*offsetsize + table_base; 1084 /* No malloc here yet so no leak if the macro returns 1085 DW_DLV_ERROR */ 1086 READ_UNALIGNED_CK(dbg,table_entryval, Dwarf_Unsigned, 1087 table_entry,offsetsize,error,enddata); 1088 rle_global_offset = rctx->rc_offsets_off_in_sect + 1089 table_entryval; 1090 } else { 1091 rle_global_offset = attr_val; 1092 } 1093 1094 shead.rh_rlepointer = rctx->rc_offsets_array + 1095 rctx->rc_offset_entry_count*offsetsize; 1096 shead.rh_end_data_area = enddata; 1097 1098 shead.rh_rlearea_offset = rle_global_offset; 1099 shead.rh_rlepointer = rle_global_offset + 1100 dbg->de_debug_rnglists.dss_data; 1101 lhead = (Dwarf_Rnglists_Head) 1102 _dwarf_get_alloc(dbg,DW_DLA_RNGLISTS_HEAD,1); 1103 if (!lhead) { 1104 _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL, 1105 "Allocating a Dwarf_Rnglists_Head struct fails" 1106 " in libdwarf function dwarf_rnglists_index_get_rle_head()"); 1107 return DW_DLV_ERROR; 1108 } 1109 shead.rh_dbg = dbg; 1110 *lhead = shead; 1111 res = build_array_of_rle(dbg,lhead,error); 1112 if (res != DW_DLV_OK) { 1113 dwarf_dealloc(dbg,lhead,DW_DLA_RNGLISTS_HEAD); 1114 return res; 1115 } 1116 if(global_offset_of_rle_set) { 1117 *global_offset_of_rle_set = rle_global_offset; 1118 } 1119 /* Caller needs the head pointer else there will be leaks. */ 1120 *head_out = lhead; 1121 if (entries_count_out) { 1122 *entries_count_out = lhead->rh_count; 1123 } 1124 return DW_DLV_OK; 1125 } 1126 1127 int 1128 dwarf_get_rnglists_entry_fields( 1129 Dwarf_Rnglists_Head head, 1130 Dwarf_Unsigned entrynum, 1131 unsigned *entrylen, 1132 unsigned *code, 1133 Dwarf_Unsigned *raw1, 1134 Dwarf_Unsigned *raw2, 1135 Dwarf_Unsigned *cooked1, 1136 Dwarf_Unsigned *cooked2, 1137 UNUSEDARG Dwarf_Error *err) 1138 { 1139 Dwarf_Rnglists_Entry e = 0; 1140 1141 if (entrynum >= head->rh_count) { 1142 return DW_DLV_NO_ENTRY; 1143 } 1144 e = head->rh_rnglists[entrynum]; 1145 *entrylen = e->rle_entrylen; 1146 *code = e->rle_code; 1147 *raw1 = e->rle_raw1; 1148 *raw2 = e->rle_raw2; 1149 *cooked1 = e->rle_cooked1; 1150 *cooked2 = e->rle_cooked2; 1151 return DW_DLV_OK; 1152 } 1153 1154 /* Deals with both fully and partially build head */ 1155 static void 1156 _dwarf_free_rnglists_head(Dwarf_Rnglists_Head head) 1157 { 1158 if (head->rh_first) { 1159 /* partially built head. */ 1160 /* ASSERT: rh_rnglists is NULL */ 1161 Dwarf_Rnglists_Entry cur = head->rh_first; 1162 Dwarf_Rnglists_Entry next = 0; 1163 1164 for ( ; cur ; cur = next) { 1165 next = cur->rle_next; 1166 free(cur); 1167 } 1168 head->rh_first = 0; 1169 head->rh_last = 0; 1170 head->rh_count = 0; 1171 } else { 1172 /* ASSERT: rh_first and rh_last are NULL */ 1173 /* fully built head. */ 1174 Dwarf_Unsigned i = 0; 1175 1176 /* Deal with the array form. */ 1177 for( ; i < head->rh_count; ++i) { 1178 free(head->rh_rnglists[i]); 1179 } 1180 free(head->rh_rnglists); 1181 head->rh_rnglists = 0; 1182 } 1183 } 1184 1185 void 1186 _dwarf_rnglists_head_destructor(void *head) 1187 { 1188 Dwarf_Rnglists_Head h = head; 1189 1190 _dwarf_free_rnglists_head(h); 1191 } 1192