📄 server-main.c
字号:
/* Main code for multi-ice server for GDB. Copyright (C) 1999 Free Software Foundation, Inc.This file is part of GDB.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <getopt.h>#include <stdio.h>#include <signal.h>#include <string.h>#include <stdlib.h>#include "defs.h"#include "tm.h"#include "config.h"#include "server.h"#include "low.h"#include "remote-utils.h"/* * These variables are used to track command-line options. */int show_config_dialog = 0;int debug_on = 0;int show_help = 0;int show_version = 0;int rdi_logging = 0;/* * This is the sticky flag for using extended remote protocol. */int use_extended_ops = 1;/* * Keep track of the command line arguments here. */int exit_status = 0;int exit_now = 0;/* * This one is set by the Cntrl-C handler, and is used to * tell the server to close the connection to the remote * GDB. */int close_connection_now = 0;/* * Thread information. */int selected_thread = 0;int current_thread = 0;int using_threads = 0;/* * This is the option descriptors, as used by getopt. * Remember, if you add an option, be sure to add a * help string to the help_strings array below as well. */struct option long_options[] ={ {"byte-sex", required_argument, 0, 'b'}, {"config-dialog", no_argument, &show_config_dialog, 1}, {"debug", no_argument, &debug_on, 1}, {"help", no_argument, &show_help, 1}, {"rdi-logging", no_argument, &rdi_logging, 1}, {"remote-port", required_argument, 0, 'r'}, {"stop-others", no_argument, &target_stop_others, 0}, {"target-driver", required_argument, 0, 'd'}, {"target-port", required_argument, 0, 't'}, {"version", no_argument, &show_version, 'v'}};/* * This is what is printed by print_help (and what you see if you * do --help. Be sure to keep it in sync with the options. */char *help_strings[] ={ " --byte-sex {b,l} - Specify the byte-sex of the target on restart.\n", " --config-dialog - Post configuration dialog for Multi-ICE DLL.\n", " --debug - Turn on debugging of remote protocol requests.\n", " --help - Print out this help message.\n", " --rdi-logging - Turn on RDI logging.\n", " --remote-port port - Specify the port to listen for remote connections.\n", " --stop-others - Execution of target stops other modules.\n", " --target-driver driver - Specify which ICE driver to use.\n", " --target-port port - Specify the port to which the target is attached.\n", " --version - Print version information and then exit.\n", (char *) NULL};void exit_handler();int run_test(char *input_buffer); /* ------------------------------------------------------------ * main * * This is the main for the multi-ice variant of gdbserver. It opens * a listening port, and a connection to the debug target, and then * waits for a connection on the listener. When the connection is * made, it processes requests from the client till the connection is * closed, then goes back to listening. * ------------------------------------------------------------ */intmain (int argc, char *argv[]){#define INITIAL_LENGTH 2000 char initial_buf[INITIAL_LENGTH], *input_buffer = initial_buf; int input_buffer_len = INITIAL_LENGTH, message_len; char *remote_port = "2331", *target_port = NULL, *byte_sex = NULL; char c; /* * First parse the command line options: */ while (1) { int option_index; c = getopt_long_only (argc, argv, "", long_options, &option_index); if (c == EOF) { break; } if (c == 0 && long_options[option_index].flag == 0) c = long_options[option_index].val; switch (c) { case 0: break; case 'b': byte_sex = optarg; if ((*byte_sex != 'b') && (*byte_sex != 'l') && (*byte_sex != 'B') && (*byte_sex != 'L')) { output_error ("Bad value for --byte-sex: \"%s\", ", byte_sex); output_error ("should be \"b\" or \"l\"\n"); exit(1); } break; case 'r': remote_port = optarg; break; case 'd': target_driver_name = optarg; break; case 't': target_port = optarg; break; case 'v': show_version = 1; break; case '?': output ("Available options are:\n"); print_help (); exit (1); } } if (show_version) { print_version(0); exit (0); } print_version(1); if (show_help) { print_help (); exit (0); } /* * Now do any platform specific initializations */ platform_init(); /* * First establish a connection to the target. */ if (!low_open_target (target_port, byte_sex, show_config_dialog)) { if (target_port == NULL) output("Error opening target.\nExiting...\n"); else output("Error opening target at %s\nExiting...\n", remote_port); exit(1); } /* * Now open the listening port. Bag out if we can't open it. */ if (!open_listener (remote_port)) { output ("Error opening listener port %s\nExiting...\n", remote_port); low_close_target (); exit (1); } output ("GDB Server starting on port %s\n", remote_port); signal (SIGINT, exit_handler); signal (SIGTERM, exit_handler); signal (SIGQUIT, exit_handler); while (!exit_now) { if (wait_for_connection()) { /* * Reset environment */ selected_thread = 0; current_thread = 0; using_threads = 0;#if 0 low_reset_thread_op();#endif while (!exit_now && !close_connection_now) { if (!handle_system_events ()) { exit_now = 1; break; } else if (close_connection_now) { exit_now = 0; close_connection_now = 0; break; } message_len = getpkt (input_buffer, &input_buffer_len); if (message_len >= 0) { if (!dispatch (input_buffer, message_len)) { /* Handle errors here */ } } else { break; } } /* If we got here, then the remote user died or detached, * so close the connection, and wait for another... */ close_connection (); close_connection_now = 0; } else { output_error ("Attempt to connect failed\n"); } } close_listener (); low_close_target (); output ("Exiting...\n"); return exit_status;}/* ------------------------------------------------------------ * update_current_thread * * This function tries to ensure that we know what the current thread * 'id' is. This is important when performing thread-based queries * because the target can't reliably respond with register information * for the "current" thread (it's not available on the board). * ------------------------------------------------------------ */static voidupdate_current_thread(void){ char *result, *ptr; int res; if ((using_threads == 0) || (current_thread != 0)) return; // Using thread operations res = low_thread_op("qC#", &result); if (res) { current_thread = strtol(result+2, &ptr, 0x10); } else { output("Can't deduce current thread\n"); }}/* ------------------------------------------------------------ * dispatch * * This takes a message, decodes the protocol request, and dispatches * the message to the appropriate functions that in the target. It also * handles whatever response the message requires before returning. * ------------------------------------------------------------ */intdispatch (char *input_buffer, int message_length){ char key; char *res; int signo, result; enum bp_action_type bp_action = BREAKPOINT_SET; if (debug_on) { output ("Recieved packet: %s\n", input_buffer); } key = input_buffer[0]; input_buffer++; switch (key) { case 'H': /* Set thread */ return handle_thread (input_buffer, THREAD_SET); case 'g': /* read registers */ update_current_thread(); if ((selected_thread == 0) || (current_thread == selected_thread)) { return handle_read_registers(input_buffer); } else { result = low_thread_op(input_buffer-1, NULL); if (result) return result; return handle_read_registers (input_buffer); } case 'G': /* write registers */ if ((selected_thread == 0) || (current_thread == selected_thread)) { return handle_write_registers (input_buffer); } else { result = low_thread_op(input_buffer-1, NULL); if (result) return result; return handle_write_registers (input_buffer); } case 'P': /* write a particular register */ if ((selected_thread == 0) || (current_thread == selected_thread)) { return handle_write_a_register (input_buffer); } else { result = low_thread_op(input_buffer-1, NULL); if (result) return result; return handle_write_registers (input_buffer); } case 'm': /* read memory */ return handle_read_memory (input_buffer); case 'M': /* write memory */ return handle_write_memory (input_buffer); case 'X': /* write memory, binary data */ putpkt (""); return 1; /* For now, we don't support binary downloads... */ /* return handle_write_memory (input_buffer); */ case 'z': /* This is the breakpoint delete packet */ bp_action = BREAKPOINT_DELETE; case 'Z': /* This is the breakpoint set packet */ key = input_buffer[0]; input_buffer++; if (*input_buffer != ',') { output_error ("Malformed breakpoint set, no \",\".\n"); putpkt ("ENN"); return 0; } input_buffer++; switch (key) { case '0': /* JT's breakpoint patches don't explicitly request a HW breakpoint. We will do our best on this side... putpkt ("ENN"); output_error ("Can't do software breakpoints on this side.\n"); */ case '1': return handle_breakpoint (bp_action, input_buffer); case '2': return handle_watchpoint (bp_action, WATCHPOINT_WRITE, input_buffer); case '3': return handle_watchpoint (bp_action, WATCHPOINT_READ, input_buffer); case '4': return handle_watchpoint (bp_action, WATCHPOINT_ACCESS, input_buffer); default: output_error ("Bad \"Z\" packet index: %c.\n", key); putpkt ("ENN"); return 0; } case 'c': /* continue */ return handle_resume (input_buffer, RESUME_CONTINUE, 0); case 'C': /* continue with signal */ input_buffer = remove_signal (input_buffer, &signo); if (input_buffer == NULL) { return 0; } return handle_resume (input_buffer, RESUME_CONTINUE, signo); case 's': /* step */ return handle_resume (input_buffer, RESUME_STEP, 0); case 'S': /* step with signal */ input_buffer = remove_signal (input_buffer, &signo); return handle_resume (input_buffer, RESUME_STEP, signo); case '?': /* query last signal */ return handle_last_signal (input_buffer); case 'D': /* detach */ return handle_detach (input_buffer); case 'T': /* query is thread alive */ return handle_thread (input_buffer, THREAD_ALIVE); case 'R': /* restart the remote server */ return handle_restart (input_buffer); case '!': /* use extended ops */ enable_extended_ops(); return 1; case 'k': /* kill target */ return handle_kill_target (input_buffer); case 'd': /* toggle debug */ return handle_toggle_debug (input_buffer); case 'r': /* reset */ return handle_reset (input_buffer); case 't': /* search memory */ return handle_search_memory (input_buffer); case 'q': /* general query */ return handle_general_query (input_buffer); case 'Q': /* general set */ return handle_general_set (input_buffer); default: /* Send a packet not recognized reply */ putpkt(""); return 1; }}/* * print_help * * This prints out all the help strings. */voidprint_help(){ int i; output ("Options:\n"); for (i = 0; help_strings[i] != NULL; i++) { output (help_strings[i]); }}/* * print_version * * This prints out the program version and copyright/licensing information */voidprint_version(int banner_only){ /* From GNU coding standards, first line is meant to be easy for a program to parse, and is just canonical program name and version number, which starts after last space. */ output ("GNU Multi-ICE GDB server " VERSION "\n\n"); if (!banner_only) output ("\Copyright 1999 Free Software Foundation, Inc.\n\This program is free software; you are welcome to change it and/or\n\redistribute it under the terms of the GNU General Public License.\n\This program is supported for customers of Cygnus Solutions.\n");}/* * handle_thread * * This handles all the thread queries using the H packed syntax. */inthandle_thread (char *input_buffer, enum thread_mode mode){ char key, *ptr; long thread_id; switch (mode) { case THREAD_SET: key = input_buffer[0]; input_buffer++; thread_id = strtol (input_buffer, &ptr, 0x10); // Protocol uses hex values if (ptr == input_buffer) { putpkt ("ENN"); output_error ("Got invalid thread id: %s\n", input_buffer); return 0; } switch (key) { case 'c': if (low_set_thread_for_resume (thread_id)) { putpkt("OK"); return 1; } else { putpkt("ENN"); return 0; } case 'g': selected_thread = thread_id; if (selected_thread) { return low_set_thread_for_query (input_buffer-2); } else { putpkt("OK"); return 1; } default: putpkt("ENN"); } break; case THREAD_ALIVE: thread_id = strtol (input_buffer, &ptr, 0x10); if (ptr == input_buffer) { putpkt ("ENN"); output_error ("Got invalid thread id: %s\n", input_buffer); return 0; } if (thread_id) { return low_is_thread_alive (input_buffer-1); } else { putpkt("OK"); } return 1; default: putpkt(""); return 1; } return 1;}/* * handle_read_registers * * This returns the entire register set in the form required by * the 'g' packet. ** Only in non-thread mode */inthandle_read_registers (char *input_buffer){ char *buffer = alloca((REGISTER_BYTES * 2) + 1); if (!low_update_registers ()) { putpkt("ENN"); return 0; } convert_bytes_to_ascii (aregisters, buffer, REGISTER_BYTES, 0); putpkt(buffer); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -