CCTLib
Calling-context and data-object attribution library for Intel Pin
redspy_temporal_client.cpp
Go to the documentation of this file.
1 // @COPYRIGHT@
2 // Licensed under MIT license.
3 // See LICENSE.TXT file in the project root for more information.
4 // ==============================================================
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <malloc.h>
10 #include <iostream>
11 #include <unistd.h>
12 #include <assert.h>
13 #include <string.h>
14 #include <sys/mman.h>
15 #include <sstream>
16 #include <functional>
17 #include <unordered_set>
18 #include <vector>
19 #include <unordered_map>
20 #include <algorithm>
21 #include <list>
22 #include "pin.H"
23 #include "pin_isa_compat.H"
24 #include "cctlib.H"
25 #include "shadow_memory.H"
26 #include <xmmintrin.h>
27 #include <immintrin.h>
28 
29 extern "C" {
30 #include "xed-interface.h"
31 #include "xed-common-hdrs.h"
32 }
33 
34 #include <google/sparse_hash_map>
35 #include <google/dense_hash_map>
36 using google::dense_hash_map;
37 
38 using namespace std;
39 using namespace PinCCTLib;
40 
41 
42 // have R, W representative macros
43 #define READ_ACTION (0)
44 #define WRITE_ACTION (0xff)
45 
46 #define ONE_BYTE_READ_ACTION (0)
47 #define TWO_BYTE_READ_ACTION (0)
48 #define FOUR_BYTE_READ_ACTION (0)
49 #define EIGHT_BYTE_READ_ACTION (0)
50 
51 #define ONE_BYTE_WRITE_ACTION (0xff)
52 #define TWO_BYTE_WRITE_ACTION (0xffff)
53 #define FOUR_BYTE_WRITE_ACTION (0xffffffff)
54 #define EIGHT_BYTE_WRITE_ACTION (0xffffffffffffffff)
55 
56 
57 #define IS_ACCESS_WITHIN_PAGE_BOUNDARY(accessAddr, accessLen) (PAGE_OFFSET((accessAddr)) <= (PAGE_OFFSET_MASK - (accessLen)))
58 
59 /* Other footprint_client settings */
60 #define MAX_REDUNDANT_CONTEXTS_TO_LOG (1000)
61 #define THREAD_MAX (1024)
62 
63 #define ENCODE_ADDRESS_AND_ACCESS_LEN(addr, len) ((addr) | (((uint64_t)(len)) << 48))
64 #define DECODE_ADDRESS(addrAndLen) ((addrAndLen) & ((1L << 48) - 1))
65 #define DECODE_ACCESS_LEN(addrAndLen) ((addrAndLen) >> 48)
66 
67 
68 #define MAX_WRITE_OP_LENGTH (512)
69 #define MAX_WRITE_OPS_IN_INS (8)
70 #define MAX_REG_LENGTH (64)
71 
72 #define MAX_SIMD_LENGTH (64)
73 #define MAX_SIMD_REGS (32)
74 
75 #define MAX_ALIAS_REGS (16) //EAX, EBX, ECX, EDX, EBP, EDI, ESI, ESP, R8-R15
76 #define MAX_ALIAS_REG_SIZE (8) //RAX is 64bits
77 #define MAX_ALIAS_TYPE (3) //(RAX, EAX, AX),(AH),(AL)
78 
79 //different register group
80 enum AliasReg {
81  ALIAS_REG_A = 0, //RAX, EAX, AX, AH, or AL
97 };
98 
99 //alias type, generic, high byte or low byte
100 
102  ALIAS_GENERIC = 0, // RAX, EAX, or AX
104  ALIAS_LOW_BYTE // AL
105 };
106 
107 #if __BYTE_ORDER == __LITTLE_ENDIAN
108 //alias begin bytes for different types
109 #define ALIAS_BYTES_INDEX_64 (0)
110 #define ALIAS_BYTES_INDEX_32 (0)
111 #define ALIAS_BYTES_INDEX_16 (0)
112 #define ALIAS_BYTES_INDEX_8_L (0)
113 #define ALIAS_BYTES_INDEX_8_H (1)
114 
115 #elif __BYTE_ORDER == __BIG_ENDIAN
116 
117 #define ALIAS_BYTES_INDEX_64 (0)
118 #define ALIAS_BYTES_INDEX_32 (4)
119 #define ALIAS_BYTES_INDEX_16 (6)
120 #define ALIAS_BYTES_INDEX_8_L (7)
121 #define ALIAS_BYTES_INDEX_8_H (6)
122 
123 #else
124 
125 #error "unknown endianness"
126 
127 #endif
128 
129 
130 #ifdef ENABLE_SAMPLING
131 
132 #define WINDOW_ENABLE 1000000
133 #define WINDOW_DISABLE 100000000
134 #define WINDOW_CLEAN 10
135 #endif
136 
137 #define DECODE_DEAD(data) static_cast<ContextHandle_t>(((data)&0xffffffffffffffff) >> 32)
138 #define DECODE_KILL(data) (static_cast<ContextHandle_t>((data)&0x00000000ffffffff))
139 
140 
141 #define MAKE_CONTEXT_PAIR(a, b) (((uint64_t)(a) << 32) | ((uint64_t)(b)))
142 
143 #define delta 0.01
144 
145 
146 struct AddrValPair {
147  uint8_t value[MAX_WRITE_OP_LENGTH];
148  void* address;
149 } __attribute__((aligned(16)));
150 
151 struct LargeReg {
153 } __attribute__((aligned(32)));
154 
155 struct RedSpyThreadData {
157  struct LargeReg simdValue[MAX_SIMD_REGS];
158 
159  uint32_t regCtxt[REG_LAST];
160  UINT8 regValue[REG_LAST][MAX_REG_LENGTH];
161  UINT8 aliasValue[MAX_ALIAS_REGS][MAX_ALIAS_REG_SIZE];
162  uint32_t aliasCtxt[MAX_ALIAS_REGS][MAX_ALIAS_TYPE];
163  uint32_t simdCtxt[MAX_SIMD_REGS];
164 
165  uint64_t bytesWritten;
166 
167  long long numIns;
168  bool sampleFlag;
169  long long numWinds;
170 };
171 
172 // key for accessing TLS storage in the threads. initialized once in main()
173 static TLS_KEY client_tls_key;
175 
176 // function to access thread-specific data
177 inline RedSpyThreadData* ClientGetTLS(const THREADID threadId) {
178 #ifdef MULTI_THREADED
179  RedSpyThreadData* tdata =
180  static_cast<RedSpyThreadData*>(PIN_GetThreadData(client_tls_key, threadId));
181  return tdata;
182 #else
183  return gSingleThreadedTData;
184 #endif
185 }
186 
187 static INT32 Usage() {
188  PIN_ERROR("Pin tool to gather calling context on each load and store.\n" + KNOB_BASE::StringKnobSummary() + "\n");
189  return -1;
190 }
191 
192 // Main for RedSpy, initialize the tool, register instrumentation functions and call the target program.
193 static FILE* gTraceFile;
195 
196 struct {
197  char dummy1[128];
198  xed_state_t xedState;
199  char dummy2[128];
201 
202 // Initialized the needed data structures before launching the target program
203 static void ClientInit(int argc, char* argv[]) {
204  // Create output file
205  char name[MAX_FILE_PATH] = "redspy_temporal.out.";
206  char* envPath = getenv("CCTLIB_CLIENT_OUTPUT_FILE");
207 
208  if (envPath) {
209  // assumes max of MAX_FILE_PATH
210  snprintf(name, sizeof(name), "%s", envPath);
211  }
212 
213  gethostname(name + strlen(name), MAX_FILE_PATH - strlen(name));
214  pid_t pid = getpid();
215  sprintf(name + strlen(name), "%d", pid);
216  cerr << "\n Creating log file at:" << name << "\n";
217  gTraceFile = fopen(name, "w");
218  // print the arguments passed
219  fprintf(gTraceFile, "\n");
220 
221  for (int i = 0; i < argc; i++) {
222  fprintf(gTraceFile, "%s ", argv[i]);
223  }
224 
225  fprintf(gTraceFile, "\n");
226 
227  // Init Xed
228  // Init XED for decoding instructions
229  xed_state_init(&RedSpyGlobals.xedState, XED_MACHINE_MODE_LONG_64, (xed_address_width_enum_t)0, XED_ADDRESS_WIDTH_64b);
230 }
231 
232 
233 static const uint64_t READ_ACCESS_STATES[] = {/*0 byte */ 0, /*1 byte */ ONE_BYTE_READ_ACTION, /*2 byte */ TWO_BYTE_READ_ACTION, /*3 byte */ 0, /*4 byte */ FOUR_BYTE_READ_ACTION, /*5 byte */ 0, /*6 byte */ 0, /*7 byte */ 0, /*8 byte */ EIGHT_BYTE_READ_ACTION};
234 static const uint64_t WRITE_ACCESS_STATES[] = {/*0 byte */ 0, /*1 byte */ ONE_BYTE_WRITE_ACTION, /*2 byte */ TWO_BYTE_WRITE_ACTION, /*3 byte */ 0, /*4 byte */ FOUR_BYTE_WRITE_ACTION, /*5 byte */ 0, /*6 byte */ 0, /*7 byte */ 0, /*8 byte */ EIGHT_BYTE_WRITE_ACTION};
235 static const uint8_t OVERFLOW_CHECK[] = {/*0 byte */ 0, /*1 byte */ 0, /*2 byte */ 0, /*3 byte */ 1, /*4 byte */ 2, /*5 byte */ 3, /*6 byte */ 4, /*7 byte */ 5, /*8 byte */ 6};
236 
237 static dense_hash_map<uint64_t, uint64_t> RedMap[THREAD_MAX];
238 static dense_hash_map<uint64_t, uint64_t> ApproxRedMap[THREAD_MAX];
239 
240 static inline void AddToRedTable(uint64_t key, uint16_t value, THREADID threadId) __attribute__((always_inline, flatten));
241 static inline void AddToRedTable(uint64_t key, uint16_t value, THREADID threadId) {
242 #ifdef MULTI_THREADED
243  LOCK_RED_MAP();
244 #endif
245  dense_hash_map<uint64_t, uint64_t>::iterator it = RedMap[threadId].find(key);
246  if (it == RedMap[threadId].end()) {
247  RedMap[threadId][key] = value;
248  } else {
249  it->second += value;
250  }
251 #ifdef MULTI_THREADED
252  UNLOCK_RED_MAP();
253 #endif
254 }
255 
256 static inline void AddToApproximateRedTable(uint64_t key, uint16_t value, THREADID threadId) __attribute__((always_inline, flatten));
257 static inline void AddToApproximateRedTable(uint64_t key, uint16_t value, THREADID threadId) {
258 #ifdef MULTI_THREADED
259  LOCK_RED_MAP();
260 #endif
261  dense_hash_map<uint64_t, uint64_t>::iterator it = ApproxRedMap[threadId].find(key);
262  if (it == ApproxRedMap[threadId].end()) {
263  ApproxRedMap[threadId][key] = value;
264  } else {
265  it->second += value;
266  }
267 #ifdef MULTI_THREADED
268  UNLOCK_RED_MAP();
269 #endif
270 }
271 
272 
273 #ifdef ENABLE_SAMPLING
274 
275 static inline VOID EmptyCtxt(RedSpyThreadData* tData) {
276  memset(&tData->regCtxt, 0, sizeof(uint32_t) * REG_LAST);
277  memset(&tData->aliasCtxt, 0, sizeof(uint32_t) * MAX_ALIAS_REGS * MAX_ALIAS_TYPE);
278  memset(&tData->regValue, 0, REG_LAST * MAX_REG_LENGTH);
279  memset(&tData->aliasValue, 0, MAX_ALIAS_REGS * MAX_ALIAS_REG_SIZE);
280 }
281 
282 static ADDRINT IfEnableSample(THREADID threadId) {
283  RedSpyThreadData* const tData = ClientGetTLS(threadId);
284  return tData->sampleFlag;
285 }
286 
287 #endif
288 
289 static inline bool IsFloatInstruction(ADDRINT ip) {
290  xed_decoded_inst_t xedd;
291  xed_decoded_inst_zero_set_mode(&xedd, &RedSpyGlobals.xedState);
292 
293  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
294  xed_category_enum_t cat = xed_decoded_inst_get_category(&xedd);
295  switch (cat) {
296  case XED_CATEGORY_AES:
297  case XED_CATEGORY_CONVERT:
298  case XED_CATEGORY_PCLMULQDQ:
299  case XED_CATEGORY_SSE:
300  case XED_CATEGORY_AVX2:
301  case XED_CATEGORY_AVX:
302  case XED_CATEGORY_MMX:
303  case XED_CATEGORY_DATAXFER: {
304  // Get the mem operand
305 
306  const xed_inst_t* xi = xed_decoded_inst_inst(&xedd);
307  int noperands = xed_inst_noperands(xi);
308  int memOpIdx = -1;
309  for (int i = 0; i < noperands; i++) {
310  const xed_operand_t* op = xed_inst_operand(xi, i);
311  xed_operand_enum_t op_name = xed_operand_name(op);
312  if (XED_OPERAND_MEM0 == op_name) {
313  memOpIdx = i;
314  break;
315  }
316  }
317  if (memOpIdx == -1) {
318  return false;
319  }
320 
321  // TO DO MILIND case XED_OPERAND_MEM1:
322  xed_operand_element_type_enum_t eType = xed_decoded_inst_operand_element_type(&xedd, memOpIdx);
323  switch (eType) {
324  case XED_OPERAND_ELEMENT_TYPE_FLOAT16:
325  case XED_OPERAND_ELEMENT_TYPE_SINGLE:
326  case XED_OPERAND_ELEMENT_TYPE_DOUBLE:
327  case XED_OPERAND_ELEMENT_TYPE_LONGDOUBLE:
328  case XED_OPERAND_ELEMENT_TYPE_LONGBCD:
329  return true;
330  default:
331  return false;
332  }
333  } break;
334  case XED_CATEGORY_X87_ALU:
335  case XED_CATEGORY_FCMOV:
336  //case XED_CATEGORY_LOGICAL_FP:
337  // assumption, the access length must be either 4 or 8 bytes else assert!!!
338  //assert(*accessLen == 4 || *accessLen == 8);
339  return true;
340  case XED_CATEGORY_XSAVE:
341  case XED_CATEGORY_AVX2GATHER:
342  case XED_CATEGORY_STRINGOP:
343  default:
344  return false;
345  }
346  } else {
347  assert(0 && "failed to disassemble instruction");
348  // printf("\n Diassembly failure\n");
349  return false;
350  }
351 }
352 
353 
354 static inline bool IsFloatInstructionOld(ADDRINT ip) {
355  xed_decoded_inst_t xedd;
356  xed_decoded_inst_zero_set_mode(&xedd, &RedSpyGlobals.xedState);
357 
358  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
359  xed_iclass_enum_t iclassType = xed_decoded_inst_get_iclass(&xedd);
360  if (iclassType >= XED_ICLASS_F2XM1 && iclassType <= XED_ICLASS_FYL2XP1) {
361  return true;
362  }
363  if (iclassType >= XED_ICLASS_VBROADCASTSD && iclassType <= XED_ICLASS_VDPPS) {
364  return true;
365  }
366  if (iclassType >= XED_ICLASS_VRCPPS && iclassType <= XED_ICLASS_VSQRTSS) {
367  return true;
368  }
369  if (iclassType >= XED_ICLASS_VSUBPD && iclassType <= XED_ICLASS_VXORPS) {
370  return true;
371  }
372  switch (iclassType) {
373  case XED_ICLASS_ADDPD:
374  case XED_ICLASS_ADDPS:
375  case XED_ICLASS_ADDSD:
376  case XED_ICLASS_ADDSS:
377  case XED_ICLASS_ADDSUBPD:
378  case XED_ICLASS_ADDSUBPS:
379  case XED_ICLASS_ANDNPD:
380  case XED_ICLASS_ANDNPS:
381  case XED_ICLASS_ANDPD:
382  case XED_ICLASS_ANDPS:
383  case XED_ICLASS_BLENDPD:
384  case XED_ICLASS_BLENDPS:
385  case XED_ICLASS_BLENDVPD:
386  case XED_ICLASS_BLENDVPS:
387  case XED_ICLASS_CMPPD:
388  case XED_ICLASS_CMPPS:
389  case XED_ICLASS_CMPSD:
390  case XED_ICLASS_CMPSD_XMM:
391  case XED_ICLASS_COMISD:
392  case XED_ICLASS_COMISS:
393  case XED_ICLASS_CVTDQ2PD:
394  case XED_ICLASS_CVTDQ2PS:
395  case XED_ICLASS_CVTPD2PS:
396  case XED_ICLASS_CVTPI2PD:
397  case XED_ICLASS_CVTPI2PS:
398  case XED_ICLASS_CVTPS2PD:
399  case XED_ICLASS_CVTSD2SS:
400  case XED_ICLASS_CVTSI2SD:
401  case XED_ICLASS_CVTSI2SS:
402  case XED_ICLASS_CVTSS2SD:
403  case XED_ICLASS_DIVPD:
404  case XED_ICLASS_DIVPS:
405  case XED_ICLASS_DIVSD:
406  case XED_ICLASS_DIVSS:
407  case XED_ICLASS_DPPD:
408  case XED_ICLASS_DPPS:
409  case XED_ICLASS_HADDPD:
410  case XED_ICLASS_HADDPS:
411  case XED_ICLASS_HSUBPD:
412  case XED_ICLASS_HSUBPS:
413  case XED_ICLASS_MAXPD:
414  case XED_ICLASS_MAXPS:
415  case XED_ICLASS_MAXSD:
416  case XED_ICLASS_MAXSS:
417  case XED_ICLASS_MINPD:
418  case XED_ICLASS_MINPS:
419  case XED_ICLASS_MINSD:
420  case XED_ICLASS_MINSS:
421  case XED_ICLASS_MOVAPD:
422  case XED_ICLASS_MOVAPS:
423  case XED_ICLASS_MOVD:
424  case XED_ICLASS_MOVHLPS:
425  case XED_ICLASS_MOVHPD:
426  case XED_ICLASS_MOVHPS:
427  case XED_ICLASS_MOVLHPS:
428  case XED_ICLASS_MOVLPD:
429  case XED_ICLASS_MOVLPS:
430  case XED_ICLASS_MOVMSKPD:
431  case XED_ICLASS_MOVMSKPS:
432  case XED_ICLASS_MOVNTPD:
433  case XED_ICLASS_MOVNTPS:
434  case XED_ICLASS_MOVNTSD:
435  case XED_ICLASS_MOVNTSS:
436  case XED_ICLASS_MOVSD:
437  case XED_ICLASS_MOVSD_XMM:
438  case XED_ICLASS_MOVSS:
439  case XED_ICLASS_MULPD:
440  case XED_ICLASS_MULPS:
441  case XED_ICLASS_MULSD:
442  case XED_ICLASS_MULSS:
443  case XED_ICLASS_ORPD:
444  case XED_ICLASS_ORPS:
445  case XED_ICLASS_ROUNDPD:
446  case XED_ICLASS_ROUNDPS:
447  case XED_ICLASS_ROUNDSD:
448  case XED_ICLASS_ROUNDSS:
449  case XED_ICLASS_SHUFPD:
450  case XED_ICLASS_SHUFPS:
451  case XED_ICLASS_SQRTPD:
452  case XED_ICLASS_SQRTPS:
453  case XED_ICLASS_SQRTSD:
454  case XED_ICLASS_SQRTSS:
455  case XED_ICLASS_SUBPD:
456  case XED_ICLASS_SUBPS:
457  case XED_ICLASS_SUBSD:
458  case XED_ICLASS_SUBSS:
459  case XED_ICLASS_VADDPD:
460  case XED_ICLASS_VADDPS:
461  case XED_ICLASS_VADDSD:
462  case XED_ICLASS_VADDSS:
463  case XED_ICLASS_VADDSUBPD:
464  case XED_ICLASS_VADDSUBPS:
465  case XED_ICLASS_VANDNPD:
466  case XED_ICLASS_VANDNPS:
467  case XED_ICLASS_VANDPD:
468  case XED_ICLASS_VANDPS:
469  case XED_ICLASS_VBLENDPD:
470  case XED_ICLASS_VBLENDPS:
471  case XED_ICLASS_VBLENDVPD:
472  case XED_ICLASS_VBLENDVPS:
473  case XED_ICLASS_VBROADCASTSD:
474  case XED_ICLASS_VBROADCASTSS:
475  case XED_ICLASS_VCMPPD:
476  case XED_ICLASS_VCMPPS:
477  case XED_ICLASS_VCMPSD:
478  case XED_ICLASS_VCMPSS:
479  case XED_ICLASS_VCOMISD:
480  case XED_ICLASS_VCOMISS:
481  case XED_ICLASS_VCVTDQ2PD:
482  case XED_ICLASS_VCVTDQ2PS:
483  case XED_ICLASS_VCVTPD2PS:
484  case XED_ICLASS_VCVTPH2PS:
485  case XED_ICLASS_VCVTPS2PD:
486  case XED_ICLASS_VCVTSD2SS:
487  case XED_ICLASS_VCVTSI2SD:
488  case XED_ICLASS_VCVTSI2SS:
489  case XED_ICLASS_VCVTSS2SD:
490  case XED_ICLASS_VDIVPD:
491  case XED_ICLASS_VDIVPS:
492  case XED_ICLASS_VDIVSD:
493  case XED_ICLASS_VDIVSS:
494  case XED_ICLASS_VDPPD:
495  case XED_ICLASS_VDPPS:
496  case XED_ICLASS_VMASKMOVPD:
497  case XED_ICLASS_VMASKMOVPS:
498  case XED_ICLASS_VMAXPD:
499  case XED_ICLASS_VMAXPS:
500  case XED_ICLASS_VMAXSD:
501  case XED_ICLASS_VMAXSS:
502  case XED_ICLASS_VMINPD:
503  case XED_ICLASS_VMINPS:
504  case XED_ICLASS_VMINSD:
505  case XED_ICLASS_VMINSS:
506  case XED_ICLASS_VMOVAPD:
507  case XED_ICLASS_VMOVAPS:
508  case XED_ICLASS_VMOVD:
509  case XED_ICLASS_VMOVHLPS:
510  case XED_ICLASS_VMOVHPD:
511  case XED_ICLASS_VMOVHPS:
512  case XED_ICLASS_VMOVLHPS:
513  case XED_ICLASS_VMOVLPD:
514  case XED_ICLASS_VMOVLPS:
515  case XED_ICLASS_VMOVMSKPD:
516  case XED_ICLASS_VMOVMSKPS:
517  case XED_ICLASS_VMOVNTPD:
518  case XED_ICLASS_VMOVNTPS:
519  case XED_ICLASS_VMOVSD:
520  case XED_ICLASS_VMOVSS:
521  case XED_ICLASS_VMOVUPD:
522  case XED_ICLASS_VMOVUPS:
523  case XED_ICLASS_VMULPD:
524  case XED_ICLASS_VMULPS:
525  case XED_ICLASS_VMULSD:
526  case XED_ICLASS_VMULSS:
527  case XED_ICLASS_VORPD:
528  case XED_ICLASS_VORPS:
529  case XED_ICLASS_VPABSD:
530  case XED_ICLASS_VPADDD:
531  case XED_ICLASS_VPCOMD:
532  case XED_ICLASS_VPCOMUD:
533  case XED_ICLASS_VPERMILPD:
534  case XED_ICLASS_VPERMILPS:
535  case XED_ICLASS_VPERMPD:
536  case XED_ICLASS_VPERMPS:
537  case XED_ICLASS_VPGATHERDD:
538  case XED_ICLASS_VPGATHERQD:
539  case XED_ICLASS_VPHADDBD:
540  case XED_ICLASS_VPHADDD:
541  case XED_ICLASS_VPHADDUBD:
542  case XED_ICLASS_VPHADDUWD:
543  case XED_ICLASS_VPHADDWD:
544  case XED_ICLASS_VPHSUBD:
545  case XED_ICLASS_VPHSUBWD:
546  case XED_ICLASS_VPINSRD:
547  case XED_ICLASS_VPMACSDD:
548  case XED_ICLASS_VPMACSSDD:
549  case XED_ICLASS_VPMASKMOVD:
550  case XED_ICLASS_VPMAXSD:
551  case XED_ICLASS_VPMAXUD:
552  case XED_ICLASS_VPMINSD:
553  case XED_ICLASS_VPMINUD:
554  case XED_ICLASS_VPROTD:
555  case XED_ICLASS_VPSUBD:
556  case XED_ICLASS_XORPD:
557  case XED_ICLASS_XORPS:
558  return true;
559 
560  default:
561  return false;
562  }
563  } else {
564  assert(0 && "failed to disassemble instruction");
565  return false;
566  }
567 }
568 /*
569 static inline bool IsFloatInstruction(ADDRINT ip, uint32_t oper) {
570  xed_decoded_inst_t xedd;
571  xed_decoded_inst_zero_set_mode(&xedd, &RedSpyGlobals.xedState);
572 
573  if(XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
574  xed_operand_element_type_enum_t TypeOperand = xed_decoded_inst_operand_element_type(&xedd,oper);
575  if(TypeOperand == XED_OPERAND_ELEMENT_TYPE_SINGLE || TypeOperand == XED_OPERAND_ELEMENT_TYPE_DOUBLE || TypeOperand == XED_OPERAND_ELEMENT_TYPE_FLOAT16 || TypeOperand == XED_OPERAND_ELEMENT_TYPE_LONGDOUBLE)
576  return true;
577  return false;
578  } else {
579  assert(0 && "failed to disassemble instruction");
580  return false;
581  }
582 }*/
583 
584 static inline uint16_t FloatOperandSize(ADDRINT ip, uint32_t oper) {
585  xed_decoded_inst_t xedd;
586  xed_decoded_inst_zero_set_mode(&xedd, &RedSpyGlobals.xedState);
587 
588  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
589  xed_operand_element_type_enum_t TypeOperand = xed_decoded_inst_operand_element_type(&xedd, oper);
590  if (TypeOperand == XED_OPERAND_ELEMENT_TYPE_SINGLE || TypeOperand == XED_OPERAND_ELEMENT_TYPE_FLOAT16)
591  return 4;
592  if (TypeOperand == XED_OPERAND_ELEMENT_TYPE_DOUBLE) {
593  return 8;
594  }
595  if (TypeOperand == XED_OPERAND_ELEMENT_TYPE_LONGDOUBLE) {
596  return 16;
597  }
598  assert(0 && "float instruction with unknown operand\n");
599  return 0;
600  } else {
601  assert(0 && "failed to disassemble instruction\n");
602  return 0;
603  }
604 }
605 
606 /*********************************************************************************/
607 /* register analysis */
608 /*********************************************************************************/
609 
610 /**************** handleing align registers ****************/
611 template <class T, AliasGroup aliasGroup>
613  static __attribute__((always_inline)) void CheckUpdateGenericAlias(uint8_t regId, T value, uint32_t opaqueHandle, THREADID threadId) {
614  RedSpyThreadData* const tData = ClientGetTLS(threadId);
615  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
616 
617 //alias begin bytes for different types
618 #if __BYTE_ORDER == __LITTLE_ENDIAN
619  uint8_t byteOffset = aliasGroup == ALIAS_HIGH_BYTE ? 1 : 0;
620 #else
621 #error "unknown endianness"
622 #endif
623 
624 
625  T* where = (T*)(&tData->aliasValue[regId][byteOffset]);
626 
627  if (*where == value) {
628  AddToRedTable(MAKE_CONTEXT_PAIR(tData->aliasCtxt[regId][aliasGroup], curCtxtHandle), sizeof(T), threadId);
629  } else {
630  *where = value;
631  }
632  tData->aliasCtxt[regId][ALIAS_GENERIC] = curCtxtHandle;
633  if (aliasGroup == ALIAS_GENERIC) {
634  tData->aliasCtxt[regId][ALIAS_HIGH_BYTE] = curCtxtHandle;
635  tData->aliasCtxt[regId][ALIAS_LOW_BYTE] = curCtxtHandle;
636  } else {
637  tData->aliasCtxt[regId][aliasGroup] = curCtxtHandle;
638  }
639  }
640 };
641 
642 /**************** handleing general registers ****************/
643 template <class T, uint8_t len>
645  static __attribute__((always_inline)) void CheckValues(T value, REG reg, uint32_t opaqueHandle, THREADID threadId) {
646  RedSpyThreadData* const tData = ClientGetTLS(threadId);
647  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
648 
649  T* regBefore = (T*)(&tData->regValue[reg][0]);
650 
651  if (*regBefore == value) {
652  AddToRedTable(MAKE_CONTEXT_PAIR(tData->regCtxt[reg], curCtxtHandle), sizeof(T), threadId);
653  } else
654  *regBefore = value;
655  tData->regCtxt[reg] = curCtxtHandle;
656  }
657 };
658 
659 //lenInt64: 1(X87), 2(XMM), 4(YMM), 8(ZMM)
660 template <uint8_t lenInt64>
662  //check the MM_x part registers in X87
663  static __attribute__((always_inline)) void CheckRegValues(PIN_REGISTER* regRef, REG regID, uint32_t opaqueHandle, THREADID threadId) {
664  RedSpyThreadData* const tData = ClientGetTLS(threadId);
665 
666  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
667 
668  if (lenInt64 == 1) {
669  uint64_t* oldValue = (uint64_t*)&(tData->regValue[regID][0]);
670  if (*oldValue == regRef->qword[0])
671  AddToRedTable(MAKE_CONTEXT_PAIR(tData->regCtxt[regID], curCtxtHandle), 8, threadId);
672  else
673  *oldValue = regRef->qword[0];
674 
675  tData->regCtxt[regID] = curCtxtHandle;
676  } else if (lenInt64 == 2) {
677  uint64_t* oldValue1 = (uint64_t*)&(tData->simdValue[regID].value);
678  uint64_t* oldValue2 = (uint64_t*)&(tData->simdValue[regID].value[8]);
679  if (*oldValue1 == regRef->qword[0] && *oldValue2 == regRef->qword[1])
680  AddToRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[regID], curCtxtHandle), 16, threadId);
681  else {
682  *oldValue1 = regRef->qword[0];
683  *oldValue2 = regRef->qword[1];
684  }
685  tData->simdCtxt[regID] = curCtxtHandle;
686 
687  } else {
688  uint64_t* oldValue;
689  bool isRedundant = true;
690  for (int i = 0, j = 0; i < lenInt64; ++i, j += 8) {
691  oldValue = (uint64_t*)&(tData->simdValue[regID].value[j]);
692  if (*oldValue != regRef->qword[i]) {
693  isRedundant = false;
694  *oldValue = regRef->qword[i];
695  }
696  }
697 
698  if (isRedundant)
699  AddToRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[regID], curCtxtHandle), lenInt64 * 8, threadId);
700 
701  tData->simdCtxt[regID] = curCtxtHandle;
702  }
703  }
704 
705  static __attribute__((always_inline)) void CheckSIMDRegValues(PIN_REGISTER* regRef, uint8_t simdID, uint32_t opaqueHandle, THREADID threadId) {
706  RedSpyThreadData* const tData = ClientGetTLS(threadId);
707 
708  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
709 
710  if (lenInt64 == 2) {
711  uint64_t* oldValue1 = (uint64_t*)&(tData->simdValue[simdID].value[0]);
712  uint64_t* oldValue2 = (uint64_t*)&(tData->simdValue[simdID].value[8]);
713  if (*oldValue1 == regRef->qword[0] && *oldValue2 == regRef->qword[1])
714  AddToRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[simdID], curCtxtHandle), 16, threadId);
715  else {
716  *oldValue1 = regRef->qword[0];
717  *oldValue2 = regRef->qword[1];
718  }
719  } else {
720  uint64_t* oldValue;
721  bool isRedundant = true;
722  for (int i = 0, j = 0; i < lenInt64; ++i, j += 8) {
723  oldValue = (uint64_t*)&(tData->simdValue[simdID].value[j]);
724  if (*oldValue != regRef->qword[i]) {
725  isRedundant = false;
726  *oldValue = regRef->qword[i];
727  }
728  }
729 
730  if (isRedundant)
731  AddToRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[simdID], curCtxtHandle), lenInt64 * 8, threadId);
732  }
733  tData->simdCtxt[simdID] = curCtxtHandle;
734  }
735 };
736 
737 /**************** handleing registers approximation ****************/
738 //static void Check10BytesReg(PIN_REGISTER* regRef, REG reg, uint32_t opaqueHandle, THREADID threadId)__attribute__((always_inline));
739 static void Check10BytesReg(CONTEXT* ctxt, REG reg, uint32_t opaqueHandle, THREADID threadId) {
740  RedSpyThreadData* const tData = ClientGetTLS(threadId);
741  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
742 
743  UINT8* valueAfter;
744  valueAfter = (UINT8*)malloc(10 * sizeof(UINT8));
745  PIN_GetContextRegval(ctxt, reg, valueAfter);
746 
747  uint64_t* upperOld = (uint64_t*)&(tData->regValue[reg][2]);
748  uint64_t* upperNew = (uint64_t*)&(valueAfter[2]);
749 
750  uint16_t* lowOld = (uint16_t*)&(tData->regValue[reg][0]);
751  uint16_t* lowNew = (uint16_t*)(valueAfter);
752 
753  if ((*lowOld & 0xfff0) == (*lowNew & 0xfff0) && *upperNew == *upperOld) {
754  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->regCtxt[reg], curCtxtHandle), 10, threadId);
755  *lowOld = *lowNew;
756  } else
757  memcpy(&tData->regValue[reg][0], valueAfter, 10);
758  tData->regCtxt[reg] = curCtxtHandle;
759 }
760 
761 //approximate general registers
762 template <class T, bool isAlias>
764  static __attribute__((always_inline)) void CheckValues(PIN_REGISTER* regRef, uint32_t reg, uint32_t opaqueHandle, THREADID threadId) {
765  RedSpyThreadData* const tData = ClientGetTLS(threadId);
766 
767  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
768 
769  if (isAlias) {
770  uint8_t byteOffset = 0;
771 
772  T newValue;
773  if (sizeof(T) == 8)
774  newValue = regRef->dbl[0];
775  else
776  newValue = regRef->flt[0];
777 
778  T oldValue = *((T*)(&tData->aliasValue[reg][byteOffset]));
779  T rate = (newValue - oldValue) / oldValue;
780  if (rate <= delta && rate >= -delta) {
781  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->aliasCtxt[reg][ALIAS_GENERIC], curCtxtHandle), sizeof(T), threadId);
782  }
783  if (newValue != oldValue)
784  *((T*)(&tData->aliasValue[reg][byteOffset])) = newValue;
785 
786  tData->aliasCtxt[reg][ALIAS_GENERIC] = curCtxtHandle;
787  tData->aliasCtxt[reg][ALIAS_HIGH_BYTE] = curCtxtHandle;
788  tData->aliasCtxt[reg][ALIAS_LOW_BYTE] = curCtxtHandle;
789 
790  } else {
791  T newValue;
792  if (sizeof(T) == 8)
793  newValue = regRef->dbl[0];
794  else
795  newValue = regRef->flt[0];
796 
797  T oldValue = *((T*)(&tData->regValue[reg][0]));
798  T rate = (newValue - oldValue) / oldValue;
799  if (rate <= delta && rate >= -delta) {
800  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->regCtxt[reg], curCtxtHandle), sizeof(T), threadId);
801  }
802  if (newValue != oldValue)
803  *((T*)(&tData->regValue[reg][0])) = newValue;
804  tData->regCtxt[reg] = curCtxtHandle;
805  }
806  }
807 };
808 
809 //approximate SIMD registers, simdType:0(XMM), 1(YMM), 2(ZMM)
810 template <class T, uint8_t simdType>
812  static __attribute__((always_inline)) void CheckValues(PIN_REGISTER* regRef, uint8_t regInd, uint32_t opaqueHandle, THREADID threadId) {
813  RedSpyThreadData* const tData = ClientGetTLS(threadId);
814 
815  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
816 
817  if (simdType == 0) {
818  if (sizeof(T) == 4) {
819  __m128 oldValue = _mm_load_ps(reinterpret_cast<const float*>(&(tData->simdValue[regInd].value[0])));
820  __m128 newValue = _mm_loadu_ps(reinterpret_cast<const float*>(regRef));
821 
822  __m128 result = _mm_sub_ps(newValue, oldValue);
823 
824  result = _mm_div_ps(result, oldValue);
825  float rates[4] __attribute__((aligned(16)));
826  _mm_store_ps(rates, result);
827 
828  uint8_t redCount = 0;
829  if (rates[0] <= delta && rates[0] >= -delta)
830  redCount++;
831  if (rates[1] <= delta && rates[1] >= -delta)
832  redCount++;
833  if (rates[2] <= delta && rates[2] >= -delta)
834  redCount++;
835  if (rates[3] <= delta && rates[3] >= -delta)
836  redCount++;
837 
838  if (redCount)
839  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[regInd], curCtxtHandle), 4 * redCount, threadId);
840  _mm_store_ps(reinterpret_cast<float*>(&(tData->simdValue[regInd].value[0])), newValue);
841 
842  } else if (sizeof(T) == 8) {
843  __m128d oldValue = _mm_load_pd(reinterpret_cast<const double*>(&(tData->simdValue[regInd].value[0])));
844  __m128d newValue = _mm_loadu_pd(reinterpret_cast<const double*>(regRef));
845 
846  __m128d result = _mm_sub_pd(newValue, oldValue);
847 
848  result = _mm_div_pd(result, oldValue);
849 
850  double rate[2];
851  _mm_storel_pd(&rate[0], result);
852  _mm_storeh_pd(&rate[1], result);
853 
854  uint8_t redCount = 0;
855  if (rate[0] <= delta && rate[0] >= -delta)
856  redCount++;
857  if (rate[1] <= delta && rate[1] >= -delta)
858  redCount++;
859 
860  if (redCount)
861  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[regInd], curCtxtHandle), 8 * redCount, threadId);
862  _mm_store_pd(reinterpret_cast<double*>(&(tData->simdValue[regInd].value[0])), newValue);
863  } else
864  ;
865 
866  } else if (simdType == 1) {
867  if (sizeof(T) == 4) {
868  __m256 oldValue = _mm256_load_ps(reinterpret_cast<const float*>(&(tData->simdValue[regInd].value[0])));
869  __m256 newValue = _mm256_loadu_ps(reinterpret_cast<const float*>(regRef));
870 
871  __m256 result = _mm256_sub_ps(newValue, oldValue);
872 
873  result = _mm256_div_ps(result, oldValue);
874  float rates[8] __attribute__((aligned(32)));
875  _mm256_store_ps(rates, result);
876 
877  uint8_t redCount = 0;
878  for (int i = 0; i < 7; ++i)
879  if (rates[i] <= delta && rates[i] >= -delta)
880  redCount++;
881 
882  if (redCount)
883  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[regInd], curCtxtHandle), 4 * redCount, threadId);
884  _mm256_store_ps(reinterpret_cast<float*>(&(tData->simdValue[regInd].value[0])), newValue);
885 
886  } else if (sizeof(T) == 8) {
887  __m256d oldValue = _mm256_load_pd(reinterpret_cast<const double*>(&(tData->simdValue[regInd].value[0])));
888  __m256d newValue = _mm256_loadu_pd(reinterpret_cast<const double*>(regRef));
889 
890  __m256d result = _mm256_sub_pd(newValue, oldValue);
891 
892  result = _mm256_div_pd(result, oldValue);
893 
894  double rate[4] __attribute__((aligned(32)));
895  _mm256_store_pd(rate, result);
896 
897  uint8_t redCount = 0;
898  if (rate[0] <= delta && rate[0] >= -delta)
899  redCount++;
900  if (rate[1] <= delta && rate[1] >= -delta)
901  redCount++;
902  if (rate[2] <= delta && rate[2] >= -delta)
903  redCount++;
904  if (rate[3] <= delta && rate[3] >= -delta)
905  redCount++;
906 
907  if (redCount)
908  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[regInd], curCtxtHandle), 8 * redCount, threadId);
909  _mm256_store_pd(reinterpret_cast<double*>(&(tData->simdValue[regInd].value[0])), newValue);
910  } else
911  ;
912 
913  } else
914  ; /*else{
915 
916  if(sizeof(T) == 4){
917  __m512 oldValue = _mm512_load_ps( reinterpret_cast<const float*> (&(tData->simdValue[regInd].value[0])));
918  __m512 newValue = _mm512_loadu_ps( reinterpret_cast<const float*> (regRef));
919 
920  __m512 result = _mm512_sub_ps(newValue,oldValue);
921 
922  result = _mm512_div_ps(result,oldValue);
923  float rates[16] __attribute__((aligned(64)));
924  _mm512_store_ps(rates,result);
925 
926  uint8_t redCount = 0;
927  for(int i = 0; i < 15; ++i)
928  if(rates[i] <= delta && rates[i] >= -delta) redCount++;
929 
930  if(redCount)
931  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->simdCtxt[regInd],curCtxtHandle),4*redCount,threadId);
932  _mm512_store_ps(reinterpret_cast<float*> (&(tData->simdValue[regInd].value[0])),newValue);
933 
934  }else if(sizeof(T) == 8){
935  __m512d oldValue = _mm512_load_pd( reinterpret_cast<const double*> (&(tData->simdValue[regInd].value[0])));
936  __m512d newValue = _mm512_loadu_pd( reinterpret_cast<const double*> (regRef));
937 
938  __m512d result = _mm512_sub_pd(newValue,oldValue);
939 
940  result = _mm512_div_pd(result,oldValue);
941 
942  double rates[8] __attribute__((aligned(64)));
943  _mm512_store_ps(rates,result);
944 
945  uint8_t redCount = 0;
946  for(int i = 0; i < 7; ++i)
947  if(rates[i] <= delta && rates[i] >= -delta) redCount++;
948 
949  if(redCount)
950  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(tData->regCtxt[reg],curCtxtHandle),8*redCount,threadId);
951  _mm512_store_pd(reinterpret_cast<double*> (&(tData->simdValue[regInd].value[0])),newValue);
952  }else ;
953  }*/
954 
955  tData->simdCtxt[regInd] = curCtxtHandle;
956  }
957 };
958 
959 static inline uint32_t GetAliasIDs(REG reg) {
960  uint8_t regGroup = 0;
961  uint8_t byteInd = 0;
962  uint8_t type = 0;
963  switch (reg) {
964  case LEVEL_BASE::REG_RAX:
965  regGroup = ALIAS_REG_A;
966  byteInd = ALIAS_BYTES_INDEX_64;
967  type = ALIAS_GENERIC;
968  break;
969  case REG_EAX:
970  regGroup = ALIAS_REG_A;
971  byteInd = ALIAS_BYTES_INDEX_32;
972  type = ALIAS_GENERIC;
973  break;
974  case REG_AX:
975  regGroup = ALIAS_REG_A;
976  byteInd = ALIAS_BYTES_INDEX_16;
977  type = ALIAS_GENERIC;
978  break;
979  case REG_AH:
980  regGroup = ALIAS_REG_A;
981  byteInd = ALIAS_BYTES_INDEX_8_H;
982  type = ALIAS_HIGH_BYTE;
983  break;
984  case REG_AL:
985  regGroup = ALIAS_REG_A;
986  byteInd = ALIAS_BYTES_INDEX_8_L;
987  type = ALIAS_LOW_BYTE;
988  break;
989 
990  case LEVEL_BASE::REG_RBX:
991  regGroup = ALIAS_REG_B;
992  byteInd = ALIAS_BYTES_INDEX_64;
993  type = ALIAS_GENERIC;
994  break;
995  case REG_EBX:
996  regGroup = ALIAS_REG_B;
997  byteInd = ALIAS_BYTES_INDEX_32;
998  type = ALIAS_GENERIC;
999  break;
1000  case REG_BX:
1001  regGroup = ALIAS_REG_B;
1002  byteInd = ALIAS_BYTES_INDEX_16;
1003  type = ALIAS_GENERIC;
1004  break;
1005  case REG_BH:
1006  regGroup = ALIAS_REG_B;
1007  byteInd = ALIAS_BYTES_INDEX_8_H;
1008  type = ALIAS_HIGH_BYTE;
1009  break;
1010  case REG_BL:
1011  regGroup = ALIAS_REG_B;
1012  byteInd = ALIAS_BYTES_INDEX_8_L;
1013  type = ALIAS_LOW_BYTE;
1014  break;
1015 
1016  case LEVEL_BASE::REG_RCX:
1017  regGroup = ALIAS_REG_C;
1018  byteInd = ALIAS_BYTES_INDEX_64;
1019  type = ALIAS_GENERIC;
1020  break;
1021  case REG_ECX:
1022  regGroup = ALIAS_REG_C;
1023  byteInd = ALIAS_BYTES_INDEX_32;
1024  type = ALIAS_GENERIC;
1025  break;
1026  case REG_CX:
1027  regGroup = ALIAS_REG_C;
1028  byteInd = ALIAS_BYTES_INDEX_16;
1029  type = ALIAS_GENERIC;
1030  break;
1031  case REG_CH:
1032  regGroup = ALIAS_REG_C;
1033  byteInd = ALIAS_BYTES_INDEX_8_H;
1034  type = ALIAS_HIGH_BYTE;
1035  break;
1036  case REG_CL:
1037  regGroup = ALIAS_REG_C;
1038  byteInd = ALIAS_BYTES_INDEX_8_L;
1039  type = ALIAS_LOW_BYTE;
1040  break;
1041 
1042  case LEVEL_BASE::REG_RDX:
1043  regGroup = ALIAS_REG_D;
1044  byteInd = ALIAS_BYTES_INDEX_64;
1045  type = ALIAS_GENERIC;
1046  break;
1047  case REG_EDX:
1048  regGroup = ALIAS_REG_D;
1049  byteInd = ALIAS_BYTES_INDEX_32;
1050  type = ALIAS_GENERIC;
1051  break;
1052  case REG_DX:
1053  regGroup = ALIAS_REG_D;
1054  byteInd = ALIAS_BYTES_INDEX_16;
1055  type = ALIAS_GENERIC;
1056  break;
1057  case REG_DH:
1058  regGroup = ALIAS_REG_D;
1059  byteInd = ALIAS_BYTES_INDEX_8_H;
1060  type = ALIAS_HIGH_BYTE;
1061  break;
1062  case REG_DL:
1063  regGroup = ALIAS_REG_D;
1064  byteInd = ALIAS_BYTES_INDEX_8_L;
1065  type = ALIAS_LOW_BYTE;
1066  break;
1067 
1068  case LEVEL_BASE::REG_RBP:
1069  regGroup = ALIAS_REG_BP;
1070  byteInd = ALIAS_BYTES_INDEX_64;
1071  type = ALIAS_GENERIC;
1072  break;
1073  case REG_EBP:
1074  regGroup = ALIAS_REG_BP;
1075  byteInd = ALIAS_BYTES_INDEX_32;
1076  type = ALIAS_GENERIC;
1077  break;
1078  case REG_BP:
1079  regGroup = ALIAS_REG_BP;
1080  byteInd = ALIAS_BYTES_INDEX_16;
1081  type = ALIAS_GENERIC;
1082  break;
1083  case REG_BPL:
1084  regGroup = ALIAS_REG_BP;
1085  byteInd = ALIAS_BYTES_INDEX_8_L;
1086  type = ALIAS_GENERIC;
1087  break;
1088 
1089  case LEVEL_BASE::REG_RDI:
1090  regGroup = ALIAS_REG_DI;
1091  byteInd = ALIAS_BYTES_INDEX_64;
1092  type = ALIAS_GENERIC;
1093  break;
1094  case REG_EDI:
1095  regGroup = ALIAS_REG_DI;
1096  byteInd = ALIAS_BYTES_INDEX_32;
1097  type = ALIAS_GENERIC;
1098  break;
1099  case REG_DI:
1100  regGroup = ALIAS_REG_DI;
1101  byteInd = ALIAS_BYTES_INDEX_16;
1102  type = ALIAS_GENERIC;
1103  break;
1104  case REG_DIL:
1105  regGroup = ALIAS_REG_DI;
1106  byteInd = ALIAS_BYTES_INDEX_8_L;
1107  type = ALIAS_GENERIC;
1108  break;
1109 
1110  case LEVEL_BASE::REG_RSI:
1111  regGroup = ALIAS_REG_SI;
1112  byteInd = ALIAS_BYTES_INDEX_64;
1113  type = ALIAS_GENERIC;
1114  break;
1115  case REG_ESI:
1116  regGroup = ALIAS_REG_SI;
1117  byteInd = ALIAS_BYTES_INDEX_32;
1118  type = ALIAS_GENERIC;
1119  break;
1120  case REG_SI:
1121  regGroup = ALIAS_REG_SI;
1122  byteInd = ALIAS_BYTES_INDEX_16;
1123  type = ALIAS_GENERIC;
1124  break;
1125  case REG_SIL:
1126  regGroup = ALIAS_REG_SI;
1127  byteInd = ALIAS_BYTES_INDEX_8_L;
1128  type = ALIAS_GENERIC;
1129  break;
1130 
1131  case LEVEL_BASE::REG_RSP:
1132  regGroup = ALIAS_REG_SP;
1133  byteInd = ALIAS_BYTES_INDEX_64;
1134  type = ALIAS_GENERIC;
1135  break;
1136  case REG_ESP:
1137  regGroup = ALIAS_REG_SP;
1138  byteInd = ALIAS_BYTES_INDEX_32;
1139  type = ALIAS_GENERIC;
1140  break;
1141  case REG_SP:
1142  regGroup = ALIAS_REG_SP;
1143  byteInd = ALIAS_BYTES_INDEX_16;
1144  type = ALIAS_GENERIC;
1145  break;
1146  case REG_SPL:
1147  regGroup = ALIAS_REG_SP;
1148  byteInd = ALIAS_BYTES_INDEX_8_L;
1149  type = ALIAS_GENERIC;
1150  break;
1151 
1152  case LEVEL_BASE::REG_R8:
1153  regGroup = ALIAS_REG_R8;
1154  byteInd = ALIAS_BYTES_INDEX_64;
1155  type = ALIAS_GENERIC;
1156  break;
1157  case REG_R8D:
1158  regGroup = ALIAS_REG_R8;
1159  byteInd = ALIAS_BYTES_INDEX_32;
1160  type = ALIAS_GENERIC;
1161  break;
1162  case REG_R8W:
1163  regGroup = ALIAS_REG_R8;
1164  byteInd = ALIAS_BYTES_INDEX_16;
1165  type = ALIAS_GENERIC;
1166  break;
1167  case REG_R8B:
1168  regGroup = ALIAS_REG_R8;
1169  byteInd = ALIAS_BYTES_INDEX_8_L;
1170  type = ALIAS_GENERIC;
1171  break;
1172 
1173  case LEVEL_BASE::REG_R9:
1174  regGroup = ALIAS_REG_R9;
1175  byteInd = ALIAS_BYTES_INDEX_64;
1176  type = ALIAS_GENERIC;
1177  break;
1178  case REG_R9D:
1179  regGroup = ALIAS_REG_R9;
1180  byteInd = ALIAS_BYTES_INDEX_32;
1181  type = ALIAS_GENERIC;
1182  break;
1183  case REG_R9W:
1184  regGroup = ALIAS_REG_R9;
1185  byteInd = ALIAS_BYTES_INDEX_16;
1186  type = ALIAS_GENERIC;
1187  break;
1188  case REG_R9B:
1189  regGroup = ALIAS_REG_R9;
1190  byteInd = ALIAS_BYTES_INDEX_8_L;
1191  type = ALIAS_GENERIC;
1192  break;
1193 
1194  case LEVEL_BASE::REG_R10:
1195  regGroup = ALIAS_REG_R10;
1196  byteInd = ALIAS_BYTES_INDEX_64;
1197  type = ALIAS_GENERIC;
1198  break;
1199  case REG_R10D:
1200  regGroup = ALIAS_REG_R10;
1201  byteInd = ALIAS_BYTES_INDEX_32;
1202  type = ALIAS_GENERIC;
1203  break;
1204  case REG_R10W:
1205  regGroup = ALIAS_REG_R10;
1206  byteInd = ALIAS_BYTES_INDEX_16;
1207  type = ALIAS_GENERIC;
1208  break;
1209  case REG_R10B:
1210  regGroup = ALIAS_REG_R10;
1211  byteInd = ALIAS_BYTES_INDEX_8_L;
1212  type = ALIAS_GENERIC;
1213  break;
1214 
1215  case LEVEL_BASE::REG_R11:
1216  regGroup = ALIAS_REG_R11;
1217  byteInd = ALIAS_BYTES_INDEX_64;
1218  type = ALIAS_GENERIC;
1219  break;
1220  case REG_R11D:
1221  regGroup = ALIAS_REG_R11;
1222  byteInd = ALIAS_BYTES_INDEX_32;
1223  type = ALIAS_GENERIC;
1224  break;
1225  case REG_R11W:
1226  regGroup = ALIAS_REG_R11;
1227  byteInd = ALIAS_BYTES_INDEX_16;
1228  type = ALIAS_GENERIC;
1229  break;
1230  case REG_R11B:
1231  regGroup = ALIAS_REG_R11;
1232  byteInd = ALIAS_BYTES_INDEX_8_L;
1233  type = ALIAS_GENERIC;
1234  break;
1235 
1236  case LEVEL_BASE::REG_R12:
1237  regGroup = ALIAS_REG_R12;
1238  byteInd = ALIAS_BYTES_INDEX_64;
1239  type = ALIAS_GENERIC;
1240  break;
1241  case REG_R12D:
1242  regGroup = ALIAS_REG_R12;
1243  byteInd = ALIAS_BYTES_INDEX_32;
1244  type = ALIAS_GENERIC;
1245  break;
1246  case REG_R12W:
1247  regGroup = ALIAS_REG_R12;
1248  byteInd = ALIAS_BYTES_INDEX_16;
1249  type = ALIAS_GENERIC;
1250  break;
1251  case REG_R12B:
1252  regGroup = ALIAS_REG_R12;
1253  byteInd = ALIAS_BYTES_INDEX_8_L;
1254  type = ALIAS_GENERIC;
1255  break;
1256 
1257  case LEVEL_BASE::REG_R13:
1258  regGroup = ALIAS_REG_R13;
1259  byteInd = ALIAS_BYTES_INDEX_64;
1260  type = ALIAS_GENERIC;
1261  break;
1262  case REG_R13D:
1263  regGroup = ALIAS_REG_R13;
1264  byteInd = ALIAS_BYTES_INDEX_32;
1265  type = ALIAS_GENERIC;
1266  break;
1267  case REG_R13W:
1268  regGroup = ALIAS_REG_R13;
1269  byteInd = ALIAS_BYTES_INDEX_16;
1270  type = ALIAS_GENERIC;
1271  break;
1272  case REG_R13B:
1273  regGroup = ALIAS_REG_R13;
1274  byteInd = ALIAS_BYTES_INDEX_8_L;
1275  type = ALIAS_GENERIC;
1276  break;
1277 
1278  case LEVEL_BASE::REG_R14:
1279  regGroup = ALIAS_REG_R14;
1280  byteInd = ALIAS_BYTES_INDEX_64;
1281  type = ALIAS_GENERIC;
1282  break;
1283  case REG_R14D:
1284  regGroup = ALIAS_REG_R14;
1285  byteInd = ALIAS_BYTES_INDEX_32;
1286  type = ALIAS_GENERIC;
1287  break;
1288  case REG_R14W:
1289  regGroup = ALIAS_REG_R14;
1290  byteInd = ALIAS_BYTES_INDEX_16;
1291  type = ALIAS_GENERIC;
1292  break;
1293  case REG_R14B:
1294  regGroup = ALIAS_REG_R14;
1295  byteInd = ALIAS_BYTES_INDEX_8_L;
1296  type = ALIAS_GENERIC;
1297  break;
1298 
1299  case LEVEL_BASE::REG_R15:
1300  regGroup = ALIAS_REG_R15;
1301  byteInd = ALIAS_BYTES_INDEX_64;
1302  type = ALIAS_GENERIC;
1303  break;
1304  case REG_R15D:
1305  regGroup = ALIAS_REG_R15;
1306  byteInd = ALIAS_BYTES_INDEX_32;
1307  type = ALIAS_GENERIC;
1308  break;
1309  case REG_R15W:
1310  regGroup = ALIAS_REG_R15;
1311  byteInd = ALIAS_BYTES_INDEX_16;
1312  type = ALIAS_GENERIC;
1313  break;
1314  case REG_R15B:
1315  regGroup = ALIAS_REG_R15;
1316  byteInd = ALIAS_BYTES_INDEX_8_L;
1317  type = ALIAS_GENERIC;
1318  break;
1319 
1320  default:
1321  assert(0 && "not alias registers! should not reach here!");
1322  break;
1323  }
1324  uint32_t aliasGroupByteType = ((uint32_t)regGroup << 16) | ((uint32_t)byteInd << 8) | ((uint32_t)type);
1325  return aliasGroupByteType;
1326 }
1327 
1328 inline bool RegHasAlias(REG reg) {
1329  switch (reg) {
1330  case LEVEL_BASE::REG_RAX:
1331  case LEVEL_BASE::REG_RBX:
1332  case LEVEL_BASE::REG_RCX:
1333  case LEVEL_BASE::REG_RDX:
1334  case REG_EAX:
1335  case REG_EBX:
1336  case REG_ECX:
1337  case REG_EDX:
1338  case REG_AX:
1339  case REG_BX:
1340  case REG_CX:
1341  case REG_DX:
1342  case REG_AH:
1343  case REG_BH:
1344  case REG_CH:
1345  case REG_DH:
1346  case REG_AL:
1347  case REG_BL:
1348  case REG_CL:
1349  case REG_DL:
1350  case LEVEL_BASE::REG_RBP:
1351  case REG_EBP:
1352  case REG_BP:
1353  case REG_BPL:
1354  case LEVEL_BASE::REG_RDI:
1355  case REG_EDI:
1356  case REG_DI:
1357  case REG_DIL:
1358  case LEVEL_BASE::REG_RSI:
1359  case REG_ESI:
1360  case REG_SI:
1361  case REG_SIL:
1362  case LEVEL_BASE::REG_RSP:
1363  case REG_ESP:
1364  case REG_SP:
1365  case REG_SPL:
1366  case LEVEL_BASE::REG_R8:
1367  case REG_R8D:
1368  case REG_R8W:
1369  case REG_R8B:
1370  case LEVEL_BASE::REG_R9:
1371  case REG_R9D:
1372  case REG_R9W:
1373  case REG_R9B:
1374  case LEVEL_BASE::REG_R10:
1375  case REG_R10D:
1376  case REG_R10W:
1377  case REG_R10B:
1378  case LEVEL_BASE::REG_R11:
1379  case REG_R11D:
1380  case REG_R11W:
1381  case REG_R11B:
1382  case LEVEL_BASE::REG_R12:
1383  case REG_R12D:
1384  case REG_R12W:
1385  case REG_R12B:
1386  case LEVEL_BASE::REG_R13:
1387  case REG_R13D:
1388  case REG_R13W:
1389  case REG_R13B:
1390  case LEVEL_BASE::REG_R14:
1391  case REG_R14D:
1392  case REG_R14W:
1393  case REG_R14B:
1394  case LEVEL_BASE::REG_R15:
1395  case REG_R15D:
1396  case REG_R15W:
1397  case REG_R15B:
1398  return true;
1399  default:
1400  return false;
1401  }
1402 }
1403 
1404 #ifdef ENABLE_SAMPLING
1405 
1406 #define HANDLE_SPECIALREG(LEN, REG_ID) \
1407  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1408  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)HandleSpecialRegisters<LEN>::CheckRegValues, IARG_REG_CONST_REFERENCE, reg, IARG_UINT32, REG_ID, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1409 
1410 #define HANDLE_LARGEREG_APPROX(T, SIMD_TYPE, REG_ID) \
1411  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1412  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)ApproxLargeRegisters<T, SIMD_TYPE>::CheckValues, IARG_REG_CONST_REFERENCE, reg, IARG_UINT32, REG_ID, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1413 
1414 #define HANDLE_ALIAS_REG(T, ALIAS_GRP, ID) \
1415  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1416  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)HandleAliasRegisters<T, ALIAS_GRP>::CheckUpdateGenericAlias, IARG_UINT32, ID, IARG_REG_VALUE, reg, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1417 
1418 #define HANDLE_GENERAL(T) \
1419  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1420  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)HandleGeneralRegisters<T, 1>::CheckValues, IARG_REG_VALUE, reg, IARG_UINT32, reg, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1421 
1422 #define HANDLE_APPROXREG(T, IS_ALIAS, REG_ID) \
1423  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1424  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)ApproxGeneralRegisters<T, IS_ALIAS>::CheckValues, IARG_REG_CONST_REFERENCE, reg, IARG_UINT32, REG_ID, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1425 
1426 #define HANDLE_10BYTES_APPROX(REG_ID) \
1427  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1428  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)Check10BytesReg, IARG_CONTEXT, IARG_UINT32, REG_ID, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1429 
1430 #else
1431 
1432 #define HANDLE_SPECIALREG(LEN, REG_ID) \
1433  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)HandleSpecialRegisters<LEN>::CheckRegValues, IARG_REG_CONST_REFERENCE, reg, IARG_UINT32, REG_ID, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1434 
1435 #define HANDLE_LARGEREG_APPROX(T, SIMD_TYPE, REG_ID) \
1436  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)ApproxLargeRegisters<T, SIMD_TYPE>::CheckValues, IARG_REG_CONST_REFERENCE, reg, IARG_UINT32, REG_ID, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1437 
1438 #define HANDLE_ALIAS_REG(T, ALIAS_GRP, ID) \
1439  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)HandleAliasRegisters<T, ALIAS_GRP>::CheckUpdateGenericAlias, IARG_UINT32, ID, IARG_REG_VALUE, reg, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1440 
1441 #define HANDLE_GENERAL(T) \
1442  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)HandleGeneralRegisters<T, 1>::CheckValues, IARG_REG_VALUE, reg, IARG_UINT32, reg, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1443 
1444 #define HANDLE_APPROXREG(T, IS_ALIAS, REG_ID) \
1445  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)ApproxGeneralRegisters<T, IS_ALIAS>::CheckValues, IARG_REG_CONST_REFERENCE, reg, IARG_UINT32, REG_ID, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1446 
1447 #define HANDLE_10BYTES_APPROX(REG_ID) \
1448  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)Check10BytesReg, IARG_CONTEXT, IARG_UINT32, REG_ID, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1449 
1450 #endif
1451 
1452 static inline void InstrumentAliasReg(INS ins, REG reg, uint16_t oper, uint32_t opaqueHandle) {
1453  // All registers that reach this function are GR sub-registers
1454  // (AL/AH/AX/EAX/RAX, ..., R15B/R15W/R15D/R15) hardcoded in RegHasAlias().
1455  // Every one of them is <=8 bytes and valid for IARG_REG_VALUE, so no
1456  // REG_valid_for_iarg_reg_value guard is needed here. K-mask, PIN-internal
1457  // and other IARG_REG_VALUE-incompatible registers can only reach the
1458  // sibling InstrumentGeneralReg(), which does the real filtering.
1459  uint32_t regSize = REG_Size(reg);
1460  uint32_t aliasIDs = GetAliasIDs(reg);
1461  uint8_t regId = static_cast<uint8_t>(((aliasIDs)&0x00ffffff) >> 16);
1462 
1463  if (IsFloatInstruction(INS_Address(ins))) {
1464  switch (regSize) {
1465  case 1:
1466  case 2:
1467  case 4:
1468  HANDLE_APPROXREG(float, true, regId);
1469  break;
1470  case 8:
1471  HANDLE_APPROXREG(double, true, regId);
1472  break;
1473  default:
1474  break;
1475  }
1476  } else {
1477  switch (regSize) {
1478  case 8:
1479  HANDLE_ALIAS_REG(uint64_t, ALIAS_GENERIC, regId);
1480  break;
1481  case 4:
1482  HANDLE_ALIAS_REG(uint32_t, ALIAS_GENERIC, regId);
1483  break;
1484  case 2:
1485  HANDLE_ALIAS_REG(uint16_t, ALIAS_GENERIC, regId);
1486  break;
1487  case 1:
1488  if (REG_is_Lower8(reg)) {
1489  HANDLE_ALIAS_REG(uint8_t, ALIAS_LOW_BYTE, regId);
1490  } else {
1491  HANDLE_ALIAS_REG(uint8_t, ALIAS_HIGH_BYTE, regId);
1492  }
1493  break;
1494  default:
1495  break;
1496  }
1497  }
1498 }
1499 
1500 static inline void InstrumentGeneralReg(INS ins, REG reg, uint16_t oper, uint32_t opaqueHandle) {
1501  // HACK(port-blocker, missing-feature): Pin 4.x can surface register
1502  // classes that IARG_REG_VALUE cannot serve -- notably AVX-512 opmask
1503  // registers K0-K7 (Pin refuses IARG_REG_VALUE on them and aborts at
1504  // instrumentation time). These now show up unavoidably even on trivial
1505  // workloads because modern libc/ld.so uses kmov* in paths like
1506  // _dl_deallocate_tls; without this early-return the tool refuses to
1507  // load on /bin/echo. The early-return silently drops these register
1508  // writes from the temporal-redundancy analysis, so they are simply
1509  // not measured.
1510  //
1511  // Proper fix (deferred, MISSING FEATURE):
1512  // 1. Filter at the CALLER (InstrumentInsCallback's dispatch loop that
1513  // selects InstrumentAliasReg vs InstrumentGeneralReg) so this
1514  // function never receives an unsupported register.
1515  // 2. Add a dedicated K-mask analysis routine that uses
1516  // IARG_REG_CONST_REFERENCE and reads PINTOOL_REGISTER::qword[0]
1517  // (K regs are 64 bits) -- essentially routing K writes through
1518  // HandleSpecialRegisters<1>::CheckRegValues.
1519  // Both belong in a separate AVX-512 feature change, not this port.
1520  if (!REG_valid_for_iarg_reg_value(reg))
1521  return;
1522  uint32_t regSize = REG_Size(reg);
1523 
1524  if (IsFloatInstruction(INS_Address(ins))) {
1525  unsigned int operSize = FloatOperandSize(INS_Address(ins), oper);
1526  switch (regSize) {
1527  case 1:
1528  case 2:
1529  case 4:
1530  HANDLE_APPROXREG(float, false, reg);
1531  break;
1532  case 8:
1533  HANDLE_APPROXREG(double, false, reg);
1534  break;
1535  case 10:
1536  HANDLE_10BYTES_APPROX(reg);
1537  break;
1538  case 16: {
1539  switch (operSize) {
1540  case 4:
1541  HANDLE_LARGEREG_APPROX(float, 0, reg - REG_XMM_BASE);
1542  break;
1543  case 8:
1544  HANDLE_LARGEREG_APPROX(double, 0, reg - REG_XMM_BASE);
1545  break;
1546  default:
1547  assert(0 && "handle large reg with large operand size\n");
1548  break;
1549  }
1550  } break;
1551  case 32: {
1552  switch (operSize) {
1553  case 4:
1554  HANDLE_LARGEREG_APPROX(float, 1, reg - REG_YMM_BASE);
1555  break;
1556  case 8:
1557  HANDLE_LARGEREG_APPROX(double, 1, reg - REG_YMM_BASE);
1558  break;
1559  default:
1560  assert(0 && "handle large reg with large operand size\n");
1561  break;
1562  }
1563  } break;
1564  case 64: {
1565  switch (operSize) {
1566  case 4:
1567  HANDLE_LARGEREG_APPROX(float, 2, reg - REG_ZMM_BASE);
1568  break;
1569  case 8:
1570  HANDLE_LARGEREG_APPROX(double, 2, reg - REG_ZMM_BASE);
1571  break;
1572  default:
1573  assert(0 && "handle large reg with large operand size\n");
1574  break;
1575  }
1576  } break;
1577  default:
1578  assert(0 && "not recoganized register size for floating instruction!\n");
1579  }
1580  } else {
1581  if (REG_is_in_X87(reg)) {
1582  HANDLE_SPECIALREG(1, reg);
1583  return;
1584  }
1585  switch (regSize) {
1586  case 1:
1587  HANDLE_GENERAL(uint8_t);
1588  break;
1589  case 2:
1590  HANDLE_GENERAL(uint16_t);
1591  break;
1592  case 4:
1593  HANDLE_GENERAL(uint32_t);
1594  break;
1595  case 8:
1596  HANDLE_GENERAL(uint64_t);
1597  break;
1598  case 16:
1599  HANDLE_SPECIALREG(2, reg - REG_XMM_BASE);
1600  break;
1601  case 32:
1602  HANDLE_SPECIALREG(4, reg - REG_YMM_BASE);
1603  break;
1604  case 64:
1605  HANDLE_SPECIALREG(8, reg - REG_ZMM_BASE);
1606  break;
1607  default:
1608  assert(0 && "not recoganized register size for integer instruction!\n");
1609  break;
1610  }
1611  }
1612 }
1613 
1614 /***************************************************************************************/
1615 /*********************** memory temporal redundancy functions **************************/
1616 /***************************************************************************************/
1617 
1618 template <int start, int end, int incr, bool conditional, bool approx>
1619 struct UnrolledLoop {
1620  static __attribute__((always_inline)) void Body(const function<void(const int)>& func) {
1621  func(start); // Real loop body
1623  }
1624  static __attribute__((always_inline)) void BodySamePage(ContextHandle_t* __restrict__ prevIP, const ContextHandle_t handle, THREADID threadId) {
1625  if (conditional) {
1626  // report in RedTable
1627  if (approx)
1628  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(prevIP[start], handle), 1, threadId);
1629  else
1630  AddToRedTable(MAKE_CONTEXT_PAIR(prevIP[start], handle), 1, threadId);
1631  }
1632  // Update context
1633  prevIP[start] = handle;
1634  UnrolledLoop<start + incr, end, incr, conditional, approx>::BodySamePage(prevIP, handle, threadId); // unroll next iteration
1635  }
1636  static __attribute__((always_inline)) void BodyStraddlePage(uint64_t addr, const ContextHandle_t handle, THREADID threadId) {
1637  uint8_t* status = (uint8_t*)get<0>(sm.GetOrCreateShadowBaseAddress((uint64_t)addr + start));
1638  ContextHandle_t* prevIP = (ContextHandle_t*)(status + PAGE_OFFSET(((uint64_t)addr + start)) * sizeof(ContextHandle_t));
1639  if (conditional) {
1640  // report in RedTable
1641  if (approx)
1642  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(prevIP[0 /* 0 is correct*/], handle), 1, threadId);
1643  else
1644  AddToRedTable(MAKE_CONTEXT_PAIR(prevIP[0 /* 0 is correct*/], handle), 1, threadId);
1645  }
1646  // Update context
1647  prevIP[0] = handle;
1649  }
1650 };
1651 
1652 template <int end, int incr, bool conditional, bool approx>
1653 struct UnrolledLoop<end, end, incr, conditional, approx> {
1654  static __attribute__((always_inline)) void Body(const function<void(const int)>& func) {}
1655  static __attribute__((always_inline)) void BodySamePage(ContextHandle_t* __restrict__ prevIP, const ContextHandle_t handle, THREADID threadId) {}
1656  static __attribute__((always_inline)) void BodyStraddlePage(uint64_t addr, const ContextHandle_t handle, THREADID threadId) {}
1657 };
1658 
1659 template <int start, int end, int incr>
1660 struct UnrolledConjunction {
1661  static __attribute__((always_inline)) bool Body(const function<bool(const int)>& func) {
1662  return func(start) && UnrolledConjunction<start + incr, end, incr>::Body(func); // unroll next iteration
1663  }
1664  static __attribute__((always_inline)) bool BodyContextCheck(ContextHandle_t* __restrict__ prevIP) {
1665  return (prevIP[0] == prevIP[start]) && UnrolledConjunction<start + incr, end, incr>::BodyContextCheck(prevIP); // unroll next iteration
1666  }
1667 };
1668 
1669 template <int end, int incr>
1670 struct UnrolledConjunction<end, end, incr> {
1671  static __attribute__((always_inline)) bool Body(const function<void(const int)>& func) {
1672  return true;
1673  }
1674  static __attribute__((always_inline)) bool BodyContextCheck(ContextHandle_t* __restrict__ prevIP) {
1675  return true;
1676  }
1677 };
1678 
1679 
1680 template <class T, uint32_t AccessLen, uint32_t bufferOffset, bool isApprox>
1681 struct RedSpyAnalysis {
1682  static __attribute__((always_inline)) bool IsWriteRedundant(void*& addr, THREADID threadId) {
1683  RedSpyThreadData* const tData = ClientGetTLS(threadId);
1684  AddrValPair* avPair = &tData->buffer[bufferOffset];
1685  addr = avPair->address;
1686 
1687  if (isApprox) {
1688  if (AccessLen >= 32) {
1689  if (sizeof(T) == 4) {
1690  __m256 oldValue = _mm256_load_ps(reinterpret_cast<const float*>(&avPair->value));
1691  __m256 newValue = _mm256_loadu_ps(reinterpret_cast<const float*>(avPair->address));
1692 
1693  __m256 result = _mm256_sub_ps(newValue, oldValue);
1694 
1695  result = _mm256_div_ps(result, oldValue);
1696  float rates[8] __attribute__((aligned(32)));
1697  _mm256_store_ps(rates, result);
1698 
1699  for (int i = 0; i < 8; ++i) {
1700  if (rates[i] < -delta || rates[i] > delta) {
1701  return false;
1702  }
1703  }
1704  return true;
1705 
1706  } else if (sizeof(T) == 8) {
1707  __m256d oldValue = _mm256_load_pd(reinterpret_cast<const double*>(&avPair->value));
1708  __m256d newValue = _mm256_loadu_pd(reinterpret_cast<const double*>(avPair->address));
1709 
1710  __m256d result = _mm256_sub_pd(newValue, oldValue);
1711 
1712  result = _mm256_div_pd(result, oldValue);
1713 
1714  double rates[4] __attribute__((aligned(32)));
1715  _mm256_store_pd(rates, result);
1716 
1717  for (int i = 0; i < 4; ++i) {
1718  if (rates[i] < -delta || rates[i] > delta) {
1719  return false;
1720  }
1721  }
1722  return true;
1723  }
1724  } else if (AccessLen == 16) {
1725  if (sizeof(T) == 4) {
1726  __m128 oldValue = _mm_load_ps(reinterpret_cast<const float*>(&avPair->value));
1727  __m128 newValue = _mm_loadu_ps(reinterpret_cast<const float*>(avPair->address));
1728 
1729  __m128 result = _mm_sub_ps(newValue, oldValue);
1730 
1731  result = _mm_div_ps(result, oldValue);
1732  float rates[4] __attribute__((aligned(16)));
1733  _mm_store_ps(rates, result);
1734 
1735  for (int i = 0; i < 4; ++i) {
1736  if (rates[i] < -delta || rates[i] > delta) {
1737  return false;
1738  }
1739  }
1740  return true;
1741 
1742  } else if (sizeof(T) == 8) {
1743  __m128d oldValue = _mm_load_pd(reinterpret_cast<const double*>(&avPair->value));
1744  __m128d newValue = _mm_loadu_pd(reinterpret_cast<const double*>(avPair->address));
1745 
1746  __m128d result = _mm_sub_pd(newValue, oldValue);
1747 
1748  result = _mm_div_pd(result, oldValue);
1749 
1750  double rate[2];
1751  _mm_storel_pd(&rate[0], result);
1752  _mm_storeh_pd(&rate[1], result);
1753 
1754  if (rate[0] < -delta || rate[0] > delta)
1755  return false;
1756  if (rate[1] < -delta || rate[1] > delta)
1757  return false;
1758  return true;
1759  }
1760  } else if (AccessLen == 10) {
1761  UINT8 newValue[10];
1762  memcpy(newValue, addr, AccessLen);
1763 
1764  uint64_t* upperOld = (uint64_t*)&(avPair->value[2]);
1765  uint64_t* upperNew = (uint64_t*)&(newValue[2]);
1766 
1767  uint16_t* lowOld = (uint16_t*)&(avPair->value[0]);
1768  uint16_t* lowNew = (uint16_t*)&(newValue[0]);
1769 
1770  return (*lowOld & 0xfff0) == (*lowNew & 0xfff0) && *upperNew == *upperOld;
1771  } else {
1772  T newValue = *(static_cast<T*>(avPair->address));
1773  T oldValue = *((T*)(&avPair->value));
1774 
1775  T rate = (newValue - oldValue) / oldValue;
1776  return static_cast<bool>(rate <= delta && rate >= -delta);
1777  }
1778  } else {
1779  return *((T*)(&avPair->value)) == *(static_cast<T*>(avPair->address));
1780  }
1781  return false;
1782  }
1783 
1784  static __attribute__((always_inline)) VOID RecordNByteValueBeforeWrite(void* addr, THREADID threadId) {
1785  RedSpyThreadData* const tData = ClientGetTLS(threadId);
1786 
1787  AddrValPair* avPair = &tData->buffer[bufferOffset];
1788 
1789  avPair->address = addr;
1790  if (AccessLen >= 32) {
1791  if (sizeof(T) == 4) {
1792  __m256 newValue = _mm256_loadu_ps(reinterpret_cast<const float*>(addr));
1793  _mm256_store_ps(reinterpret_cast<float*>(&avPair->value), newValue);
1794 
1795  } else if (sizeof(T) == 8) {
1796  __m256d newValue = _mm256_loadu_pd(reinterpret_cast<const double*>(addr));
1797  _mm256_store_pd(reinterpret_cast<double*>(&avPair->value), newValue);
1798  }
1799  } else if (AccessLen == 16) {
1800  if (sizeof(T) == 4) {
1801  __m128 newValue = _mm_loadu_ps(reinterpret_cast<const float*>(addr));
1802  _mm_store_ps(reinterpret_cast<float*>(&avPair->value), newValue);
1803 
1804  } else if (sizeof(T) == 8) {
1805  __m128d newValue = _mm_loadu_pd(reinterpret_cast<const double*>(addr));
1806  _mm_store_pd(reinterpret_cast<double*>(&avPair->value), newValue);
1807  }
1808  } else if (AccessLen == 10) {
1809  memcpy(&avPair->value, addr, AccessLen);
1810  } else
1811  *((T*)(&avPair->value)) = *(static_cast<T*>(addr));
1812  }
1813 
1814  static __attribute__((always_inline)) VOID CheckNByteValueAfterWrite(uint32_t opaqueHandle, THREADID threadId) {
1815  RedSpyThreadData* const tData = ClientGetTLS(threadId);
1816  void* addr;
1817  bool isRedundantWrite = IsWriteRedundant(addr, threadId);
1818 
1819  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
1820 
1821  uint8_t* status = (uint8_t*)get<0>(sm.GetOrCreateShadowBaseAddress((uint64_t)addr));
1822  ContextHandle_t* __restrict__ prevIP = (ContextHandle_t*)(status + PAGE_OFFSET((uint64_t)addr) * sizeof(ContextHandle_t));
1823  const bool isAccessWithinPageBoundary = IS_ACCESS_WITHIN_PAGE_BOUNDARY((uint64_t)addr, AccessLen);
1824  if (isRedundantWrite) {
1825  // detected redundancy
1826  if (isAccessWithinPageBoundary) {
1827  // All from same ctxt?
1829  // report in RedTable
1830  if (isApprox)
1831  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(prevIP[0], curCtxtHandle), AccessLen, threadId);
1832  else
1833  AddToRedTable(MAKE_CONTEXT_PAIR(prevIP[0], curCtxtHandle), AccessLen, threadId);
1834  // Update context
1835  UnrolledLoop<0, AccessLen, 1, false, /* redundancy is updated outside*/ isApprox>::BodySamePage(prevIP, curCtxtHandle, threadId);
1836  } else {
1837  // different contexts
1838  UnrolledLoop<0, AccessLen, 1, true, /* redundancy is updated inside*/ isApprox>::BodySamePage(prevIP, curCtxtHandle, threadId);
1839  }
1840  } else {
1841  // Write across a 64-K page boundary
1842  // First byte is on this page though
1843  if (isApprox)
1844  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(prevIP[0], curCtxtHandle), 1, threadId);
1845  else
1846  AddToRedTable(MAKE_CONTEXT_PAIR(prevIP[0], curCtxtHandle), 1, threadId);
1847  // Update context
1848  prevIP[0] = curCtxtHandle;
1849 
1850  // Remaining bytes [1..AccessLen] somewhere will across a 64-K page boundary
1851  UnrolledLoop<1, AccessLen, 1, true, /* update redundancy */ isApprox>::BodyStraddlePage((uint64_t)addr, curCtxtHandle, threadId);
1852  }
1853  } else {
1854  // No redundancy.
1855  // Just update contexts
1856  if (isAccessWithinPageBoundary) {
1857  // Update context
1858  UnrolledLoop<0, AccessLen, 1, false, /* not redundant*/ isApprox>::BodySamePage(prevIP, curCtxtHandle, threadId);
1859  } else {
1860  // Write across a 64-K page boundary
1861  // Update context
1862  prevIP[0] = curCtxtHandle;
1863 
1864  // Remaining bytes [1..AccessLen] somewhere will across a 64-K page boundary
1865  UnrolledLoop<1, AccessLen, 1, false, /* not redundant*/ isApprox>::BodyStraddlePage((uint64_t)addr, curCtxtHandle, threadId);
1866  }
1867  }
1868  }
1869  static __attribute__((always_inline)) VOID ApproxCheckAfterWrite(uint32_t opaqueHandle, THREADID threadId) {
1870  RedSpyThreadData* const tData = ClientGetTLS(threadId);
1871  void* addr;
1872  bool isRedundantWrite = IsWriteRedundant(addr, threadId);
1873 
1874  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
1875 
1876  UINT32 const interv = sizeof(T);
1877  uint8_t* status = (uint8_t*)get<0>(sm.GetOrCreateShadowBaseAddress((uint64_t)addr));
1878  ContextHandle_t* __restrict__ prevIP = (ContextHandle_t*)(status + PAGE_OFFSET((uint64_t)addr) * sizeof(ContextHandle_t));
1879 
1880  if (isRedundantWrite) {
1881  for (UINT32 index = 0; index < AccessLen; index += interv) {
1882  status = (uint8_t*)get<0>(sm.GetOrCreateShadowBaseAddress((uint64_t)addr + index));
1883  prevIP = (ContextHandle_t*)(status + PAGE_OFFSET(((uint64_t)addr + index)) * sizeof(ContextHandle_t));
1884  // report in RedTable
1885  AddToApproximateRedTable(MAKE_CONTEXT_PAIR(prevIP[0 /* 0 is correct*/], curCtxtHandle), interv, threadId);
1886  // Update context
1887  prevIP[0] = curCtxtHandle;
1888  }
1889  } else {
1890  for (UINT32 index = 0; index < AccessLen; index += interv) {
1891  status = (uint8_t*)get<0>(sm.GetOrCreateShadowBaseAddress((uint64_t)addr + index));
1892  prevIP = (ContextHandle_t*)(status + PAGE_OFFSET(((uint64_t)addr + index)) * sizeof(ContextHandle_t));
1893  // Update context
1894  prevIP[0] = curCtxtHandle;
1895  }
1896  }
1897  }
1898 };
1899 
1900 
1901 static inline VOID RecordValueBeforeLargeWrite(void* addr, UINT32 accessLen, uint32_t bufferOffset, THREADID threadId) {
1902  RedSpyThreadData* const tData = ClientGetTLS(threadId);
1903  memcpy(&(tData->buffer[bufferOffset].value), addr, accessLen);
1904  tData->buffer[bufferOffset].address = addr;
1905 }
1906 
1907 static inline VOID CheckAfterLargeWrite(UINT32 accessLen, uint32_t bufferOffset, uint32_t opaqueHandle, THREADID threadId) {
1908  RedSpyThreadData* const tData = ClientGetTLS(threadId);
1909  void* addr = tData->buffer[bufferOffset].address;
1910  ContextHandle_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
1911 
1912  uint8_t* status;
1913  ContextHandle_t* __restrict__ prevIP;
1914  if (memcmp(&(tData->buffer[bufferOffset].value), addr, accessLen) == 0) {
1915  // redundant
1916  for (UINT32 index = 0; index < accessLen; index++) {
1917  status = (uint8_t*)get<0>(sm.GetOrCreateShadowBaseAddress((uint64_t)addr + index));
1918  prevIP = (ContextHandle_t*)(status + PAGE_OFFSET(((uint64_t)addr + index)) * sizeof(ContextHandle_t));
1919  // report in RedTable
1920  AddToRedTable(MAKE_CONTEXT_PAIR(prevIP[0 /* 0 is correct*/], curCtxtHandle), 1, threadId);
1921  // Update context
1922  prevIP[0] = curCtxtHandle;
1923  }
1924  } else {
1925  // Not redundant
1926  for (UINT32 index = 0; index < accessLen; index++) {
1927  status = (uint8_t*)get<0>(sm.GetOrCreateShadowBaseAddress((uint64_t)addr + index));
1928  prevIP = (ContextHandle_t*)(status + PAGE_OFFSET(((uint64_t)addr + index)) * sizeof(ContextHandle_t));
1929  // Update context
1930  prevIP[0] = curCtxtHandle;
1931  }
1932  }
1933 }
1934 
1935 #ifdef ENABLE_SAMPLING
1936 
1937 #define HANDLE_CASE(T, ACCESS_LEN, BUFFER_INDEX, IS_APPROX) \
1938  INS_InsertIfPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1939  INS_InsertThenPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RedSpyAnalysis<T, (ACCESS_LEN), (BUFFER_INDEX), (IS_APPROX)>::RecordNByteValueBeforeWrite, IARG_MEMORYOP_EA, memOp, IARG_THREAD_ID, IARG_END); \
1940  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1941  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)RedSpyAnalysis<T, (ACCESS_LEN), (BUFFER_INDEX), (IS_APPROX)>::CheckNByteValueAfterWrite, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_INST_PTR, IARG_END)
1942 
1943 #define HANDLE_APPROX_CASE(T, ACCESS_LEN, BUFFER_INDEX, IS_APPROX) \
1944  INS_InsertIfPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1945  INS_InsertThenPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RedSpyAnalysis<T, (ACCESS_LEN), (BUFFER_INDEX), (IS_APPROX)>::RecordNByteValueBeforeWrite, IARG_MEMORYOP_EA, memOp, IARG_THREAD_ID, IARG_END); \
1946  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1947  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)RedSpyAnalysis<T, (ACCESS_LEN), (BUFFER_INDEX), (IS_APPROX)>::ApproxCheckAfterWrite, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_INST_PTR, IARG_END)
1948 
1949 #define HANDLE_LARGE() \
1950  INS_InsertIfPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1951  INS_InsertThenPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordValueBeforeLargeWrite, IARG_MEMORYOP_EA, memOp, IARG_MEMORYWRITE_SIZE, IARG_UINT32, readBufferSlotIndex, IARG_THREAD_ID, IARG_END); \
1952  INS_InsertIfPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
1953  INS_InsertThenPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)CheckAfterLargeWrite, IARG_MEMORYREAD_SIZE, IARG_UINT32, readBufferSlotIndex, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1954 
1955 #else
1956 
1957 #define HANDLE_CASE(T, ACCESS_LEN, BUFFER_INDEX, IS_APPROX) \
1958  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RedSpyAnalysis<T, (ACCESS_LEN), (BUFFER_INDEX), (IS_APPROX)>::RecordNByteValueBeforeWrite, IARG_MEMORYOP_EA, memOp, IARG_THREAD_ID, IARG_END); \
1959  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)RedSpyAnalysis<T, (ACCESS_LEN), (BUFFER_INDEX), (IS_APPROX)>::CheckNByteValueAfterWrite, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_INST_PTR, IARG_END)
1960 
1961 #define HANDLE_APPROX_CASE(T, ACCESS_LEN, BUFFER_INDEX, IS_APPROX) \
1962  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RedSpyAnalysis<T, (ACCESS_LEN), (BUFFER_INDEX), (IS_APPROX)>::RecordNByteValueBeforeWrite, IARG_MEMORYOP_EA, memOp, IARG_THREAD_ID, IARG_END); \
1963  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)RedSpyAnalysis<T, (ACCESS_LEN), (BUFFER_INDEX), (IS_APPROX)>::ApproxCheckAfterWrite, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_INST_PTR, IARG_END)
1964 
1965 #define HANDLE_LARGE() \
1966  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordValueBeforeLargeWrite, IARG_MEMORYOP_EA, memOp, IARG_MEMORYWRITE_SIZE, IARG_UINT32, readBufferSlotIndex, IARG_THREAD_ID, IARG_END); \
1967  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)CheckAfterLargeWrite, IARG_MEMORYREAD_SIZE, IARG_UINT32, readBufferSlotIndex, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
1968 
1969 #endif
1970 
1971 
1972 static int GetNumWriteOperandsInIns(INS ins, UINT32& whichOp) {
1973  int numWriteOps = 0;
1974  UINT32 memOperands = INS_MemoryOperandCount(ins);
1975  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
1976  if (INS_MemoryOperandIsWritten(ins, memOp)) {
1977  numWriteOps++;
1978  whichOp = memOp;
1979  }
1980  }
1981  return numWriteOps;
1982 }
1983 
1984 template <uint32_t readBufferSlotIndex>
1985 struct RedSpyInstrument {
1986  static __attribute__((always_inline)) void InstrumentReadValueBeforeAndAfterWriting(INS ins, UINT32 memOp, uint32_t opaqueHandle) {
1987  UINT32 refSize = INS_MemoryOperandSize(ins, memOp);
1988 
1989  if (IsFloatInstruction(INS_Address(ins))) {
1990  unsigned int operSize = FloatOperandSize(INS_Address(ins), INS_MemoryOperandIndexToOperandIndex(ins, memOp));
1991  switch (refSize) {
1992  case 1:
1993  case 2:
1994  assert(0 && "memory write floating data with unexptected small size");
1995  case 4:
1996  HANDLE_APPROX_CASE(float, 4, readBufferSlotIndex, true);
1997  break;
1998  case 8:
1999  HANDLE_APPROX_CASE(double, 8, readBufferSlotIndex, true);
2000  break;
2001  case 10:
2002  HANDLE_APPROX_CASE(uint8_t, 10, readBufferSlotIndex, true);
2003  break;
2004  case 16: {
2005  switch (operSize) {
2006  case 4:
2007  HANDLE_APPROX_CASE(float, 16, readBufferSlotIndex, true);
2008  break;
2009  case 8:
2010  HANDLE_APPROX_CASE(double, 16, readBufferSlotIndex, true);
2011  break;
2012  default:
2013  assert(0 && "handle large mem write with unexpected operand size\n");
2014  break;
2015  }
2016  } break;
2017  case 32: {
2018  switch (operSize) {
2019  case 4:
2020  HANDLE_APPROX_CASE(float, 32, readBufferSlotIndex, true);
2021  break;
2022  case 8:
2023  HANDLE_APPROX_CASE(double, 32, readBufferSlotIndex, true);
2024  break;
2025  default:
2026  assert(0 && "handle large mem write with unexpected operand size\n");
2027  break;
2028  }
2029  } break;
2030  default:
2031  assert(0 && "unexpected large memory writes\n");
2032  break;
2033  }
2034  } else {
2035  switch (refSize) {
2036  case 1:
2037  HANDLE_CASE(uint8_t, 1, readBufferSlotIndex, false);
2038  break;
2039  case 2:
2040  HANDLE_CASE(uint16_t, 2, readBufferSlotIndex, false);
2041  break;
2042  case 4:
2043  HANDLE_CASE(uint32_t, 4, readBufferSlotIndex, false);
2044  break;
2045  case 8:
2046  HANDLE_CASE(uint64_t, 8, readBufferSlotIndex, false);
2047  break;
2048 
2049  default: {
2050  HANDLE_LARGE();
2051  }
2052  }
2053  }
2054  }
2055 };
2056 
2057 /********************* instrument analysis ************************/
2058 
2059 static inline bool INS_IsIgnorable(INS ins) {
2060  if (INS_IsFarJump(ins) || INS_IsDirectFarJump(ins) || INS_IsMaskedJump(ins))
2061  return true;
2062  if (INS_IsRet(ins) || INS_IsIRet(ins))
2063  return true;
2064  if (INS_IsCall(ins) || INS_IsSyscall(ins))
2065  return true;
2066  if (INS_IsBranch(ins) || INS_IsRDTSC(ins) || INS_IsNop(ins))
2067  return true;
2068  // XSAVEC and XRSTOR are problematic since its access length is variable.
2069  // Execution of XSAVEC is similar to that of XSAVE. XSAVEC differs from XSAVE in that it uses compaction and that it may use the init optimization.
2070  // It fails with "Cannot use IARG_MEMORYWRITE_SIZE on non-standard memory access of instruction at 0xfoo: xsavec ptr [rsp]" error.
2071  // A correct solution should use INS_hasKnownMemorySize() which is not available in Pin 2.14.
2072  if (INS_Mnemonic(ins) == "XSAVEC")
2073  return true;
2074  if (INS_Mnemonic(ins) == "XSAVE")
2075  return true;
2076  if (INS_Mnemonic(ins) == "XRSTOR")
2077  return true;
2078  return false;
2079 }
2080 
2081 static inline bool REG_IsIgnorable(REG reg) {
2082  if (REG_is_seg(reg))
2083  return true;
2084  else if (REG_is_pin_gr(reg))
2085  return true;
2086  else if (reg == REG_MXCSR)
2087  return true;
2088  else if (REG_is_flags(reg))
2089  return true;
2090  return false;
2091 }
2092 
2093 static VOID InstrumentInsCallback(INS ins, VOID* v, const uint32_t opaqueHandle) {
2094  if (!INS_HasFallThrough(ins))
2095  return;
2096  if (INS_IsIgnorable(ins))
2097  return;
2098  if (INS_IsControlFlow(ins) || INS_IsRet(ins))
2099  return;
2100 
2101  //Instrument memory writes to find redundancy
2102  // Special case, if we have only one write operand
2103  UINT32 whichOp = 0;
2104  if (GetNumWriteOperandsInIns(ins, whichOp) == 1) {
2105  // Read the value at location before and after the instruction
2107  } else {
2108  UINT32 memOperands = INS_MemoryOperandCount(ins);
2109  int readBufferSlotIndex = 0;
2110  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
2111  if (!INS_MemoryOperandIsWritten(ins, memOp))
2112  continue;
2113 
2114  switch (readBufferSlotIndex) {
2115  case 0:
2116  // Read the value at location before and after the instruction
2118  break;
2119  case 1:
2120  // Read the value at location before and after the instruction
2122  break;
2123  case 2:
2124  // Read the value at location before and after the instruction
2126  break;
2127  case 3:
2128  // Read the value at location before and after the instruction
2130  break;
2131  case 4:
2132  // Read the value at location before and after the instruction
2134  break;
2135  default:
2136  assert(0 && "NYI");
2137  break;
2138  }
2139  // use next slot for the next write operand
2140  readBufferSlotIndex++;
2141  }
2142  }
2143 
2144  //Instrument register writes to find redundancy
2145  UINT32 numOperands = INS_OperandCount(ins);
2146 
2147  for (UINT32 oper = 0; oper < numOperands; oper++) {
2148  if (!INS_OperandWritten(ins, oper) || !INS_OperandIsReg(ins, oper))
2149  continue;
2150 
2151  REG reg = INS_OperandReg(ins, oper);
2152 
2153  if (REG_IsIgnorable(reg))
2154  continue;
2155 
2156  if (RegHasAlias(reg)) {
2157  InstrumentAliasReg(ins, reg, oper, opaqueHandle);
2158  } else {
2159  InstrumentGeneralReg(ins, reg, oper, opaqueHandle);
2160  }
2161  }
2162 }
2163 
2164 /**********************************************************************************/
2165 
2166 #ifdef ENABLE_SAMPLING
2167 
2168 inline VOID UpdateAndCheck(uint32_t count, uint32_t bytes, THREADID threadId) {
2169  RedSpyThreadData* const tData = ClientGetTLS(threadId);
2170 
2171  if (tData->sampleFlag) {
2172  tData->numIns += count;
2173  if (tData->numIns > WINDOW_ENABLE) {
2174  tData->sampleFlag = false;
2175  tData->numIns = 0;
2176  EmptyCtxt(tData);
2177  }
2178  } else {
2179  tData->numIns += count;
2180  if (tData->numIns > WINDOW_DISABLE) {
2181  tData->sampleFlag = true;
2182  tData->numIns = 0;
2183  }
2184  }
2185  if (tData->sampleFlag) {
2186  tData->bytesWritten += bytes;
2187  }
2188 }
2189 
2190 inline VOID Update(uint32_t count, uint32_t bytes, THREADID threadId) {
2191  RedSpyThreadData* const tData = ClientGetTLS(threadId);
2192  tData->numIns += count;
2193  if (tData->sampleFlag) {
2194  tData->bytesWritten += bytes;
2195  }
2196 }
2197 
2198 //instrument the trace, count the number of ins in the trace, decide to instrument or not
2199 static void InstrumentTrace(TRACE trace, void* f) {
2200  bool check = false;
2201  for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
2202  uint32_t totInsInBbl = BBL_NumIns(bbl);
2203  uint32_t totBytes = 0;
2204  for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {
2205  if (!INS_HasFallThrough(ins))
2206  continue;
2207  if (INS_IsIgnorable(ins))
2208  continue;
2209  if (INS_IsControlFlow(ins) || INS_IsRet(ins))
2210  continue;
2211 
2212  if (INS_IsMemoryWrite(ins)) {
2213  totBytes += INS_MemoryWriteSize(ins);
2214  }
2215  UINT32 numOperands = INS_OperandCount(ins);
2216 
2217  for (UINT32 Oper = 0; Oper < numOperands; Oper++) {
2218  if (!INS_OperandWritten(ins, Oper) || !INS_OperandIsReg(ins, Oper))
2219  continue;
2220 
2221  REG curReg = INS_OperandReg(ins, Oper);
2222 
2223  if (REG_IsIgnorable(curReg))
2224  continue;
2225 
2226  totBytes += REG_Size(curReg);
2227  }
2228  }
2229 
2230  if (BBL_InsTail(bbl) == BBL_InsHead(bbl)) {
2231  BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)UpdateAndCheck, IARG_UINT32, totInsInBbl, IARG_UINT32, totBytes, IARG_THREAD_ID, IARG_CALL_ORDER, CALL_ORDER_FIRST, IARG_END);
2232  } else if (INS_IsIndirectBranchOrCall(BBL_InsTail(bbl))) {
2233  BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)UpdateAndCheck, IARG_UINT32, totInsInBbl, IARG_UINT32, totBytes, IARG_THREAD_ID, IARG_CALL_ORDER, CALL_ORDER_FIRST, IARG_END);
2234  } else {
2235  if (check) {
2236  BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)UpdateAndCheck, IARG_UINT32, totInsInBbl, IARG_UINT32, totBytes, IARG_THREAD_ID, IARG_CALL_ORDER, CALL_ORDER_FIRST, IARG_END);
2237  check = false;
2238  } else {
2239  BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)Update, IARG_UINT32, totInsInBbl, IARG_UINT32, totBytes, IARG_THREAD_ID, IARG_CALL_ORDER, CALL_ORDER_FIRST, IARG_END);
2240  check = true;
2241  }
2242  }
2243  }
2244 }
2245 
2246 #else
2247 
2248 inline VOID Update(uint32_t bytes, THREADID threadId) {
2249  RedSpyThreadData* const tData = ClientGetTLS(threadId);
2250  tData->bytesWritten += bytes;
2251 }
2252 
2253 //instrument the trace, count the number of ins in the trace, decide to instrument or not
2254 static void InstrumentTrace(TRACE trace, void* f) {
2255  for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
2256  uint32_t totBytes = 0;
2257  for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {
2258  if (!INS_HasFallThrough(ins))
2259  continue;
2260  if (INS_IsIgnorable(ins))
2261  continue;
2262  if (INS_IsControlFlow(ins) || INS_IsRet(ins))
2263  continue;
2264 
2265  if (INS_IsMemoryWrite(ins)) {
2266  totBytes += INS_MemoryWriteSize(ins);
2267  }
2268  UINT32 numOperands = INS_OperandCount(ins);
2269 
2270  for (UINT32 Oper = 0; Oper < numOperands; Oper++) {
2271  if (!INS_OperandWritten(ins, Oper) || !INS_OperandIsReg(ins, Oper))
2272  continue;
2273 
2274  REG curReg = INS_OperandReg(ins, Oper);
2275 
2276  if (REG_IsIgnorable(curReg))
2277  continue;
2278 
2279  totBytes += REG_Size(curReg);
2280  }
2281  }
2282  BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)Update, IARG_UINT32, totBytes, IARG_THREAD_ID, IARG_END);
2283  }
2284 }
2285 
2286 #endif
2287 
2288 struct RedundacyData {
2289  ContextHandle_t dead;
2290  ContextHandle_t kill;
2291  uint64_t frequency;
2292 };
2293 
2294 static inline bool RedundacyCompare(const struct RedundacyData& first, const struct RedundacyData& second) {
2295  return first.frequency > second.frequency;
2296 }
2297 
2298 static void PrintRedundancyPairs(THREADID threadId) {
2299  vector<RedundacyData> tmpList;
2300  vector<RedundacyData>::iterator tmpIt;
2301 
2302  uint64_t grandTotalRedundantBytes = 0;
2303  fprintf(gTraceFile, "*************** Dump Data from Thread %d ****************\n", threadId);
2304 
2305 #ifdef MERGING
2306  for (dense_hash_map<uint64_t, uint64_t>::iterator it = RedMap[threadId].begin(); it != RedMap[threadId].end(); ++it) {
2307  ContextHandle_t dead = DECODE_DEAD((*it).first);
2308  ContextHandle_t kill = DECODE_KILL((*it).first);
2309 
2310  for (tmpIt = tmpList.begin(); tmpIt != tmpList.end(); ++tmpIt) {
2311  if (dead == 0 || ((*tmpIt).dead) == 0) {
2312  continue;
2313  }
2314  if (!HaveSameCallerPrefix(dead, (*tmpIt).dead)) {
2315  continue;
2316  }
2317  if (!HaveSameCallerPrefix(kill, (*tmpIt).kill)) {
2318  continue;
2319  }
2320  bool ct1 = IsSameSourceLine(dead, (*tmpIt).dead);
2321  bool ct2 = IsSameSourceLine(kill, (*tmpIt).kill);
2322  if (ct1 && ct2) {
2323  (*tmpIt).frequency += (*it).second;
2324  grandTotalRedundantBytes += (*it).second;
2325  break;
2326  }
2327  }
2328  if (tmpIt == tmpList.end()) {
2329  RedundacyData tmp = {dead, kill, (*it).second};
2330  tmpList.push_back(tmp);
2331  grandTotalRedundantBytes += tmp.frequency;
2332  }
2333  }
2334 #else
2335  for (dense_hash_map<uint64_t, uint64_t>::iterator it = RedMap[threadId].begin(); it != RedMap[threadId].end(); ++it) {
2336  RedundacyData tmp = {DECODE_DEAD((*it).first), DECODE_KILL((*it).first), (*it).second};
2337  tmpList.push_back(tmp);
2338  grandTotalRedundantBytes += tmp.frequency;
2339  }
2340 #endif
2341 
2342  fprintf(gTraceFile, "\n Total redundant bytes = %f %%\n", grandTotalRedundantBytes * 100.0 / ClientGetTLS(threadId)->bytesWritten);
2343 
2344  sort(tmpList.begin(), tmpList.end(), RedundacyCompare);
2345  vector<struct AnalyzedMetric_t>::iterator listIt;
2346  int cntxtNum = 0;
2347  for (vector<RedundacyData>::iterator listIt = tmpList.begin(); listIt != tmpList.end(); ++listIt) {
2348  if (cntxtNum < MAX_REDUNDANT_CONTEXTS_TO_LOG) {
2349  fprintf(gTraceFile, "\n======= (%f) %% ======\n", (*listIt).frequency * 100.0 / grandTotalRedundantBytes);
2350  if ((*listIt).dead == 0) {
2351  fprintf(gTraceFile, "\n Prepopulated with by OS\n");
2352  } else {
2353  PrintFullCallingContext((*listIt).dead);
2354  }
2355  fprintf(gTraceFile, "\n---------------------Redundantly written by---------------------------\n");
2356  PrintFullCallingContext((*listIt).kill);
2357  } else {
2358  break;
2359  }
2360  cntxtNum++;
2361  }
2362 }
2363 
2364 static void PrintApproximationRedundancyPairs(THREADID threadId) {
2365  vector<RedundacyData> tmpList;
2366  vector<RedundacyData>::iterator tmpIt;
2367 
2368  uint64_t grandTotalRedundantBytes = 0;
2369  fprintf(gTraceFile, "*************** Dump Data(delta=%.2f%%) from Thread %d ****************\n", delta * 100, threadId);
2370 
2371 #ifdef MERGING
2372  for (dense_hash_map<uint64_t, uint64_t>::iterator it = ApproxRedMap[threadId].begin(); it != ApproxRedMap[threadId].end(); ++it) {
2373  ContextHandle_t dead = DECODE_DEAD((*it).first);
2374  ContextHandle_t kill = DECODE_KILL((*it).first);
2375 
2376  for (tmpIt = tmpList.begin(); tmpIt != tmpList.end(); ++tmpIt) {
2377  if (dead == 0 || ((*tmpIt).dead) == 0) {
2378  continue;
2379  }
2380  if (!HaveSameCallerPrefix(dead, (*tmpIt).dead)) {
2381  continue;
2382  }
2383  if (!HaveSameCallerPrefix(kill, (*tmpIt).kill)) {
2384  continue;
2385  }
2386  bool ct1 = IsSameSourceLine(dead, (*tmpIt).dead);
2387  bool ct2 = IsSameSourceLine(kill, (*tmpIt).kill);
2388  if (ct1 && ct2) {
2389  (*tmpIt).frequency += (*it).second;
2390  grandTotalRedundantBytes += (*it).second;
2391  grandTotalRedundantIns += 1;
2392  break;
2393  }
2394  }
2395  if (tmpIt == tmpList.end()) {
2396  RedundacyData tmp = {dead, kill, (*it).second};
2397  tmpList.push_back(tmp);
2398  grandTotalRedundantBytes += tmp.frequency;
2399  }
2400  }
2401 #else
2402  for (dense_hash_map<uint64_t, uint64_t>::iterator it = ApproxRedMap[threadId].begin(); it != ApproxRedMap[threadId].end(); ++it) {
2403  RedundacyData tmp = {DECODE_DEAD((*it).first), DECODE_KILL((*it).first), (*it).second};
2404  tmpList.push_back(tmp);
2405  grandTotalRedundantBytes += tmp.frequency;
2406  }
2407 #endif
2408 
2409  fprintf(gTraceFile, "\n Total redundant bytes = %f %%\n", grandTotalRedundantBytes * 100.0 / ClientGetTLS(threadId)->bytesWritten);
2410 
2411  sort(tmpList.begin(), tmpList.end(), RedundacyCompare);
2412  vector<struct AnalyzedMetric_t>::iterator listIt;
2413  int cntxtNum = 0;
2414  for (vector<RedundacyData>::iterator listIt = tmpList.begin(); listIt != tmpList.end(); ++listIt) {
2415  if (cntxtNum < MAX_REDUNDANT_CONTEXTS_TO_LOG) {
2416  fprintf(gTraceFile, "\n======= (%f) %% ======\n", (*listIt).frequency * 100.0 / grandTotalRedundantBytes);
2417  if ((*listIt).dead == 0) {
2418  fprintf(gTraceFile, "\n Prepopulated with by OS\n");
2419  } else {
2420  PrintFullCallingContext((*listIt).dead);
2421  }
2422  fprintf(gTraceFile, "\n---------------------Redundantly written by---------------------------\n");
2423  PrintFullCallingContext((*listIt).kill);
2424  } else {
2425  break;
2426  }
2427  cntxtNum++;
2428  }
2429 }
2430 
2431 // On each Unload of a loaded image, the accummulated redundancy information is dumped
2432 static VOID ImageUnload(IMG img, VOID* v) {
2433  fprintf(gTraceFile, "\n TODO .. Multi-threading is not well supported.");
2434  THREADID threadid = PIN_ThreadId();
2435  fprintf(gTraceFile, "\nUnloading %s", IMG_Name(img).c_str());
2436  // Update gTotalInstCount first
2437  PIN_LockClient();
2438  PrintRedundancyPairs(threadid);
2440  PIN_UnlockClient();
2441  // clear redmap now
2442  RedMap[threadid].clear();
2443  ApproxRedMap[threadid].clear();
2444 }
2445 
2446 static VOID ThreadFiniFunc(THREADID threadid, const CONTEXT* ctxt, INT32 code, VOID* v) {
2447 }
2448 
2449 static VOID FiniFunc(INT32 code, VOID* v) {
2450  // do whatever you want to the full CCT with footpirnt
2451 }
2452 
2453 static void InitThreadData(RedSpyThreadData* tdata) {
2454  tdata->bytesWritten = 0;
2455  tdata->sampleFlag = true;
2456  tdata->numIns = 0;
2457  tdata->numWinds = 0;
2458  for (int i = 0; i < THREAD_MAX; ++i) {
2459  RedMap[i].set_empty_key(0);
2460  ApproxRedMap[i].set_empty_key(0);
2461  }
2462 }
2463 
2464 static VOID ThreadStart(THREADID threadid, CONTEXT* ctxt, INT32 flags, VOID* v) {
2465  RedSpyThreadData* tdata = (RedSpyThreadData*)memalign(32, sizeof(RedSpyThreadData));
2466  InitThreadData(tdata);
2467  // __sync_fetch_and_add(&gClientNumThreads, 1);
2468 #ifdef MULTI_THREADED
2469  PIN_SetThreadData(client_tls_key, tdata, threadid);
2470 #else
2471  gSingleThreadedTData = tdata;
2472 #endif
2473 }
2474 
2475 
2476 int main(int argc, char* argv[]) {
2477  // Initialize PIN
2478  if (PIN_Init(argc, argv))
2479  return Usage();
2480 
2481  // Initialize Symbols, we need them to report functions and lines
2482  PIN_InitSymbols();
2483 
2484  // Init Client
2485  ClientInit(argc, argv);
2486  // Intialize CCTLib
2488 
2489 
2490  // Obtain a key for TLS storage.
2491  client_tls_key = PIN_CreateThreadDataKey(nullptr /*TODO have a destructir*/);
2492  // Register ThreadStart to be called when a thread starts.
2493  PIN_AddThreadStartFunction(ThreadStart, nullptr);
2494 
2495 
2496  // fini function for post-mortem analysis
2497  PIN_AddThreadFiniFunction(ThreadFiniFunc, nullptr);
2498  PIN_AddFiniFunction(FiniFunc, nullptr);
2499 
2500  TRACE_AddInstrumentFunction(InstrumentTrace, nullptr);
2501 
2502  // Register ImageUnload to be called when an image is unloaded
2503  IMG_AddUnloadFunction(ImageUnload, nullptr);
2504 
2505  // Launch program now
2506  PIN_StartProgram();
2507  return 0;
2508 }
#define MAX_FILE_PATH
Definition: cctlib.H:18
#define INTERESTING_INS_ALL
Definition: cctlib.H:85
int PinCCTLibInit(IsInterestingInsFptr isInterestingIns, FILE *logFile, CCTLibInstrumentInsCallback userCallback, VOID *userCallbackArg, BOOL doDataCentric=false)
Definition: cctlib.cpp:3132
hpcrun_metricFlags_t flags
Definition: cctlib.cpp:3425
VOID PrintFullCallingContext(const ContextHandle_t ctxtHandle)
Definition: cctlib.cpp:2346
bool HaveSameCallerPrefix(ContextHandle_t ctxt1, ContextHandle_t ctxt2)
Definition: cctlib.cpp:3241
bool IsSameSourceLine(ContextHandle_t ctxt1, ContextHandle_t ctxt2)
Definition: cctlib.cpp:3255
volatile uint8_t status
Definition: cctlib.cpp:230
ContextHandle_t GetContextHandle(const THREADID id, const uint32_t slot)
Definition: cctlib.cpp:1356
uint32_t ContextHandle_t
Definition: cctlib.H:22
static BOOL INS_IsMaskedJump(INS ins)
static BOOL INS_IsIndirectBranchOrCall(INS ins)
static USIZE INS_MemoryWriteSize(INS ins)
PINTOOL_REGISTER PIN_REGISTER
static BOOL REG_is_in_X87(REG reg)
#define WINDOW_ENABLE
#define WINDOW_DISABLE
static void CheckRegValues(CONTEXT *ctxt, THREADID threadId)
#define HANDLE_CASE(T, ACCESS_LEN, BUFFER_INDEX, IS_APPROX)
#define MAX_WRITE_OP_LENGTH
#define HANDLE_10BYTES_APPROX(REG_ID)
static void ClientInit(int argc, char *argv[])
int main(int argc, char *argv[])
static bool IsFloatInstruction(ADDRINT ip)
#define HANDLE_LARGE()
static FILE * gTraceFile
xed_state_t xedState
#define MAX_REDUNDANT_CONTEXTS_TO_LOG
#define MAX_REG_LENGTH
static VOID ImageUnload(IMG img, VOID *v)
struct @15 RedSpyGlobals
static RedSpyThreadData * gSingleThreadedTData
#define EIGHT_BYTE_WRITE_ACTION
static void AddToRedTable(uint64_t key, uint16_t value, THREADID threadId) __attribute__((always_inline
static void PrintRedundancyPairs(THREADID threadId)
char dummy2[128]
static bool REG_IsIgnorable(REG reg)
#define HANDLE_APPROXREG(T, IS_ALIAS, REG_ID)
static const uint64_t READ_ACCESS_STATES[]
#define THREAD_MAX
#define ALIAS_BYTES_INDEX_64
#define MAX_WRITE_OPS_IN_INS
#define MAX_ALIAS_REG_SIZE
#define ONE_BYTE_READ_ACTION
static bool RedundacyCompare(const struct RedundacyData &first, const struct RedundacyData &second)
static INT32 Usage()
static bool IsFloatInstructionOld(ADDRINT ip)
#define EIGHT_BYTE_READ_ACTION
#define TWO_BYTE_READ_ACTION
#define ALIAS_BYTES_INDEX_32
#define HANDLE_APPROX_CASE(T, ACCESS_LEN, BUFFER_INDEX, IS_APPROX)
#define ALIAS_BYTES_INDEX_8_L
static dense_hash_map< uint64_t, uint64_t > RedMap[THREAD_MAX]
static uint16_t FloatOperandSize(ADDRINT ip, uint32_t oper)
static const uint8_t OVERFLOW_CHECK[]
static void flatten
#define MAKE_CONTEXT_PAIR(a, b)
static ConcurrentShadowMemory< ContextHandle_t > sm
#define HANDLE_SPECIALREG(LEN, REG_ID)
VOID Update(uint32_t bytes, THREADID threadId)
#define DECODE_DEAD(data)
static VOID RecordValueBeforeLargeWrite(void *addr, UINT32 accessLen, uint32_t bufferOffset, THREADID threadId)
#define HANDLE_LARGEREG_APPROX(T, SIMD_TYPE, REG_ID)
struct RedSpyThreadData __attribute__
static VOID InstrumentInsCallback(INS ins, VOID *v, const uint32_t opaqueHandle)
static void InstrumentTrace(TRACE trace, void *f)
uint8_t value[MAX_WRITE_OP_LENGTH]
static void Check10BytesReg(CONTEXT *ctxt, REG reg, uint32_t opaqueHandle, THREADID threadId)
static void InitThreadData(RedSpyThreadData *tdata)
#define MAX_ALIAS_TYPE
static bool INS_IsIgnorable(INS ins)
RedSpyThreadData * ClientGetTLS(const THREADID threadId)
static void AddToApproximateRedTable(uint64_t key, uint16_t value, THREADID threadId) __attribute__((always_inline
#define delta
static VOID FiniFunc(INT32 code, VOID *v)
#define MAX_ALIAS_REGS
#define TWO_BYTE_WRITE_ACTION
static const uint64_t WRITE_ACCESS_STATES[]
static VOID CheckAfterLargeWrite(UINT32 accessLen, uint32_t bufferOffset, uint32_t opaqueHandle, THREADID threadId)
#define FOUR_BYTE_READ_ACTION
#define ALIAS_BYTES_INDEX_8_H
static void PrintApproximationRedundancyPairs(THREADID threadId)
#define IS_ACCESS_WITHIN_PAGE_BOUNDARY(accessAddr, accessLen)
static uint32_t GetAliasIDs(REG reg)
#define HANDLE_ALIAS_REG(T, ALIAS_GRP, ID)
static VOID ThreadFiniFunc(THREADID threadid, const CONTEXT *ctxt, INT32 code, VOID *v)
void * address
char dummy1[128]
static int GetNumWriteOperandsInIns(INS ins, UINT32 &whichOp)
#define ONE_BYTE_WRITE_ACTION
#define FOUR_BYTE_WRITE_ACTION
static void InstrumentGeneralReg(INS ins, REG reg, uint16_t oper, uint32_t opaqueHandle)
#define DECODE_KILL(data)
static TLS_KEY client_tls_key
#define ALIAS_BYTES_INDEX_16
#define HANDLE_GENERAL(T)
#define MAX_SIMD_LENGTH
static void InstrumentAliasReg(INS ins, REG reg, uint16_t oper, uint32_t opaqueHandle)
bool RegHasAlias(REG reg)
static VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
static dense_hash_map< uint64_t, uint64_t > ApproxRedMap[THREAD_MAX]
#define MAX_SIMD_REGS
#define PAGE_OFFSET(addr)
Definition: shadow_memory.H:15
uint8_t value[MAX_WRITE_OP_LENGTH]
void * address
static __attribute__((always_inline)) void CheckValues(PIN_REGISTER *regRef
static __attribute__((always_inline)) void CheckValues(PIN_REGISTER *regRef
static __attribute__((always_inline)) void CheckUpdateGenericAlias(uint8_t regId
static __attribute__((always_inline)) void CheckValues(T value
static __attribute__((always_inline)) void CheckRegValues(PIN_REGISTER *regRef
static __attribute__((always_inline)) void CheckSIMDRegValues(PIN_REGISTER *regRef
UINT8 value[MAX_SIMD_LENGTH]
static __attribute__((always_inline)) bool IsWriteRedundant(void *&addr
static __attribute__((always_inline)) VOID CheckNByteValueAfterWrite(uint32_t opaqueHandle
static __attribute__((always_inline)) VOID RecordNByteValueBeforeWrite(void *addr
static __attribute__((always_inline)) void InstrumentReadValueBeforeAndAfterWriting(INS ins
struct LargeReg simdValue[MAX_SIMD_REGS]
uint64_t bytesWritten
uint32_t simdCtxt[MAX_SIMD_REGS]
uint32_t aliasCtxt[MAX_ALIAS_REGS][MAX_ALIAS_TYPE]
AddrValPair buffer[MAX_WRITE_OPS_IN_INS]
uint32_t regCtxt[REG_LAST]
UINT8 aliasValue[MAX_ALIAS_REGS][MAX_ALIAS_REG_SIZE]
UINT8 regValue[REG_LAST][MAX_REG_LENGTH]
static __attribute__((always_inline)) bool BodyContextCheck(ContextHandle_t *__restrict__ prevIP)
static __attribute__((always_inline)) bool Body(const function< void(const int)> &func)
static __attribute__((always_inline)) bool Body(const function< bool(const int)> &func)
static __attribute__((always_inline)) bool BodyContextCheck(ContextHandle_t *__restrict__ prevIP)
static bool Body(const function< bool(const int)> &func)
static __attribute__((always_inline)) void BodySamePage(ContextHandle_t *__restrict__ prevIP
static __attribute__((always_inline)) void Body(const function< void(const int)> &func)
static __attribute__((always_inline)) void BodyStraddlePage(uint64_t addr
static void Body(const function< void(const int)> &func)
static __attribute__((always_inline)) void BodySamePage(ContextHandle_t *__restrict__ prevIP
static __attribute__((always_inline)) void Body(const function< void(const int)> &func)
void f()
Definition: test1.c:23