123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- /* Native-dependent code for GNU/Linux x86 (i386 and x86-64).
- Copyright (C) 1999-2022 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/>. */
- #include "defs.h"
- #include "inferior.h"
- #include "elf/common.h"
- #include "gdb_proc_service.h"
- #include "nat/gdb_ptrace.h"
- #include <sys/user.h>
- #include <sys/procfs.h>
- #include <sys/uio.h>
- #include "x86-nat.h"
- #ifndef __x86_64__
- #include "i386-linux-nat.h"
- #endif
- #include "x86-linux-nat.h"
- #include "i386-linux-tdep.h"
- #ifdef __x86_64__
- #include "amd64-linux-tdep.h"
- #endif
- #include "gdbsupport/x86-xstate.h"
- #include "nat/linux-btrace.h"
- #include "nat/linux-nat.h"
- #include "nat/x86-linux.h"
- #include "nat/x86-linux-dregs.h"
- #include "nat/linux-ptrace.h"
- /* linux_nat_target::low_new_fork implementation. */
- void
- x86_linux_nat_target::low_new_fork (struct lwp_info *parent, pid_t child_pid)
- {
- pid_t parent_pid;
- struct x86_debug_reg_state *parent_state;
- struct x86_debug_reg_state *child_state;
- /* NULL means no watchpoint has ever been set in the parent. In
- that case, there's nothing to do. */
- if (parent->arch_private == NULL)
- return;
- /* Linux kernel before 2.6.33 commit
- 72f674d203cd230426437cdcf7dd6f681dad8b0d
- will inherit hardware debug registers from parent
- on fork/vfork/clone. Newer Linux kernels create such tasks with
- zeroed debug registers.
- GDB core assumes the child inherits the watchpoints/hw
- breakpoints of the parent, and will remove them all from the
- forked off process. Copy the debug registers mirrors into the
- new process so that all breakpoints and watchpoints can be
- removed together. The debug registers mirror will become zeroed
- in the end before detaching the forked off process, thus making
- this compatible with older Linux kernels too. */
- parent_pid = parent->ptid.pid ();
- parent_state = x86_debug_reg_state (parent_pid);
- child_state = x86_debug_reg_state (child_pid);
- *child_state = *parent_state;
- }
- x86_linux_nat_target::~x86_linux_nat_target ()
- {
- }
- /* Implement the virtual inf_ptrace_target::post_startup_inferior method. */
- void
- x86_linux_nat_target::post_startup_inferior (ptid_t ptid)
- {
- x86_cleanup_dregs ();
- linux_nat_target::post_startup_inferior (ptid);
- }
- #ifdef __x86_64__
- /* Value of CS segment register:
- 64bit process: 0x33
- 32bit process: 0x23 */
- #define AMD64_LINUX_USER64_CS 0x33
- /* Value of DS segment register:
- LP64 process: 0x0
- X32 process: 0x2b */
- #define AMD64_LINUX_X32_DS 0x2b
- #endif
- /* Get Linux/x86 target description from running target. */
- const struct target_desc *
- x86_linux_nat_target::read_description ()
- {
- int tid;
- int is_64bit = 0;
- #ifdef __x86_64__
- int is_x32;
- #endif
- static uint64_t xcr0;
- uint64_t xcr0_features_bits;
- tid = inferior_ptid.pid ();
- #ifdef __x86_64__
- {
- unsigned long cs;
- unsigned long ds;
- /* Get CS register. */
- errno = 0;
- cs = ptrace (PTRACE_PEEKUSER, tid,
- offsetof (struct user_regs_struct, cs), 0);
- if (errno != 0)
- perror_with_name (_("Couldn't get CS register"));
- is_64bit = cs == AMD64_LINUX_USER64_CS;
- /* Get DS register. */
- errno = 0;
- ds = ptrace (PTRACE_PEEKUSER, tid,
- offsetof (struct user_regs_struct, ds), 0);
- if (errno != 0)
- perror_with_name (_("Couldn't get DS register"));
- is_x32 = ds == AMD64_LINUX_X32_DS;
- if (sizeof (void *) == 4 && is_64bit && !is_x32)
- error (_("Can't debug 64-bit process with 32-bit GDB"));
- }
- #elif HAVE_PTRACE_GETFPXREGS
- if (have_ptrace_getfpxregs == -1)
- {
- elf_fpxregset_t fpxregs;
- if (ptrace (PTRACE_GETFPXREGS, tid, 0, (int) &fpxregs) < 0)
- {
- have_ptrace_getfpxregs = 0;
- have_ptrace_getregset = TRIBOOL_FALSE;
- return i386_linux_read_description (X86_XSTATE_X87_MASK);
- }
- }
- #endif
- if (have_ptrace_getregset == TRIBOOL_UNKNOWN)
- {
- uint64_t xstateregs[(X86_XSTATE_SSE_SIZE / sizeof (uint64_t))];
- struct iovec iov;
- iov.iov_base = xstateregs;
- iov.iov_len = sizeof (xstateregs);
- /* Check if PTRACE_GETREGSET works. */
- if (ptrace (PTRACE_GETREGSET, tid,
- (unsigned int) NT_X86_XSTATE, &iov) < 0)
- have_ptrace_getregset = TRIBOOL_FALSE;
- else
- {
- have_ptrace_getregset = TRIBOOL_TRUE;
- /* Get XCR0 from XSAVE extended state. */
- xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET
- / sizeof (uint64_t))];
- }
- }
- /* Check the native XCR0 only if PTRACE_GETREGSET is available. If
- PTRACE_GETREGSET is not available then set xcr0_features_bits to
- zero so that the "no-features" descriptions are returned by the
- switches below. */
- if (have_ptrace_getregset == TRIBOOL_TRUE)
- xcr0_features_bits = xcr0 & X86_XSTATE_ALL_MASK;
- else
- xcr0_features_bits = 0;
- if (is_64bit)
- {
- #ifdef __x86_64__
- return amd64_linux_read_description (xcr0_features_bits, is_x32);
- #endif
- }
- else
- {
- const struct target_desc * tdesc
- = i386_linux_read_description (xcr0_features_bits);
- if (tdesc == NULL)
- tdesc = i386_linux_read_description (X86_XSTATE_SSE_MASK);
- return tdesc;
- }
- gdb_assert_not_reached ("failed to return tdesc");
- }
- /* Enable branch tracing. */
- struct btrace_target_info *
- x86_linux_nat_target::enable_btrace (thread_info *tp,
- const struct btrace_config *conf)
- {
- struct btrace_target_info *tinfo = nullptr;
- ptid_t ptid = tp->ptid;
- try
- {
- tinfo = linux_enable_btrace (ptid, conf);
- }
- catch (const gdb_exception_error &exception)
- {
- error (_("Could not enable branch tracing for %s: %s"),
- target_pid_to_str (ptid).c_str (), exception.what ());
- }
- return tinfo;
- }
- /* Disable branch tracing. */
- void
- x86_linux_nat_target::disable_btrace (struct btrace_target_info *tinfo)
- {
- enum btrace_error errcode = linux_disable_btrace (tinfo);
- if (errcode != BTRACE_ERR_NONE)
- error (_("Could not disable branch tracing."));
- }
- /* Teardown branch tracing. */
- void
- x86_linux_nat_target::teardown_btrace (struct btrace_target_info *tinfo)
- {
- /* Ignore errors. */
- linux_disable_btrace (tinfo);
- }
- enum btrace_error
- x86_linux_nat_target::read_btrace (struct btrace_data *data,
- struct btrace_target_info *btinfo,
- enum btrace_read_type type)
- {
- return linux_read_btrace (data, btinfo, type);
- }
- /* See to_btrace_conf in target.h. */
- const struct btrace_config *
- x86_linux_nat_target::btrace_conf (const struct btrace_target_info *btinfo)
- {
- return linux_btrace_conf (btinfo);
- }
- /* Helper for ps_get_thread_area. Sets BASE_ADDR to a pointer to
- the thread local storage (or its descriptor) and returns PS_OK
- on success. Returns PS_ERR on failure. */
- ps_err_e
- x86_linux_get_thread_area (pid_t pid, void *addr, unsigned int *base_addr)
- {
- /* NOTE: cagney/2003-08-26: The definition of this buffer is found
- in the kernel header <asm-i386/ldt.h>. It, after padding, is 4 x
- 4 byte integers in size: `entry_number', `base_addr', `limit',
- and a bunch of status bits.
- The values returned by this ptrace call should be part of the
- regcache buffer, and ps_get_thread_area should channel its
- request through the regcache. That way remote targets could
- provide the value using the remote protocol and not this direct
- call.
- Is this function needed? I'm guessing that the `base' is the
- address of a descriptor that libthread_db uses to find the
- thread local address base that GDB needs. Perhaps that
- descriptor is defined by the ABI. Anyway, given that
- libthread_db calls this function without prompting (gdb
- requesting tls base) I guess it needs info in there anyway. */
- unsigned int desc[4];
- /* This code assumes that "int" is 32 bits and that
- GET_THREAD_AREA returns no more than 4 int values. */
- gdb_assert (sizeof (int) == 4);
- #ifndef PTRACE_GET_THREAD_AREA
- #define PTRACE_GET_THREAD_AREA 25
- #endif
- if (ptrace (PTRACE_GET_THREAD_AREA, pid, addr, &desc) < 0)
- return PS_ERR;
- *base_addr = desc[1];
- return PS_OK;
- }
- void _initialize_x86_linux_nat ();
- void
- _initialize_x86_linux_nat ()
- {
- /* Initialize the debug register function vectors. */
- x86_dr_low.set_control = x86_linux_dr_set_control;
- x86_dr_low.set_addr = x86_linux_dr_set_addr;
- x86_dr_low.get_addr = x86_linux_dr_get_addr;
- x86_dr_low.get_status = x86_linux_dr_get_status;
- x86_dr_low.get_control = x86_linux_dr_get_control;
- x86_set_debug_register_length (sizeof (void *));
- }
|