/*
 * Copyright (c) 2007-2008 Cisco Systems, Inc.  All rights reserved.
 * Copyright (c) 2004-2007 The University of Tennessee and The University
 *                         of Tennessee Research Foundation.  All rights
 *                         reserved.
 * Copyright (c) 2008      Sun Microsystems, Inc.  All rights reserved.
 * $COPYRIGHT$
 * 
 * Additional copyrights may follow
 * 
 * $HEADER$
 */

/**********************************************************************
 * Copyright (C) 2000-2004 by Etnus, LLC.
 * Copyright (C) 1999 by Etnus, Inc.
 * Copyright (C) 1997-1998 Dolphin Interconnect Solutions Inc.
 *
 * Permission is hereby granted to use, reproduce, prepare derivative
 * works, and to redistribute to others.
 *
 *				  DISCLAIMER
 *
 * Neither Dolphin Interconnect Solutions, Etnus LLC, nor any of their
 * employees, makes any warranty express or implied, or assumes any
 * legal liability or responsibility for the accuracy, completeness,
 * or usefulness of any information, apparatus, product, or process
 * disclosed, or represents that its use would not infringe privately
 * owned rights.
 *
 * This code was written by
 * James Cownie: Dolphin Interconnect Solutions. <jcownie@dolphinics.com>
 *               Etnus LLC <jcownie@etnus.com>
 **********************************************************************/

#include "ompi_config.h"

#if defined(HAVE_STRING_H)
#include <string.h>
#endif  /* defined(HAVE_STRING_H) */
#if defined(HAVE_STDLIB_H)
#include <stdlib.h>
#endif  /* defined(HAVE_STDLIB_H) */

#include "ompi/mca/pml/base/pml_base_request.h"
#include "mpihandles_interface.h"
#include "ompi_mpihandles_dll_defs.h"
#include "ompi/communicator/communicator.h"


#define OPAL_ALIGN(x,a,t) (((x)+((t)(a)-1)) & ~(((t)(a)-1)))

/* Globals that the debugger expects to find in the DLL */
#if defined(WORDS_BIGENDIAN)
char mpidbg_dll_is_big_endian = 1;
#else
char mpidbg_dll_is_big_endian = 0;
#endif
char mpidbg_dll_bitness = (char) (sizeof(void*) * 8);
enum mpidbg_comm_capabilities_t mpidbg_comm_capabilities = 0;
struct mpidbg_name_map_t *mpidbg_comm_name_map = NULL;
enum mpidbg_errhandler_capabilities_t mpidbg_errhandler_capabilities = 0;
struct mpidbg_name_map_t *mpidbg_errhandler_name_map = NULL;
enum mpidbg_request_capabilities_t mpidbg_request_capabilities = 0;
struct mpidbg_name_map_t *mpidbg_request_name_map = NULL;
enum mpidbg_status_capabilities_t mpidbg_status_capabilities = 0;
struct mpidbg_name_map_t *mpidbg_status_name_map = NULL;

#if defined(__SUNPRO_C)
/*
 * These symbols are defined here because of the different way compilers
 * may handle extern definitions. The particular case that is causing 
 * problems is when there is an extern variable that is accessed in a 
 * static inline function. For example, here is the code we often see in 
 * a header file.
 * 
 * extern int request_complete;
 * static inline check_request(void) {
 *    request_complete = 1;
 * }
 *
 * If this code exists in a header file and gets included in a source 
 * file, then some compilers expect to have request_complete defined 
 * somewhere even if request_complete is never referenced and 
 * check_request is never called. Other compilers do not need them defined 
 * if they are never referenced in the source file. Therefore, to handle 
 * cases like the above with compilers that require the symbol (like 
 * Sun Studio) we add in these definitions here.
 */
size_t ompi_request_completed;
opal_condition_t ompi_request_cond;
size_t ompi_request_waiting;
opal_mutex_t ompi_request_lock;
opal_mutex_t opal_event_lock;
uint32_t opal_progress_recursion_depth_counter;
int opal_progress_spin_count;
volatile int32_t opal_progress_thread_count;
bool opal_mutex_check_locks;
bool opal_uses_threads;
#endif /* defined(__SUNPRO_C) */

/*---------------------------------------------------------------------*/

/* Small helper function: allocate a map of a given length */
static struct mpidbg_name_map_t *alloc_map(mqs_image *image, int len)
{
    mpi_image_info *i_info = (mpi_image_info *) mqs_get_image_info(image);
    struct mpidbg_name_map_t *m = NULL;

    if (NULL != i_info) {
        m = mqs_malloc(len * sizeof(struct mpidbg_name_map_t));
    }

    return m;
}

/* Small helper function: look up a symbol, and if we find it, put it
   in a map entry */
static void fill_map(mqs_image *image, 
                     char *public_name, char *private_name,
                     struct mpidbg_name_map_t *map)
{
    mqs_taddr_t value;
    mpi_image_info *i_info = (mpi_image_info *) mqs_get_image_info(image);

    if (NULL != i_info) {
        map->map_name = strdup(public_name);
        if (NULL != private_name) {
            if (mqs_ok == mqs_find_symbol(image, private_name, &value)) {
                map->map_handle = value;
                return;
            }
        } else {
            map->map_handle = 0;
            return;
        }
    }

    printf("OMPI MPI handles DLL: fill_map: Unable to find symbol: %s\n", 
           private_name);
}

/* Helper function to lookup MPI attributes and fill an
   mpidbg_attribute_pair_t array with their keys/values */
static int fill_attributes(int *num_attrs, 
                           struct mpidbg_attribute_pair_t **attrs, 
                           mqs_taddr_t table)
{
    /* JMS fill me in */
    return mqs_ok;
}

/*---------------------------------------------------------------------*/

int mpidbg_init_once(const mqs_basic_callbacks *cb)
{
    mqs_basic_entrypoints = cb;
    printf("mpidbg_init_once\n");
    return MPIDBG_SUCCESS;
}

/*---------------------------------------------------------------------*/

/* Returns the fixed value */
int mpidbg_interface_version_compatibility(void)
{
    printf("mpidbg_interface_version_compatibility\n");
    return MPIDBG_INTERFACE_VERSION;
}


/* Returns a string specific to OMPI */
char *mpidbg_version_string(void)
{
    printf("mpidbg_version_string\n");
    return "Open MPI handle interpretation support for parallel"
           " debuggers compiled on " __DATE__;
}


/* So the debugger can tell what interface width the library was
   compiled with */
int mpidbg_dll_taddr_width(void)
{
    printf("mpidbg_dll_taddr_width\n");
    return sizeof(mqs_taddr_t);
}

/*---------------------------------------------------------------------*/

/* Once-per-image setup */
int mpidbg_init_per_image(mqs_image *image, const mqs_image_callbacks *icb,
                          struct mpidbg_handle_info_t *handle_types)
{
    char **message;
    mpi_image_info *i_info = 
        (mpi_image_info *) mqs_malloc(sizeof(mpi_image_info));
    printf("mpidbg_init_per_image\n");

    if (NULL == i_info) {
        printf("mpidbg_init_per_image: malloc failed!\n");
        return MPIDBG_ERR_NO_MEM;
    }

    memset((void *)i_info, 0, sizeof(mpi_image_info));
    /* Before we do *ANYTHING* else */
    i_info->image_callbacks = icb;

    /* Nothing extra (yet) */
    i_info->extra = NULL;

    /* Save the info */
    mqs_put_image_info(image, (mqs_image_info *)i_info);

    /* Fill in the OMPI type information */
    if (mqs_ok != ompi_fill_in_type_info(image, message)) {
        printf("mpidbg_init_per_image: failed to get all type info\n");
        return MPIDBG_ERR_NOT_SUPPORTED;
    }

    /* Fill in the handle_types struct with our types */
    /* JMS: "MPI_Aint" is a typedef -- is that enough?  (the actual
       type is a #define, so it's not easy to put into the
       mqs_find_type call as a string) */
    handle_types->hi_c_aint = mqs_find_type(image, "MPI_Aint", mqs_lang_c);
    /* JMS: these ompi types are just the "foo" types; but OMPI MPI
       types are all "foo*"'s -- is this right?  If this is wrong, I
       *suspect* that something like the following may be right:
       
       handle_types->hi_c_comm = mqs_find_type(image, "ompi_communicator_t*", mqs_lang_c);

       Need to confirm this with the DDT guys...
    */
    handle_types->hi_c_comm = i_info->ompi_communicator_t.type;
    handle_types->hi_c_datatype = i_info->ompi_datatype_t.type;
    handle_types->hi_c_errhandler = 
        mqs_find_type(image, "ompi_errhandler_t", mqs_lang_c);
    handle_types->hi_c_file = 
        mqs_find_type(image, "ompi_file_t", mqs_lang_c);
    handle_types->hi_c_group = i_info->ompi_group_t.type;
    handle_types->hi_c_info = 
        mqs_find_type(image, "ompi_info_t", mqs_lang_c);
    /* JMS: "MPI_Offset" is a typedef (see comment about MPI_Aint above) */
    handle_types->hi_c_offset =
        mqs_find_type(image, "MPI_Offset", mqs_lang_c);
    handle_types->hi_c_op = 
        mqs_find_type(image, "ompi_op_t", mqs_lang_c);
    handle_types->hi_c_request = i_info->ompi_request_t.type;
    handle_types->hi_c_status = i_info->ompi_status_public_t.type;
    handle_types->hi_c_win = 
        mqs_find_type(image, "ompi_win_t", mqs_lang_c);

    /* MPI::Aint is a typedef to MPI_Aint */
    handle_types->hi_cxx_aint = handle_types->hi_cxx_aint;
    handle_types->hi_cxx_comm =
        mqs_find_type(image, "MPI::Comm", mqs_lang_cplus);
    handle_types->hi_cxx_intracomm =
        mqs_find_type(image, "MPI::Intracomm", mqs_lang_cplus);
    handle_types->hi_cxx_intercomm =
        mqs_find_type(image, "MPI::Intercomm", mqs_lang_cplus);
    handle_types->hi_cxx_graphcomm =
        mqs_find_type(image, "MPI::Graphcomm", mqs_lang_cplus);
    handle_types->hi_cxx_cartcomm =
        mqs_find_type(image, "MPI::Cartcomm", mqs_lang_cplus);
    handle_types->hi_cxx_datatype =
        mqs_find_type(image, "MPI::Datatype", mqs_lang_cplus);
    handle_types->hi_cxx_errhandler =
        mqs_find_type(image, "MPI::Errhandler", mqs_lang_cplus);
    handle_types->hi_cxx_file =
        mqs_find_type(image, "MPI::File", mqs_lang_cplus);
    handle_types->hi_cxx_group =
        mqs_find_type(image, "MPI::Group", mqs_lang_cplus);
    handle_types->hi_cxx_info =
        mqs_find_type(image, "MPI::Info", mqs_lang_cplus);
    /* MPI::Offset is a typedef to MPI_Offset */
    handle_types->hi_cxx_offset = handle_types->hi_c_offset;
    handle_types->hi_cxx_op =
        mqs_find_type(image, "MPI::Op", mqs_lang_cplus);
    handle_types->hi_cxx_request =
        mqs_find_type(image, "MPI::Request", mqs_lang_cplus);
    handle_types->hi_cxx_prequest =
        mqs_find_type(image, "MPI::Prequest", mqs_lang_cplus);
    handle_types->hi_cxx_grequest =
        mqs_find_type(image, "MPI::Grequest", mqs_lang_cplus);
    handle_types->hi_cxx_status =
        mqs_find_type(image, "MPI::Status", mqs_lang_cplus);
    handle_types->hi_cxx_win =
        mqs_find_type(image, "MPI::Win", mqs_lang_cplus);

    /* Tell the debuger what capabilities we have */
    mpidbg_comm_capabilities = 
        MPIDBG_COMM_CAP_BASIC | 
        MPIDBG_COMM_CAP_STRING_NAMES | 
        MPIDBG_COMM_CAP_FREED_HANDLE | 
        MPIDBG_COMM_CAP_FREED_OBJECT;
    mpidbg_errhandler_capabilities =
        MPIDBG_ERRH_CAP_BASIC | 
        MPIDBG_ERRH_CAP_STRING_NAMES | 
        MPIDBG_ERRH_CAP_FREED_HANDLE | 
        MPIDBG_ERRH_CAP_FREED_OBJECT;
    mpidbg_request_capabilities = 
        MPIDBG_REQUEST_CAP_BASIC;
    mpidbg_status_capabilities = 
        MPIDBG_STATUS_CAP_BASIC;

    /* All done */
    printf("mpidbg_init_per_image: init succeeded -- ready!\n");
    return MPIDBG_SUCCESS;
}


/* This image is now dead; free all the state associated with it */
void mpidbg_finalize_per_image(mqs_image *image, mqs_image_info *info)
{
    mpi_image_info *i_info = (mpi_image_info *)info;

    printf("mpidbg_finalize_per_image\n");
    if (NULL != i_info->extra) {
        mqs_free(i_info->extra);
    }
    mqs_free(info);
}

/*---------------------------------------------------------------------*/

/* Setup information needed for a specific process.  The debugger
 * assumes that this will hang something onto the process, if nothing
 * is attached to it, then TV will believe that this process has no
 * message queue information.
 */
int mpidbg_init_per_process(mqs_process *process, 
                            const mqs_process_callbacks *pcb,
                            struct mpidbg_handle_info_t *handle_types)
{ 
    mqs_image *image;
    mpi_image_info *i_info;

    /* Extract the addresses of the global variables we need and save
       them away */
    mpi_process_info *p_info = 
        (mpi_process_info *) mqs_malloc(sizeof(mpi_process_info));
    printf("mpidbg_init_per_process\n");

    if (NULL == p_info) {
        return MPIDBG_ERR_NO_MEM;
    }

    /* Setup the callbacks first */
    p_info->process_callbacks = pcb;

    /* Nothing extra (yet) */
    p_info->extra = NULL;

    /* Now we can get the rest of the info */
    image = mqs_get_image(process);
    i_info = (mpi_image_info *) mqs_get_image_info(image);

    /* Get process info sizes */
    mqs_get_type_sizes (process, &p_info->sizes);

    /* Save the info */
    mqs_put_process_info(process, (mqs_process_info *) p_info);

    /* Fill in pre-defined MPI handle name mappings (because OMPI uses
       #define's for the pre-defined names, such as "#define
       MPI_COMM_WORLD &ompi_mpi_comm_world"). */
    /* Communicators */
    mpidbg_comm_name_map = alloc_map(image, 4);
    if (NULL != mpidbg_comm_name_map) {
        int i = 0;
        fill_map(image, "MPI_COMM_WORLD", "ompi_mpi_comm_world",
                 &mpidbg_comm_name_map[i++]);
        fill_map(image, "MPI_COMM_SELF", "ompi_mpi_comm_self",
                 &mpidbg_comm_name_map[i++]);
        fill_map(image, "MPI_COMM_NULL", "ompi_mpi_comm_null",
                 &mpidbg_comm_name_map[i++]);

        /* Sentinel value */
        mpidbg_comm_name_map[i].map_name = NULL;
    }

    /* Error handlers */
    mpidbg_errhandler_name_map = alloc_map(image, 4);
    if (NULL != mpidbg_errhandler_name_map) {
        int i = 0;
        fill_map(image, "MPI_ERRORS_ARE_FATAL", "ompi_mpi_errors_are_fatal",
                 &mpidbg_errhandler_name_map[i++]);
        fill_map(image, "MPI_ERRORS_RETURN", "ompi_mpi_errors_return",
                 &mpidbg_errhandler_name_map[i++]);
        fill_map(image, "MPI_ERRHANDLER_NULL", "ompi_mpi_errhandler_null",
                 &mpidbg_errhandler_name_map[i++]);
        /* MPI::ERRORS_THROW_EXCEPTIONS exists as a symbol in OMPI; no
           need to alias it here */

        /* Sentinel value */
        mpidbg_errhandler_name_map[i].map_name = NULL;
    }

    /* Requests */
    mpidbg_request_name_map = alloc_map(image, 2);
    if (NULL != mpidbg_request_name_map) {
        int i = 0;
        fill_map(image, "MPI_REQUEST_NULL", "ompi_request_null",
                 &mpidbg_request_name_map[i++]);

        /* Sentinel value */
        mpidbg_request_name_map[i].map_name = NULL;
    }

    /* Statuses */
    mpidbg_status_name_map = alloc_map(image, 2);
    if (NULL != mpidbg_status_name_map) {
        int i = 0;
        fill_map(image, "MPI_STATUS_IGNORE", NULL,
                 &mpidbg_status_name_map[i++]);

        /* Sentinel value */
        mpidbg_status_name_map[i].map_name = NULL;
    }

    /* All done */
    return MPIDBG_SUCCESS;
}


/* This process is now done; free all the state associated with it */
void mpidbg_finalize_per_process(mqs_process *process, mqs_process_info *info)
{
    mpi_process_info *p_info = (mpi_process_info *)info;

    printf("mpidbg_finalize_per_process\n");
    if (NULL != p_info->extra) {
        mqs_free(p_info->extra);
    }
    mqs_free(info);
}


/*---------------------------------------------------------------------*/

int mpidbg_comm_query(mqs_image *image, mqs_image_info *image_info, 
                      mqs_process *process, mqs_process_info *process_info,
                      mqs_taddr_t c_comm, struct mpidbg_comm_info_t **info)
{
    int flags;
    mpi_image_info *i_info = (mpi_image_info*) image_info;
    mpi_process_info *p_info = (mpi_process_info*) process_info;
    mqs_taddr_t group, topo, keyhash;

    /* Get the comm name */

    *info = mqs_malloc(sizeof(struct mpidbg_comm_info_t));
    if (NULL == *info) {
        return MPIDBG_ERR_NO_MEM;
    }
    /* JMS temporarily zero everything out.  Remove this when we fill
       in all the fields */
    memset(*info, 0, sizeof(struct mpidbg_comm_info_t));
    (*info)->comm_c_handle = c_comm;

    printf("mpidbg_comm_query: %p\n", (void*) c_comm);
    mqs_fetch_data(process, c_comm + i_info->ompi_communicator_t.offset.c_name,
                   MPIDBG_MAX_OBJECT_NAME, (*info)->comm_name);

    /* Get this process' rank in the comm */
    (*info)->comm_rank = ompi_fetch_int(process, 
                                        c_comm + i_info->ompi_communicator_t.offset.c_my_rank,
                                        p_info);

    /* Analyze the flags on the comm */
    flags = ompi_fetch_int(process, 
                           c_comm + i_info->ompi_communicator_t.offset.c_flags,
                           p_info);
    (*info)->comm_bitflags = 0;
    if (MPI_PROC_NULL == (*info)->comm_rank) {
        /* This communicator is MPI_COMM_NULL */
        (*info)->comm_rank = (*info)->comm_size = 0;
        (*info)->comm_bitflags |= MPIDBG_COMM_INFO_COMM_NULL;
    } else if (0 != (flags & OMPI_COMM_INTER)) {
        (*info)->comm_bitflags |= MPIDBG_COMM_INFO_INTERCOMM;
    } else {
        if (0 != (flags & OMPI_COMM_CART)) {
            (*info)->comm_bitflags |= MPIDBG_COMM_INFO_CARTESIAN;
        } else if (0 != (flags & OMPI_COMM_GRAPH)) {
            (*info)->comm_bitflags |= MPIDBG_COMM_INFO_GRAPH;
        }
    }
    if (0 != (flags & OMPI_COMM_ISFREED)) {
        (*info)->comm_bitflags |= MPIDBG_COMM_INFO_FREED_HANDLE;
    }
    if (0 != (flags & OMPI_COMM_INTRINSIC)) {
        (*info)->comm_bitflags |= MPIDBG_COMM_INFO_PREDEFINED;
    }
    if (0 != (flags & OMPI_COMM_INVALID)) {
        (*info)->comm_bitflags |= MPIDBG_COMM_INFO_FREED_OBJECT;
    }
    
    /* Look up the local group */
    group = ompi_fetch_pointer(process, 
                               c_comm + i_info->ompi_communicator_t.offset.c_local_group,
                               p_info);
    (*info)->comm_rank = ompi_fetch_int(process, 
                                        group + i_info->ompi_group_t.offset.grp_my_rank,
                                        p_info);
    (*info)->comm_num_local_procs = ompi_fetch_int(process, 
                                                   group + i_info->ompi_group_t.offset.grp_proc_count,
                                                   p_info);

    /* Fill in the comm_size with the size of the local group.  We'll
       override below if this is an intercommunicator. */
    (*info)->comm_size = (*info)->comm_num_local_procs;

    /* JMS fill this in: waiting to decide between mpidbg_process_t
       and mqs_process_location */
    (*info)->comm_local_procs = NULL;

    /* Look up the remote group (if relevant) */
    if (0 != (flags & OMPI_COMM_INTER)) {
        group = ompi_fetch_pointer(process, 
                                   c_comm + i_info->ompi_communicator_t.offset.c_remote_group,
                                   p_info);
        (*info)->comm_num_remote_procs = ompi_fetch_int(process, 
                                                        group + i_info->ompi_group_t.offset.grp_proc_count,
                                                        p_info);
        (*info)->comm_size = (*info)->comm_num_remote_procs;

        /* JMS fill this in: waiting to decide between
           mpidbg_process_t and mqs_process_location */
        (*info)->comm_remote_procs = NULL;
    } else {
        (*info)->comm_num_remote_procs = 0;
        (*info)->comm_remote_procs = NULL;
    }

    /* Fill in cartesian/graph info, if relevant.  The cartesian and
       graph data is just slightly different from each other; it's
       [slightly] easier (and less confusing!) to have separate
       retrieval code blocks. */
    topo = ompi_fetch_pointer(process, 
                              c_comm + i_info->ompi_communicator_t.offset.c_topo_comm,
                              p_info);
    if (0 != topo && 
        0 != ((*info)->comm_bitflags & MPIDBG_COMM_INFO_CARTESIAN)) {
        int i, ndims, tmp;
        mqs_taddr_t dims, periods;

        /* Alloc space for copying arrays */
        (*info)->comm_cart_num_dims = ndims =
            ompi_fetch_int(process, 
                           topo + i_info->ompi_mca_topo_base_comm_1_0_0_t.offset.mtc_ndims_or_nnodes,
                           p_info);
        (*info)->comm_cart_dims = mqs_malloc(ndims * sizeof(int));
        if (NULL == (*info)->comm_cart_dims) {
            return MPIDBG_ERR_NO_MEM;
        }
        (*info)->comm_cart_periods = mqs_malloc(ndims * sizeof(int8_t));
        if (NULL == (*info)->comm_cart_periods) {
            mqs_free((*info)->comm_cart_dims);
            (*info)->comm_cart_dims = NULL;
            return MPIDBG_ERR_NO_MEM;
        }

        /* Retrieve the dimension and periodic description data from
           the two arrays on the image's communicator */
        dims = ompi_fetch_pointer(process, 
                                 topo + i_info->ompi_mca_topo_base_comm_1_0_0_t.offset.mtc_dims_or_index,
                                 p_info);
        periods = ompi_fetch_pointer(process, 
                                 topo + i_info->ompi_mca_topo_base_comm_1_0_0_t.offset.mtc_periods_or_edges,
                                 p_info);

        for (i = 0; i < ndims; ++i) {
            (*info)->comm_cart_dims[i] =
                ompi_fetch_int(process, dims + (sizeof(int) * i), p_info);
            tmp = ompi_fetch_int(process, periods + (sizeof(int) * i), p_info);
            (*info)->comm_cart_periods[i] = (int8_t) tmp;
            printf("mpidbg: cart comm: dimension %d: (length %d, periodic: %d)\n", i, (*info)->comm_cart_dims[i], tmp);
        }
    } else if (0 != topo &&
               0 != ((*info)->comm_bitflags & MPIDBG_COMM_INFO_GRAPH)) {
        int i, nnodes;
        mqs_taddr_t index, edges;

        /* Alloc space for copying the indexes */
        (*info)->comm_graph_num_nodes = nnodes = 
            ompi_fetch_int(process, 
                           topo + i_info->ompi_mca_topo_base_comm_1_0_0_t.offset.mtc_ndims_or_nnodes,
                           p_info);
        (*info)->comm_graph_index = mqs_malloc(nnodes * sizeof(int));
        if (NULL == (*info)->comm_graph_index) {
            return MPIDBG_ERR_NO_MEM;
        }

        /* Retrieve the index data */
        index = ompi_fetch_pointer(process, 
                                 topo + i_info->ompi_mca_topo_base_comm_1_0_0_t.offset.mtc_dims_or_index,
                                 p_info);
        for (i = 0; i < nnodes; ++i) {
            (*info)->comm_graph_index[i] = 
                ompi_fetch_int(process, index + (sizeof(int) * i), p_info);
        }

        /* Allocate space for the edges */
        (*info)->comm_graph_edges = mqs_malloc((*info)->comm_graph_index[(*info)->comm_graph_num_nodes - 1] * sizeof(int));
        if (NULL == (*info)->comm_graph_edges) {
            mqs_free((*info)->comm_graph_index);
            (*info)->comm_graph_index = NULL;
            return MPIDBG_ERR_NO_MEM;
        }

        /* Retrieve the edge data */
        edges = ompi_fetch_pointer(process, 
                                 topo + i_info->ompi_mca_topo_base_comm_1_0_0_t.offset.mtc_periods_or_edges,
                                 p_info);
        for (i = 0; 
             i < (*info)->comm_graph_index[(*info)->comm_graph_num_nodes - 1]; 
             ++i) {
            (*info)->comm_graph_edges[i] = 
                ompi_fetch_int(process, edges + (sizeof(int) * i), p_info);
        }
    }

    /* Fortran handle */
    (*info)->comm_fortran_handle = 
        ompi_fetch_int(process, 
                       c_comm + i_info->ompi_communicator_t.offset.c_f_to_c_index,
                       p_info);
    printf("mpdbg: comm fortran handle: %d\n", (*info)->comm_fortran_handle);

    /* Fill in attributes */
    keyhash = ompi_fetch_pointer(process, 
                                 c_comm + i_info->ompi_communicator_t.offset.c_keyhash,
                                 p_info);
    fill_attributes(&((*info)->comm_num_attrs), &((*info)->comm_attrs),
                    keyhash);

    /* JMS temporary */
    (*info)->comm_num_pending_requests = MPIDBG_ERR_NOT_SUPPORTED;
    (*info)->comm_pending_requests = NULL;
    (*info)->comm_num_derived_windows = MPIDBG_ERR_NOT_SUPPORTED;
    (*info)->comm_derived_windows = NULL;
    (*info)->comm_num_derived_files = MPIDBG_ERR_NOT_SUPPORTED;
    (*info)->comm_derived_files = NULL;

    return MPIDBG_SUCCESS;
}

