1da0c48c4Sopenharmony_ci/* Return list address ranges. 2da0c48c4Sopenharmony_ci Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2000. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of either 8da0c48c4Sopenharmony_ci 9da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 10da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 11da0c48c4Sopenharmony_ci your option) any later version 12da0c48c4Sopenharmony_ci 13da0c48c4Sopenharmony_ci or 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 16da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 17da0c48c4Sopenharmony_ci your option) any later version 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci or both in parallel, as here. 20da0c48c4Sopenharmony_ci 21da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 22da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 23da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24da0c48c4Sopenharmony_ci General Public License for more details. 25da0c48c4Sopenharmony_ci 26da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 27da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 28da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 29da0c48c4Sopenharmony_ci 30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 31da0c48c4Sopenharmony_ci# include <config.h> 32da0c48c4Sopenharmony_ci#endif 33da0c48c4Sopenharmony_ci 34da0c48c4Sopenharmony_ci#include <stdlib.h> 35da0c48c4Sopenharmony_ci#include <assert.h> 36da0c48c4Sopenharmony_ci#include "libdwP.h" 37da0c48c4Sopenharmony_ci#include <dwarf.h> 38da0c48c4Sopenharmony_ci 39da0c48c4Sopenharmony_cistruct arangelist 40da0c48c4Sopenharmony_ci{ 41da0c48c4Sopenharmony_ci Dwarf_Arange arange; 42da0c48c4Sopenharmony_ci struct arangelist *next; 43da0c48c4Sopenharmony_ci}; 44da0c48c4Sopenharmony_ci 45da0c48c4Sopenharmony_ci/* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers. */ 46da0c48c4Sopenharmony_cistatic int 47da0c48c4Sopenharmony_cicompare_aranges (const void *a, const void *b) 48da0c48c4Sopenharmony_ci{ 49da0c48c4Sopenharmony_ci struct arangelist *const *p1 = a, *const *p2 = b; 50da0c48c4Sopenharmony_ci struct arangelist *l1 = *p1, *l2 = *p2; 51da0c48c4Sopenharmony_ci if (l1->arange.addr != l2->arange.addr) 52da0c48c4Sopenharmony_ci return (l1->arange.addr < l2->arange.addr) ? -1 : 1; 53da0c48c4Sopenharmony_ci return 0; 54da0c48c4Sopenharmony_ci} 55da0c48c4Sopenharmony_ci 56da0c48c4Sopenharmony_ciint 57da0c48c4Sopenharmony_cidwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges) 58da0c48c4Sopenharmony_ci{ 59da0c48c4Sopenharmony_ci if (dbg == NULL) 60da0c48c4Sopenharmony_ci return -1; 61da0c48c4Sopenharmony_ci 62da0c48c4Sopenharmony_ci if (dbg->aranges != NULL) 63da0c48c4Sopenharmony_ci { 64da0c48c4Sopenharmony_ci *aranges = dbg->aranges; 65da0c48c4Sopenharmony_ci if (naranges != NULL) 66da0c48c4Sopenharmony_ci *naranges = dbg->aranges->naranges; 67da0c48c4Sopenharmony_ci return 0; 68da0c48c4Sopenharmony_ci } 69da0c48c4Sopenharmony_ci 70da0c48c4Sopenharmony_ci if (dbg->sectiondata[IDX_debug_aranges] == NULL) 71da0c48c4Sopenharmony_ci { 72da0c48c4Sopenharmony_ci /* No such section. */ 73da0c48c4Sopenharmony_ci *aranges = NULL; 74da0c48c4Sopenharmony_ci if (naranges != NULL) 75da0c48c4Sopenharmony_ci *naranges = 0; 76da0c48c4Sopenharmony_ci return 0; 77da0c48c4Sopenharmony_ci } 78da0c48c4Sopenharmony_ci 79da0c48c4Sopenharmony_ci if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL) 80da0c48c4Sopenharmony_ci return -1; 81da0c48c4Sopenharmony_ci 82da0c48c4Sopenharmony_ci struct arangelist *arangelist = NULL; 83da0c48c4Sopenharmony_ci unsigned int narangelist = 0; 84da0c48c4Sopenharmony_ci 85da0c48c4Sopenharmony_ci const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf; 86da0c48c4Sopenharmony_ci const unsigned char *readendp 87da0c48c4Sopenharmony_ci = readp + dbg->sectiondata[IDX_debug_aranges]->d_size; 88da0c48c4Sopenharmony_ci 89da0c48c4Sopenharmony_ci while (readp < readendp) 90da0c48c4Sopenharmony_ci { 91da0c48c4Sopenharmony_ci const unsigned char *hdrstart = readp; 92da0c48c4Sopenharmony_ci 93da0c48c4Sopenharmony_ci /* Each entry starts with a header: 94da0c48c4Sopenharmony_ci 95da0c48c4Sopenharmony_ci 1. A 4-byte or 12-byte length containing the length of the 96da0c48c4Sopenharmony_ci set of entries for this compilation unit, not including the 97da0c48c4Sopenharmony_ci length field itself. [...] 98da0c48c4Sopenharmony_ci 99da0c48c4Sopenharmony_ci 2. A 2-byte version identifier containing the value 2 for 100da0c48c4Sopenharmony_ci DWARF Version 2.1. 101da0c48c4Sopenharmony_ci 102da0c48c4Sopenharmony_ci 3. A 4-byte or 8-byte offset into the .debug_info section. [...] 103da0c48c4Sopenharmony_ci 104da0c48c4Sopenharmony_ci 4. A 1-byte unsigned integer containing the size in bytes of 105da0c48c4Sopenharmony_ci an address (or the offset portion of an address for segmented 106da0c48c4Sopenharmony_ci addressing) on the target system. 107da0c48c4Sopenharmony_ci 108da0c48c4Sopenharmony_ci 5. A 1-byte unsigned integer containing the size in bytes of 109da0c48c4Sopenharmony_ci a segment descriptor on the target system. */ 110da0c48c4Sopenharmony_ci if (unlikely (readp + 4 > readendp)) 111da0c48c4Sopenharmony_ci goto invalid; 112da0c48c4Sopenharmony_ci 113da0c48c4Sopenharmony_ci Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp); 114da0c48c4Sopenharmony_ci unsigned int length_bytes = 4; 115da0c48c4Sopenharmony_ci if (length == DWARF3_LENGTH_64_BIT) 116da0c48c4Sopenharmony_ci { 117da0c48c4Sopenharmony_ci if (unlikely (readp + 8 > readendp)) 118da0c48c4Sopenharmony_ci goto invalid; 119da0c48c4Sopenharmony_ci 120da0c48c4Sopenharmony_ci length = read_8ubyte_unaligned_inc (dbg, readp); 121da0c48c4Sopenharmony_ci length_bytes = 8; 122da0c48c4Sopenharmony_ci } 123da0c48c4Sopenharmony_ci else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE 124da0c48c4Sopenharmony_ci && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE)) 125da0c48c4Sopenharmony_ci goto invalid; 126da0c48c4Sopenharmony_ci 127da0c48c4Sopenharmony_ci if (unlikely (readp + 2 > readendp)) 128da0c48c4Sopenharmony_ci goto invalid; 129da0c48c4Sopenharmony_ci 130da0c48c4Sopenharmony_ci unsigned int version = read_2ubyte_unaligned_inc (dbg, readp); 131da0c48c4Sopenharmony_ci if (version != 2) 132da0c48c4Sopenharmony_ci { 133da0c48c4Sopenharmony_ci invalid: 134da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_INVALID_DWARF); 135da0c48c4Sopenharmony_ci fail: 136da0c48c4Sopenharmony_ci while (arangelist != NULL) 137da0c48c4Sopenharmony_ci { 138da0c48c4Sopenharmony_ci struct arangelist *next = arangelist->next; 139da0c48c4Sopenharmony_ci free (arangelist); 140da0c48c4Sopenharmony_ci arangelist = next; 141da0c48c4Sopenharmony_ci } 142da0c48c4Sopenharmony_ci return -1; 143da0c48c4Sopenharmony_ci } 144da0c48c4Sopenharmony_ci 145da0c48c4Sopenharmony_ci Dwarf_Word offset = 0; 146da0c48c4Sopenharmony_ci if (__libdw_read_offset_inc (dbg, 147da0c48c4Sopenharmony_ci IDX_debug_aranges, &readp, 148da0c48c4Sopenharmony_ci length_bytes, &offset, IDX_debug_info, 4)) 149da0c48c4Sopenharmony_ci goto fail; 150da0c48c4Sopenharmony_ci 151da0c48c4Sopenharmony_ci /* Next up two bytes for address and segment size. */ 152da0c48c4Sopenharmony_ci if (readp + 2 > readendp) 153da0c48c4Sopenharmony_ci goto invalid; 154da0c48c4Sopenharmony_ci 155da0c48c4Sopenharmony_ci unsigned int address_size = *readp++; 156da0c48c4Sopenharmony_ci if (unlikely (address_size != 4 && address_size != 8)) 157da0c48c4Sopenharmony_ci goto invalid; 158da0c48c4Sopenharmony_ci 159da0c48c4Sopenharmony_ci /* We don't actually support segment selectors. */ 160da0c48c4Sopenharmony_ci unsigned int segment_size = *readp++; 161da0c48c4Sopenharmony_ci if (segment_size != 0) 162da0c48c4Sopenharmony_ci goto invalid; 163da0c48c4Sopenharmony_ci 164da0c48c4Sopenharmony_ci /* Round the address to the next multiple of 2*address_size. */ 165da0c48c4Sopenharmony_ci readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size))) 166da0c48c4Sopenharmony_ci % (2 * address_size)); 167da0c48c4Sopenharmony_ci 168da0c48c4Sopenharmony_ci while (1) 169da0c48c4Sopenharmony_ci { 170da0c48c4Sopenharmony_ci Dwarf_Word range_address; 171da0c48c4Sopenharmony_ci Dwarf_Word range_length; 172da0c48c4Sopenharmony_ci 173da0c48c4Sopenharmony_ci if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp, 174da0c48c4Sopenharmony_ci address_size, &range_address)) 175da0c48c4Sopenharmony_ci goto fail; 176da0c48c4Sopenharmony_ci 177da0c48c4Sopenharmony_ci if (readp + address_size > readendp) 178da0c48c4Sopenharmony_ci goto invalid; 179da0c48c4Sopenharmony_ci 180da0c48c4Sopenharmony_ci if (address_size == 4) 181da0c48c4Sopenharmony_ci range_length = read_4ubyte_unaligned_inc (dbg, readp); 182da0c48c4Sopenharmony_ci else 183da0c48c4Sopenharmony_ci range_length = read_8ubyte_unaligned_inc (dbg, readp); 184da0c48c4Sopenharmony_ci 185da0c48c4Sopenharmony_ci /* Two zero values mark the end. */ 186da0c48c4Sopenharmony_ci if (range_address == 0 && range_length == 0) 187da0c48c4Sopenharmony_ci break; 188da0c48c4Sopenharmony_ci 189da0c48c4Sopenharmony_ci /* We don't use alloca for these temporary structures because 190da0c48c4Sopenharmony_ci the total number of them can be quite large. */ 191da0c48c4Sopenharmony_ci struct arangelist *new_arange = malloc (sizeof *new_arange); 192da0c48c4Sopenharmony_ci if (unlikely (new_arange == NULL)) 193da0c48c4Sopenharmony_ci { 194da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_NOMEM); 195da0c48c4Sopenharmony_ci goto fail; 196da0c48c4Sopenharmony_ci } 197da0c48c4Sopenharmony_ci 198da0c48c4Sopenharmony_ci new_arange->arange.addr = range_address; 199da0c48c4Sopenharmony_ci new_arange->arange.length = range_length; 200da0c48c4Sopenharmony_ci 201da0c48c4Sopenharmony_ci /* We store the actual CU DIE offset, not the CU header offset. */ 202da0c48c4Sopenharmony_ci Dwarf_CU *cu = __libdw_findcu (dbg, offset, false); 203da0c48c4Sopenharmony_ci if (unlikely (cu == NULL)) 204da0c48c4Sopenharmony_ci { 205da0c48c4Sopenharmony_ci /* We haven't gotten a chance to link in the new_arange 206da0c48c4Sopenharmony_ci into the arangelist, don't leak it. */ 207da0c48c4Sopenharmony_ci free (new_arange); 208da0c48c4Sopenharmony_ci goto fail; 209da0c48c4Sopenharmony_ci } 210da0c48c4Sopenharmony_ci new_arange->arange.offset = __libdw_first_die_off_from_cu (cu); 211da0c48c4Sopenharmony_ci 212da0c48c4Sopenharmony_ci new_arange->next = arangelist; 213da0c48c4Sopenharmony_ci arangelist = new_arange; 214da0c48c4Sopenharmony_ci ++narangelist; 215da0c48c4Sopenharmony_ci 216da0c48c4Sopenharmony_ci /* Sanity-check the data. */ 217da0c48c4Sopenharmony_ci if (unlikely (new_arange->arange.offset 218da0c48c4Sopenharmony_ci >= dbg->sectiondata[IDX_debug_info]->d_size)) 219da0c48c4Sopenharmony_ci goto invalid; 220da0c48c4Sopenharmony_ci } 221da0c48c4Sopenharmony_ci } 222da0c48c4Sopenharmony_ci 223da0c48c4Sopenharmony_ci if (narangelist == 0) 224da0c48c4Sopenharmony_ci { 225da0c48c4Sopenharmony_ci assert (arangelist == NULL); 226da0c48c4Sopenharmony_ci if (naranges != NULL) 227da0c48c4Sopenharmony_ci *naranges = 0; 228da0c48c4Sopenharmony_ci *aranges = NULL; 229da0c48c4Sopenharmony_ci return 0; 230da0c48c4Sopenharmony_ci } 231da0c48c4Sopenharmony_ci 232da0c48c4Sopenharmony_ci /* Allocate the array for the result. */ 233da0c48c4Sopenharmony_ci void *buf = libdw_alloc (dbg, Dwarf_Aranges, 234da0c48c4Sopenharmony_ci sizeof (Dwarf_Aranges) 235da0c48c4Sopenharmony_ci + narangelist * sizeof (Dwarf_Arange), 1); 236da0c48c4Sopenharmony_ci 237da0c48c4Sopenharmony_ci /* First use the buffer for the pointers, and sort the entries. 238da0c48c4Sopenharmony_ci We'll write the pointers in the end of the buffer, and then 239da0c48c4Sopenharmony_ci copy into the buffer from the beginning so the overlap works. */ 240da0c48c4Sopenharmony_ci assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *)); 241da0c48c4Sopenharmony_ci struct arangelist **sortaranges 242da0c48c4Sopenharmony_ci = (buf + sizeof (Dwarf_Aranges) 243da0c48c4Sopenharmony_ci + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist)); 244da0c48c4Sopenharmony_ci 245da0c48c4Sopenharmony_ci /* The list is in LIFO order and usually they come in clumps with 246da0c48c4Sopenharmony_ci ascending addresses. So fill from the back to probably start with 247da0c48c4Sopenharmony_ci runs already in order before we sort. */ 248da0c48c4Sopenharmony_ci unsigned int i = narangelist; 249da0c48c4Sopenharmony_ci while (i-- > 0) 250da0c48c4Sopenharmony_ci { 251da0c48c4Sopenharmony_ci sortaranges[i] = arangelist; 252da0c48c4Sopenharmony_ci arangelist = arangelist->next; 253da0c48c4Sopenharmony_ci } 254da0c48c4Sopenharmony_ci assert (arangelist == NULL); 255da0c48c4Sopenharmony_ci 256da0c48c4Sopenharmony_ci /* Sort by ascending address. */ 257da0c48c4Sopenharmony_ci qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges); 258da0c48c4Sopenharmony_ci 259da0c48c4Sopenharmony_ci /* Now that they are sorted, put them in the final array. 260da0c48c4Sopenharmony_ci The buffers overlap, so we've clobbered the early elements 261da0c48c4Sopenharmony_ci of SORTARANGES by the time we're reading the later ones. */ 262da0c48c4Sopenharmony_ci *aranges = buf; 263da0c48c4Sopenharmony_ci (*aranges)->dbg = dbg; 264da0c48c4Sopenharmony_ci (*aranges)->naranges = narangelist; 265da0c48c4Sopenharmony_ci dbg->aranges = *aranges; 266da0c48c4Sopenharmony_ci if (naranges != NULL) 267da0c48c4Sopenharmony_ci *naranges = narangelist; 268da0c48c4Sopenharmony_ci for (i = 0; i < narangelist; ++i) 269da0c48c4Sopenharmony_ci { 270da0c48c4Sopenharmony_ci struct arangelist *elt = sortaranges[i]; 271da0c48c4Sopenharmony_ci (*aranges)->info[i] = elt->arange; 272da0c48c4Sopenharmony_ci free (elt); 273da0c48c4Sopenharmony_ci } 274da0c48c4Sopenharmony_ci 275da0c48c4Sopenharmony_ci return 0; 276da0c48c4Sopenharmony_ci} 277da0c48c4Sopenharmony_ciINTDEF(dwarf_getaranges) 278