HPCToolkit
x86-move.c
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
48 #include "x86-decoder.h"
49 #include "x86-interval-arg.h"
50 
52 
53 int
54 x86_bp_size(xed_reg_enum_t reg)
55 {
56  switch(reg) {
57 #if defined (HOST_CPU_x86_64)
58  case XED_REG_RBP: return 8;
59 #endif
60  case XED_REG_EBP: return 4;
61  case XED_REG_BP: return 2;
62  default: return 1;
63  }
64 }
65 
66 
68 process_move(xed_decoded_inst_t *xptr, const xed_inst_t *xi, interval_arg_t *iarg)
69 {
70  unwind_interval *next = iarg->current;
71  highwatermark_t *hw_tmp = &(iarg->highwatermark);
72 
73  const xed_operand_t *op0 = xed_inst_operand(xi, 0);
74  const xed_operand_t *op1 = xed_inst_operand(xi, 1);
75 
76  xed_operand_enum_t op0_name = xed_operand_name(op0);
77  xed_operand_enum_t op1_name = xed_operand_name(op1);
78  x86recipe_t *xr = UWI_RECIPE(iarg->current);
79  x86registers_t reg = xr->reg;
80 
81  if ((op0_name == XED_OPERAND_MEM0) && (op1_name == XED_OPERAND_REG0)) {
82  //------------------------------------------------------------------------
83  // storing a register to memory
84  //------------------------------------------------------------------------
85  xed_reg_enum_t basereg = xed_decoded_inst_get_base_reg(xptr, 0);
86  if (x86_isReg_SP(basereg)) {
87  //----------------------------------------------------------------------
88  // a memory move with SP as a base register
89  //----------------------------------------------------------------------
90  xed_reg_enum_t reg1 = xed_decoded_inst_get_reg(xptr, op1_name);
91  if (x86_isReg_BP(reg1) ||
92  (x86_isReg_AX(reg1) && (iarg->rax_rbp_equivalent_at == iarg->ins))){
93  //--------------------------------------------------------------------
94  // register being stored is BP (or a copy in RAX)
95  //--------------------------------------------------------------------
96  if (reg.bp_status == BP_UNCHANGED) {
97  //==================================================================
98  // instruction: save caller's BP into the stack
99  // action: create a new interval with
100  // (1) BP status reset to BP_SAVED
101  // (2) BP position relative to the stack pointer set
102  // to the offset from SP
103  //==================================================================
104  reg.bp_status = BP_SAVED;
105  reg.sp_bp_pos = xed_decoded_inst_get_memory_displacement(xptr, 0);
106  next = new_ui(nextInsn(iarg, xptr), xr->ra_status, &reg);
107  hw_tmp->uwi = next;
108  hw_tmp->state =
109  HW_NEW_STATE(hw_tmp->state, HW_BP_SAVED);
110  }
111  }
112  }
113  } else if ((op1_name == XED_OPERAND_MEM0) && (op0_name == XED_OPERAND_REG0)) {
114  //----------------------------------------------------------------------
115  // loading a register from memory
116  //----------------------------------------------------------------------
117  xed_reg_enum_t reg0 = xed_decoded_inst_get_reg(xptr, op0_name);
118  if (x86_isReg_BP(reg0)) {
119  //--------------------------------------------------------------------
120  // register being loaded is BP
121  //--------------------------------------------------------------------
122  if (reg.bp_status != BP_UNCHANGED) {
123  int64_t offset = xed_decoded_inst_get_memory_displacement(xptr, 0);
124  xed_reg_enum_t basereg = xed_decoded_inst_get_base_reg(xptr, 0);
125  if (x86_isReg_SP(basereg) && (offset == reg.sp_bp_pos)) {
126  //================================================================
127  // instruction: restore BP from its saved location in the stack
128  // action: create a new interval with BP status reset to
129  // BP_UNCHANGED
130  //================================================================
131  reg.bp_status = BP_UNCHANGED;
132  next = new_ui(nextInsn(iarg, xptr), RA_SP_RELATIVE, &reg);
133  } else {
134  //================================================================
135  // instruction: BP is loaded from a memory address DIFFERENT from
136  // its saved location in the stack
137  // action: create a new interval with BP status reset to
138  // BP_HOSED
139  //================================================================
140  if (reg.bp_status != BP_HOSED) {
141  reg.bp_status = BP_HOSED;
142  next = new_ui(nextInsn(iarg, xptr), RA_SP_RELATIVE, &reg);
143  if (HW_TEST_STATE(hw_tmp->state, HW_BP_SAVED,
144  HW_BP_OVERWRITTEN) &&
145  (UWI_RECIPE(hw_tmp->uwi)->reg.sp_ra_pos == UWI_RECIPE(next)->reg.sp_ra_pos)) {
146  hw_tmp->uwi = next;
147  hw_tmp->state =
149  }
150  }
151  }
152  }
153  } else if (x86_isReg_SP(reg0)) {
154  //--------------------------------------------------------------------
155  // register being loaded is SP
156  //--------------------------------------------------------------------
157  xed_reg_enum_t basereg = xed_decoded_inst_get_base_reg(xptr, 0);
158  if (x86_isReg_SP(basereg)) {
159  //================================================================
160  // instruction: restore SP from a saved location in the stack
161  // action: create a new interval with SP status reset to
162  // BP_UNCHANGED
163  //================================================================
164  reg.sp_ra_pos = 0;
165  reg.bp_ra_pos = 0;
166  next = new_ui(nextInsn(iarg, xptr), RA_SP_RELATIVE, &reg);
167  }
168  }
169  } else if ((op0_name == XED_OPERAND_REG0) && (op1_name == XED_OPERAND_REG1)){
170  //----------------------------------------------------------------------
171  // register-to-register move
172  //----------------------------------------------------------------------
173  xed_reg_enum_t reg0 = xed_decoded_inst_get_reg(xptr, op0_name);
174  xed_reg_enum_t reg1 = xed_decoded_inst_get_reg(xptr, op1_name);
175  if (x86_isReg_BP(reg1) && x86_isReg_SP(reg0)) {
176  //====================================================================
177  // instruction: restore SP from BP
178  // action: begin a new SP_RELATIVE interval
179  //====================================================================
180  reg.sp_ra_pos = reg.bp_ra_pos;
181  reg.sp_bp_pos = reg.bp_bp_pos;
182  next = new_ui(nextInsn(iarg, xptr), RA_SP_RELATIVE, &reg);
183  } else if (x86_isReg_BP(reg0) && x86_isReg_SP(reg1)) {
184  //====================================================================
185  // instruction: initialize BP with value of SP to set up a frame ptr
186  // action: begin a new interval
187  //====================================================================
188  reg.bp_status = BP_SAVED;
189  reg.bp_ra_pos = reg.sp_ra_pos;
190  reg.bp_bp_pos = reg.sp_bp_pos;
191  next = new_ui(nextInsn(iarg, xptr), RA_STD_FRAME, &reg);
192  if (iarg->sp_realigned) {
193  // SP was previously realigned. correct RA offsets based on typical
194  // frame layout in these circumstances.
195 
196  // assume RA is in word below BP
197  UWI_RECIPE(next)->reg.bp_ra_pos =
198  (UWI_RECIPE(next)->reg.bp_bp_pos + x86_bp_size(reg0));
199 
200  // RA offset wrt SP is the same, since SP == BP
201  UWI_RECIPE(next)->reg.sp_ra_pos = UWI_RECIPE(next)->reg.bp_ra_pos;
202 
203  // once we've handled SP realignment in the routine prologue, we can
204  // ignore it for the rest of the routine.
205  iarg->sp_realigned = false;
206  }
207  if (HW_TEST_STATE(hw_tmp->state, HW_BP_SAVED,
208  HW_BP_OVERWRITTEN)) {
209  hw_tmp->uwi = next;
210  hw_tmp->state =
212  }
213  } else if (x86_isReg_BP(reg1) && x86_isReg_AX(reg0)) {
214  //====================================================================
215  // instruction: copy BP to RAX
216  //====================================================================
217  iarg->rax_rbp_equivalent_at = nextInsn(iarg, xptr);
218  } else if (x86_isReg_BP(reg0)) {
219  if (reg.bp_status != BP_HOSED){
220  //==================================================================
221  // instruction: move some NON-special register to BP
222  // state: bp_status is NOT BP_HOSED
223  // action: begin a new RA_SP_RELATIVE,BP_HOSED interval
224  //==================================================================
225  reg.bp_status = BP_HOSED;
226  reg.bp_ra_pos = reg.sp_ra_pos;
227  reg.bp_bp_pos = reg.sp_bp_pos;
228  next = new_ui(nextInsn(iarg, xptr), RA_SP_RELATIVE, &reg);
229  if (HW_TEST_STATE(hw_tmp->state, HW_BP_SAVED,
230  HW_BP_OVERWRITTEN) &&
231  (UWI_RECIPE(hw_tmp->uwi)->reg.sp_ra_pos == UWI_RECIPE(next)->reg.sp_ra_pos)) {
232  hw_tmp->uwi = next;
233  hw_tmp->state =
235  }
236  }
237  }
238  }
239  return next;
240 }
#define HW_NEW_STATE(state, set)
int x86_bp_size(xed_reg_enum_t reg)
Definition: x86-move.c:54
bitree_uwi_t * current
#define HW_BP_SAVED
Definition: x86-canonical.c:55
#define UWI_RECIPE(btuwi)
#define HW_BP_OVERWRITTEN
Definition: x86-canonical.c:56
x86registers_t reg
static char * nextInsn(uint32_t *insn)
highwatermark_t highwatermark
unwind_interval * new_ui(char *startaddr, sp_ty_t sp_ty, ra_ty_t ra_ty, int sp_arg, int ra_arg)
void * rax_rbp_equivalent_at
#define HW_TEST_STATE(state, is_set, is_clear)
unwind_interval * process_move(xed_decoded_inst_t *xptr, const xed_inst_t *xi, interval_arg_t *iarg)
Definition: x86-move.c:68
bitree_uwi_t unwind_interval