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

« back to all changes in this revision

Viewing changes to src/ia64/Gtables-ia64.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 */