a61f01dafd2f0ef7683ed71c822c43b58d5a1658
[charm.git] / src / ck-core / debug-charm.C
1 /*****************************************************************************
2  * A few useful built-in CPD and CCS handlers.
3  *****************************************************************************/
4
5 #include "converse.h"
6
7 #include <errno.h>
8 #include <string.h>
9 #include <sys/stat.h>           // for chmod
10
11 #include "ckhashtable.h"
12 #include "conv-ccs.h"
13 #include "debug-charm.h"
14 #include "sockRoutines.h"
15 #include "charm.h"
16 #include "middle.h"
17 #include "cklists.h"
18 #include "register.h"
19 //#include "queueing.h"
20 #include <unistd.h>
21
22
23 /** Specify if we are replaying the processor from message logs, thus disable delivering of messages */
24 int _replaySystem = 0;
25
26 #if CMK_REPLAYSYSTEM
27
28 int ConverseDeliver() {
29   return !_replaySystem;
30 }
31 #endif
32
33 #if CMK_CCS_AVAILABLE && !defined(_WIN32)
34
35 #include "ck.h"
36
37 CkVec<DebugEntryInfo> _debugEntryTable;
38 CpdPersistentChecker persistentCheckerUselessClass;
39
40 void CpdFinishInitialization() {
41 #ifndef CMK_OPTIMIZE
42   _debugEntryTable.resize(_entryTable.size());
43 #endif
44 }
45
46 extern "C" void resetAllCRC();
47 extern "C" void checkAllCRC(int report);
48
49 typedef struct DebugRecursiveEntry {
50   int previousChareID;
51   int alreadyUserCode;
52   char *memoryBackup;
53   void *obj;
54   void *msg;
55 } DebugRecursiveEntry;
56
57 CkQ<DebugRecursiveEntry> _debugData;
58
59 void *CpdGetCurrentObject() { return _debugData.peek().obj; }
60 void *CpdGetCurrentMsg() { return _debugData.peek().msg; }
61
62 extern int cpdInSystem;
63 extern "C" int CpdInUserCode() {return cpdInSystem==0 && _debugData.length()>0 && _debugData.peek().alreadyUserCode==1;}
64
65 // Function called right before an entry method
66 void CpdBeforeEp(int ep, void *obj, void *msg) {
67 #ifndef CMK_OPTIMIZE
68   if (CpvAccess(cmiArgDebugFlag)) {
69     DebugRecursiveEntry entry;
70     entry.previousChareID = setMemoryChareIDFromPtr(obj);
71     entry.alreadyUserCode = _entryTable[ep]->inCharm ? 0 : 1;
72     entry.memoryBackup = NULL;
73     entry.obj = obj;
74     if (msg != NULL) {
75       entry.msg = msg;
76       CmiReference(UsrToEnv(msg));
77     }
78     else entry.msg = NULL;
79     _debugData.push(entry);
80     setMemoryStatus(entry.alreadyUserCode);
81     //if (_debugEntryTable[ep].isBreakpoint) printf("CpdBeforeEp breakpointed %d\n",ep);
82     memoryBackup = &_debugData.peek().memoryBackup;
83     if (!_entryTable[ep]->inCharm) {
84       CpdResetMemory();
85     }
86     CkVec<DebugPersistentCheck> &preExecutes = _debugEntryTable[ep].preProcess;
87     for (int i=0; i<preExecutes.size(); ++i) {
88       preExecutes[i].object->cpdCheck(preExecutes[i].msg);
89     }
90   }
91 #endif
92 }
93
94 // Function called right after an entry method
95 void CpdAfterEp(int ep) {
96 #ifndef CMK_OPTIMIZE
97   if (CpvAccess(cmiArgDebugFlag)) {
98     DebugRecursiveEntry entry = _debugData.peek();
99     CkVec<DebugPersistentCheck> &postExecutes = _debugEntryTable[ep].postProcess;
100     for (int i=0; i<postExecutes.size(); ++i) {
101       postExecutes[i].object->cpdCheck(postExecutes[i].msg);
102     }
103     memoryBackup = &entry.memoryBackup;
104     if (!_entryTable[ep]->inCharm) {
105       CpdCheckMemory();
106     }
107     if (entry.msg != NULL) CmiFree(UsrToEnv(entry.msg));
108     setMemoryChareID(entry.previousChareID);
109     setMemoryStatus(entry.alreadyUserCode);
110     _debugData.deq();
111   }
112 #endif
113 }
114
115 /************ Array Element CPD Lists ****************/
116
117 /**
118   Count array elements going by until they reach this
119   range (lo to hi), then start passing them to dest.
120 */
121 template <class T>
122 class CkArrayElementRangeIterator : public CkLocIterator {
123 private:
124    T *dest;
125    CkArray *mgr;
126    int cur,lo,hi;
127 public:
128    CkArrayElementRangeIterator(T *dest_,int l,int h)
129         :dest(dest_),mgr(0),cur(0),lo(l),hi(h) {}
130
131   /** Called to iterate only on a specific array manager.
132       Returs the number of objects it iterate on.
133   */
134   int iterate(int start, CkArray *m) {
135     cur = start;
136     mgr = m;
137     mgr->getLocMgr()->iterate(*this);
138     cur -= start;
139     return cur;
140   }
141
142    /** Call add for every in-range array element on this processor */
143    void iterate(void)
144    { /* Walk the groupTable for arrays (FIXME: get rid of _groupIDTable) */
145      int numGroups=CkpvAccess(_groupIDTable)->size();
146      for(int i=0;i<numGroups;i++) {
147         IrrGroup *obj = CkpvAccess(_groupTable)->find((*CkpvAccess(_groupIDTable))[i]).getObj();
148         if (obj->isArrMgr())
149         { /* This is an array manager: examine its array elements */
150           mgr=(CkArray *)obj;
151           mgr->getLocMgr()->iterate(*this);
152         }
153      }
154    }
155
156    // Called by location manager's iterate function
157    virtual void addLocation (CkLocation &loc)
158    {
159      if (cur>=lo && cur<hi)
160      { /* This element is in our range-- look it up */
161        dest->add(cur,mgr->lookup(loc.getIndex()),mgr->getGroupID().idx);
162      }
163      cur++;
164    }
165
166    // Return the number of total array elements seen so far.
167    int getCount(void) {return cur;}
168 };
169
170 /**
171   Count charm++ objects going by until they reach this
172   range (lo to hi), then start passing them to dest.
173 */
174 template <class T>
175 class CkObjectRangeIterator {
176 private:
177    T *dest;
178    int cur,lo,hi;
179 public:
180    CkObjectRangeIterator(T *dest_,int l,int h)
181         :dest(dest_),cur(0),lo(l),hi(h) {}
182
183    /** Call add for every in-range array element on this processor */
184    void iterate(void)
185    { /* Walk the groupTable for arrays (FIXME: get rid of _groupIDTable) */
186      int numGroups=CkpvAccess(_groupIDTable)->size();
187      for(int i=0;i<numGroups;i++) {
188        CkGroupID groupID = (*CkpvAccess(_groupIDTable))[i];
189         IrrGroup *obj = CkpvAccess(_groupTable)->find(groupID).getObj();
190         /*if (obj->isArrMgr())
191         { / * This is an array manager: examine its array elements * /
192           CkArray *mgr=(CkArray *)obj;
193           CkArrayElementRangeIterator<T> ait(dest,lo,hi);
194           ait.iterate(cur, mgr);
195           cur+=ait.getCount();
196         } else {*/
197           dest->add(cur,obj,groupID.idx);
198           cur++;
199         //}
200      }
201    }
202
203    // Return the number of total array elements seen so far.
204    int getCount(void) {return cur;}
205 };
206
207 class ignoreAdd {
208 public: void add(int cur,Chare *elt,int group) {}
209 };
210
211 /** Examine all the objects on the server returning the name */
212 class CpdList_objectNames : public CpdListAccessor {
213   PUP::er *pp; // Only used while inside pup routine.
214   int curGroup;
215 public:
216   virtual const char * getPath(void) const {return "charm/objectNames";}
217   virtual size_t getLength(void) const {
218     CkObjectRangeIterator<ignoreAdd> it(0,0,0);
219     it.iterate();
220     return it.getCount();
221   }
222   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
223     pp=&p;
224     CkObjectRangeIterator<CpdList_objectNames> it(this,req.lo,req.hi);
225     it.iterate(); // calls "add" for in-range elements
226   }
227   void add(int cur, Chare *obj, int group) {
228     PUP::er &p=*pp;
229     beginItem(p,cur);
230     p.comment("id");
231     char *n = (char*)malloc(30);
232     int s=obj->ckDebugChareID(n, 30);
233     CkAssert(s > 0);
234     p(n,s);
235     free(n);
236     PUPn(group);
237     p.comment("name");
238     n=obj->ckDebugChareName();
239     p(n,strlen(n));
240     free(n);
241   }
242 };
243
244 /** Examine a single object identified by the id passed in the request and
245     return its type and memory data */
246 class CpdList_object : public CpdListAccessor {
247   PUP::er *pp; //Only used while inside pup routine.
248   CpdListItemsRequest *reqq; // Only used while inside pup routine.
249 public:
250   virtual const char * getPath(void) const {return "charm/object";}
251   virtual size_t getLength(void) const {
252     CkObjectRangeIterator<ignoreAdd> it(0,0,0);
253     it.iterate();
254     return it.getCount();
255   }
256   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
257     pp=&p;
258     reqq=&req;
259     CkObjectRangeIterator<CpdList_object> it(this,req.lo,req.hi);
260     it.iterate(); // calls "add" for in-range elements;
261   }
262   void add(int cur, Chare *obj, int group) {
263     PUP::er &p=*pp;
264     CpdListItemsRequest &req=*reqq;
265     char *n = (char *)malloc(30);
266     int s=obj->ckDebugChareID(n, 30);
267     CkAssert(s > 0);
268     if (req.extraLen == s && memcmp(req.extra, n, s) == 0) {
269       // the object match, found!
270       beginItem(p,cur);
271       int type = obj->ckGetChareType();
272       p.comment("type");
273       const char *t = _chareTable[type]->name;
274       p((char*)t,strlen(t));
275       p.comment("value");
276       int size = _chareTable[type]->size;
277       p((char*)obj,size);
278     }
279   }
280 };
281
282 /** Coarse: examine array element names */
283 class CpdList_arrayElementNames : public CpdListAccessor {
284   PUP::er *pp; // Only used while inside pup routine.
285 public:
286   virtual const char * getPath(void) const {return "charm/arrayElementNames";}
287   virtual size_t getLength(void) const {
288     CkArrayElementRangeIterator<ignoreAdd> it(0,0,0);
289     it.iterate();
290     return it.getCount();
291   }
292   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
293     pp=&p;
294     CkArrayElementRangeIterator<CpdList_arrayElementNames> it(this,req.lo,req.hi);
295     it.iterate(); // calls "add" for in-range elements
296   }
297   void add(int cur,Chare *e,int group)
298   { // Just grab the name and nothing else:
299     ArrayElement *elt = (ArrayElement*)e;
300          PUP::er &p=*pp;
301          beginItem(p,cur);
302          p.comment("name");
303          char *n=elt->ckDebugChareName();
304          p(n,strlen(n));
305          free(n);
306   }
307 };
308
309 /** Detailed: examine array element data */
310 class CpdList_arrayElements : public CpdListAccessor {
311   PUP::er *pp; // Only used while inside pup routine.
312 public:
313   virtual const char * getPath(void) const {return "charm/arrayElements";}
314   virtual size_t getLength(void) const {
315     CkArrayElementRangeIterator<ignoreAdd> it(0,0,0);
316     it.iterate();
317     return it.getCount();
318   }
319   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
320     pp=&p;
321     CkArrayElementRangeIterator<CpdList_arrayElements> it(this,req.lo,req.hi);
322     it.iterate(); // calls "add" for in-range elements
323   }
324   void add(int cur, Chare *e, int group)
325   { // Pup the element data
326     ArrayElement *elt = (ArrayElement*)e;
327     PUP::er &p=*pp;
328     beginItem(p,cur);
329     //elt->ckDebugPup(p);
330     // Now ignore any pupper, just copy all the memory as raw data
331     p.comment("name");
332     char *n=elt->ckDebugChareName();
333     p(n,strlen(n));
334     free(n);
335     int type = elt->ckGetChareType();
336     p.comment("type");
337     const char *t = _chareTable[type]->name;
338     p((char*)t,strlen(t));
339     p.comment("value");
340     int size = _chareTable[type]->size;
341     p((char*)elt,size);
342   }
343 };
344
345 #ifndef __CYGWIN__
346 #include <rpc/rpc.h>
347 #endif
348
349 size_t hostInfoLength(void *) {return 1;}
350
351 void hostInfo(void *itemIter, pup_er pp, CpdListItemsRequest *req) {
352   PUP::er &p = *(PUP::er *)pp;
353   struct sockaddr_in addr;
354   CpdListBeginItem(pp, 0);
355 #if CMK_HAS_GET_MYADDRESS
356   get_myaddress(&addr);
357 #else
358   CmiAbort("hostInfo: get_myaddress does not work on this machine");
359 #endif
360   char *address = (char*)&addr.sin_addr.s_addr;
361   PUPv(address, 4);
362   int pid = getpid();
363   PUPn(pid);
364 }
365
366 /************ Message CPD Lists ****************/
367 CkpvExtern(void *,debugQueue);
368 CpvCExtern(int, skipBreakpoint);
369
370 // Interpret data in a message in a user-friendly way.
371 //  Ignores most of the envelope fields used by CkPupMessage,
372 //  and instead concentrates on user data
373 void CpdPupMessage(PUP::er &p, void *msg)
374 {
375   envelope *env=UsrToEnv(msg);
376   //int wasPacked=env->isPacked();
377   int size=env->getTotalsize();
378   int prioBits=env->getPriobits();
379   int from=env->getSrcPe();
380   PUPn(from);
381   //PUPn(wasPacked);
382   PUPn(prioBits);
383   int userSize=size-sizeof(envelope)-sizeof(int)*CkPriobitsToInts(prioBits);
384   PUPn(userSize);
385   int msgType = env->getMsgIdx();
386   PUPn(msgType);
387   int envType = env->getMsgtype();
388   PUPn(envType);
389
390   //p.synchronize(PUP::sync_last_system);
391
392   int ep=CkMessageToEpIdx(msg);
393   PUPn(ep);
394
395   // Pup the information specific to this envelope type
396   if (envType == ForArrayEltMsg || envType == ArrayEltInitMsg) {
397     int arrID = env->getsetArrayMgr().idx;
398     PUPn(arrID);
399     CkArrayIndexStruct &idx = *(CkArrayIndexStruct *)&env->getsetArrayIndex();
400     int nInts = idx.nInts;
401     int dimension = idx.dimension;
402     PUPn(nInts);
403     PUPn(dimension);
404     p.comment("index");
405     if (dimension >=4 && dimension <=6) {
406       p((short int *)idx.index, dimension);
407     } else {
408       p(idx.index, nInts);
409     }
410   } else if (envType == BocInitMsg || envType == NodeBocInitMsg ||
411              envType == ForNodeBocMsg || envType == ForBocMsg) {
412     int groupID = env->getGroupNum().idx;
413     PUPn(groupID);
414   } else if (envType == NewVChareMsg || envType == ForVidMsg || envType == FillVidMsg) {
415     p.comment("ptr");
416     void *ptr = env->getVidPtr();
417     pup_pointer(&p, &ptr);
418   } else if (envType == ForChareMsg) {
419     p.comment("ptr");
420     void *ptr = env->getObjPtr();
421     pup_pointer(&p, &ptr);
422   }
423   
424   /* user data */
425   p.comment("data");
426   p.synchronize(PUP::sync_begin_object);
427   if (_entryTable[ep]->messagePup!=NULL)
428     _entryTable[ep]->messagePup(p,msg);
429   else
430     CkMessage::ckDebugPup(p,msg);
431   p.synchronize(PUP::sync_end_object);
432 }
433
434 CkpvStaticDeclare(void *, lastBreakPointMsg);
435
436 //Cpd Lists for local and scheduler queues
437 class CpdList_localQ : public CpdListAccessor {
438
439 public:
440   CpdList_localQ() {}
441   virtual const char * getPath(void) const {return "converse/localqueue";}
442   virtual size_t getLength(void) const {
443     int x = CdsFifo_Length((CdsFifo)(CkpvAccess(debugQueue)));
444     //CmiPrintf("*******Returning fifo length %d*********\n", x);
445     //return CdsFifo_Length((CdsFifo)(CpvAccess(CmiLocalQueue)));
446     if (CkpvAccess(lastBreakPointMsg) != NULL) x++;
447     return x;
448   }
449   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
450     int length = CdsFifo_Length((CdsFifo)(CkpvAccess(debugQueue)));
451     void ** messages = CdsFifo_Enumerate(CkpvAccess(debugQueue));
452     int curObj=0;
453
454     if (CkpvAccess(lastBreakPointMsg) != NULL) {
455       beginItem(p, -1);
456       envelope *env=(envelope *)UsrToEnv(CkpvAccess(lastBreakPointMsg));
457       p.comment("name");
458       char *type=(char*)"Breakpoint";
459       p(type,strlen(type));
460       p.comment("charmMsg");
461       p.synchronize(PUP::sync_begin_object);
462       CkUnpackMessage(&env);
463       CpdPupMessage(p, EnvToUsr(env));
464       p.synchronize(PUP::sync_end_object);
465     }
466
467     for(curObj=req.lo; curObj<req.hi; curObj++)
468       if ((curObj>=0) && (curObj<length))
469       {
470         beginItem(p,curObj);
471         void *msg=messages[curObj]; /* converse message */
472         int isCharm=0;
473         const char *type="Converse";
474         p.comment("name");
475         char name[128];
476 #if ! CMK_BLUEGENE_CHARM
477         if (CmiGetHandler(msg)==_charmHandlerIdx) {isCharm=1; type="Local Charm";}
478         if (CmiGetXHandler(msg)==_charmHandlerIdx) {isCharm=1; type="Network Charm";}
479 #else
480         isCharm=1; type="BG";
481 #endif
482         sprintf(name,"%s %d: %s (%d)","Message",curObj,type,CmiGetHandler(msg));
483         p(name, strlen(name));
484
485         if (isCharm)
486         { /* charm message */
487           p.comment("charmMsg");
488           p.synchronize(PUP::sync_begin_object);
489           envelope *env=(envelope *)msg;
490           CkUnpackMessage(&env);
491           messages[curObj]=env;
492           CpdPupMessage(p, EnvToUsr(env));
493           //CkPupMessage(p, &messages[curObj], 0);
494           p.synchronize(PUP::sync_end_object);
495         }
496       }
497     delete[] messages;
498
499   }
500 };
501
502 class CpdList_message : public CpdListAccessor {
503   virtual const char * getPath(void) const {return "converse/message";}
504   virtual size_t getLength(void) const {return 1;}
505   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
506     envelope *env = (envelope*)(((unsigned int)req.lo) + (((unsigned long)req.hi)<<32)+sizeof(CmiChunkHeader));
507     beginItem(p, 0);
508     const char *type="Converse";
509     p.comment("name");
510     char name[128];
511     if (CmiGetHandler(env)==_charmHandlerIdx) {type="Local Charm";}
512     if (CmiGetXHandler(env)==_charmHandlerIdx) {type="Network Charm";}
513     sprintf(name,"%s 0: %s (%d)","Message",type,CmiGetHandler(env));
514     p(name, strlen(name));
515     p.comment("charmMsg");
516     p.synchronize(PUP::sync_begin_object);
517     CpdPupMessage(p, EnvToUsr(env));
518     p.synchronize(PUP::sync_end_object);
519   }
520 };
521
522 class CpdList_msgStack : public CpdListAccessor {
523   virtual const char * getPath(void) const {return "charm/messageStack";}
524   virtual size_t getLength(void) const {
525     return _debugData.length();
526   }
527   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
528     for (int i=0; i<_debugData.length(); ++i) {
529       beginItem(p, i);
530       void *obj = _debugData[i].obj;
531       p.comment("obj");
532       pup_pointer(&p, &obj);
533       void *msg = _debugData[i].msg;
534       p.comment("msg");
535       pup_pointer(&p, &msg);
536     }
537   }
538 };
539
540 /****************** Breakpoints and other debug support **************/
541
542 typedef CkHashtableTslow<int,EntryInfo *> CpdBpFuncTable_t;
543
544
545 extern void CpdFreeze(void);
546 extern void CpdUnFreeze(void);
547 extern int  CpdIsFrozen(void);
548
549 CpvStaticDeclare(int, _debugMsg);
550 CpvStaticDeclare(int, _debugChare);
551
552 CkpvStaticDeclare(CpdBpFuncTable_t *, breakPointEntryTable);
553
554 //CpvStaticDeclare(void *, lastBreakPointMsg);
555 CkpvStaticDeclare(void *, lastBreakPointObject);
556 CkpvStaticDeclare(int, lastBreakPointIndex);
557
558 void CpdBreakPointInit()
559 {
560   CkpvInitialize(void *, lastBreakPointMsg);
561   CkpvInitialize(void *, lastBreakPointObject);
562   CkpvInitialize(int, lastBreakPointIndex);
563   CpvInitialize(int, _debugMsg);
564   CpvInitialize(int, _debugChare);
565   CkpvInitialize(CpdBpFuncTable_t *, breakPointEntryTable);
566   CkpvAccess(lastBreakPointMsg) = NULL;
567   CkpvAccess(lastBreakPointObject) = NULL;
568   CkpvAccess(lastBreakPointIndex) = 0;
569   CpvAccess(_debugMsg) = CkRegisterMsg("debug_msg",0,0,0,0);
570   CpvAccess(_debugChare) = CkRegisterChare("debug_Chare",0,TypeChare);
571   CkRegisterChareInCharm(CpvAccess(_debugChare));
572   CkpvAccess(breakPointEntryTable) = new CpdBpFuncTable_t(10,0.5,CkHashFunction_int,CkHashCompare_int );
573 }
574
575 #if CMK_BLUEGENE_CHARM
576 #include "blue_impl.h"
577 #endif
578
579 static void _call_freeze_on_break_point(void * msg, void * object)
580 {
581       //Save breakpoint entry point index. This is retrieved from msg.
582       //So that the appropriate EntryInfo can be later retrieved from the hash table
583       //of break point function entries, on continue.
584
585   // If the counter "skipBreakpoint" is not zero we actually do not freeze and deliver the regular message
586   if (CpvAccess(skipBreakpoint) > 0) {
587     EntryInfo * breakPointEntryInfo = CkpvAccess(breakPointEntryTable)->get(CkMessageToEpIdx(msg));
588     CkAssert(breakPointEntryInfo != NULL);
589     breakPointEntryInfo->call(msg, object);
590     CpvAccess(skipBreakpoint) --;
591   } else {
592       CkpvAccess(lastBreakPointMsg) = msg;
593       CkpvAccess(lastBreakPointObject) = object;
594       CkpvAccess(lastBreakPointIndex) = CkMessageToEpIdx(msg);
595       EntryInfo * breakPointEntryInfo = CkpvAccess(breakPointEntryTable)->get(CkpvAccess(lastBreakPointIndex));
596       CpdNotify(CPD_BREAKPOINT,breakPointEntryInfo->name);
597       CpdFreeze();
598 #if CMK_BLUEGENE_CHARM
599       stopVTimer();
600       ((workThreadInfo*)cta(threadinfo))->scheduler(-1);
601 #endif
602   }
603 }
604
605 //ccs handler when pressed the "next" command: deliver only a single message without unfreezing
606 extern "C"
607 void CpdDeliverSingleMessage () {
608   if (!CpdIsFrozen()) return; /* Do something only if we are in freeze mode */
609   if ( (CkpvAccess(lastBreakPointMsg) != NULL) && (CkpvAccess(lastBreakPointObject) != NULL) ) {
610     EntryInfo * breakPointEntryInfo = CkpvAccess(breakPointEntryTable)->get(CkpvAccess(lastBreakPointIndex));
611     if (breakPointEntryInfo != NULL) {
612       breakPointEntryInfo->call(CkpvAccess(lastBreakPointMsg), CkpvAccess(lastBreakPointObject));
613     }
614     CkpvAccess(lastBreakPointMsg) = NULL;
615     CkpvAccess(lastBreakPointObject) = NULL;
616 #if CMK_BLUEGENE_CHARM
617     ((workThreadInfo*)cta(threadinfo))->stopScheduler();
618 #endif
619   }
620   else {
621     // we were not stopped at a breakpoint, then deliver the first message in the debug queue
622     if (!CdsFifo_Empty(CkpvAccess(debugQueue))) {
623       CpvAccess(skipBreakpoint) = 1;
624       char *queuedMsg = (char *)CdsFifo_Dequeue(CkpvAccess(debugQueue));
625 #if CMK_BLUEGENE_CHARM
626       BgProcessMessageDefault(cta(threadinfo), queuedMsg);
627 #else
628       CmiHandleMessage(queuedMsg);
629 #endif
630       CpvAccess(skipBreakpoint) = 0;
631     }
632   }
633 }
634
635 //ccs handler when continue from a break point
636 extern "C"
637 void CpdContinueFromBreakPoint ()
638 {
639     CpdUnFreeze();
640     if ( (CkpvAccess(lastBreakPointMsg) != NULL) && (CkpvAccess(lastBreakPointObject) != NULL) )
641     {
642         EntryInfo * breakPointEntryInfo = CkpvAccess(breakPointEntryTable)->get(CkpvAccess(lastBreakPointIndex));
643         if (breakPointEntryInfo != NULL) {
644            breakPointEntryInfo->call(CkpvAccess(lastBreakPointMsg), CkpvAccess(lastBreakPointObject));
645 #if CMK_BLUEGENE_CHARM
646            ((workThreadInfo*)cta(threadinfo))->stopScheduler();
647 #endif
648         } else {
649           // This means that the breakpoint got deleted in the meanwhile
650           
651         }
652     }
653     CkpvAccess(lastBreakPointMsg) = NULL;
654     CkpvAccess(lastBreakPointObject) = NULL;
655 }
656
657 //ccs handler to set a breakpoint with entry function name msg
658 void CpdSetBreakPoint (char *msg)
659 {
660   char functionName[128];
661   int tableSize, tableIdx = 0;
662   int reply = 0;
663   sscanf(msg+CmiReservedHeaderSize, "%s", functionName);
664   if (strlen(functionName) > 0)
665   {
666     tableSize = _entryTable.size();
667     // Replace entry in entry table with _call_freeze_on_break_point
668     // retrieve epIdx for entry method
669     //for (tableIdx=0; tableIdx < tableSize; tableIdx++)
670     //{
671        //if (strstr(_entryTable[tableIdx]->name, functionName) != NULL)
672        //{
673     tableIdx = atoi(functionName);
674     if (tableIdx >= 0 && tableIdx < tableSize) {
675            EntryInfo * breakPointEntryInfo = (EntryInfo *)CkpvAccess(breakPointEntryTable)->get(tableIdx);
676            delete breakPointEntryInfo;
677            breakPointEntryInfo = new EntryInfo(_entryTable[tableIdx]->name, _entryTable[tableIdx]->call, _entryTable[tableIdx]->msgIdx, _entryTable[tableIdx]->chareIdx );
678            //CmiPrintf("Breakpoint is set for function %s with an epIdx = %ld\n", _entryTable[tableIdx]->name, tableIdx);
679            CkpvAccess(breakPointEntryTable)->put(tableIdx) = breakPointEntryInfo;
680            _entryTable[tableIdx]->name = "debug_breakpoint_ep";
681            _entryTable[tableIdx]->call = (CkCallFnPtr)_call_freeze_on_break_point;
682            //_entryTable[tableIdx]->msgIdx = CpvAccess(_debugMsg);
683            //_entryTable[tableIdx]->chareIdx = CpvAccess(_debugChare);
684            //_debugEntryTable[tableIdx].isBreakpoint = CmiTrue;
685            //break;
686            reply = ~0;
687            //}
688     }
689     //if (tableIdx == tableSize)
690     //{
691     //  CmiPrintf("[ERROR]Entrypoint was not found for function %s\n", functionName);
692     //  return;
693     //}
694
695   }
696   CcsSendReply(sizeof(int), (void*)&reply);
697
698 }
699
700 void CpdQuitDebug()
701 {
702   CpdContinueFromBreakPoint();
703   CkExit();
704 }
705
706 void CpdRemoveBreakPoint (char *msg)
707 {
708   char functionName[128];
709   int reply = 0;
710   sscanf(msg+CmiReservedHeaderSize, "%s", functionName);
711   if (strlen(functionName) > 0) {
712     int idx = atoi(functionName);
713     if (idx >= 0 && idx < _entryTable.size()) {
714       //CmiPrintf("[ERROR]Entrypoint was not found for function %s\n", functionName);
715       //void *objPointer;
716       //void *keyPointer;
717       //CkHashtableIterator *it = CkpvAccess(breakPointEntryTable)->iterator();
718       //while(NULL!=(objPointer = it->next(&keyPointer)))
719       //{
720       //EntryInfo * breakPointEntryInfo = *(EntryInfo **)objPointer;
721       EntryInfo * breakPointEntryInfo = CkpvAccess(breakPointEntryTable)->get(idx);
722       if (breakPointEntryInfo != NULL) {
723         _entryTable[idx]->name =  breakPointEntryInfo->name;
724         _entryTable[idx]->call = (CkCallFnPtr)breakPointEntryInfo->call;
725         _entryTable[idx]->msgIdx = breakPointEntryInfo->msgIdx;
726         _entryTable[idx]->chareIdx = breakPointEntryInfo->chareIdx;
727         reply = ~0 ;
728         //_debugEntryTable[idx].isBreakpoint = CmiFalse;
729         //CmiPrintf("Breakpoint is removed for function %s with epIdx %ld\n", _entryTable[idx]->name, idx);
730         //CkpvAccess(breakPointEntryTable)->remove(idx);
731       }
732     }
733   }
734   CcsSendReply(sizeof(int), (void*)&reply);
735 }
736
737 void CpdRemoveAllBreakPoints ()
738 {
739   //all breakpoints removed
740   void *objPointer;
741   void *keyPointer;
742   int reply = 1;
743   CkHashtableIterator *it = CkpvAccess(breakPointEntryTable)->iterator();
744   while(NULL!=(objPointer = it->next(&keyPointer)))
745   {
746     EntryInfo * breakPointEntryInfo = *(EntryInfo **)objPointer;
747     int idx = *(int *)keyPointer;
748     _entryTable[idx]->name =  breakPointEntryInfo->name;
749     _entryTable[idx]->call = (CkCallFnPtr)breakPointEntryInfo->call;
750     _entryTable[idx]->msgIdx = breakPointEntryInfo->msgIdx;
751     _entryTable[idx]->chareIdx = breakPointEntryInfo->chareIdx;
752   }
753   CcsSendReply(sizeof(int), (void*)&reply);
754 }
755
756 extern "C" int CpdIsCharmDebugMessage(void *msg) {
757   envelope *env = (envelope*)msg;
758   // Later should use "isDebug" value, but for now just bypass all intrinsic EPs
759   return CmiGetHandler(msg) != _charmHandlerIdx || env->getMsgtype() == ForVidMsg ||
760          env->getMsgtype() == FillVidMsg || _entryTable[env->getEpIdx()]->inCharm;
761 }
762
763 CpvExtern(int, _bgCcsHandlerIdx);
764 extern "C" int CpdIsBgCharmDebugMessage(void *msg) {
765   envelope *env = (envelope*)msg;
766   return (((CmiBlueGeneMsgHeader*)msg)->hID) == CpvAccess(_bgCcsHandlerIdx) || env->getMsgtype() == ForVidMsg ||
767          env->getMsgtype() == FillVidMsg || _entryTable[env->getEpIdx()]->inCharm;
768 }
769
770 CpvExtern(char *, displayArgument);
771
772 void CpdStartGdb(void)
773 {
774 #if !defined(_WIN32) || defined(__CYGWIN__)
775   FILE *f;
776   char gdbScript[200];
777   int pid;
778   if (CpvAccess(displayArgument) != NULL)
779   {
780      /*CmiPrintf("MY NODE IS %d  and process id is %d\n", CmiMyPe(), getpid());*/
781      sprintf(gdbScript, "/tmp/cpdstartgdb.%d.%d", getpid(), CmiMyPe());
782      f = fopen(gdbScript, "w");
783      fprintf(f,"#!/bin/sh\n");
784      fprintf(f,"cat > /tmp/start_gdb.$$ << END_OF_SCRIPT\n");
785      fprintf(f,"shell /bin/rm -f /tmp/start_gdb.$$\n");
786      //fprintf(f,"handle SIGPIPE nostop noprint\n");
787      fprintf(f,"handle SIGWINCH nostop noprint\n");
788      fprintf(f,"handle SIGWAITING nostop noprint\n");
789      fprintf(f, "attach %d\n", getpid());
790      fprintf(f,"END_OF_SCRIPT\n");
791      fprintf(f, "DISPLAY='%s';export DISPLAY\n",CpvAccess(displayArgument));
792      fprintf(f,"/usr/X11R6/bin/xterm ");
793      fprintf(f," -title 'Node %d ' ",CmiMyPe());
794      fprintf(f," -e /usr/bin/gdb -x /tmp/start_gdb.$$ \n");
795      fprintf(f, "exit 0\n");
796      fclose(f);
797      if( -1 == chmod(gdbScript, 0755))
798      {
799         CmiPrintf("ERROR> chmod on script failed!\n");
800         return;
801      }
802      pid = fork();
803      if (pid < 0)
804         { perror("ERROR> forking to run debugger script\n"); exit(1); }
805      if (pid == 0)
806      {
807          //CmiPrintf("In child process to start script %s\n", gdbScript);
808  if (-1 == execvp(gdbScript, NULL))
809             CmiPrintf ("Error> Could not Execute Debugger Script: %s\n",strerror
810 (errno));
811
812       }
813     }
814 #endif
815 }
816
817 extern "C" {
818   size_t cpd_memory_length(void*);
819   void cpd_memory_pup(void*,void*,CpdListItemsRequest*);
820   void cpd_memory_leak(void*,void*,CpdListItemsRequest*);
821   size_t cpd_memory_getLength(void*);
822   void cpd_memory_get(void*,void*,CpdListItemsRequest*);
823 }
824
825
826 void CpdCharmInit()
827 {
828   CpdListRegister(new CpdListAccessor_c("converse/memory",cpd_memory_length,0,cpd_memory_pup,0));
829   //CpdListRegister(new CpdListAccessor_c("converse/memory/leak",cpd_memory_length,0,cpd_memory_leak,0));
830   CpdListRegister(new CpdListAccessor_c("converse/memory/data",cpd_memory_getLength,0,cpd_memory_get,0,false));
831
832   //CpdBreakPointInit();
833   CcsRegisterHandler("ccs_set_break_point",(CmiHandler)CpdSetBreakPoint);
834   CcsSetMergeFn("ccs_set_break_point",CcsMerge_logical_and);
835   CcsRegisterHandler("ccs_remove_break_point",(CmiHandler)CpdRemoveBreakPoint);
836   CcsSetMergeFn("ccs_remove_break_point",CcsMerge_logical_and);
837   CcsRegisterHandler("ccs_remove_all_break_points",(CmiHandler)CpdRemoveAllBreakPoints);
838   CcsSetMergeFn("ccs_remove_all_break_points",CmiReduceMergeFn_random);
839   CcsRegisterHandler("ccs_continue_break_point",(CmiHandler)CpdContinueFromBreakPoint);
840   CcsRegisterHandler("ccs_single_step",(CmiHandler)CpdDeliverSingleMessage);
841   CcsRegisterHandler("ccs_debug_quit",(CmiHandler)CpdQuitDebug);
842   CcsRegisterHandler("ccs_debug_startgdb",(CmiHandler)CpdStartGdb);
843   CpdListRegister(new CpdListAccessor_c("hostinfo",hostInfoLength,0,hostInfo,0));
844   CpdListRegister(new CpdList_localQ());
845   CpdListRegister(new CpdList_arrayElementNames());
846   CpdListRegister(new CpdList_arrayElements());
847   CpdListRegister(new CpdList_objectNames());
848   CpdListRegister(new CpdList_object());
849   CpdListRegister(new CpdList_message());
850   CpdListRegister(new CpdList_msgStack());
851   CpdIsDebugMessage = CpdIsCharmDebugMessage;
852 #if CMK_BLUEGENE_CHARM
853   CpdIsDebugMessage = CpdIsBgCharmDebugMessage;
854 #endif
855 }
856
857 #else
858
859 void CpdCharmInit() {}
860
861 void CpdFinishInitialization() {}
862
863 void *CpdGetCurrentObject() {return NULL;}
864 void *CpdGetCurrentMsg() {return NULL;}
865
866 void CpdBeforeEp(int ep, void *obj, void *msg) {}
867 void CpdAfterEp(int ep) {}
868
869 #endif /*CMK_CCS_AVAILABLE*/