Home | History | Annotate | Download | only in x86
      1 /* libunwind - a platform-independent unwind library
      2    Copyright (C) 2002-2004 Hewlett-Packard Co
      3 	Contributed by David Mosberger-Tang <davidm (at) 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 "unwind_i.h"
     27 #include "offsets.h"
     28 
     29 PROTECTED int
     30 unw_is_signal_frame (unw_cursor_t *cursor)
     31 {
     32   struct cursor *c = (struct cursor *) cursor;
     33   unw_word_t w0, w1, ip;
     34   unw_addr_space_t as;
     35   unw_accessors_t *a;
     36   void *arg;
     37   int ret;
     38 
     39   as = c->dwarf.as;
     40   a = unw_get_accessors (as);
     41   arg = c->dwarf.as_arg;
     42 
     43   /* Check if EIP points at sigreturn() sequence.  On Linux, this is:
     44 
     45     __restore:
     46 	0x58				pop %eax
     47 	0xb8 0x77 0x00 0x00 0x00	movl 0x77,%eax
     48 	0xcd 0x80			int 0x80
     49 
     50      without SA_SIGINFO, and
     51 
     52     __restore_rt:
     53        0xb8 0xad 0x00 0x00 0x00        movl 0xad,%eax
     54        0xcd 0x80                       int 0x80
     55        0x00
     56 
     57      if SA_SIGINFO is specified.
     58   */
     59   ip = c->dwarf.ip;
     60   if (c->dwarf.frame != 0) {
     61     /* Need to adjust the ip because we adjusted it down in the step call. */
     62     ip++;
     63   }
     64   if ((*a->access_mem) (as, ip, &w0, 0, arg) < 0
     65       || (*a->access_mem) (as, ip + 4, &w1, 0, arg) < 0)
     66     ret = 0;
     67   else
     68     ret = ((w0 == 0x0077b858 && w1 == 0x80cd0000)
     69 	 || (w0 == 0x0000adb8 && (w1 & 0xffffff) == 0x80cd00));
     70   Debug (16, "returning %d\n", ret);
     71   return ret;
     72 }
     73 
     74 PROTECTED int
     75 unw_handle_signal_frame (unw_cursor_t *cursor)
     76 {
     77   struct cursor *c = (struct cursor *) cursor;
     78   int ret;
     79 
     80   /* c->esp points at the arguments to the handler.  Without
     81      SA_SIGINFO, the arguments consist of a signal number
     82      followed by a struct sigcontext.  With SA_SIGINFO, the
     83      arguments consist a signal number, a siginfo *, and a
     84      ucontext *. */
     85   unw_word_t sc_addr;
     86   unw_word_t siginfo_ptr_addr = c->dwarf.cfa + 4;
     87   unw_word_t sigcontext_ptr_addr = c->dwarf.cfa + 8;
     88   unw_word_t siginfo_ptr, sigcontext_ptr;
     89   struct dwarf_loc esp_loc, siginfo_ptr_loc, sigcontext_ptr_loc;
     90 
     91   siginfo_ptr_loc = DWARF_LOC (siginfo_ptr_addr, 0);
     92   sigcontext_ptr_loc = DWARF_LOC (sigcontext_ptr_addr, 0);
     93   ret = (dwarf_get (&c->dwarf, siginfo_ptr_loc, &siginfo_ptr)
     94 	 | dwarf_get (&c->dwarf, sigcontext_ptr_loc, &sigcontext_ptr));
     95   if (ret < 0)
     96     {
     97       Debug (2, "returning 0\n");
     98       return 0;
     99     }
    100   if (siginfo_ptr < c->dwarf.cfa
    101       || siginfo_ptr > c->dwarf.cfa + 256
    102       || sigcontext_ptr < c->dwarf.cfa
    103       || sigcontext_ptr > c->dwarf.cfa + 256)
    104     {
    105       /* Not plausible for SA_SIGINFO signal */
    106       c->sigcontext_format = X86_SCF_LINUX_SIGFRAME;
    107       c->sigcontext_addr = sc_addr = c->dwarf.cfa + 4;
    108     }
    109   else
    110     {
    111       /* If SA_SIGINFO were not specified, we actually read
    112 	 various segment pointers instead.  We believe that at
    113 	 least fs and _fsh are always zero for linux, so it is
    114 	 not just unlikely, but impossible that we would end
    115 	 up here. */
    116       c->sigcontext_format = X86_SCF_LINUX_RT_SIGFRAME;
    117       c->sigcontext_addr = sigcontext_ptr;
    118       sc_addr = sigcontext_ptr + LINUX_UC_MCONTEXT_OFF;
    119     }
    120   esp_loc = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
    121   ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
    122   if (ret < 0)
    123     {
    124       Debug (2, "returning 0\n");
    125       return 0;
    126     }
    127 
    128   c->dwarf.loc[EAX] = DWARF_LOC (sc_addr + LINUX_SC_EAX_OFF, 0);
    129   c->dwarf.loc[ECX] = DWARF_LOC (sc_addr + LINUX_SC_ECX_OFF, 0);
    130   c->dwarf.loc[EDX] = DWARF_LOC (sc_addr + LINUX_SC_EDX_OFF, 0);
    131   c->dwarf.loc[EBX] = DWARF_LOC (sc_addr + LINUX_SC_EBX_OFF, 0);
    132   c->dwarf.loc[EBP] = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0);
    133   c->dwarf.loc[ESI] = DWARF_LOC (sc_addr + LINUX_SC_ESI_OFF, 0);
    134   c->dwarf.loc[EDI] = DWARF_LOC (sc_addr + LINUX_SC_EDI_OFF, 0);
    135   c->dwarf.loc[EFLAGS] = DWARF_NULL_LOC;
    136   c->dwarf.loc[TRAPNO] = DWARF_NULL_LOC;
    137   c->dwarf.loc[ST0] = DWARF_NULL_LOC;
    138   c->dwarf.loc[EIP] = DWARF_LOC (sc_addr + LINUX_SC_EIP_OFF, 0);
    139   c->dwarf.loc[ESP] = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
    140 
    141   return 0;
    142 }
    143 
    144 HIDDEN dwarf_loc_t
    145 x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg)
    146 {
    147   unw_word_t addr = c->sigcontext_addr, fpstate_addr, off;
    148   int ret, is_fpstate = 0;
    149 
    150   switch (c->sigcontext_format)
    151     {
    152     case X86_SCF_NONE:
    153       return DWARF_REG_LOC (&c->dwarf, reg);
    154 
    155     case X86_SCF_LINUX_SIGFRAME:
    156       break;
    157 
    158     case X86_SCF_LINUX_RT_SIGFRAME:
    159       addr += LINUX_UC_MCONTEXT_OFF;
    160       break;
    161 
    162     default:
    163       return DWARF_NULL_LOC;
    164     }
    165 
    166   switch (reg)
    167     {
    168     case UNW_X86_GS: off = LINUX_SC_GS_OFF; break;
    169     case UNW_X86_FS: off = LINUX_SC_FS_OFF; break;
    170     case UNW_X86_ES: off = LINUX_SC_ES_OFF; break;
    171     case UNW_X86_DS: off = LINUX_SC_DS_OFF; break;
    172     case UNW_X86_EDI: off = LINUX_SC_EDI_OFF; break;
    173     case UNW_X86_ESI: off = LINUX_SC_ESI_OFF; break;
    174     case UNW_X86_EBP: off = LINUX_SC_EBP_OFF; break;
    175     case UNW_X86_ESP: off = LINUX_SC_ESP_OFF; break;
    176     case UNW_X86_EBX: off = LINUX_SC_EBX_OFF; break;
    177     case UNW_X86_EDX: off = LINUX_SC_EDX_OFF; break;
    178     case UNW_X86_ECX: off = LINUX_SC_ECX_OFF; break;
    179     case UNW_X86_EAX: off = LINUX_SC_EAX_OFF; break;
    180     case UNW_X86_TRAPNO: off = LINUX_SC_TRAPNO_OFF; break;
    181     case UNW_X86_EIP: off = LINUX_SC_EIP_OFF; break;
    182     case UNW_X86_CS: off = LINUX_SC_CS_OFF; break;
    183     case UNW_X86_EFLAGS: off = LINUX_SC_EFLAGS_OFF; break;
    184     case UNW_X86_SS: off = LINUX_SC_SS_OFF; break;
    185 
    186       /* The following is probably not correct for all possible cases.
    187 	 Somebody who understands this better should review this for
    188 	 correctness.  */
    189 
    190     case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break;
    191     case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break;
    192     case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break;
    193     case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break;
    194     case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break;
    195     case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break;
    196     case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break;
    197     case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break;
    198 
    199       /* stacked fp registers */
    200     case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
    201     case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
    202       is_fpstate = 1;
    203       off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0);
    204       break;
    205 
    206      /* SSE fp registers */
    207     case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
    208     case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
    209     case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
    210     case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
    211     case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
    212     case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
    213     case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
    214     case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
    215       is_fpstate = 1;
    216       off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
    217       break;
    218     case UNW_X86_XMM0:
    219     case UNW_X86_XMM1:
    220     case UNW_X86_XMM2:
    221     case UNW_X86_XMM3:
    222     case UNW_X86_XMM4:
    223     case UNW_X86_XMM5:
    224     case UNW_X86_XMM6:
    225     case UNW_X86_XMM7:
    226       is_fpstate = 1;
    227       off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
    228       break;
    229 
    230     case UNW_X86_FOP:
    231     case UNW_X86_TSS:
    232     case UNW_X86_LDT:
    233     default:
    234       return DWARF_REG_LOC (&c->dwarf, reg);
    235     }
    236 
    237   if (is_fpstate)
    238     {
    239       if ((ret = dwarf_get (&c->dwarf,
    240 			    DWARF_MEM_LOC (&c->dwarf,
    241 					   addr + LINUX_SC_FPSTATE_OFF),
    242 			    &fpstate_addr)) < 0)
    243 	return DWARF_NULL_LOC;
    244 
    245       if (!fpstate_addr)
    246 	return DWARF_NULL_LOC;
    247 
    248       return DWARF_MEM_LOC (c, fpstate_addr + off);
    249     }
    250   else
    251     return DWARF_MEM_LOC (c, addr + off);
    252 }
    253 
    254 #ifndef UNW_REMOTE_ONLY
    255 HIDDEN void *
    256 x86_r_uc_addr (ucontext_t *uc, int reg)
    257 {
    258   void *addr;
    259 
    260   switch (reg)
    261     {
    262     case UNW_X86_GS:  addr = &uc->uc_mcontext.gregs[REG_GS]; break;
    263     case UNW_X86_FS:  addr = &uc->uc_mcontext.gregs[REG_FS]; break;
    264     case UNW_X86_ES:  addr = &uc->uc_mcontext.gregs[REG_ES]; break;
    265     case UNW_X86_DS:  addr = &uc->uc_mcontext.gregs[REG_DS]; break;
    266     case UNW_X86_EAX: addr = &uc->uc_mcontext.gregs[REG_EAX]; break;
    267     case UNW_X86_EBX: addr = &uc->uc_mcontext.gregs[REG_EBX]; break;
    268     case UNW_X86_ECX: addr = &uc->uc_mcontext.gregs[REG_ECX]; break;
    269     case UNW_X86_EDX: addr = &uc->uc_mcontext.gregs[REG_EDX]; break;
    270     case UNW_X86_ESI: addr = &uc->uc_mcontext.gregs[REG_ESI]; break;
    271     case UNW_X86_EDI: addr = &uc->uc_mcontext.gregs[REG_EDI]; break;
    272     case UNW_X86_EBP: addr = &uc->uc_mcontext.gregs[REG_EBP]; break;
    273     case UNW_X86_EIP: addr = &uc->uc_mcontext.gregs[REG_EIP]; break;
    274     case UNW_X86_ESP: addr = &uc->uc_mcontext.gregs[REG_ESP]; break;
    275     case UNW_X86_TRAPNO:  addr = &uc->uc_mcontext.gregs[REG_TRAPNO]; break;
    276     case UNW_X86_CS:  addr = &uc->uc_mcontext.gregs[REG_CS]; break;
    277     case UNW_X86_EFLAGS:  addr = &uc->uc_mcontext.gregs[REG_EFL]; break;
    278     case UNW_X86_SS:  addr = &uc->uc_mcontext.gregs[REG_SS]; break;
    279 
    280     default:
    281       addr = NULL;
    282     }
    283   return addr;
    284 }
    285 
    286 HIDDEN int
    287 x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
    288 {
    289   struct cursor *c = (struct cursor *) cursor;
    290 #if !defined(__ANDROID__)
    291   ucontext_t *uc = c->uc;
    292 #endif
    293 
    294   /* Ensure c->pi is up-to-date.  On x86, it's relatively common to be
    295      missing DWARF unwind info.  We don't want to fail in that case,
    296      because the frame-chain still would let us do a backtrace at
    297      least.  */
    298   dwarf_make_proc_info (&c->dwarf);
    299 
    300   if (unlikely (c->sigcontext_format != X86_SCF_NONE))
    301     {
    302       struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
    303       (void)sc;
    304 
    305       Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
    306 
    307 #if !defined(__ANDROID__)
    308       sigreturn (sc);
    309 #endif
    310     }
    311   else
    312     {
    313       Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip);
    314 #if !defined(__ANDROID__)
    315       setcontext (uc);
    316 #endif
    317     }
    318   return -UNW_EINVAL;
    319 }
    320 #endif
    321