xref: /netbsd-src/external/gpl3/binutils/dist/gas/scfi.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1*cb63e24eSchristos /* scfi.c - Support for synthesizing DWARF CFI for hand-written asm.
2*cb63e24eSchristos    Copyright (C) 2023 Free Software Foundation, Inc.
3*cb63e24eSchristos 
4*cb63e24eSchristos    This file is part of GAS, the GNU Assembler.
5*cb63e24eSchristos 
6*cb63e24eSchristos    GAS is free software; you can redistribute it and/or modify
7*cb63e24eSchristos    it under the terms of the GNU General Public License as published by
8*cb63e24eSchristos    the Free Software Foundation; either version 3, or (at your option)
9*cb63e24eSchristos    any later version.
10*cb63e24eSchristos 
11*cb63e24eSchristos    GAS is distributed in the hope that it will be useful,
12*cb63e24eSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*cb63e24eSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*cb63e24eSchristos    GNU General Public License for more details.
15*cb63e24eSchristos 
16*cb63e24eSchristos    You should have received a copy of the GNU General Public License
17*cb63e24eSchristos    along with GAS; see the file COPYING.  If not, write to the Free
18*cb63e24eSchristos    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19*cb63e24eSchristos    02110-1301, USA.  */
20*cb63e24eSchristos 
21*cb63e24eSchristos #include "as.h"
22*cb63e24eSchristos #include "scfi.h"
23*cb63e24eSchristos #include "subsegs.h"
24*cb63e24eSchristos #include "scfidw2gen.h"
25*cb63e24eSchristos #include "dw2gencfi.h"
26*cb63e24eSchristos 
27*cb63e24eSchristos #if defined (TARGET_USE_SCFI) && defined (TARGET_USE_GINSN)
28*cb63e24eSchristos 
29*cb63e24eSchristos /* Beyond the target defined number of registers to be tracked
30*cb63e24eSchristos    (SCFI_MAX_REG_ID), keep the next register ID, in sequence, for REG_CFA.  */
31*cb63e24eSchristos #define REG_CFA	      (SCFI_MAX_REG_ID+1)
32*cb63e24eSchristos /* Define the total number of registers being tracked.
33*cb63e24eSchristos    Used as index into an array of cfi_reglocS.  Note that a ginsn may carry a
34*cb63e24eSchristos    register number greater than MAX_NUM_SCFI_REGS, e.g., for the ginsns
35*cb63e24eSchristos    corresponding to push fs/gs in AMD64.  */
36*cb63e24eSchristos #define MAX_NUM_SCFI_REGS   (REG_CFA+1)
37*cb63e24eSchristos 
38*cb63e24eSchristos #define REG_INVALID	    ((unsigned int)-1)
39*cb63e24eSchristos 
40*cb63e24eSchristos enum cfi_reglocstate
41*cb63e24eSchristos {
42*cb63e24eSchristos   CFI_UNDEFINED,
43*cb63e24eSchristos   CFI_IN_REG,
44*cb63e24eSchristos   CFI_ON_STACK
45*cb63e24eSchristos };
46*cb63e24eSchristos 
47*cb63e24eSchristos /* Location at which CFI register is saved.
48*cb63e24eSchristos 
49*cb63e24eSchristos    A CFI register (callee-saved registers, RA/LR) are always an offset from
50*cb63e24eSchristos    the CFA.  REG_CFA itself, however, may have REG_SP or REG_FP as base
51*cb63e24eSchristos    register.  Hence, keep the base reg ID and offset per tracked register.  */
52*cb63e24eSchristos 
53*cb63e24eSchristos struct cfi_regloc
54*cb63e24eSchristos {
55*cb63e24eSchristos   /* Base reg ID (DWARF register number).  */
56*cb63e24eSchristos   unsigned int base;
57*cb63e24eSchristos   /* Location as offset from the CFA.  */
58*cb63e24eSchristos   offsetT offset;
59*cb63e24eSchristos   /* Current state of the CFI register.  */
60*cb63e24eSchristos   enum cfi_reglocstate state;
61*cb63e24eSchristos };
62*cb63e24eSchristos 
63*cb63e24eSchristos typedef struct cfi_regloc cfi_reglocS;
64*cb63e24eSchristos 
65*cb63e24eSchristos struct scfi_op_data
66*cb63e24eSchristos {
67*cb63e24eSchristos   const char *name;
68*cb63e24eSchristos };
69*cb63e24eSchristos 
70*cb63e24eSchristos typedef struct scfi_op_data scfi_op_dataS;
71*cb63e24eSchristos 
72*cb63e24eSchristos /* SCFI operation.
73*cb63e24eSchristos 
74*cb63e24eSchristos    An SCFI operation represents a single atomic change to the SCFI state.
75*cb63e24eSchristos    This can also be understood as an abstraction for what eventually gets
76*cb63e24eSchristos    emitted as a DWARF CFI operation.  */
77*cb63e24eSchristos 
78*cb63e24eSchristos struct scfi_op
79*cb63e24eSchristos {
80*cb63e24eSchristos   /* An SCFI op updates the state of either the CFA or other tracked
81*cb63e24eSchristos      (callee-saved, REG_SP etc) registers.  'reg' is in the DWARF register
82*cb63e24eSchristos      number space and must be strictly less than MAX_NUM_SCFI_REGS.  */
83*cb63e24eSchristos   unsigned int reg;
84*cb63e24eSchristos   /* Location of the reg.  */
85*cb63e24eSchristos   cfi_reglocS loc;
86*cb63e24eSchristos   /* DWARF CFI opcode.  */
87*cb63e24eSchristos   uint32_t dw2cfi_op;
88*cb63e24eSchristos   /* Some SCFI ops, e.g., for CFI_label, may need to carry additional data.  */
89*cb63e24eSchristos   scfi_op_dataS *op_data;
90*cb63e24eSchristos   /* A linked list.  */
91*cb63e24eSchristos   struct scfi_op *next;
92*cb63e24eSchristos };
93*cb63e24eSchristos 
94*cb63e24eSchristos /* SCFI State - accumulated unwind information at a PC.
95*cb63e24eSchristos 
96*cb63e24eSchristos    SCFI state is the accumulated unwind information encompassing:
97*cb63e24eSchristos       - REG_SP, REG_FP,
98*cb63e24eSchristos       - RA, and
99*cb63e24eSchristos       - all callee-saved registers.
100*cb63e24eSchristos 
101*cb63e24eSchristos     Note that SCFI_MAX_REG_ID is target/ABI dependent and is provided by the
102*cb63e24eSchristos     backends.  The backend must also identify the DWARF register numbers for
103*cb63e24eSchristos     the REG_SP, and REG_FP registers.  */
104*cb63e24eSchristos 
105*cb63e24eSchristos struct scfi_state
106*cb63e24eSchristos {
107*cb63e24eSchristos   cfi_reglocS regs[MAX_NUM_SCFI_REGS];
108*cb63e24eSchristos   cfi_reglocS scratch[MAX_NUM_SCFI_REGS];
109*cb63e24eSchristos   /* Current stack size.  */
110*cb63e24eSchristos   offsetT stack_size;
111*cb63e24eSchristos   /* Whether the stack size is known.
112*cb63e24eSchristos      Stack size may become untraceable depending on the specific stack
113*cb63e24eSchristos      manipulation machine instruction, e.g., rsp = rsp op reg instruction
114*cb63e24eSchristos      makes the stack size untraceable.  */
115*cb63e24eSchristos   bool traceable_p;
116*cb63e24eSchristos };
117*cb63e24eSchristos 
118*cb63e24eSchristos /* Initialize a new SCFI op.  */
119*cb63e24eSchristos 
120*cb63e24eSchristos static scfi_opS *
init_scfi_op(void)121*cb63e24eSchristos init_scfi_op (void)
122*cb63e24eSchristos {
123*cb63e24eSchristos   scfi_opS *op = XCNEW (scfi_opS);
124*cb63e24eSchristos 
125*cb63e24eSchristos   return op;
126*cb63e24eSchristos }
127*cb63e24eSchristos 
128*cb63e24eSchristos /* Free the SCFI ops, given the HEAD of the list.  */
129*cb63e24eSchristos 
130*cb63e24eSchristos void
scfi_ops_cleanup(scfi_opS ** head)131*cb63e24eSchristos scfi_ops_cleanup (scfi_opS **head)
132*cb63e24eSchristos {
133*cb63e24eSchristos   scfi_opS *op;
134*cb63e24eSchristos   scfi_opS *next;
135*cb63e24eSchristos 
136*cb63e24eSchristos   if (!head || !*head)
137*cb63e24eSchristos     return;
138*cb63e24eSchristos 
139*cb63e24eSchristos   op = *head;
140*cb63e24eSchristos   next = op->next;
141*cb63e24eSchristos 
142*cb63e24eSchristos   while (op)
143*cb63e24eSchristos     {
144*cb63e24eSchristos       free (op);
145*cb63e24eSchristos       op = next;
146*cb63e24eSchristos       next = op ? op->next : NULL;
147*cb63e24eSchristos     }
148*cb63e24eSchristos }
149*cb63e24eSchristos 
150*cb63e24eSchristos /* Compare two SCFI states.  */
151*cb63e24eSchristos 
152*cb63e24eSchristos static int
cmp_scfi_state(scfi_stateS * state1,scfi_stateS * state2)153*cb63e24eSchristos cmp_scfi_state (scfi_stateS *state1, scfi_stateS *state2)
154*cb63e24eSchristos {
155*cb63e24eSchristos   int ret;
156*cb63e24eSchristos 
157*cb63e24eSchristos   if (!state1 || !state2)
158*cb63e24eSchristos     ret = 1;
159*cb63e24eSchristos 
160*cb63e24eSchristos   /* Skip comparing the scratch[] value of registers.  The user visible
161*cb63e24eSchristos      unwind information is derived from the regs[] from the SCFI state.  */
162*cb63e24eSchristos   ret = memcmp (state1->regs, state2->regs,
163*cb63e24eSchristos 		sizeof (cfi_reglocS) * MAX_NUM_SCFI_REGS);
164*cb63e24eSchristos 
165*cb63e24eSchristos   /* For user functions which perform dynamic stack allocation, after switching
166*cb63e24eSchristos      t REG_FP based CFA tracking, it is perfectly possible to have stack usage
167*cb63e24eSchristos      in some control flows.  However, double-checking that all control flows
168*cb63e24eSchristos      have the same idea of CFA tracking before this wont hurt.  */
169*cb63e24eSchristos   gas_assert (state1->regs[REG_CFA].base == state2->regs[REG_CFA].base);
170*cb63e24eSchristos   if (state1->regs[REG_CFA].base == REG_SP)
171*cb63e24eSchristos     ret |= state1->stack_size != state2->stack_size;
172*cb63e24eSchristos 
173*cb63e24eSchristos   ret |= state1->traceable_p != state2->traceable_p;
174*cb63e24eSchristos 
175*cb63e24eSchristos   return ret;
176*cb63e24eSchristos }
177*cb63e24eSchristos 
178*cb63e24eSchristos #if 0
179*cb63e24eSchristos static void
180*cb63e24eSchristos scfi_state_update_reg (scfi_stateS *state, uint32_t dst, uint32_t base,
181*cb63e24eSchristos 		       int32_t offset)
182*cb63e24eSchristos {
183*cb63e24eSchristos   if (dst >= MAX_NUM_SCFI_REGS)
184*cb63e24eSchristos     return;
185*cb63e24eSchristos 
186*cb63e24eSchristos   state->regs[dst].base = base;
187*cb63e24eSchristos   state->regs[dst].offset = offset;
188*cb63e24eSchristos }
189*cb63e24eSchristos #endif
190*cb63e24eSchristos 
191*cb63e24eSchristos /* Update the SCFI state of REG as available on execution stack at OFFSET
192*cb63e24eSchristos    from REG_CFA (BASE).
193*cb63e24eSchristos 
194*cb63e24eSchristos    Note that BASE must be REG_CFA, because any other base (REG_SP, REG_FP)
195*cb63e24eSchristos    is by definition transitory in the function.  */
196*cb63e24eSchristos 
197*cb63e24eSchristos static void
scfi_state_save_reg(scfi_stateS * state,unsigned int reg,unsigned int base,offsetT offset)198*cb63e24eSchristos scfi_state_save_reg (scfi_stateS *state, unsigned int reg, unsigned int base,
199*cb63e24eSchristos 		     offsetT offset)
200*cb63e24eSchristos {
201*cb63e24eSchristos   if (reg >= MAX_NUM_SCFI_REGS)
202*cb63e24eSchristos     return;
203*cb63e24eSchristos 
204*cb63e24eSchristos   gas_assert (base == REG_CFA);
205*cb63e24eSchristos 
206*cb63e24eSchristos   state->regs[reg].base = base;
207*cb63e24eSchristos   state->regs[reg].offset = offset;
208*cb63e24eSchristos   state->regs[reg].state = CFI_ON_STACK;
209*cb63e24eSchristos }
210*cb63e24eSchristos 
211*cb63e24eSchristos static void
scfi_state_restore_reg(scfi_stateS * state,unsigned int reg)212*cb63e24eSchristos scfi_state_restore_reg (scfi_stateS *state, unsigned int reg)
213*cb63e24eSchristos {
214*cb63e24eSchristos   if (reg >= MAX_NUM_SCFI_REGS)
215*cb63e24eSchristos     return;
216*cb63e24eSchristos 
217*cb63e24eSchristos   /* Sanity check.  See Rule 4.  */
218*cb63e24eSchristos   gas_assert (state->regs[reg].state == CFI_ON_STACK);
219*cb63e24eSchristos   gas_assert (state->regs[reg].base == REG_CFA);
220*cb63e24eSchristos 
221*cb63e24eSchristos   state->regs[reg].base = reg;
222*cb63e24eSchristos   state->regs[reg].offset = 0;
223*cb63e24eSchristos   /* PS: the register may still be on stack much after the restore, but the
224*cb63e24eSchristos      SCFI state keeps the state as 'in register'.  */
225*cb63e24eSchristos   state->regs[reg].state = CFI_IN_REG;
226*cb63e24eSchristos }
227*cb63e24eSchristos 
228*cb63e24eSchristos /* Identify if the given GAS instruction GINSN saves a register
229*cb63e24eSchristos    (of interest) on stack.  */
230*cb63e24eSchristos 
231*cb63e24eSchristos static bool
ginsn_scfi_save_reg_p(ginsnS * ginsn,scfi_stateS * state)232*cb63e24eSchristos ginsn_scfi_save_reg_p (ginsnS *ginsn, scfi_stateS *state)
233*cb63e24eSchristos {
234*cb63e24eSchristos   bool save_reg_p = false;
235*cb63e24eSchristos   struct ginsn_src *src;
236*cb63e24eSchristos   struct ginsn_dst *dst;
237*cb63e24eSchristos 
238*cb63e24eSchristos   src = ginsn_get_src1 (ginsn);
239*cb63e24eSchristos   dst = ginsn_get_dst (ginsn);
240*cb63e24eSchristos 
241*cb63e24eSchristos   /* The first save to stack of callee-saved register is deemed as
242*cb63e24eSchristos      register save.  */
243*cb63e24eSchristos   if (!ginsn_track_reg_p (ginsn_get_src_reg (src), GINSN_GEN_SCFI)
244*cb63e24eSchristos       || state->regs[ginsn_get_src_reg (src)].state == CFI_ON_STACK)
245*cb63e24eSchristos     return save_reg_p;
246*cb63e24eSchristos 
247*cb63e24eSchristos   /* A register save insn may be an indirect mov.  */
248*cb63e24eSchristos   if (ginsn->type == GINSN_TYPE_MOV
249*cb63e24eSchristos       && ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT
250*cb63e24eSchristos       && (ginsn_get_dst_reg (dst) == REG_SP
251*cb63e24eSchristos 	  || (ginsn_get_dst_reg (dst) == REG_FP
252*cb63e24eSchristos 	      && state->regs[REG_CFA].base == REG_FP)))
253*cb63e24eSchristos     save_reg_p = true;
254*cb63e24eSchristos   /* or an explicit store to stack.  */
255*cb63e24eSchristos   else if (ginsn->type == GINSN_TYPE_STORE
256*cb63e24eSchristos 	   && ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT
257*cb63e24eSchristos 	   && ginsn_get_dst_reg (dst) == REG_SP)
258*cb63e24eSchristos     save_reg_p = true;
259*cb63e24eSchristos 
260*cb63e24eSchristos   return save_reg_p;
261*cb63e24eSchristos }
262*cb63e24eSchristos 
263*cb63e24eSchristos /* Identify if the given GAS instruction GINSN restores a register
264*cb63e24eSchristos    (of interest) on stack.  */
265*cb63e24eSchristos 
266*cb63e24eSchristos static bool
ginsn_scfi_restore_reg_p(ginsnS * ginsn,scfi_stateS * state)267*cb63e24eSchristos ginsn_scfi_restore_reg_p (ginsnS *ginsn, scfi_stateS *state)
268*cb63e24eSchristos {
269*cb63e24eSchristos   bool restore_reg_p = false;
270*cb63e24eSchristos   struct ginsn_dst *dst;
271*cb63e24eSchristos   struct ginsn_src *src1;
272*cb63e24eSchristos 
273*cb63e24eSchristos   dst = ginsn_get_dst (ginsn);
274*cb63e24eSchristos   src1 = ginsn_get_src1 (ginsn);
275*cb63e24eSchristos 
276*cb63e24eSchristos   if (!ginsn_track_reg_p (ginsn_get_dst_reg (dst), GINSN_GEN_SCFI))
277*cb63e24eSchristos     return restore_reg_p;
278*cb63e24eSchristos 
279*cb63e24eSchristos   /* A register restore insn may be an indirect mov...  */
280*cb63e24eSchristos   if (ginsn->type == GINSN_TYPE_MOV
281*cb63e24eSchristos       && ginsn_get_src_type (src1) == GINSN_SRC_INDIRECT
282*cb63e24eSchristos       && (ginsn_get_src_reg (src1) == REG_SP
283*cb63e24eSchristos 	  || (ginsn_get_src_reg (src1) == REG_FP
284*cb63e24eSchristos 	      && state->regs[REG_CFA].base == REG_FP)))
285*cb63e24eSchristos     restore_reg_p = true;
286*cb63e24eSchristos   /* ...or an explicit load from stack.  */
287*cb63e24eSchristos   else if (ginsn->type == GINSN_TYPE_LOAD
288*cb63e24eSchristos 	   && ginsn_get_src_type (src1) == GINSN_SRC_INDIRECT
289*cb63e24eSchristos 	   && ginsn_get_src_reg (src1) == REG_SP)
290*cb63e24eSchristos     restore_reg_p = true;
291*cb63e24eSchristos 
292*cb63e24eSchristos   return restore_reg_p;
293*cb63e24eSchristos }
294*cb63e24eSchristos 
295*cb63e24eSchristos /* Append the SCFI operation OP to the list of SCFI operations in the
296*cb63e24eSchristos    given GINSN.  */
297*cb63e24eSchristos 
298*cb63e24eSchristos static int
ginsn_append_scfi_op(ginsnS * ginsn,scfi_opS * op)299*cb63e24eSchristos ginsn_append_scfi_op (ginsnS *ginsn, scfi_opS *op)
300*cb63e24eSchristos {
301*cb63e24eSchristos   scfi_opS *sop;
302*cb63e24eSchristos 
303*cb63e24eSchristos   if (!ginsn || !op)
304*cb63e24eSchristos     return 1;
305*cb63e24eSchristos 
306*cb63e24eSchristos   if (!ginsn->scfi_ops)
307*cb63e24eSchristos     {
308*cb63e24eSchristos       ginsn->scfi_ops = XCNEW (scfi_opS *);
309*cb63e24eSchristos       *ginsn->scfi_ops = op;
310*cb63e24eSchristos     }
311*cb63e24eSchristos   else
312*cb63e24eSchristos     {
313*cb63e24eSchristos       /* Add to tail.  Most ginsns have a single SCFI operation,
314*cb63e24eSchristos 	 so this traversal for every insertion is acceptable for now.  */
315*cb63e24eSchristos       sop = *ginsn->scfi_ops;
316*cb63e24eSchristos       while (sop->next)
317*cb63e24eSchristos 	sop = sop->next;
318*cb63e24eSchristos 
319*cb63e24eSchristos       sop->next = op;
320*cb63e24eSchristos     }
321*cb63e24eSchristos   ginsn->num_scfi_ops++;
322*cb63e24eSchristos 
323*cb63e24eSchristos   return 0;
324*cb63e24eSchristos }
325*cb63e24eSchristos 
326*cb63e24eSchristos static void
scfi_op_add_def_cfa_reg(scfi_stateS * state,ginsnS * ginsn,unsigned int reg)327*cb63e24eSchristos scfi_op_add_def_cfa_reg (scfi_stateS *state, ginsnS *ginsn, unsigned int reg)
328*cb63e24eSchristos {
329*cb63e24eSchristos   scfi_opS *op = NULL;
330*cb63e24eSchristos 
331*cb63e24eSchristos   state->regs[REG_CFA].base = reg;
332*cb63e24eSchristos 
333*cb63e24eSchristos   op = init_scfi_op ();
334*cb63e24eSchristos 
335*cb63e24eSchristos   op->dw2cfi_op = DW_CFA_def_cfa_register;
336*cb63e24eSchristos   op->reg = REG_CFA;
337*cb63e24eSchristos   op->loc = state->regs[REG_CFA];
338*cb63e24eSchristos 
339*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
340*cb63e24eSchristos }
341*cb63e24eSchristos 
342*cb63e24eSchristos static void
scfi_op_add_cfa_offset_inc(scfi_stateS * state,ginsnS * ginsn,offsetT num)343*cb63e24eSchristos scfi_op_add_cfa_offset_inc (scfi_stateS *state, ginsnS *ginsn, offsetT num)
344*cb63e24eSchristos {
345*cb63e24eSchristos   scfi_opS *op = NULL;
346*cb63e24eSchristos 
347*cb63e24eSchristos   state->regs[REG_CFA].offset -= num;
348*cb63e24eSchristos 
349*cb63e24eSchristos   op = init_scfi_op ();
350*cb63e24eSchristos 
351*cb63e24eSchristos   op->dw2cfi_op = DW_CFA_def_cfa_offset;
352*cb63e24eSchristos   op->reg = REG_CFA;
353*cb63e24eSchristos   op->loc = state->regs[REG_CFA];
354*cb63e24eSchristos 
355*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
356*cb63e24eSchristos }
357*cb63e24eSchristos 
358*cb63e24eSchristos static void
scfi_op_add_cfa_offset_dec(scfi_stateS * state,ginsnS * ginsn,offsetT num)359*cb63e24eSchristos scfi_op_add_cfa_offset_dec (scfi_stateS *state, ginsnS *ginsn, offsetT num)
360*cb63e24eSchristos {
361*cb63e24eSchristos   scfi_opS *op = NULL;
362*cb63e24eSchristos 
363*cb63e24eSchristos   state->regs[REG_CFA].offset += num;
364*cb63e24eSchristos 
365*cb63e24eSchristos   op = init_scfi_op ();
366*cb63e24eSchristos 
367*cb63e24eSchristos   op->dw2cfi_op = DW_CFA_def_cfa_offset;
368*cb63e24eSchristos   op->reg = REG_CFA;
369*cb63e24eSchristos   op->loc = state->regs[REG_CFA];
370*cb63e24eSchristos 
371*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
372*cb63e24eSchristos }
373*cb63e24eSchristos 
374*cb63e24eSchristos static void
scfi_op_add_def_cfa(scfi_stateS * state,ginsnS * ginsn,unsigned int reg,offsetT num)375*cb63e24eSchristos scfi_op_add_def_cfa (scfi_stateS *state, ginsnS *ginsn, unsigned int reg,
376*cb63e24eSchristos 		     offsetT num)
377*cb63e24eSchristos {
378*cb63e24eSchristos   scfi_opS *op = NULL;
379*cb63e24eSchristos 
380*cb63e24eSchristos   state->regs[REG_CFA].base = reg;
381*cb63e24eSchristos   state->regs[REG_CFA].offset = num;
382*cb63e24eSchristos 
383*cb63e24eSchristos   op = init_scfi_op ();
384*cb63e24eSchristos 
385*cb63e24eSchristos   op->dw2cfi_op = DW_CFA_def_cfa;
386*cb63e24eSchristos   op->reg = REG_CFA;
387*cb63e24eSchristos   op->loc = state->regs[REG_CFA];
388*cb63e24eSchristos 
389*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
390*cb63e24eSchristos }
391*cb63e24eSchristos 
392*cb63e24eSchristos static void
scfi_op_add_cfi_offset(scfi_stateS * state,ginsnS * ginsn,unsigned int reg)393*cb63e24eSchristos scfi_op_add_cfi_offset (scfi_stateS *state, ginsnS *ginsn, unsigned int reg)
394*cb63e24eSchristos {
395*cb63e24eSchristos   scfi_opS *op = NULL;
396*cb63e24eSchristos 
397*cb63e24eSchristos   op = init_scfi_op ();
398*cb63e24eSchristos 
399*cb63e24eSchristos   op->dw2cfi_op = DW_CFA_offset;
400*cb63e24eSchristos   op->reg = reg;
401*cb63e24eSchristos   op->loc = state->regs[reg];
402*cb63e24eSchristos 
403*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
404*cb63e24eSchristos }
405*cb63e24eSchristos 
406*cb63e24eSchristos static void
scfi_op_add_cfa_restore(ginsnS * ginsn,unsigned int reg)407*cb63e24eSchristos scfi_op_add_cfa_restore (ginsnS *ginsn, unsigned int reg)
408*cb63e24eSchristos {
409*cb63e24eSchristos   scfi_opS *op = NULL;
410*cb63e24eSchristos 
411*cb63e24eSchristos   op = init_scfi_op ();
412*cb63e24eSchristos 
413*cb63e24eSchristos   op->dw2cfi_op = DW_CFA_restore;
414*cb63e24eSchristos   op->reg = reg;
415*cb63e24eSchristos   op->loc.base = REG_INVALID;
416*cb63e24eSchristos   op->loc.offset = 0;
417*cb63e24eSchristos 
418*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
419*cb63e24eSchristos }
420*cb63e24eSchristos 
421*cb63e24eSchristos static void
scfi_op_add_cfi_remember_state(ginsnS * ginsn)422*cb63e24eSchristos scfi_op_add_cfi_remember_state (ginsnS *ginsn)
423*cb63e24eSchristos {
424*cb63e24eSchristos   scfi_opS *op = NULL;
425*cb63e24eSchristos 
426*cb63e24eSchristos   op = init_scfi_op ();
427*cb63e24eSchristos 
428*cb63e24eSchristos   op->dw2cfi_op = DW_CFA_remember_state;
429*cb63e24eSchristos 
430*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
431*cb63e24eSchristos }
432*cb63e24eSchristos 
433*cb63e24eSchristos static void
scfi_op_add_cfi_restore_state(ginsnS * ginsn)434*cb63e24eSchristos scfi_op_add_cfi_restore_state (ginsnS *ginsn)
435*cb63e24eSchristos {
436*cb63e24eSchristos   scfi_opS *op = NULL;
437*cb63e24eSchristos 
438*cb63e24eSchristos   op = init_scfi_op ();
439*cb63e24eSchristos 
440*cb63e24eSchristos   op->dw2cfi_op = DW_CFA_restore_state;
441*cb63e24eSchristos 
442*cb63e24eSchristos   /* FIXME - add to the beginning of the scfi_ops.  */
443*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
444*cb63e24eSchristos }
445*cb63e24eSchristos 
446*cb63e24eSchristos void
scfi_op_add_cfi_label(ginsnS * ginsn,const char * name)447*cb63e24eSchristos scfi_op_add_cfi_label (ginsnS *ginsn, const char *name)
448*cb63e24eSchristos {
449*cb63e24eSchristos   scfi_opS *op = NULL;
450*cb63e24eSchristos 
451*cb63e24eSchristos   op = init_scfi_op ();
452*cb63e24eSchristos   op->dw2cfi_op = CFI_label;
453*cb63e24eSchristos   op->op_data = XCNEW (scfi_op_dataS);
454*cb63e24eSchristos   op->op_data->name = name;
455*cb63e24eSchristos 
456*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
457*cb63e24eSchristos }
458*cb63e24eSchristos 
459*cb63e24eSchristos void
scfi_op_add_signal_frame(ginsnS * ginsn)460*cb63e24eSchristos scfi_op_add_signal_frame (ginsnS *ginsn)
461*cb63e24eSchristos {
462*cb63e24eSchristos   scfi_opS *op = NULL;
463*cb63e24eSchristos 
464*cb63e24eSchristos   op = init_scfi_op ();
465*cb63e24eSchristos   op->dw2cfi_op = CFI_signal_frame;
466*cb63e24eSchristos 
467*cb63e24eSchristos   ginsn_append_scfi_op (ginsn, op);
468*cb63e24eSchristos }
469*cb63e24eSchristos 
470*cb63e24eSchristos static int
verify_heuristic_traceable_reg_fp(ginsnS * ginsn,scfi_stateS * state)471*cb63e24eSchristos verify_heuristic_traceable_reg_fp (ginsnS *ginsn, scfi_stateS *state)
472*cb63e24eSchristos {
473*cb63e24eSchristos   /* The function uses this variable to issue error to user right away.  */
474*cb63e24eSchristos   int fp_traceable_p = 0;
475*cb63e24eSchristos   struct ginsn_dst *dst;
476*cb63e24eSchristos   struct ginsn_src *src1;
477*cb63e24eSchristos   struct ginsn_src *src2;
478*cb63e24eSchristos 
479*cb63e24eSchristos   src1 = ginsn_get_src1 (ginsn);
480*cb63e24eSchristos   src2 = ginsn_get_src2 (ginsn);
481*cb63e24eSchristos   dst = ginsn_get_dst (ginsn);
482*cb63e24eSchristos 
483*cb63e24eSchristos   /* Stack manipulation can be done in a variety of ways.  A program may
484*cb63e24eSchristos      allocate stack statically or may perform dynamic stack allocation in
485*cb63e24eSchristos      the prologue.
486*cb63e24eSchristos 
487*cb63e24eSchristos      The SCFI machinery in GAS is based on some heuristics:
488*cb63e24eSchristos 
489*cb63e24eSchristos        - Rule 3 If the base register for CFA tracking is REG_FP, the program
490*cb63e24eSchristos        must not clobber REG_FP, unless it is for switch to REG_SP based CFA
491*cb63e24eSchristos        tracking (via say, a pop %rbp in X86).  */
492*cb63e24eSchristos 
493*cb63e24eSchristos   /* Check all applicable instructions with dest REG_FP, when the CFA base
494*cb63e24eSchristos      register is REG_FP.  */
495*cb63e24eSchristos   if (state->regs[REG_CFA].base == REG_FP && ginsn_get_dst_reg (dst) == REG_FP)
496*cb63e24eSchristos     {
497*cb63e24eSchristos       /* Excuse the add/sub with imm usage: They are OK.  */
498*cb63e24eSchristos       if ((ginsn->type == GINSN_TYPE_ADD || ginsn->type == GINSN_TYPE_SUB)
499*cb63e24eSchristos 	  && ginsn_get_src_reg (src1) == REG_FP
500*cb63e24eSchristos 	  && ginsn_get_src_type (src2) == GINSN_SRC_IMM)
501*cb63e24eSchristos 	fp_traceable_p = 0;
502*cb63e24eSchristos       /* REG_FP restore is OK too.  */
503*cb63e24eSchristos       else if (ginsn->type == GINSN_TYPE_LOAD)
504*cb63e24eSchristos 	fp_traceable_p = 0;
505*cb63e24eSchristos       /* mov's to memory with REG_FP base do not make REG_FP untraceable.  */
506*cb63e24eSchristos       else if (ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT
507*cb63e24eSchristos 	       && (ginsn->type == GINSN_TYPE_MOV
508*cb63e24eSchristos 		   || ginsn->type == GINSN_TYPE_STORE))
509*cb63e24eSchristos 	fp_traceable_p = 0;
510*cb63e24eSchristos       /* Manipulations of the values possibly on stack are OK too.  */
511*cb63e24eSchristos       else if ((ginsn->type == GINSN_TYPE_ADD || ginsn->type == GINSN_TYPE_SUB
512*cb63e24eSchristos 		|| ginsn->type == GINSN_TYPE_AND)
513*cb63e24eSchristos 	       && ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT)
514*cb63e24eSchristos 	fp_traceable_p = 0;
515*cb63e24eSchristos       /* All other ginsns with REG_FP as destination make REG_FP not
516*cb63e24eSchristos 	 traceable.  */
517*cb63e24eSchristos       else
518*cb63e24eSchristos 	fp_traceable_p = 1;
519*cb63e24eSchristos     }
520*cb63e24eSchristos 
521*cb63e24eSchristos   if (fp_traceable_p)
522*cb63e24eSchristos     as_bad_where (ginsn->file, ginsn->line,
523*cb63e24eSchristos 		  _("SCFI: usage of REG_FP as scratch not supported"));
524*cb63e24eSchristos 
525*cb63e24eSchristos   return fp_traceable_p;
526*cb63e24eSchristos }
527*cb63e24eSchristos 
528*cb63e24eSchristos static int
verify_heuristic_traceable_stack_manipulation(ginsnS * ginsn,scfi_stateS * state)529*cb63e24eSchristos verify_heuristic_traceable_stack_manipulation (ginsnS *ginsn,
530*cb63e24eSchristos 					       scfi_stateS *state)
531*cb63e24eSchristos {
532*cb63e24eSchristos   /* The function uses this variable to issue error to user right away.  */
533*cb63e24eSchristos   int sp_untraceable_p = 0;
534*cb63e24eSchristos   bool possibly_untraceable = false;
535*cb63e24eSchristos   struct ginsn_dst *dst;
536*cb63e24eSchristos   struct ginsn_src *src1;
537*cb63e24eSchristos   struct ginsn_src *src2;
538*cb63e24eSchristos 
539*cb63e24eSchristos   src1 = ginsn_get_src1 (ginsn);
540*cb63e24eSchristos   src2 = ginsn_get_src2 (ginsn);
541*cb63e24eSchristos   dst = ginsn_get_dst (ginsn);
542*cb63e24eSchristos 
543*cb63e24eSchristos   /* Stack manipulation can be done in a variety of ways.  A program may
544*cb63e24eSchristos      allocate stack statically in prologue or may need to do dynamic stack
545*cb63e24eSchristos      allocation.
546*cb63e24eSchristos 
547*cb63e24eSchristos      The SCFI machinery in GAS is based on some heuristics:
548*cb63e24eSchristos 
549*cb63e24eSchristos        - Rule 1 The base register for CFA tracking may be either REG_SP or
550*cb63e24eSchristos        REG_FP.
551*cb63e24eSchristos 
552*cb63e24eSchristos        - Rule 2 If the base register for CFA tracking is REG_SP, the precise
553*cb63e24eSchristos        amount of stack usage (and hence, the value of rsp) must be known at
554*cb63e24eSchristos        all times.  */
555*cb63e24eSchristos 
556*cb63e24eSchristos   if (ginsn->type == GINSN_TYPE_MOV
557*cb63e24eSchristos       && ginsn_get_dst_type (dst) == GINSN_DST_REG
558*cb63e24eSchristos       && ginsn_get_dst_reg (dst) == REG_SP
559*cb63e24eSchristos       && ginsn_get_src_type (src1) == GINSN_SRC_REG
560*cb63e24eSchristos       /* Exclude mov %rbp, %rsp from this check.  */
561*cb63e24eSchristos       && ginsn_get_src_reg (src1) != REG_FP)
562*cb63e24eSchristos     {
563*cb63e24eSchristos       /* mov %reg, %rsp.  */
564*cb63e24eSchristos       /* A previous mov %rsp, %reg must have been seen earlier for this to be
565*cb63e24eSchristos 	 an OK for stack manipulation.  */
566*cb63e24eSchristos       if (state->scratch[ginsn_get_src_reg (src1)].base != REG_CFA
567*cb63e24eSchristos 	  || state->scratch[ginsn_get_src_reg (src1)].state != CFI_IN_REG)
568*cb63e24eSchristos 	{
569*cb63e24eSchristos 	  possibly_untraceable = true;
570*cb63e24eSchristos 	}
571*cb63e24eSchristos     }
572*cb63e24eSchristos   /* Check add/sub/and insn usage when CFA base register is REG_SP.
573*cb63e24eSchristos      Any stack size manipulation, including stack realignment is not allowed
574*cb63e24eSchristos      if CFA base register is REG_SP.  */
575*cb63e24eSchristos   else if (ginsn_get_dst_type (dst) == GINSN_DST_REG
576*cb63e24eSchristos 	   && ginsn_get_dst_reg (dst) == REG_SP
577*cb63e24eSchristos 	   && (((ginsn->type == GINSN_TYPE_ADD || ginsn->type == GINSN_TYPE_SUB)
578*cb63e24eSchristos 		&& ginsn_get_src_type (src2) != GINSN_SRC_IMM)
579*cb63e24eSchristos 	       || ginsn->type == GINSN_TYPE_AND
580*cb63e24eSchristos 	       || ginsn->type == GINSN_TYPE_OTHER))
581*cb63e24eSchristos     possibly_untraceable = true;
582*cb63e24eSchristos   /* If a register save operation is seen when REG_SP is untraceable,
583*cb63e24eSchristos      CFI cannot be synthesized for register saves, hence bail out.  */
584*cb63e24eSchristos   else if (ginsn_scfi_save_reg_p (ginsn, state) && !state->traceable_p)
585*cb63e24eSchristos     {
586*cb63e24eSchristos       sp_untraceable_p = 1;
587*cb63e24eSchristos       /* If, however, the register save is an REG_FP-based, indirect mov
588*cb63e24eSchristos 	 like: mov reg, disp(%rbp) and CFA base register is REG_BP,
589*cb63e24eSchristos 	 untraceable REG_SP is not a problem.  */
590*cb63e24eSchristos       if (ginsn->type == GINSN_TYPE_MOV
591*cb63e24eSchristos 	  && ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT
592*cb63e24eSchristos 	  && (ginsn_get_dst_reg (dst) == REG_FP
593*cb63e24eSchristos 	      && state->regs[REG_CFA].base == REG_FP))
594*cb63e24eSchristos 	sp_untraceable_p = 0;
595*cb63e24eSchristos     }
596*cb63e24eSchristos   else if (ginsn_scfi_restore_reg_p (ginsn, state) && !state->traceable_p)
597*cb63e24eSchristos     {
598*cb63e24eSchristos       if (ginsn->type == GINSN_TYPE_MOV
599*cb63e24eSchristos 	  && ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT
600*cb63e24eSchristos 	  && (ginsn_get_src_reg (src1) == REG_SP
601*cb63e24eSchristos 	      || (ginsn_get_src_reg (src1) == REG_FP
602*cb63e24eSchristos 		  && state->regs[REG_CFA].base != REG_FP)))
603*cb63e24eSchristos 	sp_untraceable_p = 1;
604*cb63e24eSchristos     }
605*cb63e24eSchristos 
606*cb63e24eSchristos   if (possibly_untraceable)
607*cb63e24eSchristos     {
608*cb63e24eSchristos       /* See Rule 2.  For SP-based CFA, this makes CFA tracking not possible.
609*cb63e24eSchristos 	 Propagate now to caller.  */
610*cb63e24eSchristos       if (state->regs[REG_CFA].base == REG_SP)
611*cb63e24eSchristos 	sp_untraceable_p = 1;
612*cb63e24eSchristos       else if (state->traceable_p)
613*cb63e24eSchristos 	{
614*cb63e24eSchristos 	  /* An extension of Rule 2.
615*cb63e24eSchristos 	     For FP-based CFA, this may be a problem *if* certain specific
616*cb63e24eSchristos 	     changes to the SCFI state are seen beyond this point, e.g.,
617*cb63e24eSchristos 	     register save / restore from stack.  */
618*cb63e24eSchristos 	  gas_assert (state->regs[REG_CFA].base == REG_FP);
619*cb63e24eSchristos 	  /* Simply make a note in the SCFI state object for now and
620*cb63e24eSchristos 	     continue.  Indicate an error when register save / restore
621*cb63e24eSchristos 	     for callee-saved registers is seen.  */
622*cb63e24eSchristos 	  sp_untraceable_p = 0;
623*cb63e24eSchristos 	  state->traceable_p = false;
624*cb63e24eSchristos 	}
625*cb63e24eSchristos     }
626*cb63e24eSchristos 
627*cb63e24eSchristos   if (sp_untraceable_p)
628*cb63e24eSchristos     as_bad_where (ginsn->file, ginsn->line,
629*cb63e24eSchristos 		  _("SCFI: unsupported stack manipulation pattern"));
630*cb63e24eSchristos 
631*cb63e24eSchristos   return sp_untraceable_p;
632*cb63e24eSchristos }
633*cb63e24eSchristos 
634*cb63e24eSchristos static int
verify_heuristic_symmetrical_restore_reg(scfi_stateS * state,ginsnS * ginsn)635*cb63e24eSchristos verify_heuristic_symmetrical_restore_reg (scfi_stateS *state, ginsnS* ginsn)
636*cb63e24eSchristos {
637*cb63e24eSchristos   int sym_restore = true;
638*cb63e24eSchristos   offsetT expected_offset = 0;
639*cb63e24eSchristos   struct ginsn_src *src1;
640*cb63e24eSchristos   struct ginsn_dst *dst;
641*cb63e24eSchristos   unsigned int reg;
642*cb63e24eSchristos 
643*cb63e24eSchristos   /* Rule 4: Save and Restore of callee-saved registers must be symmetrical.
644*cb63e24eSchristos      It is expected that value of the saved register is restored correctly.
645*cb63e24eSchristos      E.g.,
646*cb63e24eSchristos 	push  reg1
647*cb63e24eSchristos 	push  reg2
648*cb63e24eSchristos 	...
649*cb63e24eSchristos 	body of func which uses reg1 , reg2 as scratch,
650*cb63e24eSchristos 	and may be even spills them to stack.
651*cb63e24eSchristos 	...
652*cb63e24eSchristos 	pop   reg2
653*cb63e24eSchristos 	pop   reg1
654*cb63e24eSchristos      It is difficult to verify the Rule 4 in all cases.  For the SCFI machinery,
655*cb63e24eSchristos      it is difficult to separate prologue-epilogue from the body of the function
656*cb63e24eSchristos 
657*cb63e24eSchristos      Hence, the SCFI machinery at this time, should only warn on an asymetrical
658*cb63e24eSchristos      restore.  */
659*cb63e24eSchristos   src1 = ginsn_get_src1 (ginsn);
660*cb63e24eSchristos   dst = ginsn_get_dst (ginsn);
661*cb63e24eSchristos   reg = ginsn_get_dst_reg (dst);
662*cb63e24eSchristos 
663*cb63e24eSchristos   /* For non callee-saved registers, calling the API is meaningless.  */
664*cb63e24eSchristos   if (!ginsn_track_reg_p (ginsn_get_dst_reg (dst), GINSN_GEN_SCFI))
665*cb63e24eSchristos     return sym_restore;
666*cb63e24eSchristos 
667*cb63e24eSchristos   /* The register must have been saved on stack, for sure.  */
668*cb63e24eSchristos   gas_assert (state->regs[reg].state == CFI_ON_STACK);
669*cb63e24eSchristos   gas_assert (state->regs[reg].base == REG_CFA);
670*cb63e24eSchristos 
671*cb63e24eSchristos   if ((ginsn->type == GINSN_TYPE_MOV
672*cb63e24eSchristos        || ginsn->type == GINSN_TYPE_LOAD)
673*cb63e24eSchristos       && ginsn_get_src_type (src1) == GINSN_SRC_INDIRECT
674*cb63e24eSchristos       && (ginsn_get_src_reg (src1) == REG_SP
675*cb63e24eSchristos 	  || (ginsn_get_src_reg (src1) == REG_FP
676*cb63e24eSchristos 	      && state->regs[REG_CFA].base == REG_FP)))
677*cb63e24eSchristos     {
678*cb63e24eSchristos       /* mov disp(%rsp), reg.  */
679*cb63e24eSchristos       /* mov disp(%rbp), reg.  */
680*cb63e24eSchristos       expected_offset = (((ginsn_get_src_reg (src1) == REG_SP)
681*cb63e24eSchristos 			  ? -state->stack_size
682*cb63e24eSchristos 			  : state->regs[REG_FP].offset)
683*cb63e24eSchristos 			 + ginsn_get_src_disp (src1));
684*cb63e24eSchristos     }
685*cb63e24eSchristos 
686*cb63e24eSchristos   sym_restore = (expected_offset == state->regs[reg].offset);
687*cb63e24eSchristos 
688*cb63e24eSchristos   return sym_restore;
689*cb63e24eSchristos }
690*cb63e24eSchristos 
691*cb63e24eSchristos /* Perform symbolic execution of the GINSN and update its list of scfi_ops.
692*cb63e24eSchristos    scfi_ops are later used to directly generate the DWARF CFI directives.
693*cb63e24eSchristos    Also update the SCFI state object STATE for the caller.  */
694*cb63e24eSchristos 
695*cb63e24eSchristos static int
gen_scfi_ops(ginsnS * ginsn,scfi_stateS * state)696*cb63e24eSchristos gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
697*cb63e24eSchristos {
698*cb63e24eSchristos   int ret = 0;
699*cb63e24eSchristos   offsetT offset;
700*cb63e24eSchristos   struct ginsn_src *src1;
701*cb63e24eSchristos   struct ginsn_src *src2;
702*cb63e24eSchristos   struct ginsn_dst *dst;
703*cb63e24eSchristos 
704*cb63e24eSchristos   if (!ginsn || !state)
705*cb63e24eSchristos     ret = 1;
706*cb63e24eSchristos 
707*cb63e24eSchristos   /* For the first ginsn (of type GINSN_TYPE_SYMBOL) in the gbb, generate
708*cb63e24eSchristos      the SCFI op with DW_CFA_def_cfa.  Note that the register and offset are
709*cb63e24eSchristos      target-specific.  */
710*cb63e24eSchristos   if (GINSN_F_FUNC_BEGIN_P (ginsn))
711*cb63e24eSchristos     {
712*cb63e24eSchristos       scfi_op_add_def_cfa (state, ginsn, REG_SP, SCFI_INIT_CFA_OFFSET);
713*cb63e24eSchristos       state->stack_size += SCFI_INIT_CFA_OFFSET;
714*cb63e24eSchristos       return ret;
715*cb63e24eSchristos     }
716*cb63e24eSchristos 
717*cb63e24eSchristos   src1 = ginsn_get_src1 (ginsn);
718*cb63e24eSchristos   src2 = ginsn_get_src2 (ginsn);
719*cb63e24eSchristos   dst = ginsn_get_dst (ginsn);
720*cb63e24eSchristos 
721*cb63e24eSchristos   ret = verify_heuristic_traceable_stack_manipulation (ginsn, state);
722*cb63e24eSchristos   if (ret)
723*cb63e24eSchristos     return ret;
724*cb63e24eSchristos 
725*cb63e24eSchristos   ret = verify_heuristic_traceable_reg_fp (ginsn, state);
726*cb63e24eSchristos   if (ret)
727*cb63e24eSchristos     return ret;
728*cb63e24eSchristos 
729*cb63e24eSchristos   switch (ginsn->dst.type)
730*cb63e24eSchristos     {
731*cb63e24eSchristos     case GINSN_DST_REG:
732*cb63e24eSchristos       switch (ginsn->type)
733*cb63e24eSchristos 	{
734*cb63e24eSchristos 	case GINSN_TYPE_MOV:
735*cb63e24eSchristos 	  if (ginsn_get_src_type (src1) == GINSN_SRC_REG
736*cb63e24eSchristos 	      && ginsn_get_src_reg (src1) == REG_SP
737*cb63e24eSchristos 	      && ginsn_get_dst_reg (dst) == REG_FP
738*cb63e24eSchristos 	      && state->regs[REG_CFA].base == REG_SP)
739*cb63e24eSchristos 	    {
740*cb63e24eSchristos 	      /* mov %rsp, %rbp.  */
741*cb63e24eSchristos 	      scfi_op_add_def_cfa_reg (state, ginsn, ginsn_get_dst_reg (dst));
742*cb63e24eSchristos 	    }
743*cb63e24eSchristos 	  else if (ginsn_get_src_type (src1) == GINSN_SRC_REG
744*cb63e24eSchristos 		   && ginsn_get_src_reg (src1) == REG_FP
745*cb63e24eSchristos 		   && ginsn_get_dst_reg (dst) == REG_SP
746*cb63e24eSchristos 		   && state->regs[REG_CFA].base == REG_FP)
747*cb63e24eSchristos 	    {
748*cb63e24eSchristos 	      /* mov %rbp, %rsp.  */
749*cb63e24eSchristos 	      state->stack_size = -state->regs[REG_FP].offset;
750*cb63e24eSchristos 	      scfi_op_add_def_cfa_reg (state, ginsn, ginsn_get_dst_reg (dst));
751*cb63e24eSchristos 	      state->traceable_p = true;
752*cb63e24eSchristos 	    }
753*cb63e24eSchristos 	  else if (ginsn_get_src_type (src1) == GINSN_SRC_INDIRECT
754*cb63e24eSchristos 		   && (ginsn_get_src_reg (src1) == REG_SP
755*cb63e24eSchristos 		       || ginsn_get_src_reg (src1) == REG_FP)
756*cb63e24eSchristos 		   && ginsn_track_reg_p (ginsn_get_dst_reg (dst), GINSN_GEN_SCFI))
757*cb63e24eSchristos 	    {
758*cb63e24eSchristos 	      /* mov disp(%rsp), reg.  */
759*cb63e24eSchristos 	      /* mov disp(%rbp), reg.  */
760*cb63e24eSchristos 	      if (verify_heuristic_symmetrical_restore_reg (state, ginsn))
761*cb63e24eSchristos 		{
762*cb63e24eSchristos 		  scfi_state_restore_reg (state, ginsn_get_dst_reg (dst));
763*cb63e24eSchristos 		  scfi_op_add_cfa_restore (ginsn, ginsn_get_dst_reg (dst));
764*cb63e24eSchristos 		}
765*cb63e24eSchristos 	      else
766*cb63e24eSchristos 		as_warn_where (ginsn->file, ginsn->line,
767*cb63e24eSchristos 			       _("SCFI: asymetrical register restore"));
768*cb63e24eSchristos 	    }
769*cb63e24eSchristos 	  else if (ginsn_get_src_type (src1) == GINSN_SRC_REG
770*cb63e24eSchristos 		   && ginsn_get_dst_type (dst) == GINSN_DST_REG
771*cb63e24eSchristos 		   && ginsn_get_src_reg (src1) == REG_SP)
772*cb63e24eSchristos 	    {
773*cb63e24eSchristos 	      /* mov %rsp, %reg.  */
774*cb63e24eSchristos 	      /* The value of rsp is taken directly from state->stack_size.
775*cb63e24eSchristos 		 IMP: The workflow in gen_scfi_ops must keep it updated.
776*cb63e24eSchristos 		 PS: Not taking the value from state->scratch[REG_SP] is
777*cb63e24eSchristos 		 intentional.  */
778*cb63e24eSchristos 	      state->scratch[ginsn_get_dst_reg (dst)].base = REG_CFA;
779*cb63e24eSchristos 	      state->scratch[ginsn_get_dst_reg (dst)].offset = -state->stack_size;
780*cb63e24eSchristos 	      state->scratch[ginsn_get_dst_reg (dst)].state = CFI_IN_REG;
781*cb63e24eSchristos 	    }
782*cb63e24eSchristos 	  else if (ginsn_get_src_type (src1) == GINSN_SRC_REG
783*cb63e24eSchristos 		   && ginsn_get_dst_type (dst) == GINSN_DST_REG
784*cb63e24eSchristos 		   && ginsn_get_dst_reg (dst) == REG_SP)
785*cb63e24eSchristos 	    {
786*cb63e24eSchristos 	      /* mov %reg, %rsp.  */
787*cb63e24eSchristos 	      /* Keep the value of REG_SP updated.  */
788*cb63e24eSchristos 	      if (state->scratch[ginsn_get_src_reg (src1)].state == CFI_IN_REG)
789*cb63e24eSchristos 		{
790*cb63e24eSchristos 		  state->stack_size = -state->scratch[ginsn_get_src_reg (src1)].offset;
791*cb63e24eSchristos 		  state->traceable_p = true;
792*cb63e24eSchristos 		}
793*cb63e24eSchristos # if 0
794*cb63e24eSchristos 	      scfi_state_update_reg (state, ginsn_get_dst_reg (dst),
795*cb63e24eSchristos 				     state->scratch[ginsn_get_src_reg (src1)].base,
796*cb63e24eSchristos 				     state->scratch[ginsn_get_src_reg (src1)].offset);
797*cb63e24eSchristos #endif
798*cb63e24eSchristos 
799*cb63e24eSchristos 	    }
800*cb63e24eSchristos 	  break;
801*cb63e24eSchristos 	case GINSN_TYPE_SUB:
802*cb63e24eSchristos 	  if (ginsn_get_src_reg (src1) == REG_SP
803*cb63e24eSchristos 	      && ginsn_get_dst_reg (dst) == REG_SP)
804*cb63e24eSchristos 	    {
805*cb63e24eSchristos 	      /* Stack inc/dec offset, when generated due to stack push and pop is
806*cb63e24eSchristos 		 target-specific.  Use the value encoded in the ginsn.  */
807*cb63e24eSchristos 	      state->stack_size += ginsn_get_src_imm (src2);
808*cb63e24eSchristos 	      if (state->regs[REG_CFA].base == REG_SP)
809*cb63e24eSchristos 		{
810*cb63e24eSchristos 		  /* push reg.  */
811*cb63e24eSchristos 		  scfi_op_add_cfa_offset_dec (state, ginsn, ginsn_get_src_imm (src2));
812*cb63e24eSchristos 		}
813*cb63e24eSchristos 	    }
814*cb63e24eSchristos 	  break;
815*cb63e24eSchristos 	case GINSN_TYPE_ADD:
816*cb63e24eSchristos 	  if (ginsn_get_src_reg (src1) == REG_SP
817*cb63e24eSchristos 	      && ginsn_get_dst_reg (dst) == REG_SP)
818*cb63e24eSchristos 	    {
819*cb63e24eSchristos 	      /* Stack inc/dec offset is target-specific.  Use the value
820*cb63e24eSchristos 		 encoded in the ginsn.  */
821*cb63e24eSchristos 	      state->stack_size -= ginsn_get_src_imm (src2);
822*cb63e24eSchristos 	      /* pop %reg affects CFA offset only if CFA is currently
823*cb63e24eSchristos 		 stack-pointer based.  */
824*cb63e24eSchristos 	      if (state->regs[REG_CFA].base == REG_SP)
825*cb63e24eSchristos 		{
826*cb63e24eSchristos 		  scfi_op_add_cfa_offset_inc (state, ginsn, ginsn_get_src_imm (src2));
827*cb63e24eSchristos 		}
828*cb63e24eSchristos 	    }
829*cb63e24eSchristos 	  else if (ginsn_get_src_reg (src1) == REG_FP
830*cb63e24eSchristos 		   && ginsn_get_dst_reg (dst) == REG_SP
831*cb63e24eSchristos 		   && state->regs[REG_CFA].base == REG_FP)
832*cb63e24eSchristos 	    {
833*cb63e24eSchristos 	      /* FIXME - what is this for ? */
834*cb63e24eSchristos 	      state->stack_size =  0 - (state->regs[REG_FP].offset + ginsn_get_src_imm (src2));
835*cb63e24eSchristos 	    }
836*cb63e24eSchristos 	  break;
837*cb63e24eSchristos 	case GINSN_TYPE_LOAD:
838*cb63e24eSchristos 	  /* If this is a load from stack.  */
839*cb63e24eSchristos 	  if (ginsn_get_src_type (src1) == GINSN_SRC_INDIRECT
840*cb63e24eSchristos 	      && (ginsn_get_src_reg (src1) == REG_SP
841*cb63e24eSchristos 		  || (ginsn_get_src_reg (src1) == REG_FP
842*cb63e24eSchristos 		      && state->regs[REG_CFA].base == REG_FP)))
843*cb63e24eSchristos 	    {
844*cb63e24eSchristos 	      /* pop %rbp when CFA tracking is REG_FP based.  */
845*cb63e24eSchristos 	      if (ginsn_get_dst_reg (dst) == REG_FP
846*cb63e24eSchristos 		  && state->regs[REG_CFA].base == REG_FP)
847*cb63e24eSchristos 		{
848*cb63e24eSchristos 		  scfi_op_add_def_cfa_reg (state, ginsn, REG_SP);
849*cb63e24eSchristos 		  if (state->regs[REG_CFA].offset != state->stack_size)
850*cb63e24eSchristos 		    scfi_op_add_cfa_offset_inc (state, ginsn,
851*cb63e24eSchristos 						(state->regs[REG_CFA].offset - state->stack_size));
852*cb63e24eSchristos 		}
853*cb63e24eSchristos 	      if (ginsn_track_reg_p (ginsn_get_dst_reg (dst), GINSN_GEN_SCFI))
854*cb63e24eSchristos 		{
855*cb63e24eSchristos 		  if (verify_heuristic_symmetrical_restore_reg (state, ginsn))
856*cb63e24eSchristos 		    {
857*cb63e24eSchristos 		      scfi_state_restore_reg (state, ginsn_get_dst_reg (dst));
858*cb63e24eSchristos 		      scfi_op_add_cfa_restore (ginsn, ginsn_get_dst_reg (dst));
859*cb63e24eSchristos 		    }
860*cb63e24eSchristos 		  else
861*cb63e24eSchristos 		    as_warn_where (ginsn->file, ginsn->line,
862*cb63e24eSchristos 				   _("SCFI: asymetrical register restore"));
863*cb63e24eSchristos 		}
864*cb63e24eSchristos 	    }
865*cb63e24eSchristos 	  break;
866*cb63e24eSchristos 	default:
867*cb63e24eSchristos 	  break;
868*cb63e24eSchristos 	}
869*cb63e24eSchristos       break;
870*cb63e24eSchristos 
871*cb63e24eSchristos     case GINSN_DST_INDIRECT:
872*cb63e24eSchristos       /* Some operations with an indirect access to memory (or even to stack)
873*cb63e24eSchristos 	 may still be uninteresting for SCFI purpose (e.g, addl %edx, -32(%rsp)
874*cb63e24eSchristos 	 in x86).  In case of x86_64, these can neither be a register
875*cb63e24eSchristos 	 save / unsave, nor can alter the stack size.
876*cb63e24eSchristos 	 PS: This condition may need to be revisited for other arches.  */
877*cb63e24eSchristos       if (ginsn->type == GINSN_TYPE_ADD || ginsn->type == GINSN_TYPE_SUB
878*cb63e24eSchristos 	  || ginsn->type == GINSN_TYPE_AND)
879*cb63e24eSchristos 	break;
880*cb63e24eSchristos       gas_assert (ginsn->type == GINSN_TYPE_MOV
881*cb63e24eSchristos 		  || ginsn->type == GINSN_TYPE_STORE
882*cb63e24eSchristos 		  || ginsn->type == GINSN_TYPE_LOAD);
883*cb63e24eSchristos       /* mov reg, disp(%rbp) */
884*cb63e24eSchristos       /* mov reg, disp(%rsp) */
885*cb63e24eSchristos       if (ginsn_scfi_save_reg_p (ginsn, state))
886*cb63e24eSchristos 	{
887*cb63e24eSchristos 	  if (ginsn_get_dst_reg (dst) == REG_SP)
888*cb63e24eSchristos 	    {
889*cb63e24eSchristos 	      /* mov reg, disp(%rsp) */
890*cb63e24eSchristos 	      offset = 0 - state->stack_size + ginsn_get_dst_disp (dst);
891*cb63e24eSchristos 	      scfi_state_save_reg (state, ginsn_get_src_reg (src1), REG_CFA, offset);
892*cb63e24eSchristos 	      scfi_op_add_cfi_offset (state, ginsn, ginsn_get_src_reg (src1));
893*cb63e24eSchristos 	    }
894*cb63e24eSchristos 	  else if (ginsn_get_dst_reg (dst) == REG_FP)
895*cb63e24eSchristos 	    {
896*cb63e24eSchristos 	      gas_assert (state->regs[REG_CFA].base == REG_FP);
897*cb63e24eSchristos 	      /* mov reg, disp(%rbp) */
898*cb63e24eSchristos 	      offset = 0 - state->regs[REG_CFA].offset + ginsn_get_dst_disp (dst);
899*cb63e24eSchristos 	      scfi_state_save_reg (state, ginsn_get_src_reg (src1), REG_CFA, offset);
900*cb63e24eSchristos 	      scfi_op_add_cfi_offset (state, ginsn, ginsn_get_src_reg (src1));
901*cb63e24eSchristos 	    }
902*cb63e24eSchristos 	}
903*cb63e24eSchristos       break;
904*cb63e24eSchristos 
905*cb63e24eSchristos     default:
906*cb63e24eSchristos       /* Skip GINSN_DST_UNKNOWN and GINSN_DST_MEM as they are uninteresting
907*cb63e24eSchristos 	 currently for SCFI.  */
908*cb63e24eSchristos       break;
909*cb63e24eSchristos     }
910*cb63e24eSchristos 
911*cb63e24eSchristos   return ret;
912*cb63e24eSchristos }
913*cb63e24eSchristos 
914*cb63e24eSchristos /* Recursively perform forward flow of the (unwind information) SCFI state
915*cb63e24eSchristos    starting at basic block GBB.
916*cb63e24eSchristos 
917*cb63e24eSchristos    The forward flow process propagates the SCFI state at exit of a basic block
918*cb63e24eSchristos    to the successor basic block.
919*cb63e24eSchristos 
920*cb63e24eSchristos    Returns error code, if any.  */
921*cb63e24eSchristos 
922*cb63e24eSchristos static int
forward_flow_scfi_state(gcfgS * gcfg,gbbS * gbb,scfi_stateS * state)923*cb63e24eSchristos forward_flow_scfi_state (gcfgS *gcfg, gbbS *gbb, scfi_stateS *state)
924*cb63e24eSchristos {
925*cb63e24eSchristos   ginsnS *ginsn;
926*cb63e24eSchristos   gbbS *prev_bb;
927*cb63e24eSchristos   gedgeS *gedge = NULL;
928*cb63e24eSchristos   int ret = 0;
929*cb63e24eSchristos 
930*cb63e24eSchristos   if (gbb->visited)
931*cb63e24eSchristos     {
932*cb63e24eSchristos       /* Check that the SCFI state is the same as previous.  */
933*cb63e24eSchristos       ret = cmp_scfi_state (state, gbb->entry_state);
934*cb63e24eSchristos       if (ret)
935*cb63e24eSchristos 	as_bad (_("SCFI: Bad CFI propagation perhaps"));
936*cb63e24eSchristos       return ret;
937*cb63e24eSchristos     }
938*cb63e24eSchristos 
939*cb63e24eSchristos   gbb->visited = true;
940*cb63e24eSchristos 
941*cb63e24eSchristos   gbb->entry_state = XCNEW (scfi_stateS);
942*cb63e24eSchristos   memcpy (gbb->entry_state, state, sizeof (scfi_stateS));
943*cb63e24eSchristos 
944*cb63e24eSchristos   /* Perform symbolic execution of each ginsn in the gbb and update the
945*cb63e24eSchristos      scfi_ops list of each ginsn (and also update the STATE object).   */
946*cb63e24eSchristos   bb_for_each_insn(gbb, ginsn)
947*cb63e24eSchristos     {
948*cb63e24eSchristos       ret = gen_scfi_ops (ginsn, state);
949*cb63e24eSchristos       if (ret)
950*cb63e24eSchristos 	goto fail;
951*cb63e24eSchristos     }
952*cb63e24eSchristos 
953*cb63e24eSchristos   gbb->exit_state = XCNEW (scfi_stateS);
954*cb63e24eSchristos   memcpy (gbb->exit_state, state, sizeof (scfi_stateS));
955*cb63e24eSchristos 
956*cb63e24eSchristos   /* Forward flow the SCFI state.  Currently, we process the next basic block
957*cb63e24eSchristos      in DFS order.  But any forward traversal order should be fine.  */
958*cb63e24eSchristos   prev_bb = gbb;
959*cb63e24eSchristos   if (gbb->num_out_gedges)
960*cb63e24eSchristos     {
961*cb63e24eSchristos       bb_for_each_edge(gbb, gedge)
962*cb63e24eSchristos 	{
963*cb63e24eSchristos 	  gbb = gedge->dst_bb;
964*cb63e24eSchristos 	  if (gbb->visited)
965*cb63e24eSchristos 	    {
966*cb63e24eSchristos 	      ret = cmp_scfi_state (gbb->entry_state, state);
967*cb63e24eSchristos 	      if (ret)
968*cb63e24eSchristos 		goto fail;
969*cb63e24eSchristos 	    }
970*cb63e24eSchristos 
971*cb63e24eSchristos 	  if (!gedge->visited)
972*cb63e24eSchristos 	    {
973*cb63e24eSchristos 	      gedge->visited = true;
974*cb63e24eSchristos 
975*cb63e24eSchristos 	      /* Entry SCFI state for the destination bb of the edge is the
976*cb63e24eSchristos 		 same as the exit SCFI state of the source bb of the edge.  */
977*cb63e24eSchristos 	      memcpy (state, prev_bb->exit_state, sizeof (scfi_stateS));
978*cb63e24eSchristos 	      ret = forward_flow_scfi_state (gcfg, gbb, state);
979*cb63e24eSchristos 	      if (ret)
980*cb63e24eSchristos 		goto fail;
981*cb63e24eSchristos 	    }
982*cb63e24eSchristos 	}
983*cb63e24eSchristos     }
984*cb63e24eSchristos 
985*cb63e24eSchristos   return 0;
986*cb63e24eSchristos 
987*cb63e24eSchristos fail:
988*cb63e24eSchristos 
989*cb63e24eSchristos   if (gedge)
990*cb63e24eSchristos     gedge->visited = true;
991*cb63e24eSchristos   return 1;
992*cb63e24eSchristos }
993*cb63e24eSchristos 
994*cb63e24eSchristos static int
backward_flow_scfi_state(const symbolS * func ATTRIBUTE_UNUSED,gcfgS * gcfg)995*cb63e24eSchristos backward_flow_scfi_state (const symbolS *func ATTRIBUTE_UNUSED, gcfgS *gcfg)
996*cb63e24eSchristos {
997*cb63e24eSchristos   gbbS **prog_order_bbs;
998*cb63e24eSchristos   gbbS **restore_bbs;
999*cb63e24eSchristos   gbbS *current_bb;
1000*cb63e24eSchristos   gbbS *prev_bb;
1001*cb63e24eSchristos   gbbS *dst_bb;
1002*cb63e24eSchristos   ginsnS *ginsn;
1003*cb63e24eSchristos   gedgeS *gedge = NULL;
1004*cb63e24eSchristos 
1005*cb63e24eSchristos   int ret = 0;
1006*cb63e24eSchristos   uint64_t i, j;
1007*cb63e24eSchristos 
1008*cb63e24eSchristos   /* Basic blocks in reverse program order.  */
1009*cb63e24eSchristos   prog_order_bbs = XCNEWVEC (gbbS *, gcfg->num_gbbs);
1010*cb63e24eSchristos   /* Basic blocks for which CFI remember op needs to be generated.  */
1011*cb63e24eSchristos   restore_bbs = XCNEWVEC (gbbS *, gcfg->num_gbbs);
1012*cb63e24eSchristos 
1013*cb63e24eSchristos   gcfg_get_bbs_in_prog_order (gcfg, prog_order_bbs);
1014*cb63e24eSchristos 
1015*cb63e24eSchristos   i = gcfg->num_gbbs - 1;
1016*cb63e24eSchristos   /* Traverse in reverse program order.  */
1017*cb63e24eSchristos   while (i > 0)
1018*cb63e24eSchristos     {
1019*cb63e24eSchristos       current_bb = prog_order_bbs[i];
1020*cb63e24eSchristos       prev_bb = prog_order_bbs[i-1];
1021*cb63e24eSchristos       if (cmp_scfi_state (prev_bb->exit_state, current_bb->entry_state))
1022*cb63e24eSchristos 	{
1023*cb63e24eSchristos 	  /* Candidate for .cfi_restore_state found.  */
1024*cb63e24eSchristos 	  ginsn = bb_get_first_ginsn (current_bb);
1025*cb63e24eSchristos 	  scfi_op_add_cfi_restore_state (ginsn);
1026*cb63e24eSchristos 	  /* Memorize current_bb now to find location for its remember state
1027*cb63e24eSchristos 	     later.  */
1028*cb63e24eSchristos 	  restore_bbs[i] = current_bb;
1029*cb63e24eSchristos 	}
1030*cb63e24eSchristos       else
1031*cb63e24eSchristos 	{
1032*cb63e24eSchristos 	  bb_for_each_edge (current_bb, gedge)
1033*cb63e24eSchristos 	    {
1034*cb63e24eSchristos 	      dst_bb = gedge->dst_bb;
1035*cb63e24eSchristos 	      for (j = 0; j < gcfg->num_gbbs; j++)
1036*cb63e24eSchristos 		if (restore_bbs[j] == dst_bb)
1037*cb63e24eSchristos 		  {
1038*cb63e24eSchristos 		    ginsn = bb_get_last_ginsn (current_bb);
1039*cb63e24eSchristos 		    scfi_op_add_cfi_remember_state (ginsn);
1040*cb63e24eSchristos 		    /* Remove the memorised restore_bb from the list.  */
1041*cb63e24eSchristos 		    restore_bbs[j] = NULL;
1042*cb63e24eSchristos 		    break;
1043*cb63e24eSchristos 		  }
1044*cb63e24eSchristos 	    }
1045*cb63e24eSchristos 	}
1046*cb63e24eSchristos       i--;
1047*cb63e24eSchristos     }
1048*cb63e24eSchristos 
1049*cb63e24eSchristos   /* All .cfi_restore_state pseudo-ops must have a corresponding
1050*cb63e24eSchristos      .cfi_remember_state by now.  */
1051*cb63e24eSchristos   for (j = 0; j < gcfg->num_gbbs; j++)
1052*cb63e24eSchristos     if (restore_bbs[j] != NULL)
1053*cb63e24eSchristos       {
1054*cb63e24eSchristos 	ret = 1;
1055*cb63e24eSchristos 	break;
1056*cb63e24eSchristos       }
1057*cb63e24eSchristos 
1058*cb63e24eSchristos   free (restore_bbs);
1059*cb63e24eSchristos   free (prog_order_bbs);
1060*cb63e24eSchristos 
1061*cb63e24eSchristos   return ret;
1062*cb63e24eSchristos }
1063*cb63e24eSchristos 
1064*cb63e24eSchristos /* Synthesize DWARF CFI for a function.  */
1065*cb63e24eSchristos 
1066*cb63e24eSchristos int
scfi_synthesize_dw2cfi(const symbolS * func,gcfgS * gcfg,gbbS * root_bb)1067*cb63e24eSchristos scfi_synthesize_dw2cfi (const symbolS *func, gcfgS *gcfg, gbbS *root_bb)
1068*cb63e24eSchristos {
1069*cb63e24eSchristos   int ret;
1070*cb63e24eSchristos   scfi_stateS *init_state;
1071*cb63e24eSchristos 
1072*cb63e24eSchristos   init_state = XCNEW (scfi_stateS);
1073*cb63e24eSchristos   init_state->traceable_p = true;
1074*cb63e24eSchristos 
1075*cb63e24eSchristos   /* Traverse the input GCFG and perform forward flow of information.
1076*cb63e24eSchristos      Update the scfi_op(s) per ginsn.  */
1077*cb63e24eSchristos   ret = forward_flow_scfi_state (gcfg, root_bb, init_state);
1078*cb63e24eSchristos   if (ret)
1079*cb63e24eSchristos     {
1080*cb63e24eSchristos       as_bad (_("SCFI: forward pass failed for func '%s'"), S_GET_NAME (func));
1081*cb63e24eSchristos       goto end;
1082*cb63e24eSchristos     }
1083*cb63e24eSchristos 
1084*cb63e24eSchristos   ret = backward_flow_scfi_state (func, gcfg);
1085*cb63e24eSchristos   if (ret)
1086*cb63e24eSchristos     {
1087*cb63e24eSchristos       as_bad (_("SCFI: backward pass failed for func '%s'"), S_GET_NAME (func));
1088*cb63e24eSchristos       goto end;
1089*cb63e24eSchristos     }
1090*cb63e24eSchristos 
1091*cb63e24eSchristos end:
1092*cb63e24eSchristos   free (init_state);
1093*cb63e24eSchristos   return ret;
1094*cb63e24eSchristos }
1095*cb63e24eSchristos 
1096*cb63e24eSchristos static int
handle_scfi_dot_cfi(ginsnS * ginsn)1097*cb63e24eSchristos handle_scfi_dot_cfi (ginsnS *ginsn)
1098*cb63e24eSchristos {
1099*cb63e24eSchristos   scfi_opS *op;
1100*cb63e24eSchristos 
1101*cb63e24eSchristos   /* Nothing to do.  */
1102*cb63e24eSchristos   if (!ginsn->scfi_ops)
1103*cb63e24eSchristos     return 0;
1104*cb63e24eSchristos 
1105*cb63e24eSchristos   op = *ginsn->scfi_ops;
1106*cb63e24eSchristos   if (!op)
1107*cb63e24eSchristos     goto bad;
1108*cb63e24eSchristos 
1109*cb63e24eSchristos   while (op)
1110*cb63e24eSchristos     {
1111*cb63e24eSchristos       switch (op->dw2cfi_op)
1112*cb63e24eSchristos 	{
1113*cb63e24eSchristos 	case DW_CFA_def_cfa_register:
1114*cb63e24eSchristos 	  scfi_dot_cfi (DW_CFA_def_cfa_register, op->loc.base, 0, 0, NULL,
1115*cb63e24eSchristos 			ginsn->sym);
1116*cb63e24eSchristos 	  break;
1117*cb63e24eSchristos 	case DW_CFA_def_cfa_offset:
1118*cb63e24eSchristos 	  scfi_dot_cfi (DW_CFA_def_cfa_offset, op->loc.base, 0,
1119*cb63e24eSchristos 			op->loc.offset, NULL, ginsn->sym);
1120*cb63e24eSchristos 	  break;
1121*cb63e24eSchristos 	case DW_CFA_def_cfa:
1122*cb63e24eSchristos 	  scfi_dot_cfi (DW_CFA_def_cfa, op->loc.base, 0, op->loc.offset,
1123*cb63e24eSchristos 			NULL, ginsn->sym);
1124*cb63e24eSchristos 	  break;
1125*cb63e24eSchristos 	case DW_CFA_offset:
1126*cb63e24eSchristos 	  scfi_dot_cfi (DW_CFA_offset, op->reg, 0, op->loc.offset, NULL,
1127*cb63e24eSchristos 			ginsn->sym);
1128*cb63e24eSchristos 	  break;
1129*cb63e24eSchristos 	case DW_CFA_restore:
1130*cb63e24eSchristos 	  scfi_dot_cfi (DW_CFA_restore, op->reg, 0, 0, NULL, ginsn->sym);
1131*cb63e24eSchristos 	  break;
1132*cb63e24eSchristos 	case DW_CFA_remember_state:
1133*cb63e24eSchristos 	  scfi_dot_cfi (DW_CFA_remember_state, 0, 0, 0, NULL, ginsn->sym);
1134*cb63e24eSchristos 	  break;
1135*cb63e24eSchristos 	case DW_CFA_restore_state:
1136*cb63e24eSchristos 	  scfi_dot_cfi (DW_CFA_restore_state, 0, 0, 0, NULL, ginsn->sym);
1137*cb63e24eSchristos 	  break;
1138*cb63e24eSchristos 	case CFI_label:
1139*cb63e24eSchristos 	  scfi_dot_cfi (CFI_label, 0, 0, 0, op->op_data->name, ginsn->sym);
1140*cb63e24eSchristos 	  break;
1141*cb63e24eSchristos 	case CFI_signal_frame:
1142*cb63e24eSchristos 	  scfi_dot_cfi (CFI_signal_frame, 0, 0, 0, NULL, ginsn->sym);
1143*cb63e24eSchristos 	  break;
1144*cb63e24eSchristos 	default:
1145*cb63e24eSchristos 	  goto bad;
1146*cb63e24eSchristos 	  break;
1147*cb63e24eSchristos 	}
1148*cb63e24eSchristos       op = op->next;
1149*cb63e24eSchristos     }
1150*cb63e24eSchristos 
1151*cb63e24eSchristos   return 0;
1152*cb63e24eSchristos bad:
1153*cb63e24eSchristos   as_bad (_("SCFI: Invalid DWARF CFI opcode data"));
1154*cb63e24eSchristos   return 1;
1155*cb63e24eSchristos }
1156*cb63e24eSchristos 
1157*cb63e24eSchristos /* Emit Synthesized DWARF CFI.  */
1158*cb63e24eSchristos 
1159*cb63e24eSchristos int
scfi_emit_dw2cfi(const symbolS * func)1160*cb63e24eSchristos scfi_emit_dw2cfi (const symbolS *func)
1161*cb63e24eSchristos {
1162*cb63e24eSchristos   struct frch_ginsn_data *frch_gdata;
1163*cb63e24eSchristos   ginsnS* ginsn = NULL;
1164*cb63e24eSchristos 
1165*cb63e24eSchristos   frch_gdata = frchain_now->frch_ginsn_data;
1166*cb63e24eSchristos   ginsn = frch_gdata->gins_rootP;
1167*cb63e24eSchristos 
1168*cb63e24eSchristos   while (ginsn)
1169*cb63e24eSchristos     {
1170*cb63e24eSchristos       switch (ginsn->type)
1171*cb63e24eSchristos 	{
1172*cb63e24eSchristos 	  case GINSN_TYPE_SYMBOL:
1173*cb63e24eSchristos 	    /* .cfi_startproc and .cfi_endproc pseudo-ops.  */
1174*cb63e24eSchristos 	    if (GINSN_F_FUNC_BEGIN_P (ginsn))
1175*cb63e24eSchristos 	      {
1176*cb63e24eSchristos 		scfi_dot_cfi_startproc (frch_gdata->start_addr);
1177*cb63e24eSchristos 		break;
1178*cb63e24eSchristos 	      }
1179*cb63e24eSchristos 	    else if (GINSN_F_FUNC_END_P (ginsn))
1180*cb63e24eSchristos 	      {
1181*cb63e24eSchristos 		scfi_dot_cfi_endproc (ginsn->sym);
1182*cb63e24eSchristos 		break;
1183*cb63e24eSchristos 	      }
1184*cb63e24eSchristos 	    /* Fall through.  */
1185*cb63e24eSchristos 	  case GINSN_TYPE_ADD:
1186*cb63e24eSchristos 	  case GINSN_TYPE_AND:
1187*cb63e24eSchristos 	  case GINSN_TYPE_CALL:
1188*cb63e24eSchristos 	  case GINSN_TYPE_JUMP:
1189*cb63e24eSchristos 	  case GINSN_TYPE_JUMP_COND:
1190*cb63e24eSchristos 	  case GINSN_TYPE_MOV:
1191*cb63e24eSchristos 	  case GINSN_TYPE_LOAD:
1192*cb63e24eSchristos 	  case GINSN_TYPE_PHANTOM:
1193*cb63e24eSchristos 	  case GINSN_TYPE_STORE:
1194*cb63e24eSchristos 	  case GINSN_TYPE_SUB:
1195*cb63e24eSchristos 	  case GINSN_TYPE_OTHER:
1196*cb63e24eSchristos 	  case GINSN_TYPE_RETURN:
1197*cb63e24eSchristos 
1198*cb63e24eSchristos 	    /* For all other SCFI ops, invoke the handler.  */
1199*cb63e24eSchristos 	    if (ginsn->scfi_ops)
1200*cb63e24eSchristos 	      handle_scfi_dot_cfi (ginsn);
1201*cb63e24eSchristos 	    break;
1202*cb63e24eSchristos 
1203*cb63e24eSchristos 	  default:
1204*cb63e24eSchristos 	    /* No other GINSN_TYPE_* expected.  */
1205*cb63e24eSchristos 	    as_bad (_("SCFI: bad ginsn for func '%s'"),
1206*cb63e24eSchristos 		    S_GET_NAME (func));
1207*cb63e24eSchristos 	    break;
1208*cb63e24eSchristos 	}
1209*cb63e24eSchristos       ginsn = ginsn->next;
1210*cb63e24eSchristos     }
1211*cb63e24eSchristos   return 0;
1212*cb63e24eSchristos }
1213*cb63e24eSchristos 
1214*cb63e24eSchristos #else
1215*cb63e24eSchristos 
1216*cb63e24eSchristos int
scfi_emit_dw2cfi(const symbolS * func ATTRIBUTE_UNUSED)1217*cb63e24eSchristos scfi_emit_dw2cfi (const symbolS *func ATTRIBUTE_UNUSED)
1218*cb63e24eSchristos {
1219*cb63e24eSchristos   as_bad (_("SCFI: unsupported for target"));
1220*cb63e24eSchristos   return 1;
1221*cb63e24eSchristos }
1222*cb63e24eSchristos 
1223*cb63e24eSchristos int
scfi_synthesize_dw2cfi(const symbolS * func ATTRIBUTE_UNUSED,gcfgS * gcfg ATTRIBUTE_UNUSED,gbbS * root_bb ATTRIBUTE_UNUSED)1224*cb63e24eSchristos scfi_synthesize_dw2cfi (const symbolS *func ATTRIBUTE_UNUSED,
1225*cb63e24eSchristos 			gcfgS *gcfg ATTRIBUTE_UNUSED,
1226*cb63e24eSchristos 			gbbS *root_bb ATTRIBUTE_UNUSED)
1227*cb63e24eSchristos {
1228*cb63e24eSchristos   as_bad (_("SCFI: unsupported for target"));
1229*cb63e24eSchristos   return 1;
1230*cb63e24eSchristos }
1231*cb63e24eSchristos 
1232*cb63e24eSchristos #endif  /* defined (TARGET_USE_SCFI) && defined (TARGET_USE_GINSN).  */
1233