📄 linux-xen-low.c
字号:
/* Low level interface to ptrace, for the remote server for GDB. Copyright 1995, 1996, 1998, 1999, 2000, 2001, 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 <sys/wait.h>#include <stdio.h>#include <sys/param.h>#include <sys/dir.h>#include <sys/ptrace.h>#include <sys/user.h>#include <signal.h>#include <sys/ioctl.h>#include <fcntl.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <xenctrl.h>#define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */static int xc_handle;static inline intcurvcpuid(){ struct process_info *process; if (current_inferior == NULL) return 0; process = get_thread_process(current_inferior); return (process->thread_known ? process->tid : 0);}struct inferior_list all_processes;static int current_domid;static int expect_signal = 0;static int signal_to_send = 0; static void linux_resume (struct thread_resume *resume_info);static void linux_set_inferior (void);int debug_threads;int using_threads;extern int isfile;struct pending_signals{ int signal; struct pending_signals *prev;};#define PTRACE_ARG3_TYPE long#define PTRACE_XFER_TYPE longstatic int use_regsets_p = 1;#define pid_of(proc) ((proc)->head.id)/* FIXME: Delete eventually. */#define inferior_pid (pid_of (get_thread_process (current_inferior)))/* This function should only be called if the process got a SIGTRAP. The SIGTRAP could mean several things. On i386, where decr_pc_after_break is non-zero: If we were single-stepping this process using PTRACE_SINGLESTEP, we will get only the one SIGTRAP (even if the instruction we stepped over was a breakpoint). The value of $eip will be the next instruction. If we continue the process using PTRACE_CONT, we will get a SIGTRAP when we hit a breakpoint. The value of $eip will be the instruction after the breakpoint (i.e. needs to be decremented). If we report the SIGTRAP to GDB, we must also report the undecremented PC. If we cancel the SIGTRAP, we must resume at the decremented PC. (Presumably, not yet tested) On a non-decr_pc_after_break machine with hardware or kernel single-step: If we single-step over a breakpoint instruction, our PC will point at the following instruction. If we continue and hit a breakpoint instruction, our PC will point at the breakpoint instruction. */static CORE_ADDRget_stop_pc (void){ CORE_ADDR stop_pc = (*the_low_target.get_pc) (); if (get_thread_process (current_inferior)->stepping) return stop_pc; else return stop_pc - the_low_target.decr_pc_after_break;}static void *add_process (int pid, long tid){ struct process_info *process; process = (struct process_info *) malloc (sizeof (*process)); memset (process, 0, sizeof (*process)); process->head.id = pid; process->tid = tid; process->lwpid = tid; add_inferior_to_list (&all_processes, &process->head); return process;}/* Start an inferior process and returns its pid. ALLARGS is a vector of program-name and args. */static intlinux_create_inferior (char *program, char **allargs){ fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno)); fflush (stderr); _exit (0177); /* NOT REACHED */ return -1;}intlinux_attach (int domid){ struct process_info *new_process; current_domid = domid; /* this is handled for all active vcpus in PTRACE_ATTACH via the thread_create_callback */ new_process = (struct process_info *) add_process (domid, curvcpuid()); /* Don't ignore the initial SIGSTOP if we just attached to this process. */ /* vcpuid == 0 */ add_thread (0, new_process); new_process->stop_expected = 0; if (xc_ptrace (xc_handle, PTRACE_ATTACH, domid, 0, isfile) != 0) { fprintf (stderr, "Cannot attach to domain %d: %s (%d)\n", domid, strerror (errno), errno); fflush (stderr); if (!using_threads) _exit (0177); } return 0;}/* Kill the inferior process. Make us have no inferior. */static voidlinux_kill_one_process (struct inferior_list_entry *entry){ struct thread_info *thread = (struct thread_info *) entry; struct process_info *process = get_thread_process (thread); xc_ptrace (xc_handle, PTRACE_KILL, pid_of (process), 0, 0);}static voidlinux_kill (void){ for_each_inferior (&all_threads, linux_kill_one_process);}static voidlinux_detach_one_process (struct inferior_list_entry *entry){ xc_ptrace (xc_handle, PTRACE_DETACH, current_domid, 0, 0);}static voidlinux_detach (void){ for_each_inferior (&all_threads, linux_detach_one_process);}/* Return nonzero if the given thread is still alive. */static intlinux_thread_alive (int tid){ if (find_inferior_id (&all_threads, tid) != NULL) return 1; else return 0;}/* Wait for process, returns status. */static unsigned charlinux_wait (char *status){ int w; if (xc_waitdomain(xc_handle, current_domid, &w, 0)) return -1; *status = 'T'; if (expect_signal) return expect_signal; else return SIGTRAP;}static voidlinux_resume (struct thread_resume *resume_info){ int step = resume_info->step; TRACE_ENTER; expect_signal = resume_info->sig; for_each_inferior(&all_threads, regcache_invalidate_one); if (debug_threads) fprintf(stderr, "step: %d\n", step); xc_ptrace (xc_handle, step ? PTRACE_SINGLESTEP : PTRACE_CONT, resume_info->thread, 0, 0);}static intregsets_fetch_inferior_registers (){ struct regset_info *regset; TRACE_ENTER; regset = target_regsets; while (regset->size >= 0) { void *buf; int res; if (regset->size == 0) { regset ++; continue; } buf = malloc (regset->size); res = xc_ptrace (xc_handle, regset->get_request, curvcpuid(), 0, (PTRACE_XFER_TYPE)buf); if (res < 0) { if (errno == EIO) { /* If we get EIO on the first regset, do not try regsets again. If we get EIO on a later regset, disable that regset. */ if (regset == target_regsets) { use_regsets_p = 0; return -1; } else { regset->size = 0; continue; } } else { char s[256]; sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d", inferior_pid); perror (s); } } regset->store_function (buf); regset ++; } return 0;}static intregsets_store_inferior_registers (){ struct regset_info *regset; TRACE_ENTER; regset = target_regsets; while (regset->size >= 0) { void *buf; int res; if (regset->size == 0) { regset ++; continue; } buf = malloc (regset->size); regset->fill_function (buf); res = xc_ptrace (xc_handle, regset->set_request, curvcpuid(), 0, (PTRACE_XFER_TYPE)buf); if (res < 0) { if (errno == EIO) { /* If we get EIO on the first regset, do not try regsets again. If we get EIO on a later regset, disable that regset. */ if (regset == target_regsets) { use_regsets_p = 0; return -1; } else { regset->size = 0; continue; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -