~ubuntu-branches/ubuntu/utopic/libunwind/utopic-proposed

« back to all changes in this revision

Viewing changes to src/ia64/Gtables.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthieu Delahaye
  • Date: 2005-04-22 11:12:14 UTC
  • mto: (4.1.1 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050422111214-0m74olipxly1ra8a
Tags: upstream-0.98.5
ImportĀ upstreamĀ versionĀ 0.98.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* libunwind - a platform-independent unwind library
 
2
   Copyright (c) 2001-2004 Hewlett-Packard Development Company, L.P.
 
3
        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
4
 
 
5
This file is part of libunwind.
 
6
 
 
7
Permission is hereby granted, free of charge, to any person obtaining
 
8
a copy of this software and associated documentation files (the
 
9
"Software"), to deal in the Software without restriction, including
 
10
without limitation the rights to use, copy, modify, merge, publish,
 
11
distribute, sublicense, and/or sell copies of the Software, and to
 
12
permit persons to whom the Software is furnished to do so, subject to
 
13
the following conditions:
 
14
 
 
15
The above copyright notice and this permission notice shall be
 
16
included in all copies or substantial portions of the Software.
 
17
 
 
18
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
19
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
20
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
21
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
22
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
23
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
24
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
25
 
 
26
#include <assert.h>
 
27
#include <stdlib.h>
 
28
#include <stddef.h>
 
29
 
 
30
#include "unwind_i.h"
 
31
 
 
32
#ifdef HAVE_IA64INTRIN_H
 
33
# include <ia64intrin.h>
 
34
#endif
 
35
 
 
36
extern unw_addr_space_t _ULia64_local_addr_space;
 
37
 
 
38
struct ia64_table_entry
 
39
  {
 
40
    uint64_t start_offset;
 
41
    uint64_t end_offset;
 
42
    uint64_t info_offset;
 
43
  };
 
44
 
 
45
#ifdef UNW_LOCAL_ONLY
 
46
 
 
47
static inline int
 
48
is_local_addr_space (unw_addr_space_t as)
 
49
{
 
50
  return 1;
 
51
}
 
52
 
 
53
static inline int
 
54
read_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, void *arg)
 
55
{
 
56
  *valp = *(unw_word_t *) addr;
 
57
  return 0;
 
58
}
 
59
 
 
60
#else /* !UNW_LOCAL_ONLY */
 
61
 
 
62
static inline int
 
63
is_local_addr_space (unw_addr_space_t as)
 
64
{
 
65
  return as == unw_local_addr_space;
 
66
}
 
67
 
 
68
static inline int
 
69
read_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, void *arg)
 
70
{
 
71
  unw_accessors_t *a = unw_get_accessors (as);
 
72
 
 
73
  return (*a->access_mem) (as, addr, valp, 0, arg);
 
74
}
 
75
 
 
76
/* Helper macro for reading an ia64_table_entry from remote memory.  */
 
77
#define remote_read(addr, member)                                            \
 
78
        (*a->access_mem) (as, (addr) + offsetof (struct ia64_table_entry,    \
 
79
                                                 member), &member, 0, arg)
 
80
 
 
81
/* Lookup an unwind-table entry in remote memory.  Returns 1 if an
 
82
   entry is found, 0 if no entry is found, negative if an error
 
83
   occurred reading remote memory.  */
 
84
static int
 
85
remote_lookup (unw_addr_space_t as,
 
86
               unw_word_t table, size_t table_size, unw_word_t rel_ip,
 
87
               struct ia64_table_entry *e, void *arg)
 
88
{
 
89
  unw_word_t e_addr = 0, start_offset, end_offset, info_offset;
 
90
  unw_accessors_t *a = unw_get_accessors (as);
 
91
  unsigned long lo, hi, mid;
 
92
  int ret;
 
93
 
 
94
  /* do a binary search for right entry: */
 
95
  for (lo = 0, hi = table_size / sizeof (struct ia64_table_entry); lo < hi;)
 
96
    {
 
97
      mid = (lo + hi) / 2;
 
98
      e_addr = table + mid * sizeof (struct ia64_table_entry);
 
99
      if ((ret = remote_read (e_addr, start_offset)) < 0)
 
100
        return ret;
 
101
 
 
102
      if (rel_ip < start_offset)
 
103
        hi = mid;
 
104
      else
 
105
        {
 
106
          if ((ret = remote_read (e_addr, end_offset)) < 0)
 
107
            return ret;
 
108
 
 
109
          if (rel_ip >= end_offset)
 
110
            lo = mid + 1;
 
111
          else
 
112
            break;
 
113
        }
 
114
    }
 
115
  if (rel_ip < start_offset || rel_ip >= end_offset)
 
116
    return 0;
 
117
  e->start_offset = start_offset;
 
118
  e->end_offset = end_offset;
 
119
 
 
120
  if ((ret = remote_read (e_addr, info_offset)) < 0)
 
121
    return ret;
 
122
  e->info_offset = info_offset;
 
123
  return 1;
 
124
}
 
125
 
 
126
HIDDEN void
 
127
tdep_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi, void *arg)
 
128
{
 
129
  if (!pi->unwind_info)
 
130
    return;
 
131
 
 
132
  if (is_local_addr_space (as))
 
133
    {
 
134
      free (pi->unwind_info);
 
135
      pi->unwind_info = NULL;
 
136
    }
 
137
}
 
138
 
 
139
PROTECTED unw_word_t
 
140
_Uia64_find_dyn_list (unw_addr_space_t as, unw_dyn_info_t *di, void *arg)
 
141
{
 
142
  unw_word_t hdr_addr, info_addr, hdr, directives, pers, cookie, off;
 
143
  unw_word_t start_offset, end_offset, info_offset, segbase;
 
144
  struct ia64_table_entry *e;
 
145
  size_t table_size;
 
146
  unw_word_t gp = di->gp;
 
147
  int ret;
 
148
 
 
149
  switch (di->format)
 
150
    {
 
151
    case UNW_INFO_FORMAT_DYNAMIC:
 
152
    default:
 
153
      return 0;
 
154
 
 
155
    case UNW_INFO_FORMAT_TABLE:
 
156
      e = (struct ia64_table_entry *) di->u.ti.table_data;
 
157
      table_size = di->u.ti.table_len * sizeof (di->u.ti.table_data[0]);
 
158
      segbase = di->u.ti.segbase;
 
159
      if (table_size < sizeof (struct ia64_table_entry))
 
160
        return 0;
 
161
      start_offset = e[0].start_offset;
 
162
      end_offset = e[0].end_offset;
 
163
      info_offset = e[0].info_offset;
 
164
      break;
 
165
 
 
166
    case UNW_INFO_FORMAT_REMOTE_TABLE:
 
167
      {
 
168
        unw_accessors_t *a = unw_get_accessors (as);
 
169
        unw_word_t e_addr = di->u.rti.table_data;
 
170
 
 
171
        table_size = di->u.rti.table_len * sizeof (unw_word_t);
 
172
        segbase = di->u.rti.segbase;
 
173
        if (table_size < sizeof (struct ia64_table_entry))
 
174
          return 0;
 
175
 
 
176
        if (   (ret = remote_read (e_addr, start_offset) < 0)
 
177
            || (ret = remote_read (e_addr, end_offset) < 0)
 
178
            || (ret = remote_read (e_addr, info_offset) < 0))
 
179
          return ret;
 
180
      }
 
181
      break;
 
182
    }
 
183
 
 
184
  if (start_offset != end_offset)
 
185
    /* dyn-list entry cover a zero-length "procedure" and should be
 
186
       first entry (note: technically a binary could contain code
 
187
       below the segment base, but this doesn't happen for normal
 
188
       binaries and certainly doesn't happen when libunwind is a
 
189
       separate shared object.  For weird cases, the application may
 
190
       have to provide its own (slower) version of this routine.  */
 
191
    return 0;
 
192
 
 
193
  hdr_addr = info_offset + segbase;
 
194
  info_addr = hdr_addr + 8;
 
195
 
 
196
  /* read the header word: */
 
197
  if ((ret = read_mem (as, hdr_addr, &hdr, arg)) < 0)
 
198
    return ret;
 
199
 
 
200
  if (IA64_UNW_VER (hdr) != 1
 
201
      || IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr))
 
202
    /* dyn-list entry must be version 1 and doesn't have ehandler
 
203
       or uhandler */
 
204
    return 0;
 
205
 
 
206
  if (IA64_UNW_LENGTH (hdr) != 1)
 
207
    /* dyn-list entry must consist of a single word of NOP directives */
 
208
    return 0;
 
209
 
 
210
  if (   ((ret = read_mem (as, info_addr, &directives, arg)) < 0)
 
211
      || ((ret = read_mem (as, info_addr + 0x08, &pers, arg)) < 0)
 
212
      || ((ret = read_mem (as, info_addr + 0x10, &cookie, arg)) < 0)
 
213
      || ((ret = read_mem (as, info_addr + 0x18, &off, arg)) < 0))
 
214
    return 0;
 
215
 
 
216
  if (directives != 0 || pers != 0
 
217
      || (!as->big_endian && cookie != 0x7473696c2d6e7964ULL)
 
218
      || ( as->big_endian && cookie != 0x64796e2d6c697374ULL))
 
219
    return 0;
 
220
 
 
221
  /* OK, we ran the gauntlet and found it: */
 
222
  return off + gp;
 
223
}
 
224
 
 
225
#endif /* !UNW_LOCAL_ONLY */
 
226
 
 
227
static inline const struct ia64_table_entry *
 
228
lookup (struct ia64_table_entry *table, size_t table_size, unw_word_t rel_ip)
 
229
{
 
230
  const struct ia64_table_entry *e = 0;
 
231
  unsigned long lo, hi, mid;
 
232
 
 
233
  /* do a binary search for right entry: */
 
234
  for (lo = 0, hi = table_size / sizeof (struct ia64_table_entry); lo < hi;)
 
235
    {
 
236
      mid = (lo + hi) / 2;
 
237
      e = table + mid;
 
238
      if (rel_ip < e->start_offset)
 
239
        hi = mid;
 
240
      else if (rel_ip >= e->end_offset)
 
241
        lo = mid + 1;
 
242
      else
 
243
        break;
 
244
    }
 
245
  if (rel_ip < e->start_offset || rel_ip >= e->end_offset)
 
246
    return NULL;
 
247
  return e;
 
248
}
 
249
 
 
250
PROTECTED int
 
251
unw_search_ia64_unwind_table (unw_addr_space_t as, unw_word_t ip,
 
252
                              unw_dyn_info_t *di, unw_proc_info_t *pi,
 
253
                              int need_unwind_info, void *arg)
 
254
{
 
255
  unw_word_t addr, hdr_addr, info_addr, info_end_addr, hdr, *wp;
 
256
  const struct ia64_table_entry *e = NULL;
 
257
  unw_word_t handler_offset, segbase = 0;
 
258
  int ret;
 
259
 
 
260
  assert ((di->format == UNW_INFO_FORMAT_TABLE
 
261
           || di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
 
262
          && (ip >= di->start_ip && ip < di->end_ip));
 
263
 
 
264
  pi->flags = 0;
 
265
  pi->unwind_info = 0;
 
266
  pi->handler = 0;
 
267
 
 
268
  if (likely (di->format == UNW_INFO_FORMAT_TABLE))
 
269
    {
 
270
      segbase = di->u.ti.segbase;
 
271
      e = lookup ((struct ia64_table_entry *) di->u.ti.table_data,
 
272
                  di->u.ti.table_len * sizeof (unw_word_t),
 
273
                  ip - segbase);
 
274
    }
 
275
#ifndef UNW_LOCAL_ONLY
 
276
  else
 
277
    {
 
278
      struct ia64_table_entry ent;
 
279
 
 
280
      segbase = di->u.rti.segbase;
 
281
      if ((ret = remote_lookup (as, di->u.rti.table_data,
 
282
                                di->u.rti.table_len * sizeof (unw_word_t),
 
283
                                ip - segbase, &ent, arg)) < 0)
 
284
        return ret;
 
285
      if (ret)
 
286
        e = &ent;
 
287
    }
 
288
#endif
 
289
  if (!e)
 
290
    {
 
291
      /* IP is inside this table's range, but there is no explicit
 
292
         unwind info => use default conventions (i.e., this is NOT an
 
293
         error).  */
 
294
      memset (pi, 0, sizeof (*pi));
 
295
      pi->start_ip = 0;
 
296
      pi->end_ip = 0;
 
297
      pi->gp = di->gp;
 
298
      pi->lsda = 0;
 
299
      return 0;
 
300
    }
 
301
 
 
302
  pi->start_ip = e->start_offset + segbase;
 
303
  pi->end_ip = e->end_offset + segbase;
 
304
 
 
305
  hdr_addr = e->info_offset + segbase;
 
306
  info_addr = hdr_addr + 8;
 
307
 
 
308
  /* read the header word: */
 
309
  if ((ret = read_mem (as, hdr_addr, &hdr, arg)) < 0)
 
310
    return ret;
 
311
 
 
312
  if (IA64_UNW_VER (hdr) != 1)
 
313
    return -UNW_EBADVERSION;
 
314
 
 
315
  info_end_addr = info_addr + 8 * IA64_UNW_LENGTH (hdr);
 
316
 
 
317
  if (need_unwind_info)
 
318
    {
 
319
      pi->unwind_info_size = 8 * IA64_UNW_LENGTH (hdr);
 
320
 
 
321
      if (is_local_addr_space (as))
 
322
        pi->unwind_info = (void *) (uintptr_t) info_addr;
 
323
      else
 
324
        {
 
325
          /* Internalize unwind info.  Note: since we're doing this
 
326
             only for non-local address spaces, there is no
 
327
             signal-safety issue and it is OK to use malloc()/free().  */
 
328
          pi->unwind_info = malloc (8 * IA64_UNW_LENGTH (hdr));
 
329
          if (!pi->unwind_info)
 
330
            return -UNW_ENOMEM;
 
331
 
 
332
          wp = (unw_word_t *) pi->unwind_info;
 
333
          for (addr = info_addr; addr < info_end_addr; addr += 8, ++wp)
 
334
            {
 
335
              if ((ret = read_mem (as, addr, wp, arg)) < 0)
 
336
                {
 
337
                  free (pi->unwind_info);
 
338
                  return ret;
 
339
                }
 
340
            }
 
341
        }
 
342
    }
 
343
 
 
344
  if (IA64_UNW_FLAG_EHANDLER (hdr) || IA64_UNW_FLAG_UHANDLER (hdr))
 
345
    {
 
346
      /* read the personality routine address (address is gp-relative): */
 
347
      if ((ret = read_mem (as, info_end_addr, &handler_offset, arg)) < 0)
 
348
        return ret;
 
349
      Debug (4, "handler ptr @ offset=%lx, gp=%lx\n", handler_offset, di->gp);
 
350
      if ((read_mem (as, handler_offset + di->gp, &pi->handler, arg)) < 0)
 
351
        return ret;
 
352
    }
 
353
  pi->lsda = info_end_addr + 8;
 
354
  pi->gp = di->gp;
 
355
  pi->format = di->format;
 
356
  return 0;
 
357
}
 
358
 
 
359
#ifndef UNW_REMOTE_ONLY
 
360
 
 
361
# if defined(HAVE_DL_ITERATE_PHDR)
 
362
#  include <link.h>
 
363
#  include <stdlib.h>
 
364
 
 
365
#  if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
 
366
      || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG))
 
367
#    error You need GLIBC 2.2.4 or later on IA-64 Linux
 
368
#  endif
 
369
 
 
370
#  if defined(HAVE_GETUNWIND)
 
371
     extern unsigned long getunwind (void *buf, size_t len);
 
372
#  else /* HAVE_GETUNWIND */
 
373
#   include <unistd.h>
 
374
#   include <sys/syscall.h>
 
375
#   ifndef __NR_getunwind
 
376
#     define __NR_getunwind     1215
 
377
#   endif
 
378
 
 
379
static unsigned long
 
380
getunwind (void *buf, size_t len)
 
381
{
 
382
  return syscall (SYS_getunwind, buf, len);
 
383
}
 
384
 
 
385
#  endif /* HAVE_GETUNWIND */
 
386
 
 
387
static unw_dyn_info_t kernel_table;
 
388
 
 
389
static int
 
390
get_kernel_table (unw_dyn_info_t *di)
 
391
{
 
392
  struct ia64_table_entry *ktab, *etab;
 
393
  size_t size;
 
394
 
 
395
  Debug (16, "getting kernel table");
 
396
 
 
397
  size = getunwind (NULL, 0);
 
398
  ktab = sos_alloc (size);
 
399
  if (!ktab)
 
400
    {
 
401
      dprintf (__FILE__".%s: failed to allocate %zu bytes",
 
402
               __FUNCTION__, size);
 
403
      return -UNW_ENOMEM;
 
404
    }
 
405
  getunwind (ktab, size);
 
406
 
 
407
  /* Determine length of kernel's unwind table & relocate its entries.  */
 
408
  for (etab = ktab; etab->start_offset; ++etab)
 
409
    etab->info_offset += (uint64_t) ktab;
 
410
 
 
411
  di->format = UNW_INFO_FORMAT_TABLE;
 
412
  di->gp = 0;
 
413
  di->start_ip = ktab[0].start_offset;
 
414
  di->end_ip = etab[-1].end_offset;
 
415
  di->u.ti.name_ptr = (unw_word_t) "<kernel>";
 
416
  di->u.ti.segbase = 0;
 
417
  di->u.ti.table_len = ((char *) etab - (char *) ktab) / sizeof (unw_word_t);
 
418
  di->u.ti.table_data = (unw_word_t *) ktab;
 
419
 
 
420
  Debug (16, "found table `%s': [%lx-%lx) segbase=%lx len=%lu\n",
 
421
         (char *) di->u.ti.name_ptr, di->start_ip, di->end_ip,
 
422
         di->u.ti.segbase, di->u.ti.table_len);
 
423
  return 0;
 
424
}
 
425
 
 
426
#  ifndef UNW_LOCAL_ONLY
 
427
 
 
428
/* This is exported for the benefit of libunwind-ptrace.a.  */
 
429
PROTECTED int
 
430
_Uia64_get_kernel_table (unw_dyn_info_t *di)
 
431
{
 
432
  int ret;
 
433
 
 
434
  if (!kernel_table.u.ti.table_data)
 
435
    if ((ret = get_kernel_table (&kernel_table)) < 0)
 
436
      return ret;
 
437
 
 
438
  memcpy (di, &kernel_table, sizeof (*di));
 
439
  return 0;
 
440
}
 
441
 
 
442
#  endif /* !UNW_LOCAL_ONLY */
 
443
 
 
444
static inline unsigned long
 
445
current_gp (void)
 
446
{
 
447
#  if defined(__GNUC__) && !defined(__INTEL_COMPILER)
 
448
      register unsigned long gp __asm__("gp");
 
449
      return gp;
 
450
#  elif HAVE_IA64INTRIN_H
 
451
      return __getReg (_IA64_REG_GP);
 
452
#  else
 
453
#    error Implement me.
 
454
#  endif
 
455
}
 
456
 
 
457
static int
 
458
callback (struct dl_phdr_info *info, size_t size, void *ptr)
 
459
{
 
460
  unw_dyn_info_t *di = ptr;
 
461
  const Elf64_Phdr *phdr, *p_unwind, *p_dynamic, *p_text;
 
462
  long n;
 
463
  Elf64_Addr load_base, segbase = 0;
 
464
 
 
465
  /* Make sure struct dl_phdr_info is at least as big as we need.  */
 
466
  if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
 
467
             + sizeof (info->dlpi_phnum))
 
468
    return -1;
 
469
 
 
470
  Debug (16, "checking `%s' (load_base=%lx)\n",
 
471
         info->dlpi_name, info->dlpi_addr);
 
472
 
 
473
  phdr = info->dlpi_phdr;
 
474
  load_base = info->dlpi_addr;
 
475
  p_text = NULL;
 
476
  p_unwind = NULL;
 
477
  p_dynamic = NULL;
 
478
 
 
479
  /* See if PC falls into one of the loaded segments.  Find the unwind
 
480
     segment at the same time.  */
 
481
  for (n = info->dlpi_phnum; --n >= 0; phdr++)
 
482
    {
 
483
      if (phdr->p_type == PT_LOAD)
 
484
        {
 
485
          Elf64_Addr vaddr = phdr->p_vaddr + load_base;
 
486
          if (di->u.ti.segbase >= vaddr
 
487
              && di->u.ti.segbase < vaddr + phdr->p_memsz)
 
488
            p_text = phdr;
 
489
        }
 
490
      else if (phdr->p_type == PT_IA_64_UNWIND)
 
491
        p_unwind = phdr;
 
492
      else if (phdr->p_type == PT_DYNAMIC)
 
493
        p_dynamic = phdr;
 
494
    }
 
495
  if (!p_text || !p_unwind)
 
496
    return 0;
 
497
 
 
498
  if (likely (p_unwind->p_vaddr >= p_text->p_vaddr
 
499
              && p_unwind->p_vaddr < p_text->p_vaddr + p_text->p_memsz))
 
500
    /* normal case: unwind table is inside text segment */
 
501
    segbase = p_text->p_vaddr + load_base;
 
502
  else
 
503
    {
 
504
      /* Special case: unwind table is in some other segment; this
 
505
         happens for the Linux kernel's gate DSO, for example.  */
 
506
      phdr = info->dlpi_phdr;
 
507
      for (n = info->dlpi_phnum; --n >= 0; phdr++)
 
508
        {
 
509
          if (phdr->p_type == PT_LOAD && p_unwind->p_vaddr >= phdr->p_vaddr
 
510
              && p_unwind->p_vaddr < phdr->p_vaddr + phdr->p_memsz)
 
511
            {
 
512
              segbase = phdr->p_vaddr + load_base;
 
513
              break;
 
514
            }
 
515
        }
 
516
    }
 
517
 
 
518
  if (p_dynamic)
 
519
    {
 
520
      /* For dynamicly linked executables and shared libraries,
 
521
         DT_PLTGOT is the gp value for that object.  */
 
522
      Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base);
 
523
      for (; dyn->d_tag != DT_NULL; ++dyn)
 
524
        if (dyn->d_tag == DT_PLTGOT)
 
525
          {
 
526
            /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it.  */
 
527
            di->gp = dyn->d_un.d_ptr;
 
528
            break;
 
529
          }
 
530
    }
 
531
  else
 
532
    /* Otherwise this is a static executable with no _DYNAMIC.
 
533
       The gp is constant program-wide.  */
 
534
    di->gp = current_gp();
 
535
  di->format = UNW_INFO_FORMAT_TABLE;
 
536
  di->start_ip = p_text->p_vaddr + load_base;
 
537
  di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
 
538
  di->u.ti.name_ptr = (unw_word_t) info->dlpi_name;
 
539
  di->u.ti.table_data = (void *) (p_unwind->p_vaddr + load_base);
 
540
  di->u.ti.table_len = p_unwind->p_memsz / sizeof (unw_word_t);
 
541
  di->u.ti.segbase = segbase;
 
542
 
 
543
  Debug (16, "found table `%s': segbase=%lx, len=%lu, gp=%lx, "
 
544
         "table_data=%p\n", (char *) di->u.ti.name_ptr, di->u.ti.segbase,
 
545
         di->u.ti.table_len, di->gp, di->u.ti.table_data);
 
546
  return 1;
 
547
}
 
548
 
 
549
#  ifdef HAVE_DL_PHDR_REMOVALS_COUNTER
 
550
 
 
551
static inline int
 
552
validate_cache (unw_addr_space_t as)
 
553
{
 
554
  /* Note: we don't need to serialize here with respect to
 
555
     dl_iterate_phdr() because if somebody were to remove an object
 
556
     that is required to complete the unwind on whose behalf we're
 
557
     validating the cache here, we'd be hosed anyhow.  What we're
 
558
     guarding against here is the case where library FOO gets mapped,
 
559
     unwind info for FOO gets cached, FOO gets unmapped, BAR gets
 
560
     mapped in the place where FOO was and then we unwind across a
 
561
     function in FOO.  Since no thread can execute in BAR before FOO
 
562
     has been removed, we are guaranteed that
 
563
     dl_phdr_removals_counter() would have been incremented before we
 
564
     get here.  */
 
565
  unsigned long long removals = dl_phdr_removals_counter ();
 
566
 
 
567
  if (removals == as->shared_object_removals)
 
568
    return 1;
 
569
 
 
570
  as->shared_object_removals = removals;
 
571
  unw_flush_cache (as, 0, 0);
 
572
  return -1;
 
573
}
 
574
 
 
575
#  else /* !HAVE_DL_PHDR_REMOVALS_COUNTER */
 
576
 
 
577
/* Check whether any phdrs have been removed since we last flushed the
 
578
   cache.  If so we flush the cache and return -1, if not, we do
 
579
   nothing and return 1.  */
 
580
 
 
581
static int
 
582
check_callback (struct dl_phdr_info *info, size_t size, void *ptr)
 
583
{
 
584
#   ifdef HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS
 
585
  unw_addr_space_t as = ptr;
 
586
 
 
587
  if (size <
 
588
      offsetof (struct dl_phdr_info, dlpi_subs) + sizeof (info->dlpi_subs))
 
589
    /* It would be safer to flush the cache here, but that would
 
590
       disable caching for older libc's which would be incompatible
 
591
       with the behavior of older versions of libunwind so we return 1
 
592
       instead and hope nobody runs into stale cache info...  */
 
593
    return 1;
 
594
 
 
595
  if (info->dlpi_subs == as->shared_object_removals)
 
596
    return 1;
 
597
 
 
598
  as->shared_object_removals = info->dlpi_subs;
 
599
  unw_flush_cache (as, 0, 0);
 
600
  return -1;            /* indicate that there were removals */
 
601
#   else
 
602
  return 1;
 
603
#   endif
 
604
}
 
605
 
 
606
static inline int
 
607
validate_cache (unw_addr_space_t as)
 
608
{
 
609
  sigset_t saved_sigmask;
 
610
  int ret;
 
611
 
 
612
  sigprocmask (SIG_SETMASK, &unwi_full_sigmask, &saved_sigmask);
 
613
  ret = dl_iterate_phdr (check_callback, as);
 
614
  sigprocmask (SIG_SETMASK, &saved_sigmask, NULL);
 
615
  return ret;
 
616
}
 
617
 
 
618
#  endif /* HAVE_DL_PHDR_REMOVALS_COUNTER */
 
619
 
 
620
# elif defined(HAVE_DLMODINFO)
 
621
  /* Support for HP-UX-style dlmodinfo() */
 
622
#  include <dlfcn.h>
 
623
 
 
624
static inline int
 
625
validate_cache (unw_addr_space_t as)
 
626
{
 
627
  return 1;
 
628
}
 
629
 
 
630
# endif /* !HAVE_DLMODINFO */
 
631
 
 
632
HIDDEN int
 
633
tdep_find_proc_info (unw_addr_space_t as, unw_word_t ip,
 
634
                     unw_proc_info_t *pi, int need_unwind_info, void *arg)
 
635
{
 
636
# if defined(HAVE_DL_ITERATE_PHDR)
 
637
  unw_dyn_info_t di, *dip = &di;
 
638
  sigset_t saved_sigmask;
 
639
  int ret;
 
640
 
 
641
  di.u.ti.segbase = ip; /* this is cheap... */
 
642
 
 
643
  sigprocmask (SIG_SETMASK, &unwi_full_sigmask, &saved_sigmask);
 
644
  ret = dl_iterate_phdr (callback, &di);
 
645
  sigprocmask (SIG_SETMASK, &saved_sigmask, NULL);
 
646
 
 
647
  if (ret <= 0)
 
648
    {
 
649
      if (!kernel_table.u.ti.table_data)
 
650
        {
 
651
          if ((ret = get_kernel_table (&kernel_table)) < 0)
 
652
            return ret;
 
653
        }
 
654
      if (ip < kernel_table.start_ip || ip >= kernel_table.end_ip)
 
655
        return -UNW_ENOINFO;
 
656
      dip = &kernel_table;
 
657
    }
 
658
# elif defined(HAVE_DLMODINFO)
 
659
# define UNWIND_TBL_32BIT       0x8000000000000000
 
660
  struct load_module_desc lmd;
 
661
  unw_dyn_info_t di, *dip = &di;
 
662
  struct unwind_header
 
663
    {
 
664
      uint64_t header_version;
 
665
      uint64_t start_offset;
 
666
      uint64_t end_offset;
 
667
    }
 
668
  *uhdr;
 
669
 
 
670
  if (!dlmodinfo (ip, &lmd, sizeof (lmd), NULL, 0, 0))
 
671
    return -UNW_ENOINFO;
 
672
 
 
673
  di.format = UNW_INFO_FORMAT_TABLE;
 
674
  di.start_ip = lmd.text_base;
 
675
  di.end_ip = lmd.text_base + lmd.text_size;
 
676
  di.gp = lmd.linkage_ptr;
 
677
  di.u.ti.name_ptr = 0; /* no obvious table-name available */
 
678
  di.u.ti.segbase = lmd.text_base;
 
679
 
 
680
  uhdr = (struct unwind_header *) lmd.unwind_base;
 
681
 
 
682
  if ((uhdr->header_version & ~UNWIND_TBL_32BIT) != 1
 
683
      && (uhdr->header_version & ~UNWIND_TBL_32BIT) != 2)
 
684
    {
 
685
      Debug (1, "encountered unknown unwind header version %ld\n",
 
686
             (long) (uhdr->header_version & ~UNWIND_TBL_32BIT));
 
687
      return -UNW_EBADVERSION;
 
688
    }
 
689
  if (uhdr->header_version & UNWIND_TBL_32BIT)
 
690
    {
 
691
      Debug (1, "32-bit unwind tables are not supported yet\n");
 
692
      return -UNW_EINVAL;
 
693
    }
 
694
 
 
695
  di.u.ti.table_data = (unw_word_t *) (di.u.ti.segbase + uhdr->start_offset);
 
696
  di.u.ti.table_len = ((uhdr->end_offset - uhdr->start_offset)
 
697
                       / sizeof (unw_word_t));
 
698
 
 
699
  Debug (16, "found table `%s': segbase=%lx, len=%lu, gp=%lx, "
 
700
         "table_data=%p\n", (char *) di.u.ti.name_ptr, di.u.ti.segbase,
 
701
         di.u.ti.table_len, di.gp, di.u.ti.table_data);
 
702
# endif
 
703
 
 
704
  /* now search the table: */
 
705
  return tdep_search_unwind_table (as, ip, dip, pi, need_unwind_info, arg);
 
706
}
 
707
 
 
708
/* Returns 1 if the cache is up-to-date or -1 if the cache contained
 
709
   stale data and had to be flushed.  */
 
710
 
 
711
HIDDEN int
 
712
ia64_local_validate_cache (unw_addr_space_t as, void *arg)
 
713
{
 
714
  return validate_cache (as);
 
715
}
 
716
 
 
717
#endif /* !UNW_REMOTE_ONLY */