| /****************************************************************************** | |
| * Copyright (c) 2005 The Regents of the University of California. | |
| * This material was produced under U.S. Government contract W-7405-ENG-36 | |
| * for Los Alamos National Laboratory, which is operated by the University | |
| * of California for the U.S. Department of Energy. The U.S. Government has | |
| * rights to use, reproduce, and distribute this software. NEITHER THE | |
| * GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR | |
| * ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified | |
| * to produce derivative works, such modified software should be clearly | |
| * marked, so as not to confuse it with the version available from LANL. | |
| * | |
| * Additionally, this program and the accompanying materials | |
| * are made available under the terms of the Eclipse Public License v1.0 | |
| * which accompanies this distribution, and is available at | |
| * http://www.eclipse.org/legal/epl-v10.html | |
| * | |
| * LA-CC 04-115 | |
| ******************************************************************************/ | |
| /* | |
| * server() has two roles. The first is to launch the process being debugged | |
| * (debuggee) under the control of a debugger (us). The second is to manage | |
| * communication with the client process. | |
| * | |
| * Note that there will be num_procs+1 [0..num_procs] processes in our | |
| * communicator, where num_procs is the number of processes in the parallel | |
| * job being debugged. To simplify the accounting, we use the task id of | |
| * num_procs as the client task id and [0..num_procs-1] for the server | |
| * task ids. | |
| */ | |
| #ifdef __gnu_linux__ | |
| #define _GNU_SOURCE | |
| #endif /* __gnu_linux__ */ | |
| #include "config.h" | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "hash.h" | |
| #include "backend.h" | |
| #include "proxy.h" | |
| #include "proxy_tcp.h" | |
| #include "sdm.h" | |
| extern int svr_init(dbg_backend *, void (*)(dbg_event *, int)); | |
| extern int svr_dispatch(dbg_backend *, unsigned char *, int, int); | |
| extern int svr_progress(dbg_backend *); | |
| extern int svr_isshutdown(void); | |
| extern int svr_shutdown(dbg_backend *); | |
| static dbg_backend * backend; | |
| char * | |
| stringify(unsigned char *buf, int len) | |
| { | |
| static char * str_buf = NULL; | |
| if (str_buf != NULL) { | |
| free(str_buf); | |
| } | |
| str_buf = (char *)malloc(len + 1); | |
| memcpy(str_buf, buf, len); | |
| str_buf[len] = '\0'; | |
| return str_buf; | |
| } | |
| /* | |
| * Aggregate debugger response. | |
| */ | |
| static void | |
| event_callback(dbg_event *e, int data) | |
| { | |
| int len; | |
| unsigned char * buf; | |
| sdm_message msg; | |
| if (DbgSerializeEvent(e, &buf, &len) < 0) { | |
| return; | |
| } | |
| DEBUG_PRINTF(DEBUG_LEVEL_SERVER, "[%d] server event_callback '%s'\n", sdm_route_get_id(), stringify(buf, len)); | |
| msg = sdm_message_new(buf, len); | |
| sdm_message_set_id(msg, data); | |
| sdm_set_add_element(sdm_message_get_destination(msg), SDM_MASTER); | |
| sdm_aggregate_message(msg, SDM_AGGREGATE_UPSTREAM | SDM_AGGREGATE_INIT); | |
| } | |
| /* | |
| * Dispatch payload to debugger. | |
| */ | |
| static void | |
| deliver_callback(const sdm_message msg) | |
| { | |
| int id; | |
| int len; | |
| unsigned char * buf; | |
| DEBUG_PRINTF(DEBUG_LEVEL_SERVER, "[%d] Enter deliver_callback\n", sdm_route_get_id()); | |
| sdm_message_get_payload(msg, &buf, &len); | |
| id = sdm_message_get_id(msg); | |
| (void)svr_dispatch(backend, buf, len, id); | |
| DEBUG_PRINTF(DEBUG_LEVEL_SERVER, "[%d] Leaving deliver_callback\n", sdm_route_get_id()); | |
| } | |
| /* | |
| * Just forward aggregated message to parent. | |
| */ | |
| static int | |
| aggregate_callback(sdm_message msg, void *data) | |
| { | |
| DEBUG_PRINTF(DEBUG_LEVEL_SERVER, "[%d] Enter aggregate_callback\n", sdm_route_get_id()); | |
| sdm_message_set_send_callback(msg, sdm_message_free); | |
| sdm_message_send(msg); | |
| DEBUG_PRINTF(DEBUG_LEVEL_SERVER, "[%d] Leaving aggregate_callback\n", sdm_route_get_id()); | |
| return 0; | |
| } | |
| /* | |
| * Debug server implementation | |
| * | |
| * NOTE: currently the debug server does not support multiple simulutaneous command execution. That is, it | |
| * will only process one command at at time, and will not accept another command until a reply | |
| * has been sent. The client may send multiple commands, but it is the underlying transport | |
| * that is providing the command buffering. | |
| * | |
| * This approach should be sufficient for all debugging tasks if we assume that the debugger operates | |
| * in one of two states: ACCEPTING_COMMANDS and PROCESSING_COMMAND and will only accept additional commands | |
| * when it is in the ACCEPTING_COMMANDS state. E.g. | |
| * | |
| * Command Debugger State GDB State | |
| * | |
| * --SLB--> ACCEPTING_COMMANDS SUSPENDED | |
| * PROCESSING_COMMAND SUSPENDED | |
| * <--OK--- ACCEPTING_COMMANDS SUSPENDED | |
| * | |
| * --GOP--> ACCEPTING_COMMANDS SUSPENDED | |
| * PROCESSING_COMMAND RUNNING | |
| * PROCESSING_COMMAND SUSPENDED | |
| * <--OK--- ACCEPTING_COMMANDS SUSPENDED | |
| * | |
| * The exception to this is the INT command which can be sent at any time. This works by sending | |
| * with a special MPI tag used of OOB communication. It will be implemented later... | |
| * | |
| */ | |
| void | |
| server(dbg_backend *dbgr) | |
| { | |
| DEBUG_PRINTF(DEBUG_LEVEL_SERVER, "starting server on %d, size=%d\n", sdm_route_get_id(), sdm_route_get_size()); | |
| backend = dbgr; | |
| sdm_message_set_deliver_callback(deliver_callback); | |
| sdm_aggregate_set_completion_callback(aggregate_callback, NULL); | |
| svr_init(dbgr, event_callback); | |
| while (!svr_isshutdown()) { | |
| if (sdm_progress() < 0) { | |
| svr_shutdown(dbgr); | |
| } | |
| svr_progress(dbgr); | |
| } | |
| } | |