HPCToolkit
x86-cold-path.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 //**************************************************************************
48 // Build intervals for a cold path 'function'
49 //
50 // A cold path 'function' is a block of code that the hpcfnbounds detector
51 // thinks is an independent function. The block of code, however, is not
52 // treated as a function. Instead of being called, the code block is
53 // conditionally branched to from a hot path 'parent' function. (it is not
54 // 'called' very often, so we call it cold path code). Furthermore a cold
55 // path 'function' does not 'return'; rather, it jumps back to the
56 // instruction just after the conditional branch in the hot path
57 //
58 // These routines take care of detecting a cold path 'function', and
59 // updating the intervals of the cold path code.
60 //
61 //**************************************************************************
62 
63 
64 //**************************************************************************
65 // system includes
66 //**************************************************************************
67 
68 #include <stdbool.h>
69 #include <stdint.h>
70 
71 
72 
73 //**************************************************************************
74 // local includes
75 //**************************************************************************
76 
77 #include "fnbounds_interface.h"
78 #include "uw_recipe_map.h"
79 #include "x86-decoder.h"
80 #include "x86-unwind-analysis.h"
81 #include "x86-interval-arg.h"
82 
83 #include <messages/messages.h>
84 
85 
86 
87 //**************************************************************************
88 // forward declarations
89 //**************************************************************************
90 
91 static bool confirm_cold_path_call(void *loc, interval_arg_t *iarg);
92 
93 
94 
95 //**************************************************************************
96 // interface operations
97 //**************************************************************************
98 
99 void
101 {
102  TMSG(COLD_CODE," --fixing up current intervals with the warm interval");
103  x86recipe_t *xr = UWI_RECIPE(warm);
104  int ra_offset = xr->reg.sp_ra_pos;
105  int bp_offset = xr->reg.sp_bp_pos;
106  if (ra_offset == 0) {
107  TMSG(COLD_CODE," --warm code calling routine has offset 0,"
108  " so no action taken");
109  return;
110  }
111  TMSG(COLD_CODE," --updating sp_ra_pos with offset %d",ra_offset);
112  unwind_interval *intv = first;
113  do {
114  xr = UWI_RECIPE(intv);
115  xr->reg.sp_ra_pos += ra_offset;
116  xr->reg.sp_bp_pos += bp_offset;
117  } while (intv != current && (intv = UWI_NEXT(intv)));
118 }
119 
120 // The cold code detector is called when unconditional jump is encountered
121 bool
122 hpcrun_is_cold_code(xed_decoded_inst_t *xptr, interval_arg_t *iarg)
123 {
124  void *ins = iarg->ins;
125  char *ins_end = nextInsn(iarg, xptr);
126  if (ins_end == iarg->end) {
127  void *branch_target = x86_get_branch_target(ins,xptr);
128 
129  // branch is indirect. this is not cold path code
130  if (branch_target == NULL) return false;
131 
132  // branch target is outside bounds of current routine
133  if (branch_target < iarg->beg || iarg->end <= branch_target) {
134  // this is a possible cold code routine
135  TMSG(COLD_CODE,"potential cold code jmp detected in routine starting @"
136  " %p (location in routine = %p)",iarg->beg,ins);
137 
138  unwindr_info_t unwr_info;
139  if( !uw_recipe_map_lookup(branch_target, NATIVE_UNWINDER, &unwr_info) ) {
140  EMSG("Weird result! jmp @ %p branch_target %p has no function bounds",
141  ins, branch_target);
142  return false;
143  }
144 
145  void *beg = (void*)unwr_info.interval.start;
146  if (branch_target == beg) {
147  TMSG(COLD_CODE," --jump is a regular tail call,"
148  " NOT a cold code return");
149  return false;
150  }
151 
152  // store the address of the branch, in case this turns out to be a
153  // cold path routine.
154  iarg->return_addr = branch_target;
155 
156  return confirm_cold_path_call(branch_target,iarg);
157  }
158  }
159  return false;
160 }
161 
162 
163 
164 //**************************************************************************
165 // private operations
166 //**************************************************************************
167 
168 // Confirm that the previous instruction is a conditional branch to
169 // the beginning of the cold call routine
170 static bool
172 {
173  xed_decoded_inst_t xedd;
174  xed_decoded_inst_t *xptr = &xedd;
175  xed_error_enum_t xed_error;
176  xed_decoded_inst_zero_set_mode(xptr, &x86_decoder_settings.xed_settings);
177  xed_decoded_inst_zero_keep_mode(xptr);
178  void *possible_call = loc - 6;
179  void *routine = iarg->beg;
180  xed_error = xed_decode(xptr, (uint8_t *)possible_call, 15);
181 
182  TMSG(COLD_CODE," --trying to confirm a cold code 'call' from addr %p",
183  possible_call);
184  if (xed_error != XED_ERROR_NONE) {
185  TMSG(COLD_CODE," --addr %p has xed decode error when attempting confirm",
186  possible_call);
187  return false;
188  }
189 
190  xed_iclass_enum_t xiclass = xed_decoded_inst_get_iclass(xptr);
191  switch(xiclass) {
192  case XED_ICLASS_JBE:
193  case XED_ICLASS_JL:
194  case XED_ICLASS_JLE:
195  case XED_ICLASS_JNB:
196  case XED_ICLASS_JNBE:
197  case XED_ICLASS_JNL:
198  case XED_ICLASS_JNLE:
199  case XED_ICLASS_JNO:
200  case XED_ICLASS_JNP:
201  case XED_ICLASS_JNS:
202  case XED_ICLASS_JNZ:
203  case XED_ICLASS_JO:
204  case XED_ICLASS_JP:
205  case XED_ICLASS_JRCXZ:
206  case XED_ICLASS_JS:
207  case XED_ICLASS_JZ:
208  TMSG(COLD_CODE," --conditional branch confirmed @ %p", possible_call);
209  void *the_call = x86_get_branch_target(possible_call, xptr);
210  TMSG(COLD_CODE," --comparing 'call' to %p to start of cold path %p",
211  the_call, routine);
212  return (the_call == routine);
213  break;
214  default:
215  TMSG(COLD_CODE," --No conditional branch @ %p, so NOT a cold call",
216  possible_call);
217  return false;
218  }
219  EMSG("confirm cold path call shouldn't get here!");
220  return false;
221 }
222 
xed_state_t xed_settings
Definition: x86-decoder.h:61
interval_t interval
Definition: unwindr_info.h:100
#define UWI_RECIPE(btuwi)
bool uw_recipe_map_lookup(void *addr, unwinder_t uw, unwindr_info_t *unwr_info)
x86registers_t reg
#define EMSG
Definition: messages.h:70
static char * nextInsn(uint32_t *insn)
xed_control_t x86_decoder_settings
Definition: x86-decoder.c:58
static bool confirm_cold_path_call(void *loc, interval_arg_t *iarg)
void * x86_get_branch_target(void *ins, xed_decoded_inst_t *xptr)
static xed_decoded_inst_t xedd
Definition: x86ISAXed.cpp:92
bool hpcrun_is_cold_code(xed_decoded_inst_t *xptr, interval_arg_t *iarg)
#define UWI_NEXT(btuwi)
#define TMSG(f,...)
Definition: messages.h:93
#define NULL
Definition: ElfHelper.cpp:85
bitree_uwi_t unwind_interval
uintptr_t start
Definition: interval_t.h:27
void hpcrun_cold_code_fixup(unwind_interval *first, unwind_interval *current, unwind_interval *warm)