125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Manage address space lookup table for libdwfl. 203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Copyright (C) 2008, 2009, 2010, 2013 Red Hat, Inc. 303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes This file is part of elfutils. 425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes This file is free software; you can redistribute it and/or modify 603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes it under the terms of either 725b3c049e70834cf33790a28643ab058b507b35cBen Cheng 803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes * the GNU Lesser General Public License as published by the Free 903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Software Foundation; either version 3 of the License, or (at 1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes your option) any later version 1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes or 1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes * the GNU General Public License as published by the Free 1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes Software Foundation; either version 2 of the License, or (at 1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes your option) any later version 1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes or both in parallel, as here. 1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes 2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes elfutils is distributed in the hope that it will be useful, but 2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng WITHOUT ANY WARRANTY; without even the implied warranty of 2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng General Public License for more details. 2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes You should have received copies of the GNU General Public License and 2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes the GNU Lesser General Public License along with this program. If 2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes not, see <http://www.gnu.org/licenses/>. */ 2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "libdwflP.h" 3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 3103333823c75a1c1887e923828113a1b0fd12020cElliott HughesGElf_Addr 3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesinternal_function 3303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes__libdwfl_segment_start (Dwfl *dwfl, GElf_Addr start) 3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->segment_align > 1) 3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng start &= -dwfl->segment_align; 3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng return start; 3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng 4003333823c75a1c1887e923828113a1b0fd12020cElliott HughesGElf_Addr 4103333823c75a1c1887e923828113a1b0fd12020cElliott Hughesinternal_function 4203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes__libdwfl_segment_end (Dwfl *dwfl, GElf_Addr end) 4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->segment_align > 1) 4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng end = (end + dwfl->segment_align - 1) & -dwfl->segment_align; 4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return end; 4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 4925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool 5025b3c049e70834cf33790a28643ab058b507b35cBen Chenginsert (Dwfl *dwfl, size_t i, GElf_Addr start, GElf_Addr end, int segndx) 5125b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng bool need_start = (i == 0 || dwfl->lookup_addr[i - 1] != start); 5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng bool need_end = (i >= dwfl->lookup_elts || dwfl->lookup_addr[i + 1] != end); 5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng size_t need = need_start + need_end; 5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (need == 0) 5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return false; 5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng 5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->lookup_alloc - dwfl->lookup_elts < need) 5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 6025b3c049e70834cf33790a28643ab058b507b35cBen Cheng size_t n = dwfl->lookup_alloc == 0 ? 16 : dwfl->lookup_alloc * 2; 6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng GElf_Addr *naddr = realloc (dwfl->lookup_addr, sizeof naddr[0] * n); 6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (naddr == NULL)) 6325b3c049e70834cf33790a28643ab058b507b35cBen Cheng return true; 6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng int *nsegndx = realloc (dwfl->lookup_segndx, sizeof nsegndx[0] * n); 6525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (nsegndx == NULL)) 6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (naddr != dwfl->lookup_addr) 6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng free (naddr); 6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return true; 7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_alloc = n; 7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_addr = naddr; 7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_segndx = nsegndx; 7425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->lookup_module != NULL) 7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Make sure this array is big enough too. */ 7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng Dwfl_Module **old = dwfl->lookup_module; 7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_module = realloc (dwfl->lookup_module, 8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng sizeof dwfl->lookup_module[0] * n); 8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (dwfl->lookup_module == NULL)) 8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 8325b3c049e70834cf33790a28643ab058b507b35cBen Cheng free (old); 8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng return true; 8525b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 8625b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 8925b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (i < dwfl->lookup_elts)) 9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng const size_t move = dwfl->lookup_elts - i; 9225b3c049e70834cf33790a28643ab058b507b35cBen Cheng memmove (&dwfl->lookup_addr[i + need], &dwfl->lookup_addr[i], 9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng move * sizeof dwfl->lookup_addr[0]); 9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng memmove (&dwfl->lookup_segndx[i + need], &dwfl->lookup_segndx[i], 9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng move * sizeof dwfl->lookup_segndx[0]); 9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->lookup_module != NULL) 9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng memmove (&dwfl->lookup_module[i + need], &dwfl->lookup_module[i], 9825b3c049e70834cf33790a28643ab058b507b35cBen Cheng move * sizeof dwfl->lookup_module[0]); 9925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (need_start) 10225b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 10325b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_addr[i] = start; 10425b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_segndx[i] = segndx; 10525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->lookup_module != NULL) 10625b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_module[i] = NULL; 10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng ++i; 10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng else 11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_segndx[i - 1] = segndx; 11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (need_end) 11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_addr[i] = end; 11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_segndx[i] = -1; 11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->lookup_module != NULL) 11725b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_module[i] = NULL; 11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng 12025b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_elts += need; 12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng return false; 12325b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 12425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 12525b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int 12625b3c049e70834cf33790a28643ab058b507b35cBen Chenglookup (Dwfl *dwfl, GElf_Addr address, int hint) 12725b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (hint >= 0 12925b3c049e70834cf33790a28643ab058b507b35cBen Cheng && address >= dwfl->lookup_addr[hint] 13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng && ((size_t) hint + 1 == dwfl->lookup_elts 13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng || address < dwfl->lookup_addr[hint + 1])) 13225b3c049e70834cf33790a28643ab058b507b35cBen Cheng return hint; 13325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Do binary search on the array indexed by module load address. */ 13525b3c049e70834cf33790a28643ab058b507b35cBen Cheng size_t l = 0, u = dwfl->lookup_elts; 13625b3c049e70834cf33790a28643ab058b507b35cBen Cheng while (l < u) 13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng size_t idx = (l + u) / 2; 13925b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (address < dwfl->lookup_addr[idx]) 14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng u = idx; 14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng else 14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 14325b3c049e70834cf33790a28643ab058b507b35cBen Cheng l = idx + 1; 14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (l == dwfl->lookup_elts || address < dwfl->lookup_addr[l]) 14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng return idx; 14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -1; 15025b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 15225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool 15325b3c049e70834cf33790a28643ab058b507b35cBen Chengreify_segments (Dwfl *dwfl) 15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng int hint = -1; 15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng int highest = -1; 15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng bool fixup = false; 15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next) 15925b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (! mod->gc) 16025b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 16103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const GElf_Addr start = __libdwfl_segment_start (dwfl, mod->low_addr); 16203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes const GElf_Addr end = __libdwfl_segment_end (dwfl, mod->high_addr); 16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng bool resized = false; 16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng int idx = lookup (dwfl, start, hint); 16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (idx < 0)) 16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Module starts below any segment. Insert a low one. */ 16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (insert (dwfl, 0, start, end, -1))) 17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return true; 17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng idx = 0; 17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng resized = true; 17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 17425b3c049e70834cf33790a28643ab058b507b35cBen Cheng else if (dwfl->lookup_addr[idx] > start) 17525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* The module starts in the middle of this segment. Split it. */ 17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (insert (dwfl, idx + 1, start, end, 17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_segndx[idx]))) 17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return true; 18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng ++idx; 18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng resized = true; 18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng else if (dwfl->lookup_addr[idx] < start) 18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* The module starts past the end of this segment. 18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng Add a new one. */ 18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (insert (dwfl, idx + 1, start, end, -1))) 18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return true; 18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng ++idx; 19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng resized = true; 19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if ((size_t) idx + 1 < dwfl->lookup_elts 19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng && end < dwfl->lookup_addr[idx + 1]) 19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* The module ends in the middle of this segment. Split it. */ 19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (insert (dwfl, idx + 1, 19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng end, dwfl->lookup_addr[idx + 1], -1))) 19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng return true; 20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng resized = true; 20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->lookup_module == NULL) 20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_module = calloc (dwfl->lookup_alloc, 20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng sizeof dwfl->lookup_module[0]); 20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (dwfl->lookup_module == NULL)) 20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng return true; 20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Cache a backpointer in the module. */ 21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng mod->segment = idx; 21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Put MOD in the table for each segment that's inside it. */ 21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng do 21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_module[idx++] = mod; 21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng while ((size_t) idx < dwfl->lookup_elts 21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng && dwfl->lookup_addr[idx] < end); 21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng assert (dwfl->lookup_module[mod->segment] == mod); 22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (resized && idx - 1 >= highest) 22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Expanding the lookup tables invalidated backpointers 22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng we've already stored. Reset those ones. */ 22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng fixup = true; 22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng 22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng highest = idx - 1; 22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng hint = (size_t) idx < dwfl->lookup_elts ? idx : -1; 22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng 23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (fixup) 23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Reset backpointer indices invalidated by table insertions. */ 23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng for (size_t idx = 0; idx < dwfl->lookup_elts; ++idx) 23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl->lookup_module[idx] != NULL) 23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_module[idx]->segment = idx; 23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng 23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return false; 23725b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 23825b3c049e70834cf33790a28643ab058b507b35cBen Cheng 23925b3c049e70834cf33790a28643ab058b507b35cBen Chengint 24025b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_addrsegment (Dwfl *dwfl, Dwarf_Addr address, Dwfl_Module **mod) 24125b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 24225b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (dwfl == NULL)) 24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -1; 24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (dwfl->lookup_module == NULL) 24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng && mod != NULL 24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng && unlikely (reify_segments (dwfl))) 24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 24925b3c049e70834cf33790a28643ab058b507b35cBen Cheng __libdwfl_seterrno (DWFL_E_NOMEM); 25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -1; 25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng int idx = lookup (dwfl, address, -1); 25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (likely (mod != NULL)) 25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (idx < 0) || unlikely (dwfl->lookup_module == NULL)) 25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng *mod = NULL; 25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng else 25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng *mod = dwfl->lookup_module[idx]; 26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng 26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* If this segment does not have a module, but the address is 26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng the upper boundary of the previous segment's module, use that. */ 26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (*mod == NULL && idx > 0 && dwfl->lookup_addr[idx] == address) 26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng *mod = dwfl->lookup_module[idx - 1]; 26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (*mod != NULL && (*mod)->high_addr != address) 26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng *mod = NULL; 26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng 27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (likely (idx >= 0)) 27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Translate internal segment table index to user segment index. */ 27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng idx = dwfl->lookup_segndx[idx]; 27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng 27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng return idx; 27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 27925b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwfl_addrsegment) 28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 28125b3c049e70834cf33790a28643ab058b507b35cBen Chengint 28225b3c049e70834cf33790a28643ab058b507b35cBen Chengdwfl_report_segment (Dwfl *dwfl, int ndx, const GElf_Phdr *phdr, GElf_Addr bias, 28325b3c049e70834cf33790a28643ab058b507b35cBen Cheng const void *ident) 28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{ 28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (dwfl == NULL) 28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -1; 28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng 28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (ndx < 0) 28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng ndx = dwfl->lookup_tail_ndx; 29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 29125b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (phdr->p_align > 1 && (dwfl->segment_align <= 1 || 29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng phdr->p_align < dwfl->segment_align)) 29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->segment_align = phdr->p_align; 29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (dwfl->lookup_module != NULL)) 29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng free (dwfl->lookup_module); 29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_module = NULL; 29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng 30103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Addr start = __libdwfl_segment_start (dwfl, bias + phdr->p_vaddr); 30203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes GElf_Addr end = __libdwfl_segment_end (dwfl, 30303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes bias + phdr->p_vaddr + phdr->p_memsz); 30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Coalesce into the last one if contiguous and matching. */ 30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (ndx != dwfl->lookup_tail_ndx 30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng || ident == NULL 30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng || ident != dwfl->lookup_tail_ident 30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng || start != dwfl->lookup_tail_vaddr 31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng || phdr->p_offset != dwfl->lookup_tail_offset) 31125b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng /* Normally just appending keeps us sorted. */ 31325b3c049e70834cf33790a28643ab058b507b35cBen Cheng 31425b3c049e70834cf33790a28643ab058b507b35cBen Cheng size_t i = dwfl->lookup_elts; 31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng while (i > 0 && unlikely (start < dwfl->lookup_addr[i - 1])) 31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng --i; 31725b3c049e70834cf33790a28643ab058b507b35cBen Cheng 31825b3c049e70834cf33790a28643ab058b507b35cBen Cheng if (unlikely (insert (dwfl, i, start, end, ndx))) 31925b3c049e70834cf33790a28643ab058b507b35cBen Cheng { 32025b3c049e70834cf33790a28643ab058b507b35cBen Cheng __libdwfl_seterrno (DWFL_E_NOMEM); 32125b3c049e70834cf33790a28643ab058b507b35cBen Cheng return -1; 32225b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 32325b3c049e70834cf33790a28643ab058b507b35cBen Cheng } 32425b3c049e70834cf33790a28643ab058b507b35cBen Cheng 32525b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_tail_ident = ident; 32625b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_tail_vaddr = end; 32725b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_tail_offset = end - bias - phdr->p_vaddr + phdr->p_offset; 32825b3c049e70834cf33790a28643ab058b507b35cBen Cheng dwfl->lookup_tail_ndx = ndx + 1; 32925b3c049e70834cf33790a28643ab058b507b35cBen Cheng 33025b3c049e70834cf33790a28643ab058b507b35cBen Cheng return ndx; 33125b3c049e70834cf33790a28643ab058b507b35cBen Cheng} 33225b3c049e70834cf33790a28643ab058b507b35cBen ChengINTDEF (dwfl_report_segment) 333