📄 server.c
字号:
/* Main code for remote server for GDB. Copyright 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the 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 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "server.h"#include "linux-low.h"#include <unistd.h>#include <signal.h>#include <sys/wait.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int cont_thread;int general_thread;int step_thread;int thread_from_wait;int old_thread_from_wait;int extended_protocol;int server_waiting;int isfile = 0;jmp_buf toplevel;/* The PID of the originally created or attached inferior. Used to send signals to the process when GDB sends us an asynchronous interrupt (user hitting Control-C in the client), and to wait for the child to exit when no longer debugging it. */int signal_pid;static unsigned charstart_inferior (char *argv[], char *statusptr){ signal (SIGTTOU, SIG_DFL); signal (SIGTTIN, SIG_DFL); signal_pid = create_inferior (argv[0], argv); fprintf (stderr, "Process %s created; pid = %d\n", argv[0], signal_pid); signal (SIGTTOU, SIG_IGN); signal (SIGTTIN, SIG_IGN); tcsetpgrp (fileno (stderr), signal_pid); /* Wait till we are at 1st instruction in program, return signal number. */ return mywait (statusptr, 0);}static intattach_inferior (int pid, char *statusptr, unsigned char *sigptr){ /* myattach should return -1 if attaching is unsupported, 0 if it succeeded, and call error() otherwise. */ if (myattach (pid) != 0) return -1; fprintf (stderr, "Attached; pid = %d\n", pid); /* FIXME - It may be that we should get the SIGNAL_PID from the attach function, so that it can be the main thread instead of whichever we were told to attach to. */ signal_pid = pid; *sigptr = mywait (statusptr, 0); return 0;}extern int remote_debug;/* Handle all of the extended 'q' packets. */voidhandle_query (char *own_buf){ static struct inferior_list_entry *thread_ptr; if (strcmp ("qSymbol::", own_buf) == 0) { if (the_target->look_up_symbols != NULL) (*the_target->look_up_symbols) (); strcpy (own_buf, "OK"); return; } if (strcmp ("qC", own_buf) == 0) { struct process_info *process; if (current_inferior == NULL) return; process = get_thread_process(current_inferior); sprintf(own_buf, "QC%x", process->thread_known ? process->tid : 0); } if (strcmp ("qfThreadInfo", own_buf) == 0) { thread_ptr = all_threads.head; sprintf (own_buf, "m%x", thread_ptr->id); thread_ptr = thread_ptr->next; return; } if (strcmp ("qsThreadInfo", own_buf) == 0) { if (thread_ptr != NULL) { sprintf (own_buf, "m%x", thread_ptr->id); thread_ptr = thread_ptr->next; return; } else { sprintf (own_buf, "l"); return; } } if (the_target->read_auxv != NULL && strncmp ("qPart:auxv:read::", own_buf, 17) == 0) { char data[(PBUFSIZ - 1) / 2]; CORE_ADDR ofs; unsigned int len; int n; decode_m_packet (&own_buf[17], &ofs, &len); /* "OFS,LEN" */ if (len > sizeof data) len = sizeof data; n = (*the_target->read_auxv) (ofs, data, len); if (n == 0) write_ok (own_buf); else if (n < 0) write_enn (own_buf); else convert_int_to_ascii (data, own_buf, n); return; } /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ own_buf[0] = 0;}/* Parse vCont packets. */voidhandle_v_cont (char *own_buf, char *status, unsigned char *signal){ char *p, *q; int n = 0, i = 0; struct thread_resume *resume_info, default_action; /* Count the number of semicolons in the packet. There should be one for every action. */ p = &own_buf[5]; while (p) { n++; p++; p = strchr (p, ';'); } /* Allocate room for one extra action, for the default remain-stopped behavior; if no default action is in the list, we'll need the extra slot. */ resume_info = malloc ((n + 1) * sizeof (resume_info[0])); default_action.thread = -1; default_action.leave_stopped = 1; default_action.step = 0; default_action.sig = 0; p = &own_buf[5]; i = 0; while (*p) { p++; resume_info[i].leave_stopped = 0; if (p[0] == 's' || p[0] == 'S') resume_info[i].step = 1; else if (p[0] == 'c' || p[0] == 'C') resume_info[i].step = 0; else goto err; if (p[0] == 'S' || p[0] == 'C') { int sig; sig = strtol (p + 1, &q, 16); if (p == q) goto err; p = q; if (!target_signal_to_host_p (sig)) goto err; resume_info[i].sig = target_signal_to_host (sig); } else { resume_info[i].sig = 0; p = p + 1; } if (p[0] == 0) { resume_info[i].thread = -1; default_action = resume_info[i]; /* Note: we don't increment i here, we'll overwrite this entry the next time through. */ } else if (p[0] == ':') { resume_info[i].thread = strtol (p + 1, &q, 16); if (p == q) goto err; p = q; if (p[0] != ';' && p[0] != 0) goto err; i++; } } resume_info[i] = default_action; /* Still used in occasional places in the backend. */ if (n == 1 && resume_info[0].thread != -1) cont_thread = resume_info[0].thread; else cont_thread = -1; set_desired_inferior (0); (*the_target->resume) (resume_info); free (resume_info); *signal = mywait (status, 1); prepare_resume_reply (own_buf, *status, *signal); return;err: /* No other way to report an error... */ strcpy (own_buf, ""); free (resume_info); return;}/* Handle all of the extended 'v' packets. */voidhandle_v_requests (char *own_buf, char *status, unsigned char *signal){ if (strncmp (own_buf, "vCont;", 6) == 0) { handle_v_cont (own_buf, status, signal); return; } if (strncmp (own_buf, "vCont?", 6) == 0) { strcpy (own_buf, "vCont;c;C;s;S"); return; } /* Otherwise we didn't know what packet it was. Say we didn't understand it. */ own_buf[0] = 0; return;}voidhandle_breakpoint_requests (char *own_buf, char *status, unsigned char *signal){ /* Currently we only support software breakpoints */ switch (own_buf[1]) { case '0': /* software breakpoint, int3 based */ own_buf[0] = '\0'; break; case '1': /* hardware breakpoint */ default: write_enn (own_buf); break; }}voidmyresume (int step, int sig){ struct thread_resume resume_info[2]; int n = 0; if (step || sig || cont_thread > 0) { resume_info[0].thread = ((struct inferior_list_entry *) current_inferior)->id; resume_info[0].step = step; resume_info[0].sig = sig; resume_info[0].leave_stopped = 0; n++; } resume_info[n].thread = -1; resume_info[n].step = 0; resume_info[n].sig = 0; resume_info[n].leave_stopped = (cont_thread > 0); (*the_target->resume) (resume_info);}static int attached;static voidgdbserver_usage (void){ error ("Usage:\tgdbserver COMM PROG [ARGS ...]\n" "\tgdbserver COMM --attach PID\n" "\tgdbserver COMM --file COREFILE\n" "\n" "COMM may either be a tty device (for serial debugging), or \n" "HOST:PORT to listen for a TCP connection.\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -