xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_rnglists.c (revision 28ab0ca48b3e331cbbb231b1c8325f9f24f9af95)
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