int mpidbg_comm_f2c(mqs_image *image, mqs_image_info *image_info, 
                    mqs_process *process, mqs_process_info *process_info,
                    mqs_taddr_t f77_comm, mqs_taddr_t *c_comm)
{
    mqs_taddr_t comm_list;
    mpi_image_info *i_info = (mpi_image_info *) image_info;
    mpi_process_info *p_info = (mpi_process_info*) process_info;

    mqs_find_symbol(image, "ompi_mpi_communicators", &comm_list);
    if (mqs_ok != ompi_fetch_opal_pointer_array_item(process, comm_list, 
                                                     p_info, f77_comm,
                                                     c_comm) ||
        NULL == c_comm) {
        printf("mpidbg_comm_f2c: %lu -> not found\n", 
               (long unsigned int) f77_comm);
        return MPIDBG_ERR_NOT_FOUND;
    }
    printf("mpidbg_comm_f2c: %lu -> %lu\n", 
           (long unsigned int) f77_comm, (long unsigned int) c_comm);
    return MPIDBG_SUCCESS;
}

int mpidbg_comm_cxx2c(mqs_image *image, mqs_image_info *image_info, 
                      mqs_process *process, mqs_process_info *process_info,
                      mqs_taddr_t cxx_comm, 
                      enum mpidbg_comm_info_bitmap_t comm_type,
                      mqs_taddr_t *c_comm)
{
    /* David tells me that any type of communicator (MPI::Comm,
       MPI::Intracomm, etc.) should have the offset to the mpi_comm
       member in the same place. */
    printf("mpidbg_comm_cxx2c: %p\n", (void*) cxx_comm);
    return MPIDBG_ERR_NOT_FOUND;
}

/*---------------------------------------------------------------------*/

int mpidbg_errhandler_query(mqs_image *image, mqs_image_info *image_info, 
                            mqs_process *process, mqs_process_info *process_info,
                            mqs_taddr_t c_errhandler, 
                            struct mpidbg_errhandler_info_t **info)
{
    printf("mpidbg_errhandler_query: %p\n", (void*) c_errhandler);
    printf("mpidbg_errhandler_query: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}

int mpidbg_errhandler_f2c(mqs_image *image, mqs_image_info *image_info, 
                          mqs_process *process, mqs_process_info *process_info,
                          mqs_taddr_t f77_errhandler, mqs_taddr_t *c_errhandler)
{
    printf("mpidbg_errhandler_f2c: %lu\n", (long unsigned int) f77_errhandler);
    printf("mpidbg_errhandler_f2c: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}

int mpidbg_errhandler_cxx2c(mqs_image *image, mqs_image_info *image_info, 
                            mqs_process *process, mqs_process_info *process_info,
                            mqs_taddr_t cxx_errhandler, 
                            mqs_taddr_t *c_errhandler)
{
    printf("mpidbg_errhandler_cxx2c: %p\n", (void*) cxx_errhandler);
    printf("mpidbg_errhandler_cxx2c: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}

/*---------------------------------------------------------------------*/

int mpidbg_request_query(mqs_image *image, mqs_image_info *image_info, 
                         mqs_process *process, mqs_process_info *process_info,
                         mqs_taddr_t c_request, 
                         struct mpidbg_request_info_t **info)
{
    printf("mpidbg_request_query: %p\n", (void*) c_request);
    printf("mpidbg_request_query: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}

int mpidbg_request_f2c(mqs_image *image, mqs_image_info *image_info, 
                       mqs_process *process, mqs_process_info *process_info,
                       mqs_taddr_t f77_request, mqs_taddr_t *c_request)
{
    printf("mpidbg_request_f2c: %lu\n", (long unsigned int) f77_request);
    printf("mpidbg_request_f2c: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}

int mpidbg_request_cxx2c(mqs_image *image, mqs_image_info *image_info, 
                         mqs_process *process, mqs_process_info *process_info,
                         mqs_taddr_t cxx_request, 
                         enum mpidbg_request_info_bitmap_t request_type,
                         mqs_taddr_t *c_request)
{
    printf("mpidbg_request_cxx2c: %p\n", (void*) cxx_request);
    printf("mpidbg_request_cxx2c: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}

/*---------------------------------------------------------------------*/

int mpidbg_status_query(mqs_image *image, mqs_image_info *image_info, 
                        mqs_process *process, mqs_process_info *process_info,
                        mqs_taddr_t c_status, 
                        struct mpidbg_status_info_t **info)
{
    printf("mpidbg_status_query: %p\n", (void*) c_status);
    printf("mpidbg_status_query: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}

int mpidbg_status_f2c(mqs_image *image, mqs_image_info *image_info, 
                      mqs_process *process, mqs_process_info *process_info,
                      mqs_taddr_t f77_status, mqs_taddr_t *c_status)
{
    printf("mpidbg_status_f2c: %lu\n", (long unsigned int) f77_status);
    printf("mpidbg_status_f2c: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}

int mpidbg_status_cxx2c(mqs_image *image, mqs_image_info *image_info, 
                        mqs_process *process, mqs_process_info *process_info,
                        mqs_taddr_t cxx_status, 
                        mqs_taddr_t *c_status)
{
    printf("mpidbg_status_cxx2c: %p\n", (void*) cxx_status);
    printf("mpidbg_status_cxx2c: not [yet] found\n");
    return MPIDBG_ERR_NOT_FOUND;
}