1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3  *  (C) 2005 by Argonne National Laboratory.
4  *      See COPYRIGHT in top-level directory.
5  */
6 
7 /* Fixme: include the mpichconf.h file? */
8 
9 /* Allow fprintf in debug statements */
10 /* style: allow:fprintf:5 sig:0 */
11 
12 #include <stdlib.h>
13 #include <stdint.h>
14 #include <string.h>
15 #include "mpi.h"
16 
17 /* #define DEBUG_MPIDBG_DLL 1 */
18 
19 /* Define this to have the code print out details of its list traversal
20    action.  This is primarily for use with dbgstub.c and the test programs
21    such as tvtest.c */
22 /* #define DEBUG_LIST_ITER */
23 
24 /* Define this to have the code print out its operation to a file.
25    This may be used to help understand how the debugger is using this
26    interface */
27 /* #define DEBUG_MPIDBG_LOGGING */
28 #ifdef DEBUG_MPIDBG_LOGGING
29 #include <stdio.h>
30 FILE *debugfp = 0;
31 
initLogFile(void)32 static void initLogFile(void)
33 {
34     if (!debugfp) {
35 	debugfp = fopen( "mpich-dbg-interface-log.txt", "w" );
36     }
37 }
38 #else
39 /* no-op definition */
40 #define initLogFile()
41 #endif
42 
43 /* MPIR_dll_name is defined in dbg_init.c; it must be part of the target image,
44    not the debugger interface */
45 
46 /* mpi_interface.h defines the interface to the debugger.  This interface
47    is the same for any MPI implementation, for a given debugger
48    (a more precise name might be mpi_tv_interface.h) */
49 #include "mpi_interface.h"
50 /* mpich2_dll_defs.h defines the structures for a particular MPI
51    implementation (MPICH2 in this case) */
52 #include "mpich2_dll_defs.h"
53 
54 /* style: allow:strncpy:1 sig:0 */
55 
56 /* ------------------------------------------------------------------------ */
57 /* Local variables for this package */
58 
59 static const mqs_basic_callbacks *mqs_basic_entrypoints = 0;
60 static int host_is_big_endian = -1;
61 
62 /* ------------------------------------------------------------------------ */
63 /* Error values. */
64 enum {
65     err_silent_failure = mqs_first_user_code,
66 
67     err_no_current_communicator,
68     err_bad_request,
69     err_no_store,
70     err_all_communicators,
71     err_group_corrupt,
72 
73   err_failed_qhdr,
74     err_unexpected,
75     err_posted,
76 
77   err_failed_queue,
78     err_first,
79 
80 };
81 
82 /* Internal structure we hold for each communicator */
83 typedef struct communicator_t
84 {
85   struct communicator_t * next;
86   group_t *               group;		/* Translations */
87   int                     context_id;		/* To catch changes */
88   int                     recvcontext_id;       /* May also be needed for
89 						   matchine */
90   int                     present;
91   mqs_communicator        comm_info;		/* Info needed at the higher level */
92 } communicator_t;
93 
94 /* Internal functions used only by routines in this package */
95 static void mqs_free_communicator_list( struct communicator_t *comm );
96 
97 static int communicators_changed (mqs_process *proc);
98 static int rebuild_communicator_list (mqs_process *proc);
99 static int compare_comms (const void *a, const void *b);
100 
101 static group_t * find_or_create_group (mqs_process *proc,
102 				       mqs_tword_t np,
103 				       mqs_taddr_t table);
104 static int translate (group_t *this, int idx);
105 #if 0
106 static int reverse_translate (group_t * this, int idx);
107 #endif
108 static void group_decref (group_t * group);
109 static communicator_t * find_communicator (mpich_process_info *p_info,
110 				   mqs_taddr_t comm_base, int recv_ctx);
111 
112 /* ------------------------------------------------------------------------ */
113 /*
114  * Many of the services used by this file are performed by calling
115  * functions executed by the debugger.  In other words, these are routines
116  * that the debugger must export to this package.  To make it easy to
117  * identify these functions as well as to make their use simple,
118  * we use macros that start with dbgr_xxx (for debugger).  These
119  * function pointers are set early in the initialization phase.
120  *
121  * Note: to avoid any changes to the mpi_interface.h file, the fields in
122  * the structures that contain the function pointers have not been
123  * renamed dbgr_xxx and continue to use their original mqs_ prefix.
124  * Using the dbgr_ prefix for the debugger-provided callbacks was done to
125  * make it more obvious whether the debugger or the MPI interface DLL is
126  * responsible for providing the function.
127  */
128 #define dbgr_malloc           (mqs_basic_entrypoints->mqs_malloc_fp)
129 #define dbgr_free             (mqs_basic_entrypoints->mqs_free_fp)
130 #define dbgr_prints           (mqs_basic_entrypoints->mqs_eprints_fp)
131 #define dbgr_put_image_info   (mqs_basic_entrypoints->mqs_put_image_info_fp)
132 #define dbgr_get_image_info   (mqs_basic_entrypoints->mqs_get_image_info_fp)
133 #define dbgr_put_process_info (mqs_basic_entrypoints->mqs_put_process_info_fp)
134 #define dbgr_get_process_info (mqs_basic_entrypoints->mqs_get_process_info_fp)
135 
136 /* These macros *RELY* on the function already having set up the conventional
137  * local variables i_info or p_info.
138  */
139 #define dbgr_find_type        (i_info->image_callbacks->mqs_find_type_fp)
140 #define dbgr_field_offset     (i_info->image_callbacks->mqs_field_offset_fp)
141 #define dbgr_get_type_sizes   (i_info->image_callbacks->mqs_get_type_sizes_fp)
142 #define dbgr_find_function    (i_info->image_callbacks->mqs_find_function_fp)
143 #define dbgr_find_symbol      (i_info->image_callbacks->mqs_find_symbol_fp)
144 
145 #define dbgr_get_image        (p_info->process_callbacks->mqs_get_image_fp)
146 #define dbgr_get_global_rank  (p_info->process_callbacks->mqs_get_global_rank_fp)
147 #define dbgr_fetch_data       (p_info->process_callbacks->mqs_fetch_data_fp)
148 #define dbgr_target_to_host   (p_info->process_callbacks->mqs_target_to_host_fp)
149 
150 /* Routines to access data within the process */
151 static mqs_taddr_t fetch_pointer (mqs_process * proc, mqs_taddr_t addr,
152 				  mpich_process_info *p_info);
153 static mqs_tword_t fetch_int (mqs_process * proc, mqs_taddr_t addr,
154 			      mpich_process_info *p_info);
155 static mqs_tword_t fetch_int16 (mqs_process * proc, mqs_taddr_t addr,
156 				mpich_process_info *p_info);
157 
158 /* ------------------------------------------------------------------------ */
159 /* Startup calls
160    These three routines are the first ones invoked by the debugger; they
161    are used to ensure that the debug interface library is a known version.
162 */
mqs_version_compatibility(void)163 int mqs_version_compatibility ( void )
164 {
165   return MQS_INTERFACE_COMPATIBILITY;
166 }
167 
mqs_version_string(void)168 char *mqs_version_string ( void )
169 {
170     return (char *)"MPICH message queue support for MPICH2 " MPICH2_VERSION " compiled on " __DATE__;
171 }
172 
173 /* Allow the debugger to discover the size of an address type */
mqs_dll_taddr_width(void)174 int mqs_dll_taddr_width (void)
175 {
176   return sizeof (mqs_taddr_t);
177 }
178 
179 /* ------------------------------------------------------------------------ */
180 /* Initialization
181 
182    The function mqs_setup_basic_callbacks is used by the debugger to
183    inform the routines in this file of the addresses of functions that
184    it may call in the debugger.
185 
186    The function mqs_setup_image creates the image structure (local to this
187    file) and tell the debugger about it
188 
189    The function mqs_image_has_queues initializes the image structure.
190    Much of the information that is saved in the image structure is information
191    about the relative offset to data within an MPICH2 data structure.
192    These offsets allow the debugger to retrieve information about the
193    MPICH2 structures.  The debugger routine dbgr_find_type is used to
194    find information on an named type, and dbgr_field_offset is used
195    to get the offset of a named field within a type.
196 
197    The function mqs_setup_process(process, callbacks) creates a private
198    process information structure and stores a pointer to it in process
199    (using dbgr_put_process_info).  The use of a routine to store this
200    value rather than passing an address to the process structure is
201    done to give the debugger control over any operation that might store
202    into the debuggers memory (instead, we'll use put_xxx_info).
203 
204    The function mqs_process_has_queues ??
205  */
mqs_setup_basic_callbacks(const mqs_basic_callbacks * cb)206 void mqs_setup_basic_callbacks (const mqs_basic_callbacks * cb)
207 {
208   int t = 1;
209   initLogFile();
210   host_is_big_endian    = (*(char *)&t) != 1;
211   mqs_basic_entrypoints = cb;
212 }
213 
214 /*
215    Allocate and setup the basic image data structure.  Also
216    save the callbacks provided by the debugger; these will be used
217    to access information about the image.  This memory may be recovered
218    with mqs_destroy_image_info.
219  */
mqs_setup_image(mqs_image * image,const mqs_image_callbacks * icb)220 int mqs_setup_image (mqs_image *image, const mqs_image_callbacks *icb)
221 {
222     mpich_image_info *i_info =
223       (mpich_image_info *)dbgr_malloc (sizeof (mpich_image_info));
224 
225     if (!i_info)
226 	return err_no_store;
227 
228     memset ((void *)i_info, 0, sizeof (mpich_image_info));
229     i_info->image_callbacks = icb;		/* Before we do *ANYTHING* */
230 
231     /* Tell the debugger to associate i_info with image */
232     dbgr_put_image_info (image, (mqs_image_info *)i_info);
233 
234     return mqs_ok;
235 }
236 
237 /*
238  * Setup information needed to access the queues.  If successful, return
239  * mqs_ok.  If not, return an erro rcode.  Also set the message pointer
240  * with an explanatory message if there is a problem; otherwise, set it
241  * to NULL.
242  *
243  * This routine is where much of the information specific to an MPI
244  * implementation is used.  In particular, the names of the structures
245  * internal to an implementation and their fields are used here.
246  *
247  * FIXME: some of this information is specific to particular devices.
248  * For example, the message queues are defined by the device.  How do
249  * we export this information?  Should the queue code itself be responsible
250  * for this (either by calling a routine in the image, using
251  * dbgr_find_function (?) or by having the queue implementation provide a
252  * separate file that can be included here to get the necessary information.
253  */
mqs_image_has_queues(mqs_image * image,char ** message)254 int mqs_image_has_queues (mqs_image *image, char **message)
255 {
256     mpich_image_info * i_info =
257 	(mpich_image_info *)dbgr_get_image_info (image);
258     int have_co = 0, have_cl = 0, have_req = 0, have_dreq = 0;
259 
260     /* Default failure message ! */
261     *message = (char *)"The symbols and types in the MPICH library used by TotalView\n"
262 	"to extract the message queues are not as expected in\n"
263 	"the image '%s'\n"
264 	"No message queue display is possible.\n"
265 	"This is probably an MPICH version or configuration problem.";
266 
267     /* Force in the file containing our wait-for-debugger function, to ensure
268      * that types have been read from there before we try to look them up.
269      */
270     dbgr_find_function (image, (char *)"MPIR_WaitForDebugger", mqs_lang_c, NULL);
271 
272     /* Find the various global variables and structure definitions
273        that describe the communicator and message queue structures for
274        the MPICH2 implementation */
275 
276     /* First, the communicator information.  This is in two parts:
277        MPIR_All_Communicators - a structure containing the head of the
278        list of all active communicators.  The type is MPIR_Comm_list.
279        The communicators themselves are of type MPID_Comm.
280     */
281     {
282 	mqs_type *cl_type = dbgr_find_type( image, (char *)"MPIR_Comm_list",
283 					    mqs_lang_c );
284 	if (cl_type) {
285 	    have_cl = 1;
286 	    i_info->sequence_number_offs =
287 		dbgr_field_offset( cl_type, (char *)"sequence_number" );
288 	    i_info->comm_head_offs = dbgr_field_offset( cl_type, (char *)"head" );
289 	}
290     }
291     {
292 	mqs_type *co_type = dbgr_find_type( image, (char *)"MPID_Comm", mqs_lang_c );
293 	if (co_type) {
294 	    have_co = 1;
295 	    i_info->comm_name_offs = dbgr_field_offset( co_type, (char *)"name" );
296 	    i_info->comm_next_offs = dbgr_field_offset( co_type, (char *)"comm_next" );
297 	    i_info->comm_rsize_offs = dbgr_field_offset( co_type, (char *)"remote_size" );
298 	    i_info->comm_rank_offs = dbgr_field_offset( co_type, (char *)"rank" );
299 	    i_info->comm_context_id_offs = dbgr_field_offset( co_type, (char *)"context_id" );
300 	    i_info->comm_recvcontext_id_offs = dbgr_field_offset( co_type, (char *)"recvcontext_id" );
301 	}
302     }
303 
304     /* Now the receive queues.  The receive queues contain MPID_Request
305        objects, and the various fields are within types in that object.
306        To simplify the eventual access, we compute all offsets relative to the
307        request.  This means diving into the types that make of the
308        request definition */
309     {
310 	mqs_type *req_type = dbgr_find_type( image, (char *)"MPID_Request", mqs_lang_c );
311 	if (req_type) {
312 	    int dev_offs;
313 	    have_req = 1;
314 	    dev_offs = dbgr_field_offset( req_type, (char *)"dev" );
315 	    i_info->req_status_offs = dbgr_field_offset( req_type, (char *)"status" );
316 	    i_info->req_cc_offs     = dbgr_field_offset( req_type, (char *)"cc" );
317 	    if (dev_offs >= 0) {
318 		mqs_type *dreq_type = dbgr_find_type( image, (char *)"MPIDI_Request",
319 						      mqs_lang_c );
320 		i_info->req_dev_offs = dev_offs;
321 		if (dreq_type) {
322 		    int loff, match_offs;
323 		    have_dreq = 1;
324 		    loff = dbgr_field_offset( dreq_type, (char *)"next" );
325 		    i_info->req_next_offs = dev_offs + loff;
326 		    loff = dbgr_field_offset( dreq_type, (char *)"user_buf" );
327 		    i_info->req_user_buf_offs = dev_offs + loff;
328 		    loff = dbgr_field_offset( dreq_type, (char *)"user_count" );
329 		    i_info->req_user_count_offs = dev_offs + loff;
330 		    loff = dbgr_field_offset( dreq_type, (char *)"datatype" );
331 		    i_info->req_datatype_offs = dev_offs + loff;
332 		    match_offs = dbgr_field_offset( dreq_type, (char *)"match" );
333 		    /*
334 		      Current definition from the mpidpre.h file for ch3.
335 
336 		      typedef struct MPIDI_Message_match_parts {
337 		      int32_t tag;
338 		      MPIR_Rank_t rank;
339 		      MPIR_Context_id_t context_id;
340 		      } MPIDI_Message_match_parts_t;
341 		      typedef union {
342 		      MPIDI_Message_match_parts_t parts;
343 		      MPIR_Upint whole;
344 		      } MPIDI_Message_match;
345 		    */
346 		    if (match_offs >= 0) {
347 			mqs_type *match_type = dbgr_find_type( image, (char *)"MPIDI_Message_match", mqs_lang_c );
348 			if (match_type) {
349 			    int parts_offs = dbgr_field_offset( match_type, (char *)"parts" );
350 			    if (parts_offs >= 0) {
351 				mqs_type *parts_type = dbgr_find_type( image, (char *)"MPIDI_Message_match_parts_t", mqs_lang_c );
352 				if (parts_type) {
353 				    int moff;
354 				    moff = dbgr_field_offset( parts_type, (char *)"tag" );
355 				    i_info->req_tag_offs = dev_offs + match_offs + moff;
356 				    moff = dbgr_field_offset( parts_type, (char *)"rank" );
357 				    i_info->req_rank_offs = dev_offs + match_offs + moff;
358 				    moff = dbgr_field_offset( parts_type, (char *)"context_id" );
359 				    i_info->req_context_id_offs = dev_offs + match_offs + moff;
360 				}
361 			    }
362 			}
363 		    }
364 		}
365 	    }
366 	}
367     }
368 
369     /* Send queues use a separate system */
370     {
371 	mqs_type *sreq_type = dbgr_find_type( image, (char *)"MPIR_Sendq", mqs_lang_c );
372 	if (sreq_type) {
373 	    i_info->sendq_next_offs = dbgr_field_offset( sreq_type, (char *)"next" );
374 	    i_info->sendq_tag_offs  = dbgr_field_offset( sreq_type, (char *)"tag" );
375 	    i_info->sendq_rank_offs = dbgr_field_offset( sreq_type, (char *)"rank" );
376 	    i_info->sendq_context_id_offs  = dbgr_field_offset( sreq_type, (char *)"context_id" );
377 	    i_info->sendq_req_offs  = dbgr_field_offset( sreq_type, (char *)"sreq" );
378 	}
379     }
380 
381     return mqs_ok;
382 }
383 /* mqs_setup_process initializes the process structure.
384  * The memory allocated by this routine (and routines that modify this
385  * structure) is freed with mqs_destroy_process_info
386  */
mqs_setup_process(mqs_process * process,const mqs_process_callbacks * pcb)387 int mqs_setup_process (mqs_process *process, const mqs_process_callbacks *pcb)
388 {
389     /* Extract the addresses of the global variables we need and save
390        them away */
391     mpich_process_info *p_info =
392 	(mpich_process_info *)dbgr_malloc (sizeof (mpich_process_info));
393 
394     if (p_info) {
395 	mqs_image        *image;
396 	mpich_image_info *i_info;
397 
398 	p_info->process_callbacks = pcb;
399 
400 	/* Now we can get the rest of the info ! */
401 	image  = dbgr_get_image (process);
402 	i_info = (mpich_image_info *)dbgr_get_image_info (image);
403 
404 	/* Library starts at zero, so this ensures we go look to start with */
405 	p_info->communicator_sequence = -1;
406 	/* We have no communicators yet */
407 	p_info->communicator_list     = NULL;
408 	/* Ask the debugger to initialize the structure that contains
409 	   the sizes of basic items (short, int, long, long long, and
410 	   void *) */
411 	dbgr_get_type_sizes (process, &p_info->sizes);
412 
413 	/* Tell the debugger to associate p_info with process */
414 	dbgr_put_process_info (process, (mqs_process_info *)p_info);
415 
416 	return mqs_ok;
417     }
418     else
419 	return err_no_store;
420 }
mqs_process_has_queues(mqs_process * proc,char ** msg)421 int mqs_process_has_queues (mqs_process *proc, char **msg)
422 {
423     mpich_process_info *p_info =
424 	(mpich_process_info *)dbgr_get_process_info (proc);
425     mqs_image * image          = dbgr_get_image (proc);
426     mpich_image_info *i_info   =
427 	(mpich_image_info *)dbgr_get_image_info (image);
428     mqs_taddr_t head_ptr;
429 
430     /* Don't bother with a pop up here, it's unlikely to be helpful */
431     *msg = 0;
432 
433     /* Check first for the communicator list */
434     if (dbgr_find_symbol (image, (char *)"MPIR_All_communicators", &p_info->commlist_base) != mqs_ok)
435 	return err_all_communicators;
436 
437     /* Check for the receive and send queues */
438     if (dbgr_find_symbol( image, (char *)"MPID_Recvq_posted_head_ptr", &head_ptr ) != mqs_ok)
439 	return err_posted;
440     p_info->posted_base = fetch_pointer( proc, head_ptr, p_info );
441 
442     if (dbgr_find_symbol( image, (char *)"MPID_Recvq_unexpected_head_ptr", &head_ptr ) != mqs_ok)
443 	return err_unexpected;
444     p_info->unexpected_base = fetch_pointer( proc, head_ptr, p_info );
445 
446     /* Send queues are optional */
447     if (dbgr_find_symbol( image, (char *)"MPIR_Sendq_head", &p_info->sendq_base) ==
448 	mqs_ok) {
449 	p_info->has_sendq = 1;
450     }
451     else {
452 	p_info->has_sendq = 0;
453     }
454 
455     return mqs_ok;
456 }
457 
458 /* This routine is called by the debugger to map an error code into a
459    printable string */
mqs_dll_error_string(int errcode)460 char * mqs_dll_error_string (int errcode)
461 {
462     switch (errcode) {
463     case err_silent_failure:
464 	return (char *)"";
465     case err_no_current_communicator:
466 	return (char *)"No current communicator in the communicator iterator";
467     case err_bad_request:
468 	return (char *)"Attempting to setup to iterate over an unknown queue of operations";
469     case err_no_store:
470 	return (char *)"Unable to allocate store";
471     case err_group_corrupt:
472 	return (char *)"Could not read a communicator's group from the process (probably a store corruption)";
473     case err_unexpected:
474 	return (char *)"Failed to find symbol MPID_Recvq_unexpected_head_ptr";
475     case err_posted:
476 	return (char *)"Failed to find symbol MPID_Recvq_posted_head_ptr";
477     }
478     return (char *)"Unknown error code";
479 }
480 /* ------------------------------------------------------------------------ */
481 /* Queue Display
482  *
483  */
484 
485 /* Communicator list.
486  *
487  * To avoid problems that might be caused by having the list of communicators
488  * change in the process that is being debugged, the communicator access
489  * routines make an internal copy of the communicator list.
490  *
491  */
492 /* update_communicator_list makes a copy of the list of currently active
493  * communicators and stores it in the mqs_process structure.
494  */
mqs_update_communicator_list(mqs_process * proc)495 int mqs_update_communicator_list (mqs_process *proc)
496 {
497     if (communicators_changed (proc))
498 	return rebuild_communicator_list (proc);
499     else
500 	return mqs_ok;
501 }
502 /* These three routines (setup_communicator_iterator, get_communicator,
503  * and next_communicator) provide a way to access each communicator in the
504  * list that is initialized by update_communicator_list.
505  */
mqs_setup_communicator_iterator(mqs_process * proc)506 int mqs_setup_communicator_iterator (mqs_process *proc)
507 {
508     mpich_process_info *p_info =
509 	(mpich_process_info *)dbgr_get_process_info (proc);
510 
511     /* Start at the front of the list again */
512     p_info->current_communicator = p_info->communicator_list;
513     /* Reset the operation iterator too */
514     p_info->next_msg = 0;
515 
516     return p_info->current_communicator == NULL ? mqs_end_of_list : mqs_ok;
517 }
mqs_get_communicator(mqs_process * proc,mqs_communicator * comm)518 int mqs_get_communicator (mqs_process *proc, mqs_communicator *comm)
519 {
520     mpich_process_info *p_info =
521 	(mpich_process_info *)dbgr_get_process_info (proc);
522 
523     if (p_info->current_communicator) {
524 	*comm = p_info->current_communicator->comm_info;
525 	return mqs_ok;
526     }
527     else
528 	return err_no_current_communicator;
529 }
mqs_next_communicator(mqs_process * proc)530 int mqs_next_communicator (mqs_process *proc)
531 {
532     mpich_process_info *p_info =
533 	(mpich_process_info *)dbgr_get_process_info (proc);
534 
535     p_info->current_communicator = p_info->current_communicator->next;
536 
537     return (p_info->current_communicator != NULL) ? mqs_ok : mqs_end_of_list;
538 }
539 /* ------------------------------------------------------------------------ */
540 /* Iterate over the queues attached to the current communicator. */
541 
542 /* Forward references for routines used to implement the operations */
543 static int fetch_send (mqs_process *proc, mpich_process_info *p_info,
544 		       mqs_pending_operation *res);
545 static int fetch_receive (mqs_process *proc, mpich_process_info *p_info,
546 			  mqs_pending_operation *res, int look_for_user_buffer);
547 
mqs_setup_operation_iterator(mqs_process * proc,int op)548 int mqs_setup_operation_iterator (mqs_process *proc, int op)
549 {
550     mpich_process_info *p_info =
551 	(mpich_process_info *)dbgr_get_process_info (proc);
552     /*    mqs_image * image          = dbgr_get_image (proc); */
553 /*    mpich_image_info *i_info   =
554       (mpich_image_info *)dbgr_get_image_info (image); */
555 
556   p_info->what = (mqs_op_class)op;
557 
558   switch (op) {
559   case mqs_pending_sends:
560       if (!p_info->has_sendq)
561 	  return mqs_no_information;
562       else {
563 	  p_info->next_msg = p_info->sendq_base;
564 	  return mqs_ok;
565       }
566 
567       /* The address on the receive queues is the address of a pointer to
568          the head of the list.  */
569   case mqs_pending_receives:
570       p_info->next_msg = p_info->posted_base;
571       return mqs_ok;
572 
573   case mqs_unexpected_messages:
574       p_info->next_msg = p_info->unexpected_base;
575       return mqs_ok;
576 
577   default:
578       return err_bad_request;
579   }
580 }
581 
582 /* Fetch the next operation on the current communicator, from the
583    selected queue. Since MPICH2 does not (normally) use separate queues
584    for each communicator, we must compare the queue items with the
585    current communicator.
586 */
mqs_next_operation(mqs_process * proc,mqs_pending_operation * op)587 int mqs_next_operation (mqs_process *proc, mqs_pending_operation *op)
588 {
589     mpich_process_info *p_info =
590 	(mpich_process_info *)dbgr_get_process_info (proc);
591 
592     switch (p_info->what) {
593     case mqs_pending_receives:
594 	return fetch_receive (proc,p_info,op,1);
595     case mqs_unexpected_messages:
596 	return fetch_receive (proc,p_info,op,0);
597     case mqs_pending_sends:
598 	return fetch_send (proc,p_info,op);
599     default: return err_bad_request;
600     }
601 }
602 /* ------------------------------------------------------------------------ */
603 /* Clean up routines
604  * These routines free any memory allocated when the process or image
605  * structures were allocated.
606  */
mqs_destroy_process_info(mqs_process_info * mp_info)607 void mqs_destroy_process_info (mqs_process_info *mp_info)
608 {
609     mpich_process_info *p_info = (mpich_process_info *)mp_info;
610 
611     /* Need to handle the communicators and groups too */
612     mqs_free_communicator_list( p_info->communicator_list );
613 
614     dbgr_free (p_info);
615 }
616 
mqs_destroy_image_info(mqs_image_info * info)617 void mqs_destroy_image_info (mqs_image_info *info)
618 {
619     dbgr_free (info);
620 }
621 
622 /* ------------------------------------------------------------------------ */
623 
624 /* ------------------------------------------------------------------------ */
625 /* Internal Routine
626  *
627  * These routine know about the internal structure of the MPI implementation.
628  */
629 
630 /* Get the next entry in the current receive queue (posted or unexpected) */
631 
fetch_receive(mqs_process * proc,mpich_process_info * p_info,mqs_pending_operation * res,int look_for_user_buffer)632 static int fetch_receive (mqs_process *proc, mpich_process_info *p_info,
633 			  mqs_pending_operation *res, int look_for_user_buffer)
634 {
635     mqs_image * image          = dbgr_get_image (proc);
636     mpich_image_info *i_info   = (mpich_image_info *)dbgr_get_image_info (image);
637     communicator_t   *comm     = p_info->current_communicator;
638     int16_t wanted_context     = comm->recvcontext_id;
639     mqs_taddr_t base           = fetch_pointer (proc, p_info->next_msg, p_info);
640 
641 #ifdef DEBUG_LIST_ITER
642     initLogFile();
643     fprintf( debugfp, "fetch receive base = %x, comm= %x, context = %d\n",
644 	    base, comm, wanted_context );
645 #endif
646     while (base != 0) {
647 	/* Check this entry to see if the context matches */
648 	int16_t actual_context = fetch_int16( proc, base + i_info->req_context_id_offs, p_info );
649 
650 #ifdef DEBUG_LIST_ITER
651 	initLogFile();
652 	fprintf( debugfp, "fetch receive msg context = %d\n", actual_context );
653 #endif
654 	if (actual_context == wanted_context) {
655 	    /* Found a request for this communicator */
656 	    int tag = fetch_int( proc, base + i_info->req_tag_offs, p_info );
657 	    int rank = fetch_int16( proc, base + i_info->req_rank_offs, p_info );
658 	    int is_complete   = fetch_int ( proc, base + i_info->req_cc_offs, p_info);
659 	    mqs_tword_t user_buffer = fetch_pointer( proc,base+i_info->req_user_buf_offs, p_info);
660 	    int   user_count  = fetch_int( proc,base + i_info->req_user_count_offs, p_info );
661 
662 	    /* Return -1 for ANY_TAG or ANY_SOURCE */
663 	    res->desired_tag         = (tag >= 0) ? tag : -1;
664 	    res->desired_local_rank  = (rank >= 0) ? rank : -1;
665 	    res->desired_global_rank = -1;   /* Convert to rank in comm world,
666 						if valid (in mpi-2, may
667 						not be available) */
668 	    res->desired_length      = user_count; /* Count, not bytes */
669 
670 	    res->tag_wild = (tag < 0);
671 	    res->buffer             = user_buffer;
672 	    /* We don't know the rest of these */
673 	    res->system_buffer      = 0;
674 	    res->actual_local_rank  = rank;
675 	    res->actual_global_rank = -1;
676 	    res->actual_tag         = tag;
677 	    res->actual_length      = -1;
678 	    res->extra_text[0][0]   = 0;
679 
680 	    res->status = (is_complete != 0) ? mqs_st_pending : mqs_st_complete;
681 
682 	    /* Don't forget to step the queue ! */
683 	    p_info->next_msg = base + i_info->req_next_offs;
684 	    return mqs_ok;
685 	}
686 	else {
687 	    /* Try the next one */
688 	    base = fetch_pointer (proc, base + i_info->req_next_offs, p_info);
689 	}
690     }
691 #if 0
692   while (base != 0)
693     { /* Well, there's a queue, at least ! */
694       mqs_tword_t actual_context = fetch_int16(proc, base + i_info->context_id_offs, p_info);
695 
696       if (actual_context == wanted_context)
697 	{ /* Found a good one */
698 	  mqs_tword_t tag     = fetch_int (proc, base + i_info->tag_offs, p_info);
699 	  mqs_tword_t tagmask = fetch_int (proc, base + i_info->tagmask_offs, p_info);
700 	  mqs_tword_t lsrc    = fetch_int (proc, base + i_info->lsrc_offs, p_info);
701 	  mqs_tword_t srcmask = fetch_int (proc, base + i_info->srcmask_offs, p_info);
702 	  mqs_taddr_t ptr     = fetch_pointer (proc, base + i_info->ptr_offs, p_info);
703 
704 	  /* Fetch the fields from the MPIR_RHANDLE */
705 	  int is_complete     = fetch_int (proc, ptr + i_info->is_complete_offs, p_info);
706 	  mqs_taddr_t buf     = fetch_pointer (proc, ptr + i_info->buf_offs, p_info);
707 	  mqs_tword_t len     = fetch_int (proc, ptr + i_info->len_offs, p_info);
708 	  mqs_tword_t count   = fetch_int (proc, ptr + i_info->count_offs, p_info);
709 
710 	  /* If we don't have start, then use buf instead... */
711 	  mqs_taddr_t start;
712 	  if (i_info->start_offs < 0)
713 	    start = buf;
714 	  else
715 	    start = fetch_pointer (proc, ptr + i_info->start_offs, p_info);
716 
717 	  /* Hurrah, we should now be able to fill in all the necessary fields in the
718 	   * result !
719 	   */
720 	  res->status = is_complete ? mqs_st_complete : mqs_st_pending; /* We can't discern matched */
721 	  if (srcmask == 0)
722 	    {
723 	      res->desired_local_rank  = -1;
724 	      res->desired_global_rank = -1;
725 	    }
726 	  else
727 	    {
728 	      res->desired_local_rank  = lsrc;
729 	      res->desired_global_rank = translate (comm->group, lsrc);
730 
731 	    }
732 	  res->tag_wild       = (tagmask == 0);
733 	  res->desired_tag    = tag;
734 
735 	  if (look_for_user_buffer)
736 	    {
737 		res->system_buffer  = 0;
738 	      res->buffer         = buf;
739 	      res->desired_length = len;
740 	    }
741 	  else
742 	    {
743 	      res->system_buffer  = 1;
744 	      /* Correct an oddity. If the buffer length is zero then no buffer
745 	       * is allocated, but the descriptor is left with random data.
746 	       */
747 	      if (count == 0)
748 		start = 0;
749 
750 	      res->buffer         = start;
751 	      res->desired_length = count;
752 	    }
753 
754 	  if (is_complete)
755 	    { /* Fill in the actual results, rather than what we were looking for */
756 	      mqs_tword_t mpi_source  = fetch_int (proc, ptr + i_info->MPI_SOURCE_offs, p_info);
757 	      mqs_tword_t mpi_tag  = fetch_int (proc, ptr + i_info->MPI_TAG_offs, p_info);
758 
759 	      res->actual_length     = count;
760 	      res->actual_tag        = mpi_tag;
761 	      res->actual_local_rank = mpi_source;
762 	      res->actual_global_rank= translate (comm->group, mpi_source);
763 	    }
764 
765 	  /* Don't forget to step the queue ! */
766 	  p_info->next_msg = base + i_info->next_offs;
767 	  return mqs_ok;
768 	}
769       else
770 	{ /* Try the next one */
771 	  base = fetch_pointer (proc, base + i_info->next_offs, p_info);
772 	}
773     }
774 #endif
775   p_info->next_msg = 0;
776   return mqs_end_of_list;
777 }  /* fetch_receive */
778 
779 /* Get the next entry in the send queue, if there is one.  The assumption is
780    that the MPI implementation is quiescent while these queue probes are
781    taking place, so we can simply keep track of the location of the "next"
782    entry. (in the next_msg field) */
fetch_send(mqs_process * proc,mpich_process_info * p_info,mqs_pending_operation * res)783 static int fetch_send (mqs_process *proc, mpich_process_info *p_info,
784 		       mqs_pending_operation *res)
785 {
786     mqs_image * image        = dbgr_get_image (proc);
787     mpich_image_info *i_info = (mpich_image_info *)dbgr_get_image_info (image);
788     communicator_t   *comm   = p_info->current_communicator;
789     int wanted_context       = comm->context_id;
790     mqs_taddr_t base         = fetch_pointer (proc, p_info->next_msg, p_info);
791 
792     if (!p_info->has_sendq)
793 	return mqs_no_information;
794 
795 #ifdef DEBUG_LIST_ITER
796     if (base) {
797 	initLogFile();
798 	fprintf( debugf, "comm ptr = %p, comm context = %d\n",
799 		 comm, comm->context_id );
800     }
801 #endif
802     /* Say what operation it is. We can only see non blocking send operations
803      * in MPICH. Other MPI systems may be able to show more here.
804      */
805     /* FIXME: handle size properly (declared as 64 in mpi_interface.h) */
806     strncpy ((char *)res->extra_text[0],"Non-blocking send",20);
807     res->extra_text[1][0] = 0;
808 
809     while (base != 0) {
810 	/* Check this entry to see if the context matches */
811 	int actual_context = fetch_int16( proc, base + i_info->sendq_context_id_offs, p_info );
812 
813 	if (actual_context == wanted_context) {
814 	    /* Fill in some of the fields */
815 	    mqs_tword_t target = fetch_int (proc, base+i_info->sendq_rank_offs,      p_info);
816 	    mqs_tword_t tag    = fetch_int (proc, base+i_info->sendq_tag_offs,         p_info);
817 	    mqs_tword_t length = 0;
818 	    mqs_taddr_t data   = 0;
819 	    mqs_taddr_t sreq = fetch_pointer(proc, base+i_info->sendq_req_offs, p_info );
820 	    mqs_tword_t is_complete = fetch_int( proc, sreq+i_info->req_cc_offs, p_info );
821 	    data = fetch_pointer( proc, sreq+i_info->req_user_buf_offs, p_info );
822 	    length = fetch_int( proc, sreq+i_info->req_user_count_offs, p_info );
823 	    /* mqs_tword_t complete=0; */
824 
825 #ifdef DEBUG_LIST_ITER
826 	    initLogFile();
827 	    fprintf( debugpf, "sendq entry = %p, rank off = %d, tag off = %d, context = %d\n",
828 		    base, i_info->sendq_rank_offs, i_info->sendq_tag_offs, actual_context );
829 #endif
830 
831 	    /* Ok, fill in the results */
832 	    res->status = (is_complete != 0) ? mqs_st_pending : mqs_st_complete;
833 	    res->actual_local_rank = res->desired_local_rank = target;
834 	    res->actual_global_rank= res->desired_global_rank= translate (comm->group, target);
835 	    res->tag_wild       = 0;
836 	    res->actual_tag     = res->desired_tag = tag;
837 	    res->desired_length = res->actual_length = length;
838 	    res->system_buffer  = 0;
839 	    res->buffer         = data;
840 
841 
842 	    /* Don't forget to step the queue ! */
843 	    p_info->next_msg = base + i_info->sendq_next_offs;
844 	    return mqs_ok;
845 	}
846 	else {
847 	    /* Try the next one */
848 	    base = fetch_pointer (proc, base + i_info->sendq_next_offs, p_info);
849 	}
850     }
851 #if 0
852   while (base != 0)
853     { /* Well, there's a queue, at least ! */
854       /* Check if it's one we're interested in ? */
855       mqs_taddr_t commp = fetch_pointer (proc, base+i_info->db_comm_offs, p_info);
856       mqs_taddr_t next  = base+i_info->db_next_offs;
857 
858       if (commp == comm->comm_info.unique_id)
859 	{ /* Found one */
860 	  mqs_tword_t target = fetch_int (proc, base+i_info->db_target_offs,      p_info);
861 	  mqs_tword_t tag    = fetch_int (proc, base+i_info->db_tag_offs,         p_info);
862 	  mqs_tword_t length = fetch_int (proc, base+i_info->db_byte_length_offs, p_info);
863 	  mqs_taddr_t data   = fetch_pointer (proc, base+i_info->db_data_offs,    p_info);
864 	  mqs_taddr_t shandle= fetch_pointer (proc, base+i_info->db_shandle_offs, p_info);
865 	  mqs_tword_t complete=fetch_int (proc, shandle+i_info->is_complete_offs, p_info);
866 
867 	  /* Ok, fill in the results */
868 	  res->status = complete ? mqs_st_complete : mqs_st_pending; /* We can't discern matched */
869 	  res->actual_local_rank = res->desired_local_rank = target;
870 	  res->actual_global_rank= res->desired_global_rank= translate (comm->group, target);
871 	  res->tag_wild   = 0;
872 	  res->actual_tag = res->desired_tag = tag;
873 	  res->desired_length = res->actual_length = length;
874 	  res->system_buffer  = 0;
875 	  res->buffer = data;
876 
877 	  p_info->next_msg = next;
878 	  return mqs_ok;
879 	}
880 
881       base = fetch_pointer (proc, next, p_info);
882     }
883 
884   p_info->next_msg = 0;
885 #endif
886   return mqs_end_of_list;
887 } /* fetch_send */
888 
889 /* ------------------------------------------------------------------------ */
890 /* Communicator */
communicators_changed(mqs_process * proc)891 static int communicators_changed (mqs_process *proc)
892 {
893     mpich_process_info *p_info =
894 	(mpich_process_info *)dbgr_get_process_info (proc);
895     mqs_image * image          = dbgr_get_image (proc);
896     mpich_image_info *i_info   =
897 	(mpich_image_info *)dbgr_get_image_info (image);
898     mqs_tword_t new_seq = fetch_int (proc,
899 				     p_info->commlist_base+i_info->sequence_number_offs,
900 				     p_info);
901     int  res = (new_seq != p_info->communicator_sequence);
902 
903     /* Save the sequence number for next time */
904     p_info->communicator_sequence = new_seq;
905 
906     return res;
907 }
908 
909 /***********************************************************************
910  * Find a matching communicator on our list. We check the recv context
911  * as well as the address since the communicator structures may be
912  * being re-allocated from a free list, in which case the same
913  * address will be re-used a lot, which could confuse us.
914  */
find_communicator(mpich_process_info * p_info,mqs_taddr_t comm_base,int recv_ctx)915 static communicator_t * find_communicator ( mpich_process_info *p_info,
916 					    mqs_taddr_t comm_base, int recv_ctx)
917 {
918   communicator_t * comm = p_info->communicator_list;
919 
920   for (; comm; comm=comm->next)
921     {
922       if (comm->comm_info.unique_id == comm_base &&
923 	  comm->recvcontext_id == recv_ctx)
924 	return comm;
925     }
926 
927   return NULL;
928 } /* find_communicator */
929 /* This is the comparison function used in the qsort call in
930    rebuild_communicator_list */
compare_comms(const void * a,const void * b)931 static int compare_comms (const void *a, const void *b)
932 {
933   communicator_t * ca = *(communicator_t **)a;
934   communicator_t * cb = *(communicator_t **)b;
935 
936   return cb->recvcontext_id - ca->recvcontext_id;
937 } /* compare_comms */
rebuild_communicator_list(mqs_process * proc)938 static int rebuild_communicator_list (mqs_process *proc)
939 {
940     mpich_process_info *p_info =
941 	(mpich_process_info *)dbgr_get_process_info (proc);
942     mqs_image * image          = dbgr_get_image (proc);
943     mpich_image_info *i_info   =
944 	(mpich_image_info *)dbgr_get_image_info (image);
945     mqs_taddr_t comm_base = fetch_pointer (proc,
946 					   p_info->commlist_base+i_info->comm_head_offs,
947 					   p_info);
948 
949     communicator_t **commp;
950     int commcount = 0;
951 
952     /* Iterate over the list in the process comparing with the list
953      * we already have saved. This is n**2, because we search for each
954      * communicator on the existing list. I don't think it matters, though
955      * because there aren't that many communicators to worry about, and
956      * we only ever do this if something changed.
957      */
958     while (comm_base) {
959 	/* We do have one to look at, so extract the info */
960 	int recv_ctx = fetch_int16 (proc, comm_base+i_info->comm_recvcontext_id_offs, p_info);
961 	int send_ctx = fetch_int16 (proc, comm_base+i_info->comm_context_id_offs, p_info);
962 	communicator_t *old = find_communicator (p_info, comm_base, recv_ctx);
963 
964 	char *name = (char *)"--unnamed--";
965 	char namebuffer[64];
966 	/* In MPICH2, the name is preallocated and of size MPI_MAX_OBJECT_NAME */
967 	if (dbgr_fetch_data( proc, comm_base+i_info->comm_name_offs,64,
968 			     namebuffer) == mqs_ok && namebuffer[0] != 0) {
969 	    name = namebuffer;
970 	}
971 
972 	if (old) {
973 	    old->present = 1;		/* We do want this communicator */
974 	    strncpy (old->comm_info.name, name, sizeof(old->comm_info.name) ); /* Make sure the name is up to date,
975 						    * it might have changed and we can't tell.
976 						    */
977 	}
978 	else {
979 	    mqs_taddr_t group_base = fetch_pointer (proc, comm_base+i_info->lrank_to_grank_offs,
980 					      p_info);
981 	    int np     = fetch_int (proc, comm_base+i_info->comm_rsize_offs,p_info);
982 	    group_t *g = find_or_create_group (proc, np, group_base);
983 	    communicator_t *nc;
984 
985 #if 0
986 	    if (!g)
987 		return err_group_corrupt;
988 #endif
989 
990 	    nc = (communicator_t *)dbgr_malloc (sizeof (communicator_t));
991 
992 	    /* Save the results */
993 	    nc->next = p_info->communicator_list;
994 	    p_info->communicator_list = nc;
995 	    nc->present               = 1;
996 	    nc->group                 = g;
997 	    nc->context_id            = send_ctx;
998 	    nc->recvcontext_id        = recv_ctx;
999 
1000 	    strncpy (nc->comm_info.name, name, sizeof( nc->comm_info.name ) );
1001 	    nc->comm_info.unique_id = comm_base;
1002 	    nc->comm_info.size      = np;
1003 	    nc->comm_info.local_rank = fetch_int (proc, comm_base+i_info->comm_rank_offs,p_info);
1004 #ifdef DEBUG_LIST_ITER
1005 	    initLogFile();
1006 	    fprintf( debugfp, "Adding communicator %p, send context=%d, recv context=%d, size=%d, name=%s\n",
1007 		    comm_base, send_ctx, recv_ctx, np, name );
1008 #endif
1009 #if 0
1010 	    nc->comm_info.local_rank= reverse_translate (g, dbgr_get_global_rank (proc));
1011 #endif
1012 	}
1013 	/* Step to the next communicator on the list */
1014 	comm_base = fetch_pointer (proc, comm_base+i_info->comm_next_offs, p_info);
1015     }
1016 
1017     /* Now iterate over the list tidying up any communicators which
1018      * no longer exist, and cleaning the flags on any which do.
1019      */
1020     commp = &p_info->communicator_list;
1021 
1022     for (; *commp; commp = &(*commp)->next) {
1023 	communicator_t *comm = *commp;
1024 
1025 	if (comm->present) {
1026 	    comm->present = 0;
1027 	    commcount++;
1028 	}
1029 	else {
1030 	    /* It needs to be deleted */
1031 	    *commp = comm->next;			/* Remove from the list */
1032 	    group_decref (comm->group);		/* Group is no longer referenced from here */
1033 	    dbgr_free (comm);
1034 	}
1035     }
1036 
1037     if (commcount) {
1038 	/* Sort the list so that it is displayed in some semi-sane order. */
1039 	communicator_t ** comm_array = (communicator_t **) dbgr_malloc (
1040 					commcount * sizeof (communicator_t *));
1041 	communicator_t *comm = p_info->communicator_list;
1042 	int i;
1043 	for (i=0; i<commcount; i++, comm=comm->next)
1044 	    comm_array [i] = comm;
1045 
1046 	/* Do the sort */
1047 	qsort (comm_array, commcount, sizeof (communicator_t *), compare_comms);
1048 
1049 	/* Re build the list */
1050 	p_info->communicator_list = NULL;
1051 	for (i=0; i<commcount; i++) {
1052 	    comm = comm_array[i];
1053 	    comm->next = p_info->communicator_list;
1054 	    p_info->communicator_list = comm;
1055 	}
1056 
1057 	dbgr_free (comm_array);
1058     }
1059 
1060     return mqs_ok;
1061 } /* rebuild_communicator_list */
1062 
1063 /* Internal routine to free the communicator list */
mqs_free_communicator_list(struct communicator_t * comm)1064 static void mqs_free_communicator_list( struct communicator_t *comm )
1065 {
1066     while (comm) {
1067 	communicator_t *next = comm->next;
1068 
1069 	/* Release the group data structures */
1070 	/* group_decref (comm->group);		 */
1071 	dbgr_free (comm);
1072 
1073 	comm = next;
1074     }
1075 }
1076 
1077 /* ------------------------------------------------------------------------ */
1078 /* Internal routine to fetch data from the process */
fetch_pointer(mqs_process * proc,mqs_taddr_t addr,mpich_process_info * p_info)1079 static mqs_taddr_t fetch_pointer (mqs_process * proc, mqs_taddr_t addr,
1080 				  mpich_process_info *p_info)
1081 {
1082     int asize = p_info->sizes.pointer_size;
1083     char data [8];			/* ASSUME a pointer fits in 8 bytes */
1084     mqs_taddr_t res = 0;
1085 
1086     if (mqs_ok == dbgr_fetch_data (proc, addr, asize, data))
1087 	dbgr_target_to_host (proc, data,
1088 			     ((char *)&res) + (host_is_big_endian ? sizeof(mqs_taddr_t)-asize : 0),
1089 			     asize);
1090 
1091     return res;
1092 }
fetch_int(mqs_process * proc,mqs_taddr_t addr,mpich_process_info * p_info)1093 static mqs_tword_t fetch_int (mqs_process * proc, mqs_taddr_t addr,
1094 			      mpich_process_info *p_info)
1095 {
1096     int isize = p_info->sizes.int_size;
1097     char buffer[8];			/* ASSUME an integer fits in 8 bytes */
1098     mqs_tword_t res = 0;
1099 
1100     if (mqs_ok == dbgr_fetch_data (proc, addr, isize, buffer))
1101 	dbgr_target_to_host (proc, buffer,
1102 			     ((char *)&res) + (host_is_big_endian ? sizeof(mqs_tword_t)-isize : 0),
1103 			     isize);
1104 
1105     return res;
1106 }
fetch_int16(mqs_process * proc,mqs_taddr_t addr,mpich_process_info * p_info)1107 static mqs_tword_t fetch_int16 (mqs_process * proc, mqs_taddr_t addr,
1108 				mpich_process_info *p_info)
1109 {
1110     char buffer[8];			/* ASSUME an integer fits in 8 bytes */
1111     int16_t res = 0;
1112 
1113     if (mqs_ok == dbgr_fetch_data (proc, addr, 2, buffer))
1114 	dbgr_target_to_host (proc, buffer,
1115 			     ((char *)&res) + (host_is_big_endian ? sizeof(mqs_tword_t)-2 : 0),
1116 			     2);
1117 
1118     return res;
1119 }
1120 
1121 /* ------------------------------------------------------------------------- */
1122 /* With each communicator we need to translate ranks to/from their
1123    MPI_COMM_WORLD equivalents.  This code is not yet implemented
1124 */
1125 /* ------------------------------------------------------------------------- */
1126 /* idx is rank in group this; return rank in MPI_COMM_WORLD */
translate(group_t * this,int idx)1127 static int translate (group_t *this, int idx)
1128 {
1129     return -1;
1130 }
1131 #if 0
1132 /* idx is rank in MPI_COMM_WORLD, return rank in group this */
1133 static int reverse_translate (group_t * this, int idx)
1134 {
1135     return -1;
1136 }
1137 #endif
find_or_create_group(mqs_process * proc,mqs_tword_t np,mqs_taddr_t table)1138 static group_t * find_or_create_group (mqs_process *proc,
1139 				       mqs_tword_t np,
1140 				       mqs_taddr_t table)
1141 {
1142     return 0;
1143 }
group_decref(group_t * group)1144 static void group_decref (group_t * group)
1145 {
1146     if (--(group->ref_count) == 0) {
1147 	dbgr_free (group->local_to_global);
1148 	dbgr_free (group);
1149     }
1150 } /* group_decref */
1151