123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131 |
- /* libunwind - a platform-independent unwind library
- Copyright (C) 2001-2004 Hewlett-Packard Co
- Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
- This file is part of libunwind.
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- #include "unwind_i.h"
- /* forward declaration: */
- static int create_state_record_for (struct cursor *c,
- struct ia64_state_record *sr,
- unw_word_t ip);
- typedef unsigned long unw_word;
- #define alloc_reg_state() (mempool_alloc (&unw.reg_state_pool))
- #define free_reg_state(rs) (mempool_free (&unw.reg_state_pool, rs))
- #define alloc_labeled_state() (mempool_alloc (&unw.labeled_state_pool))
- #define free_labeled_state(s) (mempool_free (&unw.labeled_state_pool, s))
- /* Routines to manipulate the state stack. */
- static inline void
- push (struct ia64_state_record *sr)
- {
- struct ia64_reg_state *rs;
- rs = alloc_reg_state ();
- if (!rs)
- {
- print_error ("libunwind: cannot stack reg state!\n");
- return;
- }
- memcpy (rs, &sr->curr, sizeof (*rs));
- sr->curr.next = rs;
- }
- static void
- pop (struct ia64_state_record *sr)
- {
- struct ia64_reg_state *rs = sr->curr.next;
- if (!rs)
- {
- print_error ("libunwind: stack underflow!\n");
- return;
- }
- memcpy (&sr->curr, rs, sizeof (*rs));
- free_reg_state (rs);
- }
- /* Make a copy of the state stack. Non-recursive to avoid stack overflows. */
- static struct ia64_reg_state *
- dup_state_stack (struct ia64_reg_state *rs)
- {
- struct ia64_reg_state *copy, *prev = NULL, *first = NULL;
- while (rs)
- {
- copy = alloc_reg_state ();
- if (!copy)
- {
- print_error ("unwind.dup_state_stack: out of memory\n");
- return NULL;
- }
- memcpy (copy, rs, sizeof (*copy));
- if (first)
- prev->next = copy;
- else
- first = copy;
- rs = rs->next;
- prev = copy;
- }
- return first;
- }
- /* Free all stacked register states (but not RS itself). */
- static void
- free_state_stack (struct ia64_reg_state *rs)
- {
- struct ia64_reg_state *p, *next;
- for (p = rs->next; p != NULL; p = next)
- {
- next = p->next;
- free_reg_state (p);
- }
- rs->next = NULL;
- }
- /* Unwind decoder routines */
- static enum ia64_pregnum __attribute__ ((const))
- decode_abreg (unsigned char abreg, int memory)
- {
- switch (abreg)
- {
- case 0x04 ... 0x07:
- return IA64_REG_R4 + (abreg - 0x04);
- case 0x22 ... 0x25:
- return IA64_REG_F2 + (abreg - 0x22);
- case 0x30 ... 0x3f:
- return IA64_REG_F16 + (abreg - 0x30);
- case 0x41 ... 0x45:
- return IA64_REG_B1 + (abreg - 0x41);
- case 0x60:
- return IA64_REG_PR;
- case 0x61:
- return IA64_REG_PSP;
- case 0x62:
- return memory ? IA64_REG_PRI_UNAT_MEM : IA64_REG_PRI_UNAT_GR;
- case 0x63:
- return IA64_REG_IP;
- case 0x64:
- return IA64_REG_BSP;
- case 0x65:
- return IA64_REG_BSPSTORE;
- case 0x66:
- return IA64_REG_RNAT;
- case 0x67:
- return IA64_REG_UNAT;
- case 0x68:
- return IA64_REG_FPSR;
- case 0x69:
- return IA64_REG_PFS;
- case 0x6a:
- return IA64_REG_LC;
- default:
- break;
- }
- Dprintf ("libunwind: bad abreg=0x%x\n", abreg);
- return IA64_REG_LC;
- }
- static void
- set_reg (struct ia64_reg_info *reg, enum ia64_where where, int when,
- unsigned long val)
- {
- reg->val = val;
- reg->where = where;
- if (reg->when == IA64_WHEN_NEVER)
- reg->when = when;
- }
- static void
- alloc_spill_area (unsigned long *offp, unsigned long regsize,
- struct ia64_reg_info *lo, struct ia64_reg_info *hi)
- {
- struct ia64_reg_info *reg;
- for (reg = hi; reg >= lo; --reg)
- {
- if (reg->where == IA64_WHERE_SPILL_HOME)
- {
- reg->where = IA64_WHERE_PSPREL;
- *offp -= regsize;
- reg->val = *offp;
- }
- }
- }
- static inline void
- spill_next_when (struct ia64_reg_info **regp, struct ia64_reg_info *lim,
- unw_word t)
- {
- struct ia64_reg_info *reg;
- for (reg = *regp; reg <= lim; ++reg)
- {
- if (reg->where == IA64_WHERE_SPILL_HOME)
- {
- reg->when = t;
- *regp = reg + 1;
- return;
- }
- }
- Dprintf ("libunwind: excess spill!\n");
- }
- static inline void
- finish_prologue (struct ia64_state_record *sr)
- {
- struct ia64_reg_info *reg;
- unsigned long off;
- int i;
- /* First, resolve implicit register save locations (see Section
- "11.4.2.3 Rules for Using Unwind Descriptors", rule 3). */
- for (i = 0; i < (int) ARRAY_SIZE (unw.save_order); ++i)
- {
- reg = sr->curr.reg + unw.save_order[i];
- if (reg->where == IA64_WHERE_GR_SAVE)
- {
- reg->where = IA64_WHERE_GR;
- reg->val = sr->gr_save_loc++;
- }
- }
- /* Next, compute when the fp, general, and branch registers get
- saved. This must come before alloc_spill_area() because we need
- to know which registers are spilled to their home locations. */
- if (sr->imask)
- {
- unsigned char kind, mask = 0, *cp = sr->imask;
- unsigned long t;
- static const unsigned char limit[3] =
- {
- IA64_REG_F31, IA64_REG_R7, IA64_REG_B5
- };
- struct ia64_reg_info *(regs[3]);
- regs[0] = sr->curr.reg + IA64_REG_F2;
- regs[1] = sr->curr.reg + IA64_REG_R4;
- regs[2] = sr->curr.reg + IA64_REG_B1;
- for (t = 0; (int) t < sr->region_len; ++t)
- {
- if ((t & 3) == 0)
- mask = *cp++;
- kind = (mask >> 2 * (3 - (t & 3))) & 3;
- if (kind > 0)
- spill_next_when (®s[kind - 1], sr->curr.reg + limit[kind - 1],
- sr->region_start + t);
- }
- }
- /* Next, lay out the memory stack spill area. */
- if (sr->any_spills)
- {
- off = sr->spill_offset;
- alloc_spill_area (&off, 16, sr->curr.reg + IA64_REG_F2,
- sr->curr.reg + IA64_REG_F31);
- alloc_spill_area (&off, 8, sr->curr.reg + IA64_REG_B1,
- sr->curr.reg + IA64_REG_B5);
- alloc_spill_area (&off, 8, sr->curr.reg + IA64_REG_R4,
- sr->curr.reg + IA64_REG_R7);
- }
- }
- /* Region header descriptors. */
- static void
- desc_prologue (int body, unw_word rlen, unsigned char mask,
- unsigned char grsave, struct ia64_state_record *sr)
- {
- int i, region_start;
- if (!(sr->in_body || sr->first_region))
- finish_prologue (sr);
- sr->first_region = 0;
- /* check if we're done: */
- if (sr->when_target < sr->region_start + sr->region_len)
- {
- sr->done = 1;
- return;
- }
- region_start = sr->region_start + sr->region_len;
- for (i = 0; i < sr->epilogue_count; ++i)
- pop (sr);
- sr->epilogue_count = 0;
- sr->when_sp_restored = IA64_WHEN_NEVER;
- sr->region_start = region_start;
- sr->region_len = rlen;
- sr->in_body = body;
- if (!body)
- {
- push (sr);
- if (mask)
- for (i = 0; i < 4; ++i)
- {
- if (mask & 0x8)
- set_reg (sr->curr.reg + unw.save_order[i], IA64_WHERE_GR,
- sr->region_start + sr->region_len - 1, grsave++);
- mask <<= 1;
- }
- sr->gr_save_loc = grsave;
- sr->any_spills = 0;
- sr->imask = 0;
- sr->spill_offset = 0x10; /* default to psp+16 */
- }
- }
- /* Prologue descriptors. */
- static inline void
- desc_abi (unsigned char abi, unsigned char context,
- struct ia64_state_record *sr)
- {
- sr->abi_marker = (abi << 8) | context;
- }
- static inline void
- desc_br_gr (unsigned char brmask, unsigned char gr,
- struct ia64_state_record *sr)
- {
- int i;
- for (i = 0; i < 5; ++i)
- {
- if (brmask & 1)
- set_reg (sr->curr.reg + IA64_REG_B1 + i, IA64_WHERE_GR,
- sr->region_start + sr->region_len - 1, gr++);
- brmask >>= 1;
- }
- }
- static inline void
- desc_br_mem (unsigned char brmask, struct ia64_state_record *sr)
- {
- int i;
- for (i = 0; i < 5; ++i)
- {
- if (brmask & 1)
- {
- set_reg (sr->curr.reg + IA64_REG_B1 + i, IA64_WHERE_SPILL_HOME,
- sr->region_start + sr->region_len - 1, 0);
- sr->any_spills = 1;
- }
- brmask >>= 1;
- }
- }
- static inline void
- desc_frgr_mem (unsigned char grmask, unw_word frmask,
- struct ia64_state_record *sr)
- {
- int i;
- for (i = 0; i < 4; ++i)
- {
- if ((grmask & 1) != 0)
- {
- set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_SPILL_HOME,
- sr->region_start + sr->region_len - 1, 0);
- sr->any_spills = 1;
- }
- grmask >>= 1;
- }
- for (i = 0; i < 20; ++i)
- {
- if ((frmask & 1) != 0)
- {
- int base = (i < 4) ? IA64_REG_F2 : IA64_REG_F16 - 4;
- set_reg (sr->curr.reg + base + i, IA64_WHERE_SPILL_HOME,
- sr->region_start + sr->region_len - 1, 0);
- sr->any_spills = 1;
- }
- frmask >>= 1;
- }
- }
- static inline void
- desc_fr_mem (unsigned char frmask, struct ia64_state_record *sr)
- {
- int i;
- for (i = 0; i < 4; ++i)
- {
- if ((frmask & 1) != 0)
- {
- set_reg (sr->curr.reg + IA64_REG_F2 + i, IA64_WHERE_SPILL_HOME,
- sr->region_start + sr->region_len - 1, 0);
- sr->any_spills = 1;
- }
- frmask >>= 1;
- }
- }
- static inline void
- desc_gr_gr (unsigned char grmask, unsigned char gr,
- struct ia64_state_record *sr)
- {
- int i;
- for (i = 0; i < 4; ++i)
- {
- if ((grmask & 1) != 0)
- set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_GR,
- sr->region_start + sr->region_len - 1, gr++);
- grmask >>= 1;
- }
- }
- static inline void
- desc_gr_mem (unsigned char grmask, struct ia64_state_record *sr)
- {
- int i;
- for (i = 0; i < 4; ++i)
- {
- if ((grmask & 1) != 0)
- {
- set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_SPILL_HOME,
- sr->region_start + sr->region_len - 1, 0);
- sr->any_spills = 1;
- }
- grmask >>= 1;
- }
- }
- static inline void
- desc_mem_stack_f (unw_word t, unw_word size, struct ia64_state_record *sr)
- {
- set_reg (sr->curr.reg + IA64_REG_PSP, IA64_WHERE_NONE,
- sr->region_start + MIN ((int) t, sr->region_len - 1), 16 * size);
- }
- static inline void
- desc_mem_stack_v (unw_word t, struct ia64_state_record *sr)
- {
- sr->curr.reg[IA64_REG_PSP].when =
- sr->region_start + MIN ((int) t, sr->region_len - 1);
- }
- static inline void
- desc_reg_gr (unsigned char reg, unsigned char dst,
- struct ia64_state_record *sr)
- {
- set_reg (sr->curr.reg + reg, IA64_WHERE_GR,
- sr->region_start + sr->region_len - 1, dst);
- }
- static inline void
- desc_reg_psprel (unsigned char reg, unw_word pspoff,
- struct ia64_state_record *sr)
- {
- set_reg (sr->curr.reg + reg, IA64_WHERE_PSPREL,
- sr->region_start + sr->region_len - 1, 0x10 - 4 * pspoff);
- }
- static inline void
- desc_reg_sprel (unsigned char reg, unw_word spoff,
- struct ia64_state_record *sr)
- {
- set_reg (sr->curr.reg + reg, IA64_WHERE_SPREL,
- sr->region_start + sr->region_len - 1, 4 * spoff);
- }
- static inline void
- desc_rp_br (unsigned char dst, struct ia64_state_record *sr)
- {
- sr->return_link_reg = dst;
- }
- static inline void
- desc_reg_when (unsigned char regnum, unw_word t, struct ia64_state_record *sr)
- {
- struct ia64_reg_info *reg = sr->curr.reg + regnum;
- if (reg->where == IA64_WHERE_NONE)
- reg->where = IA64_WHERE_GR_SAVE;
- reg->when = sr->region_start + MIN ((int) t, sr->region_len - 1);
- }
- static inline void
- desc_spill_base (unw_word pspoff, struct ia64_state_record *sr)
- {
- sr->spill_offset = 0x10 - 4 * pspoff;
- }
- static inline unsigned char *
- desc_spill_mask (unsigned char *imaskp, struct ia64_state_record *sr)
- {
- sr->imask = imaskp;
- return imaskp + (2 * sr->region_len + 7) / 8;
- }
- /* Body descriptors. */
- static inline void
- desc_epilogue (unw_word t, unw_word ecount, struct ia64_state_record *sr)
- {
- sr->when_sp_restored = sr->region_start + sr->region_len - 1 - t;
- sr->epilogue_count = ecount + 1;
- }
- static inline void
- desc_copy_state (unw_word label, struct ia64_state_record *sr)
- {
- struct ia64_labeled_state *ls;
- for (ls = sr->labeled_states; ls; ls = ls->next)
- {
- if (ls->label == label)
- {
- free_state_stack (&sr->curr);
- memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr));
- sr->curr.next = dup_state_stack (ls->saved_state.next);
- return;
- }
- }
- print_error ("libunwind: failed to find labeled state\n");
- }
- static inline void
- desc_label_state (unw_word label, struct ia64_state_record *sr)
- {
- struct ia64_labeled_state *ls;
- ls = alloc_labeled_state ();
- if (!ls)
- {
- print_error ("unwind.desc_label_state(): out of memory\n");
- return;
- }
- ls->label = label;
- memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state));
- ls->saved_state.next = dup_state_stack (sr->curr.next);
- /* insert into list of labeled states: */
- ls->next = sr->labeled_states;
- sr->labeled_states = ls;
- }
- /* General descriptors. */
- static inline int
- desc_is_active (unsigned char qp, unw_word t, struct ia64_state_record *sr)
- {
- if (sr->when_target <= sr->region_start + MIN ((int) t, sr->region_len - 1))
- return 0;
- if (qp > 0)
- {
- if ((sr->pr_val & ((unw_word_t) 1 << qp)) == 0)
- return 0;
- sr->pr_mask |= ((unw_word_t) 1 << qp);
- }
- return 1;
- }
- static inline void
- desc_restore_p (unsigned char qp, unw_word t, unsigned char abreg,
- struct ia64_state_record *sr)
- {
- struct ia64_reg_info *r;
- if (!desc_is_active (qp, t, sr))
- return;
- r = sr->curr.reg + decode_abreg (abreg, 0);
- r->where = IA64_WHERE_NONE;
- r->when = IA64_WHEN_NEVER;
- r->val = 0;
- }
- static inline void
- desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg,
- unsigned char x, unsigned char ytreg,
- struct ia64_state_record *sr)
- {
- enum ia64_where where = IA64_WHERE_GR;
- struct ia64_reg_info *r;
- if (!desc_is_active (qp, t, sr))
- return;
- if (x)
- where = IA64_WHERE_BR;
- else if (ytreg & 0x80)
- where = IA64_WHERE_FR;
- r = sr->curr.reg + decode_abreg (abreg, 0);
- r->where = where;
- r->when = sr->region_start + MIN ((int) t, sr->region_len - 1);
- r->val = (ytreg & 0x7f);
- }
- static inline void
- desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg,
- unw_word pspoff, struct ia64_state_record *sr)
- {
- struct ia64_reg_info *r;
- if (!desc_is_active (qp, t, sr))
- return;
- r = sr->curr.reg + decode_abreg (abreg, 1);
- r->where = IA64_WHERE_PSPREL;
- r->when = sr->region_start + MIN ((int) t, sr->region_len - 1);
- r->val = 0x10 - 4 * pspoff;
- }
- static inline void
- desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg,
- unw_word spoff, struct ia64_state_record *sr)
- {
- struct ia64_reg_info *r;
- if (!desc_is_active (qp, t, sr))
- return;
- r = sr->curr.reg + decode_abreg (abreg, 1);
- r->where = IA64_WHERE_SPREL;
- r->when = sr->region_start + MIN ((int) t, sr->region_len - 1);
- r->val = 4 * spoff;
- }
- #define UNW_DEC_BAD_CODE(code) \
- print_error ("libunwind: unknown code encountered\n")
- /* Register names. */
- #define UNW_REG_BSP IA64_REG_BSP
- #define UNW_REG_BSPSTORE IA64_REG_BSPSTORE
- #define UNW_REG_FPSR IA64_REG_FPSR
- #define UNW_REG_LC IA64_REG_LC
- #define UNW_REG_PFS IA64_REG_PFS
- #define UNW_REG_PR IA64_REG_PR
- #define UNW_REG_RNAT IA64_REG_RNAT
- #define UNW_REG_PSP IA64_REG_PSP
- #define UNW_REG_RP IA64_REG_IP
- #define UNW_REG_UNAT IA64_REG_UNAT
- /* Region headers. */
- #define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg)
- #define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg)
- /* Prologue descriptors. */
- #define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg)
- #define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg)
- #define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg)
- #define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg)
- #define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg)
- #define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg)
- #define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg)
- #define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg)
- #define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg)
- #define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg)
- #define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg)
- #define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg)
- #define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg)
- #define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) \
- desc_reg_when(IA64_REG_PRI_UNAT_GR,t,arg)
- #define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) \
- desc_reg_when(IA64_REG_PRI_UNAT_MEM,t,arg)
- #define UNW_DEC_PRIUNAT_GR(fmt,r,arg) \
- desc_reg_gr(IA64_REG_PRI_UNAT_GR,r,arg)
- #define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) \
- desc_reg_psprel(IA64_REG_PRI_UNAT_MEM,o,arg)
- #define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) \
- desc_reg_sprel(IA64_REG_PRI_UNAT_MEM,o,arg)
- #define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg)
- #define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg)
- #define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg))
- /* Body descriptors. */
- #define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg)
- #define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg)
- #define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg)
- /* General unwind descriptors. */
- #define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg)
- #define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg)
- #define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) \
- desc_spill_psprel_p(p,t,a,o,arg)
- #define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) \
- desc_spill_psprel_p(0,t,a,o,arg)
- #define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg)
- #define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg)
- #define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg)
- #define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg)
- #include "unwind_decoder.h"
- #ifdef _U_dyn_op
- /* parse dynamic unwind info */
- static struct ia64_reg_info *
- lookup_preg (int regnum, int memory, struct ia64_state_record *sr)
- {
- int preg;
- switch (regnum)
- {
- case UNW_IA64_AR_BSP: preg = IA64_REG_BSP; break;
- case UNW_IA64_AR_BSPSTORE: preg = IA64_REG_BSPSTORE; break;
- case UNW_IA64_AR_FPSR: preg = IA64_REG_FPSR; break;
- case UNW_IA64_AR_LC: preg = IA64_REG_LC; break;
- case UNW_IA64_AR_PFS: preg = IA64_REG_PFS; break;
- case UNW_IA64_AR_RNAT: preg = IA64_REG_RNAT; break;
- case UNW_IA64_AR_UNAT: preg = IA64_REG_UNAT; break;
- case UNW_IA64_BR + 0: preg = IA64_REG_IP; break;
- case UNW_IA64_PR: preg = IA64_REG_PR; break;
- case UNW_IA64_SP: preg = IA64_REG_PSP; break;
- case UNW_IA64_NAT:
- if (memory)
- preg = IA64_REG_PRI_UNAT_MEM;
- else
- preg = IA64_REG_PRI_UNAT_GR;
- break;
- case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7:
- preg = IA64_REG_R4 + (regnum - (UNW_IA64_GR + 4));
- break;
- case UNW_IA64_BR + 1 ... UNW_IA64_BR + 5:
- preg = IA64_REG_B1 + (regnum - UNW_IA64_BR);
- break;
- case UNW_IA64_FR + 2 ... UNW_IA64_FR + 5:
- preg = IA64_REG_F2 + (regnum - (UNW_IA64_FR + 2));
- break;
- case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31:
- preg = IA64_REG_F16 + (regnum - (UNW_IA64_FR + 16));
- break;
- default:
- Dprintf ("%s: invalid register number %d\n", __FUNCTION__, regnum);
- return NULL;
- }
- return sr->curr.reg + preg;
- }
- /* An alias directive inside a region of length RLEN is interpreted to
- mean that the region behaves exactly like the first RLEN
- instructions at the aliased IP. RLEN=0 implies that the current
- state matches exactly that of before the instruction at the aliased
- IP is executed. */
- static int
- desc_alias (unw_dyn_op_t *op, struct cursor *c, struct ia64_state_record *sr)
- {
- struct ia64_state_record orig_sr = *sr;
- int i, ret, when, rlen = sr->region_len;
- unw_word_t new_ip;
- when = MIN (sr->when_target, rlen);
- new_ip = op->val + ((when / 3) * 16 + (when % 3));
- if ((ret = ia64_fetch_proc_info (c, new_ip, 1)) < 0)
- return ret;
- if ((ret = create_state_record_for (c, sr, new_ip)) < 0)
- return ret;
- sr->first_region = orig_sr.first_region;
- sr->done = 0;
- sr->any_spills |= orig_sr.any_spills;
- sr->in_body = orig_sr.in_body;
- sr->region_start = orig_sr.region_start;
- sr->region_len = orig_sr.region_len;
- if (sr->when_sp_restored != IA64_WHEN_NEVER)
- sr->when_sp_restored = op->when + MIN (orig_sr.when_sp_restored, rlen);
- sr->epilogue_count = orig_sr.epilogue_count;
- sr->when_target = orig_sr.when_target;
- for (i = 0; i < IA64_NUM_PREGS; ++i)
- if (sr->curr.reg[i].when != IA64_WHEN_NEVER)
- sr->curr.reg[i].when = op->when + MIN (sr->curr.reg[i].when, rlen);
- ia64_free_state_record (sr);
- sr->labeled_states = orig_sr.labeled_states;
- sr->curr.next = orig_sr.curr.next;
- return 0;
- }
- static inline int
- parse_dynamic (struct cursor *c, struct ia64_state_record *sr)
- {
- unw_dyn_info_t *di = c->pi.unwind_info;
- unw_dyn_proc_info_t *proc = &di->u.pi;
- unw_dyn_region_info_t *r;
- struct ia64_reg_info *ri;
- enum ia64_where where;
- int32_t when, len;
- unw_dyn_op_t *op;
- unw_word_t val;
- int memory, ret;
- int8_t qp;
- for (r = proc->regions; r; r = r->next)
- {
- len = r->insn_count;
- if (len < 0)
- {
- if (r->next)
- {
- Debug (1, "negative region length allowed in last region only!");
- return -UNW_EINVAL;
- }
- len = -len;
- /* hack old region info to set the start where we need it: */
- sr->region_start = (di->end_ip - di->start_ip) / 0x10 * 3 - len;
- sr->region_len = 0;
- }
- /* all regions are treated as prologue regions: */
- desc_prologue (0, len, 0, 0, sr);
- if (sr->done)
- return 0;
- for (op = r->op; op < r->op + r->op_count; ++op)
- {
- when = op->when;
- val = op->val;
- qp = op->qp;
- if (!desc_is_active (qp, when, sr))
- continue;
- when = sr->region_start + MIN ((int) when, sr->region_len - 1);
- switch (op->tag)
- {
- case UNW_DYN_SAVE_REG:
- memory = 0;
- if ((unsigned) (val - UNW_IA64_GR) < 128)
- where = IA64_WHERE_GR;
- else if ((unsigned) (val - UNW_IA64_FR) < 128)
- where = IA64_WHERE_FR;
- else if ((unsigned) (val - UNW_IA64_BR) < 8)
- where = IA64_WHERE_BR;
- else
- {
- Dprintf ("%s: can't save to register number %d\n",
- __FUNCTION__, (int) op->reg);
- return -UNW_EBADREG;
- }
- /* fall through */
- update_reg_info:
- ri = lookup_preg (op->reg, memory, sr);
- if (!ri)
- return -UNW_EBADREG;
- ri->where = where;
- ri->when = when;
- ri->val = val;
- break;
- case UNW_DYN_SPILL_FP_REL:
- memory = 1;
- where = IA64_WHERE_PSPREL;
- val = 0x10 - val;
- goto update_reg_info;
- case UNW_DYN_SPILL_SP_REL:
- memory = 1;
- where = IA64_WHERE_SPREL;
- goto update_reg_info;
- case UNW_DYN_ADD:
- if (op->reg == UNW_IA64_SP)
- {
- if (val & 0xf)
- {
- Dprintf ("%s: frame-size %ld not an integer "
- "multiple of 16\n",
- __FUNCTION__, (long) op->val);
- return -UNW_EINVAL;
- }
- desc_mem_stack_f (when, -((int64_t) val / 16), sr);
- }
- else
- {
- Dprintf ("%s: can only ADD to stack-pointer\n",
- __FUNCTION__);
- return -UNW_EBADREG;
- }
- break;
- case UNW_DYN_POP_FRAMES:
- sr->when_sp_restored = when;
- sr->epilogue_count = op->val;
- break;
- case UNW_DYN_LABEL_STATE:
- desc_label_state (op->val, sr);
- break;
- case UNW_DYN_COPY_STATE:
- desc_copy_state (op->val, sr);
- break;
- case UNW_DYN_ALIAS:
- if ((ret = desc_alias (op, c, sr)) < 0)
- return ret;
- case UNW_DYN_STOP:
- goto end_of_ops;
- }
- }
- end_of_ops:
- ;
- }
- return 0;
- }
- #else
- # define parse_dynamic(c,sr) (-UNW_EINVAL)
- #endif /* _U_dyn_op */
- HIDDEN int
- ia64_fetch_proc_info (struct cursor *c, unw_word_t ip, int need_unwind_info)
- {
- int ret, dynamic = 1;
- if (c->pi_valid && !need_unwind_info)
- return 0;
- /* check dynamic info first --- it overrides everything else */
- ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, need_unwind_info,
- c->as_arg);
- if (ret == -UNW_ENOINFO)
- {
- dynamic = 0;
- ret = ia64_find_proc_info (c, ip, need_unwind_info);
- }
- c->pi_valid = 1;
- c->pi_is_dynamic = dynamic;
- return ret;
- }
- static inline void
- put_unwind_info (struct cursor *c, unw_proc_info_t *pi)
- {
- if (!c->pi_valid)
- return;
- if (c->pi_is_dynamic)
- unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg);
- else
- ia64_put_unwind_info (c, pi);
- }
- static int
- create_state_record_for (struct cursor *c, struct ia64_state_record *sr,
- unw_word_t ip)
- {
- unw_word_t predicates = c->pr;
- struct ia64_reg_info *r;
- uint8_t *dp, *desc_end;
- int ret;
- assert (c->pi_valid);
- /* build state record */
- memset (sr, 0, sizeof (*sr));
- for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r)
- r->when = IA64_WHEN_NEVER;
- sr->pr_val = predicates;
- sr->first_region = 1;
- if (!c->pi.unwind_info)
- {
- /* No info, return default unwinder (leaf proc, no mem stack, no
- saved regs), rp in b0, pfs in ar.pfs. */
- Debug (1, "no unwind info for ip=0x%lx (gp=%lx)\n",
- (long) ip, (long) c->pi.gp);
- sr->curr.reg[IA64_REG_IP].where = IA64_WHERE_BR;
- sr->curr.reg[IA64_REG_IP].when = -1;
- sr->curr.reg[IA64_REG_IP].val = 0;
- goto out;
- }
- sr->when_target = (3 * ((ip & ~(unw_word_t) 0xf) - c->pi.start_ip) / 16
- + (ip & 0xf));
- switch (c->pi.format)
- {
- case UNW_INFO_FORMAT_TABLE:
- case UNW_INFO_FORMAT_REMOTE_TABLE:
- dp = c->pi.unwind_info;
- desc_end = dp + c->pi.unwind_info_size;
- while (!sr->done && dp < desc_end)
- dp = unw_decode (dp, sr->in_body, sr);
- ret = 0;
- break;
- case UNW_INFO_FORMAT_DYNAMIC:
- ret = parse_dynamic (c, sr);
- break;
- default:
- ret = -UNW_EINVAL;
- }
- put_unwind_info (c, &c->pi);
- if (ret < 0)
- return ret;
- if (sr->when_target > sr->when_sp_restored)
- {
- /* sp has been restored and all values on the memory stack below
- psp also have been restored. */
- sr->curr.reg[IA64_REG_PSP].val = 0;
- sr->curr.reg[IA64_REG_PSP].where = IA64_WHERE_NONE;
- sr->curr.reg[IA64_REG_PSP].when = IA64_WHEN_NEVER;
- for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r)
- if ((r->where == IA64_WHERE_PSPREL && r->val <= 0x10)
- || r->where == IA64_WHERE_SPREL)
- {
- r->val = 0;
- r->where = IA64_WHERE_NONE;
- r->when = IA64_WHEN_NEVER;
- }
- }
- /* If RP did't get saved, generate entry for the return link
- register. */
- if (sr->curr.reg[IA64_REG_IP].when >= sr->when_target)
- {
- sr->curr.reg[IA64_REG_IP].where = IA64_WHERE_BR;
- sr->curr.reg[IA64_REG_IP].when = -1;
- sr->curr.reg[IA64_REG_IP].val = sr->return_link_reg;
- }
- if (sr->when_target > sr->curr.reg[IA64_REG_BSP].when
- && sr->when_target > sr->curr.reg[IA64_REG_BSPSTORE].when
- && sr->when_target > sr->curr.reg[IA64_REG_RNAT].when)
- {
- Debug (8, "func 0x%lx may switch the register-backing-store\n",
- c->pi.start_ip);
- c->pi.flags |= UNW_PI_FLAG_IA64_RBS_SWITCH;
- }
- out:
- #if UNW_DEBUG
- if (unwi_debug_level > 2)
- {
- Dprintf ("%s: state record for func 0x%lx, t=%u (flags=0x%lx):\n",
- __FUNCTION__,
- (long) c->pi.start_ip, sr->when_target, (long) c->pi.flags);
- for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r)
- {
- if (r->where != IA64_WHERE_NONE || r->when != IA64_WHEN_NEVER)
- {
- Dprintf (" %s <- ", unw.preg_name[r - sr->curr.reg]);
- switch (r->where)
- {
- case IA64_WHERE_GR:
- Dprintf ("r%lu", (long) r->val);
- break;
- case IA64_WHERE_FR:
- Dprintf ("f%lu", (long) r->val);
- break;
- case IA64_WHERE_BR:
- Dprintf ("b%lu", (long) r->val);
- break;
- case IA64_WHERE_SPREL:
- Dprintf ("[sp+0x%lx]", (long) r->val);
- break;
- case IA64_WHERE_PSPREL:
- Dprintf ("[psp+0x%lx]", (long) r->val);
- break;
- case IA64_WHERE_NONE:
- Dprintf ("%s+0x%lx",
- unw.preg_name[r - sr->curr.reg], (long) r->val);
- break;
- default:
- Dprintf ("BADWHERE(%d)", r->where);
- break;
- }
- Dprintf ("\t\t%d\n", r->when);
- }
- }
- }
- #endif
- return 0;
- }
- /* The proc-info must be valid for IP before this routine can be
- called. */
- HIDDEN int
- ia64_create_state_record (struct cursor *c, struct ia64_state_record *sr)
- {
- return create_state_record_for (c, sr, c->ip);
- }
- HIDDEN int
- ia64_free_state_record (struct ia64_state_record *sr)
- {
- struct ia64_labeled_state *ls, *next;
- /* free labeled register states & stack: */
- for (ls = sr->labeled_states; ls; ls = next)
- {
- next = ls->next;
- free_state_stack (&ls->saved_state);
- free_labeled_state (ls);
- }
- free_state_stack (&sr->curr);
- return 0;
- }
- HIDDEN int
- ia64_make_proc_info (struct cursor *c)
- {
- int ret, caching = c->as->caching_policy != UNW_CACHE_NONE;
- if (!caching || ia64_get_cached_proc_info (c) < 0)
- {
- /* Lookup it up the slow way... */
- if ((ret = ia64_fetch_proc_info (c, c->ip, 0)) < 0)
- return ret;
- if (caching)
- ia64_cache_proc_info (c);
- }
- return 0;
- }
|