f8a9a3b782e64c99add1834016ed22eb19471c15
[charm.git] / src / conv-core / debug-conv.c
1 /*
2 Converse-level debugger support
3
4 Collected from convcore.c, conv-ccs.c, register.c by
5 Orion Sky Lawlor, olawlor@acm.org, 4/10/2001
6  */
7 #include <stdio.h> /*for sscanf*/
8 #include <string.h> /*for strcmp*/
9 #include "converse.h"
10 #include "conv-trace.h"
11 #include "queueing.h"
12 #include "conv-ccs.h"
13 #include <errno.h>
14
15 CpvExtern(int, freezeModeFlag);
16 CpvStaticDeclare(int, continueFlag);
17 CpvStaticDeclare(int, stepFlag);
18 CpvExtern(void *, debugQueue);
19 CpvDeclare(void*, conditionalQueue);
20 int conditionalPipe[2] = {0, 0};
21 int _debugHandlerIdx;
22
23 char ** memoryBackup;
24
25 /** Specify if we are replaying the processor from message logs, thus disable delivering of messages */
26 int _replaySystem = 0;
27 int _conditionalDelivery = 0;
28
29 #undef ConverseDeliver
30 int ConverseDeliver(int pe) {
31   return !_replaySystem && (!_conditionalDelivery || pe==CmiMyPe());
32 }
33
34 #if ! CMK_HAS_NTOHL
35 uint32_t ntohl(uint32_t netlong) {
36   union { uint32_t i; unsigned char c[4]; } uaw;
37   uaw.i = netlong;
38   netlong = uaw.c[0]<<24 + uaw.c[1]<<16 + uaw.c[2]<<8 + uaw.c[3];
39   return netlong;
40 }
41 #endif
42
43 /***************************************************
44   The CCS interface to the debugger
45 */
46
47 #include <string.h>
48
49 #include "pup_c.h"
50
51 CpvDeclare(int, CpdSearchLeaks_Index);
52 CpvDeclare(int, CpdSearchLeaksDone_Index);
53 CpvStaticDeclare(CcsDelayedReply, leakSearchDelayedReply);
54
55 void CpdSearchLeaksDone(void *msg) {
56   CmiInt4 ok = 1;
57   CcsSendDelayedReply(CpvAccess(leakSearchDelayedReply), 4, &ok);
58   CmiFree(msg);
59 }
60
61 void CpdSearchLeaks(char * msg) {
62   LeakSearchInfo *info = (LeakSearchInfo *)(msg+CmiMsgHeaderSizeBytes);
63   if (CmiMyPe() == info->pe || (info->pe == -1 && CmiMyPe() == 0)) {
64     if (sizeof(char*) == 8) {
65       info->begin_data = (((CmiUInt8)ntohl(((int*)&info->begin_data)[0]))<<32) + ntohl(((int*)&info->begin_data)[1]);
66       info->end_data = (((CmiUInt8)ntohl(((int*)&info->end_data)[0]))<<32) + ntohl(((int*)&info->end_data)[1]);
67       info->begin_bss = (((CmiUInt8)ntohl(((int*)&info->begin_bss)[0]))<<32) + ntohl(((int*)&info->begin_bss)[1]);
68       info->end_bss = (((CmiUInt8)ntohl(((int*)&info->end_bss)[0]))<<32) + ntohl(((int*)&info->end_bss)[1]);
69     } else {
70       info->begin_data = ntohl((int)info->begin_data);
71       info->end_data = ntohl((int)info->end_data);
72       info->begin_bss = ntohl((int)info->begin_bss);
73       info->end_bss = ntohl((int)info->end_bss);
74     }
75     info->quick = ntohl(info->quick);
76     info->pe = ntohl(info->pe);
77     CpvAccess(leakSearchDelayedReply) = CcsDelayReply();
78     if (info->pe == -1) {
79       CmiSetXHandler(msg, CpvAccess(CpdSearchLeaks_Index));
80       CmiSetHandler(msg, _debugHandlerIdx);
81       CmiSyncBroadcast(CmiMsgHeaderSizeBytes+sizeof(LeakSearchInfo), msg);
82     }
83   }
84   check_memory_leaks(info);
85   if (info->pe == CmiMyPe()) CpdSearchLeaksDone(msg);
86   else if (info->pe == -1) {
87     void *reduceMsg = CmiAlloc(0);
88     CmiSetHandler(reduceMsg, CpvAccess(CpdSearchLeaksDone_Index));
89     CmiReduce(reduceMsg, CmiMsgHeaderSizeBytes, CmiReduceMergeFn_random);
90     CmiFree(msg);
91   }
92   else CmiAbort("Received allocationTree request for another PE!");
93 }
94
95 void * (*CpdDebugGetAllocationTree)(int *) = NULL;
96 void (*CpdDebug_pupAllocationPoint)(pup_er p, void *data) = NULL;
97 void (*CpdDebug_deleteAllocationPoint)(void *ptr) = NULL;
98 void * (*CpdDebug_MergeAllocationTree)(int *size, void *data, void **remoteData, int numRemote) = NULL;
99 CpvDeclare(int, CpdDebugCallAllocationTree_Index);
100 CpvStaticDeclare(CcsDelayedReply, allocationTreeDelayedReply);
101
102 static void CpdDebugReturnAllocationTree(void *tree) {
103   pup_er sizer = pup_new_sizer();
104   char *buf;
105   pup_er packer;
106   int i;
107   CpdDebug_pupAllocationPoint(sizer, tree);
108   buf = (char *)malloc(pup_size(sizer));
109   packer = pup_new_toMem(buf);
110   CpdDebug_pupAllocationPoint(packer, tree);
111   /*CmiPrintf("size=%d tree:",pup_size(sizer));
112   for (i=0;i<100;++i) CmiPrintf(" %02x",((unsigned char*)buf)[i]);
113   CmiPrintf("\n");*/
114   CcsSendDelayedReply(CpvAccess(allocationTreeDelayedReply), pup_size(sizer),buf);
115   pup_destroy(sizer);
116   pup_destroy(packer);
117   free(buf);
118 }
119
120 static void CpdDebugCallAllocationTree(char *msg)
121 {
122   int numNodes;
123   int forPE;
124   void *tree;
125   if (CpdDebugGetAllocationTree == NULL) {
126     CmiPrintf("Error> Invoked CpdDebugCalloAllocationTree but no function initialized.\nDid you forget to link in memory charmdebug?\n");
127     CcsSendReply(0, NULL);
128     return;
129   }
130   sscanf(msg+CmiMsgHeaderSizeBytes, "%d", &forPE);
131   if (CmiMyPe() == forPE) CpvAccess(allocationTreeDelayedReply) = CcsDelayReply();
132   if (forPE == -1 && CmiMyPe()==0) {
133     CpvAccess(allocationTreeDelayedReply) = CcsDelayReply();
134     CmiSetXHandler(msg, CpvAccess(CpdDebugCallAllocationTree_Index));
135     CmiSetHandler(msg, _debugHandlerIdx);
136     CmiSyncBroadcast(CmiMsgHeaderSizeBytes+strlen(msg+CmiMsgHeaderSizeBytes)+1, msg);
137   }
138   tree = CpdDebugGetAllocationTree(&numNodes);
139   if (forPE == CmiMyPe()) CpdDebugReturnAllocationTree(tree);
140   else if (forPE == -1) CmiReduceStruct(tree, CpdDebug_pupAllocationPoint, CpdDebug_MergeAllocationTree,
141                                 CpdDebugReturnAllocationTree, CpdDebug_deleteAllocationPoint);
142   else CmiAbort("Received allocationTree request for another PE!");
143   CmiFree(msg);
144 }
145
146 void * (*CpdDebugGetMemStat)(void) = NULL;
147 void (*CpdDebug_pupMemStat)(pup_er p, void *data) = NULL;
148 void (*CpdDebug_deleteMemStat)(void *ptr) = NULL;
149 void * (*CpdDebug_mergeMemStat)(int *size, void *data, void **remoteData, int numRemote) = NULL;
150 CpvDeclare(int, CpdDebugCallMemStat_Index);
151 CpvStaticDeclare(CcsDelayedReply, memStatDelayedReply);
152
153 static void CpdDebugReturnMemStat(void *stat) {
154 #if CMK_CCS_AVAILABLE
155   pup_er sizerNet = pup_new_network_sizer();
156   pup_er sizer = pup_new_fmt(sizerNet);
157   char *buf;
158   pup_er packerNet;
159   pup_er packer;
160   int i;
161   CpdDebug_pupMemStat(sizer, stat);
162   buf = (char *)malloc(pup_size(sizer));
163   packerNet = pup_new_network_pack(buf);
164   packer = pup_new_fmt(packerNet);
165   CpdDebug_pupMemStat(packer, stat);
166   /*CmiPrintf("size=%d tree:",pup_size(sizer));
167   for (i=0;i<100;++i) CmiPrintf(" %02x",((unsigned char*)buf)[i]);
168   CmiPrintf("\n");*/
169   CcsSendDelayedReply(CpvAccess(memStatDelayedReply), pup_size(sizer),buf);
170   pup_destroy(sizerNet);
171   pup_destroy(sizer);
172   pup_destroy(packerNet);
173   pup_destroy(packer);
174   free(buf);
175 #endif
176 }
177
178 static void CpdDebugCallMemStat(char *msg) {
179   int forPE;
180   void *stat;
181   if (CpdDebugGetMemStat == NULL) {
182     CmiPrintf("Error> Invoked CpdDebugCalloMemStat but no function initialized.\nDid you forget to link in memory charmdebug?\n");
183     CcsSendReply(0, NULL);
184     return;
185   }
186   sscanf(msg+CmiMsgHeaderSizeBytes, "%d", &forPE);
187   if (CmiMyPe() == forPE) CpvAccess(memStatDelayedReply) = CcsDelayReply();
188   if (forPE == -1 && CmiMyPe()==0) {
189     CpvAccess(memStatDelayedReply) = CcsDelayReply();
190     CmiSetXHandler(msg, CpvAccess(CpdDebugCallMemStat_Index));
191     CmiSetHandler(msg, _debugHandlerIdx);
192     CmiSyncBroadcast(CmiMsgHeaderSizeBytes+strlen(msg+CmiMsgHeaderSizeBytes)+1, msg);
193   }
194   stat = CpdDebugGetMemStat();
195   if (forPE == CmiMyPe()) CpdDebugReturnMemStat(stat);
196   else if (forPE == -1) CmiReduceStruct(stat, CpdDebug_pupMemStat, CpdDebug_mergeMemStat,
197                                 CpdDebugReturnMemStat, CpdDebug_deleteMemStat);
198   else CmiAbort("Received allocationTree request for another PE!");
199   CmiFree(msg);
200 }
201
202 static void CpdDebugHandler(char *msg)
203 {
204     char name[128];
205     sscanf(msg+CmiReservedHeaderSize, "%s", name);
206
207     if (strcmp(name, "freeze") == 0) {
208       CpdFreeze();
209     }
210     else if (strcmp(name, "unfreeze") == 0) {
211       CpdUnFreeze();
212     }
213     else if (strncmp(name, "step", strlen("step")) == 0){
214       /*CmiPrintf("step received\n");*/
215       CpvAccess(stepFlag) = 1;
216       CpdUnFreeze();
217     }
218     else if (strncmp(name, "continue", strlen("continue")) == 0){
219       /*CmiPrintf("continue received\n");*/
220       CpvAccess(continueFlag) = 1;
221       CpdUnFreeze();
222     }
223 #if ! CMK_NO_SOCKETS
224     else if (strncmp(name, "status", strlen("status")) == 0) {
225       ChMessageInt_t reply[2];
226       reply[0] = ChMessageInt_new(CmiMyPe());
227       reply[1] = ChMessageInt_new(CpdIsFrozen() ? 0 : 1);
228       CcsSendReply(2*sizeof(ChMessageInt_t), reply);
229     }
230 #endif
231     else{
232       CmiPrintf("bad debugger command:%s received,len=%ld\n",name,strlen(name));
233     }
234     CmiFree(msg);
235 }
236
237
238 /* Deliver a single message in the queue while not unfreezing the program */
239 void CpdNext(void) {
240
241 }
242
243 /* This converse handler is used by the debugger itself, to send messages
244  * even when the scheduler is in freeze mode.
245  */
246 void handleDebugMessage(void *msg) {
247   CmiSetHandler(msg, CmiGetXHandler(msg));
248   CmiHandleMessage(msg);
249 }
250
251 /* Special scheduler-type loop only executed while in
252 freeze mode-- only executes CCS requests.
253 */
254 void CcsServerCheck(void);
255 extern int _isCcsHandlerIdx(int idx);
256 int (*CpdIsDebugMessage)(void *);
257 void * (*CpdGetNextMessage)(CsdSchedulerState_t*);
258
259 void CpdFreezeModeScheduler(void)
260 {
261 #if CMK_BLUEGENE_CHARM
262     CmiAbort("Cannot run CpdFreezeModeScheduler inside BigSim emulated environment");
263 #else
264 #if CMK_CCS_AVAILABLE
265     void *msg;
266     void *debugQ=CpvAccess(debugQueue);
267     CsdSchedulerState_t state;
268     CsdSchedulerState_new(&state);
269
270     /* While frozen, queue up messages */
271     while (CpvAccess(freezeModeFlag)) {
272 #if NODE_0_IS_CONVHOST
273       if (CmiMyPe()==0) CcsServerCheck(); /*Make sure we can get CCS messages*/
274 #endif
275       msg = CpdGetNextMessage(&state);
276
277       if (msg!=NULL) {
278         /*int hIdx=CmiGetHandler(msg);*/
279           /*
280           if(_isCcsHandlerIdx(hIdx))
281           / *A CCS request-- handle it immediately* /
282           {
283             CmiHandleMessage(msg);
284           }
285           else if (hIdx == _debugHandlerIdx ||
286                   (hIdx == CmiGetReductionHandler() && CmiGetReductionDestination() == CpdDebugReturnAllocationTree)) {
287             / * Debug messages should be handled immediately * /
288             CmiHandleMessage(msg);
289           } else */
290         
291       if (CpdIsDebugMessage(msg)) {
292         CmiHandleMessage(msg);
293           }
294           else
295           /*An ordinary charm++ message-- queue it up*/
296             CdsFifo_Enqueue(debugQ, msg);
297       } else CmiNotifyIdle();
298     }
299     /* Before leaving freeze mode, execute the messages
300        in the order they would have executed before.*/
301     while (!CdsFifo_Empty(debugQ))
302     {
303         char *queuedMsg = (char *)CdsFifo_Dequeue(debugQ);
304         CmiHandleMessage(queuedMsg);
305     }
306 #endif
307 #endif
308 }
309
310 void CpdMemoryMarkClean(char *msg);
311
312 void CpdInit(void)
313 {
314 #if ! CMK_BLUEGENE_CHARM
315   CpvInitialize(int, freezeModeFlag);
316   CpvAccess(freezeModeFlag) = 0;
317
318   CpvInitialize(void *, debugQueue);
319   CpvAccess(debugQueue) = CdsFifo_Create();
320 #endif
321
322   CpvInitialize(void *, conditionalQueue);
323   CpvAccess(conditionalQueue) = CdsFifo_Create();
324   
325   CcsRegisterHandler("ccs_debug", (CmiHandler)CpdDebugHandler);
326   CcsSetMergeFn("ccs_debug", CcsMerge_concat);
327
328   CcsRegisterHandler("ccs_debug_allocationTree", (CmiHandler)CpdDebugCallAllocationTree);
329   CpvInitialize(int, CpdDebugCallAllocationTree_Index);
330   CpvAccess(CpdDebugCallAllocationTree_Index) = CmiRegisterHandler((CmiHandler)CpdDebugCallAllocationTree);
331   
332   CcsRegisterHandler("ccs_debug_memStat", (CmiHandler)CpdDebugCallMemStat);
333   CpvInitialize(int, CpdDebugCallMemStat_Index);
334   CpvAccess(CpdDebugCallMemStat_Index) = CmiRegisterHandler((CmiHandler)CpdDebugCallMemStat);
335
336   CcsRegisterHandler("converse_memory_leak",(CmiHandler)CpdSearchLeaks);
337   CpvInitialize(int, CpdSearchLeaks_Index);
338   CpvAccess(CpdSearchLeaks_Index) = CmiRegisterHandler((CmiHandler)CpdSearchLeaks);
339   CpvInitialize(int, CpdSearchLeaksDone_Index);
340   CpvAccess(CpdSearchLeaksDone_Index) = CmiRegisterHandler((CmiHandler)CpdSearchLeaksDone);
341   
342   CcsRegisterHandler("converse_memory_mark",(CmiHandler)CpdMemoryMarkClean);
343   CcsSetMergeFn("converse_memory_mark", CcsMerge_concat);
344
345   _debugHandlerIdx = CmiRegisterHandler((CmiHandler)handleDebugMessage);
346 #if 0
347   CpdInitializeObjectTable();
348   CpdInitializeHandlerArray();
349   CpdInitializeBreakPoints();
350
351   /* To allow start in freeze state: */
352   msgListCleanup();
353   msgListCache();
354 #endif
355
356 }
357