rpc.h does not exisit for cygwin and win32 build.
[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
21 #if CMK_CCS_AVAILABLE && !defined(_WIN32)
22
23 #include "ck.h"
24
25
26 /************ Array Element CPD Lists ****************/
27
28 /**
29   Count array elements going by until they reach this 
30   range (lo to hi), then start passing them to dest.
31 */
32 template <class T>
33 class CkArrayElementRangeIterator : public CkLocIterator {
34 private:
35    T *dest;
36    CkArray *mgr;
37    int cur,lo,hi;
38 public:
39    CkArrayElementRangeIterator(T *dest_,int l,int h) 
40         :dest(dest_),mgr(0),cur(0),lo(l),hi(h) {}
41    
42   /** Called to iterate only on a specific array manager.
43       Returs the number of objects it iterate on.
44   */
45   int iterate(int start, CkArray *m) {
46     cur = start;
47     mgr = m;
48     mgr->getLocMgr()->iterate(*this);
49     cur -= start;
50     return cur;
51   }
52
53    /** Call add for every in-range array element on this processor */
54    void iterate(void)
55    { /* Walk the groupTable for arrays (FIXME: get rid of _groupIDTable) */
56      int numGroups=CkpvAccess(_groupIDTable)->size();
57      for(int i=0;i<numGroups;i++) {
58         IrrGroup *obj = CkpvAccess(_groupTable)->find((*CkpvAccess(_groupIDTable))[i]).getObj();
59         if (obj->isArrMgr()) 
60         { /* This is an array manager: examine its array elements */
61           mgr=(CkArray *)obj;
62           mgr->getLocMgr()->iterate(*this);
63         }
64      }
65    }
66    
67    // Called by location manager's iterate function
68    virtual void addLocation (CkLocation &loc)
69    {
70      if (cur>=lo && cur<hi) 
71      { /* This element is in our range-- look it up */
72        dest->add(cur,mgr->lookup(loc.getIndex()));
73      }
74      cur++;
75    }
76    
77    // Return the number of total array elements seen so far.
78    int getCount(void) {return cur;}
79 };
80
81 /**
82   Count charm++ objects going by until they reach this 
83   range (lo to hi), then start passing them to dest.
84 */
85 template <class T>
86 class CkObjectRangeIterator {
87 private:
88    T *dest;
89    int cur,lo,hi;
90 public:
91    CkObjectRangeIterator(T *dest_,int l,int h) 
92         :dest(dest_),cur(0),lo(l),hi(h) {}
93    
94    /** Call add for every in-range array element on this processor */
95    void iterate(void)
96    { /* Walk the groupTable for arrays (FIXME: get rid of _groupIDTable) */
97      int numGroups=CkpvAccess(_groupIDTable)->size();
98      for(int i=0;i<numGroups;i++) {
99         IrrGroup *obj = CkpvAccess(_groupTable)->find((*CkpvAccess(_groupIDTable))[i]).getObj();
100         if (obj->isArrMgr()) 
101         { /* This is an array manager: examine its array elements */
102           CkArray *mgr=(CkArray *)obj;
103           CkArrayElementRangeIterator<T> ait(dest,lo,hi);
104           ait.iterate(cur, mgr);
105           cur+=ait.getCount();
106         } else {
107           dest->add(cur,obj);
108           cur++;
109         }
110      }
111    }
112    
113    // Return the number of total array elements seen so far.
114    int getCount(void) {return cur;}
115 };
116
117 class ignoreAdd {
118 public: void add(int cur,Chare *elt) {}
119 };
120
121 /** Examine all the objects on the server returning the name */
122 class CpdList_objectNames : public CpdListAccessor {
123   PUP::er *pp; // Only used while inside pup routine.
124   int curGroup;
125 public:
126   virtual const char * getPath(void) const {return "charm/objectNames";}
127   virtual int getLength(void) const {
128     CkObjectRangeIterator<ignoreAdd> it(0,0,0);
129     it.iterate();
130     return it.getCount();
131   }
132   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
133     pp=&p;
134     CkObjectRangeIterator<CpdList_objectNames> it(this,req.lo,req.hi);
135     it.iterate(); // calls "add" for in-range elements
136   }
137   void add(int cur, Chare *obj) {
138     PUP::er &p=*pp;
139     beginItem(p,cur);
140     p.comment("id");
141     char *n = (char*)malloc(30);
142     int s=obj->ckDebugChareID(n, 30);
143     CkAssert(s > 0);
144     p(n,s);
145     free(n);
146     p.comment("name");
147     n=obj->ckDebugChareName();
148     p(n,strlen(n));
149     free(n);
150   }
151 };
152
153 /** Examine a single object identified by the id passed in the request and
154     return its type and memory data */
155 class CpdList_object : public CpdListAccessor {
156   PUP::er *pp; //Only used while inside pup routine.
157   CpdListItemsRequest *reqq; // Only used while inside pup routine.
158 public:
159   virtual const char * getPath(void) const {return "charm/object";}
160   virtual int getLength(void) const {
161     CkObjectRangeIterator<ignoreAdd> it(0,0,0);
162     it.iterate();
163     return it.getCount();
164   }
165   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
166     pp=&p;
167     reqq=&req;
168     CkObjectRangeIterator<CpdList_object> it(this,req.lo,req.hi);
169     it.iterate(); // calls "add" for in-range elements;
170   }
171   void add(int cur, Chare *obj) {
172     PUP::er &p=*pp;
173     CpdListItemsRequest &req=*reqq;
174     char *n = (char *)malloc(30);
175     int s=obj->ckDebugChareID(n, 30);
176     CkAssert(s > 0);
177     if (req.extraLen == s && memcmp(req.extra, n, s) == 0) {
178       // the object match, found!
179       beginItem(p,cur);
180       int type = obj->ckGetChareType();
181       p.comment("type");
182       const char *t = _chareTable[type]->name;
183       p((char*)t,strlen(t));
184       p.comment("value");
185       int size = _chareTable[type]->size;
186       p((char*)obj,size);
187     }
188   }
189 };
190
191 /** Coarse: examine array element names */
192 class CpdList_arrayElementNames : public CpdListAccessor {
193   PUP::er *pp; // Only used while inside pup routine.
194 public:
195   virtual const char * getPath(void) const {return "charm/arrayElementNames";}
196   virtual int getLength(void) const {
197     CkArrayElementRangeIterator<ignoreAdd> it(0,0,0);
198     it.iterate();
199     return it.getCount();
200   }
201   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
202     pp=&p;
203     CkArrayElementRangeIterator<CpdList_arrayElementNames> it(this,req.lo,req.hi);
204     it.iterate(); // calls "add" for in-range elements
205   }
206   void add(int cur,Chare *e) 
207   { // Just grab the name and nothing else:
208     ArrayElement *elt = (ArrayElement*)e;
209          PUP::er &p=*pp;
210          beginItem(p,cur);
211          p.comment("name");
212          char *n=elt->ckDebugChareName();
213          p(n,strlen(n));
214          free(n);
215   }
216 };
217
218 /** Detailed: examine array element data */
219 class CpdList_arrayElements : public CpdListAccessor {
220   PUP::er *pp; // Only used while inside pup routine.
221 public:
222   virtual const char * getPath(void) const {return "charm/arrayElements";}
223   virtual int getLength(void) const {
224     CkArrayElementRangeIterator<ignoreAdd> it(0,0,0);
225     it.iterate();
226     return it.getCount();
227   }
228   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
229     pp=&p;
230     CkArrayElementRangeIterator<CpdList_arrayElements> it(this,req.lo,req.hi);
231     it.iterate(); // calls "add" for in-range elements
232   }
233   void add(int cur, Chare *e) 
234   { // Pup the element data
235     ArrayElement *elt = (ArrayElement*)e;
236     PUP::er &p=*pp;
237     beginItem(p,cur);
238     //elt->ckDebugPup(p);
239     // Now ignore any pupper, just copy all the memory as raw data
240     p.comment("name");
241     char *n=elt->ckDebugChareName();
242     p(n,strlen(n));
243     free(n);
244     int type = elt->ckGetChareType();
245     p.comment("type");
246     const char *t = _chareTable[type]->name;
247     p((char*)t,strlen(t));
248     p.comment("value");
249     int size = _chareTable[type]->size;
250     p((char*)elt,size);
251   }
252 };
253
254 #ifndef __CYGWIN__
255 #include <rpc/rpc.h>
256 #endif
257
258 int hostInfoLength(void *) {return 1;}
259
260 void hostInfo(void *itemIter, pup_er pp, CpdListItemsRequest *req) {
261   PUP::er &p = *(PUP::er *)pp;
262   struct sockaddr_in addr;
263   CpdListBeginItem(pp, 0);
264 #if CMK_HAS_GET_MYADDRESS
265   get_myaddress(&addr);
266 #else
267   CmiAbort("hostInfo: get_myaddress does not work on this machine");
268 #endif
269   char *address = (char*)&addr.sin_addr.s_addr;
270   PUPv(address, 4);
271   int pid = getpid();
272   PUPn(pid);
273 }
274
275 /************ Message CPD Lists ****************/
276 CpvCExtern(void *,debugQueue);
277
278 // Interpret data in a message in a user-friendly way.
279 //  Ignores most of the envelope fields used by CkPupMessage,
280 //  and instead concentrates on user data
281 void CpdPupMessage(PUP::er &p, void *msg)
282 {
283   envelope *env=UsrToEnv(msg);
284   //int wasPacked=env->isPacked();
285   int size=env->getTotalsize();
286   int prioBits=env->getPriobits();
287   int from=env->getSrcPe();
288   PUPn(from);
289   //PUPn(wasPacked);
290   PUPn(prioBits);
291   int userSize=size-sizeof(envelope)-sizeof(int)*CkPriobitsToInts(prioBits);
292   PUPn(userSize);
293   int msgType = env->getMsgIdx();
294   PUPn(msgType);
295   int msgFor = env->getMsgtype();
296   PUPn(msgFor);
297
298   //p.synchronize(PUP::sync_last_system);
299   
300   int ep=CkMessageToEpIdx(msg);
301   PUPn(ep);
302   
303   /* user data */
304   p.comment("data");
305   p.synchronize(PUP::sync_begin_object);
306   if (_entryTable[ep]->messagePup!=NULL) 
307     _entryTable[ep]->messagePup(p,msg);
308   else
309     CkMessage::ckDebugPup(p,msg);
310   p.synchronize(PUP::sync_end_object);
311 }
312
313 //Cpd Lists for local and scheduler queues
314 class CpdList_localQ : public CpdListAccessor {
315
316 public:
317   CpdList_localQ() {}
318   virtual const char * getPath(void) const {return "converse/localqueue";}
319   virtual int getLength(void) const {
320     int x = CdsFifo_Length((CdsFifo)(CpvAccess(debugQueue)));
321     //CmiPrintf("*******Returning fifo length %d*********\n", x);
322     //return CdsFifo_Length((CdsFifo)(CpvAccess(CmiLocalQueue)));
323     return x;
324   }
325   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
326     int length = CdsFifo_Length((CdsFifo)(CpvAccess(debugQueue)));
327     void ** messages = CdsFifo_Enumerate(CpvAccess(debugQueue));
328     int curObj=0;
329     
330     for(curObj=req.lo; curObj<req.hi; curObj++)
331     if ((curObj>=0) && (curObj<length))
332     {
333         beginItem(p,curObj);
334         void *msg=messages[curObj]; /* converse message */
335         int isCharm=0;
336         const char *type="Converse";
337         p.comment("name");
338         char name[128];
339         if (CmiGetHandler(msg)==_charmHandlerIdx) {isCharm=1; type="Local Charm";}
340         if (CmiGetXHandler(msg)==_charmHandlerIdx) {isCharm=1; type="Network Charm";}
341         sprintf(name,"%s %d: %s (%d)","Message",curObj,type,CmiGetHandler(msg));
342         p(name, strlen(name));
343         
344         if (isCharm) 
345         { /* charm message */
346           p.comment("charmMsg");
347           p.synchronize(PUP::sync_begin_object);
348           envelope *env=(envelope *)msg;
349           CkUnpackMessage(&env);
350           messages[curObj]=env;
351           CpdPupMessage(p, EnvToUsr(env));
352           //CkPupMessage(p, &messages[curObj], 0);
353           p.synchronize(PUP::sync_end_object);
354         }
355     }
356     delete[] messages;
357
358   }
359 };
360
361
362 /****************** Breakpoints and other debug support **************/
363
364 typedef CkHashtableTslow<int,EntryInfo *> CpdBpFuncTable_t;
365
366
367 extern void CpdFreeze(void);
368 extern void CpdUnFreeze(void);
369
370
371 CpvStaticDeclare(int, _debugMsg);
372 CpvStaticDeclare(int, _debugChare);
373
374 CpvStaticDeclare(CpdBpFuncTable_t *, breakPointEntryTable);
375
376 CpvStaticDeclare(void *, lastBreakPointMsg);
377 CpvStaticDeclare(void *, lastBreakPointObject);
378 CpvStaticDeclare(int, lastBreakPointIndex);
379
380 void CpdBreakPointInit()
381 {
382   CpvInitialize(void *, lastBreakPointMsg);
383   CpvInitialize(void *, lastBreakPointObject);
384   CpvInitialize(int, lastBreakPointIndex);
385   CpvInitialize(int, _debugMsg);
386   CpvInitialize(int, _debugChare);
387   CpvInitialize(CpdBpFuncTable_t *, breakPointEntryTable);
388   CpvAccess(lastBreakPointMsg) = NULL;
389   CpvAccess(lastBreakPointObject) = NULL;
390   CpvAccess(lastBreakPointIndex) = 0;
391   CpvAccess(_debugMsg) = CkRegisterMsg("debug_msg",0,0,0);
392   CpvAccess(_debugChare) = CkRegisterChare("debug_Chare",0);
393   CpvAccess(breakPointEntryTable) = new CpdBpFuncTable_t(10,0.5,CkHashFunction_int,CkHashCompare_int );
394 }
395
396
397
398 static void _call_freeze_on_break_point(void * msg, void * object)
399 {
400       //Save breakpoint entry point index. This is retrieved from msg.
401       //So that the appropriate EntryInfo can be later retrieved from the hash table 
402       //of break point function entries, on continue.
403       CpvAccess(lastBreakPointMsg) = msg;
404       CpvAccess(lastBreakPointObject) = object;
405       CpvAccess(lastBreakPointIndex) = CkMessageToEpIdx(msg);
406       EntryInfo * breakPointEntryInfo = CpvAccess(breakPointEntryTable)->get(CpvAccess(lastBreakPointIndex));
407       CmiPrintf("Break point reached for Function = %s\n", breakPointEntryInfo->name);
408       CpdFreeze();
409 }
410
411
412
413 //ccs handler when continue from a break point
414 extern "C"
415 void CpdContinueFromBreakPoint ()
416 {
417     CpdUnFreeze();
418     if ( (CpvAccess(lastBreakPointMsg) != NULL) && (CpvAccess(lastBreakPointObject) != NULL) )
419     {
420         EntryInfo * breakPointEntryInfo = CpvAccess(breakPointEntryTable)->get(CpvAccess(lastBreakPointIndex));
421         if (breakPointEntryInfo != NULL)
422            breakPointEntryInfo->call(CpvAccess(lastBreakPointMsg), CpvAccess(lastBreakPointObject));
423     }
424     CpvAccess(lastBreakPointMsg) = NULL;
425     CpvAccess(lastBreakPointObject) = NULL;
426 }
427
428 //ccs handler to set a breakpoint with entry function name msg
429 void CpdSetBreakPoint (char *msg)
430 {
431   char functionName[128];
432   int tableSize, tableIdx = 0;
433   sscanf(msg+CmiMsgHeaderSizeBytes, "%s", functionName);
434   if (strlen(functionName) > 0)
435   {
436     tableSize = _entryTable.size();
437     // Replace entry in entry table with _call_freeze_on_break_point
438     // retrieve epIdx for entry method
439     for (tableIdx=0; tableIdx < tableSize; tableIdx++)
440     {
441        if (strstr(_entryTable[tableIdx]->name, functionName) != NULL)
442        {
443             EntryInfo * breakPointEntryInfo = new EntryInfo(_entryTable[tableIdx]->name, _entryTable[tableIdx]->call, _entryTable[tableIdx]->msgIdx, _entryTable[tableIdx]->chareIdx );
444            CmiPrintf("Breakpoint is set for function %s with an epIdx = %ld\n", _entryTable[tableIdx]->name, tableIdx);
445            CpvAccess(breakPointEntryTable)->put(tableIdx) = breakPointEntryInfo;  
446            _entryTable[tableIdx]->name = "debug_breakpoint_ep";  
447            _entryTable[tableIdx]->call = (CkCallFnPtr)_call_freeze_on_break_point;
448            _entryTable[tableIdx]->msgIdx = CpvAccess(_debugMsg); 
449            _entryTable[tableIdx]->chareIdx = CpvAccess(_debugChare);
450            break;
451        }
452     }
453     if (tableIdx == tableSize)
454     {
455       CmiPrintf("[ERROR]Entrypoint was not found for function %s\n", functionName); 
456       return;
457     }
458
459   }
460
461 }
462
463 void CpdQuitDebug()
464 {
465   CpdContinueFromBreakPoint();
466   CkExit();
467 }
468
469 void CpdRemoveBreakPoint (char *msg)
470 {
471   char functionName[128];
472   sscanf(msg+CmiMsgHeaderSizeBytes, "%s", functionName);
473   void *objPointer;
474   void *keyPointer; 
475   CkHashtableIterator *it = CpvAccess(breakPointEntryTable)->iterator();
476   while(NULL!=(objPointer = it->next(&keyPointer)))
477   {
478     EntryInfo * breakPointEntryInfo = *(EntryInfo **)objPointer;
479     int idx = *(int *)keyPointer;
480     if (strstr(breakPointEntryInfo->name, functionName) != NULL){
481         _entryTable[idx]->name =  breakPointEntryInfo->name;
482         _entryTable[idx]->call = (CkCallFnPtr)breakPointEntryInfo->call;
483         _entryTable[idx]->msgIdx = breakPointEntryInfo->msgIdx;
484         _entryTable[idx]->chareIdx = breakPointEntryInfo->chareIdx;
485         CmiPrintf("Breakpoint is removed for function %s with epIdx %ld\n", _entryTable[idx]->name, idx);
486     }
487   }
488 }
489
490 void CpdRemoveAllBreakPoints ()
491 {
492   //all breakpoints removed
493   void *objPointer;
494   void *keyPointer; 
495   CkHashtableIterator *it = CpvAccess(breakPointEntryTable)->iterator();
496   while(NULL!=(objPointer = it->next(&keyPointer)))
497   {
498     EntryInfo * breakPointEntryInfo = *(EntryInfo **)objPointer;
499     int idx = *(int *)keyPointer;
500     _entryTable[idx]->name =  breakPointEntryInfo->name;
501     _entryTable[idx]->call = (CkCallFnPtr)breakPointEntryInfo->call;
502     _entryTable[idx]->msgIdx = breakPointEntryInfo->msgIdx;
503     _entryTable[idx]->chareIdx = breakPointEntryInfo->chareIdx;
504   }
505 }
506
507
508
509
510
511 CpvExtern(char *, displayArgument);
512
513 void CpdStartGdb(void)
514 {
515 #if !defined(_WIN32) || defined(__CYGWIN__)
516   FILE *f;
517   char gdbScript[200];
518   int pid;
519   if (CpvAccess(displayArgument) != NULL)
520   {
521      /*CmiPrintf("MY NODE IS %d  and process id is %d\n", CmiMyPe(), getpid());*/
522      sprintf(gdbScript, "/tmp/cpdstartgdb.%d.%d", getpid(), CmiMyPe());
523      f = fopen(gdbScript, "w");
524      fprintf(f,"#!/bin/sh\n");
525      fprintf(f,"cat > /tmp/start_gdb.$$ << END_OF_SCRIPT\n");
526      fprintf(f,"shell /bin/rm -f /tmp/start_gdb.$$\n");
527      //fprintf(f,"handle SIGPIPE nostop noprint\n");
528      fprintf(f,"handle SIGWINCH nostop noprint\n");
529      fprintf(f,"handle SIGWAITING nostop noprint\n");
530      fprintf(f, "attach %d\n", getpid());
531      fprintf(f,"END_OF_SCRIPT\n");
532      fprintf(f, "DISPLAY='%s';export DISPLAY\n",CpvAccess(displayArgument));
533      fprintf(f,"/usr/X11R6/bin/xterm ");
534      fprintf(f," -title 'Node %d ' ",CmiMyPe());
535      fprintf(f," -e /usr/bin/gdb -x /tmp/start_gdb.$$ \n");
536      fprintf(f, "exit 0\n");
537      fclose(f);
538      if( -1 == chmod(gdbScript, 0755))
539      {
540         CmiPrintf("ERROR> chmod on script failed!\n");
541         return;
542      }
543      pid = fork();
544      if (pid < 0)
545         { perror("ERROR> forking to run debugger script\n"); exit(1); }
546      if (pid == 0)
547      {
548          //CmiPrintf("In child process to start script %s\n", gdbScript);
549  if (-1 == execvp(gdbScript, NULL))
550             CmiPrintf ("Error> Could not Execute Debugger Script: %s\n",strerror
551 (errno));
552
553       }
554     }
555 #endif
556 }
557
558 void CpdCharmInit()
559 {
560   CpdBreakPointInit();
561   CcsRegisterHandler("ccs_set_break_point",(CmiHandler)CpdSetBreakPoint);
562   CcsRegisterHandler("ccs_remove_break_point",(CmiHandler)CpdRemoveBreakPoint);
563   CcsRegisterHandler("ccs_remove_all_break_points",(CmiHandler)CpdRemoveAllBreakPoints);
564   CcsRegisterHandler("ccs_continue_break_point",(CmiHandler)CpdContinueFromBreakPoint);
565   CcsRegisterHandler("ccs_debug_quit",(CmiHandler)CpdQuitDebug);
566   CcsRegisterHandler("ccs_debug_startgdb",(CmiHandler)CpdStartGdb);
567   CpdListRegister(new CpdListAccessor_c("hostinfo",hostInfoLength,0,hostInfo,0));
568   CpdListRegister(new CpdList_localQ());
569   CpdListRegister(new CpdList_arrayElementNames());
570   CpdListRegister(new CpdList_arrayElements());
571   CpdListRegister(new CpdList_objectNames());
572   CpdListRegister(new CpdList_object());
573 }
574
575
576 #endif /*CMK_CCS_AVAILABLE*/