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

« back to all changes in this revision

Viewing changes to src/ia64/Gscript-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 "offsets.h"
27
 
#include "regs.h"
28
 
#include "unwind_i.h"
29
 
 
30
 
enum ia64_script_insn_opcode
31
 
  {
32
 
    IA64_INSN_INC_PSP,          /* psp += val */
33
 
    IA64_INSN_LOAD_PSP,         /* psp = *psp_loc */
34
 
    IA64_INSN_ADD_PSP,          /* s[dst] = (s.psp + val) */
35
 
    IA64_INSN_ADD_PSP_NAT,      /* like above, but with NaT info */
36
 
    IA64_INSN_ADD_SP,           /* s[dst] = (s.sp + val) */
37
 
    IA64_INSN_ADD_SP_NAT,       /* like above, but with NaT info */
38
 
    IA64_INSN_MOVE,             /* s[dst] = s[val] */
39
 
    IA64_INSN_MOVE_NAT,         /* like above, but with NaT info */
40
 
    IA64_INSN_MOVE_NO_NAT,      /* like above, but clear NaT info */
41
 
    IA64_INSN_MOVE_STACKED,     /* s[dst] = ia64_rse_skip(*s.bsp_loc, val) */
42
 
    IA64_INSN_MOVE_STACKED_NAT, /* like above, but with NaT info */
43
 
    IA64_INSN_MOVE_SCRATCH,     /* s[dst] = scratch reg "val" */
44
 
    IA64_INSN_MOVE_SCRATCH_NAT, /* like above, but with NaT info */
45
 
    IA64_INSN_MOVE_SCRATCH_NO_NAT /* like above, but clear NaT info */
46
 
  };
47
 
 
48
 
#ifdef HAVE___THREAD
49
 
static __thread struct ia64_script_cache ia64_per_thread_cache =
50
 
  {
51
 
#ifdef HAVE_ATOMIC_OPS_H
52
 
    .busy = AO_TS_INITIALIZER
53
 
#else
54
 
    .lock = PTHREAD_MUTEX_INITIALIZER
55
 
#endif
56
 
  };
57
 
#endif
58
 
 
59
 
static inline unw_hash_index_t
60
 
hash (unw_word_t ip)
61
 
{
62
 
  /* based on (sqrt(5)/2-1)*2^64 */
63
 
# define magic  ((unw_word_t) 0x9e3779b97f4a7c16ULL)
64
 
 
65
 
  return (ip >> 4) * magic >> (64 - IA64_LOG_UNW_HASH_SIZE);
66
 
}
67
 
 
68
 
static inline long
69
 
cache_match (struct ia64_script *script, unw_word_t ip, unw_word_t pr)
70
 
{
71
 
  if (ip == script->ip && ((pr ^ script->pr_val) & script->pr_mask) == 0)
72
 
    return 1;
73
 
  return 0;
74
 
}
75
 
 
76
 
static inline void
77
 
flush_script_cache (struct ia64_script_cache *cache)
78
 
{
79
 
  int i;
80
 
 
81
 
  cache->lru_head = IA64_UNW_CACHE_SIZE - 1;
82
 
  cache->lru_tail = 0;
83
 
 
84
 
  for (i = 0; i < IA64_UNW_CACHE_SIZE; ++i)
85
 
    {
86
 
      if (i > 0)
87
 
        cache->buckets[i].lru_chain = (i - 1);
88
 
      cache->buckets[i].coll_chain = -1;
89
 
      cache->buckets[i].ip = 0;
90
 
    }
91
 
  for (i = 0; i<IA64_UNW_HASH_SIZE; ++i)
92
 
    cache->hash[i] = -1;
93
 
}
94
 
 
95
 
static inline struct ia64_script_cache *
96
 
get_script_cache (unw_addr_space_t as, sigset_t *saved_sigmaskp)
97
 
{
98
 
  struct ia64_script_cache *cache = &as->global_cache;
99
 
  unw_caching_policy_t caching = as->caching_policy;
100
 
 
101
 
  if (caching == UNW_CACHE_NONE)
102
 
    return NULL;
103
 
 
104
 
#ifdef HAVE___THREAD
105
 
  if (as->caching_policy == UNW_CACHE_PER_THREAD)
106
 
    cache = &ia64_per_thread_cache;
107
 
#endif
108
 
 
109
 
#ifdef HAVE_ATOMIC_OPS_H
110
 
  if (AO_test_and_set (&cache->busy) == AO_TS_SET)
111
 
    return NULL;
112
 
#else
113
 
  sigprocmask (SIG_SETMASK, &unwi_full_sigmask, saved_sigmaskp);
114
 
  if (likely (caching == UNW_CACHE_GLOBAL))
115
 
    {
116
 
      Debug (16, "%s: acquiring lock\n");
117
 
      mutex_lock (&cache->lock);
118
 
    }
119
 
#endif
120
 
 
121
 
  if (as->cache_generation != cache->generation)
122
 
    {
123
 
      flush_script_cache (cache);
124
 
      cache->generation = as->cache_generation;
125
 
    }
126
 
  return cache;
127
 
}
128
 
 
129
 
static inline void
130
 
put_script_cache (unw_addr_space_t as, struct ia64_script_cache *cache,
131
 
                  sigset_t *saved_sigmaskp)
132
 
{
133
 
  assert (as->caching_policy != UNW_CACHE_NONE);
134
 
 
135
 
  Debug (16, "unmasking signals/releasing lock\n");
136
 
#ifdef HAVE_ATOMIC_OPS_H
137
 
  AO_CLEAR (&cache->busy);
138
 
#else
139
 
  if (likely (as->caching_policy == UNW_CACHE_GLOBAL))
140
 
    mutex_unlock (&cache->lock);
141
 
  sigprocmask (SIG_SETMASK, saved_sigmaskp, NULL);
142
 
#endif
143
 
}
144
 
 
145
 
static struct ia64_script *
146
 
script_lookup (struct ia64_script_cache *cache, struct cursor *c)
147
 
{
148
 
  struct ia64_script *script = cache->buckets + c->hint;
149
 
  unsigned short index;
150
 
  unw_word_t ip, pr;
151
 
 
152
 
  ip = c->ip;
153
 
  pr = c->pr;
154
 
 
155
 
  if (cache_match (script, ip, pr))
156
 
    return script;
157
 
 
158
 
  index = cache->hash[hash (ip)];
159
 
  if (index >= IA64_UNW_CACHE_SIZE)
160
 
    return 0;
161
 
 
162
 
  script = cache->buckets + index;
163
 
  while (1)
164
 
    {
165
 
      if (cache_match (script, ip, pr))
166
 
        {
167
 
          /* update hint; no locking needed: single-word writes are atomic */
168
 
          c->hint = cache->buckets[c->prev_script].hint =
169
 
            (script - cache->buckets);
170
 
          return script;
171
 
        }
172
 
      if (script->coll_chain >= IA64_UNW_HASH_SIZE)
173
 
        return 0;
174
 
      script = cache->buckets + script->coll_chain;
175
 
    }
176
 
}
177
 
 
178
 
HIDDEN int
179
 
ia64_get_cached_proc_info (struct cursor *c)
180
 
{
181
 
  struct ia64_script_cache *cache;
182
 
  struct ia64_script *script;
183
 
  sigset_t saved_sigmask;
184
 
 
185
 
  cache = get_script_cache (c->as, &saved_sigmask);
186
 
  if (!cache)
187
 
    return -UNW_ENOINFO;        /* cache is busy */
188
 
  {
189
 
    script = script_lookup (cache, c);
190
 
    if (script)
191
 
      c->pi = script->pi;
192
 
  }
193
 
  put_script_cache (c->as, cache, &saved_sigmask);
194
 
  return script ? 0 : -UNW_ENOINFO;
195
 
}
196
 
 
197
 
static inline void
198
 
script_init (struct ia64_script *script, unw_word_t ip)
199
 
{
200
 
  script->ip = ip;
201
 
  script->hint = 0;
202
 
  script->count = 0;
203
 
  script->abi_marker = 0;
204
 
}
205
 
 
206
 
static inline struct ia64_script *
207
 
script_new (struct ia64_script_cache *cache, unw_word_t ip)
208
 
{
209
 
  struct ia64_script *script, *prev, *tmp;
210
 
  unw_hash_index_t index;
211
 
  unsigned short head;
212
 
 
213
 
  head = cache->lru_head;
214
 
  script = cache->buckets + head;
215
 
  cache->lru_head = script->lru_chain;
216
 
 
217
 
  /* re-insert script at the tail of the LRU chain: */
218
 
  cache->buckets[cache->lru_tail].lru_chain = head;
219
 
  cache->lru_tail = head;
220
 
 
221
 
  /* remove the old script from the hash table (if it's there): */
222
 
  if (script->ip)
223
 
    {
224
 
      index = hash (script->ip);
225
 
      tmp = cache->buckets + cache->hash[index];
226
 
      prev = 0;
227
 
      while (1)
228
 
        {
229
 
          if (tmp == script)
230
 
            {
231
 
              if (prev)
232
 
                prev->coll_chain = tmp->coll_chain;
233
 
              else
234
 
                cache->hash[index] = tmp->coll_chain;
235
 
              break;
236
 
            }
237
 
          else
238
 
            prev = tmp;
239
 
          if (tmp->coll_chain >= IA64_UNW_CACHE_SIZE)
240
 
            /* old script wasn't in the hash-table */
241
 
            break;
242
 
          tmp = cache->buckets + tmp->coll_chain;
243
 
        }
244
 
    }
245
 
 
246
 
  /* enter new script in the hash table */
247
 
  index = hash (ip);
248
 
  script->coll_chain = cache->hash[index];
249
 
  cache->hash[index] = script - cache->buckets;
250
 
 
251
 
  script_init (script, ip);
252
 
  return script;
253
 
}
254
 
 
255
 
static inline void
256
 
script_finalize (struct ia64_script *script, struct cursor *c,
257
 
                 struct ia64_state_record *sr)
258
 
{
259
 
  script->pr_mask = sr->pr_mask;
260
 
  script->pr_val = sr->pr_val;
261
 
  script->pi = c->pi;
262
 
}
263
 
 
264
 
static inline void
265
 
script_emit (struct ia64_script *script, struct ia64_script_insn insn)
266
 
{
267
 
  if (script->count >= IA64_MAX_SCRIPT_LEN)
268
 
    {
269
 
      dprintf ("%s: script exceeds maximum size of %u instructions!\n",
270
 
               __FUNCTION__, IA64_MAX_SCRIPT_LEN);
271
 
      return;
272
 
    }
273
 
  script->insn[script->count++] = insn;
274
 
}
275
 
 
276
 
static void
277
 
compile_reg (struct ia64_state_record *sr, int i, struct ia64_reg_info *r,
278
 
             struct ia64_script *script)
279
 
{
280
 
  enum ia64_script_insn_opcode opc;
281
 
  unsigned long val, rval;
282
 
  struct ia64_script_insn insn;
283
 
  long is_preserved_gr;
284
 
 
285
 
  if (r->where == IA64_WHERE_NONE || r->when >= sr->when_target)
286
 
    return;
287
 
 
288
 
  opc = IA64_INSN_MOVE;
289
 
  val = rval = r->val;
290
 
  is_preserved_gr = (i >= IA64_REG_R4 && i <= IA64_REG_R7);
291
 
 
292
 
  if (r->where == IA64_WHERE_GR)
293
 
    {
294
 
      /* Handle most common case first... */
295
 
      if (rval >= 32)
296
 
        {
297
 
          /* register got spilled to a stacked register */
298
 
          if (is_preserved_gr)
299
 
            opc = IA64_INSN_MOVE_STACKED_NAT;
300
 
          else
301
 
            opc = IA64_INSN_MOVE_STACKED;
302
 
          val = rval;
303
 
        }
304
 
      else if (rval >= 4 && rval <= 7)
305
 
        {
306
 
          /* register got spilled to a preserved register */
307
 
          val = IA64_REG_R4 + (rval - 4);
308
 
          if (is_preserved_gr)
309
 
            opc = IA64_INSN_MOVE_NAT;
310
 
        }
311
 
      else
312
 
        {
313
 
          /* register got spilled to a scratch register */
314
 
          if (is_preserved_gr)
315
 
            opc = IA64_INSN_MOVE_SCRATCH_NAT;
316
 
          else
317
 
            opc = IA64_INSN_MOVE_SCRATCH;
318
 
          val = UNW_IA64_GR + rval;
319
 
        }
320
 
    }
321
 
  else
322
 
    {
323
 
      switch (r->where)
324
 
        {
325
 
        case IA64_WHERE_FR:
326
 
          /* Note: There is no need to handle NaT-bit info here
327
 
             (indepent of is_preserved_gr), because for floating-point
328
 
             NaTs are represented as NaTVal, so the NaT-info never
329
 
             needs to be consulated.  */
330
 
          if (rval >= 2 && rval <= 5)
331
 
            val = IA64_REG_F2 + (rval - 2);
332
 
          else if (rval >= 16 && rval <= 31)
333
 
            val = IA64_REG_F16 + (rval - 16);
334
 
          else
335
 
            {
336
 
              opc = IA64_INSN_MOVE_SCRATCH;
337
 
              val = UNW_IA64_FR + rval;
338
 
            }
339
 
          break;
340
 
 
341
 
        case IA64_WHERE_BR:
342
 
          if (rval >= 1 && rval <= 5)
343
 
            {
344
 
              val = IA64_REG_B1 + (rval - 1);
345
 
              if (is_preserved_gr)
346
 
                opc = IA64_INSN_MOVE_NO_NAT;
347
 
            }
348
 
          else
349
 
            {
350
 
              opc = IA64_INSN_MOVE_SCRATCH;
351
 
              if (is_preserved_gr)
352
 
                opc = IA64_INSN_MOVE_SCRATCH_NO_NAT;
353
 
              val = UNW_IA64_BR + rval;
354
 
            }
355
 
          break;
356
 
 
357
 
        case IA64_WHERE_SPREL:
358
 
          if (is_preserved_gr)
359
 
            opc = IA64_INSN_ADD_SP_NAT;
360
 
          else
361
 
            {
362
 
              opc = IA64_INSN_ADD_SP;
363
 
              if (i >= IA64_REG_F2 && i <= IA64_REG_F31)
364
 
                val |= IA64_LOC_TYPE_FP;
365
 
            }
366
 
          break;
367
 
 
368
 
        case IA64_WHERE_PSPREL:
369
 
          if (is_preserved_gr)
370
 
            opc = IA64_INSN_ADD_PSP_NAT;
371
 
          else
372
 
            {
373
 
              opc = IA64_INSN_ADD_PSP;
374
 
              if (i >= IA64_REG_F2 && i <= IA64_REG_F31)
375
 
                val |= IA64_LOC_TYPE_FP;
376
 
            }
377
 
          break;
378
 
 
379
 
        default:
380
 
          dprintf ("%s: register %u has unexpected `where' value of %u\n",
381
 
                   __FUNCTION__, i, r->where);
382
 
          break;
383
 
        }
384
 
    }
385
 
  insn.opc = opc;
386
 
  insn.dst = i;
387
 
  insn.val = val;
388
 
  script_emit (script, insn);
389
 
 
390
 
  if (i == IA64_REG_PSP)
391
 
    {
392
 
      /* c->psp must contain the _value_ of the previous sp, not it's
393
 
         save-location.  We get this by dereferencing the value we
394
 
         just stored in loc[IA64_REG_PSP]: */
395
 
      insn.opc = IA64_INSN_LOAD_PSP;
396
 
      script_emit (script, insn);
397
 
    }
398
 
}
399
 
 
400
 
/* Sort the registers which got saved in decreasing order of WHEN
401
 
   value.  This is needed to ensure that the save-locations are
402
 
   updated in the proper order.  For example, suppose r4 gets spilled
403
 
   to memory and then r5 gets saved in r4.  In this case, we need to
404
 
   update the save location of r5 before the one of r4.  */
405
 
 
406
 
static inline int
407
 
sort_regs (struct ia64_state_record *sr, int regorder[])
408
 
{
409
 
  int r, i, j, max, max_reg, max_when, num_regs = 0;
410
 
 
411
 
  assert (IA64_REG_BSP == 3);
412
 
 
413
 
  for (r = IA64_REG_BSP; r < IA64_NUM_PREGS; ++r)
414
 
    {
415
 
      if (sr->curr.reg[r].where == IA64_WHERE_NONE
416
 
          || sr->curr.reg[r].when >= sr->when_target)
417
 
        continue;
418
 
 
419
 
      regorder[num_regs++] = r;
420
 
    }
421
 
 
422
 
  /* Simple insertion-sort.  Involves about N^2/2 comparisons and N
423
 
     exchanges.  N is often small (say, 2-5) so a fancier sorting
424
 
     algorithm may not be worthwhile.  */
425
 
 
426
 
  for (i = max = 0; i < num_regs - 1; ++i)
427
 
    {
428
 
      max_reg = regorder[max];
429
 
      max_when = sr->curr.reg[max_reg].when;
430
 
 
431
 
      for (j = i + 1; j < num_regs; ++j)
432
 
        if (sr->curr.reg[regorder[j]].when > max_when)
433
 
          {
434
 
            max = j;
435
 
            max_reg = regorder[j];
436
 
            max_when = sr->curr.reg[max_reg].when;
437
 
          }
438
 
      if (i != max)
439
 
        {
440
 
          regorder[max] = regorder[i];
441
 
          regorder[i] = max_reg;
442
 
        }
443
 
    }
444
 
  return num_regs;
445
 
}
446
 
 
447
 
/* Build an unwind script that unwinds from state OLD_STATE to the
448
 
   entrypoint of the function that called OLD_STATE.  */
449
 
 
450
 
static inline int
451
 
build_script (struct cursor *c, struct ia64_script *script)
452
 
{
453
 
  int num_regs, i, ret, regorder[IA64_NUM_PREGS - 3];
454
 
  struct ia64_reg_info *pri_unat;
455
 
  struct ia64_state_record sr;
456
 
  struct ia64_script_insn insn;
457
 
 
458
 
  ret = ia64_create_state_record (c, &sr);
459
 
  if (ret < 0)
460
 
    return ret;
461
 
 
462
 
  /* First, compile the update for IA64_REG_PSP.  This is important
463
 
     because later save-locations may depend on it's correct (updated)
464
 
     value.  Fixed-size frames are handled specially and variable-size
465
 
     frames get handled via the normal compile_reg().  */
466
 
 
467
 
  if (sr.when_target > sr.curr.reg[IA64_REG_PSP].when
468
 
      && (sr.curr.reg[IA64_REG_PSP].where == IA64_WHERE_NONE)
469
 
      && sr.curr.reg[IA64_REG_PSP].val != 0)
470
 
    {
471
 
      /* new psp is psp plus frame size */
472
 
      insn.opc = IA64_INSN_INC_PSP;
473
 
      insn.val = sr.curr.reg[IA64_REG_PSP].val; /* frame size */
474
 
      script_emit (script, insn);
475
 
    }
476
 
  else
477
 
    compile_reg (&sr, IA64_REG_PSP, sr.curr.reg + IA64_REG_PSP, script);
478
 
 
479
 
  /* Second, compile the update for the primary UNaT, if any: */
480
 
 
481
 
  if (sr.when_target >= sr.curr.reg[IA64_REG_PRI_UNAT_GR].when
482
 
      || sr.when_target >= sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when)
483
 
    {
484
 
      if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_GR].when)
485
 
        /* (primary) NaT bits were saved to memory only */
486
 
        pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_MEM;
487
 
      else if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when)
488
 
        /* (primary) NaT bits were saved to a register only */
489
 
        pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_GR;
490
 
      else if (sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when >
491
 
               sr.curr.reg[IA64_REG_PRI_UNAT_GR].when)
492
 
        /* (primary) NaT bits were last saved to memory */
493
 
        pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_MEM;
494
 
      else
495
 
        /* (primary) NaT bits were last saved to a register */
496
 
        pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_GR;
497
 
 
498
 
      /* Note: we always store the final primary-UNaT location in UNAT_MEM.  */
499
 
      compile_reg (&sr, IA64_REG_PRI_UNAT_MEM, pri_unat, script);
500
 
    }
501
 
 
502
 
  /* Third, compile the other register in decreasing order of WHEN values.  */
503
 
 
504
 
  num_regs = sort_regs (&sr, regorder);
505
 
  for (i = 0; i < num_regs; ++i)
506
 
    compile_reg (&sr, regorder[i], sr.curr.reg + regorder[i], script);
507
 
 
508
 
  script->abi_marker = sr.abi_marker;
509
 
  script_finalize (script, c, &sr);
510
 
 
511
 
  ia64_free_state_record (&sr);
512
 
  return 0;
513
 
}
514
 
 
515
 
static inline void
516
 
set_nat_info (struct cursor *c, unsigned long dst,
517
 
              ia64_loc_t nat_loc, uint8_t bitnr)
518
 
{
519
 
  assert (dst >= IA64_REG_R4 && dst <= IA64_REG_R7);
520
 
 
521
 
  c->loc[dst - IA64_REG_R4 + IA64_REG_NAT4] = nat_loc;
522
 
  c->nat_bitnr[dst - IA64_REG_R4] = bitnr;
523
 
}
524
 
 
525
 
/* Apply the unwinding actions represented by OPS and update SR to
526
 
   reflect the state that existed upon entry to the function that this
527
 
   unwinder represents.  */
528
 
 
529
 
static inline int
530
 
run_script (struct ia64_script *script, struct cursor *c)
531
 
{
532
 
  struct ia64_script_insn *ip, *limit, next_insn;
533
 
  ia64_loc_t loc, nat_loc;
534
 
  unsigned long opc, dst;
535
 
  uint8_t nat_bitnr;
536
 
  unw_word_t val;
537
 
  int ret;
538
 
 
539
 
  c->pi = script->pi;
540
 
  ip = script->insn;
541
 
  limit = script->insn + script->count;
542
 
  next_insn = *ip;
543
 
  c->abi_marker = script->abi_marker;
544
 
 
545
 
  while (ip++ < limit)
546
 
    {
547
 
      opc = next_insn.opc;
548
 
      dst = next_insn.dst;
549
 
      val = next_insn.val;
550
 
      next_insn = *ip;
551
 
 
552
 
      /* This is by far the most common operation: */
553
 
      if (likely (opc == IA64_INSN_MOVE_STACKED))
554
 
        {
555
 
          if ((ret = ia64_get_stacked (c, val, &loc, NULL)) < 0)
556
 
            return ret;
557
 
        }
558
 
      else
559
 
        switch (opc)
560
 
          {
561
 
          case IA64_INSN_INC_PSP:
562
 
            c->psp += val;
563
 
            continue;
564
 
 
565
 
          case IA64_INSN_LOAD_PSP:
566
 
            if ((ret = ia64_get (c, c->loc[IA64_REG_PSP], &c->psp)) < 0)
567
 
              return ret;
568
 
            continue;
569
 
 
570
 
          case IA64_INSN_ADD_PSP:
571
 
            loc = IA64_LOC_ADDR (c->psp + val, (val & IA64_LOC_TYPE_FP));
572
 
            break;
573
 
 
574
 
          case IA64_INSN_ADD_SP:
575
 
            loc = IA64_LOC_ADDR (c->sp + val, (val & IA64_LOC_TYPE_FP));
576
 
            break;
577
 
 
578
 
          case IA64_INSN_MOVE_NO_NAT:
579
 
            set_nat_info (c, dst, IA64_NULL_LOC, 0);
580
 
          case IA64_INSN_MOVE:
581
 
            loc = c->loc[val];
582
 
            break;
583
 
 
584
 
          case IA64_INSN_MOVE_SCRATCH_NO_NAT:
585
 
            set_nat_info (c, dst, IA64_NULL_LOC, 0);
586
 
          case IA64_INSN_MOVE_SCRATCH:
587
 
            loc = ia64_scratch_loc (c, val, NULL);
588
 
            break;
589
 
 
590
 
          case IA64_INSN_ADD_PSP_NAT:
591
 
            loc = IA64_LOC_ADDR (c->psp + val, 0);
592
 
            assert (!IA64_IS_REG_LOC (loc));
593
 
            set_nat_info (c, dst,
594
 
                          c->loc[IA64_REG_PRI_UNAT_MEM],
595
 
                          ia64_unat_slot_num (IA64_GET_ADDR (loc)));
596
 
            break;
597
 
 
598
 
          case IA64_INSN_ADD_SP_NAT:
599
 
            loc = IA64_LOC_ADDR (c->sp + val, 0);
600
 
            assert (!IA64_IS_REG_LOC (loc));
601
 
            set_nat_info (c, dst,
602
 
                          c->loc[IA64_REG_PRI_UNAT_MEM],
603
 
                          ia64_unat_slot_num (IA64_GET_ADDR (loc)));
604
 
            break;
605
 
 
606
 
          case IA64_INSN_MOVE_NAT:
607
 
            loc = c->loc[val];
608
 
            set_nat_info (c, dst,
609
 
                          c->loc[val - IA64_REG_R4 + IA64_REG_NAT4],
610
 
                          c->nat_bitnr[val - IA64_REG_R4]);
611
 
            break;
612
 
 
613
 
          case IA64_INSN_MOVE_STACKED_NAT:
614
 
            if ((ret = ia64_get_stacked (c, val, &loc, &nat_loc)) < 0)
615
 
              return ret;
616
 
            assert (!IA64_IS_REG_LOC (loc));
617
 
            set_nat_info (c, dst,
618
 
                          nat_loc, ia64_rse_slot_num (IA64_GET_ADDR (loc)));
619
 
            break;
620
 
 
621
 
          case IA64_INSN_MOVE_SCRATCH_NAT:
622
 
            loc = ia64_scratch_loc (c, val, NULL);
623
 
            nat_loc = ia64_scratch_loc (c, val + (UNW_IA64_NAT - UNW_IA64_GR),
624
 
                                        &nat_bitnr);
625
 
            set_nat_info (c, dst, nat_loc, nat_bitnr);
626
 
            break;
627
 
          }
628
 
      c->loc[dst] = loc;
629
 
    }
630
 
  return 0;
631
 
}
632
 
 
633
 
static int
634
 
uncached_find_save_locs (struct cursor *c)
635
 
{
636
 
  struct ia64_script script;
637
 
  int ret = 0;
638
 
 
639
 
  if ((ret = ia64_fetch_proc_info (c, c->ip, 1)) < 0)
640
 
    return ret;
641
 
 
642
 
  script_init (&script, c->ip);
643
 
  if ((ret = build_script (c, &script)) < 0)
644
 
    {
645
 
      if (ret != -UNW_ESTOPUNWIND)
646
 
        dprintf ("%s: failed to build unwind script for ip %lx\n",
647
 
                 __FUNCTION__, (long) c->ip);
648
 
      return ret;
649
 
    }
650
 
  return run_script (&script, c);
651
 
}
652
 
 
653
 
HIDDEN int
654
 
ia64_find_save_locs (struct cursor *c)
655
 
{
656
 
  struct ia64_script_cache *cache = NULL;
657
 
  struct ia64_script *script = NULL;
658
 
  sigset_t saved_sigmask;
659
 
  int ret = 0;
660
 
 
661
 
  if (c->as->caching_policy == UNW_CACHE_NONE)
662
 
    return uncached_find_save_locs (c);
663
 
 
664
 
  cache = get_script_cache (c->as, &saved_sigmask);
665
 
  if (!cache)
666
 
    {
667
 
      Debug (1, "contention on script-cache; doing uncached lookup\n");
668
 
      return uncached_find_save_locs (c);
669
 
    }
670
 
  {
671
 
    script = script_lookup (cache, c);
672
 
    Debug (8, "ip %lx %s in script cache\n", (long) c->ip,
673
 
           script ? "hit" : "missed");
674
 
    if (!script)
675
 
      {
676
 
        if ((ret = ia64_fetch_proc_info (c, c->ip, 1)) < 0)
677
 
          goto out;
678
 
 
679
 
        script = script_new (cache, c->ip);
680
 
        if (!script)
681
 
          {
682
 
            dprintf ("%s: failed to create unwind script\n", __FUNCTION__);
683
 
            ret = -UNW_EUNSPEC;
684
 
            goto out;
685
 
          }
686
 
        cache->buckets[c->prev_script].hint = script - cache->buckets;
687
 
 
688
 
        ret = build_script (c, script);
689
 
      }
690
 
    c->hint = script->hint;
691
 
    c->prev_script = script - cache->buckets;
692
 
 
693
 
    if (ret < 0)
694
 
      {
695
 
        if (ret != -UNW_ESTOPUNWIND)
696
 
          dprintf ("%s: failed to locate/build unwind script for ip %lx\n",
697
 
                   __FUNCTION__, (long) c->ip);
698
 
        goto out;
699
 
      }
700
 
 
701
 
    ret = run_script (script, c);
702
 
  }
703
 
 out:
704
 
  put_script_cache (c->as, cache, &saved_sigmask);
705
 
  return ret;
706
 
}
707
 
 
708
 
HIDDEN void
709
 
ia64_validate_cache (unw_addr_space_t as, void *arg)
710
 
{
711
 
#ifndef UNW_REMOTE_ONLY
712
 
  if (as == unw_local_addr_space && ia64_local_validate_cache (as, arg) == 1)
713
 
    return;
714
 
#endif
715
 
 
716
 
#ifndef UNW_LOCAL_ONLY
717
 
  /* local info is up-to-date, check dynamic info.  */
718
 
  unwi_dyn_validate_cache (as, arg);
719
 
#endif
720
 
}