Back to index

plt-scheme  4.2.1
libunwind.c
Go to the documentation of this file.
00001 /* libunwind - a platform-independent unwind library
00002    Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
00003        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
00004 
00005 This file is several parts of libunwind concatenated.
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining
00008 a copy of this software and associated documentation files (the
00009 "Software"), to deal in the Software without restriction, including
00010 without limitation the rights to use, copy, modify, merge, publish,
00011 distribute, sublicense, and/or sell copies of the Software, and to
00012 permit persons to whom the Software is furnished to do so, subject to
00013 the following conditions:
00014 
00015 The above copyright notice and this permission notice shall be
00016 included in all copies or substantial portions of the Software.
00017 
00018 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00019 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00021 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00022 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00023 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00024 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
00025 
00026 #include "../../sconfig.h"
00027 
00028 #ifdef MZ_USE_DWARF_LIBUNWIND
00029 
00030 #include <stddef.h>
00031 #include "libunwind_i.h"
00032 
00033 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
00034 /*                             Gexpr.c                                */
00035 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
00036 
00037 /* The "pick" operator provides an index range of 0..255 indicating
00038    that the stack could at least have a depth of up to 256 elements,
00039    but the GCC unwinder restricts the depth to 64, which seems
00040    reasonable so we use the same value here.  */
00041 #define MAX_EXPR_STACK_SIZE 64
00042 
00043 #define NUM_OPERANDS(signature)    (((signature) >> 6) & 0x3)
00044 #define OPND1_TYPE(signature)      (((signature) >> 3) & 0x7)
00045 #define OPND2_TYPE(signature)      (((signature) >> 0) & 0x7)
00046 
00047 #define OPND_SIGNATURE(n, t1, t2) (((n) << 6) | ((t1) << 3) | ((t2) << 0))
00048 #define OPND1(t1)           OPND_SIGNATURE(1, t1, 0)
00049 #define OPND2(t1, t2)              OPND_SIGNATURE(2, t1, t2)
00050 
00051 #define VAL8  0x0
00052 #define VAL16 0x1
00053 #define VAL32 0x2
00054 #define VAL64 0x3
00055 #define ULEB128      0x4
00056 #define SLEB128      0x5
00057 #define OFFSET       0x6    /* 32-bit offset for 32-bit DWARF, 64-bit otherwise */
00058 
00059 static uint8_t operands[256] =
00060   {
00061     [DW_OP_addr] =   OPND1 (sizeof (unw_word_t) == 4 ? VAL32 : VAL64),
00062     [DW_OP_const1u] =              OPND1 (VAL8),
00063     [DW_OP_const1s] =              OPND1 (VAL8),
00064     [DW_OP_const2u] =              OPND1 (VAL16),
00065     [DW_OP_const2s] =              OPND1 (VAL16),
00066     [DW_OP_const4u] =              OPND1 (VAL32),
00067     [DW_OP_const4s] =              OPND1 (VAL32),
00068     [DW_OP_const8u] =              OPND1 (VAL64),
00069     [DW_OP_const8s] =              OPND1 (VAL64),
00070     [DW_OP_pick] =          OPND1 (VAL8),
00071     [DW_OP_plus_uconst] =   OPND1 (ULEB128),
00072     [DW_OP_skip] =          OPND1 (VAL16),
00073     [DW_OP_bra] =           OPND1 (VAL16),
00074     [DW_OP_breg0 +  0] =    OPND1 (SLEB128),
00075     [DW_OP_breg0 +  1] =    OPND1 (SLEB128),
00076     [DW_OP_breg0 +  2] =    OPND1 (SLEB128),
00077     [DW_OP_breg0 +  3] =    OPND1 (SLEB128),
00078     [DW_OP_breg0 +  4] =    OPND1 (SLEB128),
00079     [DW_OP_breg0 +  5] =    OPND1 (SLEB128),
00080     [DW_OP_breg0 +  6] =    OPND1 (SLEB128),
00081     [DW_OP_breg0 +  7] =    OPND1 (SLEB128),
00082     [DW_OP_breg0 +  8] =    OPND1 (SLEB128),
00083     [DW_OP_breg0 +  9] =    OPND1 (SLEB128),
00084     [DW_OP_breg0 + 10] =    OPND1 (SLEB128),
00085     [DW_OP_breg0 + 11] =    OPND1 (SLEB128),
00086     [DW_OP_breg0 + 12] =    OPND1 (SLEB128),
00087     [DW_OP_breg0 + 13] =    OPND1 (SLEB128),
00088     [DW_OP_breg0 + 14] =    OPND1 (SLEB128),
00089     [DW_OP_breg0 + 15] =    OPND1 (SLEB128),
00090     [DW_OP_breg0 + 16] =    OPND1 (SLEB128),
00091     [DW_OP_breg0 + 17] =    OPND1 (SLEB128),
00092     [DW_OP_breg0 + 18] =    OPND1 (SLEB128),
00093     [DW_OP_breg0 + 19] =    OPND1 (SLEB128),
00094     [DW_OP_breg0 + 20] =    OPND1 (SLEB128),
00095     [DW_OP_breg0 + 21] =    OPND1 (SLEB128),
00096     [DW_OP_breg0 + 22] =    OPND1 (SLEB128),
00097     [DW_OP_breg0 + 23] =    OPND1 (SLEB128),
00098     [DW_OP_breg0 + 24] =    OPND1 (SLEB128),
00099     [DW_OP_breg0 + 25] =    OPND1 (SLEB128),
00100     [DW_OP_breg0 + 26] =    OPND1 (SLEB128),
00101     [DW_OP_breg0 + 27] =    OPND1 (SLEB128),
00102     [DW_OP_breg0 + 28] =    OPND1 (SLEB128),
00103     [DW_OP_breg0 + 29] =    OPND1 (SLEB128),
00104     [DW_OP_breg0 + 30] =    OPND1 (SLEB128),
00105     [DW_OP_breg0 + 31] =    OPND1 (SLEB128),
00106     [DW_OP_regx] =          OPND1 (ULEB128),
00107     [DW_OP_fbreg] =         OPND1 (SLEB128),
00108     [DW_OP_bregx] =         OPND2 (ULEB128, SLEB128),
00109     [DW_OP_piece] =         OPND1 (ULEB128),
00110     [DW_OP_deref_size] =    OPND1 (VAL8),
00111     [DW_OP_xderef_size] =   OPND1 (VAL8),
00112     [DW_OP_call2] =         OPND1 (VAL16),
00113     [DW_OP_call4] =         OPND1 (VAL32),
00114     [DW_OP_call_ref] =             OPND1 (OFFSET)
00115   };
00116 
00117 #define sword(X)     ((unw_sword_t) (X))
00118 
00119 static inline unw_word_t
00120 read_operand (unw_addr_space_t as, unw_accessors_t *a,
00121              unw_word_t *addr, int operand_type, unw_word_t *val, void *arg)
00122 {
00123   uint8_t u8;
00124   uint16_t u16;
00125   uint32_t u32;
00126   uint64_t u64;
00127   int ret;
00128 
00129   switch (operand_type)
00130     {
00131     case VAL8:
00132       ret = dwarf_readu8 (as, a, addr, &u8, arg);
00133       *val = u8;
00134       break;
00135 
00136     case VAL16:
00137       ret = dwarf_readu16 (as, a, addr, &u16, arg);
00138       *val = u16;
00139       break;
00140 
00141     case VAL32:
00142       ret = dwarf_readu32 (as, a, addr, &u32, arg);
00143       *val = u32;
00144       break;
00145 
00146     case VAL64:
00147       ret = dwarf_readu64 (as, a, addr, &u64, arg);
00148       *val = u64;
00149       break;
00150 
00151     case ULEB128:
00152       ret = dwarf_read_uleb128 (as, a, addr, val, arg);
00153       break;
00154 
00155     case SLEB128:
00156       ret = dwarf_read_sleb128 (as, a, addr, val, arg);
00157       break;
00158 
00159     case OFFSET: /* only used by DW_OP_call_ref, which we don't implement */
00160     default:
00161       Debug (1, "Unexpected operand type %d\n", operand_type);
00162       ret = -UNW_EINVAL;
00163     }
00164   return ret;
00165 }
00166 
00167 HIDDEN int
00168 dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, unw_word_t len,
00169                unw_word_t *valp, int *is_register)
00170 {
00171   unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2, tmp3, end_addr;
00172   uint8_t opcode, operands_signature, u8;
00173   unw_addr_space_t as;
00174   unw_accessors_t *a;
00175   void *arg;
00176   unw_word_t stack[MAX_EXPR_STACK_SIZE];
00177   unsigned int tos = 0;
00178   uint16_t u16;
00179   uint32_t u32;
00180   uint64_t u64;
00181   int ret;
00182 # define pop()                                   \
00183 ({                                        \
00184   if ((tos - 1) >= MAX_EXPR_STACK_SIZE)          \
00185     {                                     \
00186       Debug (1, "Stack underflow\n");            \
00187       return -UNW_EINVAL;                 \
00188     }                                     \
00189   stack[--tos];                                  \
00190 })
00191 # define push(x)                          \
00192 do {                                      \
00193   if (tos >= MAX_EXPR_STACK_SIZE)         \
00194     {                                     \
00195       Debug (1, "Stack overflow\n");             \
00196       return -UNW_EINVAL;                 \
00197     }                                     \
00198   stack[tos++] = (x);                            \
00199 } while (0)
00200 # define pick(n)                          \
00201 ({                                        \
00202   unsigned int _index = tos - 1 - (n);           \
00203   if (_index >= MAX_EXPR_STACK_SIZE)             \
00204     {                                     \
00205       Debug (1, "Out-of-stack pick\n");          \
00206       return -UNW_EINVAL;                 \
00207     }                                     \
00208   stack[_index];                          \
00209 })
00210 
00211   as = c->as;
00212   arg = c->as_arg;
00213   a = unw_get_accessors (as);
00214   end_addr = *addr + len;
00215   *is_register = 0;
00216 
00217   Debug (14, "len=%lu, pushing cfa=0x%lx\n",
00218         (unsigned long) len, (unsigned long) c->cfa);
00219 
00220   push (c->cfa);     /* push current CFA as required by DWARF spec */
00221 
00222   while (*addr < end_addr)
00223     {
00224       if ((ret = dwarf_readu8 (as, a, addr, &opcode, arg)) < 0)
00225        return ret;
00226 
00227       operands_signature = operands[opcode];
00228 
00229       if (unlikely (NUM_OPERANDS (operands_signature) > 0))
00230        {
00231          if ((ret = read_operand (as, a, addr,
00232                                OPND1_TYPE (operands_signature),
00233                                &operand1, arg)) < 0)
00234            return ret;
00235          if (NUM_OPERANDS (operands_signature > 1))
00236            if ((ret = read_operand (as, a, addr,
00237                                  OPND2_TYPE (operands_signature),
00238                                  &operand2, arg)) < 0)
00239              return ret;
00240        }
00241 
00242       switch ((dwarf_expr_op_t) opcode)
00243        {
00244        case DW_OP_lit0:  case DW_OP_lit1:  case DW_OP_lit2:
00245        case DW_OP_lit3:  case DW_OP_lit4:  case DW_OP_lit5:
00246        case DW_OP_lit6:  case DW_OP_lit7:  case DW_OP_lit8:
00247        case DW_OP_lit9:  case DW_OP_lit10: case DW_OP_lit11:
00248        case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14:
00249        case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17:
00250        case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20:
00251        case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23:
00252        case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26:
00253        case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29:
00254        case DW_OP_lit30: case DW_OP_lit31:
00255          Debug (15, "OP_lit(%d)\n", (int) opcode - DW_OP_lit0);
00256          push (opcode - DW_OP_lit0);
00257          break;
00258 
00259        case DW_OP_breg0:  case DW_OP_breg1:  case DW_OP_breg2:
00260        case DW_OP_breg3:  case DW_OP_breg4:  case DW_OP_breg5:
00261        case DW_OP_breg6:  case DW_OP_breg7:  case DW_OP_breg8:
00262        case DW_OP_breg9:  case DW_OP_breg10: case DW_OP_breg11:
00263        case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14:
00264        case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17:
00265        case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20:
00266        case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
00267        case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26:
00268        case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29:
00269        case DW_OP_breg30: case DW_OP_breg31:
00270          Debug (15, "OP_breg(r%d,0x%lx)\n",
00271                (int) opcode - DW_OP_breg0, (unsigned long) operand1);
00272          if ((ret = unw_get_reg (dwarf_to_cursor (c),
00273                               dwarf_to_unw_regnum (opcode - DW_OP_breg0),
00274                               &tmp1)) < 0)
00275            return ret;
00276          push (tmp1 + operand1);
00277          break;
00278 
00279        case DW_OP_bregx:
00280          Debug (15, "OP_bregx(r%d,0x%lx)\n",
00281                (int) operand1, (unsigned long) operand2);
00282          if ((ret = unw_get_reg (dwarf_to_cursor (c),
00283                               dwarf_to_unw_regnum (operand1), &tmp1)) < 0)
00284            return ret;
00285          push (tmp1 + operand2);
00286          break;
00287 
00288        case DW_OP_reg0:  case DW_OP_reg1:  case DW_OP_reg2:
00289        case DW_OP_reg3:  case DW_OP_reg4:  case DW_OP_reg5:
00290        case DW_OP_reg6:  case DW_OP_reg7:  case DW_OP_reg8:
00291        case DW_OP_reg9:  case DW_OP_reg10: case DW_OP_reg11:
00292        case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14:
00293        case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17:
00294        case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20:
00295        case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23:
00296        case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26:
00297        case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29:
00298        case DW_OP_reg30: case DW_OP_reg31:
00299          Debug (15, "OP_reg(r%d)\n", (int) opcode - DW_OP_reg0);
00300          *valp = dwarf_to_unw_regnum (opcode - DW_OP_reg0);
00301          *is_register = 1;
00302          return 0;
00303 
00304        case DW_OP_regx:
00305          Debug (15, "OP_regx(r%d)\n", (int) operand1);
00306          *valp = dwarf_to_unw_regnum (operand1);
00307          *is_register = 1;
00308          return 0;
00309 
00310        case DW_OP_addr:
00311        case DW_OP_const1u:
00312        case DW_OP_const2u:
00313        case DW_OP_const4u:
00314        case DW_OP_const8u:
00315        case DW_OP_constu:
00316        case DW_OP_const8s:
00317        case DW_OP_consts:
00318          Debug (15, "OP_const(0x%lx)\n", (unsigned long) operand1);
00319          push (operand1);
00320          break;
00321 
00322        case DW_OP_const1s:
00323          if (operand1 & 0x80)
00324            operand1 |= ((unw_word_t) -1) << 8;
00325          Debug (15, "OP_const1s(%ld)\n", (long) operand1);
00326          push (operand1);
00327          break;
00328 
00329        case DW_OP_const2s:
00330          if (operand1 & 0x8000)
00331            operand1 |= ((unw_word_t) -1) << 16;
00332          Debug (15, "OP_const2s(%ld)\n", (long) operand1);
00333          push (operand1);
00334          break;
00335 
00336        case DW_OP_const4s:
00337          if (operand1 & 0x80000000)
00338            operand1 |= (((unw_word_t) -1) << 16) << 16;
00339          Debug (15, "OP_const4s(%ld)\n", (long) operand1);
00340          push (operand1);
00341          break;
00342 
00343        case DW_OP_deref:
00344          Debug (15, "OP_deref\n");
00345          tmp1 = pop ();
00346          if ((ret = dwarf_readw (as, a, &tmp1, &tmp2, arg)) < 0)
00347            return ret;
00348          push (tmp2);
00349          break;
00350 
00351        case DW_OP_deref_size:
00352          Debug (15, "OP_deref_size(%d)\n", (int) operand1);
00353          tmp1 = pop ();
00354          switch (operand1)
00355            {
00356             default:
00357            case 0:
00358               tmp2 = 0;
00359              break;
00360 
00361            case 1:
00362              if ((ret = dwarf_readu8 (as, a, &tmp1, &u8, arg)) < 0)
00363               return ret;
00364              tmp2 = u8;
00365              break;
00366 
00367            case 2:
00368              if ((ret = dwarf_readu16 (as, a, &tmp1, &u16, arg)) < 0)
00369               return ret;
00370              tmp2 = u16;
00371              break;
00372 
00373            case 3:
00374            case 4:
00375              if ((ret = dwarf_readu32 (as, a, &tmp1, &u32, arg)) < 0)
00376               return ret;
00377              tmp2 = u32;
00378              if (operand1 == 3)
00379               {
00380                 if (dwarf_is_big_endian (as))
00381                   tmp2 >>= 8;
00382                 else
00383                   tmp2 &= 0xffffff;
00384               }
00385              break;
00386            case 5:
00387            case 6:
00388            case 7:
00389            case 8:
00390              if ((ret = dwarf_readu64 (as, a, &tmp1, &u64, arg)) < 0)
00391               return ret;
00392              tmp2 = u64;
00393              if (operand1 != 8)
00394               {
00395                 if (dwarf_is_big_endian (as))
00396                   tmp2 >>= 64 - 8 * operand1;
00397                 else
00398                   tmp2 &= (~ (unw_word_t) 0) << (8 * operand1);
00399               }
00400              break;
00401            }
00402          push (tmp2);
00403          break;
00404 
00405        case DW_OP_dup:
00406          Debug (15, "OP_dup\n");
00407          push (pick (0));
00408          break;
00409 
00410        case DW_OP_drop:
00411          Debug (15, "OP_drop\n");
00412          pop ();
00413          break;
00414 
00415        case DW_OP_pick:
00416          Debug (15, "OP_pick(%d)\n", (int) operand1);
00417          push (pick (operand1));
00418          break;
00419 
00420        case DW_OP_over:
00421          Debug (15, "OP_over\n");
00422          push (pick (1));
00423          break;
00424 
00425        case DW_OP_swap:
00426          Debug (15, "OP_swap\n");
00427          tmp1 = pop ();
00428          tmp2 = pop ();
00429          push (tmp1);
00430          push (tmp2);
00431          break;
00432 
00433        case DW_OP_rot:
00434          Debug (15, "OP_rot\n");
00435          tmp1 = pop ();
00436          tmp2 = pop ();
00437          tmp3 = pop ();
00438          push (tmp1);
00439          push (tmp3);
00440          push (tmp2);
00441          break;
00442 
00443        case DW_OP_abs:
00444          Debug (15, "OP_abs\n");
00445          tmp1 = pop ();
00446          if (tmp1 & ((unw_word_t) 1 << (8 * sizeof (unw_word_t) - 1)))
00447            tmp1 = -tmp1;
00448          push (tmp1);
00449          break;
00450 
00451        case DW_OP_and:
00452          Debug (15, "OP_and\n");
00453          tmp1 = pop ();
00454          tmp2 = pop ();
00455          push (tmp1 & tmp2);
00456          break;
00457 
00458        case DW_OP_div:
00459          Debug (15, "OP_div\n");
00460          tmp1 = pop ();
00461          tmp2 = pop ();
00462          if (tmp1)
00463            tmp1 = sword (tmp2) / sword (tmp1);
00464          push (tmp1);
00465          break;
00466 
00467        case DW_OP_minus:
00468          Debug (15, "OP_minus\n");
00469          tmp1 = pop ();
00470          tmp2 = pop ();
00471          tmp1 = tmp2 - tmp1;
00472          push (tmp1);
00473          break;
00474 
00475        case DW_OP_mod:
00476          Debug (15, "OP_mod\n");
00477          tmp1 = pop ();
00478          tmp2 = pop ();
00479          if (tmp1)
00480            tmp1 = tmp2 % tmp1;
00481          push (tmp1);
00482          break;
00483 
00484        case DW_OP_mul:
00485          Debug (15, "OP_mul\n");
00486          tmp1 = pop ();
00487          tmp2 = pop ();
00488          if (tmp1)
00489            tmp1 = tmp2 * tmp1;
00490          push (tmp1);
00491          break;
00492 
00493        case DW_OP_neg:
00494          Debug (15, "OP_neg\n");
00495          push (-pop ());
00496          break;
00497 
00498        case DW_OP_not:
00499          Debug (15, "OP_not\n");
00500          push (~pop ());
00501          break;
00502 
00503        case DW_OP_or:
00504          Debug (15, "OP_or\n");
00505          tmp1 = pop ();
00506          tmp2 = pop ();
00507          push (tmp1 | tmp2);
00508          break;
00509 
00510        case DW_OP_plus:
00511          Debug (15, "OP_plus\n");
00512          tmp1 = pop ();
00513          tmp2 = pop ();
00514          push (tmp1 + tmp2);
00515          break;
00516 
00517        case DW_OP_plus_uconst:
00518          Debug (15, "OP_plus_uconst(%lu)\n", (unsigned long) operand1);
00519          tmp1 = pop ();
00520          push (tmp1 + operand1);
00521          break;
00522 
00523        case DW_OP_shl:
00524          Debug (15, "OP_shl\n");
00525          tmp1 = pop ();
00526          tmp2 = pop ();
00527          push (tmp2 << tmp1);
00528          break;
00529 
00530        case DW_OP_shr:
00531          Debug (15, "OP_shr\n");
00532          tmp1 = pop ();
00533          tmp2 = pop ();
00534          push (tmp2 >> tmp1);
00535          break;
00536 
00537        case DW_OP_shra:
00538          Debug (15, "OP_shra\n");
00539          tmp1 = pop ();
00540          tmp2 = pop ();
00541          push (sword (tmp2) >> tmp1);
00542          break;
00543 
00544        case DW_OP_xor:
00545          Debug (15, "OP_xor\n");
00546          tmp1 = pop ();
00547          tmp2 = pop ();
00548          push (tmp1 ^ tmp2);
00549          break;
00550 
00551        case DW_OP_le:
00552          Debug (15, "OP_le\n");
00553          tmp1 = pop ();
00554          tmp2 = pop ();
00555          push (sword (tmp1) <= sword (tmp2));
00556          break;
00557 
00558        case DW_OP_ge:
00559          Debug (15, "OP_ge\n");
00560          tmp1 = pop ();
00561          tmp2 = pop ();
00562          push (sword (tmp1) >= sword (tmp2));
00563          break;
00564 
00565        case DW_OP_eq:
00566          Debug (15, "OP_eq\n");
00567          tmp1 = pop ();
00568          tmp2 = pop ();
00569          push (sword (tmp1) == sword (tmp2));
00570          break;
00571 
00572        case DW_OP_lt:
00573          Debug (15, "OP_lt\n");
00574          tmp1 = pop ();
00575          tmp2 = pop ();
00576          push (sword (tmp1) < sword (tmp2));
00577          break;
00578 
00579        case DW_OP_gt:
00580          Debug (15, "OP_gt\n");
00581          tmp1 = pop ();
00582          tmp2 = pop ();
00583          push (sword (tmp1) > sword (tmp2));
00584          break;
00585 
00586        case DW_OP_ne:
00587          Debug (15, "OP_ne\n");
00588          tmp1 = pop ();
00589          tmp2 = pop ();
00590          push (sword (tmp1) != sword (tmp2));
00591          break;
00592 
00593        case DW_OP_skip:
00594          Debug (15, "OP_skip(%d)\n", (int16_t) operand1);
00595          *addr += (int16_t) operand1;
00596          break;
00597 
00598        case DW_OP_bra:
00599          Debug (15, "OP_skip(%d)\n", (int16_t) operand1);
00600          tmp1 = pop ();
00601          if (tmp1)
00602            *addr += (int16_t) operand1;
00603          break;
00604 
00605        case DW_OP_nop:
00606          Debug (15, "OP_nop\n");
00607          break;
00608 
00609        case DW_OP_call2:
00610        case DW_OP_call4:
00611        case DW_OP_call_ref:
00612        case DW_OP_fbreg:
00613        case DW_OP_piece:
00614        case DW_OP_push_object_address:
00615        case DW_OP_xderef:
00616        case DW_OP_xderef_size:
00617        default:
00618          Debug (1, "Unexpected opcode 0x%x\n", opcode);
00619          return -UNW_EINVAL;
00620        }
00621     }
00622   *valp = pop ();
00623   Debug (14, "final value = 0x%lx\n", (unsigned long) *valp);
00624   return 0;
00625 }
00626 
00627 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
00628 /*                              Gfde.c                                */
00629 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
00630 
00631 static inline int
00632 is_cie_id (unw_word_t val)
00633 {
00634   /* DWARF spec says CIE_id is 0xffffffff (for 32-bit ELF) or
00635      0xffffffffffffffff (for 64-bit ELF).  However, the GNU toolchain
00636      uses 0.  */
00637   return (val == 0 || val == - (unw_word_t) 1);
00638 }
00639 
00640 /* Note: we don't need to keep track of more than the first four
00641    characters of the augmentation string, because we (a) ignore any
00642    augmentation string contents once we find an unrecognized character
00643    and (b) those characters that we do recognize, can't be
00644    repeated.  */
00645 static inline int
00646 parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
00647           const unw_proc_info_t *pi, struct dwarf_cie_info *dci, void *arg)
00648 {
00649   uint8_t version, ch, augstr[5], fde_encoding, handler_encoding;
00650   unw_word_t len, cie_end_addr, aug_size;
00651   uint32_t u32val;
00652   uint64_t u64val;
00653   size_t i;
00654   int ret;
00655 # define STR2(x)     #x
00656 # define STR(x)             STR2(x)
00657 
00658   /* Pick appropriate default for FDE-encoding.  DWARF spec says
00659      start-IP (initial_location) and the code-size (address_range) are
00660      "address-unit sized constants".  The `R' augmentation can be used
00661      to override this, but by default, we pick an address-sized unit
00662      for fde_encoding.  */
00663   switch (sizeof (unw_word_t))
00664     {
00665     case 4:   fde_encoding = DW_EH_PE_udata4; break;
00666     case 8:   fde_encoding = DW_EH_PE_udata8; break;
00667     default:  fde_encoding = DW_EH_PE_omit; break;
00668     }
00669 
00670   dci->lsda_encoding = DW_EH_PE_omit;
00671   dci->handler = 0;
00672 
00673   if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0)
00674     return ret;
00675 
00676   if (u32val != 0xffffffff)
00677     {
00678       /* the CIE is in the 32-bit DWARF format */
00679       uint32_t cie_id;
00680 
00681       len = u32val;
00682       cie_end_addr = addr + len;
00683       if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0)
00684        return ret;
00685       /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */
00686       if (cie_id != 0)
00687        {
00688          Debug (1, "Unexpected CIE id %x\n", cie_id);
00689          return -UNW_EINVAL;
00690        }
00691     }
00692   else
00693     {
00694       /* the CIE is in the 64-bit DWARF format */
00695       uint64_t cie_id;
00696 
00697       if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
00698        return ret;
00699       len = u64val;
00700       cie_end_addr = addr + len;
00701       if ((ret = dwarf_readu64 (as, a, &addr, &cie_id, arg)) < 0)
00702        return ret;
00703       /* DWARF says CIE id should be 0xffffffffffffffff, but in
00704         .eh_frame, it's 0 */
00705       if (cie_id != 0)
00706        {
00707          Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id);
00708          return -UNW_EINVAL;
00709        }
00710     }
00711   dci->cie_instr_end = cie_end_addr;
00712 
00713   if ((ret = dwarf_readu8 (as, a, &addr, &version, arg)) < 0)
00714     return ret;
00715 
00716   if (version != 1 && version != DWARF_CIE_VERSION)
00717     {
00718       Debug (1, "Got CIE version %u, expected version 1 or "
00719             STR (DWARF_CIE_VERSION) "\n", version);
00720       return -UNW_EBADVERSION;
00721     }
00722 
00723   /* read and parse the augmentation string: */
00724   memset (augstr, 0, sizeof (augstr));
00725   for (i = 0;;)
00726     {
00727       if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
00728        return ret;
00729 
00730       if (!ch)
00731        break; /* end of augmentation string */
00732 
00733       if (i < sizeof (augstr) - 1)
00734        augstr[i++] = ch;
00735     }
00736 
00737   if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->code_align, arg)) < 0
00738       || (ret = dwarf_read_sleb128 (as, a, &addr, &dci->data_align, arg)) < 0)
00739     return ret;
00740 
00741   /* Read the return-address column either as a u8 or as a uleb128.  */
00742   if (version == 1)
00743     {
00744       if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
00745        return ret;
00746       dci->ret_addr_column = ch;
00747     }
00748   else if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->ret_addr_column,
00749                                   arg)) < 0)
00750     return ret;
00751 
00752   if (augstr[0] == 'z')
00753     {
00754       dci->sized_augmentation = 1;
00755       if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
00756        return ret;
00757     }
00758 
00759   for (i = 1; i < sizeof (augstr) && augstr[i]; ++i)
00760     switch (augstr[i])
00761       {
00762       case 'L':
00763        /* read the LSDA pointer-encoding format.  */
00764        if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
00765          return ret;
00766        dci->lsda_encoding = ch;
00767        break;
00768 
00769       case 'R':
00770        /* read the FDE pointer-encoding format.  */
00771        if ((ret = dwarf_readu8 (as, a, &addr, &fde_encoding, arg)) < 0)
00772          return ret;
00773        break;
00774 
00775       case 'P':
00776        /* read the personality-routine pointer-encoding format.  */
00777        if ((ret = dwarf_readu8 (as, a, &addr, &handler_encoding, arg)) < 0)
00778          return ret;
00779        if ((ret = dwarf_read_encoded_pointer (as, a, &addr, handler_encoding,
00780                                           pi, &dci->handler, arg)) < 0)
00781          return ret;
00782        break;
00783 
00784       case 'S':
00785        /* Temporarily set it to one so dwarf_parse_fde() knows that
00786           it should fetch the actual ABI/TAG pair from the FDE.  */
00787        dci->have_abi_marker = 1;
00788        break;
00789 
00790       default:
00791        if (dci->sized_augmentation)
00792          /* If we have the size of the augmentation body, we can skip
00793             over the parts that we don't understand, so we're OK. */
00794          return 0;
00795        else
00796          {
00797            Debug (1, "Unexpected augmentation string `%s'\n", augstr);
00798            return -UNW_EINVAL;
00799          }
00800       }
00801   dci->fde_encoding = fde_encoding;
00802   dci->cie_instr_start = addr;
00803   Debug (15, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n",
00804         augstr, (long) dci->handler);
00805   return 0;
00806 }
00807 
00808 /* Extract proc-info from the FDE starting at adress ADDR.  */
00809 
00810 HIDDEN int
00811 dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
00812                               unw_word_t *addrp, unw_proc_info_t *pi,
00813                               int need_unwind_info,
00814                               void *arg)
00815 {
00816   unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0;
00817   unw_word_t start_ip, ip_range, aug_size, addr = *addrp;
00818   int ret, ip_range_encoding;
00819   struct dwarf_cie_info dci;
00820   uint64_t u64val;
00821   uint32_t u32val;
00822 
00823   Debug (12, "FDE @ 0x%lx\n", (long) addr);
00824 
00825   memset (&dci, 0, sizeof (dci));
00826 
00827   if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0)
00828     return ret;
00829 
00830   if (u32val != 0xffffffff)
00831     {
00832       uint32_t cie_offset;
00833 
00834       /* In some configurations, an FDE with a 0 length indicates the
00835         end of the FDE-table.  */
00836       if (u32val == 0)
00837        return -UNW_ENOINFO;
00838 
00839       /* the FDE is in the 32-bit DWARF format */
00840 
00841       *addrp = fde_end_addr = addr + u32val;
00842       cie_offset_addr = addr;
00843 
00844       if ((ret = dwarf_readu32 (as, a, &addr, &cie_offset, arg)) < 0)
00845        return ret;
00846 
00847       if (is_cie_id (cie_offset))
00848        /* ignore CIEs (happens during linear searches) */
00849        return 0;
00850 
00851       /* DWARF says that the CIE_pointer in the FDE is a
00852         .debug_frame-relative offset, but the GCC-generated .eh_frame
00853         sections instead store a "pcrelative" offset, which is just
00854         as fine as it's self-contained.  */
00855       cie_addr = cie_offset_addr - cie_offset;
00856     }
00857   else
00858     {
00859       uint64_t cie_offset;
00860 
00861       /* the FDE is in the 64-bit DWARF format */
00862 
00863       if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
00864        return ret;
00865 
00866       *addrp = fde_end_addr = addr + u64val;
00867       cie_offset_addr = addr;
00868 
00869       if ((ret = dwarf_readu64 (as, a, &addr, &cie_offset, arg)) < 0)
00870        return ret;
00871 
00872       if (is_cie_id (cie_offset))
00873        /* ignore CIEs (happens during linear searches) */
00874        return 0;
00875 
00876       /* DWARF says that the CIE_pointer in the FDE is a
00877         .debug_frame-relative offset, but the GCC-generated .eh_frame
00878         sections instead store a "pcrelative" offset, which is just
00879         as fine as it's self-contained.  */
00880       cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset);
00881     }
00882 
00883   if ((ret = parse_cie (as, a, cie_addr, pi, &dci, arg)) < 0)
00884     return ret;
00885 
00886   /* IP-range has same encoding as FDE pointers, except that it's
00887      always an absolute value: */
00888   ip_range_encoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK;
00889 
00890   if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.fde_encoding,
00891                                     pi, &start_ip, arg)) < 0
00892       || (ret = dwarf_read_encoded_pointer (as, a, &addr, ip_range_encoding,
00893                                        pi, &ip_range, arg)) < 0)
00894     return ret;
00895   pi->start_ip = start_ip;
00896   pi->end_ip = start_ip + ip_range;
00897   pi->handler = dci.handler;
00898 
00899   if (dci.sized_augmentation)
00900     {
00901       if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
00902        return ret;
00903       aug_end_addr = addr + aug_size;
00904     }
00905 
00906   if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.lsda_encoding,
00907                                     pi, &pi->lsda, arg)) < 0)
00908     return ret;
00909 
00910   Debug (15, "FDE covers IP 0x%lx-0x%lx, LSDA=0x%lx\n",
00911         (long) pi->start_ip, (long) pi->end_ip, (long) pi->lsda);
00912 
00913   if (need_unwind_info)
00914     {
00915       pi->format = UNW_INFO_FORMAT_TABLE;
00916       pi->unwind_info_size = sizeof (dci);
00917       pi->unwind_info = malloc (sizeof(struct dwarf_cie_info));
00918       if (!pi->unwind_info)
00919        return UNW_ENOMEM;
00920 
00921       if (dci.have_abi_marker)
00922        {
00923          if ((ret = dwarf_readu16 (as, a, &addr, &dci.abi, arg)) < 0
00924              || (ret = dwarf_readu16 (as, a, &addr, &dci.tag, arg)) < 0)
00925            return ret;
00926          Debug (13, "Found ABI marker = (abi=%u, tag=%u)\n",
00927                dci.abi, dci.tag);
00928        }
00929 
00930       if (dci.sized_augmentation)
00931        dci.fde_instr_start = aug_end_addr;
00932       else
00933        dci.fde_instr_start = addr;
00934       dci.fde_instr_end = fde_end_addr;
00935 
00936       memcpy (pi->unwind_info, &dci, sizeof (dci));
00937     }
00938   return 0;
00939 }
00940 
00941 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
00942 /*                            Gparser.c                               */
00943 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
00944 
00945 #define alloc_reg_state()   (malloc (sizeof(dwarf_reg_state_t)))
00946 #define free_reg_state(rs)  (free (rs))
00947 
00948 static inline int
00949 read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
00950             unw_word_t *valp, void *arg)
00951 {
00952   int ret;
00953 
00954   if ((ret = dwarf_read_uleb128 (as, a, addr, valp, arg)) < 0)
00955     return ret;
00956 
00957   if (*valp >= DWARF_NUM_PRESERVED_REGS)
00958     {
00959       Debug (1, "Invalid register number %u\n", (unsigned int) *valp);
00960       return -UNW_EBADREG;
00961     }
00962   return 0;
00963 }
00964 
00965 static inline void
00966 set_reg (dwarf_state_record_t *sr, unw_word_t regnum, dwarf_where_t where,
00967         unw_word_t val)
00968 {
00969   sr->rs_current.reg[regnum].where = where;
00970   sr->rs_current.reg[regnum].val = val;
00971 }
00972 
00973 /* Run a CFI program to update the register state.  */
00974 static int
00975 run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
00976                unw_word_t ip, unw_word_t *addr, unw_word_t end_addr,
00977                struct dwarf_cie_info *dci)
00978 {
00979   unw_word_t curr_ip, operand = 0, regnum, val, len, fde_encoding;
00980   dwarf_reg_state_t *rs_stack = NULL, *new_rs, *old_rs;
00981   unw_addr_space_t as;
00982   unw_accessors_t *a;
00983   uint8_t u8, op;
00984   uint16_t u16;
00985   uint32_t u32;
00986   void *arg;
00987   int ret;
00988 
00989   as = c->as;
00990   arg = c->as_arg;
00991   a = unw_get_accessors (as);
00992   curr_ip = c->pi.start_ip;
00993 
00994   while (curr_ip < ip && *addr < end_addr)
00995     {
00996       if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
00997        return ret;
00998 
00999       if (op & DWARF_CFA_OPCODE_MASK)
01000        {
01001          operand = op & DWARF_CFA_OPERAND_MASK;
01002          op &= ~DWARF_CFA_OPERAND_MASK;
01003        }
01004       switch ((dwarf_cfa_t) op)
01005        {
01006        case DW_CFA_advance_loc:
01007          curr_ip += operand * dci->code_align;
01008          Debug (15, "CFA_advance_loc to 0x%lx\n", (long) curr_ip);
01009          break;
01010 
01011        case DW_CFA_advance_loc1:
01012          if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0)
01013            goto fail;
01014          curr_ip += u8 * dci->code_align;
01015          Debug (15, "CFA_advance_loc1 to 0x%lx\n", (long) curr_ip);
01016          break;
01017 
01018        case DW_CFA_advance_loc2:
01019          if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0)
01020            goto fail;
01021          curr_ip += u16 * dci->code_align;
01022          Debug (15, "CFA_advance_loc2 to 0x%lx\n", (long) curr_ip);
01023          break;
01024 
01025        case DW_CFA_advance_loc4:
01026          if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0)
01027            goto fail;
01028          curr_ip += u32 * dci->code_align;
01029          Debug (15, "CFA_advance_loc4 to 0x%lx\n", (long) curr_ip);
01030          break;
01031 
01032        case DW_CFA_MIPS_advance_loc8:
01033 #ifdef UNW_TARGET_MIPS
01034          {
01035            uint64_t u64;
01036 
01037            if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0)
01038              goto fail;
01039            curr_ip += u64 * dci->code_align;
01040            Debug (15, "CFA_MIPS_advance_loc8\n");
01041            break;
01042          }
01043 #else
01044          Debug (1, "DW_CFA_MIPS_advance_loc8 on non-MIPS target\n");
01045          ret = -UNW_EINVAL;
01046          goto fail;
01047 #endif
01048 
01049        case DW_CFA_offset:
01050          regnum = operand;
01051          if (regnum >= DWARF_NUM_PRESERVED_REGS)
01052            {
01053              Debug (1, "Invalid register number %u in DW_cfa_OFFSET\n",
01054                    (unsigned int) regnum);
01055              ret = -UNW_EBADREG;
01056              goto fail;
01057            }
01058          if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
01059            goto fail;
01060          set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
01061          Debug (15, "CFA_offset r%lu at cfa+0x%lx\n",
01062                (long) regnum, (long) (val * dci->data_align));
01063          break;
01064 
01065        case DW_CFA_offset_extended:
01066          if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01067              || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
01068            goto fail;
01069          set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
01070          Debug (15, "CFA_offset_extended r%lu at cf+0x%lx\n",
01071                (long) regnum, (long) (val * dci->data_align));
01072          break;
01073 
01074        case DW_CFA_offset_extended_sf:
01075          if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01076              || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
01077            goto fail;
01078          set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
01079          Debug (15, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
01080                (long) regnum, (long) (val * dci->data_align));
01081          break;
01082 
01083        case DW_CFA_restore:
01084          regnum = operand;
01085          if (regnum >= DWARF_NUM_PRESERVED_REGS)
01086            {
01087              Debug (1, "Invalid register number %u in DW_CFA_restore\n",
01088                    (unsigned int) regnum);
01089              ret = -UNW_EINVAL;
01090              goto fail;
01091            }
01092          sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
01093          Debug (15, "CFA_restore r%lu\n", (long) regnum);
01094          break;
01095 
01096        case DW_CFA_restore_extended:
01097          if ((ret = dwarf_read_uleb128 (as, a, addr, &regnum, arg)) < 0)
01098            goto fail;
01099          if (regnum >= DWARF_NUM_PRESERVED_REGS)
01100            {
01101              Debug (1, "Invalid register number %u in "
01102                    "DW_CFA_restore_extended\n", (unsigned int) regnum);
01103              ret = -UNW_EINVAL;
01104              goto fail;
01105            }
01106          sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
01107          Debug (15, "CFA_restore_extended r%lu\n", (long) regnum);
01108          break;
01109 
01110        case DW_CFA_nop:
01111          break;
01112 
01113        case DW_CFA_set_loc:
01114          fde_encoding = dci->fde_encoding;
01115          if ((ret = dwarf_read_encoded_pointer (as, a, addr, fde_encoding,
01116                                            &c->pi, &curr_ip,
01117                                            arg)) < 0)
01118            goto fail;
01119          Debug (15, "CFA_set_loc to 0x%lx\n", (long) curr_ip);
01120          break;
01121 
01122        case DW_CFA_undefined:
01123          if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01124            goto fail;
01125          set_reg (sr, regnum, DWARF_WHERE_UNDEF, 0);
01126          Debug (15, "CFA_undefined r%lu\n", (long) regnum);
01127          break;
01128 
01129        case DW_CFA_same_value:
01130          if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01131            goto fail;
01132          set_reg (sr, regnum, DWARF_WHERE_SAME, 0);
01133          Debug (15, "CFA_same_value r%lu\n", (long) regnum);
01134          break;
01135 
01136        case DW_CFA_register:
01137          if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01138              || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
01139            goto fail;
01140          set_reg (sr, regnum, DWARF_WHERE_REG, val);
01141          Debug (15, "CFA_register r%lu to r%lu\n", (long) regnum, (long) val);
01142          break;
01143 
01144        case DW_CFA_remember_state:
01145          new_rs = alloc_reg_state ();
01146          if (!new_rs)
01147            {
01148              Debug (1, "Out of memory in DW_CFA_remember_state\n");
01149              ret = -UNW_ENOMEM;
01150              goto fail;
01151            }
01152 
01153          memcpy (new_rs->reg, sr->rs_current.reg, sizeof (new_rs->reg));
01154          new_rs->next = rs_stack;
01155          rs_stack = new_rs;
01156          Debug (15, "CFA_remember_state\n");
01157          break;
01158 
01159        case DW_CFA_restore_state:
01160          if (!rs_stack)
01161            {
01162              Debug (1, "register-state stack underflow\n");
01163              ret = -UNW_EINVAL;
01164              goto fail;
01165            }
01166          memcpy (&sr->rs_current.reg, &rs_stack->reg, sizeof (rs_stack->reg));
01167          old_rs = rs_stack;
01168          rs_stack = rs_stack->next;
01169          free_reg_state (old_rs);
01170          Debug (15, "CFA_restore_state\n");
01171          break;
01172 
01173        case DW_CFA_def_cfa:
01174          if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01175              || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
01176            goto fail;
01177          set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
01178          set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val);    /* NOT factored! */
01179          Debug (15, "CFA_def_cfa r%lu+0x%lx\n", (long) regnum, (long) val);
01180          break;
01181 
01182        case DW_CFA_def_cfa_sf:
01183          if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01184              || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
01185            goto fail;
01186          set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
01187          set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
01188                  val * dci->data_align);         /* factored! */
01189          Debug (15, "CFA_def_cfa_sf r%lu+0x%lx\n",
01190                (long) regnum, (long) (val * dci->data_align));
01191          break;
01192 
01193        case DW_CFA_def_cfa_register:
01194          if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01195            goto fail;
01196          set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
01197          Debug (15, "CFA_def_cfa_register r%lu\n", (long) regnum);
01198          break;
01199 
01200        case DW_CFA_def_cfa_offset:
01201          if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
01202            goto fail;
01203          set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val);    /* NOT factored! */
01204          Debug (15, "CFA_def_cfa_offset 0x%lx\n", (long) val);
01205          break;
01206 
01207        case DW_CFA_def_cfa_offset_sf:
01208          if ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)
01209            goto fail;
01210          set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
01211                  val * dci->data_align);  /* factored! */
01212          Debug (15, "CFA_def_cfa_offset_sf 0x%lx\n",
01213                (long) (val * dci->data_align));
01214          break;
01215 
01216        case DW_CFA_def_cfa_expression:
01217          /* Save the address of the DW_FORM_block for later evaluation. */
01218          set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_EXPR, *addr);
01219 
01220          if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
01221            goto fail;
01222 
01223          Debug (15, "CFA_def_cfa_expr @ 0x%lx [%lu bytes]\n",
01224                (long) *addr, (long) len);
01225          *addr += len;
01226          break;
01227 
01228        case DW_CFA_expression:
01229          if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01230            goto fail;
01231 
01232          /* Save the address of the DW_FORM_block for later evaluation. */
01233          set_reg (sr, regnum, DWARF_WHERE_EXPR, *addr);
01234 
01235          if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
01236            goto fail;
01237 
01238          Debug (15, "CFA_expression r%lu @ 0x%lx [%lu bytes]\n",
01239                (long) regnum, (long) addr, (long) len);
01240          *addr += len;
01241          break;
01242 
01243        case DW_CFA_GNU_args_size:
01244          if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
01245            goto fail;
01246          sr->args_size = val;
01247          Debug (15, "CFA_GNU_args_size %lu\n", (long) val);
01248          break;
01249 
01250        case DW_CFA_GNU_negative_offset_extended:
01251          /* A comment in GCC says that this is obsoleted by
01252             DW_CFA_offset_extended_sf, but that it's used by older
01253             PowerPC code.  */
01254          if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
01255              || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
01256            goto fail;
01257          set_reg (sr, regnum, DWARF_WHERE_CFAREL, -(val * dci->data_align));
01258          Debug (15, "CFA_GNU_negative_offset_extended cfa+0x%lx\n",
01259                (long) -(val * dci->data_align));
01260          break;
01261 
01262        case DW_CFA_GNU_window_save:
01263 #ifdef UNW_TARGET_SPARC
01264          /* This is a special CFA to handle all 16 windowed registers
01265             on SPARC.  */
01266          for (regnum = 16; regnum < 32; ++regnum)
01267            set_reg (sr, regnum, DWARF_WHERE_CFAREL,
01268                    (regnum - 16) * sizeof (unw_word_t));
01269          Debug (15, "CFA_GNU_window_save\n");
01270          break;
01271 #else
01272          /* FALL THROUGH */
01273 #endif
01274        case DW_CFA_lo_user:
01275        case DW_CFA_hi_user:
01276          Debug (1, "Unexpected CFA opcode 0x%x\n", op);
01277          ret = -UNW_EINVAL;
01278          goto fail;
01279        }
01280     }
01281   ret = 0;
01282 
01283  fail:
01284   /* Free the register-state stack, if not empty already.  */
01285   while (rs_stack)
01286     {
01287       old_rs = rs_stack;
01288       rs_stack = rs_stack->next;
01289       free_reg_state (old_rs);
01290     }
01291   return ret;
01292 }
01293 
01294 static int
01295 fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
01296 {
01297   int ret;
01298 
01299   --ip;
01300 
01301   if (c->pi_valid && !need_unwind_info)
01302     return 0;
01303 
01304   memset (&c->pi, 0, sizeof (c->pi));
01305 
01306   if ((ret = tdep_find_proc_info (c, ip, need_unwind_info)) < 0)
01307     return ret;
01308 
01309   c->pi_valid = 1;
01310   return ret;
01311 }
01312 
01313 static inline void
01314 put_unwind_info (struct dwarf_cursor *c, unw_proc_info_t *pi)
01315 {
01316   if (!c->pi_valid)
01317     return;
01318 
01319   if (pi->unwind_info);
01320     {
01321       free (pi->unwind_info);
01322       pi->unwind_info = NULL;
01323     }
01324 }
01325 
01326 static inline int
01327 parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
01328 {
01329   struct dwarf_cie_info *dci;
01330   unw_word_t addr;
01331   int ret;
01332 
01333   dci = c->pi.unwind_info;
01334   c->ret_addr_column = dci->ret_addr_column;
01335 
01336   addr = dci->cie_instr_start;
01337   if ((ret = run_cfi_program (c, sr, ~(unw_word_t) 0, &addr,
01338                            dci->cie_instr_end, dci)) < 0)
01339     return ret;
01340 
01341   memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial));
01342 
01343   addr = dci->fde_instr_start;
01344   if ((ret = run_cfi_program (c, sr, ip, &addr, dci->fde_instr_end, dci)) < 0)
01345     return ret;
01346 
01347   return 0;
01348 }
01349 
01350 static inline void
01351 flush_rs_cache (struct dwarf_rs_cache *cache)
01352 {
01353   int i;
01354 
01355   cache->lru_head = DWARF_UNW_CACHE_SIZE - 1;
01356   cache->lru_tail = 0;
01357 
01358   for (i = 0; i < DWARF_UNW_CACHE_SIZE; ++i)
01359     {
01360       if (i > 0)
01361        cache->buckets[i].lru_chain = (i - 1);
01362       cache->buckets[i].coll_chain = -1;
01363       cache->buckets[i].ip = 0;
01364     }
01365   for (i = 0; i<DWARF_UNW_HASH_SIZE; ++i)
01366     cache->hash[i] = -1;
01367 }
01368 
01369 static inline struct dwarf_rs_cache *
01370 get_rs_cache (unw_addr_space_t as, intrmask_t *saved_maskp)
01371 {
01372   struct dwarf_rs_cache *cache = &as->global_cache;
01373   unw_caching_policy_t caching = as->caching_policy;
01374 
01375   if (caching == UNW_CACHE_NONE)
01376     return NULL;
01377 
01378 #ifndef UW_NO_SYNC
01379 #ifdef HAVE_ATOMIC_H
01380   if (!spin_trylock_irqsave (&cache->busy, *saved_maskp))
01381     return NULL;
01382 #else
01383 # ifdef HAVE_ATOMIC_OPS_H
01384   if (AO_test_and_set (&cache->busy) == AO_TS_SET)
01385     return NULL;
01386 # else
01387   sigprocmask (SIG_SETMASK, &unwi_full_mask, saved_maskp);
01388   if (likely (caching == UNW_CACHE_GLOBAL))
01389     {
01390       Debug (16, "%s: acquiring lock\n", __FUNCTION__);
01391       mutex_lock (&cache->lock);
01392     }
01393 # endif
01394 #endif
01395 #endif
01396 
01397   if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
01398     {
01399       flush_rs_cache (cache);
01400       cache->generation = as->cache_generation;
01401     }
01402 
01403   return cache;
01404 }
01405 
01406 static inline void
01407 put_rs_cache (unw_addr_space_t as, struct dwarf_rs_cache *cache,
01408                 intrmask_t *saved_maskp)
01409 {
01410   assert (as->caching_policy != UNW_CACHE_NONE);
01411 
01412   Debug (16, "unmasking signals/interrupts and releasing lock\n");
01413 #ifndef UW_NO_SYNC
01414 #ifdef HAVE_ATOMIC_H
01415   spin_unlock_irqrestore (&cache->busy, *saved_maskp);
01416 #else
01417 # ifdef HAVE_ATOMIC_OPS_H
01418   AO_CLEAR (&cache->busy);
01419 # else
01420   if (likely (as->caching_policy == UNW_CACHE_GLOBAL))
01421      mutex_unlock (&cache->lock);
01422   sigprocmask (SIG_SETMASK, saved_maskp, NULL);
01423 # endif
01424 #endif
01425 #endif
01426 }
01427 
01428 static inline unw_hash_index_t
01429 hash (unw_word_t ip)
01430 {
01431   /* based on (sqrt(5)/2-1)*2^64 */
01432 # define magic       ((unw_word_t) 0x9e3779b97f4a7c16ULL)
01433 
01434   return ip * magic >> ((sizeof(unw_word_t) * 8) - DWARF_LOG_UNW_HASH_SIZE);
01435 }
01436 
01437 static inline long
01438 cache_match (dwarf_reg_state_t *rs, unw_word_t ip)
01439 {
01440   if (ip == rs->ip)
01441     return 1;
01442   return 0;
01443 }
01444 
01445 static dwarf_reg_state_t *
01446 rs_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c)
01447 {
01448   dwarf_reg_state_t *rs = cache->buckets + c->hint;
01449   unsigned short index;
01450   unw_word_t ip;
01451 
01452   ip = c->ip;
01453 
01454   if (cache_match (rs, ip))
01455     return rs;
01456 
01457   index = cache->hash[hash (ip)];
01458   if (index >= DWARF_UNW_CACHE_SIZE)
01459     return 0;
01460 
01461   rs = cache->buckets + index;
01462   while (1)
01463     {
01464       if (cache_match (rs, ip))
01465         {
01466           /* update hint; no locking needed: single-word writes are atomic */
01467           c->hint = cache->buckets[c->prev_rs].hint =
01468             (rs - cache->buckets);
01469           return rs;
01470         }
01471       if (rs->coll_chain >= DWARF_UNW_HASH_SIZE)
01472         return 0;
01473       if (!rs->coll_chain)
01474         /* Something went wrong */
01475         return 0;
01476       rs = cache->buckets + rs->coll_chain;
01477     }
01478 }
01479 
01480 static inline dwarf_reg_state_t *
01481 rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c)
01482 {
01483   dwarf_reg_state_t *rs, *prev, *tmp;
01484   unw_hash_index_t index;
01485   unsigned short head;
01486 
01487   head = cache->lru_head;
01488   rs = cache->buckets + head;
01489   cache->lru_head = rs->lru_chain;
01490 
01491   /* re-insert rs at the tail of the LRU chain: */
01492   cache->buckets[cache->lru_tail].lru_chain = head;
01493   cache->lru_tail = head;
01494 
01495   /* remove the old rs from the hash table (if it's there): */
01496   if (rs->ip)
01497     {
01498       index = hash (rs->ip);
01499       tmp = cache->buckets + cache->hash[index];
01500       prev = 0;
01501       while (1)
01502        {
01503          if (tmp == rs)
01504            {
01505              if (prev)
01506               prev->coll_chain = tmp->coll_chain;
01507              else
01508               cache->hash[index] = tmp->coll_chain;
01509              break;
01510            }
01511          else
01512            prev = tmp;
01513          if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE)
01514            /* old rs wasn't in the hash-table */
01515            break;
01516          tmp = cache->buckets + tmp->coll_chain;
01517        }
01518     }
01519 
01520   /* enter new rs in the hash table */
01521   index = hash (c->ip);
01522   rs->coll_chain = cache->hash[index];
01523   cache->hash[index] = rs - cache->buckets;
01524 
01525   rs->hint = 0;
01526   rs->ip = c->ip;
01527   rs->ret_addr_column = c->ret_addr_column;
01528 
01529   return rs;
01530 }
01531 
01532 static int
01533 create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr,
01534                       unw_word_t ip)
01535 {
01536   int i, ret;
01537 
01538   assert (c->pi_valid);
01539 
01540   memset (sr, 0, sizeof (*sr));
01541   for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i)
01542     set_reg (sr, i, DWARF_WHERE_SAME, 0);
01543 
01544   switch (c->pi.format)
01545     {
01546     case UNW_INFO_FORMAT_TABLE:
01547     case UNW_INFO_FORMAT_REMOTE_TABLE:
01548       ret = parse_fde (c, ip, sr);
01549       break;
01550 #if 0
01551     case UNW_INFO_FORMAT_DYNAMIC:
01552       ret = parse_dynamic (c, ip, sr);
01553       break;
01554 #endif
01555 
01556     default:
01557       Debug (1, "Unexpected unwind-info format %d\n", c->pi.format);
01558       ret = -UNW_EINVAL;
01559     }
01560   return ret;
01561 }
01562 
01563 static inline int
01564 eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
01565                   unw_accessors_t *a, unw_word_t addr,
01566                   dwarf_loc_t *locp, void *arg)
01567 {
01568   int ret, is_register;
01569   unw_word_t len, val;
01570 
01571   /* read the length of the expression: */
01572   if ((ret = dwarf_read_uleb128 (as, a, &addr, &len, arg)) < 0)
01573     return ret;
01574 
01575   /* evaluate the expression: */
01576   if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0)
01577     return ret;
01578 
01579   if (is_register)
01580     *locp = DWARF_REG_LOC (c, dwarf_to_unw_regnum (val));
01581   else
01582     *locp = DWARF_MEM_LOC (c, val);
01583 
01584   return 0;
01585 }
01586 
01587 static int
01588 apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
01589 {
01590   unw_word_t regnum, addr, cfa, ip;
01591   unw_word_t prev_ip, prev_cfa;
01592   unw_addr_space_t as;
01593   dwarf_loc_t cfa_loc;
01594   unw_accessors_t *a;
01595   int i, ret;
01596   void *arg;
01597 
01598   prev_ip = c->ip;
01599   prev_cfa = c->cfa;
01600 
01601   as = c->as;
01602   arg = c->as_arg;
01603   a = unw_get_accessors (as);
01604 
01605   /* Evaluate the CFA first, because it may be referred to by other
01606      expressions.  */
01607 
01608   if (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
01609     {
01610       /* CFA is equal to [reg] + offset: */
01611 
01612       /* As a special-case, if the stack-pointer is the CFA and the
01613         stack-pointer wasn't saved, popping the CFA implicitly pops
01614         the stack-pointer as well.  */
01615       if ((rs->reg[DWARF_CFA_REG_COLUMN].val == UNW_TDEP_SP)
01616          && (rs->reg[UNW_TDEP_SP].where == DWARF_WHERE_SAME))
01617          cfa = c->cfa;
01618       else
01619        {
01620          regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val);
01621          if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
01622            return ret;
01623        }
01624       cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val;
01625     }
01626   else
01627     {
01628       /* CFA is equal to EXPR: */
01629 
01630       assert (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_EXPR);
01631 
01632       addr = rs->reg[DWARF_CFA_REG_COLUMN].val;
01633       if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0)
01634        return ret;
01635       /* the returned location better be a memory location... */
01636       if (DWARF_IS_REG_LOC (cfa_loc))
01637        return -UNW_EBADFRAME;
01638       cfa = DWARF_GET_LOC (cfa_loc);
01639     }
01640 
01641   for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
01642     {
01643       switch ((dwarf_where_t) rs->reg[i].where)
01644        {
01645        case DWARF_WHERE_UNDEF:
01646          c->loc[i] = DWARF_NULL_LOC;
01647          break;
01648 
01649        case DWARF_WHERE_SAME:
01650          break;
01651 
01652        case DWARF_WHERE_CFAREL:
01653          c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
01654          break;
01655 
01656        case DWARF_WHERE_REG:
01657          c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
01658          break;
01659 
01660        case DWARF_WHERE_EXPR:
01661          addr = rs->reg[i].val;
01662          if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) , 0)
01663            return ret;
01664          break;
01665        }
01666     }
01667   c->cfa = cfa;
01668   ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
01669   if (ret < 0)
01670     return ret;
01671   c->ip = ip;
01672   /* XXX: check for ip to be code_aligned */
01673 
01674   if (c->ip == prev_ip && c->cfa == prev_cfa)
01675     {
01676       dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
01677               __FUNCTION__, (long) c->ip);
01678       return -UNW_EBADFRAME;
01679     }
01680   return 0;
01681 }
01682 
01683 static int
01684 uncached_dwarf_find_save_locs (struct dwarf_cursor *c)
01685 {
01686   dwarf_state_record_t sr;
01687   int ret;
01688 
01689   if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
01690     return ret;
01691 
01692   if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
01693     return ret;
01694 
01695   if ((ret = apply_reg_state (c, &sr.rs_current)) < 0)
01696     return ret;
01697 
01698   put_unwind_info (c, &c->pi);
01699   return 0;
01700 }
01701 
01702 /* The function finds the saved locations and applies the register
01703    state as well. */
01704 HIDDEN int
01705 dwarf_find_save_locs (struct dwarf_cursor *c)
01706 {
01707   dwarf_state_record_t sr;
01708   dwarf_reg_state_t *rs, *rs1;
01709   struct dwarf_rs_cache *cache;
01710   int ret = 0;
01711   intrmask_t saved_mask;
01712 
01713   if (c->as->caching_policy == UNW_CACHE_NONE)
01714     return uncached_dwarf_find_save_locs (c);
01715 
01716   cache = get_rs_cache(c->as, &saved_mask);
01717   if (!cache)
01718     return -UNW_ENOINFO;    /* cache is busy */
01719   rs = rs_lookup(cache, c);
01720 
01721   if (rs)
01722     {
01723       c->ret_addr_column = rs->ret_addr_column;
01724       goto apply;
01725     }
01726 
01727   if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
01728     goto out;
01729 
01730   if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
01731     goto out;
01732 
01733   rs1 = &sr.rs_current;
01734   if (rs1)
01735     {
01736       rs = rs_new (cache, c);
01737       memcpy(rs, rs1, offsetof(struct dwarf_reg_state, ip));
01738       if (!rs)
01739         {
01740           dprintf ("%s: failed to create unwind rs\n", __FUNCTION__);
01741           ret = -UNW_EUNSPEC;
01742          goto out;
01743         }
01744     }
01745   cache->buckets[c->prev_rs].hint = rs - cache->buckets;
01746 
01747   c->hint = rs->hint;
01748   c->prev_rs = rs - cache->buckets;
01749 
01750   put_unwind_info (c, &c->pi);
01751   ret = apply_reg_state (c, rs);
01752 
01753 out:
01754   put_rs_cache (c->as, cache, &saved_mask);
01755   return ret;
01756 
01757 apply:
01758   put_rs_cache (c->as, cache, &saved_mask);
01759   if ((ret = apply_reg_state (c, rs)) < 0)
01760     return ret;
01761 
01762   return 0;
01763 }
01764 
01765 HIDDEN int
01766 dwarf_step (struct dwarf_cursor *c)
01767 {
01768   /* unw_word_t prev_cfa = c->cfa; */
01769   int ret;
01770 
01771   if ((ret = dwarf_find_save_locs (c)) >= 0) {
01772     c->pi_valid = 0;
01773     ret = (c->ip == 0) ? 0 : 1;
01774   }
01775 
01776   Debug (15, "returning %d\n", ret);
01777   return ret;
01778 }
01779 
01780 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
01781 /*                              Gpe.c                                 */
01782 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
01783 
01784 HIDDEN int
01785 dwarf_read_encoded_pointer (unw_addr_space_t as, unw_accessors_t *a,
01786                          unw_word_t *addr, unsigned char encoding,
01787                          const unw_proc_info_t *pi,
01788                          unw_word_t *valp, void *arg)
01789 {
01790   return dwarf_read_encoded_pointer_inlined (as, a, addr, encoding,
01791                                         pi, valp, arg);
01792 }
01793 
01794 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
01795 /*                      Gfind_proc_info-lsb.c                         */
01796 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
01797 
01798 struct table_entry
01799   {
01800     int32_t start_ip_offset;
01801     int32_t fde_offset;
01802   };
01803 
01804 #ifndef UNW_REMOTE_ONLY
01805 
01806 struct callback_data
01807   {
01808     /* in: */
01809     unw_word_t ip;          /* instruction-pointer we're looking for */
01810     unw_proc_info_t *pi;    /* proc-info pointer */
01811     int need_unwind_info;
01812     /* out: */
01813     int single_fde;         /* did we find a single FDE? (vs. a table) */
01814     unw_dyn_info_t di;             /* table info (if single_fde is false) */
01815   };
01816 
01817 static int
01818 linear_search (unw_addr_space_t as, unw_word_t ip,
01819               unw_word_t eh_frame_start, unw_word_t eh_frame_end,
01820               unw_word_t fde_count,
01821               unw_proc_info_t *pi, int need_unwind_info, void *arg)
01822 {
01823   unw_accessors_t *a = unw_get_accessors (unw_local_addr_space);
01824   unw_word_t i = 0, fde_addr, addr = eh_frame_start;
01825   int ret;
01826 
01827   while (i++ < fde_count && addr < eh_frame_end)
01828     {
01829       fde_addr = addr;
01830       if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, 0, arg))
01831          < 0)
01832        return ret;
01833 
01834       if (ip >= pi->start_ip && ip < pi->end_ip)
01835        {
01836          if (!need_unwind_info)
01837            return 1;
01838          addr = fde_addr;
01839          if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi,
01840                                                  need_unwind_info, arg))
01841              < 0)
01842            return ret;
01843          return 1;
01844        }
01845     }
01846   return -UNW_ENOINFO;
01847 }
01848 
01849 /* Info is a pointer to a unw_dyn_info_t structure and, on entry,
01850    member u.rti.segbase contains the instruction-pointer we're looking
01851    for.  */
01852 static int
01853 callback (struct dl_phdr_info *info, size_t size, void *ptr)
01854 {
01855   struct callback_data *cb_data = ptr;
01856   unw_dyn_info_t *di = &cb_data->di;
01857   const Elf_W(Phdr) *phdr, *p_eh_hdr, *p_dynamic, *p_text;
01858   unw_word_t addr, eh_frame_start, eh_frame_end, fde_count, ip;
01859   Elf_W(Addr) load_base, segbase = 0, max_load_addr = 0;
01860   int ret, need_unwind_info = cb_data->need_unwind_info;
01861   unw_proc_info_t *pi = cb_data->pi;
01862   struct dwarf_eh_frame_hdr *hdr;
01863   unw_accessors_t *a;
01864   long n;
01865 
01866   ip = cb_data->ip;
01867 
01868   /* Make sure struct dl_phdr_info is at least as big as we need.  */
01869   if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
01870             + sizeof (info->dlpi_phnum))
01871     return -1;
01872 
01873   Debug (15, "checking %s, base=0x%lx)\n",
01874         info->dlpi_name, (long) info->dlpi_addr);
01875 
01876   phdr = info->dlpi_phdr;
01877   load_base = info->dlpi_addr;
01878   p_text = NULL;
01879   p_eh_hdr = NULL;
01880   p_dynamic = NULL;
01881 
01882   /* See if PC falls into one of the loaded segments.  Find the
01883      eh-header segment at the same time.  */
01884   for (n = info->dlpi_phnum; --n >= 0; phdr++)
01885     {
01886       if (phdr->p_type == PT_LOAD)
01887        {
01888          Elf_W(Addr) vaddr = phdr->p_vaddr + load_base;
01889 
01890           Debug(18, "check %lx versus %lx-%lx\n", ip, vaddr, vaddr + phdr->p_memsz);
01891 
01892          if (ip >= vaddr && ip < vaddr + phdr->p_memsz)
01893            p_text = phdr;
01894 
01895          if (vaddr + phdr->p_filesz > max_load_addr)
01896            max_load_addr = vaddr + phdr->p_filesz;
01897        }
01898       else if (phdr->p_type == PT_GNU_EH_FRAME)
01899        p_eh_hdr = phdr;
01900       else if (phdr->p_type == PT_DYNAMIC)
01901        p_dynamic = phdr;
01902     }
01903   if (!p_text || !p_eh_hdr)
01904     return 0;
01905 
01906   if (likely (p_eh_hdr->p_vaddr >= p_text->p_vaddr
01907              && p_eh_hdr->p_vaddr < p_text->p_vaddr + p_text->p_memsz))
01908     /* normal case: eh-hdr is inside text segment */
01909     segbase = p_text->p_vaddr + load_base;
01910   else
01911     {
01912       /* Special case: eh-hdr is in some other segment; this may
01913         happen, e.g., for the Linux kernel's gate DSO, for
01914         example.  */
01915       phdr = info->dlpi_phdr;
01916       for (n = info->dlpi_phnum; --n >= 0; phdr++)
01917        {
01918          if (phdr->p_type == PT_LOAD && p_eh_hdr->p_vaddr >= phdr->p_vaddr
01919              && p_eh_hdr->p_vaddr < phdr->p_vaddr + phdr->p_memsz)
01920            {
01921              segbase = phdr->p_vaddr + load_base;
01922              break;
01923            }
01924        }
01925     }
01926 
01927   if (p_dynamic)
01928     {
01929       /* For dynamicly linked executables and shared libraries,
01930         DT_PLTGOT is the value that data-relative addresses are
01931         relative to for that object.  We call this the "gp".  */
01932       Elf_W(Dyn) *dyn = (Elf_W(Dyn) *)(p_dynamic->p_vaddr + load_base);
01933       for (; dyn->d_tag != DT_NULL; ++dyn)
01934        if (dyn->d_tag == DT_PLTGOT)
01935          {
01936            /* Assume that _DYNAMIC is writable and GLIBC has
01937               relocated it (true for x86 at least).  */
01938            di->gp = dyn->d_un.d_ptr;
01939            break;
01940          }
01941     }
01942   else
01943     /* Otherwise this is a static executable with no _DYNAMIC.  Assume
01944        that data-relative addresses are relative to 0, i.e.,
01945        absolute.  */
01946     di->gp = 0;
01947   pi->gp = di->gp;
01948 
01949   hdr = (struct dwarf_eh_frame_hdr *) (p_eh_hdr->p_vaddr + load_base);
01950   if (hdr->version != DW_EH_VERSION)
01951     {
01952       Debug (1, "table `%s' has unexpected version %d\n",
01953             info->dlpi_name, hdr->version);
01954       return 0;
01955     }
01956 
01957   a = unw_get_accessors (unw_local_addr_space);
01958   addr = (unw_word_t) (hdr + 1);
01959 
01960   /* (Optionally) read eh_frame_ptr: */
01961   if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
01962                                     &addr, hdr->eh_frame_ptr_enc, pi,
01963                                     &eh_frame_start, NULL)) < 0)
01964     return ret;
01965 
01966   /* (Optionally) read fde_count: */
01967   if ((ret = dwarf_read_encoded_pointer (unw_local_addr_space, a,
01968                                     &addr, hdr->fde_count_enc, pi,
01969                                     &fde_count, NULL)) < 0)
01970     return ret;
01971 
01972   if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
01973     {
01974       /* If there is no search table or it has an unsupported
01975         encoding, fall back on linear search.  */
01976       if (hdr->table_enc == DW_EH_PE_omit)
01977        Debug (4, "table `%s' lacks search table; doing linear search\n",
01978               info->dlpi_name);
01979       else
01980        Debug (4, "table `%s' has encoding 0x%x; doing linear search\n",
01981               info->dlpi_name, hdr->table_enc);
01982 
01983       eh_frame_end = max_load_addr;       /* XXX can we do better? */
01984 
01985       if (hdr->fde_count_enc == DW_EH_PE_omit)
01986        fde_count = ~0UL;
01987       if (hdr->eh_frame_ptr_enc == DW_EH_PE_omit)
01988        abort ();
01989 
01990       cb_data->single_fde = 1;
01991       return linear_search (unw_local_addr_space, ip,
01992                          eh_frame_start, eh_frame_end, fde_count,
01993                          pi, need_unwind_info, NULL);
01994     }
01995 
01996   cb_data->single_fde = 0;
01997   di->format = UNW_INFO_FORMAT_REMOTE_TABLE;
01998   di->start_ip = p_text->p_vaddr + load_base;
01999   di->end_ip = p_text->p_vaddr + load_base + p_text->p_memsz;
02000   di->u.rti.name_ptr = (unw_word_t) info->dlpi_name;
02001   di->u.rti.table_data = addr;
02002   assert (sizeof (struct table_entry) % sizeof (unw_word_t) == 0);
02003   di->u.rti.table_len = (fde_count * sizeof (struct table_entry)
02004                       / sizeof (unw_word_t));
02005   /* For the binary-search table in the eh_frame_hdr, data-relative
02006      means relative to the start of that section... */
02007   di->u.rti.segbase = (unw_word_t) hdr;
02008 
02009   Debug (15, "found table `%s': segbase=0x%lx, len=%lu, gp=0x%lx, "
02010         "table_data=0x%lx\n", (char *) di->u.rti.name_ptr,
02011         (long) di->u.rti.segbase, (long) di->u.rti.table_len,
02012         (long) di->gp, (long) di->u.rti.table_data);
02013   return 1;
02014 }
02015 
02016 HIDDEN int
02017 dwarf_find_proc_info (unw_addr_space_t as, unw_word_t ip,
02018                     unw_proc_info_t *pi, int need_unwind_info, void *arg)
02019 {
02020   struct callback_data cb_data;
02021 #ifndef UW_NO_SYNC
02022   intrmask_t saved_mask;
02023 #endif
02024   int ret;
02025 
02026   Debug (14, "looking for IP=0x%lx\n", (long) ip);
02027 
02028   cb_data.ip = ip;
02029   cb_data.pi = pi;
02030   cb_data.need_unwind_info = need_unwind_info;
02031 
02032 #ifndef UW_NO_SYNC
02033   sigprocmask (SIG_SETMASK, &unwi_full_mask, &saved_mask);
02034 #endif
02035   ret = dl_iterate_phdr (callback, &cb_data);
02036 #ifndef UW_NO_SYNC
02037   sigprocmask (SIG_SETMASK, &saved_mask, NULL);
02038 #endif
02039 
02040   if (ret <= 0)
02041     {
02042       Debug (14, "IP=0x%lx not found\n", (long) ip);
02043       return -UNW_ENOINFO;
02044     }
02045 
02046   if (cb_data.single_fde)
02047     /* already got the result in *pi */
02048     return 0;
02049   else
02050     /* search the table: */
02051     return dwarf_search_unwind_table (as, ip, &cb_data.di,
02052                                   pi, need_unwind_info, arg);
02053 }
02054 
02055 static inline const struct table_entry *
02056 lookup (struct table_entry *table, size_t table_size, int32_t rel_ip)
02057 {
02058   unsigned long table_len = table_size / sizeof (struct table_entry);
02059   const struct table_entry *e = 0;
02060   unsigned long lo, hi, mid;
02061 
02062   /* do a binary search for right entry: */
02063   for (lo = 0, hi = table_len; lo < hi;)
02064     {
02065       mid = (lo + hi) / 2;
02066       e = table + mid;
02067       if (rel_ip < e->start_ip_offset)
02068        hi = mid;
02069       else
02070        lo = mid + 1;
02071     }
02072   if (hi <= 0)
02073        return NULL;
02074   e = table + hi - 1;
02075   return e;
02076 }
02077 
02078 #endif /* !UNW_REMOTE_ONLY */
02079 
02080 int
02081 dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
02082                         unw_dyn_info_t *di, unw_proc_info_t *pi,
02083                         int need_unwind_info, void *arg)
02084 {
02085   const struct table_entry *e = NULL;
02086   unw_word_t segbase = 0, fde_addr;
02087   unw_accessors_t *a;
02088   int ret;
02089 
02090   assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE
02091          && (ip >= di->start_ip && ip < di->end_ip));
02092 
02093   a = unw_get_accessors (as);
02094 
02095   segbase = di->u.rti.segbase;
02096   e = lookup ((struct table_entry *) di->u.rti.table_data,
02097               di->u.rti.table_len * sizeof (unw_word_t), ip - segbase);
02098 
02099   if (!e)
02100     {
02101       /* IP is inside this table's range, but there is no explicit
02102         unwind info.  */
02103       return -UNW_ENOINFO;
02104     }
02105   Debug (15, "ip=0x%lx, start_ip=0x%lx\n",
02106         (long) ip, (long) (e->start_ip_offset + segbase));
02107   fde_addr = e->fde_offset + segbase;
02108   if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
02109                                           need_unwind_info, arg)) < 0)
02110     return ret;
02111 
02112   if (ip < pi->start_ip || ip >= pi->end_ip)
02113     return -UNW_ENOINFO;
02114 
02115   return 0;
02116 }
02117 
02118 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
02119 /*                                glue                                */
02120 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
02121 
02122 unw_addr_space_t unw_local_addr_space;
02123 unw_accessors_t *unw_get_accessors (unw_addr_space_t unw_local_addr_space)
02124 {
02125   return NULL;
02126 }
02127 
02128 #ifdef OS_X
02129 
02130 int dl_iterate_phdr (DL_Iter_Callback callback, void *p)
02131 {
02132   int i, c, j, n, size;
02133   const struct mach_header *mh;
02134   struct load_command *cmd;
02135   char *data;
02136   struct dl_phdr_info info;
02137   Phdr *phdr;
02138 
02139   c = _dyld_image_count();
02140 
02141   for (i = 0; i < c; i++) {
02142     mh = _dyld_get_image_header(i);
02143     n = mh->ncmds;
02144     cmd = (struct load_command *)((char *)mh + sizeof(*mh));
02145     data = (char *)cmd + mh->sizeofcmds;
02146     phdr = (Phdr *)malloc(sizeof(Phdr) * n);
02147 
02148     info.dlpi_phnum = n;
02149     info.dlpi_addr = (long)_dyld_get_image_vmaddr_slide(i);
02150     info.dlpi_name = _dyld_get_image_name(i);
02151     info.dlpi_phdr = phdr;
02152       
02153     for (j = 0; j < n; j++) {
02154       phdr[j].p_type = cmd->cmd;
02155       if (cmd->cmd == LC_SEGMENT) {
02156         struct segment_command *scmd = (struct segment_command *)cmd;
02157         phdr[j].p_vaddr = scmd->vmaddr;
02158         phdr[j].p_memsz = scmd->vmsize;
02159         phdr[j].p_filesz = scmd->filesize;
02160       }
02161       
02162       size = (cmd->cmdsize + sizeof(long) - 1) & ~(sizeof(long) - 1);
02163       cmd = (struct load_command *)((char *)cmd + size);
02164     }
02165 
02166     if (callback(&info, sizeof(info), p))
02167       return 1;
02168   }
02169 
02170   return 0;
02171 }
02172 
02173 #endif
02174 
02175 /***********************************************************************/
02176 
02177 #ifdef PLAIN_X86
02178 static uint8_t dwarf_to_unw_regnum_map[19] =
02179   {
02180     UNW_X86_EAX, UNW_X86_ECX, UNW_X86_EDX, UNW_X86_EBX,
02181     UNW_X86_ESP, UNW_X86_EBP, UNW_X86_ESI, UNW_X86_EDI,
02182     UNW_X86_EIP, UNW_X86_EFLAGS, UNW_X86_TRAPNO,
02183     UNW_X86_ST0, UNW_X86_ST1, UNW_X86_ST2, UNW_X86_ST3,
02184     UNW_X86_ST4, UNW_X86_ST5, UNW_X86_ST6, UNW_X86_ST7
02185   };
02186 #else 
02187 static uint8_t dwarf_to_unw_regnum_map[17] =
02188   {
02189     UNW_X86_64_RAX,
02190     UNW_X86_64_RDX,
02191     UNW_X86_64_RCX,
02192     UNW_X86_64_RBX,
02193     UNW_X86_64_RSI,
02194     UNW_X86_64_RDI,
02195     UNW_X86_64_RBP,
02196     UNW_X86_64_RSP,
02197     UNW_X86_64_R8,
02198     UNW_X86_64_R9,
02199     UNW_X86_64_R10,
02200     UNW_X86_64_R11,
02201     UNW_X86_64_R12,
02202     UNW_X86_64_R13,
02203     UNW_X86_64_R14,
02204     UNW_X86_64_R15,
02205     UNW_X86_64_RIP
02206   };
02207 #endif
02208 
02209 int
02210 unw_get_reg (unw_cursor_t *cursor, int regnum, unw_word_t *valp)
02211 {
02212   void *p;
02213 
02214   p = tdep_uc_addr(((struct cursor *)cursor)->dwarf.as_arg, regnum);
02215   if (p) {
02216     *valp = *(unw_word_t *)p;
02217     return 1;
02218   } else {
02219     *valp = -1;
02220     return 0;
02221   }
02222 }
02223 
02224 void *
02225 tdep_uc_addr (ucontext_t *uc, int reg)
02226 {
02227   void *addr;
02228 
02229   switch (reg)
02230     {
02231 #ifdef LINUX
02232 # ifdef PLAIN_X86
02233     case UNW_X86_GS:  addr = &uc->uc_mcontext.gregs[REG_GS]; break;
02234     case UNW_X86_FS:  addr = &uc->uc_mcontext.gregs[REG_FS]; break;
02235     case UNW_X86_ES:  addr = &uc->uc_mcontext.gregs[REG_ES]; break;
02236     case UNW_X86_DS:  addr = &uc->uc_mcontext.gregs[REG_DS]; break;
02237     case UNW_X86_EAX: addr = &uc->uc_mcontext.gregs[REG_EAX]; break;
02238     case UNW_X86_EBX: addr = &uc->uc_mcontext.gregs[REG_EBX]; break;
02239     case UNW_X86_ECX: addr = &uc->uc_mcontext.gregs[REG_ECX]; break;
02240     case UNW_X86_EDX: addr = &uc->uc_mcontext.gregs[REG_EDX]; break;
02241     case UNW_X86_ESI: addr = &uc->uc_mcontext.gregs[REG_ESI]; break;
02242     case UNW_X86_EDI: addr = &uc->uc_mcontext.gregs[REG_EDI]; break;
02243     case UNW_X86_EBP: addr = &uc->uc_mcontext.gregs[REG_EBP]; break;
02244     case UNW_X86_EIP: addr = &uc->uc_mcontext.gregs[REG_EIP]; break;
02245     case UNW_X86_ESP: addr = &uc->uc_mcontext.gregs[REG_ESP]; break;
02246     case UNW_X86_TRAPNO:  addr = &uc->uc_mcontext.gregs[REG_TRAPNO]; break;
02247     case UNW_X86_CS:  addr = &uc->uc_mcontext.gregs[REG_CS]; break;
02248     case UNW_X86_EFLAGS:  addr = &uc->uc_mcontext.gregs[REG_EFL]; break;
02249     case UNW_X86_SS:  addr = &uc->uc_mcontext.gregs[REG_SS]; break;
02250 # else
02251     case UNW_X86_64_R8: addr = &uc->uc_mcontext.gregs[REG_R8]; break;
02252     case UNW_X86_64_R9: addr = &uc->uc_mcontext.gregs[REG_R9]; break;
02253     case UNW_X86_64_R10: addr = &uc->uc_mcontext.gregs[REG_R10]; break;
02254     case UNW_X86_64_R11: addr = &uc->uc_mcontext.gregs[REG_R11]; break;
02255     case UNW_X86_64_R12: addr = &uc->uc_mcontext.gregs[REG_R12]; break;
02256     case UNW_X86_64_R13: addr = &uc->uc_mcontext.gregs[REG_R13]; break;
02257     case UNW_X86_64_R14: addr = &uc->uc_mcontext.gregs[REG_R14]; break;
02258     case UNW_X86_64_R15: addr = &uc->uc_mcontext.gregs[REG_R15]; break;
02259     case UNW_X86_64_RDI: addr = &uc->uc_mcontext.gregs[REG_RDI]; break;
02260     case UNW_X86_64_RSI: addr = &uc->uc_mcontext.gregs[REG_RSI]; break;
02261     case UNW_X86_64_RBP: addr = &uc->uc_mcontext.gregs[REG_RBP]; break;
02262     case UNW_X86_64_RBX: addr = &uc->uc_mcontext.gregs[REG_RBX]; break;
02263     case UNW_X86_64_RDX: addr = &uc->uc_mcontext.gregs[REG_RDX]; break;
02264     case UNW_X86_64_RAX: addr = &uc->uc_mcontext.gregs[REG_RAX]; break;
02265     case UNW_X86_64_RCX: addr = &uc->uc_mcontext.gregs[REG_RCX]; break;
02266     case UNW_X86_64_RSP: addr = &uc->uc_mcontext.gregs[REG_RSP]; break;
02267     case UNW_X86_64_RIP: addr = &uc->uc_mcontext.gregs[REG_RIP]; break;
02268 # endif
02269 #endif
02270 #ifdef OS_X
02271     case UNW_X86_GS:  addr = &uc->uc_mcontext->__ss.__gs; break;
02272     case UNW_X86_FS:  addr = &uc->uc_mcontext->__ss.__fs; break;
02273     case UNW_X86_ES:  addr = &uc->uc_mcontext->__ss.__es; break;
02274     case UNW_X86_DS:  addr = &uc->uc_mcontext->__ss.__ds; break;
02275     case UNW_X86_EAX: addr = &uc->uc_mcontext->__ss.__eax; break;
02276     case UNW_X86_EBX: addr = &uc->uc_mcontext->__ss.__ebx; break;
02277     case UNW_X86_ECX: addr = &uc->uc_mcontext->__ss.__ecx; break;
02278     case UNW_X86_EDX: addr = &uc->uc_mcontext->__ss.__edx; break;
02279     case UNW_X86_ESI: addr = &uc->uc_mcontext->__ss.__esi; break;
02280     case UNW_X86_EDI: addr = &uc->uc_mcontext->__ss.__edi; break;
02281     case UNW_X86_EBP: addr = &uc->uc_mcontext->__ss.__ebp; break;
02282     case UNW_X86_EIP: addr = &uc->uc_mcontext->__ss.__eip; break;
02283     case UNW_X86_ESP: addr = &uc->uc_mcontext->__ss.__esp; break;
02284     case UNW_X86_CS:  addr = &uc->uc_mcontext->__ss.__cs; break;
02285     case UNW_X86_EFLAGS:  addr = &uc->uc_mcontext->__ss.__eflags; break;
02286     case UNW_X86_SS:  addr = &uc->uc_mcontext->__ss.__ss; break;
02287 #endif
02288 
02289     default:
02290       addr = NULL;
02291     }
02292   return addr;
02293 }
02294 
02295 int dwarf_to_unw_regnum(reg)
02296 {
02297   return (((reg) <= DWARF_REGNUM_MAP_LENGTH) ? dwarf_to_unw_regnum_map[reg] : 0);
02298 }
02299 
02300 #ifdef PLAIN_X86
02301 /* DWARF column numbers: */
02302 #define EAX   0
02303 #define ECX   1
02304 #define EDX   2
02305 #define EBX   3
02306 #define ESP   4
02307 #define EBP   5
02308 #define ESI   6
02309 #define EDI   7
02310 #define EIP   8
02311 #define EFLAGS       9
02312 #define TRAPNO       10
02313 #define ST0   11
02314 #else
02315 /* DWARF column numbers for x86_64: */
02316 #define RAX   0
02317 #define RDX   1
02318 #define RCX   2
02319 #define RBX   3
02320 #define RSI   4
02321 #define RDI   5
02322 #define RBP   6
02323 #define RSP   7
02324 #define R8    8
02325 #define R9    9
02326 #define R10   10
02327 #define R11   11
02328 #define R12   12
02329 #define R13   13
02330 #define R14   14
02331 #define R15   15
02332 #define RIP   16
02333 #endif
02334 
02335 #ifdef PLAIN_X86
02336 static inline int
02337 common_init (struct cursor *c)
02338 {
02339   int ret, i;
02340 
02341   c->dwarf.loc[EAX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EAX);
02342   c->dwarf.loc[ECX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_ECX);
02343   c->dwarf.loc[EDX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EDX);
02344   c->dwarf.loc[EBX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EBX);
02345   c->dwarf.loc[ESP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_ESP);
02346   c->dwarf.loc[EBP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EBP);
02347   c->dwarf.loc[ESI] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EDI);
02348   c->dwarf.loc[EDI] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EDI);
02349   c->dwarf.loc[EIP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EIP);
02350   c->dwarf.loc[EFLAGS] = DWARF_REG_LOC (&c->dwarf, UNW_X86_EFLAGS);
02351   c->dwarf.loc[TRAPNO] = DWARF_REG_LOC (&c->dwarf, UNW_X86_TRAPNO);
02352   c->dwarf.loc[ST0] = DWARF_REG_LOC (&c->dwarf, UNW_X86_ST0);
02353   for (i = ST0 + 1; i < DWARF_NUM_PRESERVED_REGS; ++i)
02354     c->dwarf.loc[i] = DWARF_NULL_LOC;
02355 
02356   ret = dwarf_get (&c->dwarf, c->dwarf.loc[EIP], &c->dwarf.ip);
02357   if (ret < 0)
02358     return ret;
02359 
02360   ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_X86_ESP),
02361                  &c->dwarf.cfa);
02362   if (ret < 0)
02363     return ret;
02364 
02365   c->sigcontext_format = X86_SCF_NONE;
02366   c->sigcontext_addr = 0;
02367 
02368   c->dwarf.args_size = 0;
02369   c->dwarf.ret_addr_column = 0;
02370   c->dwarf.pi_valid = 0;
02371   c->dwarf.hint = 0;
02372   c->dwarf.prev_rs = 0;
02373 
02374   return 0;
02375 }
02376 #else
02377 static inline int
02378 common_init (struct cursor *c)
02379 {
02380   int ret;
02381 
02382   c->dwarf.loc[RAX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RAX);
02383   c->dwarf.loc[RDX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RDX);
02384   c->dwarf.loc[RCX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RCX);
02385   c->dwarf.loc[RBX] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RBX);
02386   c->dwarf.loc[RSI] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RSI);
02387   c->dwarf.loc[RDI] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RDI);
02388   c->dwarf.loc[RBP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RBP);
02389   c->dwarf.loc[RSP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RSP);
02390   c->dwarf.loc[R8]  = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_R8);
02391   c->dwarf.loc[R9]  = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_R9);
02392   c->dwarf.loc[R10] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_R10);
02393   c->dwarf.loc[R11] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_R11);
02394   c->dwarf.loc[R12] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_R12);
02395   c->dwarf.loc[R13] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_R13);
02396   c->dwarf.loc[R14] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_R14);
02397   c->dwarf.loc[R15] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_R15);
02398   c->dwarf.loc[RIP] = DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RIP);
02399 
02400   ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
02401   if (ret < 0)
02402     return ret;
02403 
02404   ret = dwarf_get (&c->dwarf, DWARF_REG_LOC (&c->dwarf, UNW_X86_64_RSP),
02405                  &c->dwarf.cfa);
02406   if (ret < 0)
02407     return ret;
02408 
02409   c->sigcontext_format = X86_SCF_NONE;
02410   c->sigcontext_addr = 0;
02411 
02412   c->dwarf.args_size = 0;
02413   c->dwarf.ret_addr_column = RIP;
02414   c->dwarf.pi_valid = 0;
02415   c->dwarf.hint = 0;
02416   c->dwarf.prev_rs = 0;
02417 
02418   return 0;
02419 }
02420 #endif
02421 
02422 int unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
02423 {
02424   struct cursor *c = (struct cursor *) cursor;
02425 
02426   Debug (1, "(cursor=%p)\n", c);
02427 
02428   if (!unw_local_addr_space) {
02429     unw_local_addr_space = (unw_addr_space_t)malloc(sizeof(struct unw_addr_space));
02430     memset(unw_local_addr_space, 0, sizeof(unw_local_addr_space));
02431   }
02432 
02433   c->dwarf.as = unw_local_addr_space;
02434   c->dwarf.as_arg = uc;
02435   return common_init (c);
02436 }
02437 
02438 int unw_step (unw_cursor_t *c)
02439 {
02440   return dwarf_step(&((struct cursor *)c)->dwarf);
02441 }
02442 
02443 static int saw_bad_ptr = 0;
02444 static char safe_space[8];
02445 static unw_word_t safe_start_address, safe_end_address;
02446 
02447 void unw_set_safe_pointer_range(unw_word_t s, unw_word_t e)
02448 {
02449   safe_start_address = s;
02450   safe_end_address = e;
02451 }
02452 
02453 int unw_reset_bad_ptr_flag()
02454 {
02455   int v = saw_bad_ptr;
02456   saw_bad_ptr = 0;
02457   return v;
02458 }
02459 
02460 static void *safe_pointer(unw_word_t p)
02461 {
02462   if (safe_start_address != safe_end_address)
02463     if ((p < safe_start_address)
02464        || (p >= safe_end_address)) {
02465       saw_bad_ptr = 1;
02466       return safe_space;
02467     }
02468 
02469   return (void *)p;
02470 }
02471 
02472 #if UNW_DEBUG
02473 int unwi_debug_level = 100;
02474 #endif
02475 
02476 unw_word_t unw_get_ip(unw_cursor_t *c)
02477 {
02478   return tdep_get_ip(((struct cursor *)c));
02479 }
02480 
02481 unw_word_t unw_get_frame_pointer(unw_cursor_t *c)
02482 {
02483   return *(unw_word_t *)safe_pointer(((struct cursor *)c)->dwarf.loc[6 /* = BP */].val);
02484 }
02485 
02486 void unw_manual_step(unw_cursor_t *_c, 
02487                    void *ip_addr,
02488                    void *bp_addr,
02489                    void *sp_addr,
02490                    void *bx_addr,
02491                    void *r12_addr,
02492                    void *r13_addr)
02493 {
02494   struct cursor *c = (struct cursor *)_c;
02495 
02496   c->dwarf.loc[3].val = (unw_word_t)bx_addr;
02497   c->dwarf.loc[6].val = (unw_word_t)bp_addr;
02498   c->dwarf.loc[7].val = (unw_word_t)sp_addr;
02499   c->dwarf.loc[12].val = (unw_word_t)r12_addr;
02500   c->dwarf.loc[13].val = (unw_word_t)r13_addr;
02501   c->dwarf.loc[16].val = (unw_word_t)ip_addr;
02502 
02503   c->dwarf.ip = *(unw_word_t *)safe_pointer((unw_word_t)ip_addr);
02504   c->dwarf.cfa = *(unw_word_t *)safe_pointer((unw_word_t)sp_addr);
02505   c->dwarf.ret_addr_column = RIP;
02506   c->dwarf.pi_valid = 0;
02507   c->dwarf.hint = 0;
02508   c->dwarf.prev_rs = 0;
02509 }
02510 
02511 #endif