1/* Copyright (C) 2001-2022 Free Software Foundation, Inc.
2
3   This file is part of GCC.
4
5   GCC is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3, or (at your option)
8   any later version.
9
10   GCC is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   Under Section 7 of GPL version 3, you are granted additional
16   permissions described in the GCC Runtime Library Exception, version
17   3.1, as published by the Free Software Foundation.
18
19   You should have received a copy of the GNU General Public License and
20   a copy of the GCC Runtime Library Exception along with this program;
21   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22   <http://www.gnu.org/licenses/>.  */
23
24/* Locate the FDE entry for a given address, using Darwin's keymgr support.  */
25
26#include "tconfig.h"
27#include "tsystem.h"
28#include <string.h>
29#include <stdlib.h>
30#include "dwarf2.h"
31#include "unwind.h"
32#define NO_BASE_OF_ENCODED_VALUE
33#define DWARF2_OBJECT_END_PTR_EXTENSION
34#include "unwind-pe.h"
35#include "unwind-dw2-fde.h"
36/* Carefully don't include gthr.h.  */
37
38typedef int __gthread_mutex_t;
39#define __gthread_mutex_lock(x)  (void)(x)
40#define __gthread_mutex_unlock(x) (void)(x)
41
42static const fde * _Unwind_Find_registered_FDE (void *pc,
43						struct dwarf_eh_bases *bases);
44
45#define _Unwind_Find_FDE _Unwind_Find_registered_FDE
46#include "unwind-dw2-fde.c"
47#undef _Unwind_Find_FDE
48
49/* KeyMgr stuff.  */
50#define KEYMGR_GCC3_LIVE_IMAGE_LIST     301     /* loaded images  */
51#define KEYMGR_GCC3_DW2_OBJ_LIST        302     /* Dwarf2 object list  */
52
53extern void *_keymgr_get_and_lock_processwide_ptr (int);
54extern void _keymgr_set_and_unlock_processwide_ptr (int, void *);
55extern void _keymgr_unlock_processwide_ptr (int);
56
57struct mach_header;
58struct mach_header_64;
59extern char *getsectdatafromheader (struct mach_header*, const char*,
60				    const char *, unsigned long *);
61extern char *getsectdatafromheader_64 (struct mach_header_64*, const char*,
62				       const char *, unsigned long *);
63
64/* This is referenced from KEYMGR_GCC3_DW2_OBJ_LIST.  */
65struct km_object_info {
66  struct object *seen_objects;
67  struct object *unseen_objects;
68  unsigned spare[2];
69};
70
71/* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST.  Info about each resident image.  */
72struct live_images {
73  unsigned long this_size;                      /* sizeof (live_images)  */
74  struct mach_header *mh;                       /* the image info  */
75  unsigned long vm_slide;
76  void (*destructor)(struct live_images *);     /* destructor for this  */
77  struct live_images *next;
78  unsigned int examined_p;
79  void *fde;
80  void *object_info;
81  unsigned long info[2];                        /* Future use.  */
82};
83
84/* Bits in the examined_p field of struct live_images.  */
85enum {
86  EXAMINED_IMAGE_MASK = 1,	/* We've seen this one.  */
87  ALLOCED_IMAGE_MASK = 2,	/* The FDE entries were allocated by
88				   malloc, and must be freed.  This isn't
89				   used by newer libgcc versions.  */
90  IMAGE_IS_TEXT_MASK = 4,	/* This image is in the TEXT segment.  */
91  DESTRUCTOR_MAY_BE_CALLED_LIVE = 8  /* The destructor may be called on an
92					object that's part of the live
93					image list.  */
94};
95
96/* Delete any data we allocated on a live_images structure.  Either
97   IMAGE has already been removed from the
98   KEYMGR_GCC3_LIVE_IMAGE_LIST and the struct will be deleted
99   after we return, or that list is locked and we're being called
100   because this object might be about to be unloaded.  Called by
101   KeyMgr.  */
102
103static void
104live_image_destructor (struct live_images *image)
105{
106  if (image->object_info)
107    {
108      struct km_object_info *the_obj_info;
109
110      the_obj_info =
111	_keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST);
112      if (the_obj_info)
113	{
114	  seen_objects = the_obj_info->seen_objects;
115	  unseen_objects = the_obj_info->unseen_objects;
116
117	  /* Free any sorted arrays.  */
118	  __deregister_frame_info_bases (image->fde);
119
120	  the_obj_info->seen_objects = seen_objects;
121	  the_obj_info->unseen_objects = unseen_objects;
122	}
123      _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST,
124					      the_obj_info);
125
126      free (image->object_info);
127      image->object_info = NULL;
128      if (image->examined_p & ALLOCED_IMAGE_MASK)
129	free (image->fde);
130      image->fde = NULL;
131    }
132  image->examined_p = 0;
133  image->destructor = NULL;
134}
135
136/* Run through the list of live images.  If we can allocate memory,
137   give each unseen image a new `struct object'.  Even if we can't,
138   check whether the PC is inside the FDE of each unseen image.
139 */
140
141static inline const fde *
142examine_objects (void *pc, struct dwarf_eh_bases *bases, int dont_alloc)
143{
144  const fde *result = NULL;
145  struct live_images *image;
146
147  image = _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST);
148
149  for (; image != NULL; image = image->next)
150    if ((image->examined_p & EXAMINED_IMAGE_MASK) == 0)
151      {
152	char *fde = NULL;
153	unsigned long sz;
154
155	/* For ppc only check whether or not we have __DATA eh frames.  */
156#ifdef __ppc__
157	fde = getsectdatafromheader (image->mh, "__DATA", "__eh_frame", &sz);
158#endif
159
160	if (fde == NULL)
161	  {
162#if __LP64__
163	    fde = getsectdatafromheader_64 ((struct mach_header_64 *) image->mh,
164					    "__TEXT", "__eh_frame", &sz);
165#else
166	    fde = getsectdatafromheader (image->mh, "__TEXT",
167					 "__eh_frame", &sz);
168#endif
169	    if (fde != NULL)
170	      image->examined_p |= IMAGE_IS_TEXT_MASK;
171	  }
172
173	/* If .eh_frame is empty, don't register at all.  */
174	if (fde != NULL && sz > 0)
175	  {
176	    char *real_fde = (fde + image->vm_slide);
177	    struct object *ob = NULL;
178	    struct object panicob;
179
180	    if (! dont_alloc)
181	      ob = calloc (1, sizeof (struct object));
182	    dont_alloc |= ob == NULL;
183	    if (dont_alloc)
184	      ob = &panicob;
185
186	    ob->pc_begin = (void *)-1;
187	    ob->tbase = 0;
188	    ob->dbase = 0;
189	    ob->u.single = (struct dwarf_fde *)real_fde;
190	    ob->s.i = 0;
191	    ob->s.b.encoding = DW_EH_PE_omit;
192	    ob->fde_end = real_fde + sz;
193
194	    image->fde = real_fde;
195
196	    result = search_object (ob, pc);
197
198	    if (! dont_alloc)
199	      {
200		struct object **p;
201
202		image->destructor = live_image_destructor;
203		image->object_info = ob;
204
205		image->examined_p |= (EXAMINED_IMAGE_MASK
206				      | DESTRUCTOR_MAY_BE_CALLED_LIVE);
207
208		/* Insert the object into the classified list.  */
209		for (p = &seen_objects; *p ; p = &(*p)->next)
210		  if ((*p)->pc_begin < ob->pc_begin)
211		    break;
212		ob->next = *p;
213		*p = ob;
214	      }
215
216	    if (result)
217	      {
218		int encoding;
219		_Unwind_Ptr func;
220
221		bases->tbase = ob->tbase;
222		bases->dbase = ob->dbase;
223
224		encoding = ob->s.b.encoding;
225		if (ob->s.b.mixed_encoding)
226		  encoding = get_fde_encoding (result);
227		read_encoded_value_with_base (encoding,
228					      base_from_object (encoding, ob),
229					      result->pc_begin, &func);
230		bases->func = (void *) func;
231		break;
232	      }
233	  }
234	else
235	  image->examined_p |= EXAMINED_IMAGE_MASK;
236      }
237
238  _keymgr_unlock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST);
239
240  return result;
241}
242
243const fde *
244_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
245{
246  struct km_object_info *the_obj_info;
247  const fde *ret = NULL;
248
249  the_obj_info =
250    _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST);
251  if (! the_obj_info)
252    the_obj_info = calloc (1, sizeof (*the_obj_info));
253
254  if (the_obj_info != NULL)
255    {
256      seen_objects = the_obj_info->seen_objects;
257      unseen_objects = the_obj_info->unseen_objects;
258
259      ret = _Unwind_Find_registered_FDE (pc, bases);
260    }
261
262  /* OK, didn't find it in the list of FDEs we've seen before,
263     so go through and look at the new ones.  */
264  if (ret == NULL)
265    ret = examine_objects (pc, bases, the_obj_info == NULL);
266
267  if (the_obj_info != NULL)
268    {
269      the_obj_info->seen_objects = seen_objects;
270      the_obj_info->unseen_objects = unseen_objects;
271    }
272  _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST,
273					  the_obj_info);
274  return ret;
275}
276