<s> static void ia64_copy_rbs ( struct _Unwind_Context * info , unsigned long dst , unsigned long src , long len , unsigned long dst_rnat ) { long count ; unsigned long src_rnat ; unsigned long shift1 , shift2 ; len <<= 3 ; dst_rnat &= ( 1UL << ( ( dst >> 3 ) & 0x3f ) ) - 1 ; src_rnat = src >= info -> regstk_top ? info -> rnat : * ( unsigned long * ) ( src | 0x1f8 ) ; src_rnat &= ~ ( ( 1UL << ( ( src >> 3 ) & 0x3f ) ) - 1 ) ; src_rnat &= ~ ( 1UL << 63 ) ; shift1 = ( ( dst - src ) >> 3 ) & 0x3f ; if ( ( dst & 0x1f8 ) < ( src & 0x1f8 ) ) shift1 -- ; shift2 = 0x3f - shift1 ; if ( ( dst & 0x1f8 ) >= ( src & 0x1f8 ) ) { count = ~ dst & 0x1f8 ; goto first ; } count = ~ src & 0x1f8 ; goto second ; while ( len > 0 ) { src_rnat = src >= info -> regstk_top ? info -> rnat : * ( unsigned long * ) ( src | 0x1f8 ) ; src_rnat &= ~ ( 1UL << 63 ) ; count = shift2 << 3 ; first : if ( count > len ) count = len ; memcpy ( ( char * ) dst , ( char * ) src , count ) ; dst += count ; src += count ; len -= count ; dst_rnat |= ( src_rnat << shift1 ) & ~ ( 1UL << 63 ) ; if ( len <= 0 ) break ; * ( long * ) dst = dst_rnat ; dst += 8 ; dst_rnat = 0 ; count = shift1 << 3 ; second : if ( count > len ) count = len ; memcpy ( ( char * ) dst , ( char * ) src , count ) ; dst += count ; src += count + 8 ; len -= count + 8 ; dst_rnat |= ( src_rnat >> shift2 ) ; } if ( ( dst & 0x1f8 ) == 0x1f8 ) { * ( long * ) dst = dst_rnat ; dst += 8 ; dst_rnat = 0 ; } info -> regstk_top = dst & ~ 0x1ffUL ; info -> rnat = dst_rnat ; } </s>

Copy register backing store from SRC to DST , LEN words ( which include both saved registers and nat collections ) . DST_RNAT is a partial nat collection for DST . SRC and DST do n't have to be equal modulo 64 slots , so it can not be done with a simple memcpy as the nat collections will be at different relative offsets and need to be combined together .


<s> static void unw_access_gr ( struct _Unwind_Context * info , int regnum , unsigned long * val , char * nat , int write ) { unsigned long * addr , * nat_addr = 0 , nat_mask = 0 , dummy_nat ; struct unw_ireg * ireg ; if ( ( unsigned ) regnum - 1 >= 127 ) abort ( ) ; if ( regnum < 1 ) { nat_addr = addr = & dummy_nat ; dummy_nat = 0 ; } else if ( regnum < 32 ) { ireg = & info -> ireg [ regnum - 2 ] ; addr = ireg -> loc ; if ( addr ) { nat_addr = addr + ireg -> nat . off ; switch ( ireg -> nat . type ) { case UNW_NAT_VAL : if ( write ) { if ( * nat ) { addr [ 0 ] = 0 ; addr [ 1 ] = 0x1fffe ; return ; } addr [ 1 ] = 0x1003e ; } else if ( addr [ 0 ] == 0 && addr [ 1 ] == 0x1ffe ) { * val = 0 ; * nat = 1 ; return ; } case UNW_NAT_NONE : dummy_nat = 0 ; nat_addr = & dummy_nat ; break ; case UNW_NAT_MEMSTK : nat_mask = 1UL << ( ( long ) addr & 0x1f8 ) / 8 ; break ; case UNW_NAT_REGSTK : if ( ( unsigned long ) addr >= info -> regstk_top ) nat_addr = & info -> rnat ; else nat_addr = ia64_rse_rnat_addr ( addr ) ; nat_mask = 1UL << ia64_rse_slot_num ( addr ) ; break ; } } } else { addr = ia64_rse_skip_regs ( ( unsigned long * ) info -> bsp , regnum - 32 ) ; if ( ( unsigned long ) addr >= info -> regstk_top ) nat_addr = & info -> rnat ; else nat_addr = ia64_rse_rnat_addr ( addr ) ; nat_mask = 1UL << ia64_rse_slot_num ( addr ) ; } if ( write ) { * addr = * val ; if ( * nat ) * nat_addr |= nat_mask ; else * nat_addr &= ~ nat_mask ; } else { * val = * addr ; * nat = ( * nat_addr & nat_mask ) != 0 ; } } </s>


<s> static struct unw_reg_state * alloc_reg_state ( void ) { struct unw_reg_state * rs ; reg_state_alloced ++ ; rs = malloc ( sizeof ( struct unw_reg_state ) ) ; if ( ! rs ) { int n = atomic_alloc ( & emergency_reg_state_free ) ; if ( n >= 0 ) rs = & emergency_reg_state [ n ] ; } return rs ; } </s>

Allocation and deallocation of structures .


<s> static inline int atomic_alloc ( unsigned int * mask ) { unsigned int old = * mask , ret , new ; while ( 1 ) { if ( old == 0 ) return - 1 ; ret = old & - old ; new = old & ~ ret ; new = __sync_val_compare_and_swap ( mask , old , new ) ; if ( old == new ) break ; old = new ; } return __builtin_ffs ( ret ) - 1 ; } </s>

MASK is a bitmap describing the allocation state of emergency buffers , with bit set indicating free . Return > = 0 if allocation is successful ; < 0 if failure .


<s> static inline void atomic_free ( unsigned int * mask , int bit ) { __sync_xor_and_fetch ( mask , 1 << bit ) ; } </s>


<s> static inline void desc_abi ( unsigned char abi __attribute__ ( ( unused ) ) , unsigned char context __attribute__ ( ( unused ) ) , struct unw_state_record * sr __attribute__ ( ( unused ) ) ) { } </s>


<s> static inline void desc_epilogue ( unw_word t , unw_word ecount , struct unw_state_record * sr ) { sr -> epilogue_start = sr -> region_start + sr -> region_len - 1 - t ; sr -> epilogue_count = ecount + 1 ; } </s>


<s> static inline int desc_is_active ( unsigned char qp , unw_word t , struct unw_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 & ( 1UL << qp ) ) == 0 ) return 0 ; sr -> pr_mask |= ( 1UL << qp ) ; } return 1 ; } </s>


