C++程序  |  382行  |  14 KB

/* Common definitions for remote server for GDB.
   Copyright (C) 1993, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005,
   2006, 2012
   Free Software Foundation, Inc.

   This file is part of GDB.
   It has been modified to integrate it in valgrind

   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., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.  */

#ifndef SERVER_H
#define SERVER_H

#include "pub_core_basics.h"
#include "pub_core_vki.h"
#include "pub_core_xarray.h"
#include "pub_core_clientstate.h"
#include "pub_core_debuglog.h"
#include "pub_core_errormgr.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcfile.h"
#include "pub_core_libcprint.h"
#include "pub_core_mallocfree.h"
#include "pub_core_syscall.h"
#include "pub_core_libcproc.h"
#include "pub_core_tooliface.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcbase.h"
#include "pub_core_options.h"
#include "pub_core_threadstate.h"
#include "pub_core_gdbserver.h"
#include "pub_core_vki.h"
#include "pub_core_clreq.h"

/*------------- interface m_gdbserver <=> low level gdbserver */

/* Initializes gdbserver. After a call to gdbserver_init, vgdb
   can contact the gdbserver embedded in valgrind.
   The rest of the low level gdbserver interface can only
   be called */
extern void gdbserver_init (void);

extern void server_main (void);

/* To be called to indicate that gdbserver usage is finished.
   Resources (e.g. FIFOs) will be destroyed. */
extern void gdbserver_terminate (void);


/* Output string s to the gdb debugging this process or to vgdb.
   Do not call this directly. Rather use VG_(gdb_printf) 
   to output something to gdb, use normal valgrind messaging
   (e.g. VG_(umsg)) to send output that can either go
   to gdb or to log. */
extern void monitor_output (char *s);

/* returns 0 if there is no connection or no event on the connection
             with gdb.
   returns 1 if there are some data which has been received from gdb
             and that must (still) be handled.
   returns 2 if remote_desc_activity detected the connection has been
             lost and should be reopened.
   msg is used for debug logging.*/
extern int remote_desc_activity(const char *msg);

/* output some status of gdbserver communication */
extern void remote_utils_output_status(void);

/* True if there is a connection with gdb. */
extern Bool remote_connected(void);

/* Finish the connection with gdb and reset_valgrind_sink.
   Keeps the FIFOs and shared mem so as to allow connection
   to be reopened. */
extern void remote_finish(FinishReason reason);

/* If Valgrind sink was changed by gdbserver:
      Resets the valgrind sink to before the changes done by gdbserver,
      and does VG_(umsg). If info != NULL, info added in VG_(usmg). */
extern void reset_valgrind_sink(const char* info);

// VG_(gdb_printf) by default writes to vgdb/gdb.
// If there is no connection, it will rather write to the initial (log)
// valgrind fd using the below.
extern void print_to_initial_valgrind_sink (const char *msg);

/* For ARM usage.
   Guesses if pc is a thumb pc.
   In this case, returns pc with the thumb bit set (bit0)
   else just returns pc.

   The guess is based on the following set of check:
   if bit0 set      => thumb
   else if bit1 set => thumb
   else uses the debuginfo to guess.
   
   If debug info not found for this pc, assumes arm */
extern Addr thumb_pc (Addr pc);

/* when invoked by vgdb using ptrace, contains the tid chosen
   by vgdb (if vgdb gives a tid different of 0: a 0 tid by
   vgdb means use the running_tid if there is one running
   or tid 1 otherwise). */
extern ThreadId vgdb_interrupted_tid;

/* True if GDB is catching client syscalls. */
extern Bool catching_syscalls;

/* Size of the syscalls_to_catch. Only useful if catching_syscalls True.
   syscalls_to_catch_size 0 means all syscalls are caught. */
extern Int syscalls_to_catch_size;
extern Int *syscalls_to_catch;

/*------------ end of interface to low level gdbserver */


#define dlog(level, ...) \
   do { if (UNLIKELY(VG_(debugLog_getLevel)() >= level))  \
         VG_(debugLog) (level, "gdbsrv",__VA_ARGS__); }   \
   while (0)


/* vki only defines VKI_POLLIN but even not on all OS.
   Below is from linux bits/poll.h */
#ifndef VKI_POLLIN
#define VKI_POLLIN            0x0001
#endif
#define VKI_POLLPRI           0x0002
#define VKI_POLLOUT           0x0004
#define VKI_POLLERR           0x0008
#define VKI_POLLHUP           0x0010
#define VKI_POLLNVAL          0x0020

/* a bunch of macros to avoid libc usage in valgrind-ified gdbserver */ 
#define strcmp(s1,s2)         VG_(strcmp) ((s1),(s2))
#define strncmp(s1,s2,nmax)   VG_(strncmp) ((s1),(s2),nmax)
#define strcat(s1,s2)         VG_(strcat) ((s1),(s2))
#define strcpy(s1,s2)         VG_(strcpy) ((s1),(s2))
#define strncpy(s1,s2,nmax)   VG_(strncpy) ((s1),(s2),nmax)
#define strlen(s)             VG_(strlen) ((s))
#define strtok(p,s)           VG_(strtok) ((p),(s))
#define strtok_r(p,s,ss)      VG_(strtok_r) ((p),(s),(ss))
#define strchr(s,c)           VG_(strchr) ((s),c)
/* strtol and strtoul supports base 16 or else assumes it is base 10 */
#define strtol(s,r,b)         ((b) == 16 ? \
                               VG_(strtoll16) ((s),(r)) \
                               : VG_(strtoll10) ((s),(r)))
#define strtoul(s,r,b)        ((b) == 16 ? \
                               VG_(strtoull16) ((s),(r)) \
                               : VG_(strtoull10) ((s),(r)))

#define malloc(sz)            VG_(malloc)  ("gdbsrv", sz)
#define calloc(n,sz)          VG_(calloc)  ("gdbsrv", n, sz)
#define realloc(p,size)       VG_(realloc) ("gdbsrv", p, size)
#define strdup(s)             VG_(strdup)  ("gdbsrv", (s))
#define free(b)               VG_(free)    (b)

#ifndef ATTR_NORETURN
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
#define ATTR_NORETURN __attribute__ ((noreturn))
#else
#define ATTR_NORETURN           /* nothing */
#endif
#endif

#ifndef ATTR_FORMAT
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4))
#define ATTR_FORMAT(type, x, y) __attribute__ ((format(type, x, y)))
#else
#define ATTR_FORMAT(type, x, y) /* nothing */
#endif
#endif

/* A type used for binary buffers.  */
typedef unsigned char gdb_byte;

typedef Addr CORE_ADDR;

/* Generic information for tracking a list of ``inferiors'' - threads,
   processes, etc.  */
struct inferior_list
{
   struct inferior_list_entry *head;
   struct inferior_list_entry *tail;
};
struct inferior_list_entry
{
   unsigned long id;
   struct inferior_list_entry *next;
};

/* Opaque type for user-visible threads.  */
struct thread_info;

#include "regcache.h"
#include "gdb/signals.h"

/* signal handling with gdbserver: before delivering a signal,
   call gdbserver_signal_encountered. This will set
   the signal to report in the next resume reply sent to GDB.
   A call to call_gdbserver is needed to send the resume reply to GDB.
   After this call, gdbserver_deliver_signal indicates if the signal
   is effectively to be delivered to the guest process. */
extern void gdbserver_signal_encountered (const vki_siginfo_t *info);
/* between these two calls, call call_gdbserver.
   Between these 2 calls the signal to report to GDB can be retrieved using
   gdbserver_pending_signal_to_report. */
/* If gdbserver_deliver_signal True, then gdb did not ask
   to ignore the signal, so signal can be delivered to the guest. */
extern Bool gdbserver_deliver_signal (vki_siginfo_t *info);

/* Signal info last provided with gdbserver_signal_encountered.
   It is what is/will be reported to GDB. */
extern void gdbserver_pending_signal_to_report (vki_siginfo_t /* OUT */ *info);

/* Called when a process is about to go with reason ('W' or 'X') and code.
   This sets global variables that will be used to return the process
   exit status to GDB in the next resume_reply.
   Similarly to gdbserver_signal_encountered, a call to call_gdbserver
   is needed to send the resume reply. */
extern void gdbserver_process_exit_encountered (unsigned char status, Int code);

/* To optimise signal handling, gdb can instruct gdbserver to
   not stop on some signals. In the below, a 1 indicates the gdb_nr signal
   has to be passed directly to the guest, without asking gdb.
   A 0 indicates gdb has to be consulted to see if signal has
   or has not to be passed. The gdb consultation is to
   be done using the above two functions. */
extern int pass_signals[]; /* indexed by gdb signal nr */


#include "target.h"

/* Target-specific functions */

/* From inferiors.c.  */

extern struct inferior_list all_threads;
void add_inferior_to_list (struct inferior_list *list,
			   struct inferior_list_entry *new_inferior);
void for_each_inferior (struct inferior_list *list,
			void (*action) (struct inferior_list_entry *));
extern struct thread_info *current_inferior;
void remove_inferior (struct inferior_list *list,
		      struct inferior_list_entry *entry);
void remove_thread (struct thread_info *thread);
void add_thread (unsigned long thread_id, void *target_data, unsigned int);
unsigned int thread_id_to_gdb_id (unsigned long);
unsigned int thread_to_gdb_id (struct thread_info *);
unsigned long gdb_id_to_thread_id (unsigned int);
struct thread_info *gdb_id_to_thread (unsigned int);
void clear_inferiors (void);
struct inferior_list_entry *find_inferior (struct inferior_list *,
                                           int (*func) (struct 
                                                        inferior_list_entry *,
                                                        void *),
                                           void *arg);
struct inferior_list_entry *find_inferior_id (struct inferior_list *list,
					      unsigned long id);
void *inferior_target_data (struct thread_info *);
void set_inferior_target_data (struct thread_info *, void *);
void *inferior_regcache_data (struct thread_info *);
void set_inferior_regcache_data (struct thread_info *, void *);
void change_inferior_id (struct inferior_list *list,
			 unsigned long new_id);

/* Public variables in server.c */

extern unsigned long cont_thread;
extern unsigned long general_thread;
extern unsigned long step_thread;
extern unsigned long thread_from_wait;
extern unsigned long old_thread_from_wait;

extern VG_MINIMAL_JMP_BUF(toplevel);

/* From remote-utils.c */

extern Bool noack_mode;
int putpkt (char *buf);
int putpkt_binary (char *buf, int len);
int getpkt (char *buf);
void remote_open (const HChar *name);
void remote_close (void);

void sync_gdb_connection (void);
void write_ok (char *buf);
void write_enn (char *buf);
void convert_ascii_to_int (const char *from, unsigned char *to, int n);
void convert_int_to_ascii (const unsigned char *from, char *to, int n);
void prepare_resume_reply (char *buf, char status, unsigned char sig);

void decode_address (CORE_ADDR *addrp, const char *start, int len);
void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr,
		      unsigned int *len_ptr);
void decode_M_packet (char *from, CORE_ADDR * mem_addr_ptr,
		      unsigned int *len_ptr, unsigned char *to);
int decode_X_packet (char *from, int packet_len, CORE_ADDR * mem_addr_ptr,
		     unsigned int *len_ptr, unsigned char *to);

int unhexify (char *bin, const char *hex, int count);
int hexify (char *hex, const char *bin, int count);
/* heximage builds an image of bin according to byte order of the architecture 
   Useful for register and int image */
char* heximage (char *buf, char *bin, int count);

/* convert from CORE_ADDR to void* */
void* C2v(CORE_ADDR addr);


int remote_escape_output (const gdb_byte *buffer, int len,
			  gdb_byte *out_buf, int *out_len,
			  int out_maxlen);

/* Functions from ``signals.c''.  */
enum target_signal target_signal_from_host (int hostsig);
int target_signal_to_host_p (enum target_signal oursig);
int target_signal_to_host (enum target_signal oursig);
const char *target_signal_to_name (enum target_signal);

/* Functions from utils.c */

/* error is like VG_(umsg), then VG_MINIMAL_LONGJMP to gdbserver toplevel. */
void error (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
/* first output a description of the error inside sr, then like VG_(umsg). */
void sr_perror (SysRes sr,const char *string,...) ATTR_FORMAT (printf, 2, 3);
/* fatal is like VG_(umsg), then exit(1). */
void fatal (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
/* warning is like VG_(umsg). */
void warning (const char *string,...) ATTR_FORMAT (printf, 1, 2);

/* Functions from the register cache definition.  */

void init_registers (void);

/* Maximum number of bytes to read/write at once.  The value here
   is chosen to fill up a packet (the headers account for the 32).  */
#define MAXBUFBYTES(N) (((N)-32)/2)

/* PBUFSIZ : Buffers size for transferring memory, registers, etc.
   Must be big enough to hold all the registers, at least.
   Must be at least big as 2*DATASIZ + 5:
      1         : packet begin ($ or %)
    + 2*DATASIZ : encoded string
    + 1         : packet end (#)
    + 2         : packet checksum
    + 1         : \0 

    Max value gdb likes is 16384.

    Note that what is sent/received to/from gdb does
    not have a trailing null byte. We are adding 1 here to allow
    null terminating the strings e.g. for printf.

    => packet Packet OVERHead SIZe is 5:*/

/* keep PBUFSIZ value in sync with vgdb.c */
#define PBUFSIZ 16384
#define POVERHSIZ 5

/* Max size of a string encoded in a packet. Hex Encoding can
   multiply the size by 2 (trailing null byte not sent). */
#define DATASIZ ((PBUFSIZ-POVERHSIZ)/2)

/* Version information, from version.c.  */
extern const char version[];

#endif /* SERVER_H */