CCTLib
Calling-context and data-object attribution library for Intel Pin
omp_datarace_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 <atomic>
8 #include <stdlib.h>
9 #include <map>
10 #include <list>
11 #include <stdint.h>
12 #include <sys/types.h>
13 #include <sys/ipc.h>
14 #include <sys/shm.h>
15 #include <semaphore.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <iostream>
19 #include <locale>
20 #include <unistd.h>
21 #include <sys/syscall.h>
22 #include <assert.h>
23 #include <sys/mman.h>
24 #include <exception>
25 #include <sys/time.h>
26 #include <signal.h>
27 #include <string.h>
28 #include <setjmp.h>
29 #include <sstream>
30 #include <pthread.h>
31 #include "pin.H"
32 #include "pin_isa_compat.H"
33 #include "cctlib.H"
34 #include "shadow_memory.H"
35 
36 using namespace std;
37 using namespace PinCCTLib;
38 
39 // All globals
40 #define MAX_FILE_PATH (200)
41 
42 // Enter rank of a phase is twice the number of ordered sections it has entered
43 // This is same as the phase number rounded up to the next multiple of 2.
44 #define ENTER_RANK(phase) (((phase) + 1) & 0xfffffffffffffffe)
45 
46 // Exit rank of a phase is twice the number of ordered sections it has exited.
47 // This is same as the phase number rounded down to the next multiple of 2.
48 #define EXIT_RANK(phase) ((phase)&0xfffffffffffffffe)
49 
50 #define MAX_REGIONS (1 << 20)
51 
52 
53 //#define DEBUG_LOOP
61 };
62 
63 enum AccessType {
65  WRITE_ACCESS = 1
66 };
67 
68 // Fwd declarations
69 class Label;
70 
71 // Data structures
72 
73 // A full label is name of many concatenated label segments. Each LabelSegment has 3 components--offset, span, and sphase.
74 struct LabelSegment {
75  uint64_t offset;
76  uint64_t span;
77  uint64_t phase;
78 };
79 
80 
81 static const LabelSegment defaultExtension = {};
82 static FILE* gTraceFile;
83 const static char* HW_LOCK = "HW_LOCK";
85 // key for accessing TLS storage in the threads. initialized once in main()
86 static TLS_KEY tls_key;
87 // Range of address where images to skip are loaded e.g., OMP runtime, linux loader.
88 #define OMP_RUMTIMR_LIB_NAME "/home/xl10/support/gcc-4.7-install/lib64/libgomp.so.1"
89 #define LINUX_LD_NAME "/lib64/ld-linux-x86-64.so.2"
90 #define MAX_SKIP_IMAGES (2)
92 static int gNumCurSkipImages;
94 
95 
96 // VersionInfo_t is a concurrency control mechanism on the labels stored in the shadow memory.
97 // Readers read from one end (readStart->data->readEnd) and writers update from another (writeStart->data->writeEnd).
98 // A reader is assured of a consistent snapshot if readStart equals readEnd.
99 // A writer first increments writeStart via a CAS and then writes the data and then increments writeEnd.
100 // Two writers use "writeStart" as their lock to ensure mutual exclusion.
101 
102 using VersionInfo_t = struct VersionInfo_t {
103  union {
104  volatile atomic<uint64_t> readStart;
105  volatile atomic<uint64_t> writeEnd;
106  };
107  union {
108  volatile atomic<uint64_t> writeStart;
109  volatile atomic<uint64_t> readEnd;
110  };
111 };
112 
113 
114 // 2 readers and 1 writer are recorded per byte of memory.
115 // In addition, a concurrency control mechanism is used for atomic accesses to the shadow memory.
116 // TODO: One may optimize the granularity of locking
117 
119  // Concurreny control via versioning
120  VersionInfo_t versionInfo;
121 
122  // Read1's label
124  //Reader1's CCT id
126 
127  // Read2's label
129  //Reader2's CCT id
131 
132  // Last writer
134  // Last writer's CCT id
136 };
137 
139 
140 // This is just a wrapper for a piece of Label along with a pointer to the location of the shadow memory.
141 // This is used for updating the shadow memory after reading from it.
142 // By remembering the shadowAddress, we don't have to recompute it by following the page table indices.
144  DataraceInfo_t* shadowAddress;
146 };
147 
148 
149 // A label is a concatenation of several LabelSegments
150 class Label {
151  private:
153  uint8_t m_labelLength;
154  volatile atomic<uint64_t> m_refCount;
155 
156  public:
157  inline uint8_t GetLength() const { return m_labelLength; }
158  inline void SetLength(uint64_t len) { m_labelLength = len; }
159  inline void IncrementRef() { m_refCount.fetch_add(1, memory_order_acq_rel); }
160  inline void DecrementRef() {
161  if (m_refCount.fetch_sub(1, memory_order_acq_rel) == 1) {
162  /*TODO free if 0 assert(0 && "Free label NYI"); */
163  }
164  }
165 
166  // Initial label
168  : m_labelLength(1), m_refCount(0) {
169  m_LabelSegment = new LabelSegment[GetLength()];
170  m_LabelSegment[0].offset = 0;
171  m_LabelSegment[0].span = 1;
172  m_LabelSegment[0].phase = 0;
173  }
174 
175 
176  LabelSegment* GetSegmentAtIndex(int index) const {
177  assert(index < GetLength());
178  return &m_LabelSegment[index];
179  }
180 
181  void CopyLabelSegments(const Label& label) {
182  SetLength(label.GetLength());
183  m_LabelSegment = new LabelSegment[GetLength()];
184  for (uint32_t i = 0; i < GetLength(); i++) {
185  m_LabelSegment[i] = label.m_LabelSegment[i];
186  }
187  }
188 
189  // After a fork, a new LabelSegment should be appended to the clone of the parent
190  void LabelCreateAfterFork(const Label& label, const LabelSegment& extension) {
191  SetLength(label.GetLength() + 1);
192  m_LabelSegment = new LabelSegment[GetLength()];
193  uint8_t i = 0;
194  for (; i < GetLength() - 1; i++) {
195  m_LabelSegment[i] = label.m_LabelSegment[i];
196  }
197  m_LabelSegment[i] = extension;
198  }
199 
200  // After a join, a the last segment should be dropped and offset should be incremented by span
201  // TODO: possible memory leak? refcount?
202  void LabelCreateAfterJoin(const Label& label) {
203  assert(label.GetLength() > 1);
204  SetLength(label.GetLength() - 1);
205  m_LabelSegment = new LabelSegment[GetLength()];
206  uint8_t i = 0;
207 
208  for (; i < GetLength(); i++) {
209  m_LabelSegment[i] = label.m_LabelSegment[i];
210  }
211  // increase the offset of last component by span
212  m_LabelSegment[i - 1].offset += m_LabelSegment[i - 1].span;
213  }
214 
215 
216  // TODO: possible memory leak? refcount?
217  void LabelCreateAfterBarrier(const Label& label) {
218  // Create a label with my parent's offset incremanted by span
219  assert(label.GetLength() > 1);
220  CopyLabelSegments(label);
221  m_LabelSegment[GetLength() - 2].offset += m_LabelSegment[GetLength() - 2].span;
222  // What to do about m_LabelSegment[GetLength()-1] ????
223  }
224 
225  // TODO: possible memory leak? refcount?
227  // Increment phase
228  assert(label.GetLength() > 1);
229  CopyLabelSegments(label);
230  m_LabelSegment[GetLength() - 1].phase++;
231  }
232 
233  // TODO: possible memory leak? refcount?
235  // Increment phase
236  assert(label.GetLength() > 1);
237  CopyLabelSegments(label);
238  m_LabelSegment[GetLength() - 1].phase++;
239  }
240 
241  explicit Label(LabelCreationType type, const Label& label, const LabelSegment& extension = defaultExtension) {
242  switch (type) {
243  case CREATE_AFTER_FORK:
244  LabelCreateAfterFork(label, extension);
245  break;
246  case CREATE_AFTER_JOIN:
247  LabelCreateAfterJoin(label);
248  break;
250  LabelCreateAfterBarrier(label);
251  break;
253  LabelCreateAfterEneringOrderedSection(label);
254  break;
256  LabelCreateAfterExitingOrderedSection(label);
257  break;
258  default:
259  assert(false);
260  }
261  }
262 
263  void PrintLabel() const {
264  fprintf(gTraceFile, "\n");
265  for (uint8_t i = 0; i < GetLength(); i++) {
266  fprintf(gTraceFile, "[%lu,%lu,%lu]", m_LabelSegment[i].offset, m_LabelSegment[i].span, m_LabelSegment[i].phase);
267  }
268  }
269 };
270 
272  private:
273  const Label& m_label;
274  uint8_t m_curLoc;
275  uint8_t m_len;
276 
277  public:
278  LabelIterator(const Label& label)
279  : m_label(label) {
280  m_curLoc = 0;
281  m_len = label.GetLength();
282  }
283 
285  if (m_len == m_curLoc) {
286  return nullptr;
287  }
288  return m_label.GetSegmentAtIndex(m_curLoc++);
289  }
290 };
291 
292 
293 // Holds thread local info
299 
300  public:
301  ThreadData_t(ADDRINT stackBaseAddress, ADDRINT stackEndAddress, ADDRINT stackCurrentFrameBaseAddress)
302  : m_curLable(nullptr),
303  m_stackBaseAddress(stackBaseAddress),
304  m_stackEndAddress(stackEndAddress),
305  m_stackCurrentFrameBaseAddress(stackCurrentFrameBaseAddress) {}
306  inline Label* GetLabel() const { return m_curLable; }
307  inline void SetLabel(Label* label) {
308  // TODO: If the current label had a zero ref count, we can possibly delete it
309  m_curLable = label;
310  }
311 };
312 
313 // function to access thread-specific data
314 ThreadData_t* GetTLS(THREADID threadid) {
315  ThreadData_t* tdata =
316  static_cast<ThreadData_t*>(PIN_GetThreadData(tls_key, threadid));
317  return tdata;
318 }
319 
320 // Atomically reads the version number at the beginning for a reader
321 static inline uint64_t GetReadStartForLoc(const DataraceInfo_t* const shadowAddress) {
322  return shadowAddress->versionInfo.readStart.load(memory_order_acquire);
323 }
324 
325 // Atomically reads the version number at the end for a reader
326 static inline uint64_t GetReadEndForLoc(const DataraceInfo_t* const shadowAddress) {
327  return shadowAddress->versionInfo.readEnd.load(memory_order_acquire);
328 }
329 
330 // Atomically reads the version number at the beginning for a writer
331 static inline uint64_t GetWriteStartForLoc(const DataraceInfo_t* const shadowAddress) {
332  return shadowAddress->versionInfo.writeStart.load(memory_order_acquire);
333 }
334 
335 // Atomically reads the version number at the end for a writer
336 static inline uint64_t GetWriteEndForLoc(const DataraceInfo_t* const shadowAddress) {
337  return shadowAddress->versionInfo.writeEnd.load(memory_order_acquire);
338 }
339 
340 static inline volatile atomic<uint64_t>* GetWriteStartAddressForLoc(DataraceInfo_t* const shadowAddress) {
341  return &(shadowAddress->versionInfo.writeEnd);
342 }
343 
344 // Updates the shadow memory with new labels and contexts information
345 static inline void UpdateShadowDataAtShadowAddress(DataraceInfo_t* shadowAddress, const DataraceInfo_t& info) {
346  shadowAddress->read1 = info.read1;
347  shadowAddress->read1Context = info.read1Context;
348  shadowAddress->read2 = info.read2;
349  shadowAddress->read2Context = info.read2Context;
350  shadowAddress->write1 = info.write1;
351  shadowAddress->write1Context = info.write1Context;
352 
353  // Update the version number at writeEnd
354  shadowAddress->versionInfo.writeEnd.store(shadowAddress->versionInfo.writeStart, memory_order_release); //writeStart will be most upto date
355 }
356 
357 // Reads the labels and contexts from shadow memory
358 static inline void ReadShadowData(DataraceInfo_t* info, DataraceInfo_t* shadowAddress) {
359  info->read1 = shadowAddress->read1;
360  info->read1Context = shadowAddress->read1Context;
361  info->read2 = shadowAddress->read2;
362  info->read2Context = shadowAddress->read2Context;
363  info->write1 = shadowAddress->write1;
364  info->write1Context = shadowAddress->write1Context;
365 }
366 
367 // Snapshot is consistent iff both version numbers are same.
368 static inline bool IsConsistentSpapshot(const DataraceInfo_t* const info) {
369  return info->versionInfo.readStart == info->versionInfo.readEnd;
370 }
371 // Read a consistent snapshot of the shadow address:
372 // Uses Leslie Lamport's algorithm listed for readers and writers with two integers.
373 inline void ReadShadowMemory(DataraceInfo_t* shadowAddress, DataraceInfo_t* info) {
374 #ifdef DEBUG_LOOP
375  int trip = 0;
376 #endif
377 
378  do {
379  // Read first version number
380  info->versionInfo.readStart = GetReadStartForLoc(shadowAddress);
381  // Read data
382  ReadShadowData(info, shadowAddress);
383  // Read second version number
384  info->versionInfo.readEnd = GetReadEndForLoc(shadowAddress);
385 #ifdef DEBUG_LOOP
386  if (trip++ > 100000) {
387  fprintf(stderr, "\n Loop trip > %d in line %d ... Ver1 = %lu .. ver2 = %lu ... %d", trip, __LINE__, info->versionInfo.readStart, info->versionInfo.readEnd, PIN_ThreadId());
388  }
389 #endif
390  } while (!IsConsistentSpapshot(info));
391 
392 #ifdef DEBUG_LOOP
393  if (trip > 100000) {
394  fprintf(stderr, "\n Done ... %d", PIN_ThreadId());
395  }
396 #endif
397 }
398 
399 // Write a consistent snapshot of the shadow address:
400 // Uses Leslie Lamport algorithm listed for readers and writers with two integers.
401 static inline bool TryWriteShadowMemory(DataraceInfo_t* shadowAddress, const DataraceInfo_t& info) {
402  // Get the first integer for this shadow location:
403  volatile atomic<uint64_t>* firstVersionLoc = GetWriteStartAddressForLoc(shadowAddress);
404  uint64_t version = info.versionInfo.writeStart;
405  if (!firstVersionLoc->compare_exchange_strong(version, version + 1))
406  return false; // fail retry
407 
408  UpdateShadowDataAtShadowAddress(shadowAddress, info);
409  return true;
410 }
411 
412 // Fetch the current threads's logical label
413 static inline Label* GetMyLabel(THREADID threadId) {
414  return GetTLS(threadId)->GetLabel();
415 }
416 
417 // Fetch the current threads's logical label
418 static inline void SetMyLabel(THREADID threadId, Label* label) {
419  GetTLS(threadId)->SetLabel(label);
420 }
421 
422 static inline void UpdateLabel(Label** oldLabel, Label* newLabel) {
423  (*oldLabel) = newLabel;
424 }
425 
426 static inline void UpdateContext(ContextHandle_t* oldCtxt, ContextHandle_t ctxt) {
427  (*oldCtxt) = ctxt;
428 }
429 
430 static inline void CommitChangesToShadowMemory(Label* oldLabel, Label* newLabel) {
431  if (oldLabel) {
432  oldLabel->DecrementRef();
433  }
434  newLabel->IncrementRef();
435 }
436 
437 static inline bool HappensBefore(const Label* const oldLabel, const Label* const newLabel) {
438  // newLabel ought to be non null
439  assert(newLabel && "newLabel can't be NULL");
440 
441  /*
442  [0,1,0][2,200,0]
443  [0,1,0][1,200,0]
444 
445  if ((oldLabel && newLabel) && (oldLabel->GetLength () == 2) && (newLabel->GetLength() == 2) && (oldLabel != newLabel)) {
446  bar();
447  }
448  */
449 
450  // If oldLabel is null, then this is the first access, hence return true
451  if (oldLabel == nullptr)
452  return true;
453 
454  // Case 1: oldLabel is a prefix of newLabel
455  LabelIterator oldLabelIter = LabelIterator(*oldLabel);
456  LabelIterator newLabelIter = LabelIterator(*newLabel);
457 
458  // Special case TODO // if oldLabel == newLabel , return true;
459  LabelSegment* oldLabelSegment = nullptr;
460  LabelSegment* newLabelSegment = nullptr;
461 
462  while (true) {
463  oldLabelSegment = oldLabelIter.NextSegment();
464  newLabelSegment = newLabelIter.NextSegment();
465  if (oldLabelSegment == nullptr)
466  return true; // Found a prefix
467 
468  if (newLabelSegment == nullptr) {
469  assert(0 && "I don't expect this to happen");
470  return false; // oldLabel is longer than newLabel
471  }
472 
473  if (oldLabelSegment->offset != newLabelSegment->offset)
474  break;
475  }
476 
477  //Case 2: The place where they diverge are of the form P[O(x),SPAN]S_x
478  // and P[O(y),SPAN]S_y and O(x) < O(y) and ( O(x) mod SPAN == O(y) mod SPAN )
479  assert(oldLabelSegment->span == newLabelSegment->span);
480 
481  if ((oldLabelSegment->offset < newLabelSegment->offset) &&
482  (oldLabelSegment->offset % newLabelSegment->span == newLabelSegment->offset % newLabelSegment->span)) {
483  return true;
484  }
485 
486  // Now check the ordered secton case:
487  if ((oldLabelSegment->offset < newLabelSegment->offset) &&
488  (EXIT_RANK(oldLabelSegment->phase) < ENTER_RANK(newLabelSegment->phase))) {
489  return true;
490  }
491  return false;
492 }
493 
494 static inline bool IsLeftOf(const Label* const newLabel, const Label* const oldLabel) {
495  // newLabel ought to be non null
496  assert(newLabel && "newLabel can't be NULL");
497 
498  // If oldLabel is null, then this is the first access, hence return false
499  if (oldLabel == nullptr)
500  return false;
501 
502  LabelIterator oldLabelIter = LabelIterator(*oldLabel);
503  LabelIterator newLabelIter = LabelIterator(*newLabel);
504 
505 
506  while (true) {
507  LabelSegment* oldLabelSegment = oldLabelIter.NextSegment();
508  LabelSegment* newLabelSegment = newLabelIter.NextSegment();
509  if (oldLabelSegment == nullptr || newLabelSegment == nullptr)
510  return false; // Found a prefix
511 
512  if ((oldLabelSegment->offset % newLabelSegment->span < newLabelSegment->offset % newLabelSegment->span)) {
513  return true;
514  }
515  }
516 
517  return false;
518 }
519 
520 static inline bool MaximizesExitRank(const Label* const newLabel, const Label* const oldLabel) {
521  // newLabel ought to be non null
522  assert(newLabel && "newLabel can't be NULL");
523 
524  // If oldLabel is null, then this is the first access, hence return false
525  if (oldLabel == nullptr)
526  return false;
527 
528  LabelIterator oldLabelIter = LabelIterator(*oldLabel);
529  LabelIterator newLabelIter = LabelIterator(*newLabel);
530 
531  while (true) {
532  LabelSegment* oldLabelSegment = oldLabelIter.NextSegment();
533  LabelSegment* newLabelSegment = newLabelIter.NextSegment();
534  if (oldLabelSegment == nullptr || newLabelSegment == nullptr)
535  return false;
536 
537  if ((oldLabelSegment->offset % newLabelSegment->span != newLabelSegment->offset % newLabelSegment->span)) {
538  // At the level where offsets diverge
539  return EXIT_RANK(newLabelSegment->phase) > EXIT_RANK(oldLabelSegment->phase);
540  }
541  // TODO(preexisting-bug): the original code re-called NextSegment()
542  // here on both iterators, silently double-advancing per loop iteration
543  // and dropping the fetched segments (dead stores). Removed to match
544  // the sibling HappensBefore() function's advance-once-per-iteration
545  // pattern. Behavior may change for label sequences longer than 1
546  // segment; this file has no `make check` coverage today.
547  }
548  return false;
549 }
550 
551 
552 static inline void DumpRaceInfo(ContextHandle_t oldCtxt, Label* oldLbl, ContextHandle_t newCtxt, Label* newLbl) {
553  PIN_LockClient();
554  fprintf(gTraceFile, "\n ----------");
555  oldLbl->PrintLabel();
556  PrintFullCallingContext(oldCtxt);
557  fprintf(gTraceFile, "\n *****RACES WITH*****");
558  newLbl->PrintLabel();
559  PrintFullCallingContext(newCtxt);
560  fprintf(gTraceFile, "\n ----------");
561  PIN_UnlockClient();
562 }
563 
564 static inline void CheckRead(DataraceInfo_t* shadowAddress, Label* myLabel, uint32_t opaqueHandle, THREADID threadId) {
565  bool reported = false;
566  // TODO .. Is this do-while excessive?
567  do {
568  DataraceInfo_t shadowData;
569  ReadShadowMemory(shadowAddress, &shadowData);
570  bool updated1 = false;
571  Label* oldR1Label = nullptr;
572  Label* oldR2Label = nullptr;
573  bool updated2 = false;
574 
575  // If we have reported a data race originating from this read
576  // then let's not inundate with more data races at the same location.
577  if (!reported && !HappensBefore(shadowData.write1, myLabel)) {
578  // Report W->R Data race
579  fprintf(stderr, "\n W->R race");
580  DumpRaceInfo(shadowData.write1Context, shadowData.write1, GetContextHandle(threadId, opaqueHandle), myLabel);
581  reported = true;
582  }
583 
584  // Update labels
585  /* TODO replace HappensBefore with SAME THREAD */
586  if (MaximizesExitRank(myLabel, shadowData.read1) || IsLeftOf(myLabel, shadowData.read1) || HappensBefore(shadowData.read1, myLabel)) {
587  oldR1Label = shadowData.read1;
588  UpdateLabel(&shadowData.read1, myLabel);
589  UpdateContext(&shadowData.read1Context, GetContextHandle(threadId, opaqueHandle));
590  updated1 = true;
591  }
592 
593  /* TODO replace HappensBefore with SAME THREAD */
594  if ((shadowData.read2 && IsLeftOf(shadowData.read2, myLabel)) || HappensBefore(shadowData.read2, myLabel)) {
595  oldR2Label = shadowData.read2;
596  UpdateLabel(&shadowData.read2, myLabel);
597  UpdateContext(&shadowData.read2Context, GetContextHandle(threadId, opaqueHandle));
598  updated2 = true;
599  }
600 
601  if (updated1 || updated2) {
602  if (!TryWriteShadowMemory(shadowAddress, shadowData)) {
603  // someone updated the shadow memory before we could, we need to redo the entire process
604  continue;
605  }
606  // Commit ref count to labels
607  if (updated1) {
608  CommitChangesToShadowMemory(oldR1Label, myLabel);
609  }
610  if (updated2) {
611  CommitChangesToShadowMemory(oldR2Label, myLabel);
612  }
613  }
614  break;
615  } while (true);
616 }
617 
618 static inline void CheckWrite(DataraceInfo_t* shadowAddress, Label* myLabel, uint32_t opaqueHandle, THREADID threadId) {
619  bool reported = false;
620  do {
621  DataraceInfo_t shadowData;
622  ReadShadowMemory(shadowAddress, &shadowData);
623  //#define DEBUG
624 #ifdef DEBUG
625  if (shadowData.write1) {
626  fprintf(stderr, "\n Comparing labels:");
627  myLabel->PrintLabel();
628  shadowData.write1->PrintLabel();
629  } else {
630  fprintf(stderr, "\n shadowData.write1 is NULL");
631  }
632 #endif
633  // If we have reported a data race originating from this read
634  // then let's not inundate with more data races at the same location.
635  if (!reported && !HappensBefore(shadowData.write1, myLabel)) {
636  // Report W->W Data race
637  reported = true;
638  fprintf(stderr, "\n W->W race");
639  DumpRaceInfo(shadowData.write1Context, shadowData.write1, GetContextHandle(threadId, opaqueHandle), myLabel);
640  }
641  if (!reported && !HappensBefore(shadowData.read1, myLabel)) {
642  // Report R->W Data race
643  reported = true;
644  fprintf(stderr, "\n R->W race");
645  DumpRaceInfo(shadowData.read1Context, shadowData.read1, GetContextHandle(threadId, opaqueHandle), myLabel);
646  }
647  if (!reported && !HappensBefore(shadowData.read2, myLabel)) {
648  // Report R->W Data race
649  fprintf(stderr, "\n R->W race");
650  DumpRaceInfo(shadowData.read2Context, shadowData.read2, GetContextHandle(threadId, opaqueHandle), myLabel);
651  reported = true;
652  }
653  Label* oldW1Label = shadowData.write1;
654  // Update label
655  UpdateLabel(&shadowData.write1, myLabel);
656  UpdateContext(&shadowData.write1Context, GetContextHandle(threadId, opaqueHandle));
657  if (!TryWriteShadowMemory(shadowAddress, shadowData)) {
658  // someone updated the shadow memory before we could, we need to redo the entire process
659  continue;
660  }
661  CommitChangesToShadowMemory(oldW1Label, myLabel);
662  break;
663  } while (true);
664 }
665 
666 
667 // Run the datarace protocol and report race.
668 static inline void ExecuteOffsetSpanPhaseProtocol(DataraceInfo_t* status, Label* myLabel, bool accessType, uint32_t opaqueHandle, THREADID threadId) {
669  if (accessType == WRITE_ACCESS) {
670  CheckWrite(status, myLabel, opaqueHandle, threadId);
671  } else { // READ_ACCESS
672  CheckRead(status, myLabel, opaqueHandle, threadId);
673  }
674 }
675 
676 
677 static inline VOID CheckRace(VOID* addr, uint32_t accessLen, bool accessType, uint32_t opaqueHandle, THREADID threadId) {
678  // Get my Label
679  Label* myLabel = GetMyLabel(threadId);
680  // if myLabel is NULL, then we are in the initial serial part of the program, hence we can skip the rest
681  if (myLabel == nullptr)
682  return;
683 
684  DataraceInfo_t* status = get<0>(sm.GetOrCreateShadowBaseAddress((size_t)addr));
685  int overflow = (int)(PAGE_OFFSET((uint64_t)addr)) - (int)((PAGE_OFFSET_MASK - (accessLen - 1)));
686  status += PAGE_OFFSET((uint64_t)addr);
687 
688  if (overflow <= 0) {
689  // The accessed word's shadow memory does not straddle 2 64K shadow pages.
690  // Execute the protocol for each byte of the memory accessed.
691  for (uint32_t i = 0; i < accessLen; i++) {
692  ExecuteOffsetSpanPhaseProtocol(&status[i], myLabel, accessType, opaqueHandle, threadId);
693  }
694  } else {
695  // The accessed word's shadow memory straddles 2 64K shadow pages.
696  // Execute the protocol for each byte of the memory accessed in the first page
697  for (uint32_t nonOverflowBytes = 0; nonOverflowBytes < accessLen - overflow; nonOverflowBytes++) {
698  ExecuteOffsetSpanPhaseProtocol(&status[nonOverflowBytes], myLabel, accessType, opaqueHandle, threadId);
699  }
700  // Execute the protocol for each byte of the memory accessed in the next page
701  status = get<0>(sm.GetOrCreateShadowBaseAddress((size_t)(((char*)addr) + accessLen))); // +accessLen so that we get next page
702  for (int i = 0; i < overflow; i++) {
703  ExecuteOffsetSpanPhaseProtocol(&status[i], myLabel, accessType, opaqueHandle, threadId);
704  }
705  // TODO: We never expect the access to straddle more than 2 pages. If that happens we are hosed.
706  }
707 }
708 
709 
710 // If it is one of ignoreable instructions, then skip instrumentation.
711 static inline bool IsIgnorableIns(INS ins) {
712  //TODO .. Eliminate this check with a better one
713  /*
714  Access to the stack simply means that the instruction accesses memory relative to the stack pointer (ESP or RSP), or the frame pointer (EBP or RBP). In code compiled without a frame pointer (where EBP/RBP is used as a general register), this may give a misleading result.
715  */
716  if (INS_IsStackRead(ins) || INS_IsStackWrite(ins))
717  return true;
718 
719  // skip call, ret and JMP instructions
720  if (INS_IsControlFlow(ins) || INS_IsRet(ins)) {
721  return true;
722  }
723  // If ins is in libgomp.so, or /lib64/ld-linux-x86-64.so.2 skip it
724  for (int i = 0; i < gNumCurSkipImages; i++) {
725  if ((INS_Address(ins) >= gSkipImageAddressRanges[i][0]) && ((INS_Address(ins) < gSkipImageAddressRanges[i][1]))) {
726  return true;
727  }
728  }
729  return false;
730 }
731 #define MASTER_BEGIN_FN_NAME "gomp_datarace_master_begin_dynamic_work"
732 #define DYNAMIC_BEGIN_FN_NAME "gomp_datarace_begin_dynamic_work"
733 #define DYNAMIC_END_FN_NAME "gomp_datarace_master_end_dynamic_work"
734 #define ORDERED_ENTER_FN_NAME "gomp_datarace_begin_ordered_section"
735 #define ORDERED_EXIT_FN_NAME "gomp_datarace_end_ordered_section"
736 #define CRITICAL_ENTER_FN_NAME "gomp_datarace_begin_critical"
737 #define CRITICAL_EXIT_FN_NAME "gomp_datarace_end_critical"
738 // void gomp_datarace_begin_dynamic_work(uint64_t region_id, long span, long iter);
739 // void gomp_datarace_master_end_dynamic_work()
740 // void gomp_datarace_master_begin_dynamic_work(uint64_t region_id, long span);
741 // void gomp_datarace_begin_ordered_section(uint64_t region_id);
742 // void gomp_datarace_begin_critical(void *);
743 // void gomp_datarace_end_critical(void *);
744 using FP_MASTER = void (*)(uint64_t, long);
745 using FP_WORKER = void (*)(uint64_t, long, long);
746 using FP_WORKER_END = void (*)();
747 using FP_ORDERED_ENTER = void (*)(uint64_t);
748 using FP_ORDERED_EXIT = void (*)(uint64_t);
749 using FP_CRITICAL_ENTER = void (*)(void*);
750 using FP_CRITICAL_EXIT = void (*)(void*);
751 
752 
753 void new_MASTER_BEGIN_FN_NAME(uint64_t region_id, long span, THREADID threadid) {
754  assert(region_id < MAX_REGIONS);
755  // Publish my label into the labelHashTable
756  assert(gRegionIdToMasterLabelMap[region_id] == 0);
757  Label* myLabel = GetMyLabel(threadid);
758  // if the label was NULL, let us create a new initial label
759  if (myLabel == nullptr) {
760  myLabel = new Label();
761  SetMyLabel(threadid, myLabel);
762  }
763  gRegionIdToMasterLabelMap[region_id] = myLabel;
764 }
765 
766 void new_DYNAMIC_BEGIN_FN_NAME(uint64_t region_id, long span, long iter, THREADID threadid) {
767  // Fetch parent label and create new one
768  //fprintf(stderr,"\n fetched parent label");
769 
770  assert(gRegionIdToMasterLabelMap[region_id] != NULL);
771 
772  Label* parentLabel = gRegionIdToMasterLabelMap[region_id];
773  // Create child label
774  LabelSegment extension;
775  extension.span = span;
776  extension.offset = iter;
777  extension.phase = 0;
778  Label* myLabel = new Label(CREATE_AFTER_FORK, *parentLabel, extension);
779  SetMyLabel(threadid, myLabel);
780  //myLabel->PrintLabel();
781 }
782 
783 
784 void new_DYNAMIC_END_FN_NAME(THREADID threadId) {
785  // Fetch current label and create new one
786  Label* parentLabel = GetMyLabel(threadId);
787  Label* myLabel = new Label(CREATE_AFTER_JOIN, *parentLabel);
788  SetMyLabel(threadId, myLabel);
789  //myLabel->PrintLabel();
790 }
791 
792 
793 void new_ORDERED_ENTER_FN_NAME(uint64_t region_id, THREADID threadId) {
794  // Fetch current label and create new one
795  Label* parentLabel = GetMyLabel(threadId);
796  Label* myLabel = new Label(CREATE_AFTER_ENTERING_ORDERED_SECTION, *parentLabel);
797  SetMyLabel(threadId, myLabel);
798  //myLabel->PrintLabel();
799 }
800 
801 void new_ORDERED_EXIT_FN_NAME(uint64_t region_id, THREADID threadId) {
802  // Fetch current label and create new one
803  Label* parentLabel = GetMyLabel(threadId);
804  Label* myLabel = new Label(CREATE_AFTER_EXITING_ORDERED_SECTION, *parentLabel);
805  SetMyLabel(threadId, myLabel);
806  //myLabel->PrintLabel();
807 }
808 
809 void new_CRITICAL_ENTER_FN_NAME(void* name, THREADID threadid) {
810  if (name) {
811  // name is the address of the a symbol i.g. 0x602d20 <.gomp_critical_user_FOO> for a lock FOO
812  } else {
813  // Analymous locks
814  }
815 }
816 
817 void new_CRITICAL_EXIT_FN_NAME(void* name, THREADID threadid) {
818  if (name) {
819  // name is the address of the a symbol i.g. 0x602d20 <.gomp_critical_user_FOO> for a lock FOO
820  } else {
821  // Anonymous locks
822  }
823 }
824 
825 // Overrides for various functions
826 VOID Overrides(IMG img, VOID* v) {
827  // Master setup
828  RTN rtn = RTN_FindByName(img, MASTER_BEGIN_FN_NAME);
829  if (RTN_Valid(rtn)) {
830  // Define a function prototype that describes the application routine
831  // that will be replaced.
832  //
833  PROTO proto_master = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT,
834  MASTER_BEGIN_FN_NAME, PIN_PARG(uint64_t), PIN_PARG(long),
835  PIN_PARG_END());
836 
837  // Replace the application routine with the replacement function.
838  // Additional arguments have been added to the replacement routine.
839  //
840  RTN_ReplaceSignature(rtn, AFUNPTR(new_MASTER_BEGIN_FN_NAME),
841  IARG_PROTOTYPE, proto_master,
842  IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
843  IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
844  IARG_THREAD_ID, IARG_END);
845  // Free the function prototype.
846  PROTO_Free(proto_master);
847  }
848 
849  // Dynamic Start
850  rtn = RTN_FindByName(img, DYNAMIC_BEGIN_FN_NAME);
851  if (RTN_Valid(rtn)) {
852  PROTO proto_worker = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT,
853  DYNAMIC_BEGIN_FN_NAME, PIN_PARG(uint64_t), PIN_PARG(long), PIN_PARG(long),
854  PIN_PARG_END());
855  RTN_ReplaceSignature(rtn, AFUNPTR(new_DYNAMIC_BEGIN_FN_NAME),
856  IARG_PROTOTYPE, proto_worker,
857  IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
858  IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
859  IARG_FUNCARG_ENTRYPOINT_VALUE, 2,
860  IARG_THREAD_ID, IARG_END);
861  PROTO_Free(proto_worker);
862  }
863 
864  // Dynamic end
865  rtn = RTN_FindByName(img, DYNAMIC_END_FN_NAME);
866  if (RTN_Valid(rtn)) {
867  PROTO proto_end = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT,
868  DYNAMIC_END_FN_NAME, PIN_PARG_END());
869  RTN_ReplaceSignature(rtn, AFUNPTR(new_DYNAMIC_END_FN_NAME),
870  IARG_PROTOTYPE, proto_end,
871  IARG_THREAD_ID, IARG_END);
872  PROTO_Free(proto_end);
873  }
874 
875  // Ordered Enter
876  rtn = RTN_FindByName(img, ORDERED_ENTER_FN_NAME);
877  if (RTN_Valid(rtn)) {
878  PROTO ordered_enter = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT,
879  ORDERED_ENTER_FN_NAME, PIN_PARG(uint64_t), PIN_PARG_END());
880  RTN_ReplaceSignature(rtn, AFUNPTR(new_ORDERED_ENTER_FN_NAME),
881  IARG_PROTOTYPE, ordered_enter,
882  IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
883  IARG_THREAD_ID, IARG_END);
884  PROTO_Free(ordered_enter);
885  }
886 
887  // Ordered Exit
888  rtn = RTN_FindByName(img, ORDERED_EXIT_FN_NAME);
889  if (RTN_Valid(rtn)) {
890  PROTO ordered_exit = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT,
891  ORDERED_EXIT_FN_NAME, PIN_PARG(uint64_t), PIN_PARG_END());
892  RTN_ReplaceSignature(rtn, AFUNPTR(new_ORDERED_EXIT_FN_NAME),
893  IARG_PROTOTYPE, ordered_exit,
894  IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
895  IARG_THREAD_ID, IARG_END);
896  PROTO_Free(ordered_exit);
897  }
898 
899  // Critical Enter
900  rtn = RTN_FindByName(img, CRITICAL_ENTER_FN_NAME);
901  if (RTN_Valid(rtn)) {
902  PROTO critical_enter = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT,
903  CRITICAL_ENTER_FN_NAME, PIN_PARG(void*), PIN_PARG_END());
904  RTN_ReplaceSignature(rtn, AFUNPTR(new_CRITICAL_ENTER_FN_NAME),
905  IARG_PROTOTYPE, critical_enter,
906  IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
907  IARG_THREAD_ID, IARG_END);
908  PROTO_Free(critical_enter);
909  }
910  // Critical Exit
911  rtn = RTN_FindByName(img, CRITICAL_EXIT_FN_NAME);
912  if (RTN_Valid(rtn)) {
913  PROTO critical_exit = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT,
914  CRITICAL_EXIT_FN_NAME, PIN_PARG(void*), PIN_PARG_END());
915  RTN_ReplaceSignature(rtn, AFUNPTR(new_CRITICAL_EXIT_FN_NAME),
916  IARG_PROTOTYPE, critical_exit,
917  IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
918  IARG_THREAD_ID, IARG_END);
919  PROTO_Free(critical_exit);
920  }
921 }
922 
923 
924 // Is called for every load, store instruction to insert necessary instrumentation.
925 static VOID InstrumentInsCallback(INS ins, VOID* v, const uint32_t opaqueHandle) {
926  if (IsIgnorableIns(ins))
927  return;
928 
929  // If this is an atomic instruction, act as if a lock (HW LOCK) was taken and released
930  if (INS_IsAtomicUpdate(ins)) {
931  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
933  IARG_PTR, HW_LOCK,
934  IARG_THREAD_ID, IARG_END);
935  }
936 
937  // How may memory operations?
938  UINT32 memOperands = INS_MemoryOperandCount(ins);
939  // Iterate over each memory operand of the instruction and add Analysis routine to check races.
940  // We correctly handle instructions that do both read and write.
941  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
942  if (INS_MemoryOperandIsWritten(ins, memOp)) {
943  INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
944  (AFUNPTR)CheckRace,
945  IARG_MEMORYOP_EA, memOp, IARG_MEMORYWRITE_SIZE, IARG_BOOL, WRITE_ACCESS /* write */, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END);
946  } else if (INS_MemoryOperandIsRead(ins, memOp)) {
947  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)CheckRace, IARG_MEMORYOP_EA, memOp, IARG_MEMORYREAD_SIZE, IARG_BOOL, READ_ACCESS /* read */, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END);
948  }
949  }
950  if (INS_IsAtomicUpdate(ins)) {
951  INS_InsertPredicatedCall(ins, IPOINT_AFTER,
952  (AFUNPTR)new_CRITICAL_EXIT_FN_NAME,
953  IARG_PTR, HW_LOCK,
954  IARG_THREAD_ID, IARG_END);
955  }
956 }
957 
958 
959 static INT32 Usage() {
960  PIN_ERROR("PinTool for datarace detection.\n" + KNOB_BASE::StringKnobSummary() + "\n");
961  return -1;
962 }
963 
964 VOID ThreadStart(THREADID threadid, CONTEXT* ctxt, INT32 flags, VOID* v) {
965  // Get the stack base address:
966  ADDRINT stackBaseAddr = PIN_GetContextReg(ctxt, REG_STACK_PTR);
967  pthread_attr_t attr;
968  size_t stacksize;
969  pthread_attr_init(&attr);
970  pthread_attr_getstacksize(&attr, &stacksize);
971  ThreadData_t* tdata = new ThreadData_t(stackBaseAddr, stackBaseAddr + stacksize, stackBaseAddr);
972  //fprintf(stderr,"\n m_stackBaseAddress = %lu, m_stackEndAddress = %lu, size = %lu", stackBaseAddr, stackBaseAddr + stacksize, stacksize);
973  // Label will be NULL
974  PIN_SetThreadData(tls_key, tdata, threadid);
975 }
976 
977 static inline VOID InstrumentImageLoad(IMG img, VOID* v) {
978  for (unsigned int i = 0; i < MAX_SKIP_IMAGES; i++) {
979  if (IMG_Name(img) == skipImages[i]) {
980  gSkipImageAddressRanges[gNumCurSkipImages][0] = IMG_LowAddress(img);
981  gSkipImageAddressRanges[gNumCurSkipImages][1] = IMG_HighAddress(img);
983  fprintf(stderr, "\n Skipping image %s", skipImages[i].c_str());
984  break;
985  }
986  }
987 }
988 
989 // Initialize the data structures needed before launching the target program
990 void InitDataRaceSpy(int argc, char* argv[]) {
991  // Create output file
992  char name[MAX_FILE_PATH] = "DataRaceSpy.out.";
993  char* envPath = getenv("OUTPUT_FILE");
994  if (envPath) {
995  // assumes max of MAX_FILE_PATH
996  snprintf(name, sizeof(name), "%s", envPath);
997  }
998  gethostname(name + strlen(name), MAX_FILE_PATH - strlen(name));
999  pid_t pid = getpid();
1000  sprintf(name + strlen(name), "%d", pid);
1001  cerr << "\n Creating dead info file at:" << name << "\n";
1002 
1003  gTraceFile = fopen(name, "w");
1004  // print the arguments passed
1005  fprintf(gTraceFile, "\n");
1006  for (int i = 0; i < argc; i++) {
1007  fprintf(gTraceFile, "%s ", argv[i]);
1008  }
1009  fprintf(gTraceFile, "\n");
1010 
1011  // Allocate gRegionIdToMasterLabelMap. Array of pointers, so sizeof(Label*) is intended.
1012  // NOLINTNEXTLINE(bugprone-sizeof-expression)
1013  gRegionIdToMasterLabelMap = (Label**)calloc(MAX_REGIONS, sizeof(Label*));
1014 
1015  // Obtain a key for TLS storage.
1016  tls_key = PIN_CreateThreadDataKey(nullptr);
1017 
1018  // Register ThreadStart to be called when a thread starts.
1019  PIN_AddThreadStartFunction(ThreadStart, nullptr);
1020 
1021  // Record Module information about OMP runtime
1022  IMG_AddInstrumentFunction(InstrumentImageLoad, nullptr);
1023 }
1024 
1025 // Main for DataraceSpy, initialize the tool, register instrumentation functions and call the target program.
1026 int main(int argc, char* argv[]) {
1027  // Initialize PIN
1028  if (PIN_Init(argc, argv))
1029  return Usage();
1030  // Initialize Symbols, we need them to report functions and lines
1031  PIN_InitSymbols();
1032  // Intialize DataraceSpy
1033  InitDataRaceSpy(argc, argv);
1034  // Intialize CCTLib
1036  // Look up and replace some functions
1037  IMG_AddInstrumentFunction(Overrides, nullptr);
1038  fprintf(stderr, "\n TODO TODO ... eliminate stack local check and make it robust");
1039  // Launch program now
1040  PIN_StartProgram();
1041  return 0;
1042 }
#define INTERESTING_INS_MEMORY_ACCESS
Definition: cctlib.H:87
const Label & m_label
LabelSegment * NextSegment()
LabelIterator(const Label &label)
void LabelCreateAfterBarrier(const Label &label)
Label(LabelCreationType type, const Label &label, const LabelSegment &extension=defaultExtension)
LabelSegment * m_LabelSegment
void LabelCreateAfterExitingOrderedSection(const Label &label)
LabelSegment * GetSegmentAtIndex(int index) const
void LabelCreateAfterEneringOrderedSection(const Label &label)
void SetLength(uint64_t len)
void IncrementRef()
volatile atomic< uint64_t > m_refCount
void LabelCreateAfterFork(const Label &label, const LabelSegment &extension)
void PrintLabel() const
void DecrementRef()
void CopyLabelSegments(const Label &label)
uint8_t m_labelLength
void LabelCreateAfterJoin(const Label &label)
uint8_t GetLength() const
Label * GetLabel() const
ThreadData_t(ADDRINT stackBaseAddress, ADDRINT stackEndAddress, ADDRINT stackCurrentFrameBaseAddress)
ADDRINT m_stackCurrentFrameBaseAddress
void SetLabel(Label *label)
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
volatile uint8_t status
Definition: cctlib.cpp:230
ContextHandle_t GetContextHandle(const THREADID id, const uint32_t slot)
Definition: cctlib.cpp:1356
uint32_t ContextHandle_t
Definition: cctlib.H:22
#define MAX_SKIP_IMAGES
volatile atomic< uint64_t > writeEnd
int main(int argc, char *argv[])
#define MAX_REGIONS
ConcurrentShadowMemory< DataraceInfo_t > sm
#define EXIT_RANK(phase)
static void UpdateLabel(Label **oldLabel, Label *newLabel)
#define LINUX_LD_NAME
static bool TryWriteShadowMemory(DataraceInfo_t *shadowAddress, const DataraceInfo_t &info)
static FILE * gTraceFile
static ADDRINT gSkipImageAddressRanges[MAX_SKIP_IMAGES][2]
static volatile atomic< uint64_t > * GetWriteStartAddressForLoc(DataraceInfo_t *const shadowAddress)
static const LabelSegment defaultExtension
#define MAX_FILE_PATH
VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
static VOID CheckRace(VOID *addr, uint32_t accessLen, bool accessType, uint32_t opaqueHandle, THREADID threadId)
LabelCreationType
@ CREATE_AFTER_JOIN
@ CREATE_FIRST
@ CREATE_AFTER_EXITING_ORDERED_SECTION
@ CREATE_AFTER_FORK
@ CREATE_AFTER_BARRIER
@ CREATE_AFTER_ENTERING_ORDERED_SECTION
void(*)(void *) FP_CRITICAL_ENTER
static uint64_t GetReadStartForLoc(const DataraceInfo_t *const shadowAddress)
static bool MaximizesExitRank(const Label *const newLabel, const Label *const oldLabel)
void(*)(uint64_t) FP_ORDERED_EXIT
static bool IsConsistentSpapshot(const DataraceInfo_t *const info)
void new_DYNAMIC_BEGIN_FN_NAME(uint64_t region_id, long span, long iter, THREADID threadid)
void new_DYNAMIC_END_FN_NAME(THREADID threadId)
void new_CRITICAL_ENTER_FN_NAME(void *name, THREADID threadid)
void ReadShadowMemory(DataraceInfo_t *shadowAddress, DataraceInfo_t *info)
#define OMP_RUMTIMR_LIB_NAME
static void ReadShadowData(DataraceInfo_t *info, DataraceInfo_t *shadowAddress)
static Label * GetMyLabel(THREADID threadId)
static INT32 Usage()
static bool IsLeftOf(const Label *const newLabel, const Label *const oldLabel)
void new_MASTER_BEGIN_FN_NAME(uint64_t region_id, long span, THREADID threadid)
void new_CRITICAL_EXIT_FN_NAME(void *name, THREADID threadid)
static bool HappensBefore(const Label *const oldLabel, const Label *const newLabel)
DataraceInfo_t data
static const char * HW_LOCK
ContextHandle_t write1Context
static string skipImages[]
void(*)(uint64_t) FP_ORDERED_ENTER
#define CRITICAL_EXIT_FN_NAME
void InitDataRaceSpy(int argc, char *argv[])
void new_ORDERED_EXIT_FN_NAME(uint64_t region_id, THREADID threadId)
static uint64_t GetWriteEndForLoc(const DataraceInfo_t *const shadowAddress)
#define MASTER_BEGIN_FN_NAME
static void CheckRead(DataraceInfo_t *shadowAddress, Label *myLabel, uint32_t opaqueHandle, THREADID threadId)
static void ExecuteOffsetSpanPhaseProtocol(DataraceInfo_t *status, Label *myLabel, bool accessType, uint32_t opaqueHandle, THREADID threadId)
static bool IsIgnorableIns(INS ins)
static int gNumCurSkipImages
ContextHandle_t read2Context
static VOID InstrumentInsCallback(INS ins, VOID *v, const uint32_t opaqueHandle)
Label * read2
static uint64_t GetWriteStartForLoc(const DataraceInfo_t *const shadowAddress)
#define ORDERED_EXIT_FN_NAME
#define ORDERED_ENTER_FN_NAME
void(*)(uint64_t, long, long) FP_WORKER
struct DataraceInfo_t { VersionInfo_t versionInfo DataraceInfo_t
void(*)() FP_WORKER_END
Label * write1
static TLS_KEY tls_key
static void SetMyLabel(THREADID threadId, Label *label)
static uint64_t GetReadEndForLoc(const DataraceInfo_t *const shadowAddress)
VOID Overrides(IMG img, VOID *v)
ThreadData_t * GetTLS(THREADID threadid)
static VOID InstrumentImageLoad(IMG img, VOID *v)
static void CommitChangesToShadowMemory(Label *oldLabel, Label *newLabel)
struct VersionInfo_t { union { volatile atomic< uint64_t > readStart VersionInfo_t
Label * read1
static void CheckWrite(DataraceInfo_t *shadowAddress, Label *myLabel, uint32_t opaqueHandle, THREADID threadId)
static Label ** gRegionIdToMasterLabelMap
#define DYNAMIC_BEGIN_FN_NAME
static void UpdateContext(ContextHandle_t *oldCtxt, ContextHandle_t ctxt)
ContextHandle_t read1Context
void(*)(void *) FP_CRITICAL_EXIT
#define CRITICAL_ENTER_FN_NAME
@ WRITE_ACCESS
@ READ_ACCESS
static void DumpRaceInfo(ContextHandle_t oldCtxt, Label *oldLbl, ContextHandle_t newCtxt, Label *newLbl)
volatile atomic< uint64_t > writeStart
#define ENTER_RANK(phase)
void new_ORDERED_ENTER_FN_NAME(uint64_t region_id, THREADID threadId)
#define DYNAMIC_END_FN_NAME
static void UpdateShadowDataAtShadowAddress(DataraceInfo_t *shadowAddress, const DataraceInfo_t &info)
void(*)(uint64_t, long) FP_MASTER
struct ExtendedDataraceInfo_t { DataraceInfo_t *shadowAddress ExtendedDataraceInfo_t
volatile atomic< uint64_t > readEnd
#define PAGE_OFFSET(addr)
Definition: shadow_memory.H:15
#define PAGE_OFFSET_MASK
Definition: shadow_memory.H:16