<s> static void desc_prologue ( int body , unw_word rlen , unsigned char mask , unsigned char grsave , struct unw_state_record * sr ) { int i ; if ( ! ( sr -> in_body || sr -> first_region ) ) finish_prologue ( sr ) ; sr -> first_region = 0 ; if ( sr -> when_target < sr -> region_start + sr -> region_len ) { sr -> done = 1 ; return ; } for ( i = 0 ; i < sr -> epilogue_count ; ++ i ) pop ( sr ) ; sr -> epilogue_count = 0 ; sr -> epilogue_start = UNW_WHEN_NEVER ; if ( ! body ) push ( sr ) ; sr -> region_start += sr -> region_len ; sr -> region_len = rlen ; sr -> in_body = body ; if ( ! body ) { for ( i = 0 ; i < 4 ; ++ i ) { if ( mask & 0x8 ) set_reg ( sr -> curr . reg + save_order [ i ] , UNW_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 ; } } </s>


<s> static struct unw_reg_state * dup_state_stack ( struct unw_reg_state * rs ) { struct unw_reg_state * copy , * prev = NULL , * first = NULL ; while ( rs ) { copy = alloc_reg_state ( ) ; memcpy ( copy , rs , sizeof ( * copy ) ) ; if ( first ) prev -> next = copy ; else first = copy ; rs = rs -> next ; prev = copy ; } return first ; } </s>

Make a copy of the state stack . Non-recursive to avoid stack overflows .


<s> static void free_label_states ( struct unw_labeled_state * ls ) { struct unw_labeled_state * next ; for ( ; ls ; ls = next ) { next = ls -> next ; free_state_stack ( & ls -> saved_state ) ; free_label_state ( ls ) ; } } </s>


<s> static void free_state_stack ( struct unw_reg_state * rs ) { struct unw_reg_state * p , * next ; for ( p = rs -> next ; p != NULL ; p = next ) { next = p -> next ; free_reg_state ( p ) ; } rs -> next = NULL ; } </s>

Free all stacked register states ( but not RS itself ) .


<s> static inline unsigned long ia64_rse_is_rnat_slot ( unsigned long * addr ) { return ia64_rse_slot_num ( addr ) == 0x3f ; } </s>

Return TRUE if ADDR is the address of an RNAT slot .


<s> static inline unsigned long ia64_rse_num_regs ( unsigned long * bspstore , unsigned long * bsp ) { unsigned long slots = ( bsp - bspstore ) ; return slots - ( ia64_rse_slot_num ( bspstore ) + slots ) / 0x40 ; } </s>

Calculate the number of registers in the dirty partition starting at BSPSTORE with a size of DIRTY bytes . This is n't simply DIRTY divided by eight because the 64th slot is used to store ar.rnat .


<s> static inline unsigned long * ia64_rse_rnat_addr ( unsigned long * slot_addr ) { return ( unsigned long * ) ( ( unsigned long ) slot_addr | ( 0x3f << 3 ) ) ; } </s>

Returns the address of the RNAT slot that covers the slot at address SLOT_ADDR .


<s> static inline unsigned long * ia64_rse_skip_regs ( unsigned long * addr , long num_regs ) { long delta = ia64_rse_slot_num ( addr ) + num_regs ; if ( num_regs < 0 ) delta -= 0x3e ; return addr + num_regs + delta / 0x3f ; } </s>

The inverse of the above : given bspstore and the number of registers , calculate ar.bsp .


<s> static inline unsigned long ia64_rse_slot_num ( unsigned long * addr ) { return ( ( ( unsigned long ) addr ) >> 3 ) & 0x3f ; } </s>


<s> static void pop ( struct unw_state_record * sr ) { struct unw_reg_state * rs = sr -> curr . next ; if ( ! rs ) abort ( ) ; memcpy ( & sr -> curr , rs , sizeof ( * rs ) ) ; free_reg_state ( rs ) ; } </s>

Output RTL to pop register RN from the stack .


<s> static void push ( struct unw_state_record * sr ) { struct unw_reg_state * rs = alloc_reg_state ( ) ; memcpy ( rs , & sr -> curr , sizeof ( * rs ) ) ; sr -> curr . next = rs ; } </s>

Output RTL to push register RN onto the stack .


<s> static void unw_access_gr ( struct _Unwind_Context * info , int regnum , unsigned long * val , char * nat , int write ) { unsigned long * addr , * nat_addr = 0 , nat_mask = 0 , dummy_nat ; struct unw_ireg * ireg ; if ( ( unsigned ) regnum - 1 >= 127 ) abort ( ) ; if ( regnum < 1 ) { nat_addr = addr = & dummy_nat ; dummy_nat = 0 ; } else if ( regnum < 32 ) { ireg = & info -> ireg [ regnum - 2 ] ; addr = ireg -> loc ; if ( addr ) { nat_addr = addr + ireg -> nat . off ; switch ( ireg -> nat . type ) { case UNW_NAT_VAL : if ( write ) { if ( * nat ) { addr [ 0 ] = 0 ; addr [ 1 ] = 0x1fffe ; return ; } addr [ 1 ] = 0x1003e ; } else if ( addr [ 0 ] == 0 && addr [ 1 ] == 0x1ffe ) { * val = 0 ; * nat = 1 ; return ; } case UNW_NAT_NONE : dummy_nat = 0 ; nat_addr = & dummy_nat ; break ; case UNW_NAT_MEMSTK : nat_mask = 1UL << ( ( long ) addr & 0x1f8 ) / 8 ; break ; case UNW_NAT_REGSTK : nat_addr = ia64_rse_rnat_addr ( addr ) ; if ( ( unsigned long ) nat_addr >= info -> regstk_top ) nat_addr = & info -> rnat ; nat_mask = 1UL << ia64_rse_slot_num ( addr ) ; break ; } } } else { addr = ia64_rse_skip_regs ( ( unsigned long * ) info -> bsp , regnum - 32 ) ; nat_addr = ia64_rse_rnat_addr ( addr ) ; if ( ( unsigned long ) nat_addr >= info -> regstk_top ) nat_addr = & info -> rnat ; nat_mask = 1UL << ia64_rse_slot_num ( addr ) ; } if ( write ) { * addr = * val ; if ( * nat ) * nat_addr |= nat_mask ; else * nat_addr &= ~ nat_mask ; } else { * val = * addr ; * nat = ( * nat_addr & nat_mask ) != 0 ; } } </s>


<s> static inline unsigned char * unw_decode ( unsigned char * dp , int inside_body , void * arg ) { unw_decoder decoder ; unsigned char code ; code = * dp ++ ; decoder = unw_decode_table [ inside_body ] [ code >> 5 ] ; dp = ( * decoder ) ( dp , code , arg ) ; return dp ; } </s>

Decode one descriptor and return address of next descriptor .