HPCToolkit
x86-build-intervals.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 //************************* System Include Files ****************************
48 
49 //*************************** User Include Files ****************************
50 
51 #include <stdbool.h>
52 
53 #include <include/hpctoolkit-config.h>
54 #include "x86-build-intervals.h"
55 
56 #include "uw_recipe_map.h"
57 
58 #include "x86-decoder.h"
59 #include "x86-process-inst.h"
60 #include "x86-unwind-analysis.h"
62 #include "x86-interval-arg.h"
63 
64 #if defined(ENABLE_XOP) && defined (HOST_CPU_x86_64)
65 #include "amd-xop.h"
66 #endif // ENABLE_XOP and HOST_CPU_x86_64
67 
68 #include <messages/messages.h>
69 
70 extern void x86_dump_ins(void* addr);
71 
72 static int dump_ins = 0;
73 
74 
75 /******************************************************************************
76  * forward declarations
77  *****************************************************************************/
78 
79 btuwi_status_t x86_build_intervals(void *ins, unsigned int len, int noisy);
80 
82 
83 /******************************************************************************
84  * interface operations
85  *****************************************************************************/
86 
88 x86_build_intervals(void *ins, unsigned int len, int noisy)
89 {
90 
91  btuwi_status_t status;
92 
93  xed_decoded_inst_t xedd;
94  xed_decoded_inst_t *xptr = &xedd;
95  xed_error_enum_t xed_error;
96 
97  // the local data structure for handling all of the various data needed for
98  // building intervals.
99  //
100 
101  interval_arg_t iarg;
102 
104 
105  int error_count = 0;
106 
107  unwind_interval *next = NULL;
108 
109  // local allocation of iarg data
110 
111  void *first_ins = ins;
112  void *end = ins + len;
113  int count = 1;
114 
115  iarg.beg = first_ins;
116  iarg.end = end;
117  iarg.highwatermark = _h;
118  iarg.ins = ins;
119  x86registers_t reg = {0, 0, BP_UNCHANGED, 0, 0};
120  iarg.current = new_ui(ins, RA_SP_RELATIVE, &reg);
121  iarg.first = iarg.current;
122  iarg.restored_canonical = iarg.current;
123 
124  // handle return is different if there are any bp frames
125 
126  iarg.bp_frames_found = false;
127  iarg.bp_just_pushed = false;
128  iarg.sp_realigned = false;
129 
131  iarg.canonical_interval = NULL;
132 
133  xed_decoded_inst_zero_set_mode(xptr, &x86_decoder_settings.xed_settings);
134 
135  if (noisy) dump_ui(iarg.current, true);
136 
137  while (iarg.ins < end) {
138  if (noisy && dump_ins) {
139  x86_dump_ins(iarg.ins);
140  }
141  xed_decoded_inst_zero_keep_mode(xptr);
142  xed_error = xed_decode(xptr, (uint8_t*) iarg.ins, 15);
143 
144  if (xed_error != XED_ERROR_NONE) {
145 #if defined(ENABLE_XOP) && defined (HOST_CPU_x86_64)
146  amd_decode_t decode_res;
147  adv_amd_decode(&decode_res, iarg.ins);
148  if (decode_res.success) {
149  if (decode_res.weak) {
150  // keep count of successes that are not robust
151  }
152  iarg.ins += decode_res.len;
153  continue;
154  }
155 #endif // ENABLE_XOP and HOST_CPU_x86_64
156  error_count++; /* note the error */
157  iarg.ins++; /* skip this byte */
158  continue; /* continue onward ... */
159  }
160 
161  // ensure that we don't move past the end of the interval because of a misaligned instruction
162  void *nextins = nextInsn(&iarg, xptr);
163  if (nextins > end) break;
164 
165  next = process_inst(xptr, &iarg);
166 
167  if (next != iarg.current) {
168  link_ui(iarg.current, next);
169  iarg.current = next;
170  count++;
171 
172  if (noisy) dump_ui(iarg.current, true);
173  }
174  iarg.ins += xed_decoded_inst_get_length(xptr);
175  UWI_END_ADDR(iarg.current) = (uintptr_t)iarg.ins;
176  }
177 
178  UWI_END_ADDR(iarg.current) = (uintptr_t)end;
179 
180  status.first_undecoded_ins = iarg.ins;
181  status.error = error_count;
182  status.first = iarg.first;
183 
184  x86_fix_unwind_intervals(iarg.beg, len, &status);
185  status.count = count - x86_coalesce_unwind_intervals(status.first);
186 
187  return status;
188 }
189 
190 
191 /******************************************************************************
192  * private operations
193  *****************************************************************************/
194 
195 static bool
197 {
198  return ( (proto->ra_status == cand->ra_status) &&
199  (proto->reg.sp_ra_pos == cand->reg.sp_ra_pos) &&
200  (proto->reg.sp_bp_pos == cand->reg.sp_bp_pos) &&
201  (proto->reg.bp_status == cand->reg.bp_status) &&
202  (proto->reg.bp_ra_pos == cand->reg.bp_ra_pos) &&
203  (proto->reg.bp_bp_pos == cand->reg.bp_bp_pos) );
204 }
205 
206 // NOTE: following routine has an additional side effect!
207 // the presence of tail calls is determined at interval building time,
208 // (and noted in the interval where it is detected).
209 //
210 // During the coalesce process after the initial interval set is complete,
211 // the interval-specific tail call presence is OR-reduced to yield the
212 // tail call presence for the entire routine.
213 // The entire routine has_tail_calls value is entered in the 1st interval for the
214 // routine.
215 //
216 // The tail call info is *currently* the only routine-level info computed at interval
217 // building time. If more routine-level information items come up, the reduction side
218 // effect of the coalesce routine can be expanded to accomodate.
219 
220 static int
222 {
223  int num_freed = 0;
224  TMSG(COALESCE,"coalescing interval list starting @ %p",ui);
225  if (! ui) {
226  TMSG(COALESCE," --interval list empty, so no work");
227  return num_freed;
228  }
229 
230  unwind_interval *first = ui;
231  unwind_interval *current = first;
232  ui = UWI_NEXT(ui);
233 
234  bool routine_has_tail_calls = UWI_RECIPE(first)->has_tail_calls;
235 
236  TMSG(COALESCE," starting prototype interval =");
237  if (ENABLED(COALESCE)){
238  dump_ui_log(current);
239  }
240  for (; ui; ui = UWI_NEXT(ui)) {
241  TMSG(COALESCE,"comparing this interval to prototype:");
242  if (ENABLED(COALESCE)){
243  dump_ui_log(ui);
244  }
245 
246  routine_has_tail_calls =
247  routine_has_tail_calls || UWI_RECIPE(current)->has_tail_calls || UWI_RECIPE(ui)->has_tail_calls;
248 
249  if (x86_ui_same_data(UWI_RECIPE(current), UWI_RECIPE(ui))){
250  UWI_END_ADDR(current) = UWI_END_ADDR(ui);
252  UWI_RECIPE(current)->has_tail_calls =
253  UWI_RECIPE(current)->has_tail_calls || UWI_RECIPE(ui)->has_tail_calls;
254  // disconnect ui's right subtree and free ui:
257  ++num_freed;
258 
259  ui = current;
260  TMSG(COALESCE,"Intervals match! Extended interval:");
261  if (ENABLED(COALESCE)){
262  dump_ui_log(current);
263  }
264  }
265  else {
266  TMSG(COALESCE,"Interval does not match prototype. Reset prototype to current interval");
267  current = ui;
268  }
269  }
270 
271  // update first interval with collected info
272  UWI_RECIPE(first)->has_tail_calls = routine_has_tail_calls;
273 
274  return num_freed;
275 }
276 
277 //*************************** Debug stuff ****************************
278 
280 
282 d_build_intervals(void* b, unsigned l)
283 {
284  d_istat = x86_build_intervals(b, l, 1);
285  return &d_istat;
286 }
bitree_uwi_t * first
xed_state_t xed_settings
Definition: x86-decoder.h:61
unwind_interval * restored_canonical
bool weak
Definition: amd-xop.h:9
bitree_uwi_t * first
void link_ui(unwind_interval *current, unwind_interval *next)
void adv_amd_decode(amd_decode_t *stat, void *ins)
Definition: amd-xop.c:227
char * first_undecoded_ins
void dump_ui_log(unwind_interval *u)
static btuwi_status_t d_istat
bool success
Definition: amd-xop.h:8
bitree_uwi_t * current
static bool x86_ui_same_data(x86recipe_t *proto, x86recipe_t *cand)
#define UWI_RECIPE(btuwi)
x86registers_t reg
static int x86_coalesce_unwind_intervals(unwind_interval *ui)
bitree_uwi_t * canonical_interval
static char * nextInsn(uint32_t *insn)
xed_control_t x86_decoder_settings
Definition: x86-decoder.c:58
btuwi_status_t x86_build_intervals(void *ins, unsigned int len, int noisy)
static xed_decoded_inst_t xedd
Definition: x86ISAXed.cpp:92
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)
int x86_fix_unwind_intervals(char *ins, int len, btuwi_status_t *stat)
void * rax_rbp_equivalent_at
btuwi_status_t * d_build_intervals(void *b, unsigned l)
#define UWI_NEXT(btuwi)
static int dump_ins
void dump_ui(unwind_interval *u, int dump_to_stderr)
size_t len
Definition: amd-xop.h:10
void bitree_uwi_free(unwinder_t uw, bitree_uwi_t *tree)
#define TMSG(f,...)
Definition: messages.h:93
#define UWI_END_ADDR(btuwi)
#define HW_UNINITIALIZED
Definition: x86-canonical.c:58
#define NULL
Definition: ElfHelper.cpp:85
bitree_uwi_t unwind_interval
cct_addr_t * addr
Definition: cct.c:130
unwind_interval * process_inst(xed_decoded_inst_t *xptr, interval_arg_t *iarg)
void x86_dump_ins(void *addr)
void bitree_uwi_set_rightsubtree(bitree_uwi_t *tree, bitree_uwi_t *subtree)
#define ENABLED(f)
Definition: debug-flag.h:76