blob: 3aead1714f9d1e10422d68782d0863f6adcc1e90 [file] [log] [blame]
Jakub Jelinek99dee822021-01-04 10:26:59 +01001/* Copyright (C) 2000-2021 Free Software Foundation, Inc.
Richard Hendersonfee02252000-10-03 20:08:50 -07002 Contributed by Richard Henderson <rth@cygnus.com>.
3
Nathanael Nerode3bed2932003-03-13 18:26:30 +00004 This file is part of GCC.
Richard Hendersonfee02252000-10-03 20:08:50 -07005
Nathanael Nerode3bed2932003-03-13 18:26:30 +00006 GCC is free software; you can redistribute it and/or modify
Richard Hendersonfee02252000-10-03 20:08:50 -07007 it under the terms of the GNU General Public License as published by
Jakub Jelinek748086b2009-04-09 17:00:19 +02008 the Free Software Foundation; either version 3, or (at your option)
Richard Hendersonfee02252000-10-03 20:08:50 -07009 any later version.
10
Nathanael Nerode3bed2932003-03-13 18:26:30 +000011 GCC is distributed in the hope that it will be useful,
Richard Hendersonfee02252000-10-03 20:08:50 -070012 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
Jakub Jelinek748086b2009-04-09 17:00:19 +020016 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.
Richard Hendersonfee02252000-10-03 20:08:50 -070019
Jakub Jelinek748086b2009-04-09 17:00:19 +020020 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/>. */
Richard Hendersonfee02252000-10-03 20:08:50 -070024
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
Jakub Jelineka734f2a2001-08-09 18:22:23 +020028#ifndef _GNU_SOURCE
Andreas Schwab634879c2003-11-02 17:35:20 +000029#define _GNU_SOURCE 1
Jakub Jelineka734f2a2001-08-09 18:22:23 +020030#endif
31#include "config.h"
32#include <stddef.h>
Richard Hendersonfee02252000-10-03 20:08:50 -070033#include <stdlib.h>
34#include <link.h>
Richard Henderson2a1ee412001-05-11 23:03:20 -070035#include "unwind-ia64.h"
Richard Hendersonfee02252000-10-03 20:08:50 -070036
Jakub Jelineka734f2a2001-08-09 18:22:23 +020037#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
38 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG))
39# error You need GLIBC 2.2.4 or later on IA-64 Linux
40#endif
Richard Hendersonfee02252000-10-03 20:08:50 -070041
Jakub Jelineka734f2a2001-08-09 18:22:23 +020042struct unw_ia64_callback_data
Richard Hendersonfee02252000-10-03 20:08:50 -070043{
Jakub Jelineka734f2a2001-08-09 18:22:23 +020044 Elf64_Addr pc;
45 unsigned long *segment_base;
46 unsigned long *gp;
47 struct unw_table_entry *ret;
48};
49
50static int
51_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
52{
53 struct unw_ia64_callback_data *data = (struct unw_ia64_callback_data *) ptr;
54 const Elf64_Phdr *phdr, *p_unwind, *p_dynamic;
Richard Hendersonfee02252000-10-03 20:08:50 -070055 long n, match;
56 Elf64_Addr load_base, seg_base;
Richard Henderson2a1ee412001-05-11 23:03:20 -070057 struct unw_table_entry *f_base, *f;
Richard Hendersoncd5c4042000-11-07 17:59:35 -080058 size_t lo, hi;
Richard Hendersonfee02252000-10-03 20:08:50 -070059
Jakub Jelineka734f2a2001-08-09 18:22:23 +020060 /* Make sure struct dl_phdr_info is at least as big as we need. */
61 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
62 + sizeof (info->dlpi_phnum))
63 return -1;
Richard Hendersonfee02252000-10-03 20:08:50 -070064
65 match = 0;
Jakub Jelineka734f2a2001-08-09 18:22:23 +020066 phdr = info->dlpi_phdr;
67 load_base = info->dlpi_addr;
Richard Hendersonfee02252000-10-03 20:08:50 -070068 p_unwind = NULL;
Richard Henderson2a1ee412001-05-11 23:03:20 -070069 p_dynamic = NULL;
Jakub Jelineka734f2a2001-08-09 18:22:23 +020070 seg_base = ~(Elf64_Addr) 0;
Richard Hendersonfee02252000-10-03 20:08:50 -070071
72 /* See if PC falls into one of the loaded segments. Find the unwind
73 segment at the same time. */
Jakub Jelineka734f2a2001-08-09 18:22:23 +020074 for (n = info->dlpi_phnum; --n >= 0; phdr++)
Richard Hendersonfee02252000-10-03 20:08:50 -070075 {
76 if (phdr->p_type == PT_LOAD)
77 {
78 Elf64_Addr vaddr = phdr->p_vaddr + load_base;
Jakub Jelineka734f2a2001-08-09 18:22:23 +020079 if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
Richard Hendersonfee02252000-10-03 20:08:50 -070080 match = 1;
Jakub Jelineka734f2a2001-08-09 18:22:23 +020081 if (vaddr < seg_base)
82 seg_base = vaddr;
Richard Hendersonfee02252000-10-03 20:08:50 -070083 }
84 else if (phdr->p_type == PT_IA_64_UNWIND)
85 p_unwind = phdr;
Richard Henderson2a1ee412001-05-11 23:03:20 -070086 else if (phdr->p_type == PT_DYNAMIC)
87 p_dynamic = phdr;
Richard Hendersonfee02252000-10-03 20:08:50 -070088 }
89 if (!match || !p_unwind)
Jakub Jelineka734f2a2001-08-09 18:22:23 +020090 return 0;
Richard Hendersonfee02252000-10-03 20:08:50 -070091
92 /* Search for the FDE within the unwind segment. */
Richard Hendersonfee02252000-10-03 20:08:50 -070093
Richard Henderson2a1ee412001-05-11 23:03:20 -070094 f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base);
Richard Hendersoncd5c4042000-11-07 17:59:35 -080095 lo = 0;
Richard Henderson2a1ee412001-05-11 23:03:20 -070096 hi = p_unwind->p_memsz / sizeof (struct unw_table_entry);
Richard Hendersoncd5c4042000-11-07 17:59:35 -080097
98 while (lo < hi)
99 {
100 size_t mid = (lo + hi) / 2;
Richard Hendersoncd5c4042000-11-07 17:59:35 -0800101
Richard Henderson2a1ee412001-05-11 23:03:20 -0700102 f = f_base + mid;
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200103 if (data->pc < f->start_offset + seg_base)
Richard Hendersoncd5c4042000-11-07 17:59:35 -0800104 hi = mid;
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200105 else if (data->pc >= f->end_offset + seg_base)
Richard Hendersoncd5c4042000-11-07 17:59:35 -0800106 lo = mid + 1;
107 else
Richard Henderson2a1ee412001-05-11 23:03:20 -0700108 goto found;
109 }
Jakub Jelinek275b60d2001-12-15 12:49:18 +0100110 /* No need to search for further libraries when we know pc is contained
111 in this library. */
112 return 1;
Richard Henderson2a1ee412001-05-11 23:03:20 -0700113
114 found:
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200115 *data->segment_base = seg_base;
116 *data->gp = 0;
117 data->ret = f;
Richard Henderson2a1ee412001-05-11 23:03:20 -0700118
119 if (p_dynamic)
120 {
Kazu Hirata9e4f94de2003-01-26 20:15:36 +0000121 /* For dynamically linked executables and shared libraries,
Richard Henderson2a1ee412001-05-11 23:03:20 -0700122 DT_PLTGOT is the gp value for that object. */
123 Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base);
124 for (; dyn->d_tag != DT_NULL ; dyn++)
125 if (dyn->d_tag == DT_PLTGOT)
126 {
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200127 /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */
128 *data->gp = dyn->d_un.d_ptr;
Richard Henderson2a1ee412001-05-11 23:03:20 -0700129 break;
130 }
131 }
132 else
133 {
134 /* Otherwise this is a static executable with no _DYNAMIC.
135 The gp is constant program-wide. */
136 register unsigned long gp __asm__("gp");
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200137 *data->gp = gp;
Richard Hendersoncd5c4042000-11-07 17:59:35 -0800138 }
Richard Hendersonfee02252000-10-03 20:08:50 -0700139
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200140 return 1;
Richard Hendersonfee02252000-10-03 20:08:50 -0700141}
142
Richard Henderson2a1ee412001-05-11 23:03:20 -0700143/* Return a pointer to the unwind table entry for the function
144 containing PC. */
145
146struct unw_table_entry *
Tristan Gingold9e916de2012-03-27 09:50:10 +0000147_Unwind_FindTableEntry (void *pc, unw_word *segment_base, unw_word *gp,
Douglas B Ruppb874a902009-08-14 20:56:31 +0000148 struct unw_table_entry *ent ATTRIBUTE_UNUSED)
Richard Hendersonfee02252000-10-03 20:08:50 -0700149{
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200150 struct unw_ia64_callback_data data;
Richard Hendersonfee02252000-10-03 20:08:50 -0700151
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200152 data.pc = (Elf64_Addr) pc;
153 data.segment_base = segment_base;
154 data.gp = gp;
155 data.ret = NULL;
Richard Hendersonfee02252000-10-03 20:08:50 -0700156
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200157 if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
158 return NULL;
Richard Hendersonfee02252000-10-03 20:08:50 -0700159
Jakub Jelineka734f2a2001-08-09 18:22:23 +0200160 return data.ret;
Richard Hendersonfee02252000-10-03 20:08:50 -0700161}