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

« back to all changes in this revision

Viewing changes to src/ia64/Ginit-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 Co
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 <alloca.h>
27
 
#include <stdlib.h>
28
 
 
29
 
#include "unwind_i.h"
30
 
 
31
 
#ifdef HAVE_SYS_UC_ACCESS_H
32
 
# include <sys/uc_access.h>
33
 
#endif
34
 
 
35
 
#if UNW_DEBUG
36
 
 
37
 
HIDDEN const char *
38
 
ia64_strloc (ia64_loc_t loc)
39
 
{
40
 
  static char buf[128];
41
 
 
42
 
  if (IA64_IS_NULL_LOC (loc))
43
 
    return "<null>";
44
 
 
45
 
  buf[0] = '\0';
46
 
 
47
 
  if (IA64_IS_MEMSTK_NAT (loc))
48
 
    strcat (buf, "memstk_nat(");
49
 
  if (IA64_IS_UC_LOC (loc))
50
 
    strcat (buf, "uc(");
51
 
  if (IA64_IS_FP_LOC (loc))
52
 
    strcat (buf, "fp(");
53
 
 
54
 
  if (IA64_IS_REG_LOC (loc))
55
 
    sprintf (buf + strlen (buf), "%s", unw_regname (IA64_GET_REG (loc)));
56
 
  else
57
 
    sprintf (buf + strlen (buf), "0x%llx",
58
 
             (unsigned long long) IA64_GET_ADDR (loc));
59
 
 
60
 
  if (IA64_IS_FP_LOC (loc))
61
 
    strcat (buf, ")");
62
 
  if (IA64_IS_UC_LOC (loc))
63
 
    strcat (buf, ")");
64
 
  if (IA64_IS_MEMSTK_NAT (loc))
65
 
    strcat (buf, ")");
66
 
 
67
 
  return buf;
68
 
}
69
 
 
70
 
#endif /* UNW_DEBUG */
71
 
 
72
 
#ifdef UNW_REMOTE_ONLY
73
 
 
74
 
/* unw_local_addr_space is a NULL pointer in this case.  */
75
 
PROTECTED unw_addr_space_t unw_local_addr_space;
76
 
 
77
 
#else /* !UNW_REMOTE_ONLY */
78
 
 
79
 
static struct unw_addr_space local_addr_space;
80
 
 
81
 
PROTECTED unw_addr_space_t unw_local_addr_space = &local_addr_space;
82
 
 
83
 
#ifdef HAVE_SYS_UC_ACCESS_H
84
 
 
85
 
#else /* !HAVE_SYS_UC_ACCESS_H */
86
 
 
87
 
HIDDEN void *
88
 
tdep_uc_addr (ucontext_t *uc, int reg, uint8_t *nat_bitnr)
89
 
{
90
 
  return inlined_uc_addr (uc, reg, nat_bitnr);
91
 
}
92
 
 
93
 
#endif /* !HAVE_SYS_UC_ACCESS_H */
94
 
 
95
 
static void
96
 
put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
97
 
{
98
 
  /* it's a no-op */
99
 
}
100
 
 
101
 
static int
102
 
get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
103
 
                        void *arg)
104
 
{
105
 
  *dyn_info_list_addr = _U_dyn_info_list_addr ();
106
 
  return 0;
107
 
}
108
 
 
109
 
static int
110
 
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
111
 
            void *arg)
112
 
{
113
 
  if (write)
114
 
    {
115
 
      Debug (12, "mem[%lx] <- %lx\n", addr, *val);
116
 
      *(unw_word_t *) addr = *val;
117
 
    }
118
 
  else
119
 
    {
120
 
      *val = *(unw_word_t *) addr;
121
 
      Debug (12, "mem[%lx] -> %lx\n", addr, *val);
122
 
    }
123
 
  return 0;
124
 
}
125
 
 
126
 
#ifdef HAVE_SYS_UC_ACCESS_H
127
 
 
128
 
#define SYSCALL_CFM_SAVE_REG    11 /* on a syscall, ar.pfs is saved in r11 */
129
 
#define REASON_SYSCALL          0
130
 
 
131
 
static int
132
 
access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
133
 
            void *arg)
134
 
