CCTLib
Calling-context and data-object attribution library for Intel Pin
cctlib.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 #include <set>
6 #include "cctlib.H"
7 #include "shadow_memory.H"
8 #define __STDC_FORMAT_MACROS
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include "pin.H"
12 #include <map>
13 #include <unordered_map>
14 #include <vector>
15 #include <list>
16 #include <inttypes.h>
17 #include <stdint.h>
18 #include <sys/types.h>
19 #include <sys/ipc.h>
20 #include <sys/shm.h>
21 #include <semaphore.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <iostream>
25 #include <libgen.h>
26 #include <locale>
27 #include <unistd.h>
28 #include <sys/syscall.h>
29 #include <assert.h>
30 #include <sys/mman.h>
31 #include <exception>
32 #include <sys/time.h>
33 #include <signal.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <setjmp.h>
37 #include <sstream>
38 #include <limits.h>
39 #include <dirent.h>
40 #include <unwind.h>
41 #include <sys/resource.h>
42 
43 // CCTLib historically had an optional Boost dependency (guarded by USE_BOOST)
44 // for two tiny things -- std::to_string() didn't exist pre-C++11 and there
45 // was no std trim. Both are handled with C++11 now. Boost is also
46 // explicitly unsupported by Pin RT (no RTTI in Pin's libcxx), so we do not
47 // include or link Boost anywhere.
48 static inline void CCTLibTrimInPlace(std::string& s) {
49  const char* ws = " \t\n\r\f\v";
50  size_t b = s.find_first_not_of(ws);
51  if (b == std::string::npos) {
52  s.clear();
53  return;
54  }
55  size_t e = s.find_last_not_of(ws);
56  s = s.substr(b, e - b + 1);
57 }
58 
59 #ifdef TARGET_MAC
60 #include <libelf/libelf.h>
61 #include <libelf/gelf.h>
62 #elif defined(TARGET_LINUX)
63 #include <libelf.h>
64 #include <gelf.h>
65 #else
66 "Unsupported platform"
67 #endif
68 
69 
70 #include "splay-macros.h"
71 // Need GOOGLE sparse hash tables
72 #include <google/sparse_hash_map>
73 #include <google/dense_hash_map>
74 // XED for printing instr
75 extern "C" {
76 #include "xed-interface.h"
77 }
78 
79 using google::sparse_hash_map; // namespace where class lives by default
80 using namespace std;
81 
82 namespace PinCCTLib {
83 
84 // All globals
85 #define USE_SPLAY_TREE
86 #define MAX_PATH_NAME 1024
87 #define MALLOC_FN_NAME "malloc"
88 #define CALLOC_FN_NAME "calloc"
89 #define REALLOC_FN_NAME "realloc"
90 #define FREE_FN_NAME "free"
91 
92 
93 #define CCTLIB_SERIALIZATION_DEFAULT_DIR_NAME "cctlib-database-"
94 #ifndef MAX_IPNODES
95 #if defined(TARGET_IA32E)
96 // 2^32 IPNODES
97 #define MAX_IPNODES (1L << 32)
98 #elif defined(TARGET_IA32)
99 // 1M IPNODES
100 #define MAX_IPNODES (1L << 20)
101 #else
102 "SHOULD NEVER REACH HERE"
103 #endif
104 #endif
105 
106 #ifndef MAX_STRING_POOL_NODES
107 #if defined(TARGET_IA32E)
108 // 2^32 IPNODES
109 #define MAX_STRING_POOL_NODES (1L << 30)
110 #elif defined(TARGET_IA32)
111 // 1M charaters
112 #define MAX_STRING_POOL_NODES (1L << 20)
113 #else
114  "SHOULD NEVER REACH HERE"
115 #endif
116 #endif
117 
118 // Assuming 128 byte line size.
119 #define CACHE_LINE_SIZE (128)
120 
121 
122 #define GET_CONTEXT_HANDLE_FROM_IP_NODE_CHECKED(node) ((ContextHandle_t)((node) ? ((node)-GLOBAL_STATE.preAllocatedContextBuffer) : 0))
123 #define GET_IPNODE_FROM_CONTEXT_HANDLE_CHECKED(handle) ((handle) ? (GLOBAL_STATE.preAllocatedContextBuffer + (handle)) : NULL)
124 
125 #define GET_CONTEXT_HANDLE_FROM_IP_NODE(node) ((ContextHandle_t)((node)-GLOBAL_STATE.preAllocatedContextBuffer))
126 #define GET_IPNODE_FROM_CONTEXT_HANDLE(handle) (GLOBAL_STATE.preAllocatedContextBuffer + handle)
127 #define IS_VALID_CONTEXT(c) (c != 0)
128 
129 
130 #define BREAK_HERE raise(SIGINT)
131 
132 //Serialization related macros
133 #define SERIALIZED_SHADOW_TRACE_IP_FILE_SUFFIX "/TraceMap.traceShadowMap"
134 #define SERIALIZED_CCT_FILE_PREFIX "/Thread-"
135 #define SERIALIZED_CCT_FILE_EXTN ".cct"
136 #define SERIALIZED_CCT_FILE_SUFFIX "-CCTMap.cct"
137 
138 // Platform specific macros
139 #ifdef TARGET_MAC
140 #define MAP_ANONYMOUS MAP_ANON
141 typedef uintptr_t _Unwind_Ptr;
142 #endif
143 
144 struct _Unwind_Context;
145 
146 
147 /******** Fwd declarations **********/
148 struct TraceNode;
149 struct SerializedTraceNode;
150 struct IPNode;
151 struct TraceSplay;
152 struct ModuleInfo;
153 struct QNode;
154 struct NewIPNode;
155 
156 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
157 
158 #define LOCKED (1)
159 #define UNLOCKED (0)
160 #define UNLOCKED_AND_PREDECESSOR_WAS_WRITER (2)
161 
162 struct varType;
163 struct PendingOps_t;
164 struct ConcurrentReaderWriterTree_t;
165 using varSet = set<varType>;
166 #endif
167 
168 static inline ADDRINT GetIPFromInfo(ContextHandle_t);
169 static inline void SetIPFromInfo(ContextHandle_t ctxtHndle, ADDRINT val);
170 static inline const string& GetModulePathFromInfo(IPNode* ipNode);
171 static inline void GetLineFromInfo(const ADDRINT& ip, uint32_t& lineNo, string& filePath);
172 
173 static inline bool IsValidIP(ADDRINT ip);
174 
175 static void SerializeCCTNode(TraceNode* traceNode, FILE* const fp);
178 
179 
180 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
181 enum AccessStatus { START_READING = 0,
182  END_READING = 1,
183  WAITING_WRITE = 3,
184  WRITE_STARTED = 4 };
185 #endif
186 
187 
188 /******** Data structures **********/
189 struct TraceNode {
192  uint32_t traceKey; // max of 2^32 traces allowed
193  uint32_t nSlots;
194 };
195 
197  uint32_t traceKey;
198  uint32_t nSlots;
200 };
201 
202 
203 struct TraceSplay {
204  ADDRINT key;
208 };
209 
210 struct IPNode {
212 #ifdef USE_SPLAY_TREE
214 #else
215  sparse_hash_map<ADDRINT, TraceNode*>* calleeTraceNodes;
216 #endif
217 
218 #ifdef HAVE_METRIC_PER_IPNODE
219  void* metric;
220 #endif
221 };
222 
223 using QNode = struct QNode {
224  struct QNode* volatile next;
225  union {
226  struct {
227  volatile bool locked : 1;
228  volatile bool predecessorWasWriter : 1;
229  };
230  volatile uint8_t status;
231  };
232 };
233 
234 // should become TLS
235 struct ThreadData {
236  uint8_t pad0[CACHE_LINE_SIZE];
237 #ifndef USE_SPLAY_TREE
238  sparse_hash_map<ADDRINT, TraceNode*>::iterator gTraceIter;
239 #endif
240 
241  uint32_t tlsThreadId; // useful only during deserialization
248 
251 
252 
253  sparse_hash_map<ADDRINT, ContextHandle_t> tlsLongJmpMap;
255 
256  uint32_t curSlotNo;
257 
258  // Landing-pad re-anchor state. See design notes on
259  // CaptureLandingPadTarget + InstrumentTraceEntry's reset block.
260  //
261  // tlsPendingLandingPadIp -- set at _Unwind_SetIP entry to the
262  // resume IP the personality function
263  // just installed. Consumed on the
264  // next Pin trace entry whose first
265  // IP matches; then cleared.
266  // tlsPendingHandlerFrame -- the CCT TraceNode of the frame
267  // that owns the landing pad
268  // (identified by walking the parent
269  // chain looking for a frame whose
270  // ipShadow slots fall inside the
271  // target function's address range).
272  // tlsPendingHandlerCtxt -- the ctxt handle within that frame
273  // to re-anchor tlsCurrentCtxtHndl to.
274  //
275  // Necessary because libgcc's _Unwind_RaiseException / _Unwind_Resume
276  // / _Unwind_ForcedUnwind never RET on a caught unwind -- they
277  // transfer via __builtin_eh_return, which is not a `ret` insn and
278  // therefore not a valid hookpoint for the pre-existing "reset on
279  // last RET" scheme. The (SetIP-entry, matching-trace-entry) pair
280  // is the reliable substitute.
285  void* tlsStackEnd;
286 
287 
288  //DO_DATA_CENTRIC
291 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
292  uint8_t pad1[CACHE_LINE_SIZE];
293  uint32_t rwLockStatus;
294  uint8_t pad2[CACHE_LINE_SIZE];
295  struct ConcurrentReaderWriterTree_t* tlsLatestConcurrentTree;
296  uint8_t pad3[CACHE_LINE_SIZE];
297  volatile uint8_t tlsMallocDSAccessStatus;
298  uint8_t pad4[CACHE_LINE_SIZE];
299 #endif
300  // TODO .. identify why perf screws up w/o this buffer
301  // For hpcrun format -- report the number of new CCT nodes
302  uint64_t nodeCount;
304  uint8_t pad5[CACHE_LINE_SIZE];
305 };
306 
307 
308 //DO_DATA_CENTRIC
309 
310 // Data centric support
311 
312 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
313 
314 
315 struct varType {
316  void* start;
317  void* end;
318  union {
319  uint32_t pathHandle;
320  uint32_t symName;
321  };
322  uint8_t objectType;
323  varType(void* s, void* e, uint32_t handle, uint8_t type)
324  : start(s), end(e), pathHandle(handle), objectType(type) {}
325 };
326 
327 bool operator<(varType const& a, varType const& b) {
328  return (ADDRINT)a.start < (ADDRINT)b.start;
329 }
330 
331 struct PendingOps_t {
332  uint8_t pad0[CACHE_LINE_SIZE];
333  uint8_t operation;
334  varType var;
335  PendingOps_t(const uint8_t o, varType const& v)
336  : operation(o), var(v) {}
337 };
338 
339 enum { INSERT = 0,
340  DELETE = 1 };
341 
342 struct ConcurrentReaderWriterTree_t {
343  vector<PendingOps_t> pendingOps;
344  varSet tree;
345 };
346 
347 #endif
348 
349 
350 // Information about loaded images.
351 struct ModuleInfo {
352  // a ID used for hpcrun format
353  uint16_t id;
354  // name
355  string moduleName;
356  //Offset from the image's link-time address to its load-time address.
357  ADDRINT imgLoadOffset;
358 };
359 
360 // Per-routine info populated by GetOrClassifyRoutine() the first time
361 // we see any Pin trace of a routine. Used to fold direct self-recursion:
362 // * hasSelfRec -- true if the routine contains any direct call
363 // whose immediate target equals its own entry.
364 // * selfRecReturnAddrs -- exact set of INS_NextAddress(callIns) for
365 // each such direct self-call. On a RET, if
366 // the return target matches any of these, the
367 // RET is unwinding a collapsed recursion
368 // frame and we must NOT walk up the CCT.
369 // The address set is derived from decoded CALL immediates -- it is
370 // independent of RTN_Size / any symbol- or loader-derived range, so it
371 // works on stripped binaries and around function padding.
372 struct RtnInfo {
373  ADDRINT rtnStart;
375  uint16_t nReturnAddrs;
376  ADDRINT* selfRecReturnAddrs; // heap array, typically 1-4 entries
377 };
378 
379 /******** Globals variables **********/
380 #define MAX_METRICS (10)
381 #define MAX_LEN (128)
382 
384  // record the IP of the first instruction in main
385  bool skip; // whether we want to skip all the frames above main; default is false
386  void (*mergeFunc)(void* des, void* src); // merge metrics in nodes
387  uint64_t (*computeMetricVal)(void* metric); // convert the metric pointer to a value
388  ADDRINT mainIP;
389  int nmetric;
390  char metrics[MAX_METRICS][MAX_LEN];
391  // Should data-centric attribution be perfomed?
392  bool doDataCentric; // false by default
393  bool applicationStarted; // false by default
398  char disassemblyBuff[200]; // string of 0 by default
399  /// XED state
400  xed_state_t cct_xed_state;
401  // prefix string for flushing all data for post processing.
405  // SEGVHANDLEING FOR BAD .plt
406  jmp_buf env;
407  struct sigaction sigAct;
408  //Load module info
409  unordered_map<UINT32, ModuleInfo> ModuleInfoMap;
410  // Per-routine direct-self-recursion classifier cache, populated
411  // lazily by GetOrClassifyRoutine() on first sight of any trace of
412  // a routine. Guarded by rtnSelfRecRWMutex: reader-writer because
413  // once a routine is classified every subsequent trace-instrument
414  // pass only reads (lookup), so the common path takes the read lock
415  // and can proceed concurrently across worker threads. The write
416  // lock is taken only for the first insert per routine.
417  unordered_map<ADDRINT, RtnInfo> rtnSelfRecMap;
418  PIN_RWMUTEX rtnSelfRecRWMutex;
419  uint8_t padRtnSelfRec[CACHE_LINE_SIZE];
420  // serialization directory path
422  // Deserialized CCTs
423  vector<ThreadData> deserializedCCTs;
424  //dense_hash_map<ADDRINT, void *> traceShadowMap;
425  unordered_map<uint32_t, void*> traceShadowMap;
426  uint8_t pad13[CACHE_LINE_SIZE];
427  PIN_LOCK lock;
428  uint8_t pad0[CACHE_LINE_SIZE];
429  // key for accessing TLS storage in the threads. initialized once in main()
430  TLS_KEY CCTLibTlsKey; // align to eliminate any false sharing with other members
431  uint8_t pad1[CACHE_LINE_SIZE];
432  uint32_t numThreads; // initial value = 0 // align to eliminate any false sharing with other members
433  uint8_t pad2[CACHE_LINE_SIZE];
434  uint32_t curPreAllocatedStringPoolIndex; // align to eliminate any false sharing with other members
435  uint8_t pad3[CACHE_LINE_SIZE];
436  uint64_t curPreAllocatedContextBufferIndex; // align to eliminate any false sharing with other members
437  uint8_t pad4[CACHE_LINE_SIZE];
438  // keys to associate parent child threads
439  volatile uint64_t threadCreateCount; // initial value = 0 // align to eliminate any false sharing with other members
440  uint8_t pad5[CACHE_LINE_SIZE];
441  volatile uint64_t threadCaptureCount; // initial value = 0 // align to eliminate any false sharing with other members
442  uint8_t pad6[CACHE_LINE_SIZE];
443  volatile TraceNode* threadCreatorTraceNode; // align to eliminate any false sharing with other members
444  uint8_t pad7[CACHE_LINE_SIZE];
445  volatile ContextHandle_t threadCreatorCtxtHndl; // align to eliminate any false sharing with other members
446  uint8_t pad8[CACHE_LINE_SIZE];
447  volatile bool DSLock;
448  uint8_t pad9[CACHE_LINE_SIZE];
449 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
450  //Data centric support
451  unordered_map<UINT32, vector<PendingOps_t>> staticVariablesInModule;
452  uint8_t pad10[CACHE_LINE_SIZE];
453  volatile ConcurrentReaderWriterTree_t* latestConcurrentTree;
454  uint8_t pad11[CACHE_LINE_SIZE];
455  ConcurrentReaderWriterTree_t concurrentReaderWriterTree[2];
456  uint8_t pad12[CACHE_LINE_SIZE];
457 #endif
458 } static GLOBAL_STATE;
459 
460 static void SegvHandler(int);
461 
462 
463 /******** Function definitions **********/
464 
465 
466 inline BOOL IsCallOrRetIns(INS ins) {
467  if (INS_IsProcedureCall(ins))
468  return true;
469 
470  if (INS_IsRet(ins))
471  return true;
472 
473  return false;
474 }
475 
476 
477 // function to get the next unique key for a trace
478 ADDRINT GetNextTraceKey() {
479  static uint32_t traceKey = 0;
480  uint32_t key = __sync_fetch_and_add(&traceKey, 1);
481 
482  if (key == UINT_MAX) {
483  fprintf(stderr, "\n UINT_MAX traces created! Exiting...\n");
484  PIN_ExitProcess(-1);
485  }
486 
487  return key;
488 }
489 
490 // function to access thread-specific data
491 static inline ThreadData* CCTLibGetTLS(const THREADID threadId) {
492  ThreadData* tdata =
493  static_cast<ThreadData*>(PIN_GetThreadData(GLOBAL_STATE.CCTLibTlsKey, threadId));
494  return tdata;
495 }
496 
497 // This function is for dumping call path from debugger.
498 void DumpCallStack(THREADID id, uint32_t slot) {
499  ThreadData* tData = CCTLibGetTLS(id);
500  fprintf(stderr, "\n slot =%u, max = %u\n", slot, tData->tlsCurrentTraceNode->nSlots);
501  PIN_LockClient();
503  fprintf(stderr, "\n");
504  vector<Context> contextVec;
505  GetFullCallingContext(h, contextVec);
506 
507  for (uint32_t i = 0; i < contextVec.size(); i++) {
508  fprintf(stderr, "\n%u:%p:%s:%s:%s:%u", contextVec[i].ctxtHandle, (void*)contextVec[i].ip, contextVec[i].disassembly.c_str(), contextVec[i].functionName.c_str(), contextVec[i].filePath.c_str(), contextVec[i].lineNo);
509  }
510 
511  PIN_UnlockClient();
512 }
513 
514 // This function is for dumping call path from debugger.
516  DumpCallStack(PIN_ThreadId(), 0);
517 }
518 
519 
520 #if 0
521  static int SetJmpOverride(const CONTEXT* ctxt, THREADID tid, AFUNPTR gOriginalSetjmpRtn, jmp_buf env) {
522  int ret = -1;
523  PIN_CallApplicationFunction(ctxt,
524  tid,
525  CALLINGSTD_DEFAULT,
526  gOriginalSetjmpRtn,
527  PIN_PARG(int), &ret,
528  PIN_PARG(void*), env,
529  PIN_PARG_END());
530 
531  if(ret == 0) {
532  // Remember the context.
533  fprintf(stderr, "\n Here due to SetJmp\n");
534  } else {
535  //
536  fprintf(stderr, "\n Here due to LongJmp\n");
537  }
538 
539  return ret;
540  }
541 #endif
542 
543 static inline void UpdateCurTraceAndIp(ThreadData* tData, TraceNode* const trace, ContextHandle_t const ctxtHndle) {
544  tData->tlsCurrentTraceNode = trace;
546  tData->tlsCurrentCtxtHndl = ctxtHndle;
547 }
548 
549 static inline void UpdateCurTraceAndIp(ThreadData* tData, TraceNode* const trace) {
550  UpdateCurTraceAndIp(tData, trace, trace->childCtxtStartIdx);
551 }
552 
553 static inline void UpdateCurTraceOnly(ThreadData* tData, TraceNode* const trace) {
554  tData->tlsCurrentTraceNode = trace;
556 }
557 
558 
559 static inline VOID CaptureSigSetJmpCtxt(ADDRINT buf, THREADID threadId) {
560  ThreadData* tData = CCTLibGetTLS(threadId);
561  // Does not work when a trace has zero IPs!! tData->tlsLongJmpMap[buf] = tData->tlsCurrentCtxtHndl->parentTraceNode->callerCtxtHndl;
563  //fprintf(GLOBAL_STATE.CCTLibLogFile,"\n CaptureSetJmpCtxt buf = %lu, tData->tlsCurrentCtxtHndl = %p", buf, tData->tlsCurrentCtxtHndl);
564 }
565 
566 static inline VOID HoldLongJmpBuf(ADDRINT buf, THREADID threadId) {
567  ThreadData* tData = CCTLibGetTLS(threadId);
568  tData->tlsLongJmpHoldBuf = buf;
569  //fprintf(GLOBAL_STATE.CCTLibLogFile,"\n HoldLongJmpBuf tlsLongJmpHoldBuf = %lu, tData->tlsCurrentCtxtHndl = %p", tData->tlsLongJmpHoldBuf, tData->tlsCurrentCtxtHndl);
570 }
571 
572 static inline VOID RestoreSigLongJmpCtxt(THREADID threadId) {
573  ThreadData* tData = CCTLibGetTLS(threadId);
574  assert(tData->tlsLongJmpHoldBuf);
575  tData->tlsCurrentCtxtHndl = tData->tlsLongJmpMap[tData->tlsLongJmpHoldBuf];
577  tData->tlsLongJmpHoldBuf = 0; // reset so that next time we can check if it was set correctly.
578  //fprintf(GLOBAL_STATE.CCTLibLogFile,"\n RestoreSigLongJmpCtxt2 tlsLongJmpHoldBuf = %lu",tData->tlsLongJmpHoldBuf);
579 }
580 
581 static int GetInstructionLength(ADDRINT ip) {
582  // Get the instruction in a string
583  xed_decoded_inst_t xedd;
584  /// XED state
585  xed_decoded_inst_zero_set_mode(&xedd, &GLOBAL_STATE.cct_xed_state);
586 
587  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
588  return xed_decoded_inst_get_length(&xedd);
589  } else {
590  assert(0 && "failed to disassemble instruction");
591  return 0;
592  }
593 }
594 
595 static bool IsCallInstruction(ADDRINT ip) {
596  // Get the instruction in a string
597  xed_decoded_inst_t xedd;
598  /// XED state
599  xed_decoded_inst_zero_set_mode(&xedd, &GLOBAL_STATE.cct_xed_state);
600 
601  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
602  return XED_CATEGORY_CALL == xed_decoded_inst_get_category(&xedd);
603  } else {
604  assert(0 && "failed to disassemble instruction");
605  return false;
606  }
607 }
608 
609 // -----------------------------------------------------------------------------
610 // C++ exception (Itanium ABI / DWARF2) hook implementation.
611 //
612 // The reliable landing-pad-delivery signal is the pair (`_Unwind_SetIP`
613 // entry, next Pin trace entry whose first IP == the target IP). At
614 // `_Unwind_SetIP` entry, the personality function has just installed
615 // the resume IP; libgcc's driver will next call `uw_install_context`,
616 // which is a macro expanding to `__builtin_eh_return` that pops N
617 // frames and JMPs to that IP -- no `ret` instruction fires, so the
618 // prior "reset on _Unwind_RaiseException's last RET" scheme silently
619 // missed every caught exception. See ~/gcc/libgcc/unwind.inc:140,
620 // ~/gcc/libgcc/unwind-dw2.c:1398-1407 and Itanium C++ ABI §1.6.
621 //
622 // This section replaces the pre-existing (and pre-existingly-broken)
623 // heuristic `IsIpPresentInTrace` / `FindNearestCallerCoveringIP` /
624 // `X86_*_CALL_SITE_ADDR_FROM_RETURN_ADDR` / `SetCurTraceNodeAfterException*`
625 // with a two-part protocol:
626 // (a) At _Unwind_SetIP entry, CaptureLandingPadTarget records the
627 // target IP, identifies the handler frame by walking cctlib's
628 // parent chain for a TraceNode whose ipShadow slots fall inside
629 // the target function (via RTN_FindByAddress on the target IP),
630 // and stashes (target_ip, frame, ctxt) in TLS as pending.
631 // (b) At the top of InstrumentTraceEntry (below), if the current
632 // trace's first IP matches the pending landing pad, re-anchor
633 // tlsCurrentTraceNode to the handler frame and take the sibling
634 // branch so the landing pad's Pin trace becomes a SIBLING of the
635 // handler's own trace under the same parent. The landing pad's
636 // first-insn IP resolves via RTN_FindNameByAddress to the
637 // handler's function name, so downstream chains read
638 // `handler-caller -> handler -> ...` correctly.
639 // -----------------------------------------------------------------------------
640 
641 // True iff some slot of `trace` holds an IP that falls in [lo, hi).
642 // Cheaper than RTN_FindByAddress per slot -- we already have the raw
643 // IPs in the traceShadowMap.
644 static bool TraceIsInAddressRange(TraceNode* trace, ADDRINT lo, ADDRINT hi) {
645  ADDRINT* ips = (ADDRINT*)GLOBAL_STATE.traceShadowMap[trace->traceKey];
646  if (!ips)
647  return false;
648  for (uint32_t i = 0; i < trace->nSlots; ++i) {
649  if (ips[i] >= lo && ips[i] < hi)
650  return true;
651  }
652  return false;
653 }
654 
655 // Walk tData's CCT parent chain looking for the OUTERMOST TraceNode
656 // that is inside the address range of the routine containing
657 // `landingPadIp`. Outermost (not innermost) because on the second
658 // unwind iteration of a `try{}catch{}` loop, an earlier iteration's
659 // landing-pad Pin trace is also inside the handler function's
660 // address range -- picking THAT one would nest each iteration's
661 // re-anchor under the previous one and chains would grow linearly
662 // with iteration count. Walking to the root and keeping the LAST
663 // match gives us the ORIGINAL handler frame every time.
664 //
665 // Returns NULL if the routine can't be identified (stripped / foreign
666 // image) or no ancestor matches. Callers on the NULL path skip
667 // re-anchoring, which is a benign degradation.
668 static TraceNode* FindHandlerFrameForLandingPad(ADDRINT landingPadIp,
669  ADDRINT* outHandlerLo,
670  ADDRINT* outHandlerHi,
671  ThreadData* tData) {
672  PIN_LockClient();
673  RTN targetRtn = RTN_FindByAddress(landingPadIp);
674  ADDRINT lo = 0, hi = 0;
675  if (RTN_Valid(targetRtn)) {
676  lo = RTN_Address(targetRtn);
677  hi = lo + RTN_Size(targetRtn);
678  }
679  PIN_UnlockClient();
680  if (lo == hi)
681  return nullptr; // unrecognized image / stripped
682 
683  TraceNode* best = nullptr;
684  TraceNode* cur = tData->tlsCurrentTraceNode;
685  while (cur) {
686  if (TraceIsInAddressRange(cur, lo, hi)) {
687  best = cur; // keep walking -- want the OUTERMOST match
688  }
689  if (cur == tData->tlsRootTraceNode)
690  break;
692  }
693  if (best) {
694  if (outHandlerLo)
695  *outHandlerLo = lo;
696  if (outHandlerHi)
697  *outHandlerHi = hi;
698  }
699  return best;
700 }
701 
702 static VOID CaptureLandingPadTarget(VOID* /*exceptionCallerContext*/, ADDRINT landingPadIp, THREADID threadId) {
703  // The IP being written by _Unwind_SetIP is passed as the SECOND
704  // argument. We hook at IPOINT_BEFORE, so reading the context's IP
705  // via _Unwind_GetIP() would return the OLD value (the throwing call's
706  // return address), NOT the landing pad. Taking the second argument
707  // directly gives us the actual jump target that libgcc's
708  // uw_install_context will __builtin_eh_return to next.
709  //
710  // Bonus: we don't touch the _Unwind_Context struct, so the historic
711  // Pin-vs-libgcc _Unwind_Context layout hazard (which used to require
712  // an image-load-time RTN lookup of the application's _Unwind_GetIP)
713  // is irrelevant here.
714 
715  ThreadData* tData = CCTLibGetTLS(threadId);
716  ADDRINT lo = 0, hi = 0;
717  TraceNode* handler = FindHandlerFrameForLandingPad(landingPadIp, &lo, &hi, tData);
718  if (!handler) {
719  // Can't identify the handler frame -- either the landing pad
720  // is in an unrecognized image or the parent chain is empty of
721  // matching frames. Skip the reset; the pre-existing anchor
722  // stays put and the CCT for this unwind may be less precise
723  // but is not corrupted.
724  tData->tlsPendingLandingPadIp = 0;
725  tData->tlsPendingHandlerFrame = nullptr;
726  tData->tlsPendingHandlerCtxt = 0;
727  return;
728  }
729  tData->tlsPendingLandingPadIp = landingPadIp;
731  tData->tlsPendingHandlerCtxt = handler->childCtxtStartIdx;
732 }
733 
734 inline VOID TakeLock() {
735  do {
736  while (GLOBAL_STATE.DSLock)
737  ;
738  } while (!__sync_bool_compare_and_swap(&GLOBAL_STATE.DSLock, false, true));
739 }
740 
741 inline VOID ReleaseLock() {
742  GLOBAL_STATE.DSLock = false;
743 }
744 
745 
746 // Pauses creator thread from thread creation until
747 // the previously created child thread has noted its parent.
748 static inline void ThreadCreatePoint(THREADID threadId) {
749  while (true) {
750  TakeLock();
751 
753  ReleaseLock();
754  else
755  break;
756  }
757 
760  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n ThreadCreatePoint, parent Trace = %p, parent ip = %p", GLOBAL_STATE.threadCreatorTraceNode, GLOBAL_STATE.threadCreatorCtxtHndl);
762  ReleaseLock();
763 }
764 
765 
766 // Sets the child thread's CCT's parent to its creator thread's CCT node.
767 static inline void ThreadCapturePoint(ThreadData* tdata) {
768  TakeLock();
769 
771  // Base thread, no parent
772  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n ThreadCapturePoint, no parent ");
773  } else {
776  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n ThreadCapturePoint, parent Trace = %p, parent ip = %p", GLOBAL_STATE.threadCreatorTraceNode, GLOBAL_STATE.threadCreatorCtxtHndl);
778  }
779 
780  ReleaseLock();
781 }
782 
783 
784 static inline ContextHandle_t GetNextIPVecBuffer(uint32_t num) {
785  uint64_t oldBufIndex = __sync_fetch_and_add(&GLOBAL_STATE.curPreAllocatedContextBufferIndex, num);
786 
787  if (oldBufIndex + num >= MAX_IPNODES) {
788  //printf("\nPreallocated IPNodes exhausted. CCTLib couldn't fit your application in its memory. Try a smaller program.\n");
789  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nPreallocated IPNodes exhausted. CCTLib couldn't fit your application in its memory. Try a smaller program.\n");
790  PIN_ExitProcess(-1);
791  }
792 
793  return (ContextHandle_t)oldBufIndex;
794 }
795 
796 /*
797  Description:
798  Client tools call this API when they need the char string for a symbol from string pool index.
799  Arguments:
800  index: a string pool index
801  */
802 char* GetStringFromStringPool(const uint32_t index) {
803  return GLOBAL_STATE.preAllocatedStringPool + index;
804 }
805 
806 static inline uint32_t GetNextStringPoolIndex(char* name) {
807  uint32_t len = strlen(name) + 1;
808  uint64_t oldStringPoolIndex = __sync_fetch_and_add(&GLOBAL_STATE.curPreAllocatedStringPoolIndex, len);
809 
810  if (oldStringPoolIndex + len >= MAX_STRING_POOL_NODES) {
811  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nPreallocated String Pool exhausted. CCTLib couldn't fit your application in its memory. Try by changing MAX_STRING_POOL_NODES macro.\n");
812  PIN_ExitProcess(-1);
813  }
814 
815  // copy contents
816  strncpy(GLOBAL_STATE.preAllocatedStringPool + oldStringPoolIndex, name, len);
817  return oldStringPoolIndex;
818 }
819 
820 static inline void CCTLibInitThreadData(ThreadData* const tdata, CONTEXT* ctxt, THREADID threadId) {
821  TraceNode* t = new TraceNode();
822  t->callerCtxtHndl = 0;
823  t->nSlots = 1;
826  ipNode->parentTraceNode = t;
827 #ifdef USE_SPLAY_TREE
828  ipNode->calleeTraceNodes = nullptr;
829 #else
830  ipNode->calleeTraceNodes = new sparse_hash_map<ADDRINT, TraceNode*>();
831 #endif
832 #ifdef HAVE_METRIC_PER_IPNODE
833  ipNode->metric = nullptr;
834 #endif
835  tdata->tlsThreadId = threadId;
836  tdata->tlsRootTraceNode = t;
838  UpdateCurTraceAndIp(tdata, t);
839  tdata->tlsParentThreadCtxtHndl = 0;
840  tdata->tlsParentThreadTraceNode = nullptr;
841  tdata->tlsInitiatedCall = true;
842  tdata->curSlotNo = 0;
843  tdata->tlsPendingLandingPadIp = 0;
844  tdata->tlsPendingHandlerFrame = nullptr;
845  tdata->tlsPendingHandlerCtxt = 0;
846  // init the dummy root for hpcrun format
847  tdata->tlsHPCRunCCTRoot = nullptr;
848 
849  // Set stack sizes if data-centric is needed
851  ADDRINT s = PIN_GetContextReg(ctxt, REG_STACK_PTR);
852  tdata->tlsStackBase = (void*)s;
853  struct rlimit rlim;
854 
855  if (getrlimit(RLIMIT_STACK, &rlim)) {
856  cerr << "\n Failed to getrlimit()\n";
857  PIN_ExitProcess(-1);
858  }
859 
860  if (rlim.rlim_cur == RLIM_INFINITY) {
861  cerr << "\n Need a finite stack size. Dont use unlimited.\n";
862  PIN_ExitProcess(-1);
863  }
864 
865  tdata->tlsStackEnd = (void*)(s - rlim.rlim_cur);
866  }
867 
868 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
869  tdata->tlsMallocDSAccessStatus = END_READING;
870 #endif
871 }
872 
873 static VOID CCTLibThreadStart(THREADID threadid, CONTEXT* ctxt, INT32 flags, VOID* v) {
874  PIN_GetLock(&GLOBAL_STATE.lock, threadid + 1);
876  PIN_ReleaseLock(&GLOBAL_STATE.lock);
877  ThreadData* tdata = new ThreadData();
878  CCTLibInitThreadData(tdata, ctxt, threadid);
879  PIN_SetThreadData(GLOBAL_STATE.CCTLibTlsKey, tdata, threadid);
880  ThreadCapturePoint(tdata);
881 }
882 
883 // Classify a routine's direct self-recursive call sites. Called once
884 // per routine at instrumentation time; the result is cached in
885 // GLOBAL_STATE.rtnSelfRecMap. hasSelfRec is true when the routine
886 // contains at least one direct call whose immediate target equals its
887 // own entry address. selfRecReturnAddrs is the exact set of
888 // INS_NextAddress(callIns) for each such site -- used at RET-time to
889 // distinguish a return unwinding a collapsed recursion frame (target
890 // in set -> no-op) from a return to the actual caller (target not in
891 // set -> normal pop). The set is derived from decoded CALL immediates
892 // -- independent of RTN_Size or any symbol/loader-derived metadata,
893 // so it works on stripped binaries and around function padding.
894 //
895 // The map is guarded by a reader-writer lock: the common path (a
896 // routine we've already classified) takes only the read lock and lets
897 // concurrent Pin worker threads instrument in parallel. The write
898 // lock is taken exactly once per routine, on first classification.
899 static const RtnInfo* GetOrClassifyRoutine(RTN rtn) {
900  ADDRINT rtnStart = RTN_Address(rtn);
901 
902  // Fast path: reader lock. Iterator remains valid across insert as
903  // long as we hold at least a read lock -- but we release the read
904  // lock before the walk, so we don't hold locks during RTN_Open,
905  // instruction decode, or malloc. The pointer we return points at
906  // an entry in an unordered_map; std::unordered_map guarantees
907  // reference/pointer stability across insert (only iterators over
908  // buckets can be invalidated on rehash). Callers hold no reference
909  // beyond the instrumentation callback's scope.
910  PIN_RWMutexReadLock(&GLOBAL_STATE.rtnSelfRecRWMutex);
911  auto it = GLOBAL_STATE.rtnSelfRecMap.find(rtnStart);
912  if (it != GLOBAL_STATE.rtnSelfRecMap.end()) {
913  const RtnInfo* p = &it->second;
914  PIN_RWMutexUnlock(&GLOBAL_STATE.rtnSelfRecRWMutex);
915  return p;
916  }
917  PIN_RWMutexUnlock(&GLOBAL_STATE.rtnSelfRecRWMutex);
918 
919  // Slow path: walk the routine's instructions to collect direct
920  // self-call sites. Done outside any lock -- expensive and
921  // idempotent; a losing racer just discards its result.
922  // RTN_Open/RTN_Close scopes access to RTN_InsHead/INS_Next.
923  RTN_Open(rtn);
924  std::vector<ADDRINT> rets;
925  for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins)) {
926  if (INS_IsProcedureCall(ins) &&
927  INS_IsDirectControlFlow(ins) &&
928  INS_DirectControlFlowTargetAddress(ins) == rtnStart) {
929  rets.push_back(INS_NextAddress(ins));
930  }
931  }
932  RTN_Close(rtn);
933 
934  RtnInfo info;
935  info.rtnStart = rtnStart;
936  info.hasSelfRec = !rets.empty();
937  // uint16_t is plenty; a routine with 65535 direct self-call sites
938  // is not realistic. Silently cap and pretend we saw fewer to keep
939  // the RET fast-path bounded.
940  info.nReturnAddrs = (uint16_t)(rets.size() > UINT16_MAX ? UINT16_MAX : rets.size());
941  if (info.nReturnAddrs > 0) {
942  info.selfRecReturnAddrs = (ADDRINT*)malloc(sizeof(ADDRINT) * info.nReturnAddrs);
943  for (uint16_t i = 0; i < info.nReturnAddrs; ++i) {
944  info.selfRecReturnAddrs[i] = rets[i];
945  }
946  } else {
947  info.selfRecReturnAddrs = nullptr;
948  }
949 
950  PIN_RWMutexWriteLock(&GLOBAL_STATE.rtnSelfRecRWMutex);
951  // Another thread may have raced us; std::unordered_map::emplace
952  // returns an iterator to the existing element in that case and we
953  // leak our freshly-allocated array. Compare-and-set to avoid it.
954  auto ins = GLOBAL_STATE.rtnSelfRecMap.emplace(rtnStart, info);
955  if (!ins.second) {
956  // We lost the race. Free our copy; return theirs.
957  if (info.selfRecReturnAddrs)
958  free(info.selfRecReturnAddrs);
959  }
960  const RtnInfo* p = &ins.first->second;
961  PIN_RWMutexUnlock(&GLOBAL_STATE.rtnSelfRecRWMutex);
962  return p;
963 }
964 
965 // Analysis routine called on making a function call
966 static inline VOID SetCallInitFlag(uint32_t slot, THREADID threadId) {
967  ThreadData* tData = CCTLibGetTLS(threadId);
968  tData->tlsInitiatedCall = true;
970 #if 0
971  ADDRINT* tracesIPs = (ADDRINT*)GLOBAL_STATE.traceShadowMap[tData->tlsCurrentTraceNode->traceKey];
972  printf("\n Calling from IP = %p", tracesIPs[slot]);
973 #endif
974 }
975 
976 // Analysis routine called on function return.
977 // Point gCurrentContext to its parent, if we reach the root, set tlsInitiatedCall.
978 static inline VOID GoUpCallChain(THREADID threadId) {
979  ThreadData* tData = CCTLibGetTLS(threadId);
980 
981  // If we reach the root trace, then fake the call
982  if (tData->tlsCurrentTraceNode->callerCtxtHndl == tData->tlsRootCtxtHndl) {
983  tData->tlsInitiatedCall = true;
984  }
985 
988  // RET & CALL end a trace hence the target should trigger a new trace entry for us ... pray pray.
989 #if 0
990  ADDRINT* tracesIPs = (ADDRINT*)GLOBAL_STATE.traceShadowMap[tData->tlsCurrentTraceNode->traceKey];
991  int offset = tData->tlsCurrentCtxtHndl - tData->tlsCurrentTraceNode->childCtxtStartIdx;
992  printf("\n Returning to the caller IP = %p", tracesIPs[offset]);
993 #endif
994 }
995 
996 // Analysis routine for RET in routines with hasSelfRec=true. If the
997 // return target matches any INS_NextAddress(callIns) of a direct self
998 // call in this routine, we are unwinding a collapsed recursion frame
999 // and must NOT walk up the CCT -- doing so would strand tData at an
1000 // ancestor of the true caller when the outermost RET fires. If the
1001 // target is not in the set, this is the outermost RET (returning to
1002 // the actual caller); behave like GoUpCallChain.
1003 //
1004 // n is bounded (typically 1-4, hard-capped at UINT16_MAX by the
1005 // classifier) so the linear scan is trivially cheap and, per Pin
1006 // conventions, kept off the pointer-chasing path when possible.
1007 static inline VOID MaybeGoUpCallChain(ADDRINT retTarget,
1008  const ADDRINT* returnAddrs, uint32_t n,
1009  THREADID threadId) {
1010  for (uint32_t i = 0; i < n; ++i) {
1011  if (returnAddrs[i] == retTarget)
1012  return; // recursion-return: no-op
1013  }
1014  ThreadData* tData = CCTLibGetTLS(threadId);
1015  if (tData->tlsCurrentTraceNode->callerCtxtHndl == tData->tlsRootCtxtHndl) {
1016  tData->tlsInitiatedCall = true;
1017  }
1019  UpdateCurTraceOnly(tData,
1020  GET_IPNODE_FROM_CONTEXT_HANDLE(tData->tlsCurrentCtxtHndl)->parentTraceNode);
1021 }
1022 
1023 // Analysis routine called interesting instructions to remember the slot no.
1024 static inline VOID RememberSlotNoInTLS(uint32_t slot, THREADID threadId) {
1025  ThreadData* tData = CCTLibGetTLS(threadId);
1026  tData->curSlotNo = slot;
1027 }
1028 
1029 /*
1030  static inline uint32_t GetNumInsInTrace(const TRACE& trace) {
1031  uint32_t count = 0;
1032 
1033  for(BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
1034  for(INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {
1035  count++;
1036  }
1037  }
1038 
1039  return count;
1040  }
1041 */
1042 
1043 static inline uint32_t GetNumInterestingInsInTrace(const TRACE& trace, IsInterestingInsFptr isInterestingIns) {
1044  uint32_t count = 0;
1045 
1046  for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
1047  for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {
1048  // cal ret are always interesting for us :)
1049  if (IsCallOrRetIns(ins) || isInterestingIns(ins))
1050  count++;
1051  }
1052  }
1053 
1054  return count;
1055 }
1056 
1057 // Record the data about this image in a table
1058 // Not written thread safe, but PIN guarantees that instrumentation functions are not called concurrently.
1059 static inline VOID CCTLibInstrumentImageLoad(IMG img, VOID* v) {
1060  UINT32 id = IMG_Id(img);
1061  ModuleInfo mi;
1062  if (IMG_IsMainExecutable(img))
1063  mi.id = 1;
1064  else
1065  mi.id = 0;
1066  mi.moduleName = IMG_Name(img);
1067  mi.imgLoadOffset = IMG_LoadOffset(img);
1068  GLOBAL_STATE.ModuleInfoMap[id] = mi;
1069 }
1070 
1071 
1072 // Called each time a new trace is JITed.
1073 // Given a trace this function adds instruction to each instruction in the trace.
1074 // It also adds the trace to a hash table "GLOBAL_STATE.traceShadowMap" to maintain the reverse mapping from an (interesting) instruction's position in CCT back to its IP.
1075 static inline VOID PopulateIPReverseMapAndAccountTraceInstructions(TRACE trace, uint32_t traceKey, uint32_t numInterestingInstInTrace, IsInterestingInsFptr isInterestingIns, const RtnInfo* rinfo) {
1076  // if there were 0 numInterestingInstInTrace, then let us simply return since it makes no sense to record anything about it.
1077  if (numInterestingInstInTrace == 0)
1078  return;
1079 
1080  ADDRINT* ipShadow = (ADDRINT*)malloc((2 + numInterestingInstInTrace) * sizeof(ADDRINT)); // +1 to hold the number of slots as a metadata and ++1 to hold module id
1081  // Record the number of instructions in the trace as the first entry
1082  ipShadow[0] = numInterestingInstInTrace;
1083  // Record the module id as 2nd entry
1084  ipShadow[1] = IMG_Id(IMG_FindByAddress(TRACE_Address(trace)));
1085  uint32_t slot = 0;
1086  GLOBAL_STATE.traceShadowMap[traceKey] = &ipShadow[2]; // 0th entry is 2 behind
1087 
1088  for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
1089  for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {
1090  // If it is a call/ret instruction, we need to adjust the CCT.
1091  // manage context
1092  if (INS_IsProcedureCall(ins)) {
1093  // Fold direct self-recursion: at a direct call whose
1094  // immediate target is the enclosing routine's entry,
1095  // suppress SetCallInitFlag so the callee's
1096  // InstrumentTraceEntry takes its sibling-branch and
1097  // splays under the same collapsed frame. See design
1098  // notes at RtnInfo/MaybeGoUpCallChain above.
1099  bool isDirectSelfRec = rinfo && rinfo->hasSelfRec && INS_IsDirectControlFlow(ins) && INS_DirectControlFlowTargetAddress(ins) == rinfo->rtnStart;
1100  if (!isDirectSelfRec) {
1101  // INS_InsertPredicatedCall if the call is not made, we should not set the flag
1102  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)SetCallInitFlag, IARG_UINT32, slot, IARG_THREAD_ID, IARG_END);
1103  }
1104 
1106  // Call user instrumentation passing the flag
1107  if (isInterestingIns(ins))
1109  } else {
1110  // TLS will remember your slot no.
1111  // TODO: should this be INS_InsertPredicatedCall? not sure. One can argue either ways.
1112  INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RememberSlotNoInTLS, IARG_UINT32, slot, IARG_THREAD_ID, IARG_END);
1113  }
1114 
1115  // put next slot in corresponding ins start location;
1116  ipShadow[slot + 2] = INS_Address(ins); // +2 because the first 2 entries hold metadata
1117  slot++;
1118  } else if (INS_IsRet(ins)) {
1119  // INS_InsertPredicatedCall if the RET is not made, we should not change CCT node
1120  // CALL_ORDER_LAST because we want update context after all analysis routines for RET have executed.
1121  if (rinfo && rinfo->hasSelfRec) {
1122  // Fold direct self-recursion: a RET whose target is
1123  // in the routine's set of direct-self-call return
1124  // addresses is unwinding a collapsed frame -- no-op.
1125  // The outermost RET returns to the actual caller,
1126  // whose address is outside the routine's body and
1127  // therefore never in the set: exactly one pop fires.
1128  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)MaybeGoUpCallChain,
1129  IARG_CALL_ORDER, CALL_ORDER_LAST,
1130  IARG_BRANCH_TARGET_ADDR,
1131  IARG_PTR, rinfo->selfRecReturnAddrs,
1132  IARG_UINT32, (uint32_t)rinfo->nReturnAddrs,
1133  IARG_THREAD_ID, IARG_END);
1134  } else {
1135  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)GoUpCallChain, IARG_CALL_ORDER, CALL_ORDER_LAST, IARG_THREAD_ID, IARG_END);
1136  }
1137 
1139  // Call user instrumentation passing the flag
1140  if (isInterestingIns(ins))
1142  } else {
1143  // TLS will remember your slot no.
1144  // TODO: should this be INS_InsertPredicatedCall? not sure. One can argue either ways.
1145  INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RememberSlotNoInTLS, IARG_UINT32, slot, IARG_THREAD_ID, IARG_END);
1146  }
1147 
1148  // put next slot in corresponding ins start location;
1149  ipShadow[slot + 2] = INS_Address(ins); // +2 because the first 2 entries hold metadata
1150  slot++;
1151  } else if (isInterestingIns(ins)) {
1153  // Call user instrumentation passing the flag
1155  } else {
1156  // If, it is an interesting Ins, then we need to hold on to the slot number.
1157  // TLS will remember your slot no.
1158  INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RememberSlotNoInTLS, IARG_UINT32, slot, IARG_THREAD_ID, IARG_END);
1159  }
1160 
1161  // put next slot in corresponding ins start location;
1162  ipShadow[slot + 2] = INS_Address(ins); // +2 because the first 2 entries hold metadata
1163  slot++;
1164  } else {
1165  // NOP
1166  }
1167  }
1168  }
1169 }
1170 
1171 static struct TraceSplay* splay(struct TraceSplay* root, ADDRINT ip) {
1173  return root;
1174 }
1175 
1176 
1177 // Does necessary work on a trace entry (called during runtime)
1178 // 1. If landed here due to function call, then go down in CCT.
1179 // 2. Look up the current trace under the CCT node creating new if if needed.
1180 // 3. Update iterators and curXXXX pointers.
1181 
1182 static inline void InstrumentTraceEntry(uint32_t traceKey, uint32_t numInterestingInstInTrace, ADDRINT traceFirstIp, THREADID threadId) {
1183  ThreadData* tData = CCTLibGetTLS(threadId);
1184 
1185  // Post-exception landing-pad re-anchor. See the design notes above
1186  // CaptureLandingPadTarget: if a _Unwind_SetIP call armed a pending
1187  // landing pad and THIS trace's first IP matches, libgcc just
1188  // context-restored into the handler frame and we need to move
1189  // tlsCurrentTraceNode back to that frame BEFORE the sibling/normal
1190  // branch logic below runs. tlsInitiatedCall=false forces the
1191  // sibling branch so the landing pad's own Pin trace becomes a
1192  // sibling of the handler's own trace under the same parent --
1193  // giving chains like `handler_caller -> handler(landing pad) -> C`
1194  // for the post-catch path (landing pad's function name resolves
1195  // to the handler's since its IP lies inside the handler's body).
1196  if (tData->tlsPendingLandingPadIp != 0 &&
1197  tData->tlsPendingLandingPadIp == traceFirstIp) {
1198  // Re-anchor as a CHILD of the handler frame (normal branch)
1199  // rather than a sibling. Sibling placement was ambiguous
1200  // because Pin can produce multiple "main"-labeled Pin traces
1201  // (loop body vs post-return continuation) with different
1202  // callerCtxtHndl values, so which parent we'd splay under
1203  // depended on which handler-labeled TraceNode the walker
1204  // returned. Normal-branch places the landing pad
1205  // deterministically as a child of the specific handler
1206  // TraceNode. The landing pad's function name still resolves
1207  // to the handler's own name (its IP lies inside the handler
1208  // function's body), so chain function-names read
1209  // `... -> handler -> handler(landing pad) -> C` which is
1210  // exactly the shape the user asked for -- C's immediate
1211  // parent function-name is the handler.
1214  tData->tlsCurrentCtxtHndl = tData->tlsPendingHandlerCtxt;
1215  tData->tlsInitiatedCall = true; // NORMAL branch: landing pad becomes CHILD of handler
1216  tData->tlsPendingLandingPadIp = 0;
1217  tData->tlsPendingHandlerFrame = nullptr;
1218  tData->tlsPendingHandlerCtxt = 0;
1219  }
1220 
1221  // if landed here w/o a call instruction, then let's make this trace a sibling.
1222  // The trick to do it is to go to the parent TraceNode and make this trace a child of it
1223  if (!tData->tlsInitiatedCall) {
1225  } else {
1226  // tlsCurrentCtxtHndl must be pointing to the call IP in the parent trace
1227  tData->tlsInitiatedCall = false;
1228  }
1229 
1230  // if the current trace is a child of currentIPNode, then let's set ourselves to that
1231 #ifdef USE_SPLAY_TREE
1232  TraceSplay* found = splay(GET_IPNODE_FROM_CONTEXT_HANDLE(tData->tlsCurrentCtxtHndl)->calleeTraceNodes, traceKey);
1233 
1234  // Check if a trace node with traceKey already exists under this context node
1235  if (found && (traceKey == found->key)) {
1236  GET_IPNODE_FROM_CONTEXT_HANDLE(tData->tlsCurrentCtxtHndl)->calleeTraceNodes = found;
1237  // already present, so set current trace to it
1238  UpdateCurTraceAndIp(tData, found->value);
1239  } else {
1240  // Create new trace node and insert under the IPNode.
1241  TraceNode* newChild = new TraceNode();
1242 #if 0
1243  static uint64_t traceNodeCnt = 0;
1244  traceNodeCnt++;
1245 
1246  if((traceNodeCnt % 100000) == 0)
1247  printf("\n Trace traceNodeCnt=%lu", traceNodeCnt);
1248 
1249 #endif
1250  newChild->callerCtxtHndl = tData->tlsCurrentCtxtHndl;
1251  newChild->traceKey = traceKey;
1252 
1253  if (numInterestingInstInTrace) {
1254  // if CONTINUOUS_DEADINFO is set, then all ip vecs come from a fixed 4GB buffer
1255  // might need a lock in MT case
1256  newChild->childCtxtStartIdx = GetNextIPVecBuffer(numInterestingInstInTrace);
1257  newChild->nSlots = numInterestingInstInTrace;
1259 
1260  //cerr<<"\n***:"<<numInterestingInstInTrace;
1261  for (uint32_t i = 0; i < numInterestingInstInTrace; i++) {
1262  ipNode[i].parentTraceNode = newChild;
1263  ipNode[i].calleeTraceNodes = nullptr;
1264  }
1265  } else {
1266  // This can happen since we may hot a trace with 0 interesting instructions.
1267  //assert(0 && "I never expect traces to have 0 instructions");
1268  newChild->nSlots = 0;
1269  newChild->childCtxtStartIdx = 0;
1270  }
1271 
1272  TraceSplay* newNode = new TraceSplay();
1273  newNode->key = traceKey;
1274  newNode->value = newChild;
1275  GET_IPNODE_FROM_CONTEXT_HANDLE(tData->tlsCurrentCtxtHndl)->calleeTraceNodes = newNode;
1276 
1277  if (!found) {
1278  newNode->left = nullptr;
1279  newNode->right = nullptr;
1280  } else if (traceKey < found->key) {
1281  newNode->left = found->left;
1282  newNode->right = found;
1283  found->left = nullptr;
1284  } else { // addr > addr of found
1285  newNode->left = found;
1286  newNode->right = found->right;
1287  found->right = nullptr;
1288  }
1289 
1290  UpdateCurTraceAndIp(tData, newChild);
1291  }
1292 
1293 #else
1294  assert 0 && "not maintained");
1295 #endif
1296 }
1297 
1298 
1299 // Instrument a trace, take the first instruction in the first BBL and insert the analysis function before that
1300 static void CCTLibInstrumentTrace(TRACE trace, void* isInterestingIns) {
1301  BBL bbl = TRACE_BblHead(trace);
1302  INS ins = BBL_InsHead(bbl);
1303  uint32_t numInterestingInstInTrace = GetNumInterestingInsInTrace(trace, (IsInterestingInsFptr)isInterestingIns);
1304  uint32_t traceKey = GetNextTraceKey();
1305  // Classify the enclosing routine for direct self-recursion. If Pin
1306  // has no valid RTN for this trace (data-in-code, unbacked JIT, etc.)
1307  // rinfo is null and instrumentation falls back to today's behavior.
1308  RTN rtn = TRACE_Rtn(trace);
1309  const RtnInfo* rinfo = RTN_Valid(rtn) ? GetOrClassifyRoutine(rtn) : nullptr;
1310  INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)InstrumentTraceEntry, IARG_UINT32, traceKey, IARG_UINT32, numInterestingInstInTrace, IARG_ADDRINT, TRACE_Address(trace), IARG_THREAD_ID, IARG_END);
1311  PopulateIPReverseMapAndAccountTraceInstructions(trace, traceKey, numInterestingInstInTrace, (IsInterestingInsFptr)isInterestingIns, rinfo);
1312 }
1313 
1314 
1315 static void OnSig(THREADID threadId, CONTEXT_CHANGE_REASON reason, const CONTEXT* ctxtFrom,
1316  CONTEXT* ctxtTo, INT32 sig, VOID* v) {
1317  ThreadData* tData = CCTLibGetTLS(threadId);
1318 
1319  switch (reason) {
1320  case CONTEXT_CHANGE_REASON_FATALSIGNAL:
1321  cerr << "\n FATAL SIGNAL";
1322 
1323  case CONTEXT_CHANGE_REASON_SIGNAL:
1324  //cerr<<"\n SIGNAL";
1325  // rest will be set as we enter the signal callee
1326  tData->tlsInitiatedCall = true;
1327  break;
1328 
1329  case CONTEXT_CHANGE_REASON_SIGRETURN: {
1330  // nothig needs to be done! works like magic!!
1331  //cerr<<"\n SIG RET";
1332  //assert(0 && "NYI");
1333  break;
1334  }
1335 
1336  default:
1337  assert(0 && "\n BAD CONTEXT SWITCH");
1338  }
1339 }
1340 
1341 
1343  ThreadData* tData = CCTLibGetTLS(id);
1344  uint32_t slot = tData->curSlotNo;
1345  assert(slot < tData->tlsCurrentTraceNode->nSlots);
1347 }
1348 
1349 
1350 IPNode* GetPINCCTCurrentContextWithSlot(THREADID id, uint32_t slot) {
1351  ThreadData* tData = CCTLibGetTLS(id);
1352  assert(slot < tData->tlsCurrentTraceNode->nSlots);
1354 }
1355 
1356 ContextHandle_t GetContextHandle(const THREADID id, const uint32_t slot) {
1357  ThreadData* tData = CCTLibGetTLS(id);
1358  assert(slot < tData->tlsCurrentTraceNode->nSlots);
1359  return tData->tlsCurrentTraceNode->childCtxtStartIdx + slot;
1360 }
1361 
1362 #ifdef HAVE_METRIC_PER_IPNODE
1363 void** GetIPNodeMetric(const THREADID id, const uint32_t slot) {
1364  ThreadData* tData = CCTLibGetTLS(id);
1365  assert(slot < tData->tlsCurrentTraceNode->nSlots);
1366  return &(GET_IPNODE_FROM_CONTEXT_HANDLE(tData->tlsCurrentTraceNode->childCtxtStartIdx + slot)->metric);
1367 }
1368 #endif
1369 
1372 }
1373 
1375  return &GLOBAL_STATE.preAllocatedContextBuffer[index];
1376 }
1377 
1378 static void SegvHandler(int sig) {
1379  longjmp(GLOBAL_STATE.env, 1);
1380 }
1381 
1382 
1383 // On program termination output all gathered data and statistics
1384 static VOID CCTLibFini(INT32 code, VOID* v) {
1385  // byte count
1386  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n#eof");
1387  //fclose(GLOBAL_STATE.CCTLibLogFile);
1388 }
1389 
1390 #if 0
1391 // Visit all nodes of the splay tree of child traces.
1392  static void VisitAllNodesOfSplayTree(TraceSplay* node, FILE* const fp) {
1393  if(node == NULL)
1394  return;
1395 
1396  // visit left
1397  VisitAllNodesOfSplayTree(node->left, fp);
1398  // process self
1399  SerializeCCTNode(node->value, fp);
1400  // visit right
1401  VisitAllNodesOfSplayTree(node->right, fp);
1402  }
1403 
1404  static void SerializeCCTNode(TraceNode* traceNode, FILE* const fp) {
1405  // if traceNode had 0 interesting childCtxtStartIdx, then we are at a leaf trace so, we can simply return.
1406  if(traceNode->nSlots == 0)
1407  return;
1408 
1409  IPNode* parentIPNode = traceNode->callerCtxtHndl ? traceNode->callerCtxtHndl : 0;
1410  ADDRINT* traceIPs = (ADDRINT*)(GLOBAL_STATE.traceShadowMap[traceNode->traceKey]);
1411  ADDRINT moduleId = traceIPs[-1];
1412  ADDRINT loadOffset = GLOBAL_STATE.ModuleInfoMap[moduleId].imgLoadOffset;
1413 
1414  // Iterate over all IPNodes in this trace
1415  for(uint32_t i = 0 ; i < traceNode->nSlots; i++) {
1416  fprintf(fp, "\n%p:%p:%p:%lu", &traceNode->childCtxtStartIdx[i], (void*)(traceIPs[i] - loadOffset), parentIPNode, moduleId);
1417  }
1418 
1419  // Iterate over all IPNodes
1420  for(uint32_t i = 0 ; i < traceNode->nSlots; i++) {
1421  // Iterate over all decendent TraceNode of traceNode->childCtxtStartIdx[i]
1422  VisitAllNodesOfSplayTree((traceNode->childCtxtStartIdx[i]).calleeTraceNodes, fp);
1423  }
1424  }
1425 
1426  static void SerializeAllCCTs() {
1427  for(uint32_t id = 0 ; id < GLOBAL_STATE.numThreads; id++) {
1428  ThreadData* tData = CCTLibGetTLS(id);
1429  std::stringstream cctMapFilePath;
1430  cctMapFilePath << GLOBAL_STATE.CCTLibFilePathPrefix << "-Thread" << id << "-CCTMap.txt";
1431  FILE* fp = fopen(cctMapFilePath.str().c_str(), "w");
1432  fprintf(fp, "NodeId:IP:ParentId:ModuleId");
1433  SerializeCCTNode(tData->tlsRootTraceNode, fp);
1434  fclose(fp);
1435  }
1436  }
1437 
1438 #endif
1439 
1440 // Serialization of CCTs, module info, and trace IPs. Previously guarded by
1441 // USE_BOOST as an opt-in; now always compiled in since Boost is gone.
1442 
1443 // Visit all nodes of the splay tree of child traces.
1444 static void VisitAllNodesOfSplayTree(TraceSplay* node, FILE* const fp) {
1445  // process self
1446  SerializeCCTNode(node->value, fp);
1447 
1448  // visit left
1449  if (node->left)
1450  VisitAllNodesOfSplayTree(node->left, fp);
1451 
1452  // visit right
1453  if (node->right)
1454  VisitAllNodesOfSplayTree(node->right, fp);
1455 }
1456 
1457 static uint32_t NO_MORE_TRACE_NODES_IN_SPLAY_TREE = UINT_MAX;
1458 
1459 static void SerializeCCTNode(TraceNode* traceNode, FILE* const fp) {
1460  SerializedTraceNode serializedTraceNode = {traceNode->traceKey, traceNode->nSlots, traceNode->childCtxtStartIdx};
1461  fwrite(&serializedTraceNode, sizeof(SerializedTraceNode), 1, fp);
1462 
1463  // Iterate over all IPNodes
1465  for (uint32_t i = 0; i < traceNode->nSlots; i++) {
1466  if ((ipNode[i]).calleeTraceNodes == nullptr) {
1468  } else {
1469  // Iterate over all decendent TraceNode of traceNode->childCtxtStartIdx[i]
1470  VisitAllNodesOfSplayTree((ipNode[i]).calleeTraceNodes, fp);
1472  }
1473  }
1474 }
1475 
1476 static TraceNode* DeserializeCCTNode(ContextHandle_t parentCtxtHndl, FILE* const fp) {
1477  uint32_t noMoreTrace;
1478 
1479  if (fread(&noMoreTrace, sizeof(noMoreTrace), 1, fp) != 1) {
1480  fprintf(stderr, "\n Failed to read at line %d\n", __LINE__);
1481  PIN_ExitProcess(-1);
1482  }
1483 
1484  if (noMoreTrace == NO_MORE_TRACE_NODES_IN_SPLAY_TREE) {
1485  return nullptr;
1486  }
1487 
1488  // go back 4 bytes;
1489  fseek(fp, -sizeof(noMoreTrace), SEEK_CUR);
1490  SerializedTraceNode serializedTraceNode;
1491 
1492  if (fread(&serializedTraceNode, sizeof(SerializedTraceNode), 1, fp) != 1) {
1493  fprintf(stderr, "\n Failed to read at line %d\n", __LINE__);
1494  PIN_ExitProcess(-1);
1495  }
1496 
1497  TraceNode* traceNode = new TraceNode();
1498  traceNode->traceKey = serializedTraceNode.traceKey;
1499  traceNode->nSlots = serializedTraceNode.nSlots;
1500  traceNode->childCtxtStartIdx = serializedTraceNode.childCtxtStartIdx;
1501  traceNode->callerCtxtHndl = parentCtxtHndl;
1502 
1503  // Iterate over all IPNodes
1505  for (uint32_t i = 0; i < traceNode->nSlots; i++) {
1506  ipNode[i].parentTraceNode = traceNode;
1507 
1508  while (true) {
1509  TraceNode* childTrace = DeserializeCCTNode(traceNode->childCtxtStartIdx + i, fp);
1510 
1511  if (childTrace == nullptr)
1512  break;
1513 
1514  // add childTrace to the splay tree at traceNode->childCtxtStartIdx[i]
1515  TraceSplay* newNode = new TraceSplay();
1516  newNode->key = childTrace->traceKey;
1517  newNode->value = childTrace;
1518 
1519  // if no children
1520  IPNode* childIPNode = GET_IPNODE_FROM_CONTEXT_HANDLE(traceNode->childCtxtStartIdx + i);
1521  if (childIPNode->calleeTraceNodes == nullptr) {
1522  childIPNode->calleeTraceNodes = newNode;
1523  newNode->left = nullptr;
1524  newNode->right = nullptr;
1525  } else {
1526  TraceSplay* found = splay(childIPNode->calleeTraceNodes, childTrace->traceKey);
1527 
1528  // Install newNode as the new splay root -- mirrors the
1529  // live-instrumentation insertion path (search for the
1530  // sibling site in this file). Without this line, newNode
1531  // is unreachable and leaked, and the tree still points at
1532  // `found`, so the newly deserialized child is never found.
1533  childIPNode->calleeTraceNodes = newNode;
1534  if (childTrace->traceKey < found->key) {
1535  newNode->left = found->left;
1536  newNode->right = found;
1537  found->left = nullptr;
1538  } else { // addr > addr of found
1539  newNode->left = found;
1540  newNode->right = found->right;
1541  found->right = nullptr;
1542  }
1543  }
1544  }
1545  }
1546 
1547  return traceNode;
1548 }
1549 
1550 
1551 static void SerializeAllCCTs() {
1552  for (uint32_t id = 0; id < GLOBAL_STATE.numThreads; id++) {
1553  ThreadData* tData = CCTLibGetTLS(id);
1554  std::stringstream cctMapFilePath;
1556  FILE* fp = fopen(cctMapFilePath.str().c_str(), "wb");
1557 
1558  if (fp == nullptr) {
1559  fprintf(stderr, "\n Failed to open %s in line %d. Exiting\n", cctMapFilePath.str().c_str(), __LINE__);
1560  PIN_ExitProcess(-1);
1561  }
1562 
1563  //record thread id
1564  uint32_t threadId = tData->tlsThreadId;
1565  fwrite(&threadId, sizeof(tData->tlsThreadId), 1, fp);
1566  // record path of the parent
1567  ContextHandle_t parentCtxtHndl = tData->tlsParentThreadCtxtHndl;
1568  fwrite(&parentCtxtHndl, sizeof(ContextHandle_t), 1, fp);
1569  SerializeCCTNode(tData->tlsRootTraceNode, fp);
1570  fclose(fp);
1571  }
1572 }
1573 
1574 
1575 static bool IsDirectory(const char* path) {
1576  struct stat statbuf;
1577  if (stat(path, &statbuf) != 0)
1578  return false;
1579  return S_ISDIR(statbuf.st_mode);
1580 }
1581 
1582 static bool endsWithExtn(const string& base, const string& ext) {
1583  if (ext.size() > base.size())
1584  return false;
1585  return std::equal(base.begin() + base.size() - ext.size(), base.end(), ext.begin());
1586 }
1587 
1588 // return the filenames of all files that have the specified extension
1589 // in the specified directory and all subdirectories
1590 static void GetAllFilesInDirWithExtn(const string& root, const string& ext, vector<string>& ret) {
1591  char resolvedPath[PATH_MAX];
1592  realpath(root.c_str(), resolvedPath);
1593  DIR* dirp = opendir(resolvedPath);
1594  if (nullptr == dirp) {
1595  // TODO(preexisting-bug): the original code throws here.
1596  // Pin's analysis-dispatch loop does not unwind through C++
1597  // exceptions even under `-fexceptions`; an unhandled throw
1598  // will terminate the tool with std::terminate rather than a
1599  // clean error. Convert to an error-return contract (or wrap
1600  // the caller under PIN_LockClient with a try/catch). Not
1601  // reached by `make check`; restoring the original throw to
1602  // scope this change strictly to porting.
1603  throw string("Directory does not exits" + root);
1604  }
1605  struct dirent* dp;
1606  while ((dp = readdir(dirp)) != nullptr) {
1607  char concatedPath[PATH_MAX];
1608  // Bounded concatenation of resolvedPath + "/" + dp->d_name.
1609  // snprintf always null-terminates and reports truncation via
1610  // its return value; skip entries that don't fit rather than
1611  // silently truncating a filename we might later try to open.
1612  int written = snprintf(concatedPath, sizeof(concatedPath),
1613  "%s/%s", resolvedPath, dp->d_name);
1614  if (written < 0 || (size_t)written >= sizeof(concatedPath))
1615  continue;
1616  if (IsDirectory(concatedPath))
1617  continue;
1618  if (!endsWithExtn(string(concatedPath), ext))
1619  continue;
1620  ret.push_back(string(concatedPath));
1621  }
1622  closedir(dirp);
1623 }
1624 
1625 static void DeserializeAllCCTs() {
1626  // Get all files with
1627  vector<string> serializedCCTFiles;
1629  for (uint32_t id = 0; id < serializedCCTFiles.size(); id++) {
1630  std::stringstream cctMapFilePath;
1631  cctMapFilePath << serializedCCTFiles[id];
1632  //fprintf(stderr, "\nexists = %d\n", 0);
1633  FILE* fp = fopen(cctMapFilePath.str().c_str(), "rb");
1634 
1635  if (fp == nullptr) {
1636  perror("fopen:");
1637  fprintf(stderr, "\n Failed to open %s in line %d. Exiting\n", cctMapFilePath.str().c_str(), __LINE__);
1638  PIN_ExitProcess(-1);
1639  }
1640 
1641  // Get thread id
1642  uint32_t threadId;
1643 
1644  if (fread(&threadId, sizeof(threadId), 1, fp) != 1) {
1645  fprintf(stderr, "\n Failed to read at line %d\n", __LINE__);
1646  PIN_ExitProcess(-1);
1647  }
1648 
1649  // record path of the parent
1650  ContextHandle_t parentCtxtHndl;
1651 
1652  if (fread(&parentCtxtHndl, sizeof(ContextHandle_t), 1, fp) != 1) {
1653  fprintf(stderr, "\n Failed to read at line %d\n", __LINE__);
1654  PIN_ExitProcess(-1);
1655  }
1656 
1657  TraceNode* rootTrace = DeserializeCCTNode(parentCtxtHndl, fp);
1658 #ifndef NDEBUG
1659  // we should be at the end of file now
1660  uint8_t dummy;
1661  assert(fread(&dummy, sizeof(uint8_t), 1, fp) == 0);
1662 #endif
1663  fclose(fp);
1664  // Add a ThreadData record to GLOBAL_STATE.deserializedCCTs
1665  ThreadData tdata;
1666  //bzero(&tdata, sizeof(tdata));
1667  tdata.tlsThreadId = threadId;
1668  tdata.tlsParentThreadCtxtHndl = parentCtxtHndl;
1669  tdata.tlsRootTraceNode = rootTrace;
1670  tdata.tlsRootCtxtHndl = rootTrace->childCtxtStartIdx;
1671  GLOBAL_STATE.deserializedCCTs.push_back(tdata);
1672  // Update the number of threads
1674  }
1675 }
1676 
1677 static void DottifyCCTNode(TraceNode* traceNode, uint64_t parentDotId, FILE* const fp);
1678 
1679 static uint64_t gDotId;
1680 #if 0
1681 // Visit all nodes of the splay tree of child traces.
1682  static void DottifyAllNodesOfSplayTree(TraceSplay* node, uint64_t curDotId, FILE* const fp) {
1683  if(node == NULL)
1684  return;
1685 
1686  // visit left
1687  DottifyAllNodesOfSplayTree(node->left, curDotId, fp);
1688  // process self
1689  DottifyCCTNode(node->value, curDotId, fp);
1690  // visit right
1691  DottifyAllNodesOfSplayTree(node->right, curDotId, fp);
1692  }
1693 #endif
1694 
1695 // Visit all nodes of the splay tree of child traces.
1696 static void ListAllNodesOfSplayTree(TraceSplay* node, vector<TraceNode*>& childTraces) {
1697  if (node == nullptr)
1698  return;
1699 
1700  // visit left
1701  ListAllNodesOfSplayTree(node->left, childTraces);
1702  childTraces.push_back(node->value);
1703  // visit right
1704  ListAllNodesOfSplayTree(node->right, childTraces);
1705 }
1706 
1707 
1708 static void DottifyCCTNode(TraceNode* traceNode, uint64_t parentDotId, FILE* const fp) {
1709  // if traceNode had 0 interesting childCtxtStartIdx, then we are at a leaf trace so, we can simply return.
1710  if (traceNode->nSlots == 0) {
1711  return;
1712  }
1713 
1714  uint64_t myDotId = ++gDotId;
1715  fprintf(fp, "\"%" PRIx64 "\" -> \"%" PRIx64 "\";\n", parentDotId, myDotId);
1716  vector<TraceNode*> childTraces;
1717 
1718  // Iterate over all IPNodes
1719  for (uint32_t i = 0; i < traceNode->nSlots; i++) {
1720  // Iterate over all decendent TraceNode of traceNode->childCtxtStartIdx[i]
1721  //DottifyAllNodesOfSplayTree((traceNode->childCtxtStartIdx[i]).calleeTraceNodes, childTraceDotId, fp);
1722  ListAllNodesOfSplayTree(GET_IPNODE_FROM_CONTEXT_HANDLE(traceNode->childCtxtStartIdx + i)->calleeTraceNodes, childTraces);
1723  }
1724 
1725  for (vector<TraceNode*>::iterator it = childTraces.begin(); it != childTraces.end(); it++) {
1726  DottifyCCTNode(*it, myDotId, fp);
1727  }
1728 }
1729 
1730 
1732  std::stringstream cctMapFilePath;
1733  cctMapFilePath << GLOBAL_STATE.serializationDirectory << "./CCTMap.dot";
1734  FILE* fp = fopen(cctMapFilePath.str().c_str(), "w");
1735 
1736  if (fp == nullptr) {
1737  fprintf(stderr, "\n Failed to open %s in line %d. Exiting\n", cctMapFilePath.str().c_str(), __LINE__);
1738  PIN_ExitProcess(-1);
1739  }
1740 
1741  fprintf(fp, "digraph CCTLibGraph {\n");
1742 
1743  for (uint32_t id = 0; id < GLOBAL_STATE.numThreads; id++) {
1744  ThreadData* tData = CCTLibGetTLS(id);
1745  DottifyCCTNode(tData->tlsRootTraceNode, gDotId, fp);
1746  }
1747 
1748  fprintf(fp, "\n}");
1749  fclose(fp);
1750 }
1751 
1752 
1753 #define SERIALIZED_MODULE_MAP_SUFFIX "/ModuleMap.txt"
1754 
1755 static void SerializeMouleInfo() {
1757  FILE* fp = fopen(moduleFilePath.c_str(), "w");
1758 
1759  if (fp == nullptr) {
1760  perror("Error:");
1761  fprintf(stderr, "\n Failed to open %s in line %d. Exiting\n", moduleFilePath.c_str(), __LINE__);
1762  PIN_ExitProcess(-1);
1763  }
1764 
1765  unordered_map<UINT32, ModuleInfo>::iterator it;
1766  fprintf(fp, "ModuleId\tModuleFile\tLoadOffset");
1767 
1768  for (it = GLOBAL_STATE.ModuleInfoMap.begin(); it != GLOBAL_STATE.ModuleInfoMap.end(); ++it) {
1769  fprintf(fp, "\n%u\t%s\t%p", it->first, (it->second).moduleName.c_str(), (void*)((it->second).imgLoadOffset));
1770  }
1771 
1772  fclose(fp);
1773 }
1774 
1775 static void DeserializeMouleInfo() {
1777  FILE* fp = fopen(moduleFilePath.c_str(), "r");
1778 
1779  if (fp == nullptr) {
1780  perror("Error");
1781  fprintf(stderr, "\n Failed to open %s in line %d. Exiting\n", moduleFilePath.c_str(), __LINE__);
1782  PIN_ExitProcess(-1);
1783  }
1784 
1785  // read header and thow it away
1786  uint32_t moduleId;
1787  ADDRINT offset;
1788  char path[MAX_FILE_PATH];
1789  //fprintf(fp, "ModuleId\tModuleFile\tLoadOffset");
1790  fscanf(fp, "%s%s%s", path, path, path);
1791 
1792  while (EOF != fscanf(fp, "%u%s%p", &moduleId, path, (void**)&offset)) {
1793  ModuleInfo minfo;
1794  minfo.moduleName = path;
1795  minfo.imgLoadOffset = offset;
1796  GLOBAL_STATE.ModuleInfoMap[moduleId] = minfo;
1797  }
1798 
1799  fclose(fp);
1800 }
1801 
1802 
1803 static void SerializeTraceIps() {
1805  FILE* fp = fopen(traceMapFilePath.c_str(), "wb");
1806 
1807  if (fp == nullptr) {
1808  fprintf(stderr, "\n Failed to open %s in line %d. Exiting\n", traceMapFilePath.c_str(), __LINE__);
1809  PIN_ExitProcess(-1);
1810  }
1811 
1812  unordered_map<uint32_t, void*>::iterator it;
1813  //fprintf(fp, "TraceKey:NumSlots:ModuleId:[ip1][ip2]..[ipNumSlots]");
1814 
1815  for (it = GLOBAL_STATE.traceShadowMap.begin(); it != GLOBAL_STATE.traceShadowMap.end(); ++it) {
1816  // traceId
1817  fwrite(&(it->first), sizeof(it->first), 1, fp);
1818  ADDRINT* ptr = (ADDRINT*)(it->second);
1819  uint32_t moduleId = (uint32_t)ptr[-1];
1820  ADDRINT offset = GLOBAL_STATE.ModuleInfoMap[moduleId].imgLoadOffset;
1821  ADDRINT nSlots = ptr[-2];
1822 
1823  // Normalize all IPs
1824  // NOTE --- once this update has happened, the traceShadowMapp[traceId] is rendered unusables without adding the offset in this run.
1825  // It must be used in post mortem analysis from this point onwards.
1826  for (ADDRINT i = 0; i < nSlots; i++) {
1827  ptr[i] = ptr[i] - offset;
1828  }
1829 
1830  // Write all slots
1831  fwrite(ptr - 2, sizeof(ADDRINT), ptr[-2] + 2, fp);
1832  }
1833 
1834  fclose(fp);
1835 }
1836 
1837 
1838 static void DeserializeTraceIps() {
1840  FILE* fp = fopen(traceMapFilePath.c_str(), "rb");
1841 
1842  if (fp == nullptr) {
1843  fprintf(stderr, "\n Failed to open %s in line %d. Exiting\n", traceMapFilePath.c_str(), __LINE__);
1844  PIN_ExitProcess(-1);
1845  }
1846 
1847  unordered_map<uint32_t, void*>::iterator it;
1848  //fprintf(fp, "TraceKey:NumSlots:ModuleId:[ip1][ip2]..[ipNumSlots]");
1849  uint32_t traceKey;
1850 
1851  while (fread(&traceKey, sizeof(traceKey), 1, fp) == 1) {
1852  // read num entries
1853  ADDRINT numSlots;
1854 
1855  if (fread(&numSlots, sizeof(ADDRINT), 1, fp) != 1) {
1856  fprintf(stderr, "\n Failed to read in line %d. Exiting\n", __LINE__);
1857  PIN_ExitProcess(-1);
1858  }
1859 
1860  // allocate the shadow ips
1861  ADDRINT* array = (ADDRINT*)malloc((numSlots + 2) * sizeof(ADDRINT));
1862  array[0] = numSlots;
1863 
1864  // read remaining entires
1865  if (fread(&array[1], sizeof(ADDRINT), numSlots + 1, fp) != (numSlots + 1)) {
1866  fprintf(stderr, "\n Failed to read in line %d. Exiting\n", __LINE__);
1867  PIN_ExitProcess(-1);
1868  }
1869 
1870  // Insert into the shadow map
1871  GLOBAL_STATE.traceShadowMap[traceKey] = (void*)(&array[2]); // 2 because first 2 entries are behind as in runtime.
1872  }
1873 
1874  fclose(fp);
1875 }
1876 
1877 
1878 void SerializeMetadata(const string& directoryForSerializationFiles) {
1879  if (!directoryForSerializationFiles.empty()) {
1880  GLOBAL_STATE.serializationDirectory = directoryForSerializationFiles;
1881  } else {
1882  // construct one
1883  std::stringstream ss;
1884  char hostname[MAX_FILE_PATH];
1885  gethostname(hostname, MAX_FILE_PATH);
1886  pid_t pid = getpid();
1887  ss << CCTLIB_SERIALIZATION_DEFAULT_DIR_NAME << hostname << "-" << pid;
1889  }
1890 
1891  // create directory. Using system("mkdir -p ...") here spawns /bin/sh,
1892  // which Pin has to follow into via ptrace. On modern kernels with
1893  // ptrace_scope=1 that attach is denied. Use direct syscalls instead.
1894  {
1895  const string& dir = GLOBAL_STATE.serializationDirectory;
1896  struct stat st;
1897  if (stat(dir.c_str(), &st) != 0) {
1898  size_t pos = 0;
1899  while (pos != string::npos) {
1900  pos = dir.find('/', pos + 1);
1901  string sub = (pos == string::npos) ? dir : dir.substr(0, pos);
1902  if (sub.empty())
1903  continue;
1904  if (mkdir(sub.c_str(), 0755) != 0 && errno != EEXIST) {
1905  fprintf(stderr, "\n failed to create directory %s: %s", sub.c_str(), strerror(errno));
1906  break;
1907  }
1908  }
1909  }
1910  }
1911 
1912  SerializeAllCCTs();
1915 }
1916 
1917 void DeserializeMetadata(const string& directoryForSerializationFiles) {
1918  GLOBAL_STATE.serializationDirectory = directoryForSerializationFiles;
1922 }
1923 
1924 /**
1925  * Returns the peak (maximum so far) resident set size (physical
1926  * memory use) measured in KB, or zero if the value cannot be
1927  * determined on this OS.
1928  */
1929 size_t getPeakRSS() {
1930  struct rusage rusage;
1931  getrusage(RUSAGE_SELF, &rusage);
1932  return (size_t)(rusage.ru_maxrss);
1933 }
1934 
1935 
1936 static void PrintStats() {
1937  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nTotal call paths=%" PRIu64, GLOBAL_STATE.curPreAllocatedContextBufferIndex);
1938  // Peak resource usage
1939  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nPeak RSS=%zu", getPeakRSS());
1940 }
1941 
1942 
1943 // This function is called when the application exits
1944 VOID Fini(INT32 code, VOID* v) {
1945  //SerializeMetadata();
1946  //DottifyAllCCTs();
1947  PrintStats();
1948 }
1949 
1950 // Given a pointer (i.e. slot) within a trace node, returns the IP corresponding to that slot
1951 static inline ADDRINT GetIPFromInfo(ContextHandle_t ctxtHndle) {
1952  // GET_IPNODE_FROM_CONTEXT_HANDLE is the UNCHECKED variant that does
1953  // pointer arithmetic on a base allocated during InitBuffers(); it
1954  // never returns null for a valid handle. Analyzer can't infer the invariant.
1955  TraceNode* traceNode = GET_IPNODE_FROM_CONTEXT_HANDLE(ctxtHndle)->parentTraceNode; // NOLINT(clang-analyzer-core.NullDereference)
1956  assert(ctxtHndle >= traceNode->childCtxtStartIdx);
1957  assert(ctxtHndle < traceNode->childCtxtStartIdx + traceNode->nSlots);
1958  // what is my slot id ?
1959  uint32_t slotNo = ctxtHndle - traceNode->childCtxtStartIdx;
1960 
1961  ADDRINT* ip = (ADDRINT*)GLOBAL_STATE.traceShadowMap[traceNode->traceKey];
1962  return ip[slotNo];
1963 }
1964 // Given a pointer (i.e. slot) within a trace node, set the IP corresponding to that slot
1965 // Used for creating dummy root by eliding all frames above "main"
1966 static inline void SetIPFromInfo(ContextHandle_t ctxtHndle, ADDRINT val) {
1967  TraceNode* traceNode = GET_IPNODE_FROM_CONTEXT_HANDLE(ctxtHndle)->parentTraceNode;
1968  assert(ctxtHndle >= traceNode->childCtxtStartIdx);
1969  assert(ctxtHndle < traceNode->childCtxtStartIdx + traceNode->nSlots);
1970  // what is my slot id ?
1971  uint32_t slotNo = ctxtHndle - traceNode->childCtxtStartIdx;
1972  ADDRINT* ip = (ADDRINT*)GLOBAL_STATE.traceShadowMap[traceNode->traceKey];
1973  ip[slotNo] = val;
1974 }
1975 
1976 
1977 // Given a pointer (i.e. slot) within a trace node, returns the module name corresponding to that slot
1978 static inline const string& GetModulePathFromInfo(IPNode* ipNode) {
1979  TraceNode* traceNode = ipNode->parentTraceNode;
1980  ADDRINT* ptr = (ADDRINT*)GLOBAL_STATE.traceShadowMap[traceNode->traceKey];
1981  UINT32 moduleId = ptr[-1]; // module id is stored one behind.
1982  return GLOBAL_STATE.ModuleInfoMap[moduleId].moduleName;
1983 }
1984 
1985 
1986 // Given a pointer (i.e. slot) within a trace node, returns the Line number corresponding to that slot
1987 static inline void GetLineFromInfo(const ADDRINT& ip, uint32_t& lineNo, string& filePath) {
1988  PIN_GetSourceLocation(ip, NULL, (INT32*)&lineNo, &filePath);
1989 }
1990 
1991 static void GetDecodedInstFromIP(ADDRINT ip) {
1992  // Get the instruction in a string
1993  xed_decoded_inst_t xedd;
1995  xed_decoded_inst_zero_set_mode(&xedd, &GLOBAL_STATE.cct_xed_state);
1996 
1997  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
1998  if (0 == xed_format_context(XED_SYNTAX_ATT, &xedd, GLOBAL_STATE.disassemblyBuff, 200, ip, nullptr, nullptr))
1999  strcpy(GLOBAL_STATE.disassemblyBuff, "xed_decoded_inst_dump_att_format failed");
2000  } else {
2001  strcpy(GLOBAL_STATE.disassemblyBuff, "xed_decode failed");
2002  }
2003 }
2004 
2005 // Returns true if the given address belongs to one of the loaded binaries
2006 static inline bool IsValidIP(ADDRINT ip) {
2007  for (IMG img = APP_ImgHead(); IMG_Valid(img); img = IMG_Next(img)) {
2008  if (ip >= IMG_LowAddress(img) && ip <= IMG_HighAddress(img)) {
2009  return true;
2010  }
2011  }
2012 
2013  return false;
2014 }
2015 #if 0
2016 // Returns true if the given deadinfo belongs to one of the loaded binaries
2017  static inline bool IsValidIP(DeadInfo di) {
2018  bool res = false;
2019 
2020  for(IMG img = APP_ImgHead(); IMG_Valid(img); img = IMG_Next(img)) {
2021  if((ADDRINT)di.firstIP >= IMG_LowAddress(img) && (ADDRINT)di.firstIP <= IMG_HighAddress(img)) {
2022  res = true;
2023  break;
2024  }
2025  }
2026 
2027  if(!res)
2028  return false;
2029 
2030  for(IMG img = APP_ImgHead(); IMG_Valid(img); img = IMG_Next(img)) {
2031  if((ADDRINT)di.secondIP >= IMG_LowAddress(img) && (ADDRINT)di.secondIP <= IMG_HighAddress(img)) {
2032  return true;
2033  }
2034  }
2035 
2036  return false;
2037  }
2038 #endif
2039 
2040 // Returns true if the address in the given context node corresponds to a sinature (assembly code: ) that corresponds to a .PLT section
2041 // Sample PLt signatire : ff 25 c2 24 21 00 jmpq *2172098(%rip) # 614340 <quoting_style_args+0x2a0>
2042 static inline bool IsValidPLTSignature(const ADDRINT& ip) {
2043  return (*((unsigned char*)ip) == 0xff) && (*((unsigned char*)ip + 1) == 0x25);
2044 }
2045 
2046 
2047 #define NOT_ROOT_CTX (-1)
2048 // Return true if the given ContextNode is one of the root context nodes
2049 static int IsARootIPNode(ContextHandle_t curCtxtHndle) {
2050  // if it is runing monitoring we will use CCTLibGetTLS
2052  for (uint32_t id = 0; id < GLOBAL_STATE.numThreads; id++) {
2053  ThreadData* tData = CCTLibGetTLS(id);
2054 
2055  if (tData->tlsRootCtxtHndl == curCtxtHndle)
2056  return id;
2057  }
2058  } else {
2059  //CCT_LIB_MODE_POSTMORTEM
2060  for (uint32_t id = 0; id < GLOBAL_STATE.numThreads; id++) {
2061  if (GLOBAL_STATE.deserializedCCTs[id].tlsRootCtxtHndl == curCtxtHndle)
2062  return GLOBAL_STATE.deserializedCCTs[id].tlsThreadId;
2063  }
2064  }
2065 
2066  return NOT_ROOT_CTX;
2067 }
2068 
2069 
2070 #if 0
2071 
2072  static VOID PrintFullCallingContext(IPNode* curIPNode);
2073 // Given a context node (curContext), traverses up in the chain till the root and prints the entire calling context
2074 
2075  static VOID PrintFullCallingContext(IPNode* curIPNode) {
2076  int depth = 0;
2077 #ifdef MULTI_THREADED
2078  int root;
2079 #endif // end MULTI_THREADED
2080 
2081  // set sig handler
2082  struct sigaction old;
2083  sigaction(SIGSEGV, &GLOBAL_STATE.sigAct, &old);
2084 
2085  // Dont print if the depth is more than MAX_CCT_PRINT_DEPTH since files become too large
2086  while(curIPNode && (depth ++ < MAX_CCT_PRINT_DEPTH)) {
2087  int threadCtx = 0;
2088 
2089  if((threadCtx = IsARootIPNode(curIPNode)) != NOT_ROOT_CTX) {
2090  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nTHREAD[%d]_ROOT_CTXT", threadCtx);
2091  // if the thread has a parent, recurse over it.
2092  IPNode* parentThreadIPNode = CCTLibGetTLS(threadCtx)->tlsParentThreadCtxtHndl;
2093 
2094  if(parentThreadIPNode)
2095  PrintFullCallingContext(parentThreadIPNode);
2096 
2097  break;
2098  } else {
2099  ADDRINT ip = GetIPFromInfo(curIPNode);
2100 
2101  if(IsValidIP(ip)) {
2102  if(PIN_UndecorateSymbolName(RTN_FindNameByAddress(ip), UNDECORATION_COMPLETE) == ".plt") {
2103  if(setjmp(GLOBAL_STATE.env) == 0) {
2104  if(IsValidPLTSignature(ip)) {
2105  uint64_t nextByte = (uint64_t) ip + 2;
2106  int* offset = (int*) nextByte;
2107  uint64_t nextInst = (uint64_t) ip + 6;
2108  ADDRINT loc = *((uint64_t*)(nextInst + *offset));
2109 
2110  if(IsValidIP(loc)) {
2111  string filePath;
2112  uint32_t lineNo;
2115  fprintf(GLOBAL_STATE.CCTLibLogFile, "\n%u:!%p:%s:%s:%s:%u", GET_CONTEXT_HANDLE_FROM_IP_NODE(curIPNode), (void*)ip, GLOBAL_STATE.disassemblyBuff, PIN_UndecorateSymbolName(RTN_FindNameByAddress(loc), UNDECORATION_COMPLETE).c_str(), filePath.c_str(), lineNo);
2116  } else {
2117  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nIN PLT BUT NOT VALID GOT");
2118  }
2119  } else {
2120  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nUNRECOGNIZED PLT SIGNATURE");
2121  //fprintf(GLOBAL_STATE.CCTLibLogFile,"\n plt plt plt %x", * ((UINT32*)curContext->address));
2122  //for(int i = 1; i < 4 ; i++)
2123  // fprintf(GLOBAL_STATE.CCTLibLogFile," %x", ((UINT32 *)curContext->address)[i]);
2124  }
2125  } else {
2126  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nCRASHED !!");
2127  }
2128  } else {
2129  string filePath;
2130  uint32_t lineNo;
2133 #if 0
2134  fprintf(GLOBAL_STATE.CCTLibLogFile, "\n%p:%s:%s:%s", (void*)ip, GLOBAL_STATE.disassemblyBuff, PIN_UndecorateSymbolName(RTN_FindNameByAddress(ip), UNDECORATION_COMPLETE).c_str(), line.c_str());
2135 #else
2136  // also print the IPNode handle so that I can debug deserialization
2137  fprintf(GLOBAL_STATE.CCTLibLogFile, "\n%u:%p:%s:%s:%s:%u", GET_CONTEXT_HANDLE_FROM_IP_NODE(curIPNode), (void*)ip, GLOBAL_STATE.disassemblyBuff, PIN_UndecorateSymbolName(RTN_FindNameByAddress(ip), UNDECORATION_COMPLETE).c_str(), filePath.c_str(), lineNo);
2138 #endif
2139  }
2140  } else {
2141  fprintf(GLOBAL_STATE.CCTLibLogFile, "\nBAD IP ");
2142  }
2143 
2144  curIPNode = curIPNode->parentTraceNode->callerCtxtHndl;
2145  }
2146  }
2147 
2148  //reset sig handler
2149  sigaction(SIGSEGV, &old, 0);
2150  }
2151 #endif
2152 
2153 VOID GetParentIPs(ContextHandle_t ctxtHandle, vector<ADDRINT>& parentIPs) {
2154  int depth = 0;
2155  while (IS_VALID_CONTEXT(ctxtHandle) && depth++ < MAX_CCT_PRINT_DEPTH) {
2156  ADDRINT ip = GetIPFromInfo(ctxtHandle);
2157  if (IsValidIP(ip)) {
2158  parentIPs.push_back(ip);
2159  }
2160  ctxtHandle = GET_IPNODE_FROM_CONTEXT_HANDLE(ctxtHandle)->parentTraceNode->callerCtxtHndl;
2161  }
2162 }
2163 
2164 static VOID GetFullCallingContextInSitu(ContextHandle_t curCtxtHndle, vector<Context>& contextVec) {
2165  int depth = 0;
2166 #ifdef MULTI_THREADED
2167  int root;
2168 #endif //end MULTI_THREADED
2169  // set sig handler
2170  struct sigaction old;
2171  sigaction(SIGSEGV, &GLOBAL_STATE.sigAct, &old);
2172 
2173  // Dont print if the depth is more than MAX_CCT_PRINT_DEPTH since files become too large
2174  while (IS_VALID_CONTEXT(curCtxtHndle) && (depth++ < MAX_CCT_PRINT_DEPTH)) {
2175  int threadCtx = 0;
2176 
2177  if ((threadCtx = IsARootIPNode(curCtxtHndle)) != NOT_ROOT_CTX) {
2178  // if the thread has a parent, recur over it.
2179  ContextHandle_t parentThreadCtxtHndl = CCTLibGetTLS(threadCtx)->tlsParentThreadCtxtHndl;
2180  Context ctxt = {"THREAD[" + std::to_string(threadCtx) + "]_ROOT_CTXT" /*functionName*/, "" /*filePath */, "" /*disassembly*/, curCtxtHndle /*ctxtHandle*/, 0 /*lineNo*/, 0 /*ip*/};
2181  contextVec.push_back(ctxt);
2182 
2183  if (parentThreadCtxtHndl)
2184  GetFullCallingContextInSitu(parentThreadCtxtHndl, contextVec);
2185 
2186  break;
2187  } else {
2188  ADDRINT ip = GetIPFromInfo(curCtxtHndle);
2189 
2190  if (IsValidIP(ip)) {
2191  if (PIN_UndecorateSymbolName(RTN_FindNameByAddress(ip), UNDECORATION_COMPLETE) == ".plt") {
2192  if (setjmp(GLOBAL_STATE.env) == 0) {
2193  if (IsValidPLTSignature(ip)) {
2194  uint64_t nextByte = (uint64_t)ip + 2;
2195  int* offset = (int*)nextByte;
2196  uint64_t nextInst = (uint64_t)ip + 6;
2197  ADDRINT loc = *((uint64_t*)(nextInst + *offset));
2198 
2199  if (IsValidIP(loc)) {
2200  string filePath;
2201  uint32_t lineNo;
2204  Context ctxt = {PIN_UndecorateSymbolName(RTN_FindNameByAddress(loc), UNDECORATION_COMPLETE) /*functionName*/, filePath /*filePath */, string(GLOBAL_STATE.disassemblyBuff) /*disassembly*/, curCtxtHndle /*ctxtHandle*/, lineNo /*lineNo*/, ip /*ip*/};
2205  contextVec.push_back(ctxt);
2206  } else {
2208  Context ctxt = {"IN PLT BUT NOT VALID GOT" /*functionName*/, "" /*filePath */, string(GLOBAL_STATE.disassemblyBuff) /*disassembly*/, curCtxtHndle /*ctxtHandle*/, 0 /*lineNo*/, ip /*ip*/};
2209  contextVec.push_back(ctxt);
2210  }
2211  } else {
2213  Context ctxt = {"UNRECOGNIZED PLT SIGNATURE" /*functionName*/, "" /*filePath */, string(GLOBAL_STATE.disassemblyBuff) /*disassembly*/, curCtxtHndle /*ctxtHandle*/, 0 /*lineNo*/, ip /*ip*/};
2214  contextVec.push_back(ctxt);
2215  //fprintf(GLOBAL_STATE.CCTLibLogFile,"\n plt plt plt %x", * ((UINT32*)curContext->address));
2216  //for(int i = 1; i < 4 ; i++)
2217  // fprintf(GLOBAL_STATE.CCTLibLogFile," %x", ((UINT32 *)curContext->address)[i]);
2218  }
2219  } else {
2220  Context ctxt = {"CRASHED !!" /*functionName*/, "" /*filePath */, "" /*disassembly*/, curCtxtHndle /*ctxtHandle*/, 0 /*lineNo*/, ip /*ip*/};
2221  contextVec.push_back(ctxt);
2222  }
2223  } else {
2224  string filePath;
2225  uint32_t lineNo;
2228 #if 0
2229  fprintf(GLOBAL_STATE.CCTLibLogFile, "\n%p:%s:%s:%s", (void*)ip, GLOBAL_STATE.disassemblyBuff, PIN_UndecorateSymbolName(RTN_FindNameByAddress(ip), UNDECORATION_COMPLETE).c_str(), li
2230  ne.c_str());
2231 #else
2232  // also print the IPNode handle so that I can debug deserialization
2233  Context ctxt = {PIN_UndecorateSymbolName(RTN_FindNameByAddress(ip), UNDECORATION_COMPLETE) /*functionName*/, filePath /*filePath */, string(GLOBAL_STATE.disassemblyBuff) /*disassembly*/, curCtxtHndle /*ctxtHandle*/, lineNo /*lineNo*/, ip /*ip*/};
2234  contextVec.push_back(ctxt);
2235 #endif
2236  }
2237  } else {
2238  Context ctxt = {"BAD IP !!" /*functionName*/, "" /*filePath */, "" /*disassembly*/, curCtxtHndle /*ctxtHandle*/, 0 /*lineNo*/, ip /*ip*/};
2239  contextVec.push_back(ctxt);
2240  }
2241 
2242  curCtxtHndle = GET_IPNODE_FROM_CONTEXT_HANDLE(curCtxtHndle)->parentTraceNode->callerCtxtHndl;
2243 
2244  if (depth >= MAX_CCT_PRINT_DEPTH) {
2245  Context ctxt = {"Truncated call path (due to deep call chain)" /*functionName*/, "" /*filePath */, "" /*disassembly*/, curCtxtHndle /*ctxtHandle*/, 0 /*lineNo*/, 0 /*ip*/};
2246  contextVec.push_back(ctxt);
2247  }
2248  }
2249  }
2250 
2251  //reset sig handler
2252  sigaction(SIGSEGV, &old, nullptr);
2253 }
2254 
2255 
2256 static VOID GetFullCallingContextPostmortem(ContextHandle_t curCtxtHndle, vector<Context>& contextVec) {
2257  int depth = 0;
2258 #ifdef MULTI_THREADED
2259  int root;
2260 #endif //end MULTI_THREADED
2261  // set sig handler
2262  struct sigaction old;
2263  sigaction(SIGSEGV, &GLOBAL_STATE.sigAct, &old);
2264 
2265  // Dont print if the depth is more than MAX_CCT_PRINT_DEPTH since files become too large
2266  while (IS_VALID_CONTEXT(curCtxtHndle) && (depth++ < MAX_CCT_PATH_DEPTH)) {
2267  int threadCtx = 0;
2268 
2269  if ((threadCtx = IsARootIPNode(curCtxtHndle)) != NOT_ROOT_CTX) {
2270  Context ctxt = {"THREAD[" + std::to_string(threadCtx) + "]_ROOT_CTXT" /*functionName*/, "" /*filePath */, "" /*disassembly*/, curCtxtHndle /*ctxtHandle*/, 0 /*lineNo*/, 0 /*ip*/};
2271  contextVec.push_back(ctxt);
2272  // if the thread has a parent, recurse over it.
2273  ContextHandle_t parentThreadCtxtHndl = GLOBAL_STATE.deserializedCCTs[threadCtx].tlsParentThreadCtxtHndl;
2274 
2275  if (parentThreadCtxtHndl)
2276  GetFullCallingContextPostmortem(parentThreadCtxtHndl, contextVec);
2277 
2278  break;
2279  } else {
2280  ADDRINT ip = GetIPFromInfo(curCtxtHndle);
2281  const string& modulePath = GetModulePathFromInfo(GET_IPNODE_FROM_CONTEXT_HANDLE(curCtxtHndle));
2282  std::stringstream command;
2283  command << "addr2line -C -f -e " << modulePath << " " << std::hex << ip;
2284  FILE* fp = popen(command.str().c_str(), "r");
2285  char functionName[MAX_FILE_PATH];
2286  char fileName[MAX_FILE_PATH];
2287  uint32_t lineNo;
2288 
2289  if (setjmp(GLOBAL_STATE.env) == 0) {
2290  if (fgets(functionName, MAX_FILE_PATH, fp) == nullptr) {
2291  strcpy(functionName, "FAILED_TO_READ");
2292  strcpy(fileName, "FAILED_TO_READ");
2293  lineNo = 0;
2294  } else {
2295  if (fgets(fileName, MAX_FILE_PATH, fp) == nullptr) {
2296  strcpy(fileName, "FAILED_TO_READ");
2297  lineNo = 0;
2298  } else {
2299  // Look for last ":"
2300  int len = strlen(fileName);
2301  int linePos;
2302 
2303  for (linePos = len - 1; linePos >= 0; linePos--) {
2304  if (fileName[linePos] == ':')
2305  break;
2306  }
2307 
2308  lineNo = atoi(&fileName[linePos + 1]);
2309  fileName[linePos] = '\0';
2310  }
2311  }
2312  } else {
2313  strcpy(functionName, "CRASHED!");
2314  strcpy(fileName, "CRASHED!");
2315  lineNo = 0;
2316  }
2317 
2318  pclose(fp);
2319  string fnName(functionName);
2320  CCTLibTrimInPlace(fnName);
2321  string flName(fileName);
2322  CCTLibTrimInPlace(flName);
2323  Context ctxt = {
2324  fnName /*functionName*/, flName /*filePath */, "TODO-Disassmebly" /*disassembly*/, curCtxtHndle /*ctx
2325 tHandle*/
2326  ,
2327  lineNo /*lineNo*/, ip /*ip*/
2328  };
2329  contextVec.push_back(ctxt);
2330  curCtxtHndle = GET_IPNODE_FROM_CONTEXT_HANDLE(curCtxtHndle)->parentTraceNode->callerCtxtHndl;
2331  }
2332  }
2333 
2334  //reset sig handler
2335  sigaction(SIGSEGV, &old, nullptr);
2336 }
2337 
2338 
2339 VOID GetFullCallingContext(ContextHandle_t curCtxtHndle, vector<Context>& contextVec) {
2341  GetFullCallingContextPostmortem(curCtxtHndle, contextVec);
2342  else
2343  GetFullCallingContextInSitu(curCtxtHndle, contextVec);
2344 }
2345 
2347  vector<Context> contextVec;
2348 
2351  else
2353 
2354  for (uint32_t i = 0; i < contextVec.size(); i++) {
2355  fprintf(GLOBAL_STATE.CCTLibLogFile, "\n%u:%p:%s:%s:%s:%u", contextVec[i].ctxtHandle, (void*)contextVec[i].ip, contextVec[i].disassembly.c_str(), contextVec[i].functionName.c_str(), contextVec[i].filePath.c_str(), contextVec[i].lineNo);
2356  }
2357 }
2358 
2359 void AppendLoadModulesToStream(iostream& ios) {
2360  unordered_map<UINT32, ModuleInfo>::iterator it;
2361  for (it = GLOBAL_STATE.ModuleInfoMap.begin(); it != GLOBAL_STATE.ModuleInfoMap.end(); ++it) {
2362  ios << "\n"
2363  << it->first << ":" << (void*)((it->second).imgLoadOffset) << ":" << (it->second).moduleName;
2364  }
2365 }
2367  int lm_id;
2368  ADDRINT offset;
2369 };
2370 
2371 static void GetNormalizedIpVectorClippedToMainOneAheadIp(vector<NormalizedIP>& ctxt, ContextHandle_t curCtxtHndle) {
2372  int depth = 0;
2373  // Dont print if the depth is more than MAX_CCT_PRINT_DEPTH since files become too large
2374  while (IS_VALID_CONTEXT(curCtxtHndle) && (depth++ < MAX_CCT_PRINT_DEPTH)) {
2375  int threadCtx = 0;
2376  if ((threadCtx = IsARootIPNode(curCtxtHndle)) != NOT_ROOT_CTX) {
2377  // if the thread has a parent, recur over it.
2378  ContextHandle_t parentThreadCtxtHndl = CCTLibGetTLS(threadCtx)->tlsParentThreadCtxtHndl;
2379  if (parentThreadCtxtHndl) {
2380  fprintf(stderr, "\n Multi threading not supported for this prototype feature. Exiting\n");
2381  PIN_ExitProcess(-1);
2382  }
2383  break;
2384  } else {
2385  TraceNode* traceNode = GET_IPNODE_FROM_CONTEXT_HANDLE(curCtxtHndle)->parentTraceNode;
2386  // what is my slot id ?
2387  uint32_t slotNo = curCtxtHndle - traceNode->childCtxtStartIdx;
2388 
2389  ADDRINT* ptr = (ADDRINT*)GLOBAL_STATE.traceShadowMap[traceNode->traceKey];
2390  UINT32 moduleId = ptr[-1]; // module id is stored one behind.
2391  ADDRINT ip = ptr[slotNo];
2393  NormalizedIP nip;
2394  nip.lm_id = moduleId;
2395  nip.offset = ip - GLOBAL_STATE.ModuleInfoMap[moduleId].imgLoadOffset;
2396  ctxt.push_back(nip);
2397 
2398  // if we are already in main, we are done
2399  RTN r = RTN_FindByAddress(ip);
2400  if (RTN_Invalid() != r && RTN_Name(r) == "main")
2401  return;
2402  }
2403  curCtxtHndle = GET_IPNODE_FROM_CONTEXT_HANDLE(curCtxtHndle)->parentTraceNode->callerCtxtHndl;
2404  }
2405 }
2406 
2407 void LogContexts(iostream& ios, ContextHandle_t ctxt1, ContextHandle_t ctxt2) {
2408  vector<NormalizedIP> c1;
2409  vector<NormalizedIP> c2;
2412  for (uint32_t i = 0; i < c1.size(); i++)
2413  ios << c1[i].lm_id << "-" << (void*)c1[i].offset << ",";
2414  ios << "SEP";
2415  for (uint32_t i = 0; i < c2.size(); i++)
2416  ios << "," << c2[i].lm_id << "-" << (void*)c2[i].offset;
2417 }
2418 
2419 // Initialize the needed data structures before launching the target program
2420 static void InitBuffers() {
2421  // prealloc IPNodeVec so that they all come from a continuous memory region.
2422  // IMPROVEME ... actually this can be as high as 24 GB since lower 3 bits are always zero for pointers
2423  GLOBAL_STATE.preAllocatedContextBuffer = (IPNode*)mmap(nullptr, MAX_IPNODES * sizeof(IPNode), PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
2424  // start from index 1 so that we can use 0 as empty key for the google hash table
2426  // Init the string pool
2427  GLOBAL_STATE.preAllocatedStringPool = (char*)mmap(nullptr, MAX_STRING_POOL_NODES * sizeof(char), PROT_WRITE | PROT_READ, MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
2428  // start from index 1 so that we can use 0 as a special value
2430 }
2431 
2432 
2433 #if 0
2434 // Initialize RW locks
2435  static void InitLocks() {
2436 // PIN_RWMutexInit(&gStaticVarRWLock);
2437 // PIN_RWMutexInit(&gMallocVarRWLock);
2438  }
2439 #endif
2440 
2441 static void InitLogFile(FILE* logFile) {
2442  GLOBAL_STATE.CCTLibLogFile = logFile;
2443 }
2444 
2445 static void InitMapFilePrefix() {
2446  char* envPath = getenv("OUTPUT_FILE");
2447 
2448  if (envPath) {
2449  // assumes max of MAX_FILE_PATH
2450  GLOBAL_STATE.CCTLibFilePathPrefix = string(envPath) + "-";
2451  }
2452 
2453  std::stringstream ss;
2454  char hostname[MAX_FILE_PATH];
2455  gethostname(hostname, MAX_FILE_PATH);
2456  pid_t pid = getpid();
2457  ss << hostname << "-" << pid;
2458  GLOBAL_STATE.CCTLibFilePathPrefix += ss.str();
2459 }
2460 
2461 
2462 static void InitSegHandler() {
2463  // Init the segv handler that may happen (due to PIN bug) when unwinding the stack during the printing
2464  memset(&GLOBAL_STATE.sigAct, 0, sizeof(struct sigaction));
2465  GLOBAL_STATE.sigAct.sa_handler = SegvHandler;
2466  GLOBAL_STATE.sigAct.sa_flags = SA_NODEFER;
2467 }
2468 
2469 static void InitXED() {
2470  // Init XED for decoding instructions
2471  xed_state_init(&GLOBAL_STATE.cct_xed_state, XED_MACHINE_MODE_LONG_64, (xed_address_width_enum_t)0, XED_ADDRESS_WIDTH_64b);
2472  // removed from Xed v.67254 xed_decode_init();
2473 }
2474 
2475 
2476 //DO_DATA_CENTRIC
2477 
2478 #ifdef USE_SHADOW_FOR_DATA_CENTRIC
2480 
2481 static void InitShadowSpaceForDataCentric(VOID* addr, uint32_t accessLen, DataHandle_t* initializer) {
2482  uint64_t endAddr = (uint64_t)addr + accessLen;
2483  uint32_t numInited = 0;
2484 
2485  for (uint64_t curAddr = (uint64_t)addr; curAddr < endAddr; curAddr += SHADOW_PAGE_SIZE) {
2486  DataHandle_t* status = GetOrCreateShadowAddress<0>(sm, (size_t)curAddr);
2487  int maxBytesInThisPage = SHADOW_PAGE_SIZE - PAGE_OFFSET((uint64_t)addr);
2488 
2489  for (int i = 0; (i < maxBytesInThisPage) && numInited < accessLen; numInited++, i++) {
2490  status[i] = *initializer;
2491  }
2492  }
2493 }
2494 
2495 DataHandle_t GetDataObjectHandle(VOID* addr, THREADID threadId) {
2496  DataHandle_t dataHandle;
2497  ThreadData* tData = CCTLibGetTLS(threadId);
2498 
2499  // if it is a stack location, set so and return
2500  if (addr > tData->tlsStackEnd && addr < tData->tlsStackBase) {
2501  dataHandle.objectType = STACK_OBJECT;
2502  return dataHandle;
2503  }
2504 
2505  dataHandle = *(GetOrCreateShadowAddress<0>(sm, (size_t)addr));
2506  return dataHandle;
2507 }
2508 
2509 #elif defined(USE_TREE_BASED_FOR_DATA_CENTRIC)
2510 DataHandle_t GetDataObjectHandle(VOID* addr, THREADID threadId) {
2511  DataHandle_t record;
2512  ThreadData* tData = CCTLibGetTLS(threadId);
2513 
2514  // if it is a stack location, set so and return
2515  if (addr > tData->tlsStackEnd && addr < tData->tlsStackBase) {
2516  record.objectType = STACK_OBJECT;
2517  return record;
2518  }
2519 
2520  // publish the most recent MallocVarSet that this thread sees. This allows the concurrent writer to make progress.
2521  // This is placed here so that we dont update this on each stack access. We favor reader progress.
2522  tData->tlsLatestConcurrentTree = (ConcurrentReaderWriterTree_t*)GLOBAL_STATE.latestConcurrentTree;
2523  varSet* curTree = &(tData->tlsLatestConcurrentTree->tree);
2524  tData->tlsMallocDSAccessStatus = START_READING;
2525  // first check dymanically allocated variables
2526  //ReadLock mallocRWlock(gMallocVarRWLock);
2527  // gMallocVarRWLock.lock_read();
2528  // ReadLock(&(tData->rwLockStatus));
2529  varSet::iterator node = curTree->lower_bound(varType(addr, addr, 0 /*handle*/, UNKNOWN_OBJECT));
2530 
2531  if (node != curTree->begin() && node->start != addr)
2532  node--;
2533 
2534  if (node != curTree->end() && (addr < node->start || addr >= node->end))
2535  node = curTree->end();
2536 
2537  if (node != curTree->end()) {
2538  record.objectType = node->objectType;
2539  record.pathHandle = node->pathHandle;
2540 // Milind - Commented this since thsi consumes too much space.
2541 // Need to discuss with Xu on how to maintain this efficiently.
2542 #ifdef USE_TREE_WITH_ADDR
2543  record.beg_addr = (uint64_t)node->start;
2544  record.end_addr = (uint64_t)node->end;
2545 #endif
2546  } else {
2547  record.objectType = UNKNOWN_OBJECT;
2548  }
2549 
2550  tData->tlsMallocDSAccessStatus = END_READING;
2551  return record;
2552 }
2553 
2554 
2555 #else
2556 DataHandle_t GetDataObjectHandle(VOID* addr, THREADID threadId) {
2557  assert(0 && "should never reach here");
2558 }
2559 
2560 #endif
2561 
2562 static VOID CaptureMallocSize(size_t arg0, THREADID threadId) {
2563  // Remember the CCT node and the allocation size
2564  ThreadData* tData = CCTLibGetTLS(threadId);
2565  tData->tlsDynamicMemoryAllocationSize = arg0;
2567 }
2568 
2569 static VOID CaptureCallocSize(size_t arg0, size_t arg1, THREADID threadId) {
2570  // Remember the CCT node and the allocation size
2571  ThreadData* tData = CCTLibGetTLS(threadId);
2572  tData->tlsDynamicMemoryAllocationSize = arg0 * arg1;
2574 }
2575 
2576 //Fwd declaration;
2577 static void CaptureFree(void* ptr, THREADID threadId);
2578 
2579 static VOID CaptureReallocSize(void* ptr, size_t arg1, THREADID threadId) {
2580  // Remember the CCT node and the allocation size
2581  ThreadData* tData = CCTLibGetTLS(threadId);
2582  tData->tlsDynamicMemoryAllocationSize = arg1;
2584 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
2585  // Simulate free(ptr);
2586  CaptureFree(ptr, threadId);
2587 #endif
2588 }
2589 
2590 
2591 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
2592 
2593 #if 0
2594  static void DUMP_STATUS(THREADID threadId, int stuckon, int calledFrom) {
2595  printf("\n STUCK! threadId = %d, stack waiting for %d, called from %s", threadId, stuckon, calledFrom == 0 ? "malloc" : "free");
2596 
2597  for(uint32_t i = 0; i < GLOBAL_STATE.numThreads; i++) {
2598  ThreadData* tData = CCTLibGetTLS(i);
2599  printf("\n Thread %d, tlsLatestMallocVarSet = %p, tlsMallocDSAccessStatus = %d", i, tData->tlsLatestMallocVarSet , tData->tlsMallocDSAccessStatus);
2600  }
2601 
2602  fflush(stdout);
2603  }
2604 
2605  static void WaitTillAllThreadsProgressIntoNewSet(varSet* latestVarSet, THREADID threadId, int calledFrom) {
2606  // TODO: if the thread exists in the mean time, it might not have seen the update. We need to ignore such threads.
2607  for(uint32_t i = 0; i < GLOBAL_STATE.numThreads; i++) {
2608  ThreadData* tData = CCTLibGetTLS(i);
2609  uint64_t j = 0;
2610 
2611  while((tData->tlsLatestMallocVarSet != latestVarSet) && (tData->tlsMallocDSAccessStatus == START_READING)) {
2612  // spin
2613  if(j++ == 0xffffff) {
2614  DUMP_STATUS(threadId, i, calledFrom);
2615  }
2616  }
2617  }
2618  }
2619 #else
2620 
2621 QNode* volatile MCSLock = nullptr;
2622 
2623 static void MCSAcquire(QNode* volatile* L, QNode* I) {
2624  I->next = nullptr;
2625  I->status = LOCKED;
2626  QNode* pred = (QNode*)__sync_lock_test_and_set((uint64_t*)L, (uint64_t)I);
2627 
2628  if (pred) {
2629  pred->next = I;
2630 
2631  while (I->status == LOCKED)
2632  ; // spin
2633  }
2634 }
2635 
2636 static void MCSRelease(QNode* volatile* L, QNode* I, uint8_t releaseVal) {
2637  if (I->next == nullptr) {
2638  if (__sync_bool_compare_and_swap((uint64_t*)L, (uint64_t)I, (uint64_t)NULL))
2639  return;
2640 
2641  while (I->next == nullptr)
2642  ; // spin
2643 
2644  // wait till some successor
2645  }
2646 
2647  I->next->status = releaseVal;
2648 }
2649 
2650 
2651 static void WaitTillAllThreadsProgressIntoNewSet(ConcurrentReaderWriterTree_t* latestTree) {
2652  // TODO: if the thread exists in the mean time, it might not have seen the update. We need to ignore such threads.
2653  for (uint32_t i = 0; i < GLOBAL_STATE.numThreads; i++) {
2654  ThreadData* tData = CCTLibGetTLS(i);
2655 
2656  while ((tData->tlsLatestConcurrentTree != latestTree) && (tData->tlsMallocDSAccessStatus == START_READING)) {
2657  // spin
2658  }
2659  }
2660 }
2661 
2662 static void ApplyPendingOperationsToTree(ConcurrentReaderWriterTree_t* threadFreeTree) {
2663  for (uint32_t i = 0; i < threadFreeTree->pendingOps.size(); i++) {
2664  switch (threadFreeTree->pendingOps[i].operation) {
2665  case INSERT: {
2666  //fprintf(stderr,"\n Inserting %1d %p - %p",threadFreeTree->pendingOps[i].var.objectType, threadFreeTree->pendingOps[i].var.start, threadFreeTree->pendingOps[i].var.end);
2667  threadFreeTree->tree.insert(threadFreeTree->pendingOps[i].var);
2668  break;
2669  }
2670 
2671  case DELETE: {
2672  //fprintf(stderr,"\n Deleting %1d %p\n", threadFreeTree->pendingOps[i].var.objectType, threadFreeTree->pendingOps[i].var.start);
2673  varSet::const_iterator iterThreadFreeTree = threadFreeTree->tree.lower_bound(threadFreeTree->pendingOps[i].var);
2674 
2675  //assert(iterThreadFreeTree != threadFreeTree->tree.end());
2676  //assert(threadFreeTree->pendingOps[i].var.start >= iterThreadFreeTree->start);
2677  //assert(threadFreeTree->pendingOps[i].var.start < iterThreadFreeTree->end);
2678  if (threadFreeTree->pendingOps[i].var.start == iterThreadFreeTree->start) {
2679  threadFreeTree->tree.erase(*iterThreadFreeTree);
2680  } else {
2681  fprintf(stderr, "\n Can't delete %1d %p\n", threadFreeTree->pendingOps[i].var.objectType, threadFreeTree->pendingOps[i].var.start);
2682  }
2683 
2684  break;
2685  }
2686 
2687  default:
2688  assert(0 && "Should not reach here");
2689  break;
2690  }
2691  }
2692 
2693  //clear list
2694  threadFreeTree->pendingOps.clear();
2695 }
2696 #endif
2697 
2698 
2699 static void UpdateLockLessTree(THREADID threadId, const vector<PendingOps_t>& ops) {
2700  static ThreadData dummyThreadData; // we use it when GLOBAL_STATE.applicationStarted is false
2701  ThreadData* tData;
2702 
2704  tData = &dummyThreadData;
2705  } else {
2706  tData = CCTLibGetTLS(threadId);
2707  }
2708 
2709  // tell that this thread is waiting to write
2710  tData->tlsMallocDSAccessStatus = WAITING_WRITE;
2711  QNode mcsNode;
2712  MCSAcquire(&MCSLock, &mcsNode);
2713  // Not waiting anymore
2714  tData->tlsMallocDSAccessStatus = WRITE_STARTED;
2715  ConcurrentReaderWriterTree_t* curTree = (ConcurrentReaderWriterTree_t*)GLOBAL_STATE.latestConcurrentTree;
2716  ConcurrentReaderWriterTree_t* newTree = (curTree == (&GLOBAL_STATE.concurrentReaderWriterTree[0])) ? (&GLOBAL_STATE.concurrentReaderWriterTree[1]) : (&GLOBAL_STATE.concurrentReaderWriterTree[0]);
2717  // Queue up "ops" to both trees
2718  curTree->pendingOps.insert(curTree->pendingOps.end(), ops.begin(), ops.end());
2719  newTree->pendingOps.insert(newTree->pendingOps.end(), ops.begin(), ops.end());
2720 #if 0
2721 
2722  // Write batching optimization is disabled since it can cause writer to not find its inserted item immediately if it becomes a reader.
2723  if(mcsNode.status != UNLOCKED_AND_PREDECESSOR_WAS_WRITER /* first writer*/) {
2724  // Wait for all threads to make progress into curTree
2725  WaitTillAllThreadsProgressIntoNewSet(curTree);
2726  }
2727 
2728 #else
2729  // Wait for all threads to make progress into curTree
2730  WaitTillAllThreadsProgressIntoNewSet(curTree);
2731 #endif
2732  // All threads will be in curTree, so we can modify newTree
2733  // Apply pending operations to newTree
2734  ApplyPendingOperationsToTree(newTree);
2735 #if 0
2736 
2737  // Write batching optimization is disabled since it can cause writer to not find its inserted item immediately if it becomes a reader.
2738  if(mcsNode.next == NULL /* last writer */) {
2739  // Publish newTree.
2740  GLOBAL_STATE.latestConcurrentTree = newTree;
2741  // set self tlsLatestMallocVarSet to be newTree
2742  tData->tlsLatestConcurrentTree = newTree;
2743  MCSRelease(&MCSLock, &mcsNode, UNLOCKED);
2744  } else {
2745  MCSRelease(&MCSLock, &mcsNode, UNLOCKED_AND_PREDECESSOR_WAS_WRITER);
2746  }
2747 
2748 #else
2749  // Publish newTree.
2750  GLOBAL_STATE.latestConcurrentTree = newTree;
2751  // set self tlsLatestMallocVarSet to be newTree
2752  tData->tlsLatestConcurrentTree = newTree;
2753  MCSRelease(&MCSLock, &mcsNode, UNLOCKED);
2754 #endif
2755 }
2756 
2757 
2758 #endif
2759 
2760 
2761 static VOID CaptureMallocPointer(void* ptr, THREADID threadId) {
2762  ThreadData* tData = CCTLibGetTLS(threadId);
2763 #ifdef USE_SHADOW_FOR_DATA_CENTRIC
2764  DataHandle_t dataHandle;
2765  dataHandle.objectType = DYNAMIC_OBJECT;
2766  dataHandle.pathHandle = tData->tlsDynamicMemoryAllocationPathHandle;
2768 #elif defined(USE_TREE_BASED_FOR_DATA_CENTRIC)
2769  varType v(ptr, (void*)((char*)ptr + (tData->tlsDynamicMemoryAllocationSize)), tData->tlsDynamicMemoryAllocationPathHandle, DYNAMIC_OBJECT);
2770  vector<PendingOps_t> ops(1, PendingOps_t(INSERT, v));
2771  UpdateLockLessTree(threadId, ops);
2772 #else
2773  assert(0 && "Should not reach here");
2774 #endif
2775 }
2776 
2777 static void CaptureFree(void* ptr, THREADID threadId) {
2778 #ifdef USE_SHADOW_FOR_DATA_CENTRIC
2779  //NOP
2780 #elif defined(USE_TREE_BASED_FOR_DATA_CENTRIC)
2781 
2782  if (ptr) {
2783  varType v(ptr, ptr, 0 /* handle */, DYNAMIC_OBJECT);
2784  vector<PendingOps_t> ops(1, PendingOps_t(DELETE, v));
2785  UpdateLockLessTree(threadId, ops);
2786  } // else NOP .. free() does nothing for NULL ptr
2787 
2788 #else
2789  assert(0 && "Should not reach here");
2790 #endif
2791 }
2792 
2793 
2794 // compute static variables
2795 // each image has a splay tree to include all static variables
2796 // that reside in the image. All images are linked as a link list
2797 
2798 static void compute_static_var(char* filename, IMG img) {
2799 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
2800  vector<PendingOps_t> ops;
2801  UINT32 imgId = IMG_Id(img);
2802 #endif
2803  //Elf32_Ehdr* elf_header; /* ELF header */
2804  Elf* elf; /* Our Elf pointer for libelf */
2805  Elf_Scn* scn = NULL; /* Section Descriptor */
2806  Elf_Data* edata = NULL; /* Data Descriptor */
2807  GElf_Sym sym; /* Symbol */
2808  GElf_Shdr shdr; /* Section Header */
2809  char* base_ptr; // ptr to our object in memory
2810  struct stat elf_stats; // fstat struct
2811  int i, symbol_count;
2812  int fd = open(filename, O_RDONLY);
2813 
2814  if ((fstat(fd, &elf_stats))) {
2815  printf("bss: could not fstat, so not monitor static variables\n");
2816  close(fd);
2817  return;
2818  }
2819 
2820  if ((base_ptr = (char*)malloc(elf_stats.st_size)) == nullptr) {
2821  printf("could not malloc\n");
2822  close(fd);
2823  PIN_ExitProcess(-1);
2824  }
2825 
2826  if ((read(fd, base_ptr, elf_stats.st_size)) < elf_stats.st_size) {
2827  printf("could not read\n");
2828  free(base_ptr);
2829  close(fd);
2830  PIN_ExitProcess(-1);
2831  }
2832 
2833  if (elf_version(EV_CURRENT) == EV_NONE) {
2834  printf("WARNING Elf Library is out of date!\n");
2835  }
2836 
2837  //elf_header = (Elf32_Ehdr*) base_ptr; // point elf_header at our object in memory
2838  elf = elf_begin(fd, ELF_C_READ, NULL); // Initialize 'elf' pointer to our file descriptor
2839 
2840  // Iterate each section until symtab section for object symbols
2841  while ((scn = elf_nextscn(elf, scn)) != NULL) {
2842  gelf_getshdr(scn, &shdr);
2843 
2844  if (shdr.sh_type == SHT_SYMTAB) {
2845  edata = elf_getdata(scn, edata);
2846  symbol_count = shdr.sh_size / shdr.sh_entsize;
2847 
2848  for (i = 0; i < symbol_count; i++) {
2849  if (gelf_getsym(edata, i, &sym) == NULL) {
2850  printf("gelf_getsym return NULL\n");
2851  printf("%s\n", elf_errmsg(elf_errno()));
2852  PIN_ExitProcess(-1);
2853  }
2854 
2855  if ((sym.st_size == 0) || (ELF32_ST_TYPE(sym.st_info) != STT_OBJECT)) { //not a variable
2856  continue;
2857  }
2858 
2859 #ifdef USE_SHADOW_FOR_DATA_CENTRIC
2860  DataHandle_t dataHandle;
2861  dataHandle.objectType = STATIC_OBJECT;
2862  char* symname = elf_strptr(elf, shdr.sh_link, sym.st_name);
2863  dataHandle.symName = symname ? GetNextStringPoolIndex(symname) : 0;
2864  InitShadowSpaceForDataCentric((void*)((IMG_LoadOffset(img)) + sym.st_value), (uint32_t)sym.st_size, &dataHandle);
2865 #elif defined(USE_TREE_BASED_FOR_DATA_CENTRIC)
2866  char* symname = elf_strptr(elf, shdr.sh_link, sym.st_name);
2867  uint32_t handle = symname ? GetNextStringPoolIndex(symname) : 0;
2868  varType vInsert((void*)((IMG_LoadOffset(img)) + sym.st_value), (void*)((IMG_LoadOffset(img)) + sym.st_value + sym.st_size), handle, STATIC_OBJECT);
2869  varType vDelete((void*)((IMG_LoadOffset(img)) + sym.st_value), (void*)((IMG_LoadOffset(img)) + sym.st_value), handle, STATIC_OBJECT);
2870  ops.push_back(PendingOps_t(INSERT, vInsert));
2871  // record for later deletion
2872  GLOBAL_STATE.staticVariablesInModule[imgId].push_back(PendingOps_t(INSERT, vDelete));
2873 #else
2874  assert(0 && "Should not reach here");
2875 #endif
2876  }
2877  }
2878  }
2879 
2880 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
2881  UpdateLockLessTree(PIN_ThreadId(), ops);
2882 #endif
2883 }
2884 
2885 static VOID
2886 DeleteStaticVar(IMG img, VOID* v) {
2887 #ifdef USE_SHADOW_FOR_DATA_CENTRIC
2888  //NOP
2889 #else
2890  UpdateLockLessTree(PIN_ThreadId(), GLOBAL_STATE.staticVariablesInModule[IMG_Id(img)]);
2891 #endif
2892 }
2893 
2894 static VOID ComputeVarBounds(IMG img, VOID* v) {
2895  char filename[PATH_MAX];
2896  char* result = realpath(IMG_Name(img).c_str(), filename);
2897 
2898  if (result == nullptr) {
2899  fprintf(stderr, "\n failed to resolve path");
2900  }
2901 
2903 }
2904 
2905 // end DO_DATA_CENTRIC #endif
2906 
2907 VOID CCTLibImage(IMG img, VOID* v) {
2908  // Find the pthread_create() function.
2909 #define PTHREAD_CREATE_RTN "pthread_create"
2910 #define ARCH_LONGJMP_RTN "__longjmp"
2911 #define SETJMP_RTN "_setjmp"
2912 //#define LONGJMP_RTN "longjmp"
2913 #define LONGJMP_RTN ARCH_LONGJMP_RTN
2914 #define SIGSETJMP_RTN "sigsetjmp"
2915 //#define SIGLONGJMP_RTN "siglongjmp"
2916 #define SIGLONGJMP_RTN ARCH_LONGJMP_RTN
2917 #define UNWIND_SETIP "_Unwind_SetIP"
2918 #define UNWIND_RAISEEXCEPTION "_Unwind_RaiseException"
2919 #define UNWIND_RESUME "_Unwind_Resume"
2920 #define UNWIND_FORCEUNWIND "_Unwind_ForcedUnwind"
2921 #define UNWIND_RESUME_OR_RETHROW "_Unwind_Resume_or_Rethrow"
2922  RTN pthread_createRtn = RTN_FindByName(img, PTHREAD_CREATE_RTN);
2923  RTN setjmpRtn = RTN_FindByName(img, SETJMP_RTN);
2924  RTN longjmpRtn = RTN_FindByName(img, LONGJMP_RTN);
2925  RTN sigsetjmpRtn = RTN_FindByName(img, SIGSETJMP_RTN);
2926  RTN siglongjmpRtn = RTN_FindByName(img, SIGLONGJMP_RTN);
2927  RTN archlongjmpRtn = RTN_FindByName(img, ARCH_LONGJMP_RTN);
2928  RTN unwindSetIpRtn = RTN_FindByName(img, UNWIND_SETIP);
2929  // _Unwind_RaiseException / _Unwind_Resume / _Unwind_ForcedUnwind
2930  // are no longer hooked -- their pre-existing "reset on last RET"
2931  // schemes were dead for caught exceptions (libgcc uses
2932  // __builtin_eh_return, which is not a RET). The new scheme reaches
2933  // every landing pad via the _Unwind_SetIP entry hook alone.
2934  //RTN unwindResumeOrRethrowRtn = RTN_FindByName(img, UNWIND_RESUME_OR_RETHROW);
2935 #if 0
2936  cout << "\n Image name" << IMG_Name(img);
2937 #endif
2938 
2939  if (RTN_Valid(pthread_createRtn)) {
2940  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n Found RTN %s",PTHREAD_CREATE_RTN);
2941  RTN_Open(pthread_createRtn);
2942  // Instrument malloc() to print the input argument value and the return value.
2943  RTN_InsertCall(pthread_createRtn, IPOINT_AFTER, (AFUNPTR)ThreadCreatePoint, IARG_THREAD_ID, IARG_END);
2944  RTN_Close(pthread_createRtn);
2945  }
2946 
2947 #if 0
2948 
2949  if(RTN_Valid(setjmpRtn)) {
2950  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n Found RTN %s",SETJMP_RTN);
2951  RTN_ReplaceSignature(setjmpRtn, AFUNPTR(SetJmpOverride), IARG_CONST_CONTEXT, IARG_THREAD_ID, IARG_ORIG_FUNCPTR, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_END);
2952  }
2953 
2954 #endif
2955 
2956  // Look for setjmp and longjmp routines present in libc.so.x file only
2957  if (strstr(IMG_Name(img).c_str(), "libc.so")) {
2958  if (RTN_Valid(setjmpRtn)) {
2959  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n Found RTN %s",SETJMP_RTN);
2960  RTN_Open(setjmpRtn);
2961  RTN_InsertCall(setjmpRtn, IPOINT_BEFORE, (AFUNPTR)CaptureSigSetJmpCtxt, IARG_CALL_ORDER, CALL_ORDER_LAST, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_THREAD_ID, IARG_END);
2962  RTN_Close(setjmpRtn);
2963  }
2964 
2965  if (RTN_Valid(longjmpRtn)) {
2966  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n Found RTN %s",LONGJMP_RTN);
2967  RTN_Open(longjmpRtn);
2968  RTN_InsertCall(longjmpRtn, IPOINT_BEFORE, (AFUNPTR)HoldLongJmpBuf, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_THREAD_ID, IARG_END);
2969  RTN_Close(longjmpRtn);
2970  }
2971 
2972  if (RTN_Valid(sigsetjmpRtn)) {
2973  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n Found RTN %s",SIGSETJMP_RTN);
2974  RTN_Open(sigsetjmpRtn);
2975  //CALL_ORDER_LAST so that cctlib's trace level instrumentation has updated the tlsCurrentCtxtHndl
2976  RTN_InsertCall(sigsetjmpRtn, IPOINT_BEFORE, (AFUNPTR)CaptureSigSetJmpCtxt, IARG_CALL_ORDER, CALL_ORDER_LAST, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_THREAD_ID, IARG_END);
2977  RTN_Close(sigsetjmpRtn);
2978  }
2979 
2980  if (RTN_Valid(siglongjmpRtn)) {
2981  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n Found RTN %s",SIGLONGJMP_RTN);
2982  RTN_Open(siglongjmpRtn);
2983  RTN_InsertCall(siglongjmpRtn, IPOINT_BEFORE, (AFUNPTR)HoldLongJmpBuf, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_THREAD_ID, IARG_END);
2984  RTN_Close(siglongjmpRtn);
2985  }
2986 
2987  if (RTN_Valid(archlongjmpRtn)) {
2988  //fprintf(GLOBAL_STATE.CCTLibLogFile, "\n Found RTN %s",ARCH_LONGJMP_RTN);
2989  RTN_Open(archlongjmpRtn);
2990  // Insert after the last JMP Inst.
2991  INS lastIns = RTN_InsTail(archlongjmpRtn);
2992  assert(INS_Valid(lastIns));
2993  assert(INS_IsBranch(lastIns));
2994  assert(!INS_IsDirectBranch(lastIns));
2995  INS_InsertCall(lastIns, IPOINT_TAKEN_BRANCH, (AFUNPTR)RestoreSigLongJmpCtxt, IARG_THREAD_ID, IARG_END);
2996  //RTN_InsertCall(siglongjmpRtn, IPOINT_BEFORE, (AFUNPTR)RestoreSigLongJmpCtxt, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_THREAD_ID, IARG_END);
2997  RTN_Close(archlongjmpRtn);
2998  }
2999  }
3000 
3001 //#if DISABLE_EXCEPTION_HANDLING
3002 #if 1
3003 
3004  // C++ exception (Itanium ABI) hookpoint: intercept `_Unwind_SetIP`
3005  // at entry. That's the ONLY function libgcc's driver uses to install
3006  // a resume IP (see ~/gcc/libgcc/unwind-dw2.c:368 — grep confirms it's
3007  // called nowhere in the driver itself, only from personality
3008  // routines). CaptureLandingPadTarget reads the pending resume IP,
3009  // walks cctlib's parent chain to identify the handler frame by
3010  // routine-address containment, and arms a pending re-anchor that
3011  // fires on the next Pin trace entry whose first IP matches. That
3012  // pairing is the reliable substitute for the pre-existing "reset on
3013  // _Unwind_RaiseException's last RET" scheme, which silently missed
3014  // every caught exception because libgcc uses __builtin_eh_return
3015  // (a non-RET epilogue) to jump to landing pads. Same hook covers
3016  // cleanup landing pads (dtor unwind) and handler landing pads
3017  // (catch clauses) uniformly, because personality functions call
3018  // _Unwind_SetIP for both.
3019  if (strstr(IMG_Name(img).c_str(), "libgcc_s.so")) {
3020  if (RTN_Valid(unwindSetIpRtn)) {
3021 #ifdef DEBUG_CCTLIB
3022  fprintf(GLOBAL_STATE.CCTLibLogFile, "\n %s found in %s", UNWIND_SETIP, IMG_Name(img).c_str());
3023 #endif
3024  RTN_Open(unwindSetIpRtn);
3025  RTN_InsertCall(unwindSetIpRtn, IPOINT_BEFORE, (AFUNPTR)CaptureLandingPadTarget, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_THREAD_ID, IARG_END);
3026  RTN_Close(unwindSetIpRtn);
3027  }
3028  // _Unwind_Resume, _Unwind_RaiseException, _Unwind_ForcedUnwind,
3029  // _Unwind_Resume_or_Rethrow: no hooks needed. The pre-existing
3030  // "reset on last RET" schemes on these routines were dead code
3031  // for caught exceptions (libgcc __builtin_eh_returns to the
3032  // landing pad without executing a real RET). All landing pads
3033  // -- cleanup and handler alike -- are covered by the
3034  // _Unwind_SetIP entry hook above.
3035  } // end strstr
3036 
3037 #endif
3038  //end DISABLE_EXCEPTION_HANDLING
3039 
3040  // For new DW2 exception handling, we need to reset the shadow stack to the current handler in the following functions:
3041  // 1. _Unwind_Reason_Code _Unwind_RaiseException ( struct _Unwind_Exception *exception_object );
3042  // 2. _Unwind_Reason_Code _Unwind_ForcedUnwind ( struct _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter );
3043  // 3. void _Unwind_Resume (struct _Unwind_Exception *exception_object); *** INSTALL UNCONDITIONALLY, SINCE THIS NEVER RETURNS ***
3044  // 4. _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) *** I AM NOT IMPLEMENTING THIS UNTILL I HIT A CODE THAT NEEDS IT ***
3045 
3046  // These functions call "uw_install_context" at the end of the routine just before returning, which overwrite the return address.
3047  // uw_install_context itself is a static function inlined or macroed. So we would rely on the more externally visible functions.
3048  // There are multiple returns in these (_Unwind_RaiseException, _Unwind_ForcedUnwind, _Unwind_Resume_or_Rethrow) functions. Only if the return value is "_URC_INSTALL_CONTEXT" shall we reset the shadow stack.
3049 
3050  // if data centric is enabled, capture allocation routines
3052  RTN mallocRtn = RTN_FindByName(img, MALLOC_FN_NAME);
3053 
3054  if (RTN_Valid(mallocRtn)) {
3055  RTN_Open(mallocRtn);
3056  // Capture the allocation size and CCT node
3057  RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)CaptureMallocSize, IARG_CALL_ORDER, CALL_ORDER_LAST, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_THREAD_ID, IARG_END);
3058  // capture the allocated pointer and initialize the memory with CCT node.
3059  RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)CaptureMallocPointer, IARG_FUNCRET_EXITPOINT_VALUE, IARG_THREAD_ID, IARG_END);
3060  RTN_Close(mallocRtn);
3061  }
3062 
3063  RTN callocRtn = RTN_FindByName(img, CALLOC_FN_NAME);
3064 
3065  if (RTN_Valid(callocRtn)) {
3066  RTN_Open(callocRtn);
3067  // Capture the allocation size and CCT node
3068  RTN_InsertCall(callocRtn, IPOINT_BEFORE, (AFUNPTR)CaptureCallocSize, IARG_CALL_ORDER, CALL_ORDER_LAST, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_THREAD_ID, IARG_END);
3069  // capture the allocated pointer and initialize the memory with CCT node.
3070  RTN_InsertCall(callocRtn, IPOINT_AFTER, (AFUNPTR)CaptureMallocPointer, IARG_FUNCRET_EXITPOINT_VALUE, IARG_THREAD_ID, IARG_END);
3071  RTN_Close(callocRtn);
3072  }
3073 
3074  RTN reallocRtn = RTN_FindByName(img, REALLOC_FN_NAME);
3075 
3076  if (RTN_Valid(reallocRtn)) {
3077  RTN_Open(reallocRtn);
3078  // Capture the allocation size and CCT node
3079  RTN_InsertCall(reallocRtn, IPOINT_BEFORE, (AFUNPTR)CaptureReallocSize, IARG_CALL_ORDER, CALL_ORDER_LAST, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_THREAD_ID, IARG_END);
3080  // capture the allocated pointer and initialize the memory with CCT node.
3081  RTN_InsertCall(reallocRtn, IPOINT_AFTER, (AFUNPTR)CaptureMallocPointer, IARG_FUNCRET_EXITPOINT_VALUE, IARG_THREAD_ID, IARG_END);
3082  RTN_Close(reallocRtn);
3083  }
3084 
3085  RTN freeRtn = RTN_FindByName(img, FREE_FN_NAME);
3086 
3087  if (RTN_Valid(freeRtn)) {
3088  RTN_Open(freeRtn);
3089  RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)CaptureFree, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_THREAD_ID, IARG_END);
3090  RTN_Close(freeRtn);
3091  }
3092  }
3093 
3094  // Get the first instruction of main
3095  if (GLOBAL_STATE.skip) {
3096  RTN mainRtn = RTN_FindByName(img, "main");
3097  if (!RTN_Valid(mainRtn)) {
3098  mainRtn = RTN_FindByName(img, "MAIN");
3099  if (!RTN_Valid(mainRtn)) {
3100  mainRtn = RTN_FindByName(img, "MAIN_");
3101  }
3102  }
3103  if (RTN_Valid(mainRtn)) {
3104  GLOBAL_STATE.mainIP = RTN_Address(mainRtn);
3105  }
3106  }
3107 }
3108 
3109 
3110 //DO_DATA_CENTRIC
3111 static void InitDataCentric() {
3112  // For shadow memory based approach initialize the L1 page table LEVEL_1_PAGE_TABLE_SIZE
3113  GLOBAL_STATE.doDataCentric = true;
3114 #ifdef USE_SHADOW_FOR_DATA_CENTRIC
3115 #endif // end USE_SHADOW_FOR_DATA_CENTRIC
3116  // This will perform hpc_var_bounds functionality on each image load
3117  IMG_AddInstrumentFunction(ComputeVarBounds, nullptr);
3118  // delete image from the list at the unloading callback
3119  IMG_AddUnloadFunction(DeleteStaticVar, nullptr);
3120 #ifdef USE_TREE_BASED_FOR_DATA_CENTRIC
3121  // make gLatestMallocVarSet point to one of mallocVarSets.
3122  GLOBAL_STATE.latestConcurrentTree = &(GLOBAL_STATE.concurrentReaderWriterTree[0]);
3123 #endif
3124 }
3125 
3128 }
3129 
3130 // Main for DeadSpy, initialize the tool, register instrumentation functions and call the target program.
3131 
3132 int PinCCTLibInit(IsInterestingInsFptr isInterestingIns, FILE* logFile, CCTLibInstrumentInsCallback userCallback, VOID* userCallbackArg, BOOL doDataCentric) {
3134  fprintf(stderr, "\n CCTLib was initialized for postmortem analysis using PinCCTLibInitForPostmortemAnalysis! Exiting...\n");
3135  PIN_ExitApplication(-1);
3136  }
3137 
3139  // Initialize Symbols, we need them to report functions and lines
3140  PIN_InitSymbols();
3141  // Guard rtnSelfRecMap against concurrent JIT (Pin JITs traces on
3142  // any thread). Init before TRACE_AddInstrumentFunction below.
3143  PIN_RWMutexInit(&GLOBAL_STATE.rtnSelfRecRWMutex);
3144  // Intialize
3145  InitBuffers();
3146  InitLogFile(logFile);
3148  InitSegHandler();
3149  InitXED();
3150  //InitLocks();
3151  // Obtain a key for TLS storage.
3152  GLOBAL_STATE.CCTLibTlsKey = PIN_CreateThreadDataKey(nullptr /*TODO have a destructor*/);
3153  // remember user instrumentation callback
3155  GLOBAL_STATE.userInstrumentationCallbackArg = userCallbackArg;
3156  // Register ThreadStart to be called when a thread starts.
3157  PIN_AddThreadStartFunction(CCTLibThreadStart, nullptr);
3158  // Register for context change in case of signals .. Actually this is never used. // Todo: - fix me
3159  PIN_AddContextChangeFunction(OnSig, nullptr);
3160  // Initialize ModuleInfoMap
3161  //ModuleInfoMap.set_empty_key(UINT_MAX);
3162  // Record Module information on each Image load.
3163  IMG_AddInstrumentFunction(CCTLibInstrumentImageLoad, nullptr);
3164 
3165  if (doDataCentric) {
3166  InitDataCentric();
3167  }
3168 
3169  // Since some functions may not be known, instrument every "trace"
3170  TRACE_AddInstrumentFunction(CCTLibInstrumentTrace, (void*)isInterestingIns);
3171  // Register Image to be called to instrument functions.
3172  IMG_AddInstrumentFunction(CCTLibImage, nullptr);
3173  // Add a function to report entire stats at the termination.
3174  PIN_AddFiniFunction(CCTLibFini, nullptr);
3175  // Register Fini to be called when the application exits
3176  PIN_AddFiniFunction(Fini, nullptr);
3177  // We need to know if the applicated has started
3178  PIN_AddApplicationStartFunction(CCTLibAppStartNotification, nullptr);
3179  return 0;
3180 }
3181 
3182 
3183 int PinCCTLibInitForPostmortemAnalysis(FILE* logFile, const string& serializedFilesDirectory) {
3185  fprintf(stderr, "\n CCTLib was initialized for online collection using PinCCTLibInit! Exiting...\n");
3186  PIN_ExitApplication(-1);
3187  }
3188 
3190  // Initialize Symbols, we need them to report functions and lines
3191  PIN_InitSymbols();
3192  // Intialize
3193  InitBuffers();
3194  InitLogFile(logFile);
3196  InitSegHandler();
3197  InitXED();
3198  //InitLocks();
3199  // Obtain a key for TLS storage.
3200  GLOBAL_STATE.CCTLibTlsKey = PIN_CreateThreadDataKey(nullptr /*TODO have a destructor*/);
3201  DeserializeMetadata(serializedFilesDirectory);
3202  return 0;
3203 }
3204 
3205 #ifdef HAVE_METRIC_PER_IPNODE
3206 static void BottomUpTraverse(TraceNode* node, void (*opFunc)(const THREADID threadid, ContextHandle_t myHandle, ContextHandle_t parentHandle, void** myMetric, void** parentMetric), const THREADID threadid);
3207 
3208 static void BottomUpTraverseHelper(TraceSplay* node, void (*opFunc)(const THREADID threadid, ContextHandle_t myHandle, ContextHandle_t parentHandle, void** myMetric, void** parentMetric), const THREADID threadid) {
3209  if (!node)
3210  return;
3211 
3212  BottomUpTraverseHelper(node->left, opFunc, threadid);
3213  BottomUpTraverse(node->value, opFunc, threadid);
3214  BottomUpTraverseHelper(node->right, opFunc, threadid);
3215 }
3216 static void BottomUpTraverse(TraceNode* node, void (*opFunc)(const THREADID threadid, ContextHandle_t myHandle, ContextHandle_t parentHandle, void** myMetric, void** parentMetric), const THREADID threadid) {
3217  if (!node) {
3218  return;
3219  }
3220  for (uint32_t i = 0; i < node->nSlots; i++) {
3221  if (GET_IPNODE_FROM_CONTEXT_HANDLE(node->childCtxtStartIdx + i)->calleeTraceNodes) {
3222  // Iterate over all decendent TraceNode of traceNode->childCtxtStartIdx[i]
3223  BottomUpTraverseHelper(GET_IPNODE_FROM_CONTEXT_HANDLE(node->childCtxtStartIdx + i)->calleeTraceNodes, opFunc, threadid);
3224  }
3225  // do anything here
3226  assert(node->callerCtxtHndl);
3227  if (node->callerCtxtHndl) {
3228  ContextHandle_t myHandle = node->childCtxtStartIdx + i;
3229  ContextHandle_t parentHandle = node->callerCtxtHndl;
3230  opFunc(threadid, myHandle, parentHandle, &(GET_IPNODE_FROM_CONTEXT_HANDLE(node->childCtxtStartIdx + i)->metric), &(GET_IPNODE_FROM_CONTEXT_HANDLE(node->callerCtxtHndl)->metric));
3231  }
3232  }
3233 }
3234 
3235 void TraverseCCTBottomUp(const THREADID threadid, void (*opFunc)(const THREADID threadid, ContextHandle_t myHandle, ContextHandle_t parentHandle, void** myMetric, void** parentMetric)) {
3236  ThreadData* tData = CCTLibGetTLS(threadid);
3237  BottomUpTraverse(tData->tlsRootTraceNode, opFunc, threadid);
3238 }
3239 #endif
3240 
3242  if (ctxt1 == ctxt2)
3243  return true;
3244  ContextHandle_t t1 = GET_IPNODE_FROM_CONTEXT_HANDLE(ctxt1)->parentTraceNode->callerCtxtHndl;
3245  ContextHandle_t t2 = GET_IPNODE_FROM_CONTEXT_HANDLE(ctxt2)->parentTraceNode->callerCtxtHndl;
3246  return t1 == t2;
3247 }
3248 
3250  if (!ctxtHandle)
3251  return 0;
3252  return GET_IPNODE_FROM_CONTEXT_HANDLE(ctxtHandle)->parentTraceNode->childCtxtStartIdx;
3253 }
3254 
3256  if (ctxt1 == ctxt2)
3257  return true;
3258 
3259  ADDRINT ip1 = GetIPFromInfo(ctxt1);
3260  ADDRINT ip2 = GetIPFromInfo(ctxt2);
3261 
3262  if (ip1 == ip2)
3263  return true;
3264 
3265  uint32_t lineNo1, lineNo2;
3266  string filePath1, filePath2;
3267 
3268  PIN_GetSourceLocation(ip1, NULL, (INT32*)&lineNo1, &filePath1);
3269  PIN_GetSourceLocation(ip2, NULL, (INT32*)&lineNo2, &filePath2);
3270 
3271  return static_cast<bool>(filePath1 == filePath2 && lineNo1 == lineNo2);
3272 }
3273 
3274 /* ==================================hpcviewer support===================================*/
3275 /*
3276  * This support is added by Xiaonan Hu and tailored by Xu Liu at College of William and Mary.
3277  */
3278 
3279 // necessary macros
3280 #define HASH_PRIME 2001001003
3281 #define HASH_GEN 4001
3282 #define SPINLOCK_UNLOCKED_VALUE (0L)
3283 #define SPINLOCK_LOCKED_VALUE (1L)
3284 #define OSUtil_hostid_NULL (-1)
3285 #define INITIALIZE_SPINLOCK(x) \
3286  { .thelock = (x) }
3287 #define SPINLOCK_UNLOCKED INITIALIZE_SPINLOCK(SPINLOCK_UNLOCKED_VALUE)
3288 #define SPINLOCK_LOCKED INITIALIZE_SPINLOCK(SPINLOCK_LOCKED_VALUE)
3289 
3290 #define HPCRUN_FMT_NV_prog "program-name"
3291 #define HPCRUN_FMT_NV_progPath "program-path"
3292 #define HPCRUN_FMT_NV_envPath "env-path"
3293 #define HPCRUN_FMT_NV_jobId "job-id"
3294 #define HPCRUN_FMT_NV_mpiRank "mpi-id"
3295 #define HPCRUN_FMT_NV_tid "thread-id"
3296 #define HPCRUN_FMT_NV_hostid "host-id"
3297 #define HPCRUN_FMT_NV_pid "process-id"
3298 #define HPCRUN_SAMPLE_PROB "HPCRUN_PROCESS_FRACTION"
3299 #define HPCRUN_FMT_NV_traceMinTime "trace-min-time"
3300 #define HPCRUN_FMT_NV_traceMaxTime "trace-max-time"
3301 
3302 #define FILENAME_TEMPLATE "%s/%s-%06u-%03d-%08lx-%u-%d.%s"
3303 #define TEMPORARY "%s/%s-"
3304 #define RANK 0
3305 
3306 #define FILES_RANDOM_GEN 4
3307 #define FILES_MAX_GEN 11
3308 #define FILES_EARLY 0x1
3309 #define FILES_LATE 0x2
3310 #define DEFAULT_PROB 0.1
3311 
3312 // *** atomic-op-asm.h && atomic-op-gcc.h ***
3313 #if defined(LL_BODY) && defined(SC_BODY)
3314 
3315 #define read_modify_write(type, addr, expn, result) \
3316  { \
3317  type __new; \
3318  do { \
3319  result = (type)load_linked((unsigned long*)addr); \
3320  __new = expn; \
3321  } while (!store_conditional((unsigned long*)addr, (unsigned long)__new)); \
3322  }
3323 #else
3324 
3325 #define read_modify_write(type, addr, expn, result) \
3326  { \
3327  type __new; \
3328  do { \
3329  result = *addr; \
3330  __new = expn; \
3331  } while (compare_and_swap(addr, result, __new) != result); \
3332  }
3333 #endif
3334 
3335 #define compare_and_swap(addr, oldval, newval) \
3336  __sync_val_compare_and_swap(addr, oldval, newval)
3337 
3338 // ***********************
3339 
3340 // create a new node type to substitute IPNode and TraceNode
3341 struct NewIPNode {
3342  vector<NewIPNode*> childIPNodes;
3343  // TODO(preexisting-perf): findSameIP scans childIPNodes linearly on every
3344  // insertion, making tranverseIPs / mergeIP total cost O(N^2) in
3345  // per-parent child count. For workloads whose CCT has many unique
3346  // callee IPs under one caller (e.g. reuseApp's JIT'd NOP sleds) this
3347  // makes newCCT_hpcrun_write functionally non-terminating. Fix by
3348  // mirroring inserts into an unordered_map<ADDRINT, NewIPNode*> for
3349  // O(1) findSameIP. Not required for `make check`.
3351  ADDRINT IPAddress;
3352  int32_t parentID;
3353  int32_t ID;
3355  void* metric;
3356  uint64_t* metricVal;
3357 };
3358 
3359 using size_t = uint16_t;
3360 
3361 
3362 using MetricFlags_Ty_t = enum {
3363  MetricFlags_Ty_NULL = 0,
3364  MetricFlags_Ty_Raw,
3365  MetricFlags_Ty_Final,
3366  MetricFlags_Ty_Derived
3367 };
3368 
3369 
3370 using MetricFlags_ValTy_t = enum {
3371  MetricFlags_ValTy_NULL = 0,
3372  MetricFlags_ValTy_Incl,
3373  MetricFlags_ValTy_Excl
3374 };
3375 
3376 
3377 using MetricFlags_ValFmt_t = enum {
3378  MetricFlags_ValFmt_NULL = 0,
3379  MetricFlags_ValFmt_Int,
3380  MetricFlags_ValFmt_Real,
3381 };
3382 
3383 
3385  bool isLogicalUnwind : 1;
3386  uint64_t unused : 63;
3387 };
3388 
3389 
3391  epoch_flags_bitfield fields;
3392  uint64_t bits; // for reading/writing
3393 };
3394 
3395 
3397  unsigned time : 1;
3398  unsigned cycles : 1;
3399 };
3400 
3401 
3403  MetricFlags_Ty_t ty : 8;
3406  uint8_t unused0;
3407  uint16_t partner;
3408  uint8_t /*bool*/ show;
3409  uint8_t /*bool*/ showPercent;
3410  uint64_t unused1;
3411 };
3412 
3413 
3416  uint8_t bits[2 * 8]; // for reading/writing
3417  uint64_t bits_big[2]; // for easy initialization
3418 };
3419 
3421  char* name;
3423  //uint8_t bits[2 * 8];
3424  //uint64_t bits_big[2];
3426  uint64_t period;
3428  char* formula;
3429  char* format;
3431 };
3432 
3433 
3435 
3436 
3437 using spinlock_t = struct spinlock_s {
3438  volatile long thelock;
3439 };
3440 
3441 
3442 struct fileid {
3443  int done;
3444  long host;
3445  int gen;
3446 };
3447 
3448 
3449 extern const metric_desc_t metricDesc_NULL;
3450 
3452  nullptr, // name
3453  nullptr, // description
3454  MetricFlags_Ty_NULL,
3455  MetricFlags_ValTy_NULL,
3456  MetricFlags_ValFmt_NULL,
3457  0, // fields.unused0
3458  0, // fields.partner
3459  (uint8_t) true, // fields.show
3460  (uint8_t) true, // fields.showPercent
3461  0, // unused 1
3462  0, // period
3463  0, // properties.time
3464  0, // properties.cycles
3465  nullptr,
3466  nullptr,
3467 };
3468 
3469 
3471 
3473  MetricFlags_Ty_NULL,
3474  MetricFlags_ValTy_NULL,
3475  MetricFlags_ValFmt_NULL,
3476  0, // fields.unused0
3477  0, // fields.partner
3478  (uint8_t) true, // fields.show
3479  (uint8_t) true, // fields.showPercent
3480  0, // unused 1
3481 };
3482 
3483 
3485  .bits = 0x0000000000000000};
3486 
3487 static const uint64_t default_measurement_granularity = 1;
3488 static const uint32_t default_ra_to_callsite_distance = 1;
3489 
3490 // ***************** file ************************
3492 static pid_t mypid = 0;
3493 static struct fileid earlyid;
3494 static struct fileid lateid;
3495 static int log_done = 0;
3496 static int log_rename_done = 0;
3497 static int log_rename_ret = 0;
3498 // ***********************************************
3499 /* for HPCViewer output format */
3500 std::string dirName;
3501 std::string* filename;
3502 
3503 // *************************************** format ****************************************
3504 static const char HPCRUN_FMT_Magic[] = "HPCRUN-profile____";
3505 static const int HPCRUN_FMT_MagicLen = (sizeof(HPCRUN_FMT_Magic) - 1);
3506 static const char HPCRUN_FMT_Endian[] = "b";
3507 static const int HPCRUN_FMT_EndianLen = (sizeof(HPCRUN_FMT_Endian) - 1);
3508 static const char HPCRUN_ProfileFnmSfx[] = "hpcrun";
3509 static const char HPCRUN_FMT_Version[] = "02.00";
3510 static const char HPCRUN_FMT_VersionLen = (sizeof(HPCRUN_FMT_Version) - 1);
3511 static const char HPCRUN_FMT_EpochTag[] = "EPOCH___";
3512 static const int HPCRUN_FMT_EpochTagLen = (sizeof(HPCRUN_FMT_EpochTag) - 1);
3513 const uint bufSZ = 32; // sufficient to hold a 64-bit integer in base 10
3514 int hpcfmt_str_fwrite(const char* str, FILE* outfs);
3515 int hpcrun_fmt_hdrwrite(FILE* fs);
3516 int hpcrun_fmt_hdr_fwrite(FILE* fs, const char* arg1, const char* arg2);
3517 int hpcrun_open_profile_file(int thread, const char* fileName);
3518 static int hpcrun_open_file(int thread, const char* suffix, int flags, const char* fileName);
3519 extern int fputs(const char* __restrict __s, FILE* __restrict __stream);
3520 int hpcrun_fmt_loadmap_fwrite(FILE* fs, const std::string& filename);
3522  uint64_t measurementGranularity, uint32_t raToCallsiteOfst);
3523 static void hpcrun_files_init();
3524 uint OSUtil_pid();
3525 const char* OSUtil_jobid();
3526 long OSUtil_hostid();
3527 void hpcrun_set_metric_info_w_fn(int metric_id, const char* name,
3528  MetricFlags_ValFmt_t valFmt, size_t period, FILE* fs);
3529 size_t hpcio_be2_fwrite(const uint16_t* val, FILE* fs);
3530 size_t hpcio_be4_fwrite(const uint32_t* val, FILE* fs);
3531 size_t hpcio_be8_fwrite(const uint64_t* val, FILE* fs);
3532 size_t hpcio_beX_fwrite(uint8_t* val, size_t size, FILE* fs);
3533 //string GetFileName(std::string & pathname);
3534 // ******************************************************************************************
3535 
3536 // ****************Merge splay trees **************************************************
3537 NewIPNode* constructIPNode(NewIPNode* parentIP, IPNode* oldIPNode, uint32_t parentID, uint64_t* nodeCount);
3538 void tranverseIPs(NewIPNode* curIPNode, TraceSplay* childCtxtStartIdx, uint64_t* nodeCount);
3539 NewIPNode* findSameIP(vector<NewIPNode*> nodes, IPNode* node);
3540 void mergeIP(NewIPNode* prev, IPNode* cur, uint64_t* nodeCount);
3541 uint32_t GetID();
3542 // ************************************************************************************
3543 
3544 // ****************Print merged splay tree*********************************************
3545 void IPNode_fwrite(NewIPNode* node, FILE* fs);
3546 void tranverseNewCCT(vector<NewIPNode*> nodes, FILE* fs);
3547 // ************************************************************************************
3548 
3549 uint OSUtil_pid() {
3550  pid_t pid = getpid();
3551  return (uint)pid;
3552 }
3553 
3554 
3555 const char* OSUtil_jobid() {
3556  char* jid = nullptr;
3557 
3558  // Cobalt
3559  jid = getenv("COBALT_JOB_ID");
3560  if (jid)
3561  return jid;
3562 
3563  // PBS
3564  jid = getenv("PBS_JOB_ID");
3565  if (jid)
3566  return jid;
3567 
3568  // SLURM
3569  jid = getenv("SLURM_JOB_ID");
3570  if (jid)
3571  return jid;
3572 
3573  // Sun Grid Engine
3574  jid = getenv("JOB_ID");
3575  if (jid)
3576  return jid;
3577 
3578  return jid;
3579 }
3580 
3581 
3583  static long hostid = OSUtil_hostid_NULL;
3584 
3585  if (hostid == OSUtil_hostid_NULL) {
3586  // gethostid returns a 32-bit id. treat it as unsigned to prevent useless sign extension
3587  hostid = (uint32_t)gethostid();
3588  }
3589 
3590  return hostid;
3591 }
3592 
3593 static inline int
3594 hpcfmt_int2_fwrite(uint16_t val, FILE* outfs) {
3595  if (sizeof(uint16_t) != hpcio_be2_fwrite(&val, outfs)) {
3596  return 0;
3597  }
3598  return 1;
3599 }
3600 
3601 
3602 static inline int
3603 hpcfmt_int4_fwrite(uint32_t val, FILE* outfs) {
3604  if (sizeof(uint32_t) != hpcio_be4_fwrite(&val, outfs)) {
3605  return 0;
3606  }
3607  return 1;
3608 }
3609 
3610 
3611 static inline int
3612 hpcfmt_int8_fwrite(uint64_t val, FILE* outfs) {
3613  if (sizeof(uint64_t) != hpcio_be8_fwrite(&val, outfs)) {
3614  return 0;
3615  }
3616  return 1;
3617 }
3618 
3619 
3620 static inline int
3621 hpcfmt_intX_fwrite(uint8_t* val, size_t size, FILE* outfs) {
3622  if (size != hpcio_beX_fwrite(val, size, outfs)) {
3623  return 0;
3624  }
3625  return 1;
3626 }
3627 
3628 
3629 int hpcio_fclose(FILE* fs) {
3630  if (fs && fclose(fs) == EOF) {
3631  return 1;
3632  }
3633  return 0;
3634 }
3635 
3636 static void hpcrun_files_init() {
3637  pid_t cur_pid = getpid();
3638 
3639  if (mypid != cur_pid) {
3640  mypid = cur_pid;
3641  earlyid.done = 0;
3643  earlyid.gen = 0;
3644  lateid = earlyid;
3645  log_done = 0;
3646  log_rename_done = 0;
3647  log_rename_ret = 0;
3648  }
3649 }
3650 
3651 
3652 // Replace "id" with the next unique id if possible. Normally, (hostid, pid, gen)
3653 // works after one or two iteration. To be extra robust (eg, hostid is not unique),
3654 // at some point, give up and pick a random hostid.
3655 // Returns: 0 on success, else -1 on failure.
3656 static int hpcrun_files_next_id(struct fileid* id) {
3657  struct timeval tv;
3658  int fd;
3659 
3660  if (id->done || id->gen >= FILES_MAX_GEN) {
3661  // failure, out of options
3662  return -1;
3663  }
3664 
3665  id->gen++;
3666  if (id->gen >= FILES_RANDOM_GEN) {
3667  // give up and use a random host id
3668  fd = open("/dev/urandom", O_RDONLY);
3669  printf("Inside hpcrun_files_next_id fd = %d\n", fd);
3670  if (fd >= 0) {
3671  read(fd, &id->host, sizeof(id->host));
3672  close(fd);
3673  }
3674  gettimeofday(&tv, nullptr);
3675  id->host += (tv.tv_sec << 20) + tv.tv_usec;
3676  id->host &= 0x00ffffffff;
3677  }
3678  return 0;
3679 }
3680 
3681 static int hpcrun_open_file(int thread, const char* suffix, int flags, const char* fileName) {
3682  char name[PATH_MAX];
3683  struct fileid* id;
3684  int fd, ret;
3685 
3686  id = (flags & FILES_EARLY) ? &earlyid : &lateid;
3687 
3688  for (;;) {
3689  errno = 0;
3690  ret = snprintf(name, PATH_MAX, FILENAME_TEMPLATE, dirName.c_str(), fileName, RANK, thread, id->host, mypid, id->gen, suffix);
3691 
3692  if (ret >= PATH_MAX) {
3693  fd = -1;
3694  errno = ENAMETOOLONG;
3695  break;
3696  }
3697 
3698  fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0644);
3699 
3700  if (fd >= 0) {
3701  // sucess
3702  break;
3703  }
3704 
3705  if (errno != EEXIST || hpcrun_files_next_id(id) != 0) {
3706  // failure, out of options
3707  fd = -1;
3708  break;
3709  }
3710  }
3711 
3712  id->done = 1;
3713 
3714  if (flags & FILES_EARLY) {
3715  // late id starts where early id is chosen
3716  lateid = earlyid;
3717  lateid.done = 0;
3718  }
3719 
3720  if (fd < 0) {
3721  printf("cctlib_hpcrun: unable to open %s file: '%s': %s", suffix, name, strerror(errno));
3722  }
3723 
3724  return fd;
3725 }
3726 
3727 static int unsigned long fetch_and_store(volatile long* addr, long newval) {
3728  long result;
3729  read_modify_write(long, addr, newval, result);
3730  return result;
3731 }
3732 
3733 
3734 static inline void spinlock_unlock(spinlock_t* l) {
3735  l->thelock = SPINLOCK_UNLOCKED_VALUE;
3736 }
3737 
3738 
3739 static inline void spinlock_lock(spinlock_t* l) {
3740  /* test-and-test-and-set lock*/
3741  for (;;) {
3742  while (l->thelock != SPINLOCK_UNLOCKED_VALUE)
3743  ;
3744 
3746  break;
3747  }
3748  }
3749 }
3750 
3751 
3752 // Write out the format for metric table. Needs updates
3753 void hpcrun_set_metric_info_w_fn(int metric_id, const char* name, size_t period, FILE* fs) {
3754  // Write out the number of metric table in the program
3756  mdesc.flags = hpcrun_metricFlags_NULL;
3757 
3758  for (int i = 0; i < 16; i++) {
3759  mdesc.flags.bits[i] = (uint8_t)0x00;
3760  }
3761 
3762  mdesc.name = (char*)name;
3763  mdesc.description = (char*)name; // TODO
3764  mdesc.period = period;
3765  mdesc.flags.fields.ty = MetricFlags_Ty_Raw;
3767  mdesc.flags.fields.valFmt = valFmt;
3768  mdesc.flags.fields.show = true;
3769  mdesc.flags.fields.showPercent = true;
3770  mdesc.formula = nullptr;
3771  mdesc.format = nullptr;
3772  mdesc.is_frequency_metric = false;
3773 
3774  hpcfmt_str_fwrite(mdesc.name, fs);
3775  hpcfmt_str_fwrite(mdesc.description, fs);
3776  hpcfmt_intX_fwrite(mdesc.flags.bits, sizeof(mdesc.flags), fs); // Write metric flags bits for reading/writing
3777  hpcfmt_int8_fwrite(mdesc.period, fs);
3778  hpcfmt_str_fwrite(mdesc.formula, fs);
3779  hpcfmt_str_fwrite(mdesc.format, fs);
3780  hpcfmt_int2_fwrite(mdesc.is_frequency_metric, fs);
3781 
3782  // write auxaliary description to the table.
3783  // These values are only related to perf, not applicable to cctlib, so set all to 0
3784  hpcfmt_int2_fwrite(0, fs);
3785  hpcfmt_int8_fwrite(0, fs);
3786  hpcfmt_int8_fwrite(0, fs);
3787 }
3788 
3789 // Get the filename from pathname
3790 //string GetFileName(std::string & pathname) {
3791 // size_t index = pathname.find_last_of("/");
3792 // string fileName = pathname.substr(index + 1);
3793 // return fileName;
3794 //}
3795 
3796 
3797 // Initialize binary file and write hpcrun header
3798 FILE* lazy_open_data_file(int tID, std::string* filename) {
3799  FILE* fs; // = file;
3800 
3801  // const char* pathCharName = pathname.c_str();
3802  // string fileName = GetFileName(pathname);
3803  const char* fileCharName = filename->c_str();
3804 
3805  int fd = hpcrun_open_profile_file(tID, fileCharName);
3806  fs = fdopen(fd, "w");
3807 
3808  if (fs == nullptr)
3809  return nullptr;
3810 
3811  const char* jobIdStr = OSUtil_jobid();
3812 
3813  if (!jobIdStr)
3814  jobIdStr = "";
3815 
3816  char mpiRankStr[bufSZ];
3817  mpiRankStr[0] = '0';
3818  snprintf(mpiRankStr, bufSZ, "%d", 0);
3819  char tidStr[bufSZ];
3820  snprintf(tidStr, bufSZ, "%d", tID);
3821  char hostidStr[bufSZ];
3822  snprintf(hostidStr, bufSZ, "%lx", OSUtil_hostid());
3823  char pidStr[bufSZ];
3824  snprintf(pidStr, bufSZ, "%u", OSUtil_pid());
3825  char traceMinTimeStr[bufSZ];
3826  snprintf(traceMinTimeStr, bufSZ, "%" PRIu64, (unsigned long int)0);
3827  char traceMaxTimeStr[bufSZ];
3828  snprintf(traceMaxTimeStr, bufSZ, "%" PRIu64, (unsigned long int)0);
3829 
3830  // ====== file hdr =====
3831  hpcrun_fmt_hdrwrite(fs);
3832  static int global_arg_len = 9;
3833  hpcfmt_int4_fwrite(global_arg_len, fs);
3834  hpcrun_fmt_hdr_fwrite(fs, HPCRUN_FMT_NV_prog, fileCharName);
3836  hpcrun_fmt_hdr_fwrite(fs, HPCRUN_FMT_NV_envPath, getenv("PATH"));
3841  hpcrun_fmt_hdr_fwrite(fs, HPCRUN_FMT_NV_traceMinTime, traceMinTimeStr);
3842  hpcrun_fmt_hdr_fwrite(fs, HPCRUN_FMT_NV_traceMaxTime, traceMaxTimeStr);
3844  // log the number of metrics
3845  hpcfmt_int4_fwrite((uint32_t)GLOBAL_STATE.nmetric - 1, fs);
3846  // log each metric
3847  for (int i = 1; i < GLOBAL_STATE.nmetric; i++)
3850  return fs;
3851 }
3852 
3853 int hpcrun_fmt_loadmap_fwrite(FILE* fs, const std::string& filename) {
3854  uint16_t num = 2;
3855  // Write loadmap size
3856  hpcfmt_int4_fwrite((uint32_t)GLOBAL_STATE.ModuleInfoMap.size(), fs); // Write loadmap size
3857 
3858  unordered_map<UINT32, ModuleInfo>::iterator it, ito;
3859  // First print out the load module of the executable binary
3860  for (it = GLOBAL_STATE.ModuleInfoMap.begin(); it != GLOBAL_STATE.ModuleInfoMap.end(); ++it) {
3861  if (it->second.id == 1) {
3862  // Write loadmap information
3863  hpcfmt_int2_fwrite(1, fs); // Write loadmap id of the main executbale
3864  hpcfmt_str_fwrite(it->second.moduleName.c_str(), fs); // Write loadmap name
3865  hpcfmt_int8_fwrite((uint64_t)0, fs); // Write loadmap flags
3866  break;
3867  }
3868  }
3869 
3870  // write other load modules
3871  for (it = GLOBAL_STATE.ModuleInfoMap.begin(); it != GLOBAL_STATE.ModuleInfoMap.end(); ++it) {
3872  // currently only print out the load module of the executable binary
3873  if (it->second.id == 1) {
3874  continue;
3875  }
3876 
3877  // Write loadmap information of other modules
3878  it->second.id = num;
3879  hpcfmt_int2_fwrite(num++, fs); // Write loadmap id
3880  hpcfmt_str_fwrite(it->second.moduleName.c_str(), fs); // Write loadmap name
3881  hpcfmt_int8_fwrite((uint64_t)0, fs); // Write loadmap flags
3882  }
3883 
3884  return 0;
3885 }
3886 
3887 
3888 int hpcrun_open_profile_file(int thread, const char* fileName) {
3889  int ret;
3892  ret = hpcrun_open_file(thread, HPCRUN_ProfileFnmSfx, FILES_LATE, fileName);
3894  return ret;
3895 }
3896 
3897 
3898 int hpcrun_fmt_hdrwrite(FILE* fs) {
3899  fwrite(HPCRUN_FMT_Magic, 1, HPCRUN_FMT_MagicLen, fs);
3900  fwrite(HPCRUN_FMT_Version, 1, HPCRUN_FMT_VersionLen, fs);
3901  fwrite(HPCRUN_FMT_Endian, 1, HPCRUN_FMT_EndianLen, fs);
3902  return 1;
3903 }
3904 
3905 
3907  uint64_t measurementGranularity, uint32_t raToCallsiteOfst) {
3909  hpcfmt_int8_fwrite(flags.bits, fs);
3910  hpcfmt_int8_fwrite(measurementGranularity, fs);
3911  hpcfmt_int4_fwrite(raToCallsiteOfst, fs);
3912  hpcfmt_int4_fwrite((uint32_t)1, fs);
3913  hpcrun_fmt_hdr_fwrite(fs, "TODO:epoch-name", "TODO:epoch-value");
3914  return 1;
3915 }
3916 
3917 
3918 int hpcrun_fmt_hdr_fwrite(FILE* fs, const char* arg1, const char* arg2) {
3919  hpcfmt_str_fwrite(arg1, fs);
3920  hpcfmt_str_fwrite(arg2, fs);
3921  return 1;
3922 }
3923 
3924 int hpcfmt_str_fwrite(const char* str, FILE* outfs) {
3925  unsigned int i;
3926  uint32_t len = (str) ? strlen(str) : 0;
3927  hpcfmt_int4_fwrite(len, outfs);
3928 
3929  for (i = 0; i < len; i++) {
3930  int c = fputc(str[i], outfs);
3931 
3932  if (c == EOF)
3933  return 0;
3934  }
3935 
3936  return 1;
3937 }
3938 
3939 
3940 size_t hpcio_be2_fwrite(const uint16_t* val, FILE* fs) {
3941  uint16_t v = *val; // local copy of val
3942  int shift = 0, num_write = 0, c;
3943 
3944  for (shift = 8; shift >= 0; shift -= 8) {
3945  c = fputc(((v >> shift) & 0xff), fs);
3946 
3947  if (c == EOF) {
3948  break;
3949  }
3950 
3951  num_write++;
3952  }
3953 
3954  return num_write;
3955 }
3956 
3957 
3958 size_t hpcio_be4_fwrite(const uint32_t* val, FILE* fs) {
3959  uint32_t v = *val; // local copy of val
3960  int shift = 0, num_write = 0, c;
3961 
3962  for (shift = 24; shift >= 0; shift -= 8) {
3963  c = fputc(((v >> shift) & 0xff), fs);
3964 
3965  if (c == EOF) {
3966  break;
3967  }
3968  num_write++;
3969  }
3970 
3971  return num_write;
3972 }
3973 
3974 size_t hpcio_be8_fwrite(const uint64_t* val, FILE* fs) {
3975  uint64_t v = *val; // local copy of val
3976  int shift = 0, num_write = 0, c;
3977 
3978  for (shift = 56; shift >= 0; shift -= 8) {
3979  c = fputc(((v >> shift) & 0xff), fs);
3980 
3981  if (c == EOF) {
3982  break;
3983  }
3984 
3985  num_write++;
3986  }
3987 
3988  return num_write;
3989 }
3990 
3991 
3992 size_t hpcio_beX_fwrite(uint8_t* val, size_t size, FILE* fs) {
3993  size_t num_write = 0;
3994 
3995  for (uint i = 0; i < size; ++i) {
3996  int c = fputc(val[i], fs);
3997 
3998  if (c == EOF)
3999  break;
4000  num_write++;
4001  }
4002 
4003  return num_write;
4004 }
4005 
4006 
4007 // Construct NewIPNode
4008 NewIPNode* constructIPNode(NewIPNode* parentIP, IPNode* oldIPNode, uint32_t parentID, uint64_t* nodeCount) {
4009  if (nullptr == oldIPNode)
4010  return nullptr;
4011 
4012  NewIPNode* curIP = new NewIPNode();
4013  curIP->parentIPNode = parentIP;
4015  curIP->parentID = parentID;
4016  curIP->tmpSplay = oldIPNode->calleeTraceNodes;
4017 #ifdef HAVE_METRIC_PER_IPNODE
4018  curIP->metric = oldIPNode->metric;
4019 #endif
4020 
4021  if (curIP->tmpSplay)
4022  curIP->ID = GetID();
4023  else
4024  curIP->ID = -GetID();
4025 
4026  (*nodeCount)++;
4027  return curIP;
4028 }
4029 
4030 // Inorder tranversal of the previous splay tree and create the new tree
4031 void tranverseIPs(NewIPNode* curIPNode, TraceSplay* childCtxtStartIdx, uint64_t* nodeCount) {
4032  if (nullptr == childCtxtStartIdx)
4033  return;
4034 
4035  TraceNode* tNode = childCtxtStartIdx->value;
4036  uint32_t i;
4037  tranverseIPs(curIPNode, childCtxtStartIdx->left, nodeCount);
4038 
4039  for (i = 0; i < tNode->nSlots; i++) {
4041  if (sameIP) {
4042  mergeIP(sameIP, GET_IPNODE_FROM_CONTEXT_HANDLE_CHECKED(tNode->childCtxtStartIdx + i), nodeCount);
4043  } else {
4044  NewIPNode* nNode = constructIPNode(curIPNode, GET_IPNODE_FROM_CONTEXT_HANDLE_CHECKED(tNode->childCtxtStartIdx + i), curIPNode->ID, nodeCount);
4045  curIPNode->childIPNodes.push_back(nNode);
4046 
4047  if (nNode->tmpSplay) {
4048  tranverseIPs(nNode, nNode->tmpSplay, nodeCount);
4049  }
4050  }
4051  }
4052  tranverseIPs(curIPNode, childCtxtStartIdx->right, nodeCount);
4053 }
4054 
4055 
4056 // Check to see whether another IPNode has the same address under the same parent.
4057 NewIPNode* findSameIP(vector<NewIPNode*> nodes, IPNode* node) {
4058  std::size_t i;
4060 
4061  for (i = 0; i < nodes.size(); i++) {
4062  if (nodes.at(i)->IPAddress == address)
4063  return nodes.at(i);
4064  }
4065 
4066  return nullptr;
4067 }
4068 
4069 // Merging the children of two nodes
4070 void mergeIP(NewIPNode* prev, IPNode* cur, uint64_t* nodeCount) {
4071  if (!cur)
4072  return;
4073 #ifdef HAVE_METRIC_PER_IPNODE
4074  void* m = prev->metric;
4075  void* n = cur->metric;
4076  if (m && n) {
4077  if (GLOBAL_STATE.mergeFunc)
4078  GLOBAL_STATE.mergeFunc(m, n);
4079  } else if (!m && n) {
4080  prev->metric = n;
4081  }
4082 #endif
4083 
4084  if (cur->calleeTraceNodes) {
4085  tranverseIPs(prev, cur->calleeTraceNodes, nodeCount);
4086  }
4087 }
4088 
4089 
4090 // Helper function to assign ID for each node
4091 uint32_t GetID() {
4092  // begin with 2 because 0 is the common root
4093  static uint32_t IDGlobal = 2;
4094  uint32_t id = __sync_fetch_and_add(&IDGlobal, 2);
4095  return id;
4096 }
4097 
4098 // Write out each IP's id, parent id, loadmodule id (1) and address
4099 void IPNode_fwrite(NewIPNode* node, FILE* fs) {
4100  if (!node)
4101  return;
4102  hpcfmt_int4_fwrite(node->ID, fs);
4103  hpcfmt_int4_fwrite(node->parentID, fs);
4104  // adjust the IPaddress to point to return address of the callsite (internal nodes) for hpcrun requirement
4105  if (node->ID > 0)
4106  node->IPAddress++;
4107 
4108  IMG im = IMG_FindByAddress(node->IPAddress);
4109  if (node->IPAddress == 0 || IMG_Id(im) == 0) {
4110  hpcfmt_int2_fwrite(0, fs);
4111  hpcfmt_int8_fwrite(node->IPAddress, fs);
4112  } else {
4113  hpcfmt_int2_fwrite(GLOBAL_STATE.ModuleInfoMap[IMG_Id(im)].id, fs); // Set loadmodule id to 1
4114  // normalize the IP offset to the beginning of the load module and write out
4115  hpcfmt_int8_fwrite(node->IPAddress - GLOBAL_STATE.ModuleInfoMap[IMG_Id(im)].imgLoadOffset, fs);
4116  }
4117 
4118  // this uses .metric field in the NewIPNode, which means we have per IPNode metric
4119  // for this case, by default, we only have one metric
4122  } else { // not necessarily have per IPNode metric
4123  for (int i = 1; i < GLOBAL_STATE.nmetric; i++)
4124  hpcfmt_int8_fwrite(node->metricVal[i], fs);
4125  }
4126 }
4127 
4128 
4129 // Tranverse and print the calling context tree (nodes first)
4130 // Pass `nodes` by const reference; the original by-value signature copied
4131 // the whole child vector on every recursive call and made hpcrun emission
4132 // quadratic in tree size.
4133 void tranverseNewCCT(vector<NewIPNode*> nodes, FILE* fs) {
4134  if (nodes.empty())
4135  return;
4136  std::size_t i;
4137 
4138  for (i = 0; i < nodes.size(); i++) {
4139  IPNode_fwrite(nodes.at(i), fs);
4140  }
4141 
4142  for (i = 0; i < nodes.size(); i++) {
4143  if (!nodes.at(i)->childIPNodes.empty()) {
4144  tranverseNewCCT(nodes.at(i)->childIPNodes, fs);
4145  }
4146  }
4147 }
4148 
4149 static void findMain(IPNode* curIPNode, TraceSplay* childCtxtStartIdx, IPNode** mainNode) {
4150  if (nullptr == childCtxtStartIdx)
4151  return;
4152 
4153  TraceNode* tNode = childCtxtStartIdx->value;
4154  uint32_t i;
4155  findMain(curIPNode, childCtxtStartIdx->left, mainNode);
4156 
4157  for (i = 0; i < tNode->nSlots; i++) {
4158  if (GetIPFromInfo((tNode->childCtxtStartIdx + i)) == GLOBAL_STATE.mainIP) {
4160  return;
4161  }
4163  if (childNode && childNode->calleeTraceNodes) {
4164  findMain(childNode, childNode->calleeTraceNodes, mainNode);
4165  }
4166  }
4167  findMain(curIPNode, childCtxtStartIdx->right, mainNode);
4168 }
4169 
4170 NewIPNode* findSameIPbyIP(vector<NewIPNode*> nodes, ADDRINT address) {
4171  std::size_t i;
4172  for (i = 0; i < nodes.size(); i++) {
4173  if (nodes.at(i)->IPAddress == address)
4174  return nodes.at(i);
4175  }
4176  return nullptr;
4177 }
4178 
4179 // Construct NewIPNode
4180 NewIPNode* constructIPNodeFromIP(NewIPNode* parentIP, ADDRINT address, uint64_t* nodeCount) {
4181  NewIPNode* curIP = new NewIPNode();
4182  curIP->childIPNodes.clear();
4183  curIP->parentIPNode = parentIP;
4184  curIP->IPAddress = address;
4185  curIP->parentID = parentIP->ID;
4186  curIP->tmpSplay = nullptr;
4187  curIP->ID = GetID();
4188  curIP->metric = nullptr;
4189  curIP->metricVal = new uint64_t[GLOBAL_STATE.nmetric];
4190  for (int i = 1; i < GLOBAL_STATE.nmetric; i++)
4191  curIP->metricVal[i] = 0;
4192  parentIP->childIPNodes.push_back(curIP);
4193 
4194  (*nodeCount)++;
4195  return curIP;
4196 }
4197 
4198 void hpcrun_insert_path(NewIPNode* root, HPCRunCCT_t* HPCRunNode, uint64_t* nodeCount) {
4199  vector<Context> contextVec1, contextVec2;
4200 
4201  if (HPCRunNode->ctxtHandle1 == 0)
4202  return;
4203 
4204  GetFullCallingContextInSitu(HPCRunNode->ctxtHandle1, contextVec1);
4205  GetFullCallingContextInSitu(HPCRunNode->ctxtHandle2, contextVec2);
4206 
4207  NewIPNode* tmp;
4208  NewIPNode* cur = root;
4209  for (int32_t i = contextVec1.size() - 1; i >= 0; i--) {
4210  tmp = findSameIPbyIP(cur->childIPNodes, contextVec1[i].ip);
4211  if (!tmp) {
4212  NewIPNode* nIP = constructIPNodeFromIP(cur, contextVec1[i].ip, nodeCount);
4213  cur = nIP;
4214  } else {
4215  cur = tmp;
4216  }
4217  }
4218 
4219 #if 0
4220  //add a join node
4221  tmp = findSameIPbyIP(cur->childIPNodes, (ADDRINT)KILLED_BY);
4222  if (!tmp) cur = constructIPNodeFromIP(cur, (ADDRINT)KILLED_BY, nodeCount);
4223  else cur = tmp;
4224 #endif
4225 
4226  if (HPCRunNode->ctxtHandle2 != 0) {
4227  // concatenate the two contexts
4228  for (int32_t i = contextVec2.size() - 1; i >= 0; i--) {
4229  tmp = findSameIPbyIP(cur->childIPNodes, contextVec2[i].ip);
4230  if (!tmp) {
4231  NewIPNode* nIP = constructIPNodeFromIP(cur, contextVec2[i].ip, nodeCount);
4232  cur = nIP;
4233  } else {
4234  cur = tmp;
4235  }
4236  }
4237  }
4238  // metrics only associated with leaves
4239  // if the path already exists, just merge the metrics
4240  if (cur->ID < 0) {
4241  cur->metricVal[HPCRunNode->metric_id] += HPCRunNode->metric;
4242  } else {
4243  cur->metricVal[HPCRunNode->metric_id] = HPCRunNode->metric;
4244  cur->ID = -cur->ID;
4245  }
4246 }
4247 
4248 /*======APIs to support hpcviewer format======*/
4249 /*
4250  * Initialize the formatting preparation
4251  * (called by the clients)
4252  * TODO: initialize metric table, provide custom metric merge functions
4253  */
4254 int init_hpcrun_format(int argc, char* argv[], void (*mergeFunc)(void* des, void* src), uint64_t (*computeMetricVal)(void* metric), bool skip) {
4255  // Extract executable name
4256  int i;
4257  for (i = 0; i < argc; i++) {
4258  if (strcmp(argv[i], "--") == 0) {
4259  filename = new string(basename(argv[i + 1]));
4260  break;
4261  }
4262  }
4263  // Create the measurement directory
4264  dirName = "hpctoolkit-" + *filename + "-measurements";
4265  int status = mkdir(dirName.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
4266  (void)status; // TODO: check errno != EEXIST and report real errors instead of ignoring.
4267 
4268  if (skip)
4269  GLOBAL_STATE.skip = true;
4270 
4273  // the current metric cursor is set to 1
4274  GLOBAL_STATE.nmetric = 1;
4275  return 0;
4276 }
4277 
4278 /*
4279  * API to create metrics
4280  */
4281 int hpcrun_create_metric(const char* name) {
4282  int t = GLOBAL_STATE.nmetric;
4283  snprintf(GLOBAL_STATE.metrics[GLOBAL_STATE.nmetric++], MAX_LEN, "%s", name);
4284  return t;
4285 }
4286 
4287 /*
4288  * Write the calling context tree of 'threadid' thread
4289  * (Called from clientele program)
4290  */
4291 int newCCT_hpcrun_write(THREADID threadid) {
4292  FILE* fs = lazy_open_data_file(int(threadid), filename);
4293  if (!fs)
4294  return -1;
4295 
4296  uint32_t i;
4297  ThreadData* tdata = CCTLibGetTLS(threadid);
4298  TraceNode* cctlib = tdata->tlsRootTraceNode;
4299  vector<NewIPNode*> IPHandle;
4300 
4301  // find the main node (the entry point by the programmer)
4302  IPNode* mainNode = nullptr;
4303  if (GLOBAL_STATE.skip) {
4304  for (i = 0; i < cctlib->nSlots; i++) {
4306  if (childNode) {
4307  findMain(childNode, childNode->calleeTraceNodes, &mainNode);
4308  }
4309  }
4310  }
4311 
4312  // only keep the main subtree
4313  if (mainNode) {
4314  // update cctlib and make the dummy root
4315  cctlib = new TraceNode();
4316  cctlib->nSlots = 1;
4317  cctlib->childCtxtStartIdx = mainNode->parentTraceNode->callerCtxtHndl;
4318  SetIPFromInfo(cctlib->childCtxtStartIdx, 0x0); // dummy root should have 0 ip
4319 #ifdef HAVE_METRIC_PER_IPNODE
4321  if (rootIP)
4322  rootIP->metric = nullptr;
4323 #endif
4324  }
4325 
4326  for (i = 0; i < cctlib->nSlots; i++) {
4328  IPHandle.push_back(nIP);
4329 
4330  if (nIP->tmpSplay) {
4331  tranverseIPs(nIP, nIP->tmpSplay, &tdata->nodeCount);
4332  }
4333  }
4334 
4335  hpcfmt_int8_fwrite(tdata->nodeCount, fs);
4336  tranverseNewCCT(IPHandle, fs);
4337  hpcio_fclose(fs);
4338  return 0;
4339 }
4340 
4341 
4342 // This API is used to output a hpcrun CCT with selected call paths
4343 int newCCT_hpcrun_build_cct(vector<HPCRunCCT_t*>& OldNodes, THREADID threadid) {
4344  // build the hpcrun-style CCT
4345  ThreadData* tdata = CCTLibGetTLS(threadid);
4346  // initialize the root node (dummy node)
4347  if (!tdata->tlsHPCRunCCTRoot) {
4348  tdata->tlsHPCRunCCTRoot = new NewIPNode();
4349  tdata->tlsHPCRunCCTRoot->childIPNodes.clear();
4350  tdata->tlsHPCRunCCTRoot->IPAddress = 0;
4351  tdata->tlsHPCRunCCTRoot->ID = 0;
4352  tdata->tlsHPCRunCCTRoot->tmpSplay = nullptr;
4353  tdata->tlsHPCRunCCTRoot->metric = nullptr;
4354  tdata->tlsHPCRunCCTRoot->metricVal = new uint64_t[GLOBAL_STATE.nmetric];
4355  for (int i = 1; i < GLOBAL_STATE.nmetric; i++)
4356  tdata->tlsHPCRunCCTRoot->metricVal[i] = 0;
4357  tdata->nodeCount = 0;
4358  }
4359 
4360  NewIPNode* root = tdata->tlsHPCRunCCTRoot;
4361  vector<HPCRunCCT_t*>::iterator it;
4362  for (it = OldNodes.begin(); it != OldNodes.end(); ++it) {
4363  hpcrun_insert_path(root, *it, &tdata->nodeCount);
4364  }
4365  return 0;
4366 }
4367 
4368 // output the CCT
4369 int newCCT_hpcrun_selection_write(THREADID threadid) {
4370  FILE* fs = lazy_open_data_file(int(threadid), filename);
4371  if (!fs)
4372  return -1;
4373 
4374  ThreadData* tdata = CCTLibGetTLS(threadid);
4375  uint32_t i;
4376  NewIPNode* cctlib = tdata->tlsHPCRunCCTRoot;
4377  vector<NewIPNode*> IPHandle;
4378 
4379  for (i = 0; i < cctlib->childIPNodes.size(); i++) {
4380  IPHandle.push_back(cctlib->childIPNodes[i]);
4381  }
4382 
4383  hpcfmt_int8_fwrite(tdata->nodeCount, fs);
4384  tranverseNewCCT(IPHandle, fs);
4385  hpcio_fclose(fs);
4386  return 0;
4387 }
4388 
4389 // ************************************************************
4390 
4391 } // namespace PinCCTLib
size_t getPeakRSS()
uint64_t computeMetricVal(void *metric)
void mergeFunc(void *des, void *src)
#define MAX_CCT_PRINT_DEPTH
Definition: cctlib.H:16
#define MAX_FILE_PATH
Definition: cctlib.H:18
#define MAX_CCT_PATH_DEPTH
Definition: cctlib.H:17
#define SETJMP_RTN
#define ARCH_LONGJMP_RTN
#define FILES_EARLY
Definition: cctlib.cpp:3308
#define GET_IPNODE_FROM_CONTEXT_HANDLE(handle)
Definition: cctlib.cpp:126
#define SIGLONGJMP_RTN
#define HPCRUN_FMT_NV_pid
Definition: cctlib.cpp:3297
#define FILENAME_TEMPLATE
Definition: cctlib.cpp:3302
#define SERIALIZED_CCT_FILE_PREFIX
Definition: cctlib.cpp:134
#define CALLOC_FN_NAME
Definition: cctlib.cpp:88
#define FILES_MAX_GEN
Definition: cctlib.cpp:3307
#define IS_VALID_CONTEXT(c)
Definition: cctlib.cpp:127
#define RANK
Definition: cctlib.cpp:3304
#define CCTLIB_SERIALIZATION_DEFAULT_DIR_NAME
Definition: cctlib.cpp:93
#define HPCRUN_FMT_NV_hostid
Definition: cctlib.cpp:3296
static void CCTLibTrimInPlace(std::string &s)
Definition: cctlib.cpp:48
#define SPINLOCK_UNLOCKED_VALUE
Definition: cctlib.cpp:3282
#define SERIALIZED_MODULE_MAP_SUFFIX
Definition: cctlib.cpp:1753
#define HPCRUN_FMT_NV_traceMaxTime
Definition: cctlib.cpp:3300
#define FILES_LATE
Definition: cctlib.cpp:3309
#define HPCRUN_FMT_NV_progPath
Definition: cctlib.cpp:3291
#define HPCRUN_FMT_NV_jobId
Definition: cctlib.cpp:3293
#define HPCRUN_FMT_NV_prog
Definition: cctlib.cpp:3290
#define HPCRUN_FMT_NV_tid
Definition: cctlib.cpp:3295
#define FREE_FN_NAME
Definition: cctlib.cpp:90
#define SERIALIZED_SHADOW_TRACE_IP_FILE_SUFFIX
Definition: cctlib.cpp:133
#define SERIALIZED_CCT_FILE_EXTN
Definition: cctlib.cpp:135
#define REALLOC_FN_NAME
Definition: cctlib.cpp:89
#define MAX_IPNODES
Definition: cctlib.cpp:97
#define NOT_ROOT_CTX
Definition: cctlib.cpp:2047
#define MAX_METRICS
Definition: cctlib.cpp:380
#define OSUtil_hostid_NULL
Definition: cctlib.cpp:3284
#define SPINLOCK_UNLOCKED
Definition: cctlib.cpp:3287
#define MAX_LEN
Definition: cctlib.cpp:381
#define SERIALIZED_CCT_FILE_SUFFIX
Definition: cctlib.cpp:136
#define SPINLOCK_LOCKED_VALUE
Definition: cctlib.cpp:3283
#define SIGSETJMP_RTN
#define MALLOC_FN_NAME
Definition: cctlib.cpp:87
#define HPCRUN_FMT_NV_envPath
Definition: cctlib.cpp:3292
#define HPCRUN_FMT_NV_traceMinTime
Definition: cctlib.cpp:3299
#define FILES_RANDOM_GEN
Definition: cctlib.cpp:3306
#define read_modify_write(type, addr, expn, result)
Definition: cctlib.cpp:3325
#define GET_IPNODE_FROM_CONTEXT_HANDLE_CHECKED(handle)
Definition: cctlib.cpp:123
#define GET_CONTEXT_HANDLE_FROM_IP_NODE(node)
Definition: cctlib.cpp:125
#define LONGJMP_RTN
#define UNWIND_SETIP
#define MAX_STRING_POOL_NODES
Definition: cctlib.cpp:109
#define GET_CONTEXT_HANDLE_FROM_IP_NODE_CHECKED(node)
Definition: cctlib.cpp:122
#define PTHREAD_CREATE_RTN
#define CACHE_LINE_SIZE
Definition: cctlib.cpp:119
bool IsValidIP(DeadInfo di)
static uint64_t buf[ITERS]
static uint64_t src[N]
static int hpcfmt_int4_fwrite(uint32_t val, FILE *outfs)
Definition: cctlib.cpp:3603
int metric_id
Definition: cctlib.H:61
static VOID CaptureSigSetJmpCtxt(ADDRINT buf, THREADID threadId)
Definition: cctlib.cpp:559
uint64_t metric
Definition: cctlib.H:60
static void CaptureFree(void *ptr, THREADID threadId)
Definition: cctlib.cpp:2777
DataHandle_t GetDataObjectHandle(VOID *address, const THREADID threadId)
Definition: cctlib.cpp:2495
void DumpCallStackEasy()
Definition: cctlib.cpp:515
volatile bool locked
Definition: cctlib.cpp:227
int PinCCTLibInit(IsInterestingInsFptr isInterestingIns, FILE *logFile, CCTLibInstrumentInsCallback userCallback, VOID *userCallbackArg, BOOL doDataCentric=false)
Definition: cctlib.cpp:3132
static void GetNormalizedIpVectorClippedToMainOneAheadIp(vector< NormalizedIP > &ctxt, ContextHandle_t curCtxtHndle)
Definition: cctlib.cpp:2371
size_t hpcio_beX_fwrite(uint8_t *val, size_t size, FILE *fs)
Definition: cctlib.cpp:3992
static const char HPCRUN_ProfileFnmSfx[]
Definition: cctlib.cpp:3508
VOID TakeLock()
Definition: cctlib.cpp:734
ContextHandle_t ctxtHandle
Definition: cctlib.H:52
static void DeserializeAllCCTs()
Definition: cctlib.cpp:1625
static void ThreadCapturePoint(ThreadData *tdata)
Definition: cctlib.cpp:767
struct spinlock_s { volatile long thelock spinlock_t
Definition: cctlib.cpp:3438
static void InstrumentTraceEntry(uint32_t traceKey, uint32_t numInterestingInstInTrace, ADDRINT traceFirstIp, THREADID threadId)
Definition: cctlib.cpp:1182
static ThreadData * CCTLibGetTLS(const THREADID threadId)
Definition: cctlib.cpp:491
int hpcrun_open_profile_file(int thread, const char *fileName)
Definition: cctlib.cpp:3888
int hpcrun_create_metric(const char *name)
Definition: cctlib.cpp:4281
IPNode * GetPINCCTContextFrom32BitIndex(ContextHandle_t index)
Definition: cctlib.cpp:1374
static bool IsCallInstruction(ADDRINT ip)
Definition: cctlib.cpp:595
static VOID CCTLibInstrumentImageLoad(IMG img, VOID *v)
Definition: cctlib.cpp:1059
int hpcio_fclose(FILE *fs)
Definition: cctlib.cpp:3629
static VOID CCTLibFini(INT32 code, VOID *v)
Definition: cctlib.cpp:1384
static VOID CaptureLandingPadTarget(VOID *, ADDRINT landingPadIp, THREADID threadId)
Definition: cctlib.cpp:702
VOID(*)(INS, VOID *, const uint32_t) CCTLibInstrumentInsCallback
Definition: cctlib.H:68
static void InitDataCentric()
Definition: cctlib.cpp:3111
enum { MetricFlags_ValTy_NULL=0, MetricFlags_ValTy_Incl, MetricFlags_ValTy_Excl } MetricFlags_ValTy_t
Definition: cctlib.cpp:3374
struct metric_desc_properties_t { unsigned time :1 metric_desc_properties_t
Definition: cctlib.cpp:3397
int newCCT_hpcrun_write(THREADID threadid)
Definition: cctlib.cpp:4291
static pid_t mypid
Definition: cctlib.cpp:3492
static void compute_static_var(char *filename, IMG img)
Definition: cctlib.cpp:2798
static void InitXED()
Definition: cctlib.cpp:2469
static void SetIPFromInfo(ContextHandle_t ctxtHndle, ADDRINT val)
Definition: cctlib.cpp:1966
static void InitMapFilePrefix()
Definition: cctlib.cpp:2445
static const char HPCRUN_FMT_VersionLen
Definition: cctlib.cpp:3510
static void SerializeMouleInfo()
Definition: cctlib.cpp:1755
static TraceNode * FindHandlerFrameForLandingPad(ADDRINT landingPadIp, ADDRINT *outHandlerLo, ADDRINT *outHandlerHi, ThreadData *tData)
Definition: cctlib.cpp:668
static ADDRINT GetIPFromInfo(ContextHandle_t)
Definition: cctlib.cpp:1951
static uint64_t gDotId
Definition: cctlib.cpp:1679
void AppendLoadModulesToStream(iostream &ios)
Definition: cctlib.cpp:2359
VOID CCTLibAppStartNotification(void *v)
Definition: cctlib.cpp:3126
int newCCT_hpcrun_build_cct(std::vector< HPCRunCCT_t * > &OldNodes, THREADID threadid)
Definition: cctlib.cpp:4343
void DottifyAllCCTs()
Definition: cctlib.cpp:1731
struct HPCRunCCT_t { ContextHandle_t ctxtHandle1 HPCRunCCT_t
Definition: cctlib.H:58
static ConcurrentShadowMemory< DataHandle_t > sm
Definition: cctlib.cpp:2479
ADDRINT GetNextTraceKey()
Definition: cctlib.cpp:478
hpcrun_metricFlags_t flags
Definition: cctlib.cpp:3425
static VOID HoldLongJmpBuf(ADDRINT buf, THREADID threadId)
Definition: cctlib.cpp:566
struct PinCCTLib::CCT_LIB_GLOBAL_STATE GLOBAL_STATE
metric_desc_properties_t properties
Definition: cctlib.cpp:3427
ContextHandle_t pathHandle
Definition: cctlib.H:34
ContextHandle_t GetPINCCT32BitContextIndex(IPNode *node)
Definition: cctlib.cpp:1370
static const uint64_t default_measurement_granularity
Definition: cctlib.cpp:3487
static void PrintStats()
Definition: cctlib.cpp:1936
static void GetDecodedInstFromIP(ADDRINT ip)
Definition: cctlib.cpp:1991
static spinlock_t files_lock
Definition: cctlib.cpp:3491
NewIPNode * findSameIPbyIP(vector< NewIPNode * > nodes, ADDRINT address)
Definition: cctlib.cpp:4170
struct epoch_flags_bitfield { bool isLogicalUnwind :1 epoch_flags_bitfield
Definition: cctlib.cpp:3385
void GetParentIPs(ContextHandle_t ctxtHandle, std::vector< ADDRINT > &parentIPs)
Definition: cctlib.cpp:2153
enum { MetricFlags_ValFmt_NULL=0, MetricFlags_ValFmt_Int, MetricFlags_ValFmt_Real, } MetricFlags_ValFmt_t
Definition: cctlib.cpp:3381
NewIPNode * constructIPNodeFromIP(NewIPNode *parentIP, ADDRINT address, uint64_t *nodeCount)
Definition: cctlib.cpp:4180
IPNode * GetPINCCTCurrentContextWithSlot(THREADID id, uint32_t slot)
Definition: cctlib.cpp:1350
unsigned cycles
Definition: cctlib.cpp:3398
static VOID DeleteStaticVar(IMG img, VOID *v)
Definition: cctlib.cpp:2886
long OSUtil_hostid()
Definition: cctlib.cpp:3582
void LogContexts(iostream &ios, ContextHandle_t ctxt1, ContextHandle_t ctxt2)
Definition: cctlib.cpp:2407
VOID CCTLibImage(IMG img, VOID *v)
Definition: cctlib.cpp:2907
static void InitBuffers()
Definition: cctlib.cpp:2420
size_t hpcio_be8_fwrite(const uint64_t *val, FILE *fs)
Definition: cctlib.cpp:3974
static int hpcrun_open_file(int thread, const char *suffix, int flags, const char *fileName)
Definition: cctlib.cpp:3681
char * description
Definition: cctlib.cpp:3422
static void InitSegHandler()
Definition: cctlib.cpp:2462
VOID PrintFullCallingContext(const ContextHandle_t ctxtHandle)
Definition: cctlib.cpp:2346
int PinCCTLibInitForPostmortemAnalysis(FILE *logFile, const std::string &serializedFilesDirectory)
Definition: cctlib.cpp:3183
uint8_t unused0
Definition: cctlib.cpp:3406
FILE * lazy_open_data_file(int tID, std::string *filename)
Definition: cctlib.cpp:3798
uint32_t GetID()
Definition: cctlib.cpp:4091
static int hpcrun_files_next_id(struct fileid *id)
Definition: cctlib.cpp:3656
static VOID CaptureCallocSize(size_t arg0, size_t arg1, THREADID threadId)
Definition: cctlib.cpp:2569
static VOID CaptureMallocSize(size_t arg0, THREADID threadId)
Definition: cctlib.cpp:2562
static void VisitAllNodesOfSplayTree(TraceSplay *node, FILE *const fp)
Definition: cctlib.cpp:1444
static void GetLineFromInfo(const ADDRINT &ip, uint32_t &lineNo, string &filePath)
Definition: cctlib.cpp:1987
static int IsARootIPNode(ContextHandle_t curCtxtHndle)
Definition: cctlib.cpp:2049
static int hpcfmt_int8_fwrite(uint64_t val, FILE *outfs)
Definition: cctlib.cpp:3612
NewIPNode * findSameIP(vector< NewIPNode * > nodes, IPNode *node)
Definition: cctlib.cpp:4057
static void OnSig(THREADID threadId, CONTEXT_CHANGE_REASON reason, const CONTEXT *ctxtFrom, CONTEXT *ctxtTo, INT32 sig, VOID *v)
Definition: cctlib.cpp:1315
static VOID RememberSlotNoInTLS(uint32_t slot, THREADID threadId)
Definition: cctlib.cpp:1024
static const int HPCRUN_FMT_EndianLen
Definition: cctlib.cpp:3507
static VOID CaptureReallocSize(void *ptr, size_t arg1, THREADID threadId)
Definition: cctlib.cpp:2579
static void InitShadowSpaceForDataCentric(VOID *addr, uint32_t accessLen, DataHandle_t *initializer)
Definition: cctlib.cpp:2481
uint16_t size_t
Definition: cctlib.cpp:3359
uint64_t period
Definition: cctlib.cpp:3426
static int GetInstructionLength(ADDRINT ip)
Definition: cctlib.cpp:581
static const char HPCRUN_FMT_Endian[]
Definition: cctlib.cpp:3506
static VOID GetFullCallingContextPostmortem(ContextHandle_t curCtxtHndle, vector< Context > &contextVec)
Definition: cctlib.cpp:2256
static const int HPCRUN_FMT_MagicLen
Definition: cctlib.cpp:3505
static int log_rename_done
Definition: cctlib.cpp:3496
static const char HPCRUN_FMT_EpochTag[]
Definition: cctlib.cpp:3511
struct Context { std::string functionName Context
Definition: cctlib.H:49
static int hpcfmt_int2_fwrite(uint16_t val, FILE *outfs)
Definition: cctlib.cpp:3594
static void DottifyCCTNode(TraceNode *traceNode, uint64_t parentDotId, FILE *const fp)
Definition: cctlib.cpp:1708
void mergeIP(NewIPNode *prev, IPNode *cur, uint64_t *nodeCount)
Definition: cctlib.cpp:4070
uint32_t lineNo
Definition: cctlib.H:53
size_t hpcio_be2_fwrite(const uint16_t *val, FILE *fs)
Definition: cctlib.cpp:3940
int fputs(const char *__restrict __s, FILE *__restrict __stream)
VOID GetFullCallingContext(const ContextHandle_t curCtxtHndle, std::vector< Context > &contextVec)
Definition: cctlib.cpp:2339
static bool IsDirectory(const char *path)
Definition: cctlib.cpp:1575
CCTLibUsageMode
Definition: cctlib.cpp:176
@ CCT_LIB_MODE_POSTMORTEM
Definition: cctlib.cpp:177
@ CCT_LIB_MODE_COLLECTION
Definition: cctlib.cpp:176
bool HaveSameCallerPrefix(ContextHandle_t ctxt1, ContextHandle_t ctxt2)
Definition: cctlib.cpp:3241
static const char HPCRUN_FMT_Magic[]
Definition: cctlib.cpp:3504
static void GetAllFilesInDirWithExtn(const string &root, const string &ext, vector< string > &ret)
Definition: cctlib.cpp:1590
void hpcrun_insert_path(NewIPNode *root, HPCRunCCT_t *HPCRunNode, uint64_t *nodeCount)
Definition: cctlib.cpp:4198
static int unsigned long fetch_and_store(volatile long *addr, long newval)
Definition: cctlib.cpp:3727
@ UNKNOWN_OBJECT
Definition: cctlib.H:28
@ STACK_OBJECT
Definition: cctlib.H:25
@ DYNAMIC_OBJECT
Definition: cctlib.H:26
@ STATIC_OBJECT
Definition: cctlib.H:27
int hpcrun_fmt_hdrwrite(FILE *fs)
Definition: cctlib.cpp:3898
MetricFlags_ValTy_t valTy
Definition: cctlib.cpp:3404
MetricFlags_ValFmt_t valFmt
Definition: cctlib.cpp:3405
uint64_t bits
Definition: cctlib.cpp:3392
static int log_done
Definition: cctlib.cpp:3495
void SerializeMetadata(const std::string &directoryForSerializationFiles="")
Definition: cctlib.cpp:1878
static void findMain(IPNode *curIPNode, TraceSplay *childCtxtStartIdx, IPNode **mainNode)
Definition: cctlib.cpp:4149
static void DeserializeTraceIps()
Definition: cctlib.cpp:1838
bool IsSameSourceLine(ContextHandle_t ctxt1, ContextHandle_t ctxt2)
Definition: cctlib.cpp:3255
static VOID SetCallInitFlag(uint32_t slot, THREADID threadId)
Definition: cctlib.cpp:966
uint8_t showPercent
Definition: cctlib.cpp:3409
static void ThreadCreatePoint(THREADID threadId)
Definition: cctlib.cpp:748
static ContextHandle_t GetNextIPVecBuffer(uint32_t num)
Definition: cctlib.cpp:784
volatile uint8_t status
Definition: cctlib.cpp:230
static const RtnInfo * GetOrClassifyRoutine(RTN rtn)
Definition: cctlib.cpp:899
struct QNode { struct QNode *volatile next QNode
Definition: cctlib.cpp:224
std::string dirName
Definition: cctlib.cpp:3500
int hpcrun_fmt_epochHdr_fwrite(FILE *fs, epoch_flags_t flags, uint64_t measurementGranularity, uint32_t raToCallsiteOfst)
Definition: cctlib.cpp:3906
bool is_frequency_metric
Definition: cctlib.cpp:3430
BOOL IsCallOrRetIns(INS ins)
Definition: cctlib.cpp:466
static void CCTLibInitThreadData(ThreadData *const tdata, CONTEXT *ctxt, THREADID threadId)
Definition: cctlib.cpp:820
static void InitLogFile(FILE *logFile)
Definition: cctlib.cpp:2441
static VOID CCTLibThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
Definition: cctlib.cpp:873
void DeserializeMetadata(const string &directoryForSerializationFiles)
Definition: cctlib.cpp:1917
enum { MetricFlags_Ty_NULL=0, MetricFlags_Ty_Raw, MetricFlags_Ty_Final, MetricFlags_Ty_Derived } MetricFlags_Ty_t
Definition: cctlib.cpp:3367
static VOID MaybeGoUpCallChain(ADDRINT retTarget, const ADDRINT *returnAddrs, uint32_t n, THREADID threadId)
Definition: cctlib.cpp:1007
const metric_desc_t metricDesc_NULL
Definition: cctlib.cpp:3451
void tranverseIPs(NewIPNode *curIPNode, TraceSplay *childCtxtStartIdx, uint64_t *nodeCount)
Definition: cctlib.cpp:4031
static void CCTLibInstrumentTrace(TRACE trace, void *isInterestingIns)
Definition: cctlib.cpp:1300
uint64_t bits_big[2]
Definition: cctlib.cpp:3417
static void SerializeAllCCTs()
Definition: cctlib.cpp:1551
void IPNode_fwrite(NewIPNode *node, FILE *fs)
Definition: cctlib.cpp:4099
int hpcrun_fmt_loadmap_fwrite(FILE *fs, const std::string &filename)
Definition: cctlib.cpp:3853
static TraceNode * DeserializeCCTNode(ContextHandle_t parentCtxtHndl, FILE *const fp)
Definition: cctlib.cpp:1476
struct hpcrun_metricFlags_fields { MetricFlags_Ty_t ty :8 hpcrun_metricFlags_fields
Definition: cctlib.cpp:3403
static void DeserializeMouleInfo()
Definition: cctlib.cpp:1775
std::string disassembly
Definition: cctlib.H:51
int init_hpcrun_format(int argc, char *argv[], void(*mergeFunc)(void *des, void *src)=nullptr, uint64_t(*computeMetricVal)(void *metric)=nullptr, bool skip=false)
Definition: cctlib.cpp:4254
std::string * filename
Definition: cctlib.cpp:3501
static void ListAllNodesOfSplayTree(TraceSplay *node, vector< TraceNode * > &childTraces)
Definition: cctlib.cpp:1696
static const int HPCRUN_FMT_EpochTagLen
Definition: cctlib.cpp:3512
static uint32_t GetNumInterestingInsInTrace(const TRACE &trace, IsInterestingInsFptr isInterestingIns)
Definition: cctlib.cpp:1043
static VOID GoUpCallChain(THREADID threadId)
Definition: cctlib.cpp:978
void DumpCallStack(THREADID id, uint32_t slot)
Definition: cctlib.cpp:498
static struct fileid earlyid
Definition: cctlib.cpp:3493
NewIPNode * constructIPNode(NewIPNode *parentIP, IPNode *oldIPNode, uint32_t parentID, uint64_t *nodeCount)
Definition: cctlib.cpp:4008
std::string filePath
Definition: cctlib.H:50
union epoch_flags_t { epoch_flags_bitfield fields epoch_flags_t
Definition: cctlib.cpp:3391
static VOID CaptureMallocPointer(void *ptr, THREADID threadId)
Definition: cctlib.cpp:2761
static epoch_flags_t epoch_flags
Definition: cctlib.cpp:3484
size_t hpcio_be4_fwrite(const uint32_t *val, FILE *fs)
Definition: cctlib.cpp:3958
static VOID PopulateIPReverseMapAndAccountTraceInstructions(TRACE trace, uint32_t traceKey, uint32_t numInterestingInstInTrace, IsInterestingInsFptr isInterestingIns, const RtnInfo *rinfo)
Definition: cctlib.cpp:1075
static VOID GetFullCallingContextInSitu(ContextHandle_t curCtxtHndle, vector< Context > &contextVec)
Definition: cctlib.cpp:2164
uint64_t unused1
Definition: cctlib.cpp:3410
static void UpdateCurTraceAndIp(ThreadData *tData, TraceNode *const trace)
Definition: cctlib.cpp:549
uint64_t unused
Definition: cctlib.cpp:3386
static bool endsWithExtn(const string &base, const string &ext)
Definition: cctlib.cpp:1582
const char * OSUtil_jobid()
Definition: cctlib.cpp:3555
static void SegvHandler(int)
Definition: cctlib.cpp:1378
uint8_t show
Definition: cctlib.cpp:3408
static void hpcrun_files_init()
Definition: cctlib.cpp:3636
VOID ReleaseLock()
Definition: cctlib.cpp:741
static void spinlock_unlock(spinlock_t *l)
Definition: cctlib.cpp:3734
static const char HPCRUN_FMT_Version[]
Definition: cctlib.cpp:3509
static void UpdateCurTraceOnly(ThreadData *tData, TraceNode *const trace)
Definition: cctlib.cpp:553
int hpcfmt_str_fwrite(const char *str, FILE *outfs)
Definition: cctlib.cpp:3924
void hpcrun_set_metric_info_w_fn(int metric_id, const char *name, size_t period, FILE *fs)
Definition: cctlib.cpp:3753
struct DataHandle_t { uint8_t objectType DataHandle_t
Definition: cctlib.H:32
ContextHandle_t GetContextHandle(const THREADID id, const uint32_t slot)
Definition: cctlib.cpp:1356
static VOID RestoreSigLongJmpCtxt(THREADID threadId)
Definition: cctlib.cpp:572
static VOID ComputeVarBounds(IMG img, VOID *v)
Definition: cctlib.cpp:2894
VOID Fini(INT32 code, VOID *v)
Definition: cctlib.cpp:1944
uint32_t ContextHandle_t
Definition: cctlib.H:22
static bool TraceIsInAddressRange(TraceNode *trace, ADDRINT lo, ADDRINT hi)
Definition: cctlib.cpp:644
char * formula
Definition: cctlib.cpp:3428
int newCCT_hpcrun_selection_write(THREADID threadid)
Definition: cctlib.cpp:4369
static const string & GetModulePathFromInfo(IPNode *ipNode)
Definition: cctlib.cpp:1978
IPNode * GetPINCCTCurrentContext(THREADID id)
Definition: cctlib.cpp:1342
char * format
Definition: cctlib.cpp:3429
static void spinlock_lock(spinlock_t *l)
Definition: cctlib.cpp:3739
volatile bool predecessorWasWriter
Definition: cctlib.cpp:228
static int hpcfmt_intX_fwrite(uint8_t *val, size_t size, FILE *outfs)
Definition: cctlib.cpp:3621
int hpcrun_fmt_hdr_fwrite(FILE *fs, const char *arg1, const char *arg2)
Definition: cctlib.cpp:3918
uint16_t partner
Definition: cctlib.cpp:3407
static struct fileid lateid
Definition: cctlib.cpp:3494
char * GetStringFromStringPool(const uint32_t index)
Definition: cctlib.cpp:802
ContextHandle_t GetTraceStartHandle(ContextHandle_t ctxtHandle)
Definition: cctlib.cpp:3249
static bool IsValidPLTSignature(const ADDRINT &ip)
Definition: cctlib.cpp:2042
static uint32_t GetNextStringPoolIndex(char *name)
Definition: cctlib.cpp:806
static void SerializeCCTNode(TraceNode *traceNode, FILE *const fp)
Definition: cctlib.cpp:1459
struct metric_set_t metric_set_t
Definition: cctlib.cpp:3434
const hpcrun_metricFlags_t hpcrun_metricFlags_NULL
Definition: cctlib.cpp:3472
uint32_t symName
Definition: cctlib.H:35
static uint32_t NO_MORE_TRACE_NODES_IN_SPLAY_TREE
Definition: cctlib.cpp:1457
BOOL(*)(INS) IsInterestingInsFptr
Definition: cctlib.H:65
static void SerializeTraceIps()
Definition: cctlib.cpp:1803
uint OSUtil_pid()
Definition: cctlib.cpp:3549
static const uint32_t default_ra_to_callsite_distance
Definition: cctlib.cpp:3488
struct metric_desc_t { char *name metric_desc_t
Definition: cctlib.cpp:3421
static int log_rename_ret
Definition: cctlib.cpp:3497
union hpcrun_metricFlags_t { hpcrun_metricFlags_fields fields hpcrun_metricFlags_t
Definition: cctlib.cpp:3415
const uint bufSZ
Definition: cctlib.cpp:3513
void tranverseNewCCT(vector< NewIPNode * > nodes, FILE *fs)
Definition: cctlib.cpp:4133
void * address
#define PAGE_OFFSET(addr)
Definition: shadow_memory.H:15
#define SHADOW_PAGE_SIZE
Definition: shadow_memory.H:17
#define PIN_ExitProcess(a)
Definition: shadow_memory.H:35
static void handler(int)
#define REGULAR_SPLAY_TREE(type, root, key, value, left, right)
Definition: splay-macros.h:124
static TraceSplay * splay(TraceSplay *root, uintptr_t key)
void * firstIP
void * secondIP
volatile ContextHandle_t threadCreatorCtxtHndl
Definition: cctlib.cpp:445
uint64_t(* computeMetricVal)(void *metric)
Definition: cctlib.cpp:387
uint64_t curPreAllocatedContextBufferIndex
Definition: cctlib.cpp:436
unordered_map< ADDRINT, RtnInfo > rtnSelfRecMap
Definition: cctlib.cpp:417
xed_state_t cct_xed_state
XED state.
Definition: cctlib.cpp:400
unordered_map< UINT32, ModuleInfo > ModuleInfoMap
Definition: cctlib.cpp:409
CCTLibInstrumentInsCallback userInstrumentationCallback
Definition: cctlib.cpp:396
unordered_map< uint32_t, void * > traceShadowMap
Definition: cctlib.cpp:425
char metrics[MAX_METRICS][MAX_LEN]
Definition: cctlib.cpp:390
volatile uint64_t threadCaptureCount
Definition: cctlib.cpp:441
void(* mergeFunc)(void *des, void *src)
Definition: cctlib.cpp:386
volatile TraceNode * threadCreatorTraceNode
Definition: cctlib.cpp:443
volatile uint64_t threadCreateCount
Definition: cctlib.cpp:439
vector< ThreadData > deserializedCCTs
Definition: cctlib.cpp:423
TraceNode * parentTraceNode
Definition: cctlib.cpp:211
TraceSplay * calleeTraceNodes
Definition: cctlib.cpp:213
TraceSplay * tmpSplay
Definition: cctlib.cpp:3354
vector< NewIPNode * > childIPNodes
Definition: cctlib.cpp:3342
uint64_t * metricVal
Definition: cctlib.cpp:3356
NewIPNode * parentIPNode
Definition: cctlib.cpp:3350
ADDRINT * selfRecReturnAddrs
Definition: cctlib.cpp:376
ADDRINT rtnStart
Definition: cctlib.cpp:373
uint16_t nReturnAddrs
Definition: cctlib.cpp:375
ContextHandle_t childCtxtStartIdx
Definition: cctlib.cpp:199
ContextHandle_t tlsRootCtxtHndl
Definition: cctlib.cpp:245
uint32_t tlsThreadId
Definition: cctlib.cpp:241
ContextHandle_t tlsCurrentChildContextStartIndex
Definition: cctlib.cpp:243
ContextHandle_t tlsParentThreadCtxtHndl
Definition: cctlib.cpp:250
struct TraceNode * tlsCurrentTraceNode
Definition: cctlib.cpp:244
size_t tlsDynamicMemoryAllocationSize
Definition: cctlib.cpp:289
struct TraceNode * tlsPendingHandlerFrame
Definition: cctlib.cpp:282
ContextHandle_t tlsDynamicMemoryAllocationPathHandle
Definition: cctlib.cpp:290
ADDRINT tlsPendingLandingPadIp
Definition: cctlib.cpp:281
ContextHandle_t tlsPendingHandlerCtxt
Definition: cctlib.cpp:283
struct TraceNode * tlsParentThreadTraceNode
Definition: cctlib.cpp:249
ContextHandle_t tlsCurrentCtxtHndl
Definition: cctlib.cpp:242
NewIPNode * tlsHPCRunCCTRoot
Definition: cctlib.cpp:303
ADDRINT tlsLongJmpHoldBuf
Definition: cctlib.cpp:254
struct TraceNode * tlsRootTraceNode
Definition: cctlib.cpp:246
sparse_hash_map< ADDRINT, ContextHandle_t > tlsLongJmpMap
Definition: cctlib.cpp:253
ContextHandle_t childCtxtStartIdx
Definition: cctlib.cpp:191
ContextHandle_t callerCtxtHndl
Definition: cctlib.cpp:190
TraceNode * value
Definition: cctlib.cpp:205
TraceSplay * left
Definition: cctlib.cpp:206
TraceSplay * right
Definition: cctlib.cpp:207
void h()
Definition: test1.c:12
void array()
Definition: testArray.c:7
int a[1000]
Definition: testArray.c:5