CCTLib
Calling-context and data-object attribution library for Intel Pin
deadspy_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 #define __STDC_FORMAT_MACROS
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "pin.H"
10 #include <map>
11 #include <unordered_map>
12 #include <list>
13 #include <inttypes.h>
14 #include <stdint.h>
15 #include <sys/types.h>
16 #include <sys/ipc.h>
17 #include <sys/shm.h>
18 #include <semaphore.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <iostream>
22 #include <locale>
23 #include <unistd.h>
24 #include <sys/syscall.h>
25 #include <assert.h>
26 #include <sys/mman.h>
27 #include <exception>
28 #include <sys/time.h>
29 #include <signal.h>
30 #include <string.h>
31 #include <setjmp.h>
32 #include <sstream>
33 #include <fstream>
34 // Need GOOGLE sparse hash tables
35 #include <google/sparse_hash_map>
36 #include <google/dense_hash_map>
37 using namespace std;
38 
39 
40 #include "cctlib.H"
41 using namespace PinCCTLib;
42 
43 
44 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
45 #define MAP_ANONYMOUS MAP_ANON
46 #endif
47 
48 // ensures CONTINUOUS_DEADINFO
49 
50 #define CONTINUOUS_DEADINFO
51 
52 
53 #define MAX_CCT_PRINT_DEPTH (20)
54 #define MAX_FILE_PATH (200)
55 #ifndef MAX_DEAD_CONTEXTS_TO_LOG
56 #define MAX_DEAD_CONTEXTS_TO_LOG (1000)
57 #endif //MAX_DEAD_CONTEXTS_TO_LOG
58 
59 // 64KB shadow pages
60 #define PAGE_OFFSET_BITS (16LL)
61 #define PAGE_OFFSET(addr) (addr & 0xFFFF)
62 #define PAGE_OFFSET_MASK (0xFFFF)
63 
64 #undef PAGE_SIZE
65 #define PAGE_SIZE (1 << PAGE_OFFSET_BITS)
66 
67 // 2 level page table
68 #define PTR_SIZE (sizeof(void*))
69 #define LEVEL_1_PAGE_TABLE_BITS (20)
70 #define LEVEL_1_PAGE_TABLE_ENTRIES (1 << LEVEL_1_PAGE_TABLE_BITS)
71 #define LEVEL_1_PAGE_TABLE_SIZE (LEVEL_1_PAGE_TABLE_ENTRIES * PTR_SIZE)
72 
73 #define LEVEL_2_PAGE_TABLE_BITS (12)
74 #define LEVEL_2_PAGE_TABLE_ENTRIES (1 << LEVEL_2_PAGE_TABLE_BITS)
75 #define LEVEL_2_PAGE_TABLE_SIZE (LEVEL_2_PAGE_TABLE_ENTRIES * PTR_SIZE)
76 
77 #define LEVEL_1_PAGE_TABLE_SLOT(addr) ((((uint64_t)addr) >> (LEVEL_2_PAGE_TABLE_BITS + PAGE_OFFSET_BITS)) & 0xfffff)
78 #define LEVEL_2_PAGE_TABLE_SLOT(addr) ((((uint64_t)addr) >> (PAGE_OFFSET_BITS)) & 0xFFF)
79 
80 
81 // have R, W representative macros
82 #define READ_ACTION (0)
83 #define WRITE_ACTION (0xff)
84 
85 #define ONE_BYTE_READ_ACTION (0)
86 #define TWO_BYTE_READ_ACTION (0)
87 #define FOUR_BYTE_READ_ACTION (0)
88 #define EIGHT_BYTE_READ_ACTION (0)
89 
90 #define ONE_BYTE_WRITE_ACTION (0xff)
91 #define TWO_BYTE_WRITE_ACTION (0xffff)
92 #define FOUR_BYTE_WRITE_ACTION (0xffffffff)
93 #define EIGHT_BYTE_WRITE_ACTION (0xffffffffffffffff)
94 
95 
96 #ifdef TESTING_BYTES
97 uint64_t gFullyKilling1;
98 uint64_t gFullyKilling2;
99 uint64_t gFullyKilling4;
100 uint64_t gFullyKilling8;
101 uint64_t gFullyKilling10;
102 uint64_t gFullyKilling16;
103 uint64_t gFullyKillingLarge;
104 
105 uint64_t gPartiallyKilling1;
106 uint64_t gPartiallyKilling2;
107 uint64_t gPartiallyKilling4;
108 uint64_t gPartiallyKilling8;
109 uint64_t gPartiallyKilling10;
110 uint64_t gPartiallyKilling16;
111 uint64_t gPartiallyKillingLarge;
112 
113 uint64_t gPartiallyDeadBytes1;
114 uint64_t gPartiallyDeadBytes2;
115 uint64_t gPartiallyDeadBytes4;
116 uint64_t gPartiallyDeadBytes8;
117 uint64_t gPartiallyDeadBytes10;
118 uint64_t gPartiallyDeadBytes16;
119 uint64_t gPartiallyDeadBytesLarge;
120 #endif // end TESTING_BYTES
121 
122 
123 // All fwd declarations
124 
125 struct DeadInfo;
127 std::fstream topnStream;
128 
129 
130 struct MergedDeadInfo;
132 
133 // should become TLS
143 };
144 
145 
146 struct DeadInfo {
147  void* firstIP;
148  void* secondIP;
149  uint64_t count;
150 };
151 
152 // key for accessing TLS storage in the threads. initialized once in main()
153 static TLS_KEY client_tls_key;
154 
155 struct {
156  char dummy1[128];
158  char dummy2[128];
160 
161 
162 KNOB<UINT32> KnobTopN(KNOB_MODE_WRITEONCE, "pintool", "d", "0", "how many top contexts to log");
163 
164 
165 // function to access thread-specific data
166 inline DeadSpyThreadData* ClientGetTLS(const THREADID threadId) {
167  DeadSpyThreadData* tdata =
168  static_cast<DeadSpyThreadData*>(PIN_GetThreadData(client_tls_key, threadId));
169  return tdata;
170 }
171 
172 #if 0
173 volatile bool gDSLock;
174 inline VOID TakeLock() {
175  do {
176  while(gDSLock);
177  } while(!__sync_bool_compare_and_swap(&gDSLock, 0, 1));
178 }
179 
180 inline VOID ReleaseLock() {
181  gDSLock = 0;
182 }
183 #endif
184 
185 
186 inline void InitThreadData(DeadSpyThreadData* const tdata) {
187  tdata->g1ByteWriteInstrCount = 0;
188  tdata->g2ByteWriteInstrCount = 0;
189  tdata->g4ByteWriteInstrCount = 0;
190  tdata->g8ByteWriteInstrCount = 0;
191  tdata->g10ByteWriteInstrCount = 0;
192  tdata->g16ByteWriteInstrCount = 0;
193  tdata->gLargeByteWriteInstrCount = 0;
194  tdata->gLargeByteWriteByteCount = 0;
195 }
196 
197 PIN_LOCK lock;
198 
199 inline bool DeadInfoComparer(const DeadInfo& first, const DeadInfo& second);
200 inline bool IsValidIP(DeadInfo di);
201 
202 
204 
205 //map < void *, Status > MemState;
206 #if defined(CONTINUOUS_DEADINFO)
207 unordered_map<uint64_t, uint64_t> DeadMap;
208 unordered_map<uint64_t, uint64_t>::iterator gDeadMapIt;
209 //dense_hash_map<uint64_t, uint64_t> DeadMap;
210 //dense_hash_map<uint64_t, uint64_t>::iterator gDeadMapIt;
211 //sparse_hash_map<uint64_t, uint64_t> DeadMap;
212 //sparse_hash_map<uint64_t, uint64_t>::iterator gDeadMapIt;
213 #else // no defined(CONTINUOUS_DEADINFO)
214 dense_hash_map<uint64_t, DeadInfo> DeadMap;
215 dense_hash_map<uint64_t, DeadInfo>::iterator gDeadMapIt;
216 //unordered_map<uint64_t, DeadInfo> DeadMap;
217 //unordered_map<uint64_t, DeadInfo>::iterator gDeadMapIt;
218 #endif //end defined(CONTINUOUS_DEADINFO)
219 
220 #ifdef GATHER_STATS
221 FILE* statsFile;
222 #endif //end GATHER_STATS
223 
224 uint64_t gTotalDead = 0;
225 #ifdef MULTI_THREADED
226 uint64_t gTotalMTDead = 0;
227 #endif // end MULTI_THREADED
228 
229 
230 volatile uint32_t gClientNumThreads;
231 
232 VOID Instruction(INS ins, VOID* v, const uint32_t opaqueHandle);
233 
234 // The following functions accummulates the number of bytes written in this basic block for the calling thread categorized by the write size.
235 
236 inline VOID InstructionContributionOfBBL1Byte(uint32_t count, THREADID threadId) {
237  ClientGetTLS(threadId)->g1ByteWriteInstrCount += count;
238 }
239 inline VOID InstructionContributionOfBBL2Byte(uint32_t count, THREADID threadId) {
240  ClientGetTLS(threadId)->g2ByteWriteInstrCount += count;
241 }
242 inline VOID InstructionContributionOfBBL4Byte(uint32_t count, THREADID threadId) {
243  ClientGetTLS(threadId)->g4ByteWriteInstrCount += count;
244 }
245 inline VOID InstructionContributionOfBBL8Byte(uint32_t count, THREADID threadId) {
246  ClientGetTLS(threadId)->g8ByteWriteInstrCount += count;
247 }
248 inline VOID InstructionContributionOfBBL10Byte(uint32_t count, THREADID threadId) {
249  ClientGetTLS(threadId)->g16ByteWriteInstrCount += count;
250 }
251 inline VOID InstructionContributionOfBBL16Byte(uint32_t count, THREADID threadId) {
252  ClientGetTLS(threadId)->g16ByteWriteInstrCount += count;
253 }
254 inline VOID InstructionContributionOfBBLLargeByte(uint32_t count, THREADID threadId) {
255  ClientGetTLS(threadId)->gLargeByteWriteInstrCount += count;
256 }
257 
258 
259 // Instrument a trace, take the first instruction in the first BBL and insert the analysis function before that
260 static void InstrumentTrace(TRACE trace, void* f) {
261  // Insert counting code
262  for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
263  uint32_t inst1ByteSize = 0;
264  uint32_t inst2ByteSize = 0;
265  uint32_t inst4ByteSize = 0;
266  uint32_t inst8ByteSize = 0;
267  uint32_t inst10ByteSize = 0;
268  uint32_t inst16ByteSize = 0;
269  uint32_t instLargeByteSize = 0;
270 
271  for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {
272  // instrument instruction, called by the call back
273  // Instruction(ins, 0);
274  if (INS_IsMemoryWrite(ins)) {
275  // get instruction info in trace
276  // INS_MemoryWriteSize was removed in Pin 4.x; use INS_MemoryOperandSize
277  // over all write operands (typically a single operand for stores).
278  USIZE writeSize = 0;
279  UINT32 nOps = INS_MemoryOperandCount(ins);
280  for (UINT32 op = 0; op < nOps; op++) {
281  if (INS_MemoryOperandIsWritten(ins, op)) {
282  writeSize += INS_MemoryOperandSize(ins, op);
283  }
284  }
285 
286  switch (writeSize) {
287  case 1:
288  inst1ByteSize++;
289  break;
290 
291  case 2:
292  inst2ByteSize++;
293  break;
294 
295  case 4:
296  inst4ByteSize++;
297  break;
298 
299  case 8:
300  inst8ByteSize++;
301  break;
302 
303  case 10:
304  inst10ByteSize++;
305  break;
306 
307  case 16:
308  inst16ByteSize++;
309  break;
310 
311  default:
312  instLargeByteSize += writeSize;
313  //assert(0 && "NOT IMPLEMENTED ... SHOULD NOT SEE large writes in trace");
314  }
315  }
316  }
317 
318  // Insert a call to corresponding count routines before every bbl, passing the number of instructions
319 
320  // Increment Inst count by trace
321  if (inst1ByteSize)
322  BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)InstructionContributionOfBBL1Byte, IARG_UINT32, inst1ByteSize, IARG_THREAD_ID, IARG_END);
323 
324  if (inst2ByteSize)
325  BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)InstructionContributionOfBBL2Byte, IARG_UINT32, inst2ByteSize, IARG_THREAD_ID, IARG_END);
326 
327  if (inst4ByteSize)
328  BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)InstructionContributionOfBBL4Byte, IARG_UINT32, inst4ByteSize, IARG_THREAD_ID, IARG_END);
329 
330  if (inst8ByteSize)
331  BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)InstructionContributionOfBBL8Byte, IARG_UINT32, inst8ByteSize, IARG_THREAD_ID, IARG_END);
332 
333  if (inst10ByteSize)
334  BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)InstructionContributionOfBBL10Byte, IARG_UINT32, inst10ByteSize, IARG_THREAD_ID, IARG_END);
335 
336  if (inst16ByteSize)
337  BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)InstructionContributionOfBBL16Byte, IARG_UINT32, inst16ByteSize, IARG_THREAD_ID, IARG_END);
338 
339  if (instLargeByteSize)
340  BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)InstructionContributionOfBBLLargeByte, IARG_UINT32, instLargeByteSize, IARG_THREAD_ID, IARG_END);
341  }
342 }
343 
344 
345 // Given a address generated by the program, returns the corresponding shadow address FLOORED to PAGE_SIZE
346 // If the shadow page does not exist a new one is MMAPed
347 
348 inline uint8_t* GetOrCreateShadowBaseAddress(void* address) {
349  // No entries at all ?
350  uint8_t* shadowPage;
351  uint8_t*** l1Ptr = &gL1PageTable[LEVEL_1_PAGE_TABLE_SLOT(address)];
352 
353  if (*l1Ptr == nullptr) {
354  *l1Ptr = (uint8_t**)calloc(1, LEVEL_2_PAGE_TABLE_SIZE);
355  shadowPage = (*l1Ptr)[LEVEL_2_PAGE_TABLE_SLOT(address)] = (uint8_t*)mmap(nullptr, PAGE_SIZE * (1 + sizeof(uint32_t)), PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
356  } else if ((shadowPage = (*l1Ptr)[LEVEL_2_PAGE_TABLE_SLOT(address)]) == nullptr) {
357  shadowPage = (*l1Ptr)[LEVEL_2_PAGE_TABLE_SLOT(address)] = (uint8_t*)mmap(nullptr, PAGE_SIZE * (1 + sizeof(uint32_t)), PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
358  }
359 
360  return shadowPage;
361 }
362 
363 // Given a address generated by the program, returns the corresponding shadow address FLOORED to PAGE_SIZE
364 // If the shadow page does not exist none is created instead 0 is returned
365 
366 inline uint8_t* GetShadowBaseAddress(void* address) {
367  // No entries at all ?
368  uint8_t* shadowPage;
369  uint8_t*** l1Ptr = &gL1PageTable[LEVEL_1_PAGE_TABLE_SLOT(address)];
370 
371  if (*l1Ptr == nullptr) {
372  return nullptr;
373  } else if ((shadowPage = (*l1Ptr)[LEVEL_2_PAGE_TABLE_SLOT(address)]) == nullptr) {
374  return nullptr;
375  }
376 
377  return shadowPage;
378 }
379 
380 
381 // make 64bit hash from 2 32bit deltas from
382 // remove lower 3 bits so that when we need more than 4 GB HASH still continues to work
383 
384 #if 0
385 #define CONTEXT_HASH_128BITS_TO_64BITS(curCtxt, oldCtxt, hashVar) \
386  { \
387  uint64_t key = (uint64_t)(((void**)oldCtxt) - gPreAllocatedContextBuffer); \
388  hashVar = key << 32; \
389  key = (uint64_t)(((void**)curCtxt) - gPreAllocatedContextBuffer); \
390  hashVar |= key; \
391  }
392 
393 #else
394 
395 #define CONTEXT_HASH_128BITS_TO_64BITS(curCtxt, oldCtxt, hashVar) \
396  { \
397  uint64_t key = (uint64_t)(oldCtxt); \
398  hashVar = key << 32; \
399  key = (uint64_t)(curCtxt); \
400  hashVar |= key; \
401  }
402 
403 #endif
404 
405 
406 #define OLD_CTXT (*lastIP)
407 // defined in cct lib: #define CUR_CTXT_INDEX (&(tData->gCurrentIPNode[tData->curSlotNo]))
408 
409 
410 #if defined(CONTINUOUS_DEADINFO)
411 
412 #define DECLARE_HASHVAR(name) uint64_t name
413 
414 #define REPORT_DEAD(curCtxt, lastCtxt, hashVar, size) \
415  do { \
416  CONTEXT_HASH_128BITS_TO_64BITS(curCtxt, lastCtxt, hashVar) \
417  if ((gDeadMapIt = DeadMap.find(hashVar)) == DeadMap.end()) { \
418  DeadMap.insert(std::pair<uint64_t, uint64_t>(hashVar, size)); \
419  } else { \
420  (gDeadMapIt->second) += size; \
421  } \
422  } while (0)
423 
424 #else // no defined(CONTINUOUS_DEADINFO)
425 #define DECLARE_HASHVAR(name) uint64_t name
426 
427 #define REPORT_DEAD(curCtxt, lastCtxt, hashVar, size) \
428  do { \
429  CONTEXT_HASH_128BITS_TO_64BITS(curCtxt, lastCtxt, hashVar) \
430  if ((gDeadMapIt = DeadMap.find(hashVar)) == DeadMap.end()) { \
431  DeadInfo deadInfo = {lastCtxt, curCtxt, size}; \
432  DeadMap.insert(std::pair<uint64_t, DeadInfo>(hashVar, deadInfo)); \
433  } else { \
434  (gDeadMapIt->second.count) += size; \
435  } \
436  } while (0)
437 
438 #endif // end defined(CONTINUOUS_DEADINFO)
439 
440 #define REPORT_IF_DEAD(mask, curCtxt, lastCtxt, hashVar) \
441  do { \
442  if (state & (mask)) { \
443  REPORT_DEAD(curCtxt, lastCtxt, hashVar, 1); \
444  } \
445  } while (0)
446 
447 
448 #ifdef TESTING_BYTES
449 #define RecordNByteMemWrite(type, size, sizeSTR) \
450  do { \
451  uint8_t* status = GetOrCreateShadowBaseAddress(addr); \
452  if (PAGE_OFFSET((uint64_t)addr) < (PAGE_OFFSET_MASK - size - 2)) { \
453  type state = *((type*)(status + PAGE_OFFSET((uint64_t)addr))); \
454  if (state != sizeSTR##_BYTE_READ_ACTION) { \
455  if (state == sizeSTR##_BYTE_WRITE_ACTION) { \
456  gFullyKilling##size++; \
457  } else { \
458  gPartiallyKilling##size++; \
459  for (type s = state; s != 0; s >>= 8) \
460  if (s & 0xff) \
461  gPartiallyDeadBytes##size++; \
462  } \
463  } \
464  *((type*)(status + PAGE_OFFSET((uint64_t)addr))) = sizeSTR##_BYTE_WRITE_ACTION; \
465  } else { \
466  type state = *((uint8_t*)(status + PAGE_OFFSET((uint64_t)addr))); \
467  *((uint8_t*)(status + PAGE_OFFSET((uint64_t)addr))) = ONE_BYTE_WRITE_ACTION; \
468  uint8_t deadBytes = state == ONE_BYTE_WRITE_ACTION ? 1 : 0; \
469  for (uint8_t i = 1; i < size; i++) { \
470  status = GetOrCreateShadowBaseAddress(((char*)addr) + i); \
471  state = *((uint8_t*)(status + PAGE_OFFSET((((uint64_t)addr) + i)))); \
472  if (state == ONE_BYTE_WRITE_ACTION) \
473  deadBytes++; \
474  *((uint8_t*)(status + PAGE_OFFSET((((uint64_t)addr) + i)))) = ONE_BYTE_WRITE_ACTION; \
475  } \
476  if (deadBytes == size) \
477  gFullyKilling##size++; \
478  else if (deadBytes) { \
479  gPartiallyKilling##size++; \
480  gPartiallyDeadBytes##size += deadBytes; \
481  } \
482  } \
483  } while (0)
484 
485 #endif // end TESTING_BYTES
486 
487 
488 // Analysis routines to update the shadow memory for different size READs and WRITEs
489 
490 
491 VOID Record1ByteMemRead(VOID* addr) {
492  uint8_t* status = GetShadowBaseAddress(addr);
493 
494  // status == 0 if not created.
495  if (status) {
496  // NOT NEEDED status->lastIP = ip;
497  *(status + PAGE_OFFSET((uint64_t)addr)) = ONE_BYTE_READ_ACTION;
498  }
499 }
500 
501 
502 #ifdef TESTING_BYTES
503 inline VOID Record1ByteMemWrite(VOID* addr) {
504  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
505 
506  if (*(status + PAGE_OFFSET((uint64_t)addr)) == ONE_BYTE_WRITE_ACTION) {
507  gFullyKilling1++;
508  }
509 
510  *(status + PAGE_OFFSET((uint64_t)addr)) = ONE_BYTE_WRITE_ACTION;
511 }
512 
513 #else // no TESTING_BYTES
514 VOID Record1ByteMemWrite(VOID* addr, const uint32_t opaqueHandle, THREADID threadId) {
515  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
516  const uint32_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
517  uint32_t* lastIP = (uint32_t*)(status + PAGE_SIZE + PAGE_OFFSET((uint64_t)addr) * sizeof(uint32_t));
518 
519  if (*(status + PAGE_OFFSET((uint64_t)addr)) == ONE_BYTE_WRITE_ACTION) {
520  DECLARE_HASHVAR(myhash);
521  REPORT_DEAD(curCtxtHandle, OLD_CTXT, myhash, 1);
522  } else {
523  *(status + PAGE_OFFSET((uint64_t)addr)) = ONE_BYTE_WRITE_ACTION;
524  }
525 
526  *lastIP = curCtxtHandle;
527 }
528 #endif // end TESTING_BYTES
529 
530 inline VOID Record1ByteMemWriteWithoutDead(VOID* addr, const uint32_t opaqueHandle, THREADID threadId) {
531  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
532  const uint32_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
533  uint32_t* lastIP = (uint32_t*)(status + PAGE_SIZE + PAGE_OFFSET((uint64_t)addr) * sizeof(uint32_t));
534  *(status + PAGE_OFFSET((uint64_t)addr)) = ONE_BYTE_WRITE_ACTION;
535  *lastIP = curCtxtHandle;
536 }
537 
538 
539 VOID Record2ByteMemRead(VOID* addr) {
540  uint8_t* status = GetShadowBaseAddress(addr);
541 
542  // status == 0 if not created.
543  if (PAGE_OFFSET((uint64_t)addr) != PAGE_OFFSET_MASK) {
544  if (status) {
545  *((uint16_t*)(status + PAGE_OFFSET((uint64_t)addr))) = TWO_BYTE_READ_ACTION;
546  }
547  } else {
548  if (status) {
550  }
551 
552  status = GetShadowBaseAddress(((char*)addr) + 1);
553 
554  if (status) {
556  }
557  }
558 }
559 #ifdef TESTING_BYTES
560 VOID Record2ByteMemWrite(VOID* addr) {
561  RecordNByteMemWrite(uint16_t, 2, TWO);
562 }
563 #else // no bytes test
564 VOID Record2ByteMemWrite(VOID* addr, const uint32_t opaqueHandle, THREADID threadId) {
565  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
566  const uint32_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
567 
568  // status == 0 if not created.
569  if (PAGE_OFFSET((uint64_t)addr) != PAGE_OFFSET_MASK) {
570  uint32_t* lastIP = (uint32_t*)(status + PAGE_SIZE + PAGE_OFFSET((uint64_t)addr) * sizeof(uint32_t));
571  uint16_t state = *((uint16_t*)(status + PAGE_OFFSET((uint64_t)addr)));
572 
573  if (state != TWO_BYTE_READ_ACTION) {
574  DECLARE_HASHVAR(myhash);
575 
576  // fast path where all bytes are dead by same context
577  if (state == TWO_BYTE_WRITE_ACTION && lastIP[0] == lastIP[1]) {
578  REPORT_DEAD(curCtxtHandle, (*lastIP), myhash, 2);
579  // State is already written, so no need to dead write in a tool that detects dead writes
580  } else {
581  // slow path
582  // byte 1 dead ?
583  REPORT_IF_DEAD(0x00ff, curCtxtHandle, lastIP[0], myhash);
584  // byte 2 dead ?
585  REPORT_IF_DEAD(0xff00, curCtxtHandle, lastIP[1], myhash);
586  // update state for all
587  *((uint16_t*)(status + PAGE_OFFSET((uint64_t)addr))) = TWO_BYTE_WRITE_ACTION;
588  }
589  } else {
590  // record as written
591  *((uint16_t*)(status + PAGE_OFFSET((uint64_t)addr))) = TWO_BYTE_WRITE_ACTION;
592  }
593 
594  lastIP[0] = curCtxtHandle;
595  lastIP[1] = curCtxtHandle;
596  } else {
597  Record1ByteMemWrite(addr, opaqueHandle, threadId);
598  Record1ByteMemWrite(((char*)addr) + 1, opaqueHandle, threadId);
599  }
600 }
601 #endif // end TESTING_BYTES
602 
603 VOID Record4ByteMemRead(VOID* addr) {
604  uint8_t* status = GetShadowBaseAddress(addr);
605  // status == 0 if not created.
606  int overflow = PAGE_OFFSET((uint64_t)addr) - (PAGE_OFFSET_MASK - 3);
607 
608  if (overflow <= 0) {
609  if (status) {
610  *((uint32_t*)(status + PAGE_OFFSET((uint64_t)addr))) = FOUR_BYTE_READ_ACTION;
611  }
612  } else {
613  if (status) {
614  status += PAGE_OFFSET((uint64_t)addr);
615 
616  for (int nonOverflowBytes = 0; nonOverflowBytes < 4 - overflow; nonOverflowBytes++) {
618  }
619  }
620 
621  status = GetShadowBaseAddress(((char*)addr) + 4); // +4 so that we get next page
622 
623  if (status) {
624  for (; overflow; overflow--) {
626  }
627  }
628  }
629 }
630 
631 #ifdef TESTING_BYTES
632 VOID Record4ByteMemWrite(VOID* addr) {
633  RecordNByteMemWrite(uint32_t, 4, FOUR);
634 }
635 #else // no TESTING_BYTES
636 
637 VOID Record4ByteMemWrite(VOID* addr, const uint32_t opaqueHandle, THREADID threadId) {
638  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
639  const uint32_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
640 
641  // status == 0 if not created.
642  if (PAGE_OFFSET((uint64_t)addr) < (PAGE_OFFSET_MASK - 2)) {
643  uint32_t* lastIP = (uint32_t*)(status + PAGE_SIZE + PAGE_OFFSET((uint64_t)addr) * sizeof(uint32_t));
644  uint32_t state = *((uint32_t*)(status + PAGE_OFFSET((uint64_t)addr)));
645 
646  if (state != FOUR_BYTE_READ_ACTION) {
647  DECLARE_HASHVAR(myhash);
648  uint32_t ipZero = lastIP[0];
649 
650  // fast path where all bytes are dead by same context
651  if (state == FOUR_BYTE_WRITE_ACTION &&
652  ipZero == lastIP[0] && ipZero == lastIP[1] && ipZero == lastIP[2] && ipZero == lastIP[3]) {
653  REPORT_DEAD(curCtxtHandle, ipZero, myhash, 4);
654  // State is already written, so no need to dead write in a tool that detects dead writes
655  } else {
656  // slow path
657  // byte 1 dead ?
658  REPORT_IF_DEAD(0x000000ff, curCtxtHandle, ipZero, myhash);
659  // byte 2 dead ?
660  REPORT_IF_DEAD(0x0000ff00, curCtxtHandle, lastIP[1], myhash);
661  // byte 3 dead ?
662  REPORT_IF_DEAD(0x00ff0000, curCtxtHandle, lastIP[2], myhash);
663  // byte 4 dead ?
664  REPORT_IF_DEAD(0xff000000, curCtxtHandle, lastIP[3], myhash);
665  // update state for all
666  *((uint32_t*)(status + PAGE_OFFSET((uint64_t)addr))) = FOUR_BYTE_WRITE_ACTION;
667  }
668  } else {
669  // record as written
670  *((uint32_t*)(status + PAGE_OFFSET((uint64_t)addr))) = FOUR_BYTE_WRITE_ACTION;
671  }
672 
673  lastIP[0] = curCtxtHandle;
674  lastIP[1] = curCtxtHandle;
675  lastIP[2] = curCtxtHandle;
676  lastIP[3] = curCtxtHandle;
677  } else {
678  Record1ByteMemWrite(addr, opaqueHandle, threadId);
679  Record1ByteMemWrite(((char*)addr) + 1, opaqueHandle, threadId);
680  Record1ByteMemWrite(((char*)addr) + 2, opaqueHandle, threadId);
681  Record1ByteMemWrite(((char*)addr) + 3, opaqueHandle, threadId);
682  }
683 }
684 #endif // end TESTING_BYTES
685 
686 VOID Record8ByteMemRead(VOID* addr) {
687  uint8_t* status = GetShadowBaseAddress(addr);
688  // status == 0 if not created.
689  int overflow = PAGE_OFFSET((uint64_t)addr) - (PAGE_OFFSET_MASK - 7);
690 
691  if (overflow <= 0) {
692  if (status) {
693  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_READ_ACTION;
694  }
695  } else {
696  if (status) {
697  status += PAGE_OFFSET((uint64_t)addr);
698 
699  for (int nonOverflowBytes = 0; nonOverflowBytes < 8 - overflow; nonOverflowBytes++) {
701  }
702  }
703 
704  status = GetShadowBaseAddress(((char*)addr) + 8); // +8 so that we get next page
705 
706  if (status) {
707  for (; overflow; overflow--) {
709  }
710  }
711  }
712 }
713 
714 #ifdef TESTING_BYTES
715 VOID Record8ByteMemWrite(VOID* addr) {
716  RecordNByteMemWrite(uint64_t, 8, EIGHT);
717 }
718 #else // no TESTING_BYTES
719 
720 VOID Record8ByteMemWrite(VOID* addr, const uint32_t opaqueHandle, THREADID threadId) {
721  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
722  const uint32_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
723 
724  // status == 0 if not created.
725  if (PAGE_OFFSET((uint64_t)addr) < (PAGE_OFFSET_MASK - 6)) {
726  uint32_t* lastIP = (uint32_t*)(status + PAGE_SIZE + PAGE_OFFSET((uint64_t)addr) * sizeof(uint32_t));
727  uint64_t state = *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr)));
728 
729  if (state != EIGHT_BYTE_READ_ACTION) {
730  DECLARE_HASHVAR(myhash);
731  uint32_t ipZero = lastIP[0];
732 
733  // fast path where all bytes are dead by same context
734  if (state == EIGHT_BYTE_WRITE_ACTION &&
735  ipZero == lastIP[1] && ipZero == lastIP[2] &&
736  ipZero == lastIP[3] && ipZero == lastIP[4] &&
737  ipZero == lastIP[5] && ipZero == lastIP[6] && ipZero == lastIP[7]) {
738  REPORT_DEAD(curCtxtHandle, ipZero, myhash, 8);
739  // State is already written, so no need to dead write in a tool that detects dead writes
740  } else {
741  // slow path
742  // byte 1 dead ?
743  REPORT_IF_DEAD(0x00000000000000ff, curCtxtHandle, ipZero, myhash);
744  // byte 2 dead ?
745  REPORT_IF_DEAD(0x000000000000ff00, curCtxtHandle, lastIP[1], myhash);
746  // byte 3 dead ?
747  REPORT_IF_DEAD(0x0000000000ff0000, curCtxtHandle, lastIP[2], myhash);
748  // byte 4 dead ?
749  REPORT_IF_DEAD(0x00000000ff000000, curCtxtHandle, lastIP[3], myhash);
750  // byte 5 dead ?
751  REPORT_IF_DEAD(0x000000ff00000000, curCtxtHandle, lastIP[4], myhash);
752  // byte 6 dead ?
753  REPORT_IF_DEAD(0x0000ff0000000000, curCtxtHandle, lastIP[5], myhash);
754  // byte 7 dead ?
755  REPORT_IF_DEAD(0x00ff000000000000, curCtxtHandle, lastIP[6], myhash);
756  // byte 8 dead ?
757  REPORT_IF_DEAD(0xff00000000000000, curCtxtHandle, lastIP[7], myhash);
758  // update state for all
759  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_WRITE_ACTION;
760  }
761  } else {
762  // record as written
763  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_WRITE_ACTION;
764  }
765 
766  lastIP[0] = curCtxtHandle;
767  lastIP[1] = curCtxtHandle;
768  lastIP[2] = curCtxtHandle;
769  lastIP[3] = curCtxtHandle;
770  lastIP[4] = curCtxtHandle;
771  lastIP[5] = curCtxtHandle;
772  lastIP[6] = curCtxtHandle;
773  lastIP[7] = curCtxtHandle;
774  } else {
775  Record1ByteMemWrite(addr, opaqueHandle, threadId);
776  Record1ByteMemWrite(((char*)addr) + 1, opaqueHandle, threadId);
777  Record1ByteMemWrite(((char*)addr) + 2, opaqueHandle, threadId);
778  Record1ByteMemWrite(((char*)addr) + 3, opaqueHandle, threadId);
779  Record1ByteMemWrite(((char*)addr) + 4, opaqueHandle, threadId);
780  Record1ByteMemWrite(((char*)addr) + 5, opaqueHandle, threadId);
781  Record1ByteMemWrite(((char*)addr) + 6, opaqueHandle, threadId);
782  Record1ByteMemWrite(((char*)addr) + 7, opaqueHandle, threadId);
783  }
784 }
785 #endif // end TESTING_BYTES
786 
787 VOID Record10ByteMemRead(VOID* addr) {
788  uint8_t* status = GetShadowBaseAddress(addr);
789  // status == 0 if not created.
790  int overflow = PAGE_OFFSET((uint64_t)addr) - (PAGE_OFFSET_MASK - 15);
791 
792  if (overflow <= 0) {
793  if (status) {
794  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_READ_ACTION;
795  *((uint16_t*)(status + PAGE_OFFSET(((uint64_t)addr + 8)))) = TWO_BYTE_READ_ACTION;
796  }
797  } else {
798  // slow path
799  Record8ByteMemRead(addr);
800  Record2ByteMemRead((char*)addr + 8);
801  }
802 }
803 
804 
805 #ifdef TESTING_BYTES
806 VOID Record10ByteMemWrite(VOID* addr) {
807  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
808 
809  if (PAGE_OFFSET((uint64_t)addr) < (PAGE_OFFSET_MASK - 14)) {
810  uint64_t state1 = *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr)));
811  uint16_t state2 = *((uint64_t*)(status + PAGE_OFFSET(((uint64_t)addr) + 8)));
812 
813  if ((state1 != EIGHT_BYTE_READ_ACTION) || (state2 != TWO_BYTE_READ_ACTION)) {
814  if ((state1 == EIGHT_BYTE_WRITE_ACTION) && (state2 == TWO_BYTE_WRITE_ACTION)) {
815  gFullyKilling10++;
816  } else {
817  gPartiallyKilling10++;
818 
819  for (uint64_t s = state1; s != 0; s >>= 8)
820  if (s & 0xff)
821  gPartiallyDeadBytes10++;
822 
823  for (uint16_t s = state2; s != 0; s >>= 8)
824  if (s & 0xff)
825  gPartiallyDeadBytes10++;
826  }
827  }
828 
829  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_WRITE_ACTION;
830  *((uint16_t*)(status + PAGE_OFFSET(((uint64_t)addr) + 8))) = TWO_BYTE_WRITE_ACTION;
831  } else {
832  uint8_t state = *((uint8_t*)(status + PAGE_OFFSET((uint64_t)addr)));
833  *((uint8_t*)(status + PAGE_OFFSET((uint64_t)addr))) = ONE_BYTE_WRITE_ACTION;
834  uint8_t deadBytes = state == ONE_BYTE_WRITE_ACTION ? 1 : 0;
835 
836  for (uint8_t i = 1; i < 10; i++) {
837  status = GetOrCreateShadowBaseAddress(((char*)addr) + i);
838  state = *((uint8_t*)(status + PAGE_OFFSET((((uint64_t)addr) + i))));
839 
840  if (state == ONE_BYTE_WRITE_ACTION)
841  deadBytes++;
842 
843  *((uint8_t*)(status + PAGE_OFFSET((((uint64_t)addr) + i)))) = ONE_BYTE_WRITE_ACTION;
844  }
845 
846  if (deadBytes == 10)
847  gFullyKilling10++;
848  else if (deadBytes) {
849  gPartiallyKilling10++;
850  gPartiallyDeadBytes10 += deadBytes;
851  }
852  }
853 }
854 #else // no TESTING_BYTES
855 
856 VOID Record10ByteMemWrite(VOID* addr, const uint32_t opaqueHandle, THREADID threadId) {
857  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
858  const uint32_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
859 
860  // status == 0 if not created.
861  if (PAGE_OFFSET((uint64_t)addr) < (PAGE_OFFSET_MASK - 8)) {
862  uint32_t* lastIP = (uint32_t*)(status + PAGE_SIZE + PAGE_OFFSET((uint64_t)addr) * sizeof(uint32_t));
863  uint64_t state = *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr)));
864 
865  if (state != EIGHT_BYTE_READ_ACTION) {
866  DECLARE_HASHVAR(myhash);
867  uint32_t ipZero = lastIP[0];
868 
869  // fast path where all bytes are dead by same context
870  if (state == EIGHT_BYTE_WRITE_ACTION &&
871  ipZero == lastIP[1] && ipZero == lastIP[2] &&
872  ipZero == lastIP[3] && ipZero == lastIP[4] &&
873  ipZero == lastIP[5] && ipZero == lastIP[6] && ipZero == lastIP[7]) {
874  REPORT_DEAD(curCtxtHandle, ipZero, myhash, 8);
875  // No state update needed
876  } else {
877  // slow path
878  // byte 1 dead ?
879  REPORT_IF_DEAD(0x00000000000000ff, curCtxtHandle, ipZero, myhash);
880  // byte 2 dead ?
881  REPORT_IF_DEAD(0x000000000000ff00, curCtxtHandle, lastIP[1], myhash);
882  // byte 3 dead ?
883  REPORT_IF_DEAD(0x0000000000ff0000, curCtxtHandle, lastIP[2], myhash);
884  // byte 4 dead ?
885  REPORT_IF_DEAD(0x00000000ff000000, curCtxtHandle, lastIP[3], myhash);
886  // byte 5 dead ?
887  REPORT_IF_DEAD(0x000000ff00000000, curCtxtHandle, lastIP[4], myhash);
888  // byte 6 dead ?
889  REPORT_IF_DEAD(0x0000ff0000000000, curCtxtHandle, lastIP[5], myhash);
890  // byte 7 dead ?
891  REPORT_IF_DEAD(0x00ff000000000000, curCtxtHandle, lastIP[6], myhash);
892  // byte 8 dead ?
893  REPORT_IF_DEAD(0xff00000000000000, curCtxtHandle, lastIP[7], myhash);
894  // update state of these 8 bytes could be some overwrites
895  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_WRITE_ACTION;
896  }
897  } else {
898  // update state of these 8 bytes
899  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_WRITE_ACTION;
900  }
901 
902  // This looks like it was a bug, should not OR with 0xffffffffffff0000
903  // state = (*((uint16_t*) (status + PAGE_OFFSET((uint64_t)addr) + 8)) )| 0xffffffffffff0000;
904  state = (*((uint16_t*)(status + PAGE_OFFSET((uint64_t)addr) + 8)));
905 
906  if (state != TWO_BYTE_READ_ACTION) {
907  DECLARE_HASHVAR(myhash);
908  uint32_t ipZero = lastIP[8];
909 
910  // fast path where all bytes are dead by same context
911  if (state == TWO_BYTE_WRITE_ACTION &&
912  ipZero == lastIP[9]) {
913  REPORT_DEAD(curCtxtHandle, ipZero, myhash, 2);
914  // No state update needed
915  } else {
916  // slow path
917  // byte 1 dead ?
918  REPORT_IF_DEAD(0x00ff, curCtxtHandle, ipZero, myhash);
919  // byte 2 dead ?
920  REPORT_IF_DEAD(0xff00, curCtxtHandle, lastIP[9], myhash);
921  // update state
922  *((uint16_t*)(status + PAGE_OFFSET(((uint64_t)addr + 8)))) = TWO_BYTE_WRITE_ACTION;
923  }
924  } else {
925  // Update state of these 2 bytes
926  *((uint16_t*)(status + PAGE_OFFSET(((uint64_t)addr + 8)))) = TWO_BYTE_WRITE_ACTION;
927  }
928 
929  lastIP[0] = curCtxtHandle;
930  lastIP[1] = curCtxtHandle;
931  lastIP[2] = curCtxtHandle;
932  lastIP[3] = curCtxtHandle;
933  lastIP[4] = curCtxtHandle;
934  lastIP[5] = curCtxtHandle;
935  lastIP[6] = curCtxtHandle;
936  lastIP[7] = curCtxtHandle;
937  lastIP[8] = curCtxtHandle;
938  lastIP[9] = curCtxtHandle;
939  } else {
940  for (int i = 0; i < 10; i++) {
941  Record1ByteMemWrite(((char*)addr) + i, opaqueHandle, threadId);
942  }
943  }
944 }
945 #endif // end TESTING_BYTES
946 
947 
948 VOID Record16ByteMemRead(VOID* addr) {
949  uint8_t* status = GetShadowBaseAddress(addr);
950  // status == 0 if not created.
951  int overflow = PAGE_OFFSET((uint64_t)addr) - (PAGE_OFFSET_MASK - 15);
952 
953  if (overflow <= 0) {
954  if (status) {
955  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_READ_ACTION;
956  *((uint64_t*)(status + PAGE_OFFSET(((uint64_t)addr + 8)))) = EIGHT_BYTE_READ_ACTION;
957  }
958  } else {
959  // slow path
960  Record8ByteMemRead(addr);
961  Record8ByteMemRead((char*)addr + 8);
962  }
963 }
964 
965 
966 #ifdef TESTING_BYTES
967 VOID Record16ByteMemWrite(VOID* addr) {
968  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
969 
970  if (PAGE_OFFSET((uint64_t)addr) < (PAGE_OFFSET_MASK - 14)) {
971  uint64_t state1 = *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr)));
972  uint64_t state2 = *((uint64_t*)(status + PAGE_OFFSET(((uint64_t)addr) + 8)));
973 
974  if ((state1 != EIGHT_BYTE_READ_ACTION) || (state2 != EIGHT_BYTE_READ_ACTION)) {
975  if ((state1 == EIGHT_BYTE_WRITE_ACTION) && (state2 == EIGHT_BYTE_WRITE_ACTION)) {
976  gFullyKilling16++;
977  } else {
978  gPartiallyKilling16++;
979 
980  for (uint64_t s = state1; s != 0; s >>= 8)
981  if (s & 0xff)
982  gPartiallyDeadBytes16++;
983 
984  for (uint64_t s = state2; s != 0; s >>= 8)
985  if (s & 0xff)
986  gPartiallyDeadBytes16++;
987  }
988  }
989 
990  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_WRITE_ACTION;
991  *((uint64_t*)(status + PAGE_OFFSET(((uint64_t)addr) + 8))) = EIGHT_BYTE_WRITE_ACTION;
992  } else {
993  uint8_t state = *((uint8_t*)(status + PAGE_OFFSET((uint64_t)addr)));
994  *((uint8_t*)(status + PAGE_OFFSET((uint64_t)addr))) = ONE_BYTE_WRITE_ACTION;
995  uint8_t deadBytes = state == ONE_BYTE_WRITE_ACTION ? 1 : 0;
996 
997  for (uint8_t i = 1; i < 16; i++) {
998  status = GetOrCreateShadowBaseAddress(((char*)addr) + i);
999  state = *((uint8_t*)(status + PAGE_OFFSET((((uint64_t)addr) + i))));
1000 
1001  if (state == ONE_BYTE_WRITE_ACTION)
1002  deadBytes++;
1003 
1004  *((uint8_t*)(status + PAGE_OFFSET((((uint64_t)addr) + i)))) = ONE_BYTE_WRITE_ACTION;
1005  }
1006 
1007  if (deadBytes == 16)
1008  gFullyKilling16++;
1009  else if (deadBytes) {
1010  gPartiallyKilling16++;
1011  gPartiallyDeadBytes16 += deadBytes;
1012  }
1013  }
1014 }
1015 #else // no TESTING_BYTES
1016 
1017 VOID Record16ByteMemWrite(VOID* addr, const uint32_t opaqueHandle, THREADID threadId) {
1018  uint8_t* status = GetOrCreateShadowBaseAddress(addr);
1019  const uint32_t curCtxtHandle = GetContextHandle(threadId, opaqueHandle);
1020 
1021  // status == 0 if not created.
1022  if (PAGE_OFFSET((uint64_t)addr) < (PAGE_OFFSET_MASK - 14)) {
1023  uint32_t* lastIP = (uint32_t*)(status + PAGE_SIZE + PAGE_OFFSET((uint64_t)addr) * sizeof(uint32_t));
1024  uint64_t state = *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr)));
1025 
1026  if (state != EIGHT_BYTE_READ_ACTION) {
1027  DECLARE_HASHVAR(myhash);
1028  uint32_t ipZero = lastIP[0];
1029 
1030  // fast path where all bytes are dead by same context
1031  if (state == EIGHT_BYTE_WRITE_ACTION &&
1032  ipZero == lastIP[1] && ipZero == lastIP[2] &&
1033  ipZero == lastIP[3] && ipZero == lastIP[4] &&
1034  ipZero == lastIP[5] && ipZero == lastIP[6] && ipZero == lastIP[7]) {
1035  REPORT_DEAD(curCtxtHandle, ipZero, myhash, 8);
1036  // No state update needed
1037  } else {
1038  // slow path
1039  // byte 1 dead ?
1040  REPORT_IF_DEAD(0x00000000000000ff, curCtxtHandle, ipZero, myhash);
1041  // byte 2 dead ?
1042  REPORT_IF_DEAD(0x000000000000ff00, curCtxtHandle, lastIP[1], myhash);
1043  // byte 3 dead ?
1044  REPORT_IF_DEAD(0x0000000000ff0000, curCtxtHandle, lastIP[2], myhash);
1045  // byte 4 dead ?
1046  REPORT_IF_DEAD(0x00000000ff000000, curCtxtHandle, lastIP[3], myhash);
1047  // byte 5 dead ?
1048  REPORT_IF_DEAD(0x000000ff00000000, curCtxtHandle, lastIP[4], myhash);
1049  // byte 6 dead ?
1050  REPORT_IF_DEAD(0x0000ff0000000000, curCtxtHandle, lastIP[5], myhash);
1051  // byte 7 dead ?
1052  REPORT_IF_DEAD(0x00ff000000000000, curCtxtHandle, lastIP[6], myhash);
1053  // byte 8 dead ?
1054  REPORT_IF_DEAD(0xff00000000000000, curCtxtHandle, lastIP[7], myhash);
1055  // update state of these 8 bytes could be some overwrites
1056  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_WRITE_ACTION;
1057  }
1058  } else {
1059  // update state of these 8 bytes
1060  *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr))) = EIGHT_BYTE_WRITE_ACTION;
1061  }
1062 
1063  state = *((uint64_t*)(status + PAGE_OFFSET((uint64_t)addr) + 8));
1064 
1065  if (state != EIGHT_BYTE_READ_ACTION) {
1066  DECLARE_HASHVAR(myhash);
1067  uint32_t ipZero = lastIP[8];
1068 
1069  // fast path where all bytes are dead by same context
1070  if (state == EIGHT_BYTE_WRITE_ACTION &&
1071  ipZero == lastIP[9] && ipZero == lastIP[10] && ipZero == lastIP[11] &&
1072  ipZero == lastIP[12] && ipZero == lastIP[13] &&
1073  ipZero == lastIP[14] && ipZero == lastIP[15]) {
1074  REPORT_DEAD(curCtxtHandle, ipZero, myhash, 8);
1075  // No state update needed
1076  } else {
1077  // slow path
1078  // byte 1 dead ?
1079  REPORT_IF_DEAD(0x00000000000000ff, curCtxtHandle, ipZero, myhash);
1080  // byte 2 dead ?
1081  REPORT_IF_DEAD(0x000000000000ff00, curCtxtHandle, lastIP[9], myhash);
1082  // byte 3 dead ?
1083  REPORT_IF_DEAD(0x0000000000ff0000, curCtxtHandle, lastIP[10], myhash);
1084  // byte 4 dead ?
1085  REPORT_IF_DEAD(0x00000000ff000000, curCtxtHandle, lastIP[11], myhash);
1086  // byte 5 dead ?
1087  REPORT_IF_DEAD(0x000000ff00000000, curCtxtHandle, lastIP[12], myhash);
1088  // byte 6 dead ?
1089  REPORT_IF_DEAD(0x0000ff0000000000, curCtxtHandle, lastIP[13], myhash);
1090  // byte 7 dead ?
1091  REPORT_IF_DEAD(0x00ff000000000000, curCtxtHandle, lastIP[14], myhash);
1092  // byte 8 dead ?
1093  REPORT_IF_DEAD(0xff00000000000000, curCtxtHandle, lastIP[15], myhash);
1094  // update state
1095  *((uint64_t*)(status + PAGE_OFFSET(((uint64_t)addr + 8)))) = EIGHT_BYTE_WRITE_ACTION;
1096  }
1097  } else {
1098  // Update state of these 8 bytes
1099  *((uint64_t*)(status + PAGE_OFFSET(((uint64_t)addr + 8)))) = EIGHT_BYTE_WRITE_ACTION;
1100  }
1101 
1102  lastIP[0] = curCtxtHandle;
1103  lastIP[1] = curCtxtHandle;
1104  lastIP[2] = curCtxtHandle;
1105  lastIP[3] = curCtxtHandle;
1106  lastIP[4] = curCtxtHandle;
1107  lastIP[5] = curCtxtHandle;
1108  lastIP[6] = curCtxtHandle;
1109  lastIP[7] = curCtxtHandle;
1110  lastIP[8] = curCtxtHandle;
1111  lastIP[9] = curCtxtHandle;
1112  lastIP[10] = curCtxtHandle;
1113  lastIP[11] = curCtxtHandle;
1114  lastIP[12] = curCtxtHandle;
1115  lastIP[13] = curCtxtHandle;
1116  lastIP[14] = curCtxtHandle;
1117  lastIP[15] = curCtxtHandle;
1118  } else {
1119  for (int i = 0; i < 16; i++) {
1120  Record1ByteMemWrite(((char*)addr) + i, opaqueHandle, threadId);
1121  }
1122  }
1123 }
1124 #endif // end TESTING_BYTES
1125 
1126 
1127 //// IMPROVE ME
1128 VOID RecordLargeMemRead(VOID* addr, UINT32 size) {
1129  for (UINT32 i = 0; i < size; i++) {
1130  uint8_t* status = GetShadowBaseAddress(((char*)addr) + i);
1131 
1132  if (status) {
1133  *(status + PAGE_OFFSET(((uint64_t)addr + i))) = ONE_BYTE_READ_ACTION;
1134  }
1135  }
1136 }
1137 
1138 #ifdef TESTING_BYTES
1139 
1140 VOID RecordLargeMemWrite(VOID* addr, UINT32 size) {
1141  uint8_t* status;
1142  uint8_t state;
1143  uint8_t deadBytes = 0;
1144 
1145  for (uint8_t i = 0; i < size; i++) {
1146  status = GetOrCreateShadowBaseAddress(((char*)addr) + i);
1147  state = *((uint8_t*)(status + PAGE_OFFSET((((uint64_t)addr) + i))));
1148 
1149  if (state == ONE_BYTE_WRITE_ACTION)
1150  deadBytes++;
1151 
1152  *((uint8_t*)(status + PAGE_OFFSET((((uint64_t)addr) + i)))) = ONE_BYTE_WRITE_ACTION;
1153  }
1154 
1155  if (deadBytes == size) {
1156  gFullyKillingLarge++;
1157  } else if (deadBytes) {
1158  gPartiallyKillingLarge++;
1159  }
1160 
1161  // for large we just add them all to partially dead
1162  gPartiallyDeadBytesLarge += deadBytes;
1163  //assert(0 && "NOT IMPLEMENTED LARGE WRITE BYTE");
1164 }
1165 
1166 #else // no TESTING_BYTES
1167 
1168 //// IMPROVE ME
1169 VOID RecordLargeMemWrite(VOID* addr, UINT32 size, const uint32_t opaqueHandle, THREADID threadId) {
1170  for (UINT32 i = 0; i < size; i++) {
1171  // report dead for first byte if needed
1172  Record1ByteMemWrite((char*)addr + i, opaqueHandle, threadId);
1173  }
1174 }
1175 #endif // end TESTING_BYTES
1176 
1177 void InspectMemRead(VOID* addr, UINT32 sz) {
1178  cerr << "\n"
1179  << addr << ":" << sz;
1180 }
1181 
1182 
1183 // Is called for every instruction and instruments reads and writes
1184 VOID Instruction(INS ins, void* v, const uint32_t opaqueHandle) {
1185  // Note: predicated instructions are correctly handled as given in PIN's sample example pinatrace.cpp
1186  /* Comment taken from PIN sample :
1187  Instruments memory accesses using a predicated call, i.e.
1188  the instrumentation is called iff the instruction will actually be executed.
1189 
1190  The IA-64 architecture has explicitly predicated instructions.
1191  On the IA-32 and Intel(R) 64 architectures conditional moves and REP
1192  prefixed instructions appear as predicated instructions in Pin. */
1193  // In Multi-threaded skip call, ret and JMP instructions
1194 #ifdef MULTI_THREADED
1195  if (INS_IsControlFlow(ins) || INS_IsRet(ins)) {
1196  return;
1197  }
1198 
1199 #endif //end MULTI_THREADED
1200 
1201  // XSAVEC and XRSTOR are problematic since its access length is variable.
1202  // 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.
1203  // It fails with "Cannot use IARG_MEMORYWRITE_SIZE on non-standard memory access of instruction at 0xfoo: xsavec ptr [rsp]" error.
1204  // A correct solution should use INS_hasKnownMemorySize() which is not available in Pin 2.14.
1205  if (INS_Mnemonic(ins) == "XSAVEC")
1206  return;
1207  if (INS_Mnemonic(ins) == "XSAVE")
1208  return;
1209  if (INS_Mnemonic(ins) == "XRSTOR")
1210  return;
1211 
1212  // Prefetch instructions have no architectural effect on program state:
1213  // they only hint to the hardware cache subsystem. Pin classifies them
1214  // as a memory read (e.g. "PREFETCHT0 [64:R-]") so if we let them through
1215  // Record*MemRead would set the shadow to READ_ACTION and erase the
1216  // "was-written" marker set by a preceding store. A subsequent store to
1217  // the same address would then be missed as a dead write. Filter them
1218  // out so prefetch hints don't gate dead-write detection.
1219  if (INS_IsPrefetch(ins))
1220  return;
1221 
1222  // How may memory operations?
1223  UINT32 memOperands = INS_MemoryOperandCount(ins);
1224 #ifdef MULTI_THREADED
1225  // Support for MT
1226  // Acquire the lock before starting the analysis routine since we need analysis routine and original instruction to run atomically.
1227  bool lockNeeded = false;
1228 
1229  if (memOperands) {
1230  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
1231  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)TakeLock, IARG_END);
1232  lockNeeded = true;
1233  break;
1234  }
1235  }
1236 
1237 #endif //end MULTI_THREADED
1238 
1239  // Iterate over each memory operand of the instruction and add Analysis routine to check for dead writes.
1240  // We correctly handle instructions that do both read and write.
1241 
1242  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
1243  UINT32 refSize = INS_MemoryOperandSize(ins, memOp);
1244 
1245  switch (refSize) {
1246  case 1: {
1247  if (INS_MemoryOperandIsRead(ins, memOp)) {
1248  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Record1ByteMemRead, IARG_MEMORYOP_EA, memOp, IARG_END);
1249  }
1250 
1251  if (INS_MemoryOperandIsWritten(ins, memOp)) {
1252  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
1253  (AFUNPTR)Record1ByteMemWrite,
1254  IARG_MEMORYOP_EA, memOp,
1255  IARG_UINT32, opaqueHandle,
1256  IARG_THREAD_ID, IARG_END);
1257  }
1258  } break;
1259 
1260  case 2: {
1261  if (INS_MemoryOperandIsRead(ins, memOp)) {
1262  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Record2ByteMemRead, IARG_MEMORYOP_EA, memOp, IARG_END);
1263  }
1264 
1265  if (INS_MemoryOperandIsWritten(ins, memOp)) {
1266  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
1267  (AFUNPTR)Record2ByteMemWrite,
1268  IARG_MEMORYOP_EA, memOp,
1269  IARG_UINT32, opaqueHandle,
1270  IARG_THREAD_ID, IARG_END);
1271  }
1272  } break;
1273 
1274  case 4: {
1275  if (INS_MemoryOperandIsRead(ins, memOp)) {
1276  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Record4ByteMemRead, IARG_MEMORYOP_EA, memOp, IARG_END);
1277  }
1278 
1279  if (INS_MemoryOperandIsWritten(ins, memOp)) {
1280  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
1281  (AFUNPTR)Record4ByteMemWrite,
1282  IARG_MEMORYOP_EA, memOp,
1283  IARG_UINT32, opaqueHandle,
1284  IARG_THREAD_ID, IARG_END);
1285  }
1286  } break;
1287 
1288  case 8: {
1289  if (INS_MemoryOperandIsRead(ins, memOp)) {
1290  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Record8ByteMemRead, IARG_MEMORYOP_EA, memOp, IARG_END);
1291  }
1292 
1293  if (INS_MemoryOperandIsWritten(ins, memOp)) {
1294  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
1295  (AFUNPTR)Record8ByteMemWrite,
1296  IARG_MEMORYOP_EA, memOp,
1297  IARG_UINT32, opaqueHandle,
1298  IARG_THREAD_ID, IARG_END);
1299  }
1300  } break;
1301 
1302  case 10: {
1303  if (INS_MemoryOperandIsRead(ins, memOp)) {
1304  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Record10ByteMemRead, IARG_MEMORYOP_EA, memOp, IARG_END);
1305  }
1306 
1307  if (INS_MemoryOperandIsWritten(ins, memOp)) {
1308  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
1309  (AFUNPTR)Record10ByteMemWrite,
1310  IARG_MEMORYOP_EA, memOp,
1311  IARG_UINT32, opaqueHandle,
1312  IARG_THREAD_ID, IARG_END);
1313  }
1314  } break;
1315 
1316  case 16: { // SORRY! XMM regs use 16 bits :((
1317  if (INS_MemoryOperandIsRead(ins, memOp)) {
1318  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Record16ByteMemRead, IARG_MEMORYOP_EA, memOp, IARG_END);
1319  }
1320 
1321  if (INS_MemoryOperandIsWritten(ins, memOp)) {
1322  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
1323  (AFUNPTR)Record16ByteMemWrite,
1324  IARG_MEMORYOP_EA, memOp,
1325  IARG_UINT32, opaqueHandle,
1326  IARG_THREAD_ID, IARG_END);
1327  }
1328  } break;
1329 
1330  default: {
1331  // seeing some stupid 10, 16, 512 (fxsave)byte operations. Suspecting REP-instructions.
1332  if (INS_MemoryOperandIsRead(ins, memOp)) {
1333  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordLargeMemRead, IARG_MEMORYOP_EA, memOp, IARG_MEMORYREAD_SIZE, IARG_END);
1334  }
1335 
1336  if (INS_MemoryOperandIsWritten(ins, memOp)) {
1337  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
1338  (AFUNPTR)RecordLargeMemWrite,
1339  IARG_MEMORYOP_EA, memOp, IARG_MEMORYWRITE_SIZE,
1340  IARG_UINT32, opaqueHandle,
1341  IARG_THREAD_ID, IARG_END);
1342  }
1343  } break;
1344  //assert( 0 && "BAD refSize");
1345  }
1346  }
1347 
1348 #ifdef MULTI_THREADED
1349 
1350  // Support for MT
1351  // release the lock if we had taken it
1352  if (lockNeeded) {
1353  INS_InsertPredicatedCall(ins, IPOINT_AFTER, (AFUNPTR)ReleaseLock, IARG_END);
1354  }
1355 
1356 #endif //end MULTI_THREADED
1357 }
1358 
1359 #ifdef TESTING_BYTES
1360 // Prints the collected statistics on writes along with their sizes and dead/killing writes and their sizes
1361 inline VOID PrintInstructionBreakdown() {
1362  fprintf(gTraceFile, "\n%lu,%lu,%lu,%lu ", g1ByteWriteInstrCount, gFullyKilling1, gPartiallyKilling1, gPartiallyDeadBytes1);
1363  fprintf(gTraceFile, "\n%lu,%lu,%lu,%lu ", g2ByteWriteInstrCount, gFullyKilling2, gPartiallyKilling2, gPartiallyDeadBytes2);
1364  fprintf(gTraceFile, "\n%lu,%lu,%lu,%lu ", g4ByteWriteInstrCount, gFullyKilling4, gPartiallyKilling4, gPartiallyDeadBytes4);
1365  fprintf(gTraceFile, "\n%lu,%lu,%lu,%lu ", g8ByteWriteInstrCount, gFullyKilling8, gPartiallyKilling8, gPartiallyDeadBytes8);
1366  fprintf(gTraceFile, "\n%lu,%lu,%lu,%lu ", g10ByteWriteInstrCount, gFullyKilling10, gPartiallyKilling10, gPartiallyDeadBytes10);
1367  fprintf(gTraceFile, "\n%lu,%lu,%lu,%lu ", g16ByteWriteInstrCount, gFullyKilling16, gPartiallyKilling16, gPartiallyDeadBytes16);
1368  fprintf(gTraceFile, "\n%lu,%lu,%lu,%lu,%lu ", gLargeByteWriteInstrCount, gFullyKillingLarge, gPartiallyKillingLarge, gLargeByteWriteByteCount, gPartiallyDeadBytesLarge);
1369 }
1370 #endif //end TESTING_BYTES
1371 
1372 
1373 // Returns the total N-byte size writes across all CCTs
1374 uint64_t GetTotalNByteWrites(uint32_t size) {
1375  uint64_t total = 0;
1376 
1377  for (uint32_t i = 0; i < gClientNumThreads; i++) {
1378  DeadSpyThreadData* tData = ClientGetTLS(i);
1379 
1380  switch (size) {
1381  case 1: {
1382  total += tData->g1ByteWriteInstrCount;
1383  break;
1384  }
1385 
1386  case 2: {
1387  total += tData->g2ByteWriteInstrCount;
1388  break;
1389  }
1390 
1391  case 4: {
1392  total += tData->g4ByteWriteInstrCount;
1393  break;
1394  }
1395 
1396  case 8: {
1397  total += tData->g8ByteWriteInstrCount;
1398  break;
1399  }
1400 
1401  case 10: {
1402  total += tData->g10ByteWriteInstrCount;
1403  break;
1404  }
1405 
1406  case 16: {
1407  total += tData->g16ByteWriteInstrCount;
1408  break;
1409  }
1410 
1411  default: {
1412  // Not too sure :(
1413  total += tData->gLargeByteWriteInstrCount;
1414  break;
1415  }
1416  }
1417  } //end for
1418 
1419  return total;
1420 }
1421 
1422 inline uint64_t GetMeasurementBaseCount() {
1423  // byte count
1424  uint64_t measurementBaseCount = GetTotalNByteWrites(1) + 2 * GetTotalNByteWrites(2) + 4 * GetTotalNByteWrites(4) + 8 * GetTotalNByteWrites(8) + 10 * GetTotalNByteWrites(10) + 16 * GetTotalNByteWrites(16) + GetTotalNByteWrites(-1);
1425  return measurementBaseCount;
1426 }
1427 
1428 // Prints the collected statistics on writes along with their sizes
1429 inline void PrintEachSizeWrite() {
1430  fprintf(gTraceFile, "\n1:%" PRIu64, GetTotalNByteWrites(1));
1431  fprintf(gTraceFile, "\n2:%" PRIu64, GetTotalNByteWrites(2));
1432  fprintf(gTraceFile, "\n4:%" PRIu64, GetTotalNByteWrites(4));
1433  fprintf(gTraceFile, "\n8:%" PRIu64, GetTotalNByteWrites(8));
1434  fprintf(gTraceFile, "\n10:%" PRIu64, GetTotalNByteWrites(10));
1435  fprintf(gTraceFile, "\n16:%" PRIu64, GetTotalNByteWrites(16));
1436  fprintf(gTraceFile, "\nother:%" PRIu64, GetTotalNByteWrites(-1));
1437 }
1438 
1439 
1440 // On program termination output all gathered data and statistics
1441 VOID Fini(INT32 code, VOID* v) {
1442  // Serialize CCTLib
1443  SerializeMetadata("DeadSpy-CCTLib-database");
1444  // byte count
1445  uint64_t measurementBaseCount = GetMeasurementBaseCount();
1446  fprintf(gTraceFile, "\n#deads");
1447  fprintf(gTraceFile, "\nGrandTotalWrites = %" PRIu64, measurementBaseCount);
1448  fprintf(gTraceFile, "\nGrandTotalDead = %" PRIu64 " = %e%%", gTotalDead, gTotalDead * 100.0 / measurementBaseCount);
1449 #ifdef MULTI_THREADED
1450  fprintf(gTraceFile, "\nGrandTotalMTDead = %" PRIu64 " = %e%%", gTotalMTDead, gTotalMTDead * 100.0 / measurementBaseCount);
1451 #endif // end MULTI_THREADED
1452  fprintf(gTraceFile, "\n#eof");
1453  fclose(gTraceFile);
1454  if (KnobTopN.Value())
1455  topnStream.close();
1456 }
1457 
1458 
1459 // When we make System calls we need to update the shadow regions with the effect of the system call
1460 // TODO: handle other system calls. Currently only SYS_write is handled.
1461 
1462 VOID SyscallEntry(THREADID threadIndex, CONTEXT* ctxt, SYSCALL_STANDARD std,
1463  VOID* v) {
1464  ADDRINT number = PIN_GetSyscallNumber(ctxt, std);
1465 
1466  switch (number) {
1467  case SYS_write: {
1468  char* bufStart = (char*)PIN_GetSyscallArgument(ctxt, std, 1);
1469  char* bufEnd = bufStart + (size_t)PIN_GetSyscallArgument(ctxt, std, 2);
1470 #ifdef DEBUG
1471  printf("\n WRITE %p - %p\n", bufStart, bufEnd);
1472 #endif //end DEBUG
1473 
1474  while (bufStart < bufEnd)
1475  Record1ByteMemRead(bufStart++);
1476  } break;
1477 
1478  default:
1479  break; //NOP
1480  }
1481 }
1482 
1483 
1485  uint32_t context1;
1486  uint32_t context2;
1487 
1488  bool operator==(const MergedDeadInfo& x) const {
1489  return this->context1 == x.context1 && this->context2 == x.context2;
1490  }
1491 
1492  bool operator<(const MergedDeadInfo& x) const {
1493  return (this->context1 < x.context1) ||
1494  (this->context1 == x.context1 && this->context2 < x.context2);
1495  }
1496 };
1497 
1500  uint64_t count;
1501 };
1502 
1503 
1505  return first.count > second.count;
1506 } // Returns true if the given deadinfo belongs to one of the loaded binaries
1507 inline bool IsValidIP(DeadInfo di) {
1508  bool res = false;
1509 
1510  for (IMG img = APP_ImgHead(); IMG_Valid(img); img = IMG_Next(img)) {
1511  if ((ADDRINT)di.firstIP >= IMG_LowAddress(img) && (ADDRINT)di.firstIP <= IMG_HighAddress(img)) {
1512  res = true;
1513  break;
1514  }
1515  }
1516 
1517  if (!res)
1518  return false;
1519 
1520  for (IMG img = APP_ImgHead(); IMG_Valid(img); img = IMG_Next(img)) {
1521  if ((ADDRINT)di.secondIP >= IMG_LowAddress(img) && (ADDRINT)di.secondIP <= IMG_HighAddress(img)) {
1522  return true;
1523  }
1524  }
1525 
1526  return false;
1527 }
1528 
1529 
1530 // Prints the complete calling context including the line nunbers and the context's contribution, given a DeadInfo
1531 inline VOID PrintIPAndCallingContexts(const DeadInfoForPresentation& di, uint64_t measurementBaseCount) {
1532  fprintf(gTraceFile, "\n%" PRIu64 " = %e", di.count, di.count * 100.0 / measurementBaseCount);
1533  fprintf(gTraceFile, "\n-------------------------------------------------------\n");
1535  fprintf(gTraceFile, "\n***********************\n");
1537  fprintf(gTraceFile, "\n-------------------------------------------------------\n");
1538 }
1539 
1540 
1541 // On each Unload of a loaded image, the accummulated deadness information is dumped
1542 VOID ImageUnload(IMG img, VOID* v) {
1543  fprintf(gTraceFile, "\nUnloading %s", IMG_Name(img).c_str());
1544  // Update gTotalInstCount first
1545  uint64_t measurementBaseCount = GetMeasurementBaseCount();
1546  fprintf(gTraceFile, "\nTotal Instr = %" PRIu64, measurementBaseCount);
1547  fflush(gTraceFile);
1548  unordered_map<uint64_t, uint64_t>::iterator mapIt = DeadMap.begin();
1549  map<MergedDeadInfo, uint64_t> mergedDeadInfoMap;
1550 
1551  for (; mapIt != DeadMap.end(); mapIt++) {
1552  MergedDeadInfo tmpMergedDeadInfo;
1553  uint64_t hash = mapIt->first;
1554  uint32_t ctxt1 = (hash >> 32);
1555  uint32_t ctxt2 = (hash & 0xffffffff);
1556  tmpMergedDeadInfo.context1 = ctxt1;
1557  tmpMergedDeadInfo.context2 = ctxt2;
1558  map<MergedDeadInfo, uint64_t>::iterator tmpIt;
1559 
1560  if ((tmpIt = mergedDeadInfoMap.find(tmpMergedDeadInfo)) == mergedDeadInfoMap.end()) {
1561  mergedDeadInfoMap[tmpMergedDeadInfo] = mapIt->second;
1562  } else {
1563  tmpIt->second += mapIt->second;
1564  }
1565  }
1566 
1567  // clear dead map now
1568  DeadMap.clear();
1569  map<MergedDeadInfo, uint64_t>::iterator it = mergedDeadInfoMap.begin();
1570  list<DeadInfoForPresentation> deadList;
1571 
1572  for (; it != mergedDeadInfoMap.end(); it++) {
1573  DeadInfoForPresentation deadInfoForPresentation;
1574  deadInfoForPresentation.pMergedDeadInfo = &(it->first);
1575  deadInfoForPresentation.count = it->second;
1576  deadList.push_back(deadInfoForPresentation);
1577  }
1578 
1579  deadList.sort(MergedDeadInfoComparer);
1580  //present and delete all
1581  list<DeadInfoForPresentation>::iterator dipIter = deadList.begin();
1582  PIN_LockClient();
1583  uint64_t deads = 0;
1584 
1585  for (; dipIter != deadList.end(); dipIter++) {
1586 #ifdef MULTI_THREADED
1587  assert(0 && "NYI");
1588 #endif //end MULTI_THREADED
1589 
1590  // Print just first MAX_DEAD_CONTEXTS_TO_LOG contexts
1591  if (deads < MAX_DEAD_CONTEXTS_TO_LOG) {
1592  try {
1593  PrintIPAndCallingContexts(*dipIter, measurementBaseCount);
1594  } catch (...) {
1595  fprintf(gTraceFile, "\nexcept");
1596  }
1597  } else {
1598  // print only dead count
1599 #ifdef PRINT_ALL_CTXT
1600  fprintf(gTraceFile, "\nCTXT_DEAD_CNT:%lu = %e", dipIter->count, dipIter->count * 100.0 / measurementBaseCount);
1601 #endif //end PRINT_ALL_CTXT
1602  }
1603 
1604  gTotalDead += dipIter->count;
1605  deads++;
1606  }
1607 
1608  static bool done = false;
1609  if (KnobTopN.Value() && (!done)) {
1610  done = true;
1611  // Produce a log of Top 10
1612  dipIter = deadList.begin();
1613  topnStream << "<LOADMODULES>";
1615  topnStream << "\n</LOADMODULES>\n<TOPN>";
1616  for (UINT32 topN = 0; dipIter != deadList.end() && (topN < KnobTopN.Value()); dipIter++, topN++) {
1617  topnStream << "\n"
1618  << (*dipIter).count << ":" << (*dipIter).count * 1.0 / gTotalDead << ":";
1619  LogContexts(topnStream, (*dipIter).pMergedDeadInfo->context2 /* kill first*/, (*dipIter).pMergedDeadInfo->context1);
1620  }
1621  topnStream << "\n</TOPN>";
1622  }
1624 #ifdef TESTING_BYTES
1625  PrintInstructionBreakdown();
1626 #endif //end TESTING_BYTES
1627 #ifdef GATHER_STATS
1628  PrintStats(deadList, deads);
1629 #endif //end GATHER_STATS
1630  mergedDeadInfoMap.clear();
1631  deadList.clear();
1632  PIN_UnlockClient();
1633 }
1634 
1635 
1636 // Initialized the needed data structures before launching the target program
1637 void InitDeadSpy(int argc, char* argv[]) {
1638  // Create output file
1639  char name[MAX_FILE_PATH] = "deadspy.out.";
1640  char* envPath = getenv("DEADSPY_OUTPUT_FILE");
1641 
1642  if (envPath) {
1643  // assumes max of MAX_FILE_PATH
1644  snprintf(name, sizeof(name), "%s", envPath);
1645  }
1646 
1647  gethostname(name + strlen(name), MAX_FILE_PATH - strlen(name));
1648  pid_t pid = getpid();
1649  sprintf(name + strlen(name), "%d", pid);
1650  cerr << "\n Creating log file at:" << name << "\n";
1651  gTraceFile = fopen(name, "w");
1652  // print the arguments passed
1653  fprintf(gTraceFile, "\n");
1654 
1655  for (int i = 0; i < argc; i++) {
1656  fprintf(gTraceFile, "%s ", argv[i]);
1657  }
1658 
1659  fprintf(gTraceFile, "\n");
1660  if (KnobTopN.Value()) {
1661  topnStream.open(string(name) + ".topn", std::fstream::out | std::fstream::trunc);
1662  topnStream << "\n";
1663  for (int i = 0; i < argc; i++) {
1664  topnStream << argv[i] << " ";
1665  }
1666  topnStream << "\n";
1667  }
1668 
1669 #ifdef GATHER_STATS
1670  string statFileName(name);
1671  statFileName += ".stats";
1672  statsFile = fopen(statFileName.c_str(), "w");
1673  fprintf(statsFile, "\n");
1674 
1675  for (int i = 0; i < argc; i++) {
1676  fprintf(statsFile, "%s ", argv[i]);
1677  }
1678 
1679  fprintf(statsFile, "\n");
1680 #endif //end GATHER_STATS
1681 }
1682 
1683 static INT32 Usage() {
1684  PIN_ERROR("DeadSPy is a PinTool which tracks each memory access and reports dead writes.\n" + KNOB_BASE::StringKnobSummary() + "\n");
1685  return -1;
1686 }
1687 
1688 
1689 static VOID ThreadStart(THREADID threadid, CONTEXT* ctxt, INT32 flags, VOID* v) {
1690  DeadSpyThreadData* tdata = new DeadSpyThreadData();
1691  InitThreadData(tdata);
1692  __sync_fetch_and_add(&gClientNumThreads, 1);
1693  PIN_SetThreadData(client_tls_key, tdata, threadid);
1694 }
1695 
1696 
1697 // Main for DeadSpy, initialize the tool, register instrumentation functions and call the target program.
1698 
1699 int main(int argc, char* argv[]) {
1700  // Initialize PIN
1701  if (PIN_Init(argc, argv))
1702  return Usage();
1703 
1704  // Initialize Symbols, we need them to report functions and lines
1705  PIN_InitSymbols();
1706  // Intialize DeadSpy
1707  InitDeadSpy(argc, argv);
1708  // Intialize CCTLib
1709  PinCCTLibInit(INTERESTING_INS_MEMORY_ACCESS, gTraceFile, Instruction, nullptr, /*doDataCentric=*/false);
1710  // Obtain a key for TLS storage.
1711  client_tls_key = PIN_CreateThreadDataKey(nullptr /*TODO have a destructir*/);
1712  // Register ThreadStart to be called when a thread starts.
1713  PIN_AddThreadStartFunction(ThreadStart, nullptr);
1714  // capture write or other sys call that read from user space
1715  PIN_AddSyscallEntryFunction(SyscallEntry, nullptr);
1716  // Instrument instruction
1717  TRACE_AddInstrumentFunction(InstrumentTrace, nullptr);
1718  // Register ImageUnload to be called when an image is unloaded
1719  IMG_AddUnloadFunction(ImageUnload, nullptr);
1720  // Add a function to report entire stats at the termination.
1721  PIN_AddFiniFunction(Fini, nullptr);
1722  // Launch program now
1723  PIN_StartProgram();
1724  return 0;
1725 }
#define INTERESTING_INS_MEMORY_ACCESS
Definition: cctlib.H:87
VOID Instruction(INS ins, VOID *v, const uint32_t opaqueHandle)
VOID Record1ByteMemRead(VOID *addr)
unordered_map< uint64_t, uint64_t >::iterator gDeadMapIt
VOID Record8ByteMemWrite(VOID *addr, const uint32_t opaqueHandle, THREADID threadId)
uint8_t ** gL1PageTable[LEVEL_1_PAGE_TABLE_SIZE]
int main(int argc, char *argv[])
VOID Record8ByteMemRead(VOID *addr)
VOID SyscallEntry(THREADID threadIndex, CONTEXT *ctxt, SYSCALL_STANDARD std, VOID *v)
FILE * gTraceFile
void InitDeadSpy(int argc, char *argv[])
#define LEVEL_2_PAGE_TABLE_SIZE
bool IsValidIP(DeadInfo di)
VOID InstructionContributionOfBBL16Byte(uint32_t count, THREADID threadId)
#define MAX_FILE_PATH
#define LEVEL_1_PAGE_TABLE_SLOT(addr)
void PrintEachSizeWrite()
#define EIGHT_BYTE_WRITE_ACTION
DeadSpyThreadData * ClientGetTLS(const THREADID threadId)
VOID RecordLargeMemRead(VOID *addr, UINT32 size)
char dummy2[128]
VOID RecordLargeMemWrite(VOID *addr, UINT32 size, const uint32_t opaqueHandle, THREADID threadId)
VOID InstructionContributionOfBBL4Byte(uint32_t count, THREADID threadId)
VOID Record16ByteMemWrite(VOID *addr, const uint32_t opaqueHandle, THREADID threadId)
VOID Record1ByteMemWrite(VOID *addr, const uint32_t opaqueHandle, THREADID threadId)
#define ONE_BYTE_READ_ACTION
#define DECLARE_HASHVAR(name)
VOID Record2ByteMemWrite(VOID *addr, const uint32_t opaqueHandle, THREADID threadId)
static INT32 Usage()
VOID InstructionContributionOfBBL10Byte(uint32_t count, THREADID threadId)
#define EIGHT_BYTE_READ_ACTION
#define TWO_BYTE_READ_ACTION
#define PAGE_OFFSET(addr)
uint8_t * GetOrCreateShadowBaseAddress(void *address)
uint64_t GetTotalNByteWrites(uint32_t size)
bool MergedDeadInfoComparer(const DeadInfoForPresentation &first, const DeadInfoForPresentation &second)
VOID Record2ByteMemRead(VOID *addr)
#define OLD_CTXT
uint64_t gTotalDead
KNOB< UINT32 > KnobTopN(KNOB_MODE_WRITEONCE, "pintool", "d", "0", "how many top contexts to log")
#define REPORT_DEAD(curCtxt, lastCtxt, hashVar, size)
VOID InstructionContributionOfBBL1Byte(uint32_t count, THREADID threadId)
VOID InstructionContributionOfBBLLargeByte(uint32_t count, THREADID threadId)
#define MAX_DEAD_CONTEXTS_TO_LOG
#define PAGE_SIZE
PIN_LOCK lock
bool DeadInfoComparer(const DeadInfo &first, const DeadInfo &second)
static void InstrumentTrace(TRACE trace, void *f)
VOID Record10ByteMemRead(VOID *addr)
#define TWO_BYTE_WRITE_ACTION
VOID InstructionContributionOfBBL8Byte(uint32_t count, THREADID threadId)
VOID Fini(INT32 code, VOID *v)
struct @6 DeadSpyGlobals
unordered_map< uint64_t, uint64_t > DeadMap
uint8_t * GetShadowBaseAddress(void *address)
#define FOUR_BYTE_READ_ACTION
void InspectMemRead(VOID *addr, UINT32 sz)
VOID InstructionContributionOfBBL2Byte(uint32_t count, THREADID threadId)
VOID ImageUnload(IMG img, VOID *v)
char dummy1[128]
volatile uint32_t gClientNumThreads
void InitThreadData(DeadSpyThreadData *const tdata)
#define LEVEL_1_PAGE_TABLE_SIZE
VOID Record10ByteMemWrite(VOID *addr, const uint32_t opaqueHandle, THREADID threadId)
#define ONE_BYTE_WRITE_ACTION
string topNLogFileName
#define FOUR_BYTE_WRITE_ACTION
VOID Record16ByteMemRead(VOID *addr)
static TLS_KEY client_tls_key
VOID Record1ByteMemWriteWithoutDead(VOID *addr, const uint32_t opaqueHandle, THREADID threadId)
std::fstream topnStream
#define REPORT_IF_DEAD(mask, curCtxt, lastCtxt, hashVar)
VOID Record4ByteMemRead(VOID *addr)
VOID PrintIPAndCallingContexts(const DeadInfoForPresentation &di, uint64_t measurementBaseCount)
static VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
VOID Record4ByteMemWrite(VOID *addr, const uint32_t opaqueHandle, THREADID threadId)
uint64_t GetMeasurementBaseCount()
#define PAGE_OFFSET_MASK
#define LEVEL_2_PAGE_TABLE_SLOT(addr)
int PinCCTLibInit(IsInterestingInsFptr isInterestingIns, FILE *logFile, CCTLibInstrumentInsCallback userCallback, VOID *userCallbackArg, BOOL doDataCentric=false)
Definition: cctlib.cpp:3132
VOID TakeLock()
Definition: cctlib.cpp:734
hpcrun_metricFlags_t flags
Definition: cctlib.cpp:3425
static void PrintStats()
Definition: cctlib.cpp:1936
VOID PrintFullCallingContext(const ContextHandle_t ctxtHandle)
Definition: cctlib.cpp:2346
uint16_t size_t
Definition: cctlib.cpp:3359
void SerializeMetadata(const std::string &directoryForSerializationFiles="")
Definition: cctlib.cpp:1878
volatile uint8_t status
Definition: cctlib.cpp:230
VOID ReleaseLock()
Definition: cctlib.cpp:741
ContextHandle_t GetContextHandle(const THREADID id, const uint32_t slot)
Definition: cctlib.cpp:1356
void LogContexts(std::iostream &ios, ContextHandle_t ctxt1, ContextHandle_t ctxt2)
void AppendLoadModulesToStream(std::iostream &ios)
void * address
const MergedDeadInfo * pMergedDeadInfo
void * firstIP
void * secondIP
uint64_t count
uint64_t gLargeByteWriteInstrCount
uint64_t g16ByteWriteInstrCount
uint64_t g8ByteWriteInstrCount
uint64_t g2ByteWriteInstrCount
uint64_t g4ByteWriteInstrCount
uint64_t gLargeByteWriteByteCount
uint64_t g10ByteWriteInstrCount
uint64_t g1ByteWriteInstrCount
bool operator<(const MergedDeadInfo &x) const
bool operator==(const MergedDeadInfo &x) const
void f()
Definition: test1.c:23