/* IBM RS/6000 native-dependent code for GDB, the GNU debugger.
- Copyright (C) 1986-2013 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcore.h"
#include "symfile.h"
#include "objfiles.h"
-#include "libbfd.h" /* For bfd_default_set_arch_mach (FIXME) */
#include "bfd.h"
-#include "exceptions.h"
#include "gdb-stabs.h"
#include "regcache.h"
#include "arch-utils.h"
#include "inf-ptrace.h"
#include "ppc-tdep.h"
#include "rs6000-tdep.h"
+#include "rs6000-aix-tdep.h"
#include "exec.h"
-#include "observer.h"
+#include "observable.h"
#include "xcoffread.h"
#include <sys/ptrace.h>
#include <sys/reg.h>
-#include <sys/param.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <fcntl.h>
-#include <errno.h>
#include <a.out.h>
#include <sys/file.h>
-#include "gdb_stat.h"
+#include <sys/stat.h>
#include "gdb_bfd.h"
#include <sys/core.h>
#define __LDINFO_PTRACE32__ /* for __ld_info32 */
#define __LDINFO_PTRACE64__ /* for __ld_info64 */
#include <sys/ldr.h>
#include <sys/systemcfg.h>
-#include "xml-utils.h"
/* On AIX4.3+, sys/ldr.h provides different versions of struct ld_info for
debugging 32-bit and 64-bit processes. Define a typedef and macros for
/* In 32-bit compilation mode (which is the only mode from which ptrace()
works on 4.3), __ld_info32 is #defined as equivalent to ld_info. */
-#ifdef __ld_info32
+#if defined (__ld_info32) || defined (__ld_info64)
# define ARCH3264
#endif
# define ARCH64() (register_size (target_gdbarch (), 0) == 8)
#endif
-/* Union of 32-bit and 64-bit versions of ld_info. */
+class rs6000_nat_target final : public inf_ptrace_target
+{
+public:
+ void fetch_registers (struct regcache *, int) override;
+ void store_registers (struct regcache *, int) override;
-typedef union {
-#ifndef ARCH3264
- struct ld_info l32;
- struct ld_info l64;
-#else
- struct __ld_info32 l32;
- struct __ld_info64 l64;
-#endif
-} LdInfo;
+ enum target_xfer_status xfer_partial (enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len) override;
-/* If compiling with 32-bit and 64-bit debugging capability (e.g. AIX 4.x),
- declare and initialize a variable named VAR suitable for use as the arch64
- parameter to the various LDI_*() macros. */
+ void create_inferior (const char *, const std::string &,
+ char **, int) override;
-#ifndef ARCH3264
-# define ARCH64_DECL(var)
-#else
-# define ARCH64_DECL(var) int var = ARCH64 ()
-#endif
-
-/* Return LDI's FIELD for a 64-bit process if ARCH64 and for a 32-bit process
- otherwise. This technique only works for FIELDs with the same data type in
- 32-bit and 64-bit versions of ld_info. */
+ ptid_t wait (ptid_t, struct target_waitstatus *, int) override;
-#ifndef ARCH3264
-# define LDI_FIELD(ldi, arch64, field) (ldi)->l32.ldinfo_##field
-#else
-# define LDI_FIELD(ldi, arch64, field) \
- (arch64 ? (ldi)->l64.ldinfo_##field : (ldi)->l32.ldinfo_##field)
-#endif
+private:
+ enum target_xfer_status
+ xfer_shared_libraries (enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len);
+};
-/* Return various LDI fields for a 64-bit process if ARCH64 and for a 32-bit
- process otherwise. */
-
-#define LDI_NEXT(ldi, arch64) LDI_FIELD(ldi, arch64, next)
-#define LDI_FD(ldi, arch64) LDI_FIELD(ldi, arch64, fd)
-#define LDI_FILENAME(ldi, arch64) LDI_FIELD(ldi, arch64, filename)
-
-static void exec_one_dummy_insn (struct regcache *);
-
-static LONGEST rs6000_xfer_shared_libraries
- (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf,
- ULONGEST offset, LONGEST len);
+static rs6000_nat_target the_rs6000_nat_target;
/* Given REGNO, a gdb register number, return the corresponding
number suitable for use as a ptrace() parameter. Return -1 if
static int
rs6000_ptrace32 (int req, int id, int *addr, int data, int *buf)
{
+#ifdef HAVE_PTRACE64
+ int ret = ptrace64 (req, id, (uintptr_t) addr, data, buf);
+#else
int ret = ptrace (req, id, (int *)addr, data, buf);
+#endif
#if 0
printf ("rs6000_ptrace32 (%d, %d, 0x%x, %08x, 0x%x) = 0x%x\n",
req, id, (unsigned int)addr, data, (unsigned int)buf, ret);
rs6000_ptrace64 (int req, int id, long long addr, int data, void *buf)
{
#ifdef ARCH3264
- int ret = ptracex (req, id, addr, data, buf);
+# ifdef HAVE_PTRACE64
+ int ret = ptrace64 (req, id, addr, data, (PTRACE_TYPE_ARG5) buf);
+# else
+ int ret = ptracex (req, id, addr, data, (PTRACE_TYPE_ARG5) buf);
+# endif
#else
int ret = 0;
#endif
static void
fetch_register (struct regcache *regcache, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- int addr[MAX_REGISTER_SIZE];
+ struct gdbarch *gdbarch = regcache->arch ();
+ int addr[PPC_MAX_REGISTER_SIZE];
int nr, isfloat;
+ pid_t pid = regcache->ptid ().pid ();
/* Retrieved values may be -1, so infer errors from errno. */
errno = 0;
/* Floating-point registers. */
if (isfloat)
- rs6000_ptrace32 (PT_READ_FPR, PIDGET (inferior_ptid), addr, nr, 0);
+ rs6000_ptrace32 (PT_READ_FPR, pid, addr, nr, 0);
/* Bogus register number. */
else if (nr < 0)
else
{
if (!ARCH64 ())
- *addr = rs6000_ptrace32 (PT_READ_GPR, PIDGET (inferior_ptid),
- (int *) nr, 0, 0);
+ *addr = rs6000_ptrace32 (PT_READ_GPR, pid, (int *) nr, 0, 0);
else
{
/* PT_READ_GPR requires the buffer parameter to point to long long,
even if the register is really only 32 bits. */
long long buf;
- rs6000_ptrace64 (PT_READ_GPR, PIDGET (inferior_ptid), nr, 0, &buf);
+ rs6000_ptrace64 (PT_READ_GPR, pid, nr, 0, &buf);
if (register_size (gdbarch, regno) == 8)
memcpy (addr, &buf, 8);
else
}
if (!errno)
- regcache_raw_supply (regcache, regno, (char *) addr);
+ regcache->raw_supply (regno, (char *) addr);
else
{
#if 0
static void
store_register (struct regcache *regcache, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- int addr[MAX_REGISTER_SIZE];
+ struct gdbarch *gdbarch = regcache->arch ();
+ int addr[PPC_MAX_REGISTER_SIZE];
int nr, isfloat;
+ pid_t pid = regcache->ptid ().pid ();
/* Fetch the register's value from the register cache. */
- regcache_raw_collect (regcache, regno, addr);
+ regcache->raw_collect (regno, addr);
/* -1 can be a successful return value, so infer errors from errno. */
errno = 0;
/* Floating-point registers. */
if (isfloat)
- rs6000_ptrace32 (PT_WRITE_FPR, PIDGET (inferior_ptid), addr, nr, 0);
+ rs6000_ptrace32 (PT_WRITE_FPR, pid, addr, nr, 0);
/* Bogus register number. */
else if (nr < 0)
/* Fixed-point registers. */
else
{
- if (regno == gdbarch_sp_regnum (gdbarch))
- /* Execute one dummy instruction (which is a breakpoint) in inferior
- process to give kernel a chance to do internal housekeeping.
- Otherwise the following ptrace(2) calls will mess up user stack
- since kernel will get confused about the bottom of the stack
- (%sp). */
- exec_one_dummy_insn (regcache);
-
/* The PT_WRITE_GPR operation is rather odd. For 32-bit inferiors,
the register's value is passed by value, but for 64-bit inferiors,
the address of a buffer containing the value is passed. */
if (!ARCH64 ())
- rs6000_ptrace32 (PT_WRITE_GPR, PIDGET (inferior_ptid),
- (int *) nr, *addr, 0);
+ rs6000_ptrace32 (PT_WRITE_GPR, pid, (int *) nr, *addr, 0);
else
{
/* PT_WRITE_GPR requires the buffer parameter to point to an 8-byte
memcpy (&buf, addr, 8);
else
buf = *addr;
- rs6000_ptrace64 (PT_WRITE_GPR, PIDGET (inferior_ptid), nr, 0, &buf);
+ rs6000_ptrace64 (PT_WRITE_GPR, pid, nr, 0, &buf);
}
}
/* Read from the inferior all registers if REGNO == -1 and just register
REGNO otherwise. */
-static void
-rs6000_fetch_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
+void
+rs6000_nat_target::fetch_registers (struct regcache *regcache, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
if (regno != -1)
fetch_register (regcache, regno);
If REGNO is -1, do this for all registers.
Otherwise, REGNO specifies which register (so we can save time). */
-static void
-rs6000_store_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
+void
+rs6000_nat_target::store_registers (struct regcache *regcache, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
if (regno != -1)
store_register (regcache, regno);
}
}
+/* Implement the to_xfer_partial target_ops method. */
-/* Attempt a transfer all LEN bytes starting at OFFSET between the
- inferior's OBJECT:ANNEX space and GDB's READBUF/WRITEBUF buffer.
- Return the number of bytes actually transferred. */
-
-static LONGEST
-rs6000_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf,
- ULONGEST offset, LONGEST len)
+enum target_xfer_status
+rs6000_nat_target::xfer_partial (enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len)
{
- pid_t pid = ptid_get_pid (inferior_ptid);
+ pid_t pid = inferior_ptid.pid ();
int arch64 = ARCH64 ();
switch (object)
{
case TARGET_OBJECT_LIBRARIES_AIX:
- return rs6000_xfer_shared_libraries (ops, object, annex,
- readbuf, writebuf,
- offset, len);
+ return xfer_shared_libraries (object, annex,
+ readbuf, writebuf,
+ offset, len, xfered_len);
case TARGET_OBJECT_MEMORY:
{
union
(int *) (uintptr_t) rounded_offset,
buffer.word, NULL);
if (errno)
- return 0;
+ return TARGET_XFER_EOF;
}
if (readbuf)
(int *)(uintptr_t)rounded_offset,
0, NULL);
if (errno)
- return 0;
+ return TARGET_XFER_EOF;
/* Copy appropriate bytes out of the buffer. */
memcpy (readbuf, buffer.byte + (offset - rounded_offset),
partial_len);
}
- return partial_len;
+ *xfered_len = (ULONGEST) partial_len;
+ return TARGET_XFER_OK;
}
default:
- return -1;
+ return TARGET_XFER_E_IO;
}
}
process ID of the child, or MINUS_ONE_PTID in case of error; store
the status in *OURSTATUS. */
-static ptid_t
-rs6000_wait (struct target_ops *ops,
- ptid_t ptid, struct target_waitstatus *ourstatus, int options)
+ptid_t
+rs6000_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+ int options)
{
pid_t pid;
int status, save_errno;
do
{
- pid = waitpid (ptid_get_pid (ptid), &status, 0);
+ pid = waitpid (ptid.pid (), &status, 0);
save_errno = errno;
}
while (pid == -1 && errno == EINTR);
}
/* Ignore terminated detached child processes. */
- if (!WIFSTOPPED (status) && pid != ptid_get_pid (inferior_ptid))
+ if (!WIFSTOPPED (status) && pid != inferior_ptid.pid ())
pid = -1;
}
while (pid == -1);
else
store_waitstatus (ourstatus, status);
- return pid_to_ptid (pid);
-}
-
-/* Execute one dummy breakpoint instruction. This way we give the kernel
- a chance to do some housekeeping and update inferior's internal data,
- including u_area. */
-
-static void
-exec_one_dummy_insn (struct regcache *regcache)
-{
-#define DUMMY_INSN_ADDR AIX_TEXT_SEGMENT_BASE+0x200
-
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- int ret, status, pid;
- CORE_ADDR prev_pc;
- void *bp;
-
- /* We plant one dummy breakpoint into DUMMY_INSN_ADDR address. We
- assume that this address will never be executed again by the real
- code. */
-
- bp = deprecated_insert_raw_breakpoint (gdbarch, NULL, DUMMY_INSN_ADDR);
-
- /* You might think this could be done with a single ptrace call, and
- you'd be correct for just about every platform I've ever worked
- on. However, rs6000-ibm-aix4.1.3 seems to have screwed this up --
- the inferior never hits the breakpoint (it's also worth noting
- powerpc-ibm-aix4.1.3 works correctly). */
- prev_pc = regcache_read_pc (regcache);
- regcache_write_pc (regcache, DUMMY_INSN_ADDR);
- if (ARCH64 ())
- ret = rs6000_ptrace64 (PT_CONTINUE, PIDGET (inferior_ptid), 1, 0, NULL);
- else
- ret = rs6000_ptrace32 (PT_CONTINUE, PIDGET (inferior_ptid),
- (int *) 1, 0, NULL);
-
- if (ret != 0)
- perror (_("pt_continue"));
-
- do
- {
- pid = waitpid (PIDGET (inferior_ptid), &status, 0);
- }
- while (pid != PIDGET (inferior_ptid));
-
- regcache_write_pc (regcache, prev_pc);
- deprecated_remove_raw_breakpoint (gdbarch, bp);
+ return ptid_t (pid);
}
\f
/* Set the current architecture from the host running GDB. Called when
starting a child process. */
-static void (*super_create_inferior) (struct target_ops *,char *exec_file,
- char *allargs, char **env, int from_tty);
-static void
-rs6000_create_inferior (struct target_ops * ops, char *exec_file,
- char *allargs, char **env, int from_tty)
+void
+rs6000_nat_target::create_inferior (const char *exec_file,
+ const std::string &allargs,
+ char **env, int from_tty)
{
enum bfd_architecture arch;
unsigned long mach;
bfd abfd;
struct gdbarch_info info;
- super_create_inferior (ops, exec_file, allargs, env, from_tty);
+ inf_ptrace_target::create_inferior (exec_file, allargs, env, from_tty);
if (__power_rs ())
{
/* Shared Object support. */
/* Return the LdInfo data for the given process. Raises an error
- if the data could not be obtained.
-
- The returned value must be deallocated after use. */
+ if the data could not be obtained. */
-static LdInfo *
+static gdb::byte_vector
rs6000_ptrace_ldinfo (ptid_t ptid)
{
- const int pid = ptid_get_pid (ptid);
- int ldi_size = 1024;
- LdInfo *ldi = xmalloc (ldi_size);
+ const int pid = ptid.pid ();
+ gdb::byte_vector ldi (1024);
int rc = -1;
while (1)
{
if (ARCH64 ())
- rc = rs6000_ptrace64 (PT_LDINFO, pid, (unsigned long) ldi, ldi_size,
- NULL);
+ rc = rs6000_ptrace64 (PT_LDINFO, pid, (unsigned long) ldi.data (),
+ ldi.size (), NULL);
else
- rc = rs6000_ptrace32 (PT_LDINFO, pid, (int *) ldi, ldi_size, NULL);
+ rc = rs6000_ptrace32 (PT_LDINFO, pid, (int *) ldi.data (),
+ ldi.size (), NULL);
if (rc != -1)
break; /* Success, we got the entire ld_info data. */
perror_with_name (_("ptrace ldinfo"));
/* ldi is not big enough. Double it and try again. */
- ldi_size *= 2;
- ldi = xrealloc (ldi, ldi_size);
+ ldi.resize (ldi.size () * 2);
}
return ldi;
}
-/* Assuming ABFD refers to a core file, return the LdInfo data
- stored in that core file. Raises an error if the data could
- not be read or extracted.
-
- The returned value much be deallocated after use. */
-
-static LdInfo *
-rs6000_core_ldinfo (bfd *abfd)
-{
- struct bfd_section *ldinfo_sec;
- int ldinfo_size;
- gdb_byte *ldinfo_buf;
- struct cleanup *cleanup;
-
- ldinfo_sec = bfd_get_section_by_name (abfd, ".ldinfo");
- if (ldinfo_sec == NULL)
- error (_("cannot find .ldinfo section from core file: %s"),
- bfd_errmsg (bfd_get_error ()));
- ldinfo_size = bfd_get_section_size (ldinfo_sec);
-
- ldinfo_buf = xmalloc (ldinfo_size);
- cleanup = make_cleanup (xfree, ldinfo_buf);
-
- if (! bfd_get_section_contents (abfd, ldinfo_sec,
- ldinfo_buf, 0, ldinfo_size))
- error (_("unable to read .ldinfo section from core file: %s"),
- bfd_errmsg (bfd_get_error ()));
-
- discard_cleanups (cleanup);
- return (LdInfo *) ldinfo_buf;
-}
-
-/* Append to OBJSTACK an XML string description of the shared library
- corresponding to LDI, following the TARGET_OBJECT_LIBRARIES_AIX
- format. */
-
-static void
-rs6000_xfer_shared_library (LdInfo *ldi, struct obstack *obstack)
-{
- const int arch64 = ARCH64 ();
- const char *archive_name = LDI_FILENAME (ldi, arch64);
- const char *member_name = archive_name + strlen (archive_name) + 1;
- CORE_ADDR text_addr, data_addr;
- ULONGEST text_size, data_size;
- char *p;
-
- if (arch64)
- {
- text_addr = ldi->l64.ldinfo_textorg;
- text_size = ldi->l64.ldinfo_textsize;
- data_addr = ldi->l64.ldinfo_dataorg;
- data_size = ldi->l64.ldinfo_datasize;
- }
- else
- {
- /* The text and data addresses are defined as pointers.
- To avoid sign-extending their value in the assignments
- below, we cast their value to unsigned long first. */
- text_addr = (unsigned long) ldi->l32.ldinfo_textorg;
- text_size = ldi->l32.ldinfo_textsize;
- data_addr = (unsigned long) ldi->l32.ldinfo_dataorg;
- data_size = ldi->l32.ldinfo_datasize;
- }
-
- obstack_grow_str (obstack, "<library name=\"");
- p = xml_escape_text (archive_name);
- obstack_grow_str (obstack, p);
- xfree (p);
- obstack_grow_str (obstack, "\"");
-
- if (member_name[0] != '\0')
- {
- obstack_grow_str (obstack, " member=\"");
- p = xml_escape_text (member_name);
- obstack_grow_str (obstack, p);
- xfree (p);
- obstack_grow_str (obstack, "\"");
- }
-
- obstack_grow_str (obstack, " text_addr=\"");
- obstack_grow_str (obstack, core_addr_to_string (text_addr));
- obstack_grow_str (obstack, "\"");
-
- obstack_grow_str (obstack, " text_size=\"");
- obstack_grow_str (obstack, pulongest (text_size));
- obstack_grow_str (obstack, "\"");
-
- obstack_grow_str (obstack, " data_addr=\"");
- obstack_grow_str (obstack, core_addr_to_string (data_addr));
- obstack_grow_str (obstack, "\"");
-
- obstack_grow_str (obstack, " data_size=\"");
- obstack_grow_str (obstack, pulongest (data_size));
- obstack_grow_str (obstack, "\"");
-
- obstack_grow_str (obstack, "></library>");
-}
-
/* Implement the to_xfer_partial target_ops method for
TARGET_OBJECT_LIBRARIES_AIX objects. */
-static LONGEST
-rs6000_xfer_shared_libraries
- (struct target_ops *ops, enum target_object object,
+enum target_xfer_status
+rs6000_nat_target::xfer_shared_libraries
+ (enum target_object object,
const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf,
- ULONGEST offset, LONGEST len)
+ ULONGEST offset, ULONGEST len, ULONGEST *xfered_len)
{
- const int arch64 = ARCH64 ();
- LdInfo *ldi_data;
- LdInfo *ldi;
- struct obstack obstack;
- const char *buf;
- LONGEST len_avail;
+ ULONGEST result;
- if (writebuf)
- return -1;
-
- /* Get the ldinfo raw data: If debugging a live process, we get it
- using ptrace. Otherwise, the info is stored in the .ldinfo
- section of the core file. */
-
- if (target_has_execution)
- ldi_data = rs6000_ptrace_ldinfo (inferior_ptid);
- else
- ldi_data = rs6000_core_ldinfo (core_bfd);
-
- /* Convert the raw data into an XML representation. */
-
- obstack_init (&obstack);
- obstack_grow_str (&obstack, "<library-list-aix version=\"1.0\">\n");
-
- ldi = ldi_data;
- while (1)
- {
- /* Close the fd. We cannot use it, because we cannot assume
- that the user of this descriptor will be in the same
- process. */
- close (LDI_FD (ldi, arch64));
+ /* This function assumes that it is being run with a live process.
+ Core files are handled via gdbarch. */
+ gdb_assert (target_has_execution);
- rs6000_xfer_shared_library (ldi, &obstack);
-
- if (!LDI_NEXT (ldi, arch64))
- break;
- ldi = (LdInfo *) ((char *) ldi + LDI_NEXT (ldi, arch64));
- }
-
- xfree (ldi_data);
+ if (writebuf)
+ return TARGET_XFER_E_IO;
- obstack_grow_str0 (&obstack, "</library-list-aix>\n");
+ gdb::byte_vector ldi_buf = rs6000_ptrace_ldinfo (inferior_ptid);
+ result = rs6000_aix_ld_info_to_xml (target_gdbarch (), ldi_buf.data (),
+ readbuf, offset, len, 1);
- buf = obstack_finish (&obstack);
- len_avail = strlen (buf);
- if (offset >= len_avail)
- len= 0;
+ if (result == 0)
+ return TARGET_XFER_EOF;
else
{
- if (len > len_avail - offset)
- len = len_avail - offset;
- memcpy (readbuf, buf + offset, len);
+ *xfered_len = result;
+ return TARGET_XFER_OK;
}
-
- obstack_free (&obstack, NULL);
- return len;
}
-void _initialize_rs6000_nat (void);
-
void
_initialize_rs6000_nat (void)
{
- struct target_ops *t;
-
- t = inf_ptrace_target ();
- t->to_fetch_registers = rs6000_fetch_inferior_registers;
- t->to_store_registers = rs6000_store_inferior_registers;
- t->to_xfer_partial = rs6000_xfer_partial;
-
- super_create_inferior = t->to_create_inferior;
- t->to_create_inferior = rs6000_create_inferior;
-
- t->to_wait = rs6000_wait;
-
- add_target (t);
+ add_inf_child_target (&the_rs6000_nat_target);
}