CCTLib
Calling-context and data-object attribution library for Intel Pin
runtime_value_numbering_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 "pin.H"
9 // pin_isa.H was merged into pin.H in Pin 4.x; use our compat header for
10 // removed/renamed APIs (INS_IsMaskedJump, INS_IsIndirectBranchOrCall,
11 // INS_MemoryReadSize/WriteSize, PIN_REGISTER, REG_is_in_X87).
12 #include "pin_isa_compat.H"
13 #include <map>
14 #include <unordered_map>
15 #include <list>
16 #include <stdint.h>
17 #include <sys/types.h>
18 #include <sys/ipc.h>
19 #include <sys/shm.h>
20 #include <semaphore.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <iostream>
24 #include <locale>
25 #include <unistd.h>
26 #include <sys/syscall.h>
27 #include <assert.h>
28 #include <sys/mman.h>
29 #include <exception>
30 #include <sys/time.h>
31 #include <signal.h>
32 #include <string.h>
33 #include <setjmp.h>
34 #include <sstream>
35 #include <pthread.h>
36 // Need GOOGLE sparse hash tables
37 #include <google/sparse_hash_map>
38 #include <google/dense_hash_map>
39 using namespace std;
40 
41 #include "cctlib.H"
42 using namespace PinCCTLib;
43 
44 /* infrastructure for shadow memory */
45 /* MACROs */
46 // 64KB shadow pages
47 #define PAGE_OFFSET_BITS (16LL)
48 #define PAGE_OFFSET(addr) (addr & 0xFFFF)
49 #define PAGE_OFFSET_MASK (0xFFFF)
50 
51 // Pin 4.x's musl <limits.h> defines a system PAGE_SIZE; undef before we
52 // redefine to our shadow-page constant.
53 #undef PAGE_SIZE
54 #define PAGE_SIZE (1 << PAGE_OFFSET_BITS)
55 
56 // 2 level page table
57 #define PTR_SIZE (sizeof(void*))
58 #define LEVEL_1_PAGE_TABLE_BITS (20)
59 #define LEVEL_1_PAGE_TABLE_ENTRIES (1 << LEVEL_1_PAGE_TABLE_BITS)
60 #define LEVEL_1_PAGE_TABLE_SIZE (LEVEL_1_PAGE_TABLE_ENTRIES * PTR_SIZE)
61 
62 #define LEVEL_2_PAGE_TABLE_BITS (12)
63 #define LEVEL_2_PAGE_TABLE_ENTRIES (1 << LEVEL_2_PAGE_TABLE_BITS)
64 #define LEVEL_2_PAGE_TABLE_SIZE (LEVEL_2_PAGE_TABLE_ENTRIES * PTR_SIZE)
65 
66 #define LEVEL_1_PAGE_TABLE_SLOT(addr) (((addr) >> (LEVEL_2_PAGE_TABLE_BITS + PAGE_OFFSET_BITS)) & 0xfffff)
67 #define LEVEL_2_PAGE_TABLE_SLOT(addr) (((addr) >> (PAGE_OFFSET_BITS)) & 0xFFF)
68 
69 
70 // All globals
71 #define MAX_FILE_PATH (200)
72 #define MAX_DEAD_CONTEXTS_TO_LOG (4000)
73 #define MAX_LOG_NUM (110)
74 #define MAX_OPERAND (6)
75 #define SAMPLE_PERIOD (1000000)
76 #define STOP_PERIOD (1000000000)
77 #define VALUE_N (10)
78 
79 enum AccessType {
81  WRITE_ACCESS = 1
82 };
83 
84 FILE* gTraceFile;
85 static uint64_t gValue;
87 
88 bool Sample = true;
89 uint64_t Num_instructions = 0;
90 uint64_t lastGValue;
91 
92 ////////////////////////////////////////////////////////////////////////////remove
93 uint64_t Num_redundant = 0;
94 uint64_t Num_ins = 0;
95 
96 using OPMap = struct opMap {
97  uint64_t vNum;
98  uint32_t ip;
99 };
100 
101 
102 class ThreadData_t {
103  public:
104  uint64_t regNumber[REG_LAST];
105  unordered_map<uint64_t, uint64_t> immediateMap;
106  unordered_map<uint64_t, uint64_t>::iterator immediateMapIt;
107 
108  unordered_map<uint64_t, OPMap> opcodeMap;
109  unordered_map<uint64_t, OPMap>::iterator opcodeMapIt;
110 
111  unordered_map<uint64_t, uint64_t> redundantMap;
112  unordered_map<uint64_t, uint64_t>::iterator redundantMapIt;
113 
115  memset(regNumber, 0, sizeof(uint64_t) * REG_LAST);
116  }
117 };
118 
119 using OPInfo = struct opcodeInfo {
120  OPCODE opCode;
121  int sCount;
123  int tCount;
127 };
128 
129 // key for accessing TLS storage in the threads. initialized once in main()
130 static TLS_KEY tls_key;
131 static PIN_MUTEX gMutex;
132 
133 
134 //static uint64_t total;
135 //static uint64_t totalI;
136 
137 // If it is one of ignoreable instructions, then skip instrumentation.
138 bool IsIgnorableIns(INS ins) {
139  if (INS_IsFarJump(ins) || INS_IsDirectFarJump(ins) || INS_IsMaskedJump(ins))
140  return true;
141  else if (INS_IsRet(ins) || INS_IsIRet(ins))
142  return true;
143  else if (INS_IsCall(ins) || INS_IsSyscall(ins))
144  return true;
145  else if (INS_IsBranch(ins) || INS_IsRDTSC(ins) || INS_IsNop(ins))
146  return true;
147  return false;
148 }
149 
150 bool IsMov(int opcode) {
151  switch (opcode) {
152  case XED_ICLASS_MOV:
153  case XED_ICLASS_MOVAPD:
154  case XED_ICLASS_MOVAPS:
155  case XED_ICLASS_MOVBE:
156  case XED_ICLASS_MOVD:
157  case XED_ICLASS_MOVDDUP:
158  case XED_ICLASS_MOVDQ2Q:
159  case XED_ICLASS_MOVDQA:
160  case XED_ICLASS_MOVDQU:
161  case XED_ICLASS_MOVHLPS:
162  case XED_ICLASS_MOVHPD:
163  case XED_ICLASS_MOVHPS:
164  case XED_ICLASS_MOVLHPS:
165  case XED_ICLASS_MOVLPD:
166  case XED_ICLASS_MOVLPS:
167  case XED_ICLASS_MOVMSKPD:
168  case XED_ICLASS_MOVMSKPS:
169  case XED_ICLASS_MOVNTDQ:
170  case XED_ICLASS_MOVNTDQA:
171  case XED_ICLASS_MOVNTI:
172  case XED_ICLASS_MOVNTPD:
173  case XED_ICLASS_MOVNTPS:
174  case XED_ICLASS_MOVNTQ:
175  case XED_ICLASS_MOVNTSD:
176  case XED_ICLASS_MOVNTSS:
177  case XED_ICLASS_MOVQ:
178  case XED_ICLASS_MOVQ2DQ:
179  case XED_ICLASS_MOVSB:
180  case XED_ICLASS_MOVSD:
181  case XED_ICLASS_MOVSD_XMM:
182  case XED_ICLASS_MOVSHDUP:
183  case XED_ICLASS_MOVSLDUP:
184  case XED_ICLASS_MOVSQ:
185  case XED_ICLASS_MOVSS:
186  case XED_ICLASS_MOVSW:
187  case XED_ICLASS_MOVSX:
188  case XED_ICLASS_MOVSXD:
189  case XED_ICLASS_MOVUPD:
190  case XED_ICLASS_MOVUPS:
191  case XED_ICLASS_MOVZX:
192  case XED_ICLASS_MOV_CR:
193  case XED_ICLASS_MOV_DR:
194  return true;
195  default:
196  return false;
197  }
198 }
199 
200 // function to access thread-specific data
201 inline ThreadData_t* GetTLS(THREADID threadid) {
202  ThreadData_t* tdata =
203  static_cast<ThreadData_t*>(PIN_GetThreadData(tls_key, threadid));
204  return tdata;
205 }
206 
207 /* clear method used during sampling*/
208 VOID CleanValueNumbers(THREADID threadID) {
209  ThreadData_t* td = GetTLS(threadID);
210  td->immediateMap.clear();
211  td->opcodeMap.clear();
212 
213  /** clean all the value numbers for the registers and memory locations **/
214  memset(td->regNumber, 0, REG_LAST * sizeof(td->regNumber[0]));
215  lastGValue = gValue;
216 }
217 
218 inline void UpdateValue(uint32_t reg, uint64_t value, ThreadData_t* td) {
219  switch (reg) {
220  case REG_GAX:
221  case REG_EAX:
222  td->regNumber[REG_GAX] = td->regNumber[REG_EAX] = value;
223  gValue++;
224  td->regNumber[REG_AX] = td->regNumber[REG_AL] = td->regNumber[REG_AH] = gValue;
225  break;
226  case REG_AX:
227  td->regNumber[REG_GAX] = td->regNumber[REG_EAX] = td->regNumber[REG_AX] = value;
228  gValue++;
229  td->regNumber[REG_AL] = td->regNumber[REG_AH] = gValue;
230  break;
231  case REG_AH:
232  td->regNumber[REG_GAX] = td->regNumber[REG_EAX] = td->regNumber[REG_AX] = td->regNumber[REG_AH] = value;
233  break;
234  case REG_AL:
235  td->regNumber[REG_GAX] = td->regNumber[REG_EAX] = td->regNumber[REG_AX] = td->regNumber[REG_AL] = value;
236  break;
237 
238 
239  case REG_GBX:
240  case REG_EBX:
241  td->regNumber[REG_GBX] = td->regNumber[REG_EBX] = value;
242  gValue++;
243  td->regNumber[REG_BX] = td->regNumber[REG_BL] = td->regNumber[REG_BH] = gValue;
244  break;
245  case REG_BX:
246  td->regNumber[REG_GBX] = td->regNumber[REG_EBX] = td->regNumber[REG_BX] = value;
247  gValue++;
248  td->regNumber[REG_BL] = td->regNumber[REG_BH] = gValue;
249  break;
250  case REG_BH:
251  td->regNumber[REG_GBX] = td->regNumber[REG_EBX] = td->regNumber[REG_BX] = td->regNumber[REG_BH] = value;
252  break;
253  case REG_BL:
254  td->regNumber[REG_GBX] = td->regNumber[REG_EBX] = td->regNumber[REG_BX] = td->regNumber[REG_BL] = value;
255  break;
256 
257  case REG_GCX:
258  case REG_ECX:
259  td->regNumber[REG_GCX] = td->regNumber[REG_ECX] = value;
260  gValue++;
261  td->regNumber[REG_CX] = td->regNumber[REG_CL] = td->regNumber[REG_CH] = gValue;
262  break;
263  case REG_CX:
264  td->regNumber[REG_GCX] = td->regNumber[REG_ECX] = td->regNumber[REG_CX] = value;
265  gValue++;
266  td->regNumber[REG_CL] = td->regNumber[REG_CH] = gValue;
267  break;
268  case REG_CH:
269  td->regNumber[REG_GCX] = td->regNumber[REG_ECX] = td->regNumber[REG_CX] = td->regNumber[REG_CH] = value;
270  break;
271  case REG_CL:
272  td->regNumber[REG_GCX] = td->regNumber[REG_ECX] = td->regNumber[REG_CX] = td->regNumber[REG_CL] = value;
273  break;
274 
275  case REG_GDX:
276  case REG_EDX:
277  td->regNumber[REG_GDX] = td->regNumber[REG_EDX] = value;
278  gValue++;
279  td->regNumber[REG_DX] = td->regNumber[REG_DL] = td->regNumber[REG_DH] = gValue;
280  break;
281  case REG_DX:
282  td->regNumber[REG_GDX] = td->regNumber[REG_EDX] = td->regNumber[REG_DX] = value;
283  gValue++;
284  td->regNumber[REG_DL] = td->regNumber[REG_DH] = gValue;
285  break;
286  case REG_DH:
287  td->regNumber[REG_GDX] = td->regNumber[REG_EDX] = td->regNumber[REG_DX] = td->regNumber[REG_DH] = value;
288  break;
289  case REG_DL:
290  td->regNumber[REG_GDX] = td->regNumber[REG_EDX] = td->regNumber[REG_DX] = td->regNumber[REG_DL] = value;
291  break;
292 
293  default:
294  td->regNumber[reg] = value;
295  }
296 }
297 
298 /* helper functions for shadow memory */
299 static uint8_t* GetOrCreateShadowBaseAddress(uint64_t address) {
300  uint8_t* shadowPage;
301  uint8_t*** l1Ptr = &gL1PageTable[LEVEL_1_PAGE_TABLE_SLOT(address)];
302  if (*l1Ptr == nullptr) {
303  *l1Ptr = (uint8_t**)calloc(1, LEVEL_2_PAGE_TABLE_SIZE);
304  shadowPage = (*l1Ptr)[LEVEL_2_PAGE_TABLE_SLOT(address)] = (uint8_t*)mmap(nullptr, PAGE_SIZE * sizeof(uint64_t), PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
305  } else if ((shadowPage = (*l1Ptr)[LEVEL_2_PAGE_TABLE_SLOT(address)]) == nullptr) {
306  shadowPage = (*l1Ptr)[LEVEL_2_PAGE_TABLE_SLOT(address)] = (uint8_t*)mmap(nullptr, PAGE_SIZE * sizeof(uint64_t), PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
307  }
308  return shadowPage;
309 }
310 
311 /* get the value number from the shadow memory */
312 inline uint64_t getMemValueNum(uint64_t addr, THREADID threadid) {
313  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
314  uint64_t* prevAddr = (uint64_t*)(status + PAGE_OFFSET(addr) * sizeof(uint64_t));
315  if (*prevAddr == 0) {
316  gValue++;
317  *prevAddr = gValue;
318  } else {
319  if (*prevAddr < lastGValue) {
320  gValue++;
321  *prevAddr = gValue;
322  }
323  }
324 
325  return *prevAddr;
326 }
327 
328 
329 /* get the value number from the register */
330 inline uint64_t getRegValueNum(REG reg, THREADID threadid) {
331  ThreadData_t* td = GetTLS(threadid);
332  if (td->regNumber[reg] == 0) {
333  gValue++;
334  td->regNumber[reg] = gValue;
335  }
336  return td->regNumber[reg];
337 }
338 
339 /* set a new value number to the memory */
340 inline VOID setMemValueNum(uint64_t addr, THREADID threadid, uint64_t value) {
341  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
342  uint64_t* prevAddr = (uint64_t*)(status + PAGE_OFFSET(addr) * sizeof(uint64_t));
343  *prevAddr = value;
344 }
345 
346 /* set a new value number to the register */
347 inline VOID setRegValueNum(REG reg, ThreadData_t* td, uint64_t value) {
348  //td->regNumber[reg] = value;
349  UpdateValue(reg, value, td);
350 }
351 
352 
353 /* get the value number for the immediate data */
354 inline uint64_t getImmediateValueNum(uint64_t immediate, THREADID threadid) {
355  ThreadData_t* td = GetTLS(threadid);
356  td->immediateMapIt = td->immediateMap.find(immediate);
357  if (td->immediateMapIt == td->immediateMap.end()) {
358  gValue++;
359  td->immediateMap.insert(std::pair<uint64_t, uint64_t>(immediate, gValue));
360  return gValue;
361  }
362  return td->immediateMapIt->second;
363 }
364 
365 /* record the redundant operation deadCtxt is redundant because of killer */
366 inline void recordRedundantOperation(uint32_t deadCtxt, uint32_t killerCtxt, ThreadData_t* td) {
367  uint64_t deadIndex = (uint64_t)deadCtxt;
368  uint64_t killerIndex = (uint64_t)killerCtxt;
369  uint64_t key = (deadIndex << 32) | killerIndex;
370 
371  if ((td->redundantMapIt = td->redundantMap.find(key)) == td->redundantMap.end()) {
372  td->redundantMap.insert(std::pair<uint64_t, uint64_t>(key, 1));
373  } else {
374  (td->redundantMapIt->second) += 1;
375  }
376 }
377 
378 
379 void deleteString(uint64_t key, ThreadData_t* td) {
380  td->opcodeMapIt = td->opcodeMap.find(key);
381  if (td->opcodeMapIt != td->opcodeMap.end()) {
382  td->opcodeMap.erase(td->opcodeMapIt);
383  //total--;
384  }
385 }
386 
387 
388 /* record only one hash value for each IP, if the new one is different, delete the old one */
389 void removeOldstring(void* ip, uint64_t nValue, ThreadData_t* td) {
390  uint64_t addr = (uint64_t)ip;
391  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
392  uint64_t* prevAddr = (uint64_t*)(status + PAGE_OFFSET(addr) * sizeof(uint64_t));
393  if (*prevAddr == 0) {
394  uint64_t* valueNumIP;
395  valueNumIP = (uint64_t*)malloc(sizeof(uint64_t) * (VALUE_N + 1));
396  for (int i = 0; i <= VALUE_N; ++i) {
397  valueNumIP[i] = 0;
398  }
399  valueNumIP[0] = nValue;
400  *prevAddr = (uint64_t)(valueNumIP);
401 
402  } else {
403  uint64_t* valuesIP;
404  valuesIP = (uint64_t*)(*prevAddr);
405  int i;
406  for (i = 0; i < VALUE_N; ++i) {
407  if (valuesIP[i] == 0) {
408  valuesIP[i] = nValue;
409  break;
410  } else if (valuesIP[i] == nValue)
411  break;
412  }
413 
414 
415  if (i == VALUE_N) {
416  uint64_t index = valuesIP[VALUE_N];
417  if (index >= VALUE_N)
418  index = 0;
419  uint64_t old = valuesIP[index];
420  deleteString(old, td);
421  valuesIP[index] = nValue;
422  valuesIP[VALUE_N] = index + 1;
423  }
424  *prevAddr = (uint64_t)(valuesIP);
425  }
426 }
427 
428 /*void removeOldstring(void *ip, uint64_t nValue, ThreadData_t * td){
429 
430  uint64_t addr = (uint64_t)ip;
431  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
432  uint64_t *prevAddr = (uint64_t *)(status + PAGE_OFFSET(addr) * sizeof(uint64_t));
433  if(*prevAddr == 0){
434  *prevAddr = nValue;
435 
436  }else{
437 
438  if(*prevAddr != nValue){
439 
440  uint64_t old = *prevAddr;
441  deleteString(old, td);
442  *prevAddr = nValue;
443  }
444  }
445 }*/
446 
447 
448 /* check if it is a redundant write to memory*/
449 void checkMovValueNum(int opcode, uint64_t svalue, uint64_t target, THREADID threadid, void* ip, const uint32_t opHandle) {
450  ThreadData_t* td = GetTLS(threadid);
451  uint32_t curCtxt = GetContextHandle(threadid, opHandle);
452 
453  uint64_t op = (uint64_t)opcode;
454  uint64_t key = (op << 56) | ((svalue & 0x000000000fffffff) << 28) | (target & 0x000000000fffffff);
455 
456  //uint64_t key = op+svalue+target;
457 
458  td->opcodeMapIt = td->opcodeMap.find(key);
459 
460  if (td->opcodeMapIt == td->opcodeMap.end()) {
461  //total++;
462  OPMap opmap = {svalue, curCtxt};
463  //td->opcodeMap.insert(std::pair<uint64_t, OPMap>(key,opmap));
464  td->opcodeMap[key] = opmap;
465  //fprintf(gTraceFile,"ip: %p --- key: %u\n",ip, key);
466  removeOldstring(ip, key, td);
467 
468  return;
469  }
470  Num_redundant++; //////////////////////////////////remove
471  recordRedundantOperation(td->opcodeMapIt->second.ip, curCtxt, td);
472  removeOldstring(ip, key, td);
473 }
474 
475 static inline void sortSvalues(uint64_t* svalues, int count) {
476  uint64_t temp;
477 
478  for (int i = 1; i < count; ++i) {
479  for (int j = 0; j < i; ++j) {
480  if (svalues[j] > svalues[i]) {
481  temp = svalues[j];
482  svalues[j] = svalues[i];
483  svalues[i] = temp;
484  }
485  }
486  }
487 }
488 
489 
490 /**/
491 bool IsCommutativeOp(int opcode) {
492  return opcode != XED_ICLASS_SUB && opcode != XED_ICLASS_DIV && opcode != XED_ICLASS_SHL && opcode != XED_ICLASS_SHR;
493 }
494 
495 
496 /* get the value number of the opcode and check the redundancy */
497 uint64_t checkOpcodeValueNum(int opcode, uint64_t svalues[], int sCount, THREADID threadid, void* ip, const uint32_t opHandle) {
498  ThreadData_t* td = GetTLS(threadid);
499  uint32_t curCtxt = GetContextHandle(threadid, opHandle);
500 
501  uint64_t op = (uint64_t)opcode;
502  uint64_t key;
503 
504  switch (sCount) {
505  case (0):
506  return gValue++;
507  break;
508  case (1):
509  key = (op << 56) | ((svalues[0] << 8) >> 8);
510  break;
511  case (2):
512  if (IsCommutativeOp(opcode)) {
513  sortSvalues(svalues, sCount);
514  }
515  key = (op << 56) | ((svalues[0] & 0x000000000fffffff) << 28) | (svalues[1] & 0x000000000fffffff);
516  break;
517  case (3):
518  if (IsCommutativeOp(opcode)) {
519  sortSvalues(svalues, sCount);
520  }
521  key = (op << 56) | ((svalues[0] << 45) >> 8) | ((svalues[1] << 45) >> 27) | ((svalues[2] << 45) >> 46);
522  break;
523 
524  case (4):
525  if (IsCommutativeOp(opcode)) {
526  sortSvalues(svalues, sCount);
527  }
528  key = (op << 56) | ((svalues[0] & 0x0000000000003fff) << 42) | ((svalues[1] & 0x0000000000003fff) << 28) | ((svalues[2] & 0x0000000000003fff) << 14) | (svalues[3] & 0x0000000000003fff);
529  break;
530  default:
531  printf("Source values more than 4!\n");
532  if (IsCommutativeOp(opcode)) {
533  sortSvalues(svalues, sCount);
534  }
535  key = (op << 56) | ((svalues[0] & 0x000000000fffffff) << 28) | (svalues[1] & 0x000000000fffffff);
536  break;
537  }
538 
539 
540  // use google's dense/sparse hash map
541  td->opcodeMapIt = td->opcodeMap.find(key);
542 
543  if (td->opcodeMapIt == td->opcodeMap.end()) {
544  gValue++;
545  //total++;
546  OPMap opmap = {gValue, curCtxt};
547  //td->opcodeMap.insert(std::pair<uint64_t, OPMap>(key,opmap));
548  td->opcodeMap[key] = opmap;
549  //fprintf(gTraceFile,"ip: %p --- key: %u\n",ip, key);
550  removeOldstring(ip, key, td);
551 
552  return gValue;
553  }
554  uint64_t value = td->opcodeMapIt->second.vNum;
555 
556  Num_redundant++; ////////////////////////////////////////////////remove
557  recordRedundantOperation(td->opcodeMapIt->second.ip, curCtxt, td);
558  removeOldstring(ip, key, td);
559 
560  return value;
561 }
562 
563 
564 VOID valueNumbering(void* op, bool movOrnot, THREADID threadid, void* ip, const uint32_t opHandle) {
565  if (Sample) {
568  Sample = false;
569  Num_instructions = 0;
570  CleanValueNumbers(threadid);
571  return;
572  }
573  } else {
576  Sample = true;
577  Num_instructions = 0;
578  }
579  return;
580  }
581  Num_ins++; ////////////////////////////////////remove
582 
583 
584  OPInfo* opinfo = (OPInfo*)op;
585  ThreadData_t* td = GetTLS(threadid);
586  uint64_t value;
587  int sRegsCount = opinfo->sCount;
588  int immediateCount = opinfo->immeCount;
589 
590  if (movOrnot) {
591  if (sRegsCount == 1)
592  value = getRegValueNum(opinfo->sRegs[0], threadid);
593  else if (immediateCount == 1)
594  value = opinfo->immediates[0]; // enconding immediate numbers to avoid the hash map
595  else
596  // Shasha to handle this case.
597  // putting a -1 to avoid compilation errors
598  value = -1;
599 
600  setRegValueNum(opinfo->tRegs[0], td, value);
601  } else {
602  // avoid using vectors, using constant sized array instead
603  uint64_t sValues[6];
604  int index = 0;
605 
606  for (int i = 0; i < sRegsCount; ++i)
607  sValues[index++] = getRegValueNum(opinfo->sRegs[i], threadid);
608 
609  for (int i = 0; i < immediateCount; ++i)
610  sValues[index++] = opinfo->immediates[i];
611 
612  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadid, ip, opHandle);
613  //value = gValue;
614 
615  int tRegsCount = opinfo->tCount;
616  if (tRegsCount == 1) {
617  setRegValueNum(opinfo->tRegs[0], td, value);
618  } else {
619  for (int i = 0; i < tRegsCount; i++) {
620  gValue++;
621  setRegValueNum(opinfo->tRegs[i], td, gValue);
622  }
623  }
624  }
625 }
626 
627 VOID valueNumberingMem1(void* op, void* addr, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void* ip, const uint32_t opHandle) {
628  if (Sample) {
631  Sample = false;
632  Num_instructions = 0;
633  CleanValueNumbers(threadID);
634  return;
635  }
636  } else {
639  Sample = true;
640  Num_instructions = 0;
641  }
642  return;
643  }
644  Num_ins++; ///////////////////////////////////////////remove
645 
646  OPInfo* opinfo = (OPInfo*)op;
647  ThreadData_t* td = GetTLS(threadID);
648  assert(rMem + wMem == 1);
649  uint64_t value = 0;
650 
651  int sRegsCount = opinfo->sCount;
652  int immediateCount = opinfo->immeCount;
653 
654  if (movOrnot) {
655  if (rMem == 1) {
656  assert(opinfo->tCount == 1);
657 
658  value = getMemValueNum((uint64_t)addr, threadID);
659  setRegValueNum(opinfo->tRegs[0], td, value);
660 
661  checkMovValueNum(opinfo->opCode, value, opinfo->tRegs[0], threadID, ip, opHandle);
662  } else {
663  // TODO(preexisting-bug): this assert fires on `mov imm, [mem]`
664  // which is extremely common in libc; the code below already
665  // has an `else if(immediateCount == 1)` branch that handles
666  // the immediate-source case correctly. The assert should be
667  // dropped (or relaxed to `sRegsCount + immediateCount >= 1`)
668  // and the `else` case given a real "unknown source" sentinel.
669  // Restoring the original assert to scope this change strictly
670  // to porting; a proper fix belongs with the broader RVN
671  // correctness pass.
672  assert(sRegsCount == 1);
673  if (sRegsCount == 1)
674  value = getRegValueNum(opinfo->sRegs[0], threadID);
675  else if (immediateCount == 1)
676  value = opinfo->immediates[0];
677 
678  setMemValueNum((uint64_t)addr, threadID, value);
679  checkMovValueNum(opinfo->opCode, value, (uint64_t)addr, threadID, ip, opHandle);
680  }
681  } else {
682  uint64_t sValues[6];
683  int index = 0;
684 
685  for (int i = 0; i < sRegsCount; ++i)
686  sValues[index++] = getRegValueNum(opinfo->sRegs[i], threadID);
687 
688  for (int i = 0; i < immediateCount; ++i)
689  sValues[index++] = opinfo->immediates[i];
690 
691  int tRegsCount = opinfo->tCount;
692 
693  if (rMem == 1) {
694  value = getMemValueNum((uint64_t)addr, threadID);
695  sValues[index++] = value;
696 
697  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
698  //value = gValue;
699 
700  if (tRegsCount == 1) {
701  setRegValueNum(opinfo->tRegs[0], td, value);
702  } else {
703  for (int i = 0; i < tRegsCount; i++) {
704  gValue++;
705  setRegValueNum(opinfo->tRegs[i], td, gValue);
706  }
707  }
708 
709  } else {
710  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
711  //value = gValue;
712 
713  if (tRegsCount == 0) {
714  setMemValueNum((uint64_t)addr, threadID, value);
715  } else {
716  gValue++;
717  setMemValueNum((uint64_t)addr, threadID, gValue);
718 
719  for (int i = 0; i < tRegsCount; i++) {
720  gValue++;
721  setRegValueNum(opinfo->tRegs[i], td, gValue);
722  }
723  }
724  }
725  }
726 }
727 
728 VOID valueNumberingMem2(void* op, void* addr1, void* addr2, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void* ip, const uint32_t opHandle) {
729  if (Sample) {
732  Sample = false;
733  Num_instructions = 0;
734  CleanValueNumbers(threadID);
735  return;
736  }
737  } else {
740  Sample = true;
741  Num_instructions = 0;
742  }
743  return;
744  }
745  Num_ins++; ///////////////////////////////////////////////remove
746  OPInfo* opinfo = (OPInfo*)op;
747  ThreadData_t* td = GetTLS(threadID);
748  assert(rMem + wMem == 2);
749  uint64_t value;
750 
751  int sRegsCount = opinfo->sCount;
752  int immediateCount = opinfo->immeCount;
753 
754  if (movOrnot) {
755  if (rMem == 1 && wMem == 1) {
756  value = getMemValueNum((uint64_t)addr1, threadID);
757  setMemValueNum((uint64_t)addr2, threadID, value);
758  checkMovValueNum(opinfo->opCode, value, (uint64_t)addr2, threadID, ip, opHandle);
759  }
760  } else {
761  uint64_t sValues[6];
762  int index = 0;
763 
764  for (int i = 0; i < sRegsCount; ++i)
765  sValues[index++] = getRegValueNum(opinfo->sRegs[i], threadID);
766 
767  for (int i = 0; i < immediateCount; ++i)
768  sValues[index++] = opinfo->immediates[i];
769 
770  int tRegsCount = opinfo->tCount;
771 
772  //value = gValue;
773  if (rMem == 0) {
774  (void)checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
775 
776  assert(wMem == 2);
777  gValue++;
778  setMemValueNum((uint64_t)addr1, threadID, gValue);
779  gValue++;
780  setMemValueNum((uint64_t)addr2, threadID, gValue);
781 
782  } else if (rMem == 1) {
783  assert(wMem == 1);
784  value = getMemValueNum((uint64_t)addr1, threadID);
785  sValues[index++] = value;
786 
787  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
788 
789  if (tRegsCount == 0) {
790  setMemValueNum((uint64_t)addr2, threadID, value);
791  } else {
792  gValue++;
793  setMemValueNum((uint64_t)addr2, threadID, gValue);
794 
795  for (int i = 0; i < tRegsCount; i++) {
796  gValue++;
797  setRegValueNum(opinfo->tRegs[i], td, gValue);
798  }
799  }
800 
801  } else {
802  assert(wMem == 0);
803  value = getMemValueNum((uint64_t)addr1, threadID);
804  sValues[index++] = value;
805 
806  value = getMemValueNum((uint64_t)addr2, threadID);
807  sValues[index++] = value;
808 
809  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
810 
811  if (tRegsCount == 1) {
812  setRegValueNum(opinfo->tRegs[0], td, value);
813  } else {
814  for (int i = 0; i < tRegsCount; i++) {
815  gValue++;
816  setRegValueNum(opinfo->tRegs[i], td, gValue);
817  }
818  }
819  }
820  }
821 }
822 
823 
824 VOID valueNumberingMem3(void* op, void* addr1, void* addr2, void* addr3, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void* ip, const uint32_t opHandle) {
825  if (Sample) {
828  Sample = false;
829  Num_instructions = 0;
830  CleanValueNumbers(threadID);
831  return;
832  }
833  } else {
836  Sample = true;
837  Num_instructions = 0;
838  }
839  return;
840  }
841  Num_ins++; ////////////////////////////////////////////remove
842  OPInfo* opinfo = (OPInfo*)op;
843  ThreadData_t* td = GetTLS(threadID);
844  assert(rMem + wMem == 3);
845  uint64_t value;
846 
847  int sRegsCount = opinfo->sCount;
848  int immediateCount = opinfo->immeCount;
849 
850  if (movOrnot) {
851  //printf("MOV with 3 memory addresses evloved!\n");
852  } else {
853  uint64_t sValues[6];
854  int index = 0;
855 
856  for (int i = 0; i < sRegsCount; ++i)
857  sValues[index++] = getRegValueNum(opinfo->sRegs[i], threadID);
858 
859  for (int i = 0; i < immediateCount; ++i)
860  sValues[index++] = opinfo->immediates[i];
861 
862  int tRegsCount = opinfo->tCount;
863 
864  //value = gValue;/////////////////////////////
865 
866  switch (rMem) {
867  case (0):
868  assert(wMem == 3);
869 
870  (void)checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
871 
872  gValue++;
873  setMemValueNum((uint64_t)addr1, threadID, gValue);
874  gValue++;
875  setMemValueNum((uint64_t)addr2, threadID, gValue);
876  gValue++;
877  setMemValueNum((uint64_t)addr3, threadID, gValue);
878 
879  for (int i = 0; i < tRegsCount; i++) {
880  gValue++;
881  setRegValueNum(opinfo->tRegs[i], td, gValue);
882  }
883  break;
884 
885  case (1):
886  assert(wMem == 2);
887  value = getMemValueNum((uint64_t)addr1, threadID);
888  sValues[index++] = value;
889 
890  (void)checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
891 
892  gValue++;
893  setMemValueNum((uint64_t)addr2, threadID, gValue);
894  gValue++;
895  setMemValueNum((uint64_t)addr3, threadID, gValue);
896 
897  for (int i = 0; i < tRegsCount; i++) {
898  gValue++;
899  setRegValueNum(opinfo->tRegs[i], td, gValue);
900  }
901  break;
902 
903  case (2):
904  assert(wMem == 1);
905  value = getMemValueNum((uint64_t)addr1, threadID);
906  sValues[index++] = value;
907 
908  value = getMemValueNum((uint64_t)addr2, threadID);
909  sValues[index++] = value;
910 
911  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
912 
913  if (tRegsCount == 0) {
914  setMemValueNum((uint64_t)addr3, threadID, value);
915  } else {
916  gValue++;
917  setMemValueNum((uint64_t)addr3, threadID, gValue);
918 
919  for (int i = 0; i < tRegsCount; i++) {
920  gValue++;
921  setRegValueNum(opinfo->tRegs[i], td, gValue);
922  }
923  }
924  break;
925 
926  case (3):
927  assert(wMem == 0);
928  value = getMemValueNum((uint64_t)addr1, threadID);
929  sValues[index++] = value;
930 
931  value = getMemValueNum((uint64_t)addr2, threadID);
932  sValues[index++] = value;
933 
934  value = getMemValueNum((uint64_t)addr3, threadID);
935  sValues[index++] = value;
936 
937  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
938 
939  if (tRegsCount == 1) {
940  setRegValueNum(opinfo->tRegs[0], td, value);
941  } else {
942  for (int i = 0; i < tRegsCount; i++) {
943  gValue++;
944  setRegValueNum(opinfo->tRegs[i], td, gValue);
945  }
946  }
947  break;
948 
949  default:
950  break;
951  }
952  }
953 }
954 
955 
956 VOID valueNumberingMem4(void* op, void* addr1, void* addr2, void* addr3, void* addr4, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void* ip, const uint32_t opHandle) {
957  if (Sample) {
960  Sample = false;
961  Num_instructions = 0;
962  CleanValueNumbers(threadID);
963  return;
964  }
965  } else {
968  Sample = true;
969  Num_instructions = 0;
970  }
971  return;
972  }
973  Num_ins++; //////////////////////////////////////////remove
974  OPInfo* opinfo = (OPInfo*)op;
975  ThreadData_t* td = GetTLS(threadID);
976  assert(rMem + wMem == 4);
977  uint64_t value;
978 
979  int sRegsCount = opinfo->sCount;
980  int immediateCount = opinfo->immeCount;
981 
982  if (movOrnot) {
983  //printf("MOV with 4 memory addresses evloved!\n");
984  } else {
985  uint64_t sValues[6];
986  int index = 0;
987 
988  for (int i = 0; i < sRegsCount; ++i)
989  sValues[index++] = getRegValueNum(opinfo->sRegs[i], threadID);
990 
991  for (int i = 0; i < immediateCount; ++i)
992  sValues[index++] = opinfo->immediates[i];
993 
994  int tRegsCount = opinfo->tCount;
995 
996  //value = gValue;/////////////////////////////
997 
998  switch (rMem) {
999  case (0):
1000 
1001  (void)checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
1002 
1003  gValue++;
1004  setMemValueNum((uint64_t)addr1, threadID, gValue);
1005  gValue++;
1006  setMemValueNum((uint64_t)addr2, threadID, gValue);
1007  gValue++;
1008  setMemValueNum((uint64_t)addr3, threadID, gValue);
1009  gValue++;
1010  setMemValueNum((uint64_t)addr4, threadID, gValue);
1011 
1012 
1013  for (int i = 0; i < tRegsCount; i++) {
1014  gValue++;
1015  setRegValueNum(opinfo->tRegs[i], td, gValue);
1016  }
1017  break;
1018 
1019  case (1):
1020  value = getMemValueNum((uint64_t)addr1, threadID);
1021  sValues[index++] = value;
1022 
1023  (void)checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
1024 
1025  gValue++;
1026  setMemValueNum((uint64_t)addr2, threadID, gValue);
1027  gValue++;
1028  setMemValueNum((uint64_t)addr3, threadID, gValue);
1029  gValue++;
1030  setMemValueNum((uint64_t)addr4, threadID, gValue);
1031 
1032  for (int i = 0; i < tRegsCount; i++) {
1033  gValue++;
1034  setRegValueNum(opinfo->tRegs[i], td, gValue);
1035  }
1036  break;
1037 
1038  case (2):
1039  value = getMemValueNum((uint64_t)addr1, threadID);
1040  sValues[index++] = value;
1041 
1042  value = getMemValueNum((uint64_t)addr2, threadID);
1043  sValues[index++] = value;
1044 
1045  (void)checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
1046 
1047  gValue++;
1048  setMemValueNum((uint64_t)addr3, threadID, gValue);
1049  gValue++;
1050  setMemValueNum((uint64_t)addr4, threadID, gValue);
1051 
1052  for (int i = 0; i < tRegsCount; i++) {
1053  gValue++;
1054  setRegValueNum(opinfo->tRegs[i], td, gValue);
1055  }
1056  break;
1057 
1058  case (3):
1059  value = getMemValueNum((uint64_t)addr1, threadID);
1060  sValues[index++] = value;
1061 
1062  value = getMemValueNum((uint64_t)addr2, threadID);
1063  sValues[index++] = value;
1064 
1065  value = getMemValueNum((uint64_t)addr3, threadID);
1066  sValues[index++] = value;
1067 
1068  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
1069 
1070  if (tRegsCount == 0) {
1071  setMemValueNum((uint64_t)addr4, threadID, value);
1072  } else {
1073  gValue++;
1074  setMemValueNum((uint64_t)addr4, threadID, gValue);
1075 
1076  for (int i = 0; i < tRegsCount; i++) {
1077  gValue++;
1078  setRegValueNum(opinfo->tRegs[i], td, gValue);
1079  }
1080  }
1081  break;
1082 
1083  case (4):
1084  value = getMemValueNum((uint64_t)addr1, threadID);
1085  sValues[index++] = value;
1086 
1087  value = getMemValueNum((uint64_t)addr2, threadID);
1088  sValues[index++] = value;
1089 
1090  value = getMemValueNum((uint64_t)addr3, threadID);
1091  sValues[index++] = value;
1092 
1093  value = getMemValueNum((uint64_t)addr4, threadID);
1094  sValues[index++] = value;
1095 
1096  value = checkOpcodeValueNum(opinfo->opCode, sValues, index, threadID, ip, opHandle);
1097 
1098  if (tRegsCount == 1) {
1099  setRegValueNum(opinfo->tRegs[0], td, value);
1100  } else {
1101  for (int i = 0; i < tRegsCount; i++) {
1102  gValue++;
1103  setRegValueNum(opinfo->tRegs[i], td, gValue);
1104  }
1105  }
1106  break;
1107 
1108  default:
1109  break;
1110  }
1111  }
1112 }
1113 
1114 // Is called for every instruction and instruments reads and writes
1115 VOID Instruction(INS ins, VOID* v, const uint32_t opHandle) {
1116  // Note: predicated instructions are correctly handled as given in PIN's sample example pinatrace.cpp
1117 
1118  /* Comment taken from PIN sample :
1119  Instruments memory accesses using a predicated call, i.e.
1120  the instrumentation is called iff the instruction will actually be executed.
1121 
1122  The IA-64 architecture has explicitly predicated instructions.
1123  On the IA-32 and Intel(R) 64 architectures conditional moves and REP
1124  prefixed instructions appear as predicated instructions in Pin. */
1125 
1126  if (IsIgnorableIns(ins))
1127  return;
1128 
1129  //if (INS_IsJZ(ins) || INS_IsJNZ(ins))
1130  // return;
1131 
1132  //**********************************************
1133  //compare the opcode and the value number of its operand, check the redundancy
1134  //what if there is only one REG operand
1135  THREADID threadID = PIN_ThreadId();
1136 
1137  UINT32 memOpCount = INS_MemoryOperandCount(ins);
1138 
1139  UINT32 rMemCount = 0;
1140  UINT32 wMemCount = 0;
1141  vector<int> rMem;
1142  vector<int> wMem;
1143 
1144  // TODO(preexisting-bug): the two calls below use INS_IsMemoryRead(ins)
1145  // and INS_IsMemoryWrite(ins) -- both are WHOLE-INSTRUCTION predicates,
1146  // not per-operand. Inside a per-operand loop they misclassify multi-
1147  // memop instructions (any memop bumps every counter). The correct
1148  // per-operand APIs are INS_MemoryOperandIsRead(ins, memOp) and
1149  // INS_MemoryOperandIsWritten(ins, memOp). Additionally, single-memop
1150  // read-modify-write instructions (xchg/xadd/cmpxchg/inc [mem]/...)
1151  // aren't dispatched to a matching handler and can crash the analysis
1152  // routine later. Fix requires (a) correct per-op predicates here AND
1153  // (b) a new valueNumberingMemRW analysis handler for RMW single memops
1154  // -- both belong with a broader RVN correctness pass, not this port.
1155  for (UINT32 memOp = 0; memOp < memOpCount; memOp++) {
1156  if (INS_IsMemoryRead(ins)) {
1157  rMemCount++;
1158  rMem.push_back(memOp);
1159  }
1160  if (INS_IsMemoryWrite(ins)) {
1161  wMemCount++;
1162  wMem.push_back(memOp);
1163  }
1164  }
1165 
1166  rMem.insert(rMem.end(), wMem.begin(), wMem.end());
1167 
1168  memOpCount = rMemCount + wMemCount;
1169 
1170  // Fetch opcode first so the early-return below doesn't leak an allocation.
1171  UINT32 opCode = INS_Opcode(ins);
1172  if (opCode == 82)
1173  return;
1174 
1175  OPInfo* opinfo = new OPInfo;
1176  opinfo->opCode = opCode;
1177 
1178  int sRegCount = 0;
1179  int immediateCount = 0;
1180  int tRegCount = 0;
1181 
1182  bool flag = false;
1183 
1184  if (IsMov(opinfo->opCode)) {
1185  UINT32 n = INS_OperandCount(ins);
1186 
1187  flag = true;
1188 
1189  for (UINT32 i = 0; i < n; ++i) {
1190  if (INS_OperandRead(ins, i)) {
1191  if (INS_OperandIsReg(ins, i)) {
1192  REG readReg = INS_OperandReg(ins, i);
1193  opinfo->sRegs[sRegCount++] = readReg;
1194 
1195  } else if (INS_OperandIsImmediate(ins, i)) {
1196  uint64_t immediate = INS_OperandImmediate(ins, i);
1197  opinfo->immediates[immediateCount++] = getImmediateValueNum(immediate, threadID);
1198  //opinfo->immediates.push_back(immediate);
1199  }
1200  }
1201  if (INS_OperandWritten(ins, i)) {
1202  if (INS_OperandIsReg(ins, i)) {
1203  REG writeReg = INS_OperandReg(ins, i);
1204  opinfo->tRegs[tRegCount++] = writeReg;
1205  }
1206  }
1207  }
1208  } else {
1209  UINT32 n = INS_OperandCount(ins);
1210 
1211  if (n < 1) {
1212  delete opinfo;
1213  return;
1214  }
1215 
1216  for (UINT32 i = 0; i < n; ++i) {
1217  if (INS_OperandRead(ins, i)) {
1218  if (INS_OperandIsReg(ins, i)) {
1219  REG readReg = INS_OperandReg(ins, i);
1220  opinfo->sRegs[sRegCount++] = readReg;
1221  } else if (INS_OperandIsImmediate(ins, i)) {
1222  uint64_t immediate = INS_OperandImmediate(ins, i);
1223  opinfo->immediates[immediateCount++] = getImmediateValueNum(immediate, threadID);
1224  //opinfo->immediates.push_back(immediate);
1225  }
1226  }
1227  if (INS_OperandWritten(ins, i)) {
1228  if (INS_OperandIsReg(ins, i)) {
1229  REG write = INS_OperandReg(ins, i);
1230  if (write != REG_GFLAGS)
1231  opinfo->tRegs[tRegCount++] = INS_OperandReg(ins, i);
1232  }
1233  }
1234  }
1235  }
1236 
1237  opinfo->sCount = sRegCount;
1238  opinfo->immeCount = immediateCount;
1239  opinfo->tCount = tRegCount;
1240  //totalI++;
1241 
1242  switch (memOpCount) {
1243  case (0):
1244  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)valueNumbering, IARG_PTR, opinfo, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1245  break;
1246  case (1):
1247  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)valueNumberingMem1, IARG_PTR, opinfo, IARG_MEMORYOP_EA, rMem[0], IARG_ADDRINT, rMemCount, IARG_ADDRINT, wMemCount, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1248  break;
1249  case (2):
1250  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)valueNumberingMem2, IARG_PTR, opinfo, IARG_MEMORYOP_EA, rMem[0], IARG_MEMORYOP_EA, rMem[1], IARG_ADDRINT, rMemCount, IARG_ADDRINT, wMemCount, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1251  break;
1252  case (3):
1253  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)valueNumberingMem3, IARG_PTR, opinfo, IARG_MEMORYOP_EA, rMem[0], IARG_MEMORYOP_EA, rMem[1], IARG_MEMORYOP_EA, rMem[2], IARG_ADDRINT, rMemCount, IARG_ADDRINT, wMemCount, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1254  break;
1255  case (4):
1256  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)valueNumberingMem4, IARG_PTR, opinfo, IARG_MEMORYOP_EA, rMem[0], IARG_MEMORYOP_EA, rMem[1], IARG_MEMORYOP_EA, rMem[2], IARG_MEMORYOP_EA, rMem[3], IARG_ADDRINT, rMemCount, IARG_ADDRINT, wMemCount, IARG_BOOL, flag, IARG_THREAD_ID, IARG_INST_PTR, IARG_UINT32, opHandle, IARG_END);
1257  break;
1258  default:
1259  assert(memOpCount < 5);
1260  delete opinfo; // Only reached in NDEBUG when the assert compiles out.
1261  break;
1262  }
1263 }
1264 
1265 //
1266 VOID ThreadStart(THREADID threadid, CONTEXT* ctxt, INT32 flags, VOID* v) {
1267  // Get the stack base address:
1268  ThreadData_t* tdata = new ThreadData_t();
1269  //tdata->opcodeMap.set_empty_key(-1);
1270  //tdata->redundantMap.set_empty_key(-1);
1271 
1272  // Label will be NULL
1273  PIN_SetThreadData(tls_key, tdata, threadid);
1274 }
1275 
1277  uint32_t context1;
1278  uint32_t context2;
1279 
1280  bool operator==(const MergedRedundantInfo& x) const {
1281  return this->context1 == x.context1 && this->context2 == x.context2;
1282  }
1283 
1284  bool operator<(const MergedRedundantInfo& x) const {
1285  return (this->context1 < x.context1) ||
1286  (this->context1 == x.context1 && this->context2 < x.context2);
1287  }
1288 };
1289 
1292  uint64_t count;
1293 };
1294 
1295 
1297  return first.count > second.count;
1298 }
1299 
1300 static void DumpInfo(uint32_t oldIndex, uint32_t newIndex) {
1301  PIN_LockClient();
1302  fprintf(gTraceFile, "\n ----------");
1303  PrintFullCallingContext(newIndex);
1304  fprintf(gTraceFile, "\n *****is redundant because of*****");
1305  PrintFullCallingContext(oldIndex);
1306  fprintf(gTraceFile, "\n ----------");
1307  PIN_UnlockClient();
1308 }
1309 
1310 VOID ImageUnload(IMG img, VOID* v) {
1311  fprintf(gTraceFile, "\nUnloading %s", IMG_Name(img).c_str());
1312  //printf("size of the map:%u ---- size of instructions:%u\n",total,totalI);
1313  ThreadData_t* td = GetTLS(PIN_ThreadId());
1314  PIN_MutexLock(&gMutex);
1315 
1316  unordered_map<uint64_t, uint64_t>::iterator mapIt = td->redundantMap.begin();
1317  map<MergedRedundantInfo, uint64_t> mergedRedundantInfoMap;
1318  map<MergedRedundantInfo, uint64_t>::iterator tmpIt;
1319 
1320  // Push it all into a List so that it can be sorted.
1321  // No 2 pairs will ever be same since they are unique across threads
1322  PIN_LockClient();
1323  for (; mapIt != td->redundantMap.end(); mapIt++) {
1324  uint64_t hash = mapIt->first;
1325  uint32_t ctxt1 = (hash >> 32);
1326  uint32_t ctxt2 = (hash & 0xffffffff);
1327  for (tmpIt = mergedRedundantInfoMap.begin(); tmpIt != mergedRedundantInfoMap.end(); tmpIt++) {
1328  bool ct1 = IsSameSourceLine(ctxt1, tmpIt->first.context1);
1329  bool ct2 = IsSameSourceLine(ctxt2, tmpIt->first.context2);
1330 
1331  if (ct1 && ct2) {
1332  tmpIt->second += mapIt->second;
1333  break;
1334  }
1335  }
1336  if (tmpIt == mergedRedundantInfoMap.end()) {
1337  MergedRedundantInfo tmpMergedRedundantInfo;
1338  tmpMergedRedundantInfo.context1 = ctxt1;
1339  tmpMergedRedundantInfo.context2 = ctxt2;
1340  mergedRedundantInfoMap[tmpMergedRedundantInfo] = mapIt->second;
1341  }
1342  }
1343  PIN_UnlockClient();
1344 
1345  map<MergedRedundantInfo, uint64_t>::iterator it = mergedRedundantInfoMap.begin();
1346 
1347  list<RedundantInfoForPresentation> gRedundantList;
1348 
1349  for (; it != mergedRedundantInfoMap.end(); it++) {
1350  if (it->second >= MAX_DEAD_CONTEXTS_TO_LOG) {
1351  RedundantInfoForPresentation redundantInfoForPresentation;
1352  redundantInfoForPresentation.pMergedRedundantInfo = &(it->first);
1353  redundantInfoForPresentation.count = it->second;
1354  gRedundantList.push_back(redundantInfoForPresentation);
1355  }
1356  }
1357 
1358  // clear dead map now
1359  td->redundantMap.clear();
1360  td->immediateMap.clear();
1361  td->opcodeMap.clear();
1362  gRedundantList.sort(MergedRedundantInfoComparer);
1363 
1364  //present and delete all
1365  list<RedundantInfoForPresentation>::iterator dipIter = gRedundantList.begin();
1366  int redundancyWrite = 0;
1367  uint64_t Topredundant = 0;
1368  for (; dipIter != gRedundantList.end(); dipIter++) {
1369  // Print just first MAX_DEAD_CONTEXTS_TO_LOG contexts
1370  if (redundancyWrite < MAX_LOG_NUM) {
1371  redundancyWrite++;
1372  fprintf(gTraceFile, "\nCTXT_REDUNDANT_CNT:%lu", dipIter->count);
1373  DumpInfo(dipIter->pMergedRedundantInfo->context1, dipIter->pMergedRedundantInfo->context2);
1374  Topredundant += dipIter->count;
1375  }
1376  }
1377 
1378  fprintf(gTraceFile, "Redundant instructions: %lu Total instruction: %lu Redundancy: %.5f Top redundancy: %lu rate: %.5f\n", Num_redundant, Num_ins, (double)Num_redundant / Num_ins, Topredundant, (double)Topredundant / Num_redundant);
1379  gRedundantList.clear();
1380 
1381  PIN_MutexUnlock(&gMutex);
1382 }
1383 
1384 VOID RegDeadFini(INT32 code, VOID* v) {
1385  fprintf(gTraceFile, "\nfinish");
1386 }
1387 
1388 static INT32 Usage() {
1389  PIN_ERROR("PinTool for runtime value numbering (RVN).\n" + KNOB_BASE::StringKnobSummary() + "\n");
1390  return -1;
1391 }
1392 
1393 // Initialized the needed data structures before launching the target program
1394 void InitValueNumbering(int argc, char* argv[]) {
1395  // Create output file
1396 
1397  char name[MAX_FILE_PATH] = "ValueNumbering.out.";
1398  char* envPath = getenv("OUTPUT_FILE");
1399  if (envPath) {
1400  // assumes max of MAX_FILE_PATH
1401  snprintf(name, sizeof(name), "%s", envPath);
1402  }
1403  gethostname(name + strlen(name), MAX_FILE_PATH - strlen(name));
1404  pid_t pid = getpid();
1405  sprintf(name + strlen(name), "%d", pid);
1406  cerr << "\n Creating info file at:" << name << "\n";
1407 
1408  gTraceFile = fopen(name, "w");
1409  // print the arguments passed
1410  fprintf(gTraceFile, "\n");
1411  for (int i = 0; i < argc; i++) {
1412  fprintf(gTraceFile, "%s ", argv[i]);
1413  }
1414  fprintf(gTraceFile, "\n");
1415 
1416  // Obtain a key for TLS storage.
1417  tls_key = PIN_CreateThreadDataKey(nullptr);
1418 
1419  //initilize the global value used for value numbering
1420  gValue = 0;
1421  lastGValue = 0;
1422  // Register ThreadStart to be called when a thread starts.
1423  PIN_AddThreadStartFunction(ThreadStart, nullptr);
1424 
1425  // INitialize the mutex
1426  PIN_MutexInit(&gMutex);
1427 
1428 
1429  // Register ImageUnload to be called when the image is unloaded
1430  IMG_AddUnloadFunction(ImageUnload, nullptr);
1431 
1432  // Register Fini to be called when the application exits
1433  PIN_AddFiniFunction(RegDeadFini, nullptr);
1434 }
1435 
1436 
1437 // Main for Value Numbering, initialize the tool, register instrumentation functions and call the target program.
1438 
1439 int main(int argc, char* argv[]) {
1440  // Initialize PIN
1441  if (PIN_Init(argc, argv))
1442  return Usage();
1443 
1444  // Initialize Symbols, we need them to report functions and lines
1445  PIN_InitSymbols();
1446 
1447  // Intialize Value Numbering
1448  InitValueNumbering(argc, argv);
1449 
1450  // Init CCTlib
1452 
1453 
1454  // When line level info in not needed, simplt instrument each instruction
1455  //INS_AddInstrumentFunction(, 0);
1456 
1457 
1458  // Launch program now
1459  PIN_StartProgram();
1460  return 0;
1461 }
#define INTERESTING_INS_ALL
Definition: cctlib.H:85
unordered_map< uint64_t, uint64_t >::iterator redundantMapIt
unordered_map< uint64_t, OPMap > opcodeMap
unordered_map< uint64_t, OPMap >::iterator opcodeMapIt
unordered_map< uint64_t, uint64_t >::iterator immediateMapIt
unordered_map< uint64_t, uint64_t > redundantMap
unordered_map< uint64_t, uint64_t > immediateMap
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 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
static BOOL INS_IsMaskedJump(INS ins)
uint8_t value[MAX_WRITE_OP_LENGTH]
void * address
uint64_t checkOpcodeValueNum(int opcode, uint64_t svalues[], int sCount, THREADID threadid, void *ip, const uint32_t opHandle)
void deleteString(uint64_t key, ThreadData_t *td)
static uint8_t ** gL1PageTable[LEVEL_1_PAGE_TABLE_SIZE]
VOID valueNumberingMem4(void *op, void *addr1, void *addr2, void *addr3, void *addr4, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void *ip, const uint32_t opHandle)
int main(int argc, char *argv[])
uint64_t immediates[MAX_OPERAND]
VOID valueNumbering(void *op, bool movOrnot, THREADID threadid, void *ip, const uint32_t opHandle)
uint64_t getRegValueNum(REG reg, THREADID threadid)
#define LEVEL_2_PAGE_TABLE_SIZE
VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
#define LEVEL_1_PAGE_TABLE_SLOT(addr)
struct opcodeInfo { OPCODE opCode OPInfo
VOID CleanValueNumbers(THREADID threadID)
VOID Instruction(INS ins, VOID *v, const uint32_t opHandle)
static void DumpInfo(uint32_t oldIndex, uint32_t newIndex)
static uint64_t gValue
static INT32 Usage()
VOID setRegValueNum(REG reg, ThreadData_t *td, uint64_t value)
#define PAGE_OFFSET(addr)
REG tRegs[MAX_OPERAND]
void recordRedundantOperation(uint32_t deadCtxt, uint32_t killerCtxt, ThreadData_t *td)
VOID valueNumberingMem3(void *op, void *addr1, void *addr2, void *addr3, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void *ip, const uint32_t opHandle)
#define MAX_DEAD_CONTEXTS_TO_LOG
uint64_t getImmediateValueNum(uint64_t immediate, THREADID threadid)
REG sRegs[MAX_OPERAND]
void removeOldstring(void *ip, uint64_t nValue, ThreadData_t *td)
VOID RegDeadFini(INT32 code, VOID *v)
bool IsCommutativeOp(int opcode)
static void sortSvalues(uint64_t *svalues, int count)
VOID setMemValueNum(uint64_t addr, THREADID threadid, uint64_t value)
bool MergedRedundantInfoComparer(const RedundantInfoForPresentation &first, const RedundantInfoForPresentation &second)
VOID valueNumberingMem1(void *op, void *addr, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void *ip, const uint32_t opHandle)
static TLS_KEY tls_key
static uint8_t * GetOrCreateShadowBaseAddress(uint64_t address)
bool IsMov(int opcode)
uint64_t getMemValueNum(uint64_t addr, THREADID threadid)
VOID ImageUnload(IMG img, VOID *v)
uint64_t Num_redundant
VOID valueNumberingMem2(void *op, void *addr1, void *addr2, uint32_t rMem, uint32_t wMem, bool movOrnot, THREADID threadID, void *ip, const uint32_t opHandle)
ThreadData_t * GetTLS(THREADID threadid)
bool IsIgnorableIns(INS ins)
#define LEVEL_1_PAGE_TABLE_SIZE
struct opMap { uint64_t vNum OPMap
uint64_t Num_instructions
static PIN_MUTEX gMutex
void UpdateValue(uint32_t reg, uint64_t value, ThreadData_t *td)
void InitValueNumbering(int argc, char *argv[])
void checkMovValueNum(int opcode, uint64_t svalue, uint64_t target, THREADID threadid, void *ip, const uint32_t opHandle)
#define LEVEL_2_PAGE_TABLE_SLOT(addr)
bool operator<(const MergedRedundantInfo &x) const
bool operator==(const MergedRedundantInfo &x) const
const MergedRedundantInfo * pMergedRedundantInfo