]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/ia64/fde-glibc.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / ia64 / fde-glibc.c
CommitLineData
a945c346 1/* Copyright (C) 2000-2024 Free Software Foundation, Inc.
fee0225a
RH
2 Contributed by Richard Henderson <rth@cygnus.com>.
3
3bed2930 4 This file is part of GCC.
fee0225a 5
3bed2930 6 GCC is free software; you can redistribute it and/or modify
fee0225a 7 it under the terms of the GNU General Public License as published by
748086b7 8 the Free Software Foundation; either version 3, or (at your option)
fee0225a
RH
9 any later version.
10
3bed2930 11 GCC is distributed in the hope that it will be useful,
fee0225a
RH
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
748086b7
JJ
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
fee0225a
RH
24
25/* Locate the FDE entry for a given address, using glibc ld.so routines
26 to avoid register/deregister calls at DSO load/unload. */
27
a734f2a3 28#ifndef _GNU_SOURCE
634879c8 29#define _GNU_SOURCE 1
a734f2a3
JJ
30#endif
31#include "config.h"
cef03728 32#ifndef inhibit_libc
a734f2a3 33#include <stddef.h>
fee0225a
RH
34#include <stdlib.h>
35#include <link.h>
2a1ee410 36#include "unwind-ia64.h"
fee0225a 37
a734f2a3
JJ
38#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
39 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG))
40# error You need GLIBC 2.2.4 or later on IA-64 Linux
41#endif
fee0225a 42
a734f2a3
JJ
43struct unw_ia64_callback_data
44{
45 Elf64_Addr pc;
46 unsigned long *segment_base;
47 unsigned long *gp;
48 struct unw_table_entry *ret;
49};
fee0225a 50
a734f2a3
JJ
51static int
52_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
fee0225a 53{
a734f2a3
JJ
54 struct unw_ia64_callback_data *data = (struct unw_ia64_callback_data *) ptr;
55 const Elf64_Phdr *phdr, *p_unwind, *p_dynamic;
fee0225a
RH
56 long n, match;
57 Elf64_Addr load_base, seg_base;
2a1ee410 58 struct unw_table_entry *f_base, *f;
cd5c4048 59 size_t lo, hi;
fee0225a 60
a734f2a3
JJ
61 /* Make sure struct dl_phdr_info is at least as big as we need. */
62 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
63 + sizeof (info->dlpi_phnum))
64 return -1;
fee0225a
RH
65
66 match = 0;
a734f2a3
JJ
67 phdr = info->dlpi_phdr;
68 load_base = info->dlpi_addr;
fee0225a 69 p_unwind = NULL;
2a1ee410 70 p_dynamic = NULL;
a734f2a3 71 seg_base = ~(Elf64_Addr) 0;
fee0225a
RH
72
73 /* See if PC falls into one of the loaded segments. Find the unwind
74 segment at the same time. */
a734f2a3 75 for (n = info->dlpi_phnum; --n >= 0; phdr++)
fee0225a
RH
76 {
77 if (phdr->p_type == PT_LOAD)
78 {
79 Elf64_Addr vaddr = phdr->p_vaddr + load_base;
a734f2a3 80 if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
fee0225a 81 match = 1;
a734f2a3
JJ
82 if (vaddr < seg_base)
83 seg_base = vaddr;
fee0225a
RH
84 }
85 else if (phdr->p_type == PT_IA_64_UNWIND)
86 p_unwind = phdr;
2a1ee410
RH
87 else if (phdr->p_type == PT_DYNAMIC)
88 p_dynamic = phdr;
fee0225a
RH
89 }
90 if (!match || !p_unwind)
a734f2a3 91 return 0;
fee0225a
RH
92
93 /* Search for the FDE within the unwind segment. */
fee0225a 94
2a1ee410 95 f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base);
cd5c4048 96 lo = 0;
2a1ee410 97 hi = p_unwind->p_memsz / sizeof (struct unw_table_entry);
cd5c4048
RH
98
99 while (lo < hi)
100 {
101 size_t mid = (lo + hi) / 2;
cd5c4048 102
2a1ee410 103 f = f_base + mid;
a734f2a3 104 if (data->pc < f->start_offset + seg_base)
cd5c4048 105 hi = mid;
a734f2a3 106 else if (data->pc >= f->end_offset + seg_base)
cd5c4048
RH
107 lo = mid + 1;
108 else
2a1ee410 109 goto found;
cd5c4048 110 }
275b60d6
JJ
111 /* No need to search for further libraries when we know pc is contained
112 in this library. */
113 return 1;
2a1ee410
RH
114
115 found:
a734f2a3
JJ
116 *data->segment_base = seg_base;
117 *data->gp = 0;
118 data->ret = f;
2a1ee410
RH
119
120 if (p_dynamic)
121 {
9e4f94de 122 /* For dynamically linked executables and shared libraries,
2a1ee410
RH
123 DT_PLTGOT is the gp value for that object. */
124 Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base);
125 for (; dyn->d_tag != DT_NULL ; dyn++)
126 if (dyn->d_tag == DT_PLTGOT)
127 {
a734f2a3
JJ
128 /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */
129 *data->gp = dyn->d_un.d_ptr;
2a1ee410
RH
130 break;
131 }
132 }
133 else
134 {
135 /* Otherwise this is a static executable with no _DYNAMIC.
136 The gp is constant program-wide. */
137 register unsigned long gp __asm__("gp");
a734f2a3 138 *data->gp = gp;
2a1ee410
RH
139 }
140
a734f2a3 141 return 1;
fee0225a
RH
142}
143
2a1ee410
RH
144/* Return a pointer to the unwind table entry for the function
145 containing PC. */
146
147struct unw_table_entry *
9e916de7 148_Unwind_FindTableEntry (void *pc, unw_word *segment_base, unw_word *gp,
b874a90d 149 struct unw_table_entry *ent ATTRIBUTE_UNUSED)
fee0225a 150{
a734f2a3 151 struct unw_ia64_callback_data data;
fee0225a 152
a734f2a3
JJ
153 data.pc = (Elf64_Addr) pc;
154 data.segment_base = segment_base;
155 data.gp = gp;
156 data.ret = NULL;
fee0225a 157
a734f2a3
JJ
158 if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
159 return NULL;
fee0225a 160
a734f2a3 161 return data.ret;
fee0225a 162}
cef03728 163#endif