/* Native debugging support for Intel x86 running DJGPP.
- Copyright (C) 1997-2013 Free Software Foundation, Inc.
+ Copyright (C) 1997-2014 Free Software Foundation, Inc.
Written by Robert Hoehne.
This file is part of GDB.
#include <fcntl.h>
-#include "i386-nat.h"
+#include "x86-nat.h"
#include "inferior.h"
+#include "infrun.h"
#include "gdbthread.h"
#include "gdb_wait.h"
#include "gdbcore.h"
#include "buildsym.h"
#include "i387-tdep.h"
#include "i386-tdep.h"
+#include "nat/x86-cpuid.h"
#include "value.h"
#include "regcache.h"
-#include "gdb_string.h"
#include "top.h"
#include "cli/cli-utils.h"
+#include "inf-child.h"
-#include <stdio.h> /* might be required for __DJGPP_MINOR__ */
-#include <stdlib.h>
#include <ctype.h>
-#include <errno.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <io.h>
#define SOME_PID 42
static int prog_has_started = 0;
-static void go32_open (char *name, int from_tty);
-static void go32_close (void);
-static void go32_attach (struct target_ops *ops, char *args, int from_tty);
-static void go32_detach (struct target_ops *ops, char *args, int from_tty);
-static void go32_resume (struct target_ops *ops,
- ptid_t ptid, int step,
- enum gdb_signal siggnal);
-static void go32_fetch_registers (struct target_ops *ops,
- struct regcache *, int regno);
-static void store_register (const struct regcache *, int regno);
-static void go32_store_registers (struct target_ops *ops,
- struct regcache *, int regno);
-static void go32_prepare_to_store (struct regcache *);
-static int go32_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len,
- int write,
- struct mem_attrib *attrib,
- struct target_ops *target);
-static void go32_files_info (struct target_ops *target);
-static void go32_kill_inferior (struct target_ops *ops);
-static void go32_create_inferior (struct target_ops *ops, char *exec_file,
- char *args, char **env, int from_tty);
static void go32_mourn_inferior (struct target_ops *ops);
-static int go32_can_run (void);
-
-static struct target_ops go32_ops;
-static void go32_terminal_init (void);
-static void go32_terminal_inferior (void);
-static void go32_terminal_ours (void);
#define r_ofs(x) (offsetof(TSS,x))
};
static void
-go32_open (char *name, int from_tty)
-{
- printf_unfiltered ("Done. Use the \"run\" command to run the program.\n");
-}
-
-static void
-go32_close (void)
-{
-}
-
-static void
-go32_attach (struct target_ops *ops, char *args, int from_tty)
+go32_attach (struct target_ops *ops, const char *args, int from_tty)
{
error (_("\
You cannot attach to a running program on this platform.\n\
Use the `run' command to run DJGPP programs."));
}
-static void
-go32_detach (struct target_ops *ops, char *args, int from_tty)
-{
-}
-
static int resume_is_step;
static int resume_signal = -1;
}
}
-static void
-go32_prepare_to_store (struct regcache *regcache)
-{
-}
+/* Const-correct version of DJGPP's write_child, which unfortunately
+ takes a non-const buffer pointer. */
static int
-go32_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len, int write,
- struct mem_attrib *attrib, struct target_ops *target)
+my_write_child (unsigned child_addr, const void *buf, unsigned len)
{
- if (write)
+ static void *buffer = NULL;
+ static unsigned buffer_len = 0;
+ int res;
+
+ if (buffer_len < len)
{
- if (write_child (memaddr, myaddr, len))
- {
- return 0;
- }
- else
- {
- return len;
- }
+ buffer = xrealloc (buffer, len);
+ buffer_len = len;
}
+
+ memcpy (buffer, buf, len);
+ res = write_child (child_addr, buffer, len);
+ return res;
+}
+
+/* Helper for go32_xfer_partial that handles memory transfers.
+ Arguments are like target_xfer_partial. */
+
+static enum target_xfer_status
+go32_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST memaddr, ULONGEST len, ULONGEST *xfered_len)
+{
+ int res;
+
+ if (writebuf != NULL)
+ res = my_write_child (memaddr, writebuf, len);
else
+ res = read_child (memaddr, readbuf, len);
+
+ if (res <= 0)
+ return TARGET_XFER_E_IO;
+
+ *xfered_len = res;
+ return TARGET_XFER_OK;
+}
+
+/* Target to_xfer_partial implementation. */
+
+static enum target_xfer_status
+go32_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len)
+{
+ switch (object)
{
- if (read_child (memaddr, myaddr, len))
- {
- return 0;
- }
- else
- {
- return len;
- }
+ case TARGET_OBJECT_MEMORY:
+ return go32_xfer_memory (readbuf, writebuf, offset, len, xfered_len);
+
+ default:
+ return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
+ readbuf, writebuf, offset, len,
+ xfered_len);
}
}
char **env_save = environ;
size_t cmdlen;
struct inferior *inf;
+ int result;
/* If no exec file handed to us, get it from the exec-file command -- with
a good, common error message if none is specified. */
environ = env;
- if (v2loadimage (exec_file, cmdline, start_state))
- {
- environ = env_save;
- printf_unfiltered ("Load failed for image %s\n", exec_file);
- exit (1);
- }
+ result = v2loadimage (exec_file, cmdline, start_state);
+
environ = env_save;
xfree (cmdline);
+ if (result != 0)
+ error (_("Load failed for image %s", exec_file);
+
edi_init (start_state);
#if __DJGPP_MINOR__ < 3
save_npx ();
inf = current_inferior ();
inferior_appeared (inf, SOME_PID);
- push_target (&go32_ops);
+ if (!target_is_pushed (ops))
+ push_target (ops);
add_thread_silent (inferior_ptid);
- clear_proceed_status ();
+ clear_proceed_status (0);
insert_breakpoints ();
prog_has_started = 1;
}
be nice if GDB itself would take care to remove all breakpoints
at all times, but it doesn't, probably under an assumption that
the OS cleans up when the debuggee exits. */
- i386_cleanup_dregs ();
+ x86_cleanup_dregs ();
ptid = inferior_ptid;
inferior_ptid = null_ptid;
delete_thread_silent (ptid);
prog_has_started = 0;
- unpush_target (ops);
generic_mourn_inferior ();
-}
-
-static int
-go32_can_run (void)
-{
- return 1;
+ inf_child_maybe_unpush_target (ops);
}
/* Hardware watchpoint support. */
static int terminal_is_ours = 1;
static void
-go32_terminal_init (void)
+go32_terminal_init (struct target_ops *self)
{
inf_mode_valid = 0; /* Reinitialize, in case they are restarting child. */
terminal_is_ours = 1;
}
static void
-go32_terminal_info (char *args, int from_tty)
+go32_terminal_info (struct target_ops *self, const char *args, int from_tty)
{
printf_unfiltered ("Inferior's terminal is in %s mode.\n",
!inf_mode_valid
}
static void
-go32_terminal_inferior (void)
+go32_terminal_inferior (struct target_ops *self)
{
/* Redirect standard handles as child wants them. */
errno = 0;
}
static void
-go32_terminal_ours (void)
+go32_terminal_ours (struct target_ops *self)
{
/* Switch to cooked mode on the gdb terminal and save the inferior
terminal mode to be restored when it is resumed. */
return normal_pid_to_str (ptid);
}
-static void
-init_go32_ops (void)
-{
- go32_ops.to_shortname = "djgpp";
- go32_ops.to_longname = "djgpp target process";
- go32_ops.to_doc =
- "Program loaded by djgpp, when gdb is used as an external debugger";
- go32_ops.to_open = go32_open;
- go32_ops.to_close = go32_close;
- go32_ops.to_attach = go32_attach;
- go32_ops.to_detach = go32_detach;
- go32_ops.to_resume = go32_resume;
- go32_ops.to_wait = go32_wait;
- go32_ops.to_fetch_registers = go32_fetch_registers;
- go32_ops.to_store_registers = go32_store_registers;
- go32_ops.to_prepare_to_store = go32_prepare_to_store;
- go32_ops.deprecated_xfer_memory = go32_xfer_memory;
- go32_ops.to_files_info = go32_files_info;
- go32_ops.to_insert_breakpoint = memory_insert_breakpoint;
- go32_ops.to_remove_breakpoint = memory_remove_breakpoint;
- go32_ops.to_terminal_init = go32_terminal_init;
- go32_ops.to_terminal_inferior = go32_terminal_inferior;
- go32_ops.to_terminal_ours_for_output = go32_terminal_ours;
- go32_ops.to_terminal_ours = go32_terminal_ours;
- go32_ops.to_terminal_info = go32_terminal_info;
- go32_ops.to_kill = go32_kill_inferior;
- go32_ops.to_create_inferior = go32_create_inferior;
- go32_ops.to_mourn_inferior = go32_mourn_inferior;
- go32_ops.to_can_run = go32_can_run;
- go32_ops.to_thread_alive = go32_thread_alive;
- go32_ops.to_pid_to_str = go32_pid_to_str;
- go32_ops.to_stratum = process_stratum;
- go32_ops.to_has_all_memory = default_child_has_all_memory;
- go32_ops.to_has_memory = default_child_has_memory;
- go32_ops.to_has_stack = default_child_has_stack;
- go32_ops.to_has_registers = default_child_has_registers;
- go32_ops.to_has_execution = default_child_has_execution;
-
- i386_use_watchpoints (&go32_ops);
-
-
- i386_dr_low.set_control = go32_set_dr7;
- i386_dr_low.set_addr = go32_set_dr;
- i386_dr_low.get_status = go32_get_dr6;
- i386_dr_low.get_control = go32_get_dr7;
- i386_dr_low.get_addr = go32_get_dr;
- i386_set_debug_register_length (4);
-
- go32_ops.to_magic = OPS_MAGIC;
-
- /* Initialize child's cwd as empty to be initialized when starting
- the child. */
- *child_cwd = 0;
-
- /* Initialize child's command line storage. */
- if (redir_debug_init (&child_cmd) == -1)
- internal_error (__FILE__, __LINE__,
- _("Cannot allocate redirection storage: "
- "not enough memory.\n"));
+/* Create a go32 target. */
- /* We are always processing GCC-compiled programs. */
- processing_gcc_compilation = 2;
-
- /* Override the default name of the GDB init file. */
- strcpy (gdbinit, "gdb.ini");
+static struct target_ops *
+go32_target (void)
+{
+ struct target_ops *t = inf_child_target ();
+
+ t->to_attach = go32_attach;
+ t->to_resume = go32_resume;
+ t->to_wait = go32_wait;
+ t->to_fetch_registers = go32_fetch_registers;
+ t->to_store_registers = go32_store_registers;
+ t->to_xfer_partial = go32_xfer_partial;
+ t->to_files_info = go32_files_info;
+ t->to_terminal_init = go32_terminal_init;
+ t->to_terminal_inferior = go32_terminal_inferior;
+ t->to_terminal_ours_for_output = go32_terminal_ours;
+ t->to_terminal_ours = go32_terminal_ours;
+ t->to_terminal_info = go32_terminal_info;
+ t->to_kill = go32_kill_inferior;
+ t->to_create_inferior = go32_create_inferior;
+ t->to_mourn_inferior = go32_mourn_inferior;
+ t->to_thread_alive = go32_thread_alive;
+ t->to_pid_to_str = go32_pid_to_str;
+
+ return t;
}
/* Return the current DOS codepage number. */
else if (u.machine[0] == 'i' && u.machine[1] > 4)
{
/* CPUID with EAX = 0 returns the Vendor ID. */
+#if 0
+ /* Ideally we would use x86_cpuid(), but it needs someone to run
+ native tests first to make sure things actually work. They should.
+ http://sourceware.org/ml/gdb-patches/2013-05/msg00164.html */
+ unsigned int eax, ebx, ecx, edx;
+
+ if (x86_cpuid (0, &eax, &ebx, &ecx, &edx))
+ {
+ cpuid_max = eax;
+ memcpy (&vendor[0], &ebx, 4);
+ memcpy (&vendor[4], &ecx, 4);
+ memcpy (&vendor[8], &edx, 4);
+ cpuid_vendor[12] = '\0';
+ }
+#else
__asm__ __volatile__ ("xorl %%ebx, %%ebx;"
"xorl %%ecx, %%ecx;"
"xorl %%edx, %%edx;"
:
: "%eax", "%ebx", "%ecx", "%edx");
cpuid_vendor[12] = '\0';
+#endif
}
printf_filtered ("CPU Type.......................%s", u.machine);
int amd_p = strcmp (cpuid_vendor, "AuthenticAMD") == 0;
unsigned cpu_family, cpu_model;
+#if 0
+ /* See comment above about cpuid usage. */
+ x86_cpuid (1, &cpuid_eax, &cpuid_ebx, NULL, &cpuid_edx);
+#else
__asm__ __volatile__ ("movl $1, %%eax;"
"cpuid;"
: "=a" (cpuid_eax),
"=d" (cpuid_edx)
:
: "%ecx");
+#endif
brand_idx = cpuid_ebx & 0xff;
cpu_family = (cpuid_eax >> 8) & 0xf;
cpu_model = (cpuid_eax >> 4) & 0xf;
void
_initialize_go32_nat (void)
{
- init_go32_ops ();
- add_target (&go32_ops);
+ struct target_ops *t = go32_target ();
+
+ x86_dr_low.set_control = go32_set_dr7;
+ x86_dr_low.set_addr = go32_set_dr;
+ x86_dr_low.get_status = go32_get_dr6;
+ x86_dr_low.get_control = go32_get_dr7;
+ x86_dr_low.get_addr = go32_get_dr;
+ x86_set_debug_register_length (4);
+
+ x86_use_watchpoints (t);
+ add_target (t);
+
+ /* Initialize child's cwd as empty to be initialized when starting
+ the child. */
+ *child_cwd = 0;
+
+ /* Initialize child's command line storage. */
+ if (redir_debug_init (&child_cmd) == -1)
+ internal_error (__FILE__, __LINE__,
+ _("Cannot allocate redirection storage: "
+ "not enough memory.\n"));
+
+ /* We are always processing GCC-compiled programs. */
+ processing_gcc_compilation = 2;
add_prefix_cmd ("dos", class_info, go32_info_dos_command, _("\
Print information specific to DJGPP (aka MS-DOS) debugging."),