{
135
 
  ucontext_t *uc = arg;
136
 
  unsigned int nat, mask;
137
 
  uint64_t value;
138
 
  uint16_t reason;
139
 
  int ret;
140
 
 
141
 
  __uc_get_reason (uc, &reason);
142
 
 
143
 
  switch (reg)
144
 
    {
145
 
    case UNW_IA64_GR  ... UNW_IA64_GR + 31:
146
 
      if ((ret = __uc_get_grs (uc, (reg - UNW_IA64_GR), 1, &value, &nat)))
147
 
        break;
148
 
 
149
 
      if (write)
150
 
        ret = __uc_set_grs (uc, (reg - UNW_IA64_GR), 1, val, nat);
151
 
      else
152
 
        *val = value;
153
 
      break;
154
 
 
155
 
    case UNW_IA64_NAT ... UNW_IA64_NAT + 31:
156
 
      if ((ret = __uc_get_grs (uc, (reg - UNW_IA64_GR), 1, &value, &nat)))
157
 
        break;
158
 
 
159
 
      mask = 1 << (reg - UNW_IA64_GR);
160
 
 
161
 
      if (write)
162
 
        {
163
 
          if (*val)
164
 
            nat |= mask;
165
 
          else
166
 
            nat &= ~mask;
167
 
          ret = __uc_set_grs (uc, (reg - UNW_IA64_GR), 1, &value, nat);
168
 
        }
169
 
      else
170
 
        *val = (nat & mask) != 0;
171
 
      break;
172
 
 
173
 
    case UNW_IA64_AR  ... UNW_IA64_AR + 127:
174
 
      if (reg == UNW_IA64_AR_BSP)
175
 
        {
176
 
          if (write)
177
 
            ret = __uc_set_ar (uc, (reg - UNW_IA64_AR), *val);
178
 
          else
179
 
            ret = __uc_get_ar (uc, (reg - UNW_IA64_AR), val);
180
 
        }
181
 
      else if (reg == UNW_IA64_AR_PFS && reason == REASON_SYSCALL)
182
 
        {
183
 
          /* As of HP-UX 11.22, getcontext() does not have unwind info
184
 
             and because of that, we need to hack thins manually here.
185
 
             Hopefully, this is OK because the HP-UX kernel also needs
186
 
             to know where AR.PFS has been saved, so the use of
187
 
             register r11 for this purpose is pretty much nailed
188
 
             down.  */
189
 
          if (write)
190
 
            ret = __uc_set_grs (uc, SYSCALL_CFM_SAVE_REG, 1, val, 0);
191
 
          else
192
 
            ret = __uc_get_grs (uc, SYSCALL_CFM_SAVE_REG, 1, val, &nat);
193
 
        }
194
 
      else
195
 
        {
196
 
          if (write)
197
 
            ret = __uc_set_ar (uc, (reg - UNW_IA64_AR), *val);
198
 
          else
199
 
            ret = __uc_get_ar (uc, (reg - UNW_IA64_AR), val);
200
 
        }
201
 
      break;
202
 
 
203
 
    case UNW_IA64_BR  ... UNW_IA64_BR + 7:
204
 
      if (write)
205
 
        ret = __uc_set_brs (uc, (reg - UNW_IA64_BR), 1, val);
206
 
      else
207
 
        ret = __uc_get_brs (uc, (reg - UNW_IA64_BR), 1, val);
208
 
      break;
209
 
 
210
 
    case UNW_IA64_PR:
211
 
      if (write)
212
 
        ret = __uc_set_prs (uc, *val);
213
 
      else
214
 
        ret = __uc_get_prs (uc, val);
215
 
      break;
216
 
 
217
 
    case UNW_IA64_IP:
218
 
      if (write)
219
 
        ret = __uc_set_ip (uc, *val);
220
 
      else
221
 
        ret = __uc_get_ip (uc, val);
222
 
      break;
223
 
 
224
 
    case UNW_IA64_CFM:
225
 
      if (write)
226
 
        ret = __uc_set_cfm (uc, *val);
227
 
      else
228
 
        ret = __uc_get_cfm (uc, val);
229
 
      break;
230
 
 
231
 
    case UNW_IA64_FR  ... UNW_IA64_FR + 127:
232
 
    default:
233
 
      ret = EINVAL;
234
 
      break;
235
 
    }
236
 
 
237
 
  if (ret != 0)
238
 
    {
239
 
      Debug (1, "failed to %s %s (ret = %d)\n",
240
 
             write ? "write" : "read", unw_regname (reg), ret);
241
 
      return -UNW_EBADREG;
242
 
    }
243
 
 
244
 
  if (write)
245
 
    Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
246
 
  else
247
 
    Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
248
 
  return 0;
249
 
}
250
 
 
251
 
static int
252
 
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
253
 
              int write, void *arg)
254
 
{
255
 
  ucontext_t *uc = arg;
256
 
  fp_regval_t fp_regval;
257
 
  int ret;
258
 
 
259
 
  switch (reg)
260
 
    {
261
 
    case UNW_IA64_FR  ... UNW_IA64_FR + 127:
262
 
      if (write)
263
 
        {
264
 
          memcpy (&fp_regval, val, sizeof (fp_regval));
265
 
          ret = __uc_set_frs (uc, (reg - UNW_IA64_FR), 1, &fp_regval);
266
 
        }
267
 
      else
268
 
        {
269
 
          ret = __uc_get_frs (uc, (reg - UNW_IA64_FR), 1, &fp_regval);
270
 
          memcpy (val, &fp_regval, sizeof (*val));
271
 
        }
272
 
      break;
273
 
 
274
 
    default:
275
 
      ret = EINVAL;
276
 
      break;
277
 
    }
278
 
  if (ret != 0)
279
 
    return -UNW_EBADREG;
280
 
 
281
 
  return 0;
282
 
}
283
 
 
284
 
#else /* !HAVE_SYS_UC_ACCESS_H */
285
 
 
286
 
static int
287
 
access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
288
 
            void *arg)
289
 
{
290
 
  unw_word_t *addr, mask;
291
 
  ucontext_t *uc = arg;
292
 
 
293
 
  if (reg >= UNW_IA64_NAT + 4 && reg <= UNW_IA64_NAT + 7)
294
 
    {
295
 
      mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
296
 
      if (write)
297
 
        {
298
 
          if (*val)
299
 
            uc->uc_mcontext.sc_nat |= mask;
300
 
          else
301
 
            uc->uc_mcontext.sc_nat &= ~mask;
302
 
        }
303
 
      else
304
 
        *val = (uc->uc_mcontext.sc_nat & mask) != 0;
305
 
 
306
 
      if (write)
307
 
        Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
308
 
      else
309
 
        Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
310
 
      return 0;
311
 
    }
312
 
 
313
 
  addr = tdep_uc_addr (uc, reg, NULL);
314
 
  if (!addr)
315
 
    goto badreg;
316
 
 
317
 
  if (write)
318
 
    {
319
 
      if (ia64_read_only_reg (addr))
320
 
        {
321
 
          Debug (16, "attempt to write read-only register\n");
322
 
          return -UNW_EREADONLYREG;
323
 
        }
324
 
      *addr = *val;
325
 
      Debug (12, "%s <- %lx\n", unw_regname (reg), *val);
326
 
    }
327
 
  else
328
 
    {
329
 
      *val = *(unw_word_t *) addr;
330
 
      Debug (12, "%s -> %lx\n", unw_regname (reg), *val);
331
 
    }
332
 
  return 0;
333
 
 
334
 
 badreg:
335
 
  Debug (1, "bad register number %u\n", reg);
336
 
  return -UNW_EBADREG;
337
 
}
338
 
 
339
 
static int
340
 
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
341
 
              int write, void *arg)
342
 
{
343
 
  ucontext_t *uc = arg;
344
 
  unw_fpreg_t *addr;
345
 
 
346
 
  if (reg < UNW_IA64_FR || reg >= UNW_IA64_FR + 128)
347
 
    goto badreg;
348
 
 
349
 
  addr = tdep_uc_addr (uc, reg, NULL);
350
 
  if (!addr)
351
 
    goto badreg;
352
 
 
353
 
  if (write)
354
 
    {
355
 
      if (ia64_read_only_reg (addr))
356
 
        {
357
 
          Debug (16, "attempt to write read-only register\n");
358
 
          return -UNW_EREADONLYREG;
359
 
        }
360
 
      *addr = *val;
361
 
      Debug (12, "%s <- %016lx.%016lx\n",
362
 
             unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
363
 
    }
364
 
  else
365
 
    {
366
 
      *val = *(unw_fpreg_t *) addr;
367
 
      Debug (12, "%s -> %016lx.%016lx\n",
368
 
             unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
369
 
    }
370
 
  return 0;
371
 
 
372
 
 badreg:
373
 
  Debug (1, "bad register number %u\n", reg);
374
 
  /* attempt to access a non-preserved register */
375
 
  return -UNW_EBADREG;
376
 
}
377
 
 
378
 
#endif /* !HAVE_SYS_UC_ACCESS_H */
379
 
 
380
 
static int
381
 
get_static_proc_name (unw_addr_space_t as, unw_word_t ip,
382
 
                      char *buf, size_t buf_len, unw_word_t *offp,
383
 
                      void *arg)
384
 
{
385
 
  return _Uelf64_get_proc_name (getpid (), ip, buf, buf_len, offp);
386
 
}
387
 
 
388
 
HIDDEN void
389
 
ia64_local_addr_space_init (void)
390
 
{
391
 
  memset (&local_addr_space, 0, sizeof (local_addr_space));
392
 
  local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
393
 
#if defined(__linux)
394
 
  local_addr_space.abi = ABI_LINUX;
395
 
#elif defined(__hpux)
396
 
  local_addr_space.abi = ABI_HPUX;
397
 
#endif
398
 
  local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
399
 
  local_addr_space.acc.find_proc_info = tdep_find_proc_info;
400
 
  local_addr_space.acc.put_unwind_info = put_unwind_info;
401
 
  local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
402
 
  local_addr_space.acc.access_mem = access_mem;
403
 
  local_addr_space.acc.access_reg = access_reg;
404
 
  local_addr_space.acc.access_fpreg = access_fpreg;
405
 
  local_addr_space.acc.resume = ia64_local_resume;
406
 
  local_addr_space.acc.get_proc_name = get_static_proc_name;
407
 
  unw_flush_cache (&local_addr_space, 0, 0);
408
 
}
409
 
 
410
 
#endif /* !UNW_REMOTE_ONLY */
411
 
 
412
 
#ifndef UNW_LOCAL_ONLY
413
 
 
414
 
HIDDEN int
415
 
ia64_uc_access_reg (struct cursor *c, ia64_loc_t loc, unw_word_t *valp,
416
 
                    int write)
417
 
{
418
 
#ifdef HAVE_SYS_UC_ACCESS_H
419
 
  unw_word_t uc_addr = IA64_GET_AUX_ADDR (loc);
420
 
  ucontext_t *ucp;
421
 
  int ret;
422
 
 
423
 
  Debug (16, "%s location %s\n",
424
 
         write ? "writing" : "reading", ia64_strloc (loc));
425
 
 
426
 
  if (c->as == unw_local_addr_space)
427
 
    ucp = (ucontext_t *) uc_addr;
428
 
  else
429
 
    {
430
 
      unw_word_t *dst, src;
431
 
 
432
 
      /* Need to copy-in ucontext_t first.  */
433
 
      ucp = alloca (sizeof (ucontext_t));
434
 
      if (!ucp)
435
 
        return -UNW_ENOMEM;
436
 
 
437
 
      /* For now, there is no non-HP-UX implementation of the
438
 
         uc_access(3) interface.  Because of that, we cannot, e.g.,
439
 
         unwind an HP-UX program from a Linux program.  Should that
440
 
         become possible at some point in the future, the
441
 
         copy-in/copy-out needs to be adjusted to do byte-swapping if
442
 
         necessary. */
443
 
      assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN));
444
 
 
445
 
      dst = (unw_word_t *) ucp;
446
 
      for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8)
447
 
        if ((ret = (*c->as->acc.access_mem) (c->as, src, dst++, 0, c->as_arg))
448
 
            < 0)
449
 
          return ret;
450
 
    }
451
 
 
452
 
  if (IA64_IS_REG_LOC (loc))
453
 
    ret = access_reg (unw_local_addr_space, IA64_GET_REG (loc), valp, write,
454
 
                      ucp);
455
 
  else
456
 
    {
457
 
      /* Must be an access to the RSE backing store in ucontext_t.  */
458
 
      unw_word_t addr = IA64_GET_ADDR (loc);
459
 
 
460
 
      if (write)
461
 
        ret = __uc_set_rsebs (ucp, (uint64_t *) addr, 1, valp);
462
 
      else
463
 
        ret = __uc_get_rsebs (ucp, (uint64_t *) addr, 1, valp);
464
 
      if (ret != 0)
465
 
        ret = -UNW_EBADREG;
466
 
    }
467
 
  if (ret < 0)
468
 
    return ret;
469
 
 
470
 
  if (write && c->as != unw_local_addr_space)
471
 
    {
472
 
      /* need to copy-out ucontext_t: */
473
 
      unw_word_t dst, *src = (unw_word_t *) ucp;
474
 
      for (dst = uc_addr; dst < uc_addr + sizeof (ucontext_t); dst += 8)
475
 
        if ((ret = (*c->as->acc.access_mem) (c->as, dst, src++, 1, c->as_arg))
476
 
            < 0)
477
 
          return ret;
478
 
    }
479
 
  return 0;
480
 
#else /* !HAVE_SYS_UC_ACCESS_H */
481
 
  return -UNW_EINVAL;
482
 
#endif /* !HAVE_SYS_UC_ACCESS_H */
483
 
}
484
 
 
485
 
HIDDEN int
486
 
ia64_uc_access_fpreg (struct cursor *c, ia64_loc_t loc, unw_fpreg_t *valp,
487
 
                      int write)
488
 
{
489
 
#ifdef HAVE_SYS_UC_ACCESS_H
490
 
  unw_word_t uc_addr = IA64_GET_AUX_ADDR (loc);
491
 
  ucontext_t *ucp;
492
 
  int ret;
493
 
 
494
 
  if (c->as == unw_local_addr_space)
495
 
    ucp = (ucontext_t *) uc_addr;
496
 
  else
497
 
    {
498
 
      unw_word_t *dst, src;
499
 
 
500
 
      /* Need to copy-in ucontext_t first.  */
501
 
      ucp = alloca (sizeof (ucontext_t));
502
 
      if (!ucp)
503
 
        return -UNW_ENOMEM;
504
 
 
505
 
      /* For now, there is no non-HP-UX implementation of the
506
 
         uc_access(3) interface.  Because of that, we cannot, e.g.,
507
 
         unwind an HP-UX program from a Linux program.  Should that
508
 
         become possible at some point in the future, the
509
 
         copy-in/copy-out needs to be adjusted to do byte-swapping if
510
 
         necessary. */
511
 
      assert (c->as->big_endian == (__BYTE_ORDER == __BIG_ENDIAN));
512
 
 
513
 
      dst = (unw_word_t *) ucp;
514
 
      for (src = uc_addr; src < uc_addr + sizeof (ucontext_t); src += 8)
515
 
        if ((ret = (*c->as->acc.access_mem) (c->as, src, dst++, 0, c->as_arg))
516
 
            < 0)
517
 
          return ret;
518
 
    }
519
 
 
520
 
  if ((ret = access_fpreg (unw_local_addr_space, IA64_GET_REG (loc), valp,
521
 
                           write, ucp)) < 0)
522
 
    return ret;
523
 
 
524
 
  if (write && c->as != unw_local_addr_space)
525
 
    {
526
 
      /* need to copy-out ucontext_t: */
527
 
      unw_word_t dst, *src = (unw_word_t *) ucp;
528
 
      for (dst = uc_addr; dst < uc_addr + sizeof (ucontext_t); dst += 8)
529
 
        if ((ret = (*c->as->acc.access_mem) (c->as, dst, src++, 1, c->as_arg))
530
 
            < 0)
531
 
          return ret;
532
 
    }
533
 
  return 0;
534
 
#else /* !HAVE_SYS_UC_ACCESS_H */
535
 
  return -UNW_EINVAL;
536
 
#endif /* !HAVE_SYS_UC_ACCESS_H */
537
 
}
538
 
 
539
 
#endif /* UNW_LOCAL_ONLY */