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