HPCToolkit
x86-return.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 
47 #include "x86-canonical.h"
48 #include "x86-decoder.h"
50 #include "x86-interval-arg.h"
51 
53 
54 /******************************************************************************
55  * forward declarations
56  *****************************************************************************/
57 
58 static bool plt_is_next(char *ins);
59 
60 
61 /******************************************************************************
62  * interface operations
63  *****************************************************************************/
64 
66 process_return(xed_decoded_inst_t *xptr, bool irdebug, interval_arg_t *iarg)
67 {
68  unwind_interval *next = iarg->current;
69 
70  if (UWI_RECIPE(iarg->current)->ra_status == RA_SP_RELATIVE) {
71  int offset = UWI_RECIPE(iarg->current)->reg.sp_ra_pos;
72  if (offset != 0) {
74  do {
75  // fix offset
76  x86recipe_t *xr = UWI_RECIPE(u);
77  xr->reg.sp_ra_pos -= offset;
78  xr->reg.sp_bp_pos -= offset;
79  } while (u != iarg->current && (u = UWI_NEXT(u)));
80  }
81  if (UWI_RECIPE(iarg->current)->reg.bp_status == BP_HOSED) {
82  // invariant: when we reach a return, if the BP was overwritten, it
83  // should have been restored. this must be incorrect. let's reset
84  // the bp status for all intervals leading up to this one since
85  // the last canonical restore.
86  unwind_interval *start = iarg->restored_canonical;
87  unwind_interval *u = start;
88  do {
89  x86recipe_t *xr = UWI_RECIPE(u);
90  if (xr->reg.bp_status != BP_HOSED) {
91  start = NULL;
92  } else if (start == NULL)
93  start = u;
94  } while (u != iarg->current && (u = UWI_NEXT(u)));
95  u = start;
96  do {
97  x86recipe_t *xr = UWI_RECIPE(u);
99  } while (u != iarg->current && (u = UWI_NEXT(u)));
100  }
101  }
102  if (UWI_RECIPE(iarg->current)->reg.bp_status == BP_SAVED) {
103  suspicious_interval(iarg->ins);
104  }
105  if ((void*)nextInsn(iarg, xptr) < iarg->end) {
106  //-------------------------------------------------------------------------
107  // the return is not the last instruction in the interval;
108  // set up an interval for code after the return
109  //-------------------------------------------------------------------------
110  if (plt_is_next(nextInsn(iarg, xptr))) {
111  //-------------------------------------------------------------------------
112  // the code following the return is a program linkage table. each entry in
113  // the program linkage table should be invoked with the return address at
114  // top of the stack. this is exactly what the interval containing this
115  // return instruction looks like. set the current interval as the
116  // "canonical interval" to be restored after then jump at the end of each
117  // entry in the PLT.
118  //-------------------------------------------------------------------------
119  iarg->canonical_interval = iarg->current;
120  }
121  else {
122  reset_to_canonical_interval(xptr, &next, irdebug, iarg);
123  }
124  }
125  return next;
126 }
127 
128 
129 /******************************************************************************
130  * private operations
131  *****************************************************************************/
132 
133 static bool
134 plt_is_next(char *ins)
135 {
136 
137  // Assumes: 'ins' is pointing at the instruction from which
138  // lookahead is to occur (i.e, the instruction prior to the first
139  // lookahead).
140 
141  xed_state_t *xed_settings = &(x86_decoder_settings.xed_settings);
142 
143  xed_error_enum_t xed_err;
144  xed_decoded_inst_t xedd;
145  xed_decoded_inst_t *xptr = &xedd;
146  char *val_pushed = NULL;
147  char *push_succ_addr = NULL;
148  char *jmp_target = NULL;
149 
150  // skip optional padding if there appears to be any
151  while ((((long) ins) & 0x11) && (*ins == 0x0)) ins++;
152 
153  // -------------------------------------------------------
154  // requirement 1: push of displacement relative to IP
155  // -------------------------------------------------------
156  xed_decoded_inst_zero_set_mode(xptr, xed_settings);
157  xed_err = xed_decode(xptr, (uint8_t*) ins, 15);
158  if (xed_err != XED_ERROR_NONE) {
159  return false;
160  }
161 
162  if (iclass_eq(xptr, XED_ICLASS_PUSH)) {
163  if (xed_decoded_inst_number_of_memory_operands(xptr) == 2) {
164  const xed_inst_t* xi = xed_decoded_inst_inst(xptr);
165  const xed_operand_t* op0 = xed_inst_operand(xi, 0);
166  if ((xed_operand_name(op0) == XED_OPERAND_MEM0) &&
167  x86_isReg_IP(xed_decoded_inst_get_base_reg(xptr, 0))) {
168  int64_t offset = xed_decoded_inst_get_memory_displacement(xptr, 0);
169  push_succ_addr = ins + xed_decoded_inst_get_length(xptr);
170  val_pushed = push_succ_addr + offset;
171  }
172  }
173  }
174 
175  if (val_pushed == NULL) {
176  // push of proper type not recognized
177  return false;
178  }
179 
180  // -------------------------------------------------------
181  // requirement 2: jump target affects stack
182  // -------------------------------------------------------
183  xed_decoded_inst_zero_set_mode(xptr, xed_settings);
184  xed_err = xed_decode(xptr, (uint8_t*) push_succ_addr, 15);
185  if (xed_err != XED_ERROR_NONE) {
186  return false;
187  }
188 
189  if (iclass_eq(xptr, XED_ICLASS_JMP) ||
190  iclass_eq(xptr, XED_ICLASS_JMP_FAR)) {
191  if (xed_decoded_inst_number_of_memory_operands(xptr) == 1) {
192 
193  const xed_inst_t *xi = xed_decoded_inst_inst(xptr);
194  const xed_operand_t *op0 = xed_inst_operand(xi,0);
195  if ((xed_operand_name(op0) == XED_OPERAND_MEM0) &&
196  x86_isReg_IP(xed_decoded_inst_get_base_reg(xptr, 0))) {
197  long long offset = xed_decoded_inst_get_memory_displacement(xptr,0);
198  jmp_target = push_succ_addr + xed_decoded_inst_get_length(xptr) + offset;
199  }
200  }
201  }
202 
203  if (jmp_target == NULL) {
204  // jump of proper type not recognized
205  return false;
206  }
207 
208  //
209  // FIXME: Does the 8 need to be sizeof(void*) ?????
210  //
211  if ((jmp_target - val_pushed) == 8){
212  return true;
213  }
214 
215  return false;
216 }
217 
static bool plt_is_next(char *ins)
Definition: x86-return.c:134
xed_state_t xed_settings
Definition: x86-decoder.h:61
unwind_interval * restored_canonical
void suspicious_interval(void *pc)
unwind_interval * process_return(xed_decoded_inst_t *xptr, bool irdebug, interval_arg_t *iarg)
Definition: x86-return.c:66
void reset_to_canonical_interval(xed_decoded_inst_t *xptr, unwind_interval **next, bool irdebug, interval_arg_t *iarg)
Definition: x86-canonical.c:76
bitree_uwi_t * current
#define UWI_RECIPE(btuwi)
x86registers_t reg
#define iclass_eq(xptr, class)
Definition: x86-decoder.h:71
bitree_uwi_t * canonical_interval
static char * nextInsn(uint32_t *insn)
xed_control_t x86_decoder_settings
Definition: x86-decoder.c:58
static xed_decoded_inst_t xedd
Definition: x86ISAXed.cpp:92
#define UWI_NEXT(btuwi)
#define NULL
Definition: ElfHelper.cpp:85
bitree_uwi_t unwind_interval