1/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
2
3   This file is part of GNU CC.
4
5   GNU CC 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 2, or (at your option)
8   any later version.
9
10   GNU CC 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   You should have received a copy of the GNU General Public License
16   along with GNU CC; see the file COPYING.  If not, write to
17   the Free Software Foundation, 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.  */
19
20/* As a special exception, if you link this library with other files,
21   some of which are compiled with GCC, to produce an executable,
22   this library does not by itself cause the resulting executable
23   to be covered by the GNU General Public License.
24   This exception does not however invalidate any other reasons why
25   the executable file might be covered by the GNU General Public License.  */
26
27/* Locate the FDE entry for a given address, using Darwin's keymgr support.  */
28
29#include "tconfig.h"
30#include <string.h>
31#include <stdlib.h>
32#include "dwarf2.h"
33#include "unwind.h"
34#define NO_BASE_OF_ENCODED_VALUE
35#define DWARF2_OBJECT_END_PTR_EXTENSION
36#include "unwind-pe.h"
37#include "unwind-dw2-fde.h"
38/* Carefully don't include gthr.h.  */
39
40typedef int __gthread_mutex_t;
41#define __gthread_mutex_lock(x)  (void)(x)
42#define __gthread_mutex_unlock(x) (void)(x)
43
44static fde * _Unwind_Find_registered_FDE (void *pc,
45					  struct dwarf_eh_bases *bases);
46
47#define _Unwind_Find_FDE _Unwind_Find_registered_FDE
48#include "unwind-dw2-fde.c"
49#undef _Unwind_Find_FDE
50
51/* KeyMgr stuff.  */
52#define KEYMGR_GCC3_LIVE_IMAGE_LIST     301     /* loaded images  */
53#define KEYMGR_GCC3_DW2_OBJ_LIST        302     /* Dwarf2 object list  */
54
55extern void *_keymgr_get_and_lock_processwide_ptr (int);
56extern void _keymgr_set_and_unlock_processwide_ptr (int, void *);
57extern void _keymgr_unlock_processwide_ptr (int);
58
59struct mach_header;
60extern char *getsectdatafromheader (struct mach_header*, const char*,
61			const char *, unsigned long *);
62
63/* This is referenced from KEYMGR_GCC3_DW2_OBJ_LIST.  */
64struct km_object_info {
65  struct object *seen_objects;
66  struct object *unseen_objects;
67  unsigned spare[2];
68};
69
70/* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST.  Info about each resident image.  */
71struct live_images {
72  unsigned long this_size;                      /* sizeof (live_images)  */
73  struct mach_header *mh;                       /* the image info  */
74  unsigned long vm_slide;
75  void (*destructor)(struct live_images *);     /* destructor for this  */
76  struct live_images *next;
77  unsigned int examined_p;
78  void *fde;
79  void *object_info;
80  unsigned long info[2];                        /* Future use.  */
81};
82
83/* Bits in the examined_p field of struct live_images.  */
84enum {
85  EXAMINED_IMAGE_MASK = 1,	/* We've seen this one.  */
86  ALLOCED_IMAGE_MASK = 2,	/* The FDE entries were allocated by
87				   malloc, and must be freed.  This isn't
88				   used by newer libgcc versions.  */
89  IMAGE_IS_TEXT_MASK = 4,	/* This image is in the TEXT segment.  */
90  DESTRUCTOR_MAY_BE_CALLED_LIVE = 8  /* The destructor may be called on an
91					object that's part of the live
92					image list.  */
93};
94
95/* Delete any data we allocated on a live_images structure.  Either
96   IMAGE has already been removed from the
97   KEYMGR_GCC3_LIVE_IMAGE_LIST and the struct will be deleted
98   after we return, or that list is locked and we're being called
99   because this object might be about to be unloaded.  Called by
100   KeyMgr.  */
101
102static void
103live_image_destructor (struct live_images *image)
104{
105  if (image->object_info)
106    {
107      /* Free any sorted arrays.  */
108      __deregister_frame_info_bases (image->fde);
109
110      free (image->object_info);
111      image->object_info = NULL;
112      if (image->examined_p & ALLOCED_IMAGE_MASK)
113	free (image->fde);
114      image->fde = NULL;
115    }
116  image->examined_p = 0;
117  image->destructor = NULL;
118}
119
120/* Run through the list of live images.  If we can allocate memory,
121   give each unseen image a new `struct object'.  Even if we can't,
122   check whether the PC is inside the FDE of each unseen image.
123 */
124
125static inline fde *
126examine_objects (void *pc, struct dwarf_eh_bases *bases, int dont_alloc)
127{
128  fde *result = NULL;
129  struct live_images *image;
130
131  image = _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST);
132
133  for (; image != NULL; image = image->next)
134    if ((image->examined_p & EXAMINED_IMAGE_MASK) == 0)
135      {
136	char *fde;
137	unsigned long sz;
138
139	fde = getsectdatafromheader (image->mh, "__DATA", "__eh_frame", &sz);
140	if (fde == NULL)
141	  {
142	    fde = getsectdatafromheader (image->mh, "__TEXT",
143					 "__eh_frame", &sz);
144	    if (fde != NULL)
145	      image->examined_p |= IMAGE_IS_TEXT_MASK;
146	  }
147
148	/* If .eh_frame is empty, don't register at all.  */
149	if (fde != NULL && sz > 0)
150	  {
151	    char *real_fde = (fde + image->vm_slide);
152	    struct object *ob = NULL;
153	    struct object panicob;
154
155	    if (! dont_alloc)
156	      ob = calloc (1, sizeof (struct object));
157	    dont_alloc |= ob == NULL;
158	    if (dont_alloc)
159	      ob = &panicob;
160
161	    ob->pc_begin = (void *)-1;
162	    ob->tbase = 0;
163	    ob->dbase = 0;
164	    ob->u.single = (struct dwarf_fde *)real_fde;
165	    ob->s.i = 0;
166	    ob->s.b.encoding = DW_EH_PE_omit;
167	    ob->fde_end = real_fde + sz;
168
169	    if (! dont_alloc)
170	      {
171		ob->next = unseen_objects;
172		unseen_objects = ob;
173
174		image->destructor = live_image_destructor;
175		image->object_info = ob;
176
177		image->examined_p |= (EXAMINED_IMAGE_MASK
178				      | DESTRUCTOR_MAY_BE_CALLED_LIVE);
179	      }
180	    image->fde = real_fde;
181
182	    result = search_object (ob, pc);
183	    if (result)
184	      {
185		int encoding;
186
187		bases->tbase = ob->tbase;
188		bases->dbase = ob->dbase;
189
190		encoding = ob->s.b.encoding;
191		if (ob->s.b.mixed_encoding)
192		  encoding = get_fde_encoding (result);
193		read_encoded_value_with_base (encoding,
194					      base_from_object (encoding, ob),
195					      result->pc_begin,
196					      (_Unwind_Ptr *)&bases->func);
197		break;
198	      }
199	  }
200	else
201	  image->examined_p |= EXAMINED_IMAGE_MASK;
202      }
203
204  _keymgr_unlock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST);
205
206  return result;
207}
208
209fde *
210_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
211{
212  struct km_object_info *the_obj_info;
213  fde *ret = NULL;
214
215  the_obj_info =
216    _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST);
217  if (! the_obj_info)
218    the_obj_info = calloc (1, sizeof (*the_obj_info));
219
220  if (the_obj_info != NULL)
221    {
222      seen_objects = the_obj_info->seen_objects;
223      unseen_objects = the_obj_info->unseen_objects;
224
225      ret = _Unwind_Find_registered_FDE (pc, bases);
226    }
227
228  /* OK, didn't find it in the list of FDEs we've seen before,
229     so go through and look at the new ones.  */
230  if (ret == NULL)
231    ret = examine_objects (pc, bases, the_obj_info == NULL);
232
233  if (the_obj_info != NULL)
234    {
235      the_obj_info->seen_objects = seen_objects;
236      the_obj_info->unseen_objects = unseen_objects;
237      _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST,
238					      the_obj_info);
239    }
240  return ret;
241}
242