13842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz/* libunwind - a platform-independent unwind library
23842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz   Copyright (C) 2008 CodeSourcery
33842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
43842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzThis file is part of libunwind.
53842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
63842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzPermission is hereby granted, free of charge, to any person obtaining
73842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitza copy of this software and associated documentation files (the
83842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz"Software"), to deal in the Software without restriction, including
93842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitzwithout limitation the rights to use, copy, modify, merge, publish,
103842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitzdistribute, sublicense, and/or sell copies of the Software, and to
113842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitzpermit persons to whom the Software is furnished to do so, subject to
123842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitzthe following conditions:
133842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
143842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzThe above copyright notice and this permission notice shall be
153842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitzincluded in all copies or substantial portions of the Software.
163842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
173842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
183842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
193842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
203842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
213842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
223842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
233842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
243842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
253842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz#include "unwind_i.h"
263842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz#include "offsets.h"
273842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
283842dac7333e42aa44531eda34ba55200b99ccf8Daniel JacobowitzPROTECTED int
298c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazkerunw_handle_signal_frame (unw_cursor_t *cursor)
303842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz{
313842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  struct cursor *c = (struct cursor *) cursor;
328c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
338c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  unw_word_t ra, fp;
343842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  int ret;
353842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
368c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  /* FIXME (simon): Save the SP and PC to be able to return execution
378c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker     at this point later in time (unw_resume). */
388c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  // c->sigcontext_sp = c->dwarf.cfa;
398c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  // c->sigcontext_pc = c->dwarf.ip;
408c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
418c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  switch (unw_is_signal_frame (cursor)) {
428c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  case 1:
438c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    sc_addr = sp_addr + LINUX_SF_TRAMP_SIZE + sizeof (siginfo_t) +
448c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker	    LINUX_UC_MCONTEXT_OFF;
458c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    break;
468c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  case 2:
47b02a66eca4d44c8901c7a0c447abbf2cab2ef891Faraz Shahbazker    sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF;
488c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    break;
498c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  default:
508c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    return -UNW_EUNSPEC;
518c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  }
528c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
538c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  if (tdep_big_endian(c->dwarf.as))
548c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    sc_addr += 4;
558c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
568c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->sigcontext_addr = sc_addr;
578c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
588c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  /* Update the dwarf cursor. */
598c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R0]  = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0);
608c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R1]  = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0);
618c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R2]  = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0);
628c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R3]  = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0);
638c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R4]  = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0);
648c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R5]  = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0);
658c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R6]  = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0);
668c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R7]  = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0);
678c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R8]  = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0);
688c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R9]  = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0);
698c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0);
708c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R11] = DWARF_LOC (sc_addr + LINUX_SC_R11_OFF, 0);
718c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R12] = DWARF_LOC (sc_addr + LINUX_SC_R12_OFF, 0);
728c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R13] = DWARF_LOC (sc_addr + LINUX_SC_R13_OFF, 0);
738c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R14] = DWARF_LOC (sc_addr + LINUX_SC_R14_OFF, 0);
748c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R15] = DWARF_LOC (sc_addr + LINUX_SC_R15_OFF, 0);
758c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R16] = DWARF_LOC (sc_addr + LINUX_SC_R16_OFF, 0);
768c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R17] = DWARF_LOC (sc_addr + LINUX_SC_R17_OFF, 0);
778c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R18] = DWARF_LOC (sc_addr + LINUX_SC_R18_OFF, 0);
788c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R19] = DWARF_LOC (sc_addr + LINUX_SC_R19_OFF, 0);
798c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R20] = DWARF_LOC (sc_addr + LINUX_SC_R20_OFF, 0);
808c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R21] = DWARF_LOC (sc_addr + LINUX_SC_R21_OFF, 0);
818c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R22] = DWARF_LOC (sc_addr + LINUX_SC_R22_OFF, 0);
828c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R23] = DWARF_LOC (sc_addr + LINUX_SC_R23_OFF, 0);
838c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R24] = DWARF_LOC (sc_addr + LINUX_SC_R24_OFF, 0);
848c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R25] = DWARF_LOC (sc_addr + LINUX_SC_R25_OFF, 0);
858c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R26] = DWARF_LOC (sc_addr + LINUX_SC_R26_OFF, 0);
868c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R27] = DWARF_LOC (sc_addr + LINUX_SC_R27_OFF, 0);
878c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R28] = DWARF_LOC (sc_addr + LINUX_SC_R28_OFF, 0);
888c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R29] = DWARF_LOC (sc_addr + LINUX_SC_R29_OFF, 0);
898c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R30] = DWARF_LOC (sc_addr + LINUX_SC_R30_OFF, 0);
908c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_R31] = DWARF_LOC (sc_addr + LINUX_SC_R31_OFF, 0);
918c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.loc[UNW_MIPS_PC] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0);
928c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
938c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  /* Set SP/CFA and PC/IP. */
948c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_R29], &c->dwarf.cfa);
958c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  //dwarf_get (&c->dwarf, c->dwarf.loc[UNW_MIPS_R31], &c->dwarf.ip);
968c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
978c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_PC_OFF, 0),
988c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker		       &c->dwarf.ip)) < 0)
998c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    return ret;
1008c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
1018c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_R31_OFF, 0),
1028c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker		       &ra)) < 0)
1038c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    return ret;
1048c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  if ((ret = dwarf_get(&c->dwarf, DWARF_LOC(sc_addr + LINUX_SC_R30_OFF, 0),
1058c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker		       &fp)) < 0)
1068c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    return ret;
1078c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
1088c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  Debug (2, "SH (ip=0x%016llx, ra=0x%016llx, sp=0x%016llx, fp=0x%016llx)\n",
1098c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker         (unsigned long long)c->dwarf.ip, (unsigned long long)ra,
1108c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker	 (unsigned long long)c->dwarf.cfa, (unsigned long long)fp);
1118c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
1128c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.pi_valid = 0;
1138c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  c->dwarf.use_prev_instr = 0;
1148c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
1158c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  return 1;
1168c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker}
1178c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker
1188c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz ShahbazkerPROTECTED int
1198c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazkerunw_step (unw_cursor_t *cursor)
1208c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker{
1218c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  struct cursor *c = (struct cursor *) cursor;
1228c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  int ret;
1233842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
124ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris  unw_word_t old_ip = c->dwarf.ip;
125ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris  unw_word_t old_cfa = c->dwarf.cfa;
126ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris
1278c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  ret = unw_handle_signal_frame (cursor);
1288c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker  if (ret < 0)
1298c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    /* Not a signal frame, try DWARF-based unwinding. */
1308c380e9d596cc9dbc39423e0d8ae5ee51da6be2bFaraz Shahbazker    ret = dwarf_step (&c->dwarf);
1313842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
1323842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  if (unlikely (ret == -UNW_ESTOPUNWIND))
1333842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz    return ret;
1343842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
1353842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  /* Dwarf unwinding didn't work, stop.  */
1363842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  if (unlikely (ret < 0))
1373842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz    return 0;
1383842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
139ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris  /* If the decode yields the exact same ip/cfa as before, then indicate
140ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris     the unwind is complete. */
141ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris  if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa)
142ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris    {
143ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris      Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
144ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris               __FUNCTION__, (long) c->dwarf.ip);
145ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris      return -UNW_EBADFRAME;
146ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris    }
147ba74ff681be3b1e9fab247c15b30887b8237449eChristopher Ferris
1483842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  return (c->dwarf.ip == 0) ? 0 : 1;
1493842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz}
150