mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-09 00:53:10 +00:00
This removes gdb_string.h. This patch is purely mechanical. I
created it by running the two commands:
git rm common/gdb_string.h
perl -pi -e's/"gdb_string.h"/<string.h>/;' *.[chyl] */*.[chyl]
2013-11-18 Tom Tromey <tromey@redhat.com>
* common/gdb_string.h: Remove.
* aarch64-tdep.c: Use string.h, not gdb_string.h.
* ada-exp.y: Use string.h, not gdb_string.h.
* ada-lang.c: Use string.h, not gdb_string.h.
* ada-lex.l: Use string.h, not gdb_string.h.
* ada-typeprint.c: Use string.h, not gdb_string.h.
* ada-valprint.c: Use string.h, not gdb_string.h.
* aix-thread.c: Use string.h, not gdb_string.h.
* alpha-linux-tdep.c: Use string.h, not gdb_string.h.
* alpha-mdebug-tdep.c: Use string.h, not gdb_string.h.
* alpha-nat.c: Use string.h, not gdb_string.h.
* alpha-osf1-tdep.c: Use string.h, not gdb_string.h.
* alpha-tdep.c: Use string.h, not gdb_string.h.
* alphanbsd-tdep.c: Use string.h, not gdb_string.h.
* amd64-dicos-tdep.c: Use string.h, not gdb_string.h.
* amd64-linux-nat.c: Use string.h, not gdb_string.h.
* amd64-linux-tdep.c: Use string.h, not gdb_string.h.
* amd64-nat.c: Use string.h, not gdb_string.h.
* amd64-sol2-tdep.c: Use string.h, not gdb_string.h.
* amd64fbsd-tdep.c: Use string.h, not gdb_string.h.
* amd64obsd-tdep.c: Use string.h, not gdb_string.h.
* arch-utils.c: Use string.h, not gdb_string.h.
* arm-linux-nat.c: Use string.h, not gdb_string.h.
* arm-linux-tdep.c: Use string.h, not gdb_string.h.
* arm-tdep.c: Use string.h, not gdb_string.h.
* arm-wince-tdep.c: Use string.h, not gdb_string.h.
* armbsd-tdep.c: Use string.h, not gdb_string.h.
* armnbsd-nat.c: Use string.h, not gdb_string.h.
* armnbsd-tdep.c: Use string.h, not gdb_string.h.
* armobsd-tdep.c: Use string.h, not gdb_string.h.
* avr-tdep.c: Use string.h, not gdb_string.h.
* ax-gdb.c: Use string.h, not gdb_string.h.
* ax-general.c: Use string.h, not gdb_string.h.
* bcache.c: Use string.h, not gdb_string.h.
* bfin-tdep.c: Use string.h, not gdb_string.h.
* breakpoint.c: Use string.h, not gdb_string.h.
* build-id.c: Use string.h, not gdb_string.h.
* buildsym.c: Use string.h, not gdb_string.h.
* c-exp.y: Use string.h, not gdb_string.h.
* c-lang.c: Use string.h, not gdb_string.h.
* c-typeprint.c: Use string.h, not gdb_string.h.
* c-valprint.c: Use string.h, not gdb_string.h.
* charset.c: Use string.h, not gdb_string.h.
* cli-out.c: Use string.h, not gdb_string.h.
* cli/cli-cmds.c: Use string.h, not gdb_string.h.
* cli/cli-decode.c: Use string.h, not gdb_string.h.
* cli/cli-dump.c: Use string.h, not gdb_string.h.
* cli/cli-interp.c: Use string.h, not gdb_string.h.
* cli/cli-logging.c: Use string.h, not gdb_string.h.
* cli/cli-script.c: Use string.h, not gdb_string.h.
* cli/cli-setshow.c: Use string.h, not gdb_string.h.
* cli/cli-utils.c: Use string.h, not gdb_string.h.
* coffread.c: Use string.h, not gdb_string.h.
* common/common-utils.c: Use string.h, not gdb_string.h.
* common/filestuff.c: Use string.h, not gdb_string.h.
* common/linux-procfs.c: Use string.h, not gdb_string.h.
* common/linux-ptrace.c: Use string.h, not gdb_string.h.
* common/signals.c: Use string.h, not gdb_string.h.
* common/vec.h: Use string.h, not gdb_string.h.
* core-regset.c: Use string.h, not gdb_string.h.
* corefile.c: Use string.h, not gdb_string.h.
* corelow.c: Use string.h, not gdb_string.h.
* cp-abi.c: Use string.h, not gdb_string.h.
* cp-support.c: Use string.h, not gdb_string.h.
* cp-valprint.c: Use string.h, not gdb_string.h.
* cris-tdep.c: Use string.h, not gdb_string.h.
* d-lang.c: Use string.h, not gdb_string.h.
* dbxread.c: Use string.h, not gdb_string.h.
* dcache.c: Use string.h, not gdb_string.h.
* demangle.c: Use string.h, not gdb_string.h.
* dicos-tdep.c: Use string.h, not gdb_string.h.
* disasm.c: Use string.h, not gdb_string.h.
* doublest.c: Use string.h, not gdb_string.h.
* dsrec.c: Use string.h, not gdb_string.h.
* dummy-frame.c: Use string.h, not gdb_string.h.
* dwarf2-frame.c: Use string.h, not gdb_string.h.
* dwarf2loc.c: Use string.h, not gdb_string.h.
* dwarf2read.c: Use string.h, not gdb_string.h.
* elfread.c: Use string.h, not gdb_string.h.
* environ.c: Use string.h, not gdb_string.h.
* eval.c: Use string.h, not gdb_string.h.
* event-loop.c: Use string.h, not gdb_string.h.
* exceptions.c: Use string.h, not gdb_string.h.
* exec.c: Use string.h, not gdb_string.h.
* expprint.c: Use string.h, not gdb_string.h.
* f-exp.y: Use string.h, not gdb_string.h.
* f-lang.c: Use string.h, not gdb_string.h.
* f-typeprint.c: Use string.h, not gdb_string.h.
* f-valprint.c: Use string.h, not gdb_string.h.
* fbsd-nat.c: Use string.h, not gdb_string.h.
* findcmd.c: Use string.h, not gdb_string.h.
* findvar.c: Use string.h, not gdb_string.h.
* fork-child.c: Use string.h, not gdb_string.h.
* frame.c: Use string.h, not gdb_string.h.
* frv-linux-tdep.c: Use string.h, not gdb_string.h.
* frv-tdep.c: Use string.h, not gdb_string.h.
* gdb.c: Use string.h, not gdb_string.h.
* gdb_bfd.c: Use string.h, not gdb_string.h.
* gdbarch.c: Use string.h, not gdb_string.h.
* gdbtypes.c: Use string.h, not gdb_string.h.
* gnu-nat.c: Use string.h, not gdb_string.h.
* gnu-v2-abi.c: Use string.h, not gdb_string.h.
* gnu-v3-abi.c: Use string.h, not gdb_string.h.
* go-exp.y: Use string.h, not gdb_string.h.
* go-lang.c: Use string.h, not gdb_string.h.
* go32-nat.c: Use string.h, not gdb_string.h.
* hppa-hpux-tdep.c: Use string.h, not gdb_string.h.
* hppa-linux-nat.c: Use string.h, not gdb_string.h.
* hppanbsd-tdep.c: Use string.h, not gdb_string.h.
* hppaobsd-tdep.c: Use string.h, not gdb_string.h.
* i386-cygwin-tdep.c: Use string.h, not gdb_string.h.
* i386-dicos-tdep.c: Use string.h, not gdb_string.h.
* i386-linux-nat.c: Use string.h, not gdb_string.h.
* i386-linux-tdep.c: Use string.h, not gdb_string.h.
* i386-nto-tdep.c: Use string.h, not gdb_string.h.
* i386-sol2-tdep.c: Use string.h, not gdb_string.h.
* i386-tdep.c: Use string.h, not gdb_string.h.
* i386bsd-tdep.c: Use string.h, not gdb_string.h.
* i386gnu-nat.c: Use string.h, not gdb_string.h.
* i386nbsd-tdep.c: Use string.h, not gdb_string.h.
* i386obsd-tdep.c: Use string.h, not gdb_string.h.
* i387-tdep.c: Use string.h, not gdb_string.h.
* ia64-libunwind-tdep.c: Use string.h, not gdb_string.h.
* ia64-linux-nat.c: Use string.h, not gdb_string.h.
* inf-child.c: Use string.h, not gdb_string.h.
* inf-ptrace.c: Use string.h, not gdb_string.h.
* inf-ttrace.c: Use string.h, not gdb_string.h.
* infcall.c: Use string.h, not gdb_string.h.
* infcmd.c: Use string.h, not gdb_string.h.
* inflow.c: Use string.h, not gdb_string.h.
* infrun.c: Use string.h, not gdb_string.h.
* interps.c: Use string.h, not gdb_string.h.
* iq2000-tdep.c: Use string.h, not gdb_string.h.
* irix5-nat.c: Use string.h, not gdb_string.h.
* jv-exp.y: Use string.h, not gdb_string.h.
* jv-lang.c: Use string.h, not gdb_string.h.
* jv-typeprint.c: Use string.h, not gdb_string.h.
* jv-valprint.c: Use string.h, not gdb_string.h.
* language.c: Use string.h, not gdb_string.h.
* linux-fork.c: Use string.h, not gdb_string.h.
* linux-nat.c: Use string.h, not gdb_string.h.
* lm32-tdep.c: Use string.h, not gdb_string.h.
* m2-exp.y: Use string.h, not gdb_string.h.
* m2-typeprint.c: Use string.h, not gdb_string.h.
* m32c-tdep.c: Use string.h, not gdb_string.h.
* m32r-linux-nat.c: Use string.h, not gdb_string.h.
* m32r-linux-tdep.c: Use string.h, not gdb_string.h.
* m32r-rom.c: Use string.h, not gdb_string.h.
* m32r-tdep.c: Use string.h, not gdb_string.h.
* m68hc11-tdep.c: Use string.h, not gdb_string.h.
* m68k-tdep.c: Use string.h, not gdb_string.h.
* m68kbsd-tdep.c: Use string.h, not gdb_string.h.
* m68klinux-nat.c: Use string.h, not gdb_string.h.
* m68klinux-tdep.c: Use string.h, not gdb_string.h.
* m88k-tdep.c: Use string.h, not gdb_string.h.
* macrocmd.c: Use string.h, not gdb_string.h.
* main.c: Use string.h, not gdb_string.h.
* mdebugread.c: Use string.h, not gdb_string.h.
* mem-break.c: Use string.h, not gdb_string.h.
* memattr.c: Use string.h, not gdb_string.h.
* memory-map.c: Use string.h, not gdb_string.h.
* mep-tdep.c: Use string.h, not gdb_string.h.
* mi/mi-cmd-break.c: Use string.h, not gdb_string.h.
* mi/mi-cmd-disas.c: Use string.h, not gdb_string.h.
* mi/mi-cmd-env.c: Use string.h, not gdb_string.h.
* mi/mi-cmd-stack.c: Use string.h, not gdb_string.h.
* mi/mi-cmd-var.c: Use string.h, not gdb_string.h.
* mi/mi-cmds.c: Use string.h, not gdb_string.h.
* mi/mi-console.c: Use string.h, not gdb_string.h.
* mi/mi-getopt.c: Use string.h, not gdb_string.h.
* mi/mi-interp.c: Use string.h, not gdb_string.h.
* mi/mi-main.c: Use string.h, not gdb_string.h.
* mi/mi-parse.c: Use string.h, not gdb_string.h.
* microblaze-rom.c: Use string.h, not gdb_string.h.
* microblaze-tdep.c: Use string.h, not gdb_string.h.
* mingw-hdep.c: Use string.h, not gdb_string.h.
* minidebug.c: Use string.h, not gdb_string.h.
* minsyms.c: Use string.h, not gdb_string.h.
* mips-irix-tdep.c: Use string.h, not gdb_string.h.
* mips-linux-tdep.c: Use string.h, not gdb_string.h.
* mips-tdep.c: Use string.h, not gdb_string.h.
* mips64obsd-tdep.c: Use string.h, not gdb_string.h.
* mipsnbsd-tdep.c: Use string.h, not gdb_string.h.
* mipsread.c: Use string.h, not gdb_string.h.
* mn10300-linux-tdep.c: Use string.h, not gdb_string.h.
* mn10300-tdep.c: Use string.h, not gdb_string.h.
* monitor.c: Use string.h, not gdb_string.h.
* moxie-tdep.c: Use string.h, not gdb_string.h.
* mt-tdep.c: Use string.h, not gdb_string.h.
* nbsd-tdep.c: Use string.h, not gdb_string.h.
* nios2-linux-tdep.c: Use string.h, not gdb_string.h.
* nto-procfs.c: Use string.h, not gdb_string.h.
* nto-tdep.c: Use string.h, not gdb_string.h.
* objc-lang.c: Use string.h, not gdb_string.h.
* objfiles.c: Use string.h, not gdb_string.h.
* opencl-lang.c: Use string.h, not gdb_string.h.
* osabi.c: Use string.h, not gdb_string.h.
* osdata.c: Use string.h, not gdb_string.h.
* p-exp.y: Use string.h, not gdb_string.h.
* p-lang.c: Use string.h, not gdb_string.h.
* p-typeprint.c: Use string.h, not gdb_string.h.
* parse.c: Use string.h, not gdb_string.h.
* posix-hdep.c: Use string.h, not gdb_string.h.
* ppc-linux-nat.c: Use string.h, not gdb_string.h.
* ppc-sysv-tdep.c: Use string.h, not gdb_string.h.
* ppcfbsd-tdep.c: Use string.h, not gdb_string.h.
* ppcnbsd-tdep.c: Use string.h, not gdb_string.h.
* ppcobsd-tdep.c: Use string.h, not gdb_string.h.
* printcmd.c: Use string.h, not gdb_string.h.
* procfs.c: Use string.h, not gdb_string.h.
* prologue-value.c: Use string.h, not gdb_string.h.
* python/py-auto-load.c: Use string.h, not gdb_string.h.
* python/py-gdb-readline.c: Use string.h, not gdb_string.h.
* ravenscar-thread.c: Use string.h, not gdb_string.h.
* regcache.c: Use string.h, not gdb_string.h.
* registry.c: Use string.h, not gdb_string.h.
* remote-fileio.c: Use string.h, not gdb_string.h.
* remote-m32r-sdi.c: Use string.h, not gdb_string.h.
* remote-mips.c: Use string.h, not gdb_string.h.
* remote-sim.c: Use string.h, not gdb_string.h.
* remote.c: Use string.h, not gdb_string.h.
* reverse.c: Use string.h, not gdb_string.h.
* rs6000-aix-tdep.c: Use string.h, not gdb_string.h.
* ser-base.c: Use string.h, not gdb_string.h.
* ser-go32.c: Use string.h, not gdb_string.h.
* ser-mingw.c: Use string.h, not gdb_string.h.
* ser-pipe.c: Use string.h, not gdb_string.h.
* ser-tcp.c: Use string.h, not gdb_string.h.
* ser-unix.c: Use string.h, not gdb_string.h.
* serial.c: Use string.h, not gdb_string.h.
* sh-tdep.c: Use string.h, not gdb_string.h.
* sh64-tdep.c: Use string.h, not gdb_string.h.
* shnbsd-tdep.c: Use string.h, not gdb_string.h.
* skip.c: Use string.h, not gdb_string.h.
* sol-thread.c: Use string.h, not gdb_string.h.
* solib-dsbt.c: Use string.h, not gdb_string.h.
* solib-frv.c: Use string.h, not gdb_string.h.
* solib-osf.c: Use string.h, not gdb_string.h.
* solib-spu.c: Use string.h, not gdb_string.h.
* solib-target.c: Use string.h, not gdb_string.h.
* solib.c: Use string.h, not gdb_string.h.
* somread.c: Use string.h, not gdb_string.h.
* source.c: Use string.h, not gdb_string.h.
* sparc-nat.c: Use string.h, not gdb_string.h.
* sparc-sol2-tdep.c: Use string.h, not gdb_string.h.
* sparc-tdep.c: Use string.h, not gdb_string.h.
* sparc64-tdep.c: Use string.h, not gdb_string.h.
* sparc64fbsd-tdep.c: Use string.h, not gdb_string.h.
* sparc64nbsd-tdep.c: Use string.h, not gdb_string.h.
* sparcnbsd-tdep.c: Use string.h, not gdb_string.h.
* spu-linux-nat.c: Use string.h, not gdb_string.h.
* spu-multiarch.c: Use string.h, not gdb_string.h.
* spu-tdep.c: Use string.h, not gdb_string.h.
* stabsread.c: Use string.h, not gdb_string.h.
* stack.c: Use string.h, not gdb_string.h.
* std-regs.c: Use string.h, not gdb_string.h.
* symfile.c: Use string.h, not gdb_string.h.
* symmisc.c: Use string.h, not gdb_string.h.
* symtab.c: Use string.h, not gdb_string.h.
* target.c: Use string.h, not gdb_string.h.
* thread.c: Use string.h, not gdb_string.h.
* tilegx-linux-nat.c: Use string.h, not gdb_string.h.
* tilegx-tdep.c: Use string.h, not gdb_string.h.
* top.c: Use string.h, not gdb_string.h.
* tracepoint.c: Use string.h, not gdb_string.h.
* tui/tui-command.c: Use string.h, not gdb_string.h.
* tui/tui-data.c: Use string.h, not gdb_string.h.
* tui/tui-disasm.c: Use string.h, not gdb_string.h.
* tui/tui-file.c: Use string.h, not gdb_string.h.
* tui/tui-layout.c: Use string.h, not gdb_string.h.
* tui/tui-out.c: Use string.h, not gdb_string.h.
* tui/tui-regs.c: Use string.h, not gdb_string.h.
* tui/tui-source.c: Use string.h, not gdb_string.h.
* tui/tui-stack.c: Use string.h, not gdb_string.h.
* tui/tui-win.c: Use string.h, not gdb_string.h.
* tui/tui-windata.c: Use string.h, not gdb_string.h.
* tui/tui-winsource.c: Use string.h, not gdb_string.h.
* typeprint.c: Use string.h, not gdb_string.h.
* ui-file.c: Use string.h, not gdb_string.h.
* ui-out.c: Use string.h, not gdb_string.h.
* user-regs.c: Use string.h, not gdb_string.h.
* utils.c: Use string.h, not gdb_string.h.
* v850-tdep.c: Use string.h, not gdb_string.h.
* valarith.c: Use string.h, not gdb_string.h.
* valops.c: Use string.h, not gdb_string.h.
* valprint.c: Use string.h, not gdb_string.h.
* value.c: Use string.h, not gdb_string.h.
* varobj.c: Use string.h, not gdb_string.h.
* vax-tdep.c: Use string.h, not gdb_string.h.
* vaxnbsd-tdep.c: Use string.h, not gdb_string.h.
* vaxobsd-tdep.c: Use string.h, not gdb_string.h.
* windows-nat.c: Use string.h, not gdb_string.h.
* xcoffread.c: Use string.h, not gdb_string.h.
* xml-support.c: Use string.h, not gdb_string.h.
* xstormy16-tdep.c: Use string.h, not gdb_string.h.
* xtensa-linux-nat.c: Use string.h, not gdb_string.h.
545 lines
16 KiB
C
545 lines
16 KiB
C
/* Linux-specific ptrace manipulation routines.
|
|
Copyright (C) 2012-2013 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 3 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, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifdef GDBSERVER
|
|
#include "server.h"
|
|
#else
|
|
#include "defs.h"
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#include "linux-ptrace.h"
|
|
#include "linux-procfs.h"
|
|
#include "nat/linux-waitpid.h"
|
|
#include "buffer.h"
|
|
#include "gdb_assert.h"
|
|
#include "gdb_wait.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
/* Stores the currently supported ptrace options. A value of
|
|
-1 means we did not check for features yet. A value of 0 means
|
|
there are no supported features. */
|
|
static int current_ptrace_options = -1;
|
|
|
|
/* Find all possible reasons we could fail to attach PID and append these
|
|
newline terminated reason strings to initialized BUFFER. '\0' termination
|
|
of BUFFER must be done by the caller. */
|
|
|
|
void
|
|
linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer)
|
|
{
|
|
pid_t tracerpid;
|
|
|
|
tracerpid = linux_proc_get_tracerpid (pid);
|
|
if (tracerpid > 0)
|
|
buffer_xml_printf (buffer, _("warning: process %d is already traced "
|
|
"by process %d\n"),
|
|
(int) pid, (int) tracerpid);
|
|
|
|
if (linux_proc_pid_is_zombie (pid))
|
|
buffer_xml_printf (buffer, _("warning: process %d is a zombie "
|
|
"- the process has already terminated\n"),
|
|
(int) pid);
|
|
}
|
|
|
|
#if defined __i386__ || defined __x86_64__
|
|
|
|
/* Address of the 'ret' instruction in asm code block below. */
|
|
extern void (linux_ptrace_test_ret_to_nx_instr) (void);
|
|
|
|
#include <sys/reg.h>
|
|
#include <sys/mman.h>
|
|
#include <signal.h>
|
|
|
|
#endif /* defined __i386__ || defined __x86_64__ */
|
|
|
|
/* Test broken off-trunk Linux kernel patchset for NX support on i386. It was
|
|
removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd.
|
|
|
|
Test also x86_64 arch for PaX support. */
|
|
|
|
static void
|
|
linux_ptrace_test_ret_to_nx (void)
|
|
{
|
|
#if defined __i386__ || defined __x86_64__
|
|
pid_t child, got_pid;
|
|
gdb_byte *return_address, *pc;
|
|
long l;
|
|
int status, kill_status;
|
|
|
|
return_address = mmap (NULL, 2, PROT_READ | PROT_WRITE,
|
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
if (return_address == MAP_FAILED)
|
|
{
|
|
warning (_("linux_ptrace_test_ret_to_nx: Cannot mmap: %s"),
|
|
strerror (errno));
|
|
return;
|
|
}
|
|
|
|
/* Put there 'int3'. */
|
|
*return_address = 0xcc;
|
|
|
|
child = fork ();
|
|
switch (child)
|
|
{
|
|
case -1:
|
|
warning (_("linux_ptrace_test_ret_to_nx: Cannot fork: %s"),
|
|
strerror (errno));
|
|
return;
|
|
|
|
case 0:
|
|
l = ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) NULL,
|
|
(PTRACE_TYPE_ARG4) NULL);
|
|
if (l != 0)
|
|
warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"),
|
|
strerror (errno));
|
|
else
|
|
{
|
|
#if defined __i386__
|
|
asm volatile ("pushl %0;"
|
|
".globl linux_ptrace_test_ret_to_nx_instr;"
|
|
"linux_ptrace_test_ret_to_nx_instr:"
|
|
"ret"
|
|
: : "r" (return_address) : "%esp", "memory");
|
|
#elif defined __x86_64__
|
|
asm volatile ("pushq %0;"
|
|
".globl linux_ptrace_test_ret_to_nx_instr;"
|
|
"linux_ptrace_test_ret_to_nx_instr:"
|
|
"ret"
|
|
: : "r" ((uint64_t) (uintptr_t) return_address)
|
|
: "%rsp", "memory");
|
|
#else
|
|
# error "!__i386__ && !__x86_64__"
|
|
#endif
|
|
gdb_assert_not_reached ("asm block did not terminate");
|
|
}
|
|
|
|
_exit (1);
|
|
}
|
|
|
|
errno = 0;
|
|
got_pid = waitpid (child, &status, 0);
|
|
if (got_pid != child)
|
|
{
|
|
warning (_("linux_ptrace_test_ret_to_nx: waitpid returned %ld: %s"),
|
|
(long) got_pid, strerror (errno));
|
|
return;
|
|
}
|
|
|
|
if (WIFSIGNALED (status))
|
|
{
|
|
if (WTERMSIG (status) != SIGKILL)
|
|
warning (_("linux_ptrace_test_ret_to_nx: WTERMSIG %d is not SIGKILL!"),
|
|
(int) WTERMSIG (status));
|
|
else
|
|
warning (_("Cannot call inferior functions, Linux kernel PaX "
|
|
"protection forbids return to non-executable pages!"));
|
|
return;
|
|
}
|
|
|
|
if (!WIFSTOPPED (status))
|
|
{
|
|
warning (_("linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"),
|
|
status);
|
|
return;
|
|
}
|
|
|
|
/* We may get SIGSEGV due to missing PROT_EXEC of the return_address. */
|
|
if (WSTOPSIG (status) != SIGTRAP && WSTOPSIG (status) != SIGSEGV)
|
|
{
|
|
warning (_("linux_ptrace_test_ret_to_nx: "
|
|
"WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"),
|
|
(int) WSTOPSIG (status));
|
|
return;
|
|
}
|
|
|
|
errno = 0;
|
|
#if defined __i386__
|
|
l = ptrace (PTRACE_PEEKUSER, child, (PTRACE_TYPE_ARG3) (uintptr_t) (EIP * 4),
|
|
(PTRACE_TYPE_ARG4) NULL);
|
|
#elif defined __x86_64__
|
|
l = ptrace (PTRACE_PEEKUSER, child, (PTRACE_TYPE_ARG3) (uintptr_t) (RIP * 8),
|
|
(PTRACE_TYPE_ARG4) NULL);
|
|
#else
|
|
# error "!__i386__ && !__x86_64__"
|
|
#endif
|
|
if (errno != 0)
|
|
{
|
|
warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_PEEKUSER: %s"),
|
|
strerror (errno));
|
|
return;
|
|
}
|
|
pc = (void *) (uintptr_t) l;
|
|
|
|
kill (child, SIGKILL);
|
|
ptrace (PTRACE_KILL, child, (PTRACE_TYPE_ARG3) NULL,
|
|
(PTRACE_TYPE_ARG4) NULL);
|
|
|
|
errno = 0;
|
|
got_pid = waitpid (child, &kill_status, 0);
|
|
if (got_pid != child)
|
|
{
|
|
warning (_("linux_ptrace_test_ret_to_nx: "
|
|
"PTRACE_KILL waitpid returned %ld: %s"),
|
|
(long) got_pid, strerror (errno));
|
|
return;
|
|
}
|
|
if (!WIFSIGNALED (kill_status))
|
|
{
|
|
warning (_("linux_ptrace_test_ret_to_nx: "
|
|
"PTRACE_KILL status %d is not WIFSIGNALED!"),
|
|
status);
|
|
return;
|
|
}
|
|
|
|
/* + 1 is there as x86* stops after the 'int3' instruction. */
|
|
if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1)
|
|
{
|
|
/* PASS */
|
|
return;
|
|
}
|
|
|
|
/* We may get SIGSEGV due to missing PROT_EXEC of the RETURN_ADDRESS page. */
|
|
if (WSTOPSIG (status) == SIGSEGV && pc == return_address)
|
|
{
|
|
/* PASS */
|
|
return;
|
|
}
|
|
|
|
if ((void (*) (void)) pc != &linux_ptrace_test_ret_to_nx_instr)
|
|
warning (_("linux_ptrace_test_ret_to_nx: PC %p is neither near return "
|
|
"address %p nor is the return instruction %p!"),
|
|
pc, return_address, &linux_ptrace_test_ret_to_nx_instr);
|
|
else
|
|
warning (_("Cannot call inferior functions on this system - "
|
|
"Linux kernel with broken i386 NX (non-executable pages) "
|
|
"support detected!"));
|
|
#endif /* defined __i386__ || defined __x86_64__ */
|
|
}
|
|
|
|
/* Helper function to fork a process and make the child process call
|
|
the function FUNCTION, passing CHILD_STACK as parameter.
|
|
|
|
For MMU-less targets, clone is used instead of fork, and
|
|
CHILD_STACK is used as stack space for the cloned child. If NULL,
|
|
stack space is allocated via malloc (and subsequently passed to
|
|
FUNCTION). For MMU targets, CHILD_STACK is ignored. */
|
|
|
|
static int
|
|
linux_fork_to_function (gdb_byte *child_stack, void (*function) (gdb_byte *))
|
|
{
|
|
int child_pid;
|
|
|
|
/* Sanity check the function pointer. */
|
|
gdb_assert (function != NULL);
|
|
|
|
#if defined(__UCLIBC__) && defined(HAS_NOMMU)
|
|
#define STACK_SIZE 4096
|
|
|
|
if (child_stack == NULL)
|
|
child_stack = xmalloc (STACK_SIZE * 4);
|
|
|
|
/* Use CLONE_VM instead of fork, to support uClinux (no MMU). */
|
|
#ifdef __ia64__
|
|
child_pid = __clone2 (function, child_stack, STACK_SIZE,
|
|
CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2);
|
|
#else /* !__ia64__ */
|
|
child_pid = clone (function, child_stack + STACK_SIZE,
|
|
CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2);
|
|
#endif /* !__ia64__ */
|
|
#else /* !defined(__UCLIBC) && defined(HAS_NOMMU) */
|
|
child_pid = fork ();
|
|
|
|
if (child_pid == 0)
|
|
function (NULL);
|
|
#endif /* defined(__UCLIBC) && defined(HAS_NOMMU) */
|
|
|
|
if (child_pid == -1)
|
|
perror_with_name (("fork"));
|
|
|
|
return child_pid;
|
|
}
|
|
|
|
/* A helper function for linux_check_ptrace_features, called after
|
|
the child forks a grandchild. */
|
|
|
|
static void
|
|
linux_grandchild_function (gdb_byte *child_stack)
|
|
{
|
|
/* Free any allocated stack. */
|
|
xfree (child_stack);
|
|
|
|
/* This code is only reacheable by the grandchild (child's child)
|
|
process. */
|
|
_exit (0);
|
|
}
|
|
|
|
/* A helper function for linux_check_ptrace_features, called after
|
|
the parent process forks a child. The child allows itself to
|
|
be traced by its parent. */
|
|
|
|
static void
|
|
linux_child_function (gdb_byte *child_stack)
|
|
{
|
|
ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
|
|
kill (getpid (), SIGSTOP);
|
|
|
|
/* Fork a grandchild. */
|
|
linux_fork_to_function (child_stack, linux_grandchild_function);
|
|
|
|
/* This code is only reacheable by the child (grandchild's parent)
|
|
process. */
|
|
_exit (0);
|
|
}
|
|
|
|
static void linux_test_for_tracesysgood (int child_pid);
|
|
static void linux_test_for_tracefork (int child_pid);
|
|
|
|
/* Determine ptrace features available on this target. */
|
|
|
|
static void
|
|
linux_check_ptrace_features (void)
|
|
{
|
|
int child_pid, ret, status;
|
|
|
|
/* Initialize the options. */
|
|
current_ptrace_options = 0;
|
|
|
|
/* Fork a child so we can do some testing. The child will call
|
|
linux_child_function and will get traced. The child will
|
|
eventually fork a grandchild so we can test fork event
|
|
reporting. */
|
|
child_pid = linux_fork_to_function (NULL, linux_child_function);
|
|
|
|
ret = my_waitpid (child_pid, &status, 0);
|
|
if (ret == -1)
|
|
perror_with_name (("waitpid"));
|
|
else if (ret != child_pid)
|
|
error (_("linux_check_ptrace_features: waitpid: unexpected result %d."),
|
|
ret);
|
|
if (! WIFSTOPPED (status))
|
|
error (_("linux_check_ptrace_features: waitpid: unexpected status %d."),
|
|
status);
|
|
|
|
linux_test_for_tracesysgood (child_pid);
|
|
|
|
linux_test_for_tracefork (child_pid);
|
|
|
|
/* Clean things up and kill any pending children. */
|
|
do
|
|
{
|
|
ret = ptrace (PTRACE_KILL, child_pid, (PTRACE_TYPE_ARG3) 0,
|
|
(PTRACE_TYPE_ARG4) 0);
|
|
if (ret != 0)
|
|
warning (_("linux_check_ptrace_features: failed to kill child"));
|
|
my_waitpid (child_pid, &status, 0);
|
|
}
|
|
while (WIFSTOPPED (status));
|
|
}
|
|
|
|
/* Determine if PTRACE_O_TRACESYSGOOD can be used to catch
|
|
syscalls. */
|
|
|
|
static void
|
|
linux_test_for_tracesysgood (int child_pid)
|
|
{
|
|
#ifdef GDBSERVER
|
|
/* gdbserver does not support PTRACE_O_TRACESYSGOOD. */
|
|
#else
|
|
int ret;
|
|
|
|
ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
|
|
(PTRACE_TYPE_ARG4) PTRACE_O_TRACESYSGOOD);
|
|
if (ret == 0)
|
|
current_ptrace_options |= PTRACE_O_TRACESYSGOOD;
|
|
#endif
|
|
}
|
|
|
|
/* Determine if PTRACE_O_TRACEFORK can be used to follow fork
|
|
events. */
|
|
|
|
static void
|
|
linux_test_for_tracefork (int child_pid)
|
|
{
|
|
int ret, status;
|
|
long second_pid;
|
|
|
|
/* First, set the PTRACE_O_TRACEFORK option. If this fails, we
|
|
know for sure that it is not supported. */
|
|
ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
|
|
(PTRACE_TYPE_ARG4) PTRACE_O_TRACEFORK);
|
|
|
|
if (ret != 0)
|
|
return;
|
|
|
|
#ifdef GDBSERVER
|
|
/* gdbserver does not support PTRACE_O_TRACEVFORKDONE yet. */
|
|
#else
|
|
/* Check if the target supports PTRACE_O_TRACEVFORKDONE. */
|
|
ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
|
|
(PTRACE_TYPE_ARG4) (PTRACE_O_TRACEFORK
|
|
| PTRACE_O_TRACEVFORKDONE));
|
|
if (ret == 0)
|
|
current_ptrace_options |= PTRACE_O_TRACEVFORKDONE;
|
|
#endif
|
|
|
|
/* Setting PTRACE_O_TRACEFORK did not cause an error, however we
|
|
don't know for sure that the feature is available; old
|
|
versions of PTRACE_SETOPTIONS ignored unknown options.
|
|
Therefore, we attach to the child process, use PTRACE_SETOPTIONS
|
|
to enable fork tracing, and let it fork. If the process exits,
|
|
we assume that we can't use PTRACE_O_TRACEFORK; if we get the
|
|
fork notification, and we can extract the new child's PID, then
|
|
we assume that we can.
|
|
|
|
We do not explicitly check for vfork tracing here. It is
|
|
assumed that vfork tracing is available whenever fork tracing
|
|
is available. */
|
|
ret = ptrace (PTRACE_CONT, child_pid, (PTRACE_TYPE_ARG3) 0,
|
|
(PTRACE_TYPE_ARG4) 0);
|
|
if (ret != 0)
|
|
warning (_("linux_test_for_tracefork: failed to resume child"));
|
|
|
|
ret = my_waitpid (child_pid, &status, 0);
|
|
|
|
/* Check if we received a fork event notification. */
|
|
if (ret == child_pid && WIFSTOPPED (status)
|
|
&& status >> 16 == PTRACE_EVENT_FORK)
|
|
{
|
|
/* We did receive a fork event notification. Make sure its PID
|
|
is reported. */
|
|
second_pid = 0;
|
|
ret = ptrace (PTRACE_GETEVENTMSG, child_pid, (PTRACE_TYPE_ARG3) 0,
|
|
(PTRACE_TYPE_ARG4) &second_pid);
|
|
if (ret == 0 && second_pid != 0)
|
|
{
|
|
int second_status;
|
|
|
|
/* We got the PID from the grandchild, which means fork
|
|
tracing is supported. */
|
|
#ifdef GDBSERVER
|
|
/* Do not enable all the options for now since gdbserver does not
|
|
properly support them. This restriction will be lifted when
|
|
gdbserver is augmented to support them. */
|
|
current_ptrace_options |= PTRACE_O_TRACECLONE;
|
|
#else
|
|
current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
|
|
| PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC;
|
|
|
|
/* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to
|
|
support read-only process state. */
|
|
#endif
|
|
|
|
/* Do some cleanup and kill the grandchild. */
|
|
my_waitpid (second_pid, &second_status, 0);
|
|
ret = ptrace (PTRACE_KILL, second_pid, (PTRACE_TYPE_ARG3) 0,
|
|
(PTRACE_TYPE_ARG4) 0);
|
|
if (ret != 0)
|
|
warning (_("linux_test_for_tracefork: "
|
|
"failed to kill second child"));
|
|
my_waitpid (second_pid, &status, 0);
|
|
}
|
|
}
|
|
else
|
|
warning (_("linux_test_for_tracefork: unexpected result from waitpid "
|
|
"(%d, status 0x%x)"), ret, status);
|
|
}
|
|
|
|
/* Enable reporting of all currently supported ptrace events. */
|
|
|
|
void
|
|
linux_enable_event_reporting (pid_t pid)
|
|
{
|
|
/* Check if we have initialized the ptrace features for this
|
|
target. If not, do it now. */
|
|
if (current_ptrace_options == -1)
|
|
linux_check_ptrace_features ();
|
|
|
|
/* Set the options. */
|
|
ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0,
|
|
(PTRACE_TYPE_ARG4) (uintptr_t) current_ptrace_options);
|
|
}
|
|
|
|
/* Returns non-zero if PTRACE_OPTIONS is contained within
|
|
CURRENT_PTRACE_OPTIONS, therefore supported. Returns 0
|
|
otherwise. */
|
|
|
|
static int
|
|
ptrace_supports_feature (int ptrace_options)
|
|
{
|
|
gdb_assert (current_ptrace_options >= 0);
|
|
|
|
return ((current_ptrace_options & ptrace_options) == ptrace_options);
|
|
}
|
|
|
|
/* Returns non-zero if PTRACE_EVENT_FORK is supported by ptrace,
|
|
0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is
|
|
PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK,
|
|
since they were all added to the kernel at the same time. */
|
|
|
|
int
|
|
linux_supports_tracefork (void)
|
|
{
|
|
return ptrace_supports_feature (PTRACE_O_TRACEFORK);
|
|
}
|
|
|
|
/* Returns non-zero if PTRACE_EVENT_CLONE is supported by ptrace,
|
|
0 otherwise. Note that if PTRACE_EVENT_CLONE is supported so is
|
|
PTRACE_EVENT_FORK, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK,
|
|
since they were all added to the kernel at the same time. */
|
|
|
|
int
|
|
linux_supports_traceclone (void)
|
|
{
|
|
return ptrace_supports_feature (PTRACE_O_TRACECLONE);
|
|
}
|
|
|
|
/* Returns non-zero if PTRACE_O_TRACEVFORKDONE is supported by
|
|
ptrace, 0 otherwise. */
|
|
|
|
int
|
|
linux_supports_tracevforkdone (void)
|
|
{
|
|
return ptrace_supports_feature (PTRACE_O_TRACEVFORKDONE);
|
|
}
|
|
|
|
/* Returns non-zero if PTRACE_O_TRACESYSGOOD is supported by ptrace,
|
|
0 otherwise. */
|
|
|
|
int
|
|
linux_supports_tracesysgood (void)
|
|
{
|
|
return ptrace_supports_feature (PTRACE_O_TRACESYSGOOD);
|
|
}
|
|
|
|
/* Display possible problems on this system. Display them only once per GDB
|
|
execution. */
|
|
|
|
void
|
|
linux_ptrace_init_warnings (void)
|
|
{
|
|
static int warned = 0;
|
|
|
|
if (warned)
|
|
return;
|
|
warned = 1;
|
|
|
|
linux_ptrace_test_ret_to_nx ();
|
|
}
|