/* Native debugging support for Intel x86 running DJGPP.
- Copyright 1997, 1999 Free Software Foundation, Inc.
+ Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
Written by Robert Hoehne.
This file is part of GDB.
#include <fcntl.h>
#include "defs.h"
-#include "frame.h" /* required by inferior.h */
#include "inferior.h"
-#include "target.h"
-#include "wait.h"
+#include "gdb_wait.h"
#include "gdbcore.h"
#include "command.h"
#include "floatformat.h"
+#include "buildsym.h"
+#include "i387-nat.h"
+#include "value.h"
+#include "regcache.h"
+#include "gdb_string.h"
#include <stdio.h> /* required for __DJGPP_MINOR__ */
#include <stdlib.h>
-#include <string.h>
#include <errno.h>
+#include <unistd.h>
#include <io.h>
#include <dpmi.h>
#include <debug/v2load.h>
int redirected;
} cmdline_t;
-void redir_cmdline_delete (cmdline_t *ptr) {ptr->redirected = 0;}
-int redir_cmdline_parse (const char *args, cmdline_t *ptr)
+void
+redir_cmdline_delete (cmdline_t *ptr) {ptr->redirected = 0;}
+
+int
+redir_cmdline_parse (const char *args, cmdline_t *ptr)
{
return -1;
}
-int redir_to_child (cmdline_t *ptr)
+int
+redir_to_child (cmdline_t *ptr)
{
return 1;
}
-int redir_to_debugger (cmdline_t *ptr)
+int
+redir_to_debugger (cmdline_t *ptr)
{
return 1;
}
-int redir_debug_init (cmdline_t *ptr) { return 0; }
+int
+redir_debug_init (cmdline_t *ptr) { return 0; }
#endif /* __DJGPP_MINOR < 3 */
-extern void _initialize_go32_nat (void);
-
-struct env387
- {
- unsigned short control;
- unsigned short r0;
- unsigned short status;
- unsigned short r1;
- unsigned short tag;
- unsigned short r2;
- unsigned long eip;
- unsigned short code_seg;
- unsigned short opcode;
- unsigned long operand;
- unsigned short operand_seg;
- unsigned short r3;
- unsigned char regs[8][10];
- };
-
typedef enum { wp_insert, wp_remove, wp_count } wp_op;
/* This holds the current reference counts for each debug register. */
static int dr_ref_count[4];
-extern char **environ;
-
#define SOME_PID 42
static int prog_has_started = 0;
-static void print_387_status (unsigned short status, struct env387 *ep);
static void go32_open (char *name, int from_tty);
static void go32_close (int quitting);
static void go32_attach (char *args, int from_tty);
static void go32_store_registers (int regno);
static void go32_prepare_to_store (void);
static int go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
- int write, struct target_ops *target);
+ int write,
+ struct mem_attrib *attrib,
+ struct target_ops *target);
static void go32_files_info (struct target_ops *target);
static void go32_stop (void);
static void go32_kill_inferior (void);
static void go32_create_inferior (char *exec_file, char *args, char **env);
-static void cleanup_dregs (void);
static void go32_mourn_inferior (void);
static int go32_can_run (void);
-static void ignore (void);
-static void ignore2 (char *a, int b);
-static int go32_insert_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
- int len, int rw);
-static int go32_remove_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
- int len, int rw);
-static int go32_handle_nonaligned_watchpoint (wp_op what, CORE_ADDR waddr,
- CORE_ADDR addr, int len, int rw);
static struct target_ops go32_ops;
static void go32_terminal_init (void);
static void go32_terminal_inferior (void);
static void go32_terminal_ours (void);
-static void
-print_387_status (unsigned short status, struct env387 *ep)
-{
- int i;
- int bothstatus;
- int top;
- int fpreg;
-
- bothstatus = ((status != 0) && (ep->status != 0));
- if (status != 0)
- {
- if (bothstatus)
- printf_unfiltered ("u: ");
- print_387_status_word (status);
- }
-
- if (ep->status != 0)
- {
- if (bothstatus)
- printf_unfiltered ("e: ");
- print_387_status_word (ep->status);
- }
-
- print_387_control_word (ep->control & 0xffff);
- /* Other platforms say "last exception", but that's not true: the
- FPU stores the last non-control instruction there. */
- printf_unfiltered ("last FP instruction: ");
- /* The ORing with D800h restores the upper 5 bits of the opcode that
- are not stored by the FPU (since these bits are the same for all
- floating-point instructions). */
- printf_unfiltered ("opcode %s; ",
- local_hex_string (ep->opcode ? (ep->opcode|0xd800) : 0));
- printf_unfiltered ("pc %s:", local_hex_string (ep->code_seg));
- printf_unfiltered ("%s; ", local_hex_string (ep->eip));
- printf_unfiltered ("operand %s", local_hex_string (ep->operand_seg));
- printf_unfiltered (":%s\n", local_hex_string (ep->operand));
-
- top = (ep->status >> 11) & 7;
-
- printf_unfiltered ("regno tag msb lsb value\n");
- for (fpreg = 7; fpreg >= 0; fpreg--)
- {
- /* FNSAVE saves the FP registers in their logical TOP-relative
- order, beginning with ST(0). Since we need to print them in
- their physical order, we have to remap them. */
- int regno = fpreg - top;
- long double val;
-
- if (regno < 0)
- regno += 8;
-
- printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : " ", fpreg);
-
- switch ((ep->tag >> (fpreg * 2)) & 3)
- {
- case 0:
- printf_unfiltered ("valid ");
- break;
- case 1:
- printf_unfiltered ("zero ");
- break;
- case 2:
- /* All other versions of print_387_status use TRAP here, but I
- think this is misleading, since Intel manuals say SPECIAL. */
- printf_unfiltered ("special ");
- break;
- case 3:
- printf_unfiltered ("empty ");
- break;
- }
- for (i = 9; i >= 0; i--)
- printf_unfiltered ("%02x", ep->regs[regno][i]);
-
- REGISTER_CONVERT_TO_VIRTUAL (FP0_REGNUM+regno, builtin_type_long_double,
- &ep->regs[regno], &val);
-
- printf_unfiltered (" %.19LG\n", val);
- }
-}
-
-void
-i386_go32_float_info (void)
-{
- print_387_status (0, (struct env387 *) &npx);
-}
-
#define r_ofs(x) (offsetof(TSS,x))
static struct
}
regno_mapping[] =
{
- r_ofs (tss_eax), 4, /* normal registers, from a_tss */
- r_ofs (tss_ecx), 4,
- r_ofs (tss_edx), 4,
- r_ofs (tss_ebx), 4,
- r_ofs (tss_esp), 4,
- r_ofs (tss_ebp), 4,
- r_ofs (tss_esi), 4,
- r_ofs (tss_edi), 4,
- r_ofs (tss_eip), 4,
- r_ofs (tss_eflags), 4,
- r_ofs (tss_cs), 2,
- r_ofs (tss_ss), 2,
- r_ofs (tss_ds), 2,
- r_ofs (tss_es), 2,
- r_ofs (tss_fs), 2,
- r_ofs (tss_gs), 2,
- 0, 10, /* 8 FP registers, from npx.reg[] */
- 1, 10,
- 2, 10,
- 3, 10,
- 4, 10,
- 5, 10,
- 6, 10,
- 7, 10,
+ {r_ofs (tss_eax), 4}, /* normal registers, from a_tss */
+ {r_ofs (tss_ecx), 4},
+ {r_ofs (tss_edx), 4},
+ {r_ofs (tss_ebx), 4},
+ {r_ofs (tss_esp), 4},
+ {r_ofs (tss_ebp), 4},
+ {r_ofs (tss_esi), 4},
+ {r_ofs (tss_edi), 4},
+ {r_ofs (tss_eip), 4},
+ {r_ofs (tss_eflags), 4},
+ {r_ofs (tss_cs), 2},
+ {r_ofs (tss_ss), 2},
+ {r_ofs (tss_ds), 2},
+ {r_ofs (tss_es), 2},
+ {r_ofs (tss_fs), 2},
+ {r_ofs (tss_gs), 2},
+ {0, 10}, /* 8 FP registers, from npx.reg[] */
+ {1, 10},
+ {2, 10},
+ {3, 10},
+ {4, 10},
+ {5, 10},
+ {6, 10},
+ {7, 10},
/* The order of the next 7 registers must be consistent
- with their numbering in config/i386/tm-go32.h, which see. */
- 0, 2, /* control word, from npx */
- 4, 2, /* status word, from npx */
- 8, 2, /* tag word, from npx */
- 16, 2, /* last FP exception CS from npx */
- 24, 2, /* last FP exception operand selector from npx */
- 12, 4, /* last FP exception EIP from npx */
- 20, 4 /* last FP exception operand offset from npx */
+ with their numbering in config/i386/tm-i386.h, which see. */
+ {0, 2}, /* control word, from npx */
+ {4, 2}, /* status word, from npx */
+ {8, 2}, /* tag word, from npx */
+ {16, 2}, /* last FP exception CS from npx */
+ {12, 4}, /* last FP exception EIP from npx */
+ {24, 2}, /* last FP exception operand selector from npx */
+ {20, 4}, /* last FP exception operand offset from npx */
+ {18, 2} /* last FP opcode from npx */
};
static struct
{
int go32_sig;
- int gdb_sig;
+ enum target_signal gdb_sig;
}
sig_map[] =
{
- 0, TARGET_SIGNAL_FPE,
- 1, TARGET_SIGNAL_TRAP,
+ {0, TARGET_SIGNAL_FPE},
+ {1, TARGET_SIGNAL_TRAP},
/* Exception 2 is triggered by the NMI. DJGPP handles it as SIGILL,
but I think SIGBUS is better, since the NMI is usually activated
as a result of a memory parity check failure. */
- 2, TARGET_SIGNAL_BUS,
- 3, TARGET_SIGNAL_TRAP,
- 4, TARGET_SIGNAL_FPE,
- 5, TARGET_SIGNAL_SEGV,
- 6, TARGET_SIGNAL_ILL,
- 7, TARGET_SIGNAL_FPE,
- 8, TARGET_SIGNAL_SEGV,
- 9, TARGET_SIGNAL_SEGV,
- 10, TARGET_SIGNAL_BUS,
- 11, TARGET_SIGNAL_SEGV,
- 12, TARGET_SIGNAL_SEGV,
- 13, TARGET_SIGNAL_SEGV,
- 14, TARGET_SIGNAL_SEGV,
- 16, TARGET_SIGNAL_FPE,
- 17, TARGET_SIGNAL_BUS,
- 31, TARGET_SIGNAL_ILL,
- 0x1b, TARGET_SIGNAL_INT,
- 0x75, TARGET_SIGNAL_FPE,
- 0x78, TARGET_SIGNAL_ALRM,
- 0x79, TARGET_SIGNAL_INT,
- 0x7a, TARGET_SIGNAL_QUIT,
- -1, -1
+ {2, TARGET_SIGNAL_BUS},
+ {3, TARGET_SIGNAL_TRAP},
+ {4, TARGET_SIGNAL_FPE},
+ {5, TARGET_SIGNAL_SEGV},
+ {6, TARGET_SIGNAL_ILL},
+ {7, TARGET_SIGNAL_EMT}, /* no-coprocessor exception */
+ {8, TARGET_SIGNAL_SEGV},
+ {9, TARGET_SIGNAL_SEGV},
+ {10, TARGET_SIGNAL_BUS},
+ {11, TARGET_SIGNAL_SEGV},
+ {12, TARGET_SIGNAL_SEGV},
+ {13, TARGET_SIGNAL_SEGV},
+ {14, TARGET_SIGNAL_SEGV},
+ {16, TARGET_SIGNAL_FPE},
+ {17, TARGET_SIGNAL_BUS},
+ {31, TARGET_SIGNAL_ILL},
+ {0x1b, TARGET_SIGNAL_INT},
+ {0x75, TARGET_SIGNAL_FPE},
+ {0x78, TARGET_SIGNAL_ALRM},
+ {0x79, TARGET_SIGNAL_INT},
+ {0x7a, TARGET_SIGNAL_QUIT},
+ {-1, TARGET_SIGNAL_LAST}
};
static struct {
enum target_signal gdb_sig;
int djgpp_excepno;
} excepn_map[] = {
- TARGET_SIGNAL_0, -1,
- TARGET_SIGNAL_ILL, 6, /* Invalid Opcode */
- TARGET_SIGNAL_EMT, 7, /* triggers SIGNOFP */
- TARGET_SIGNAL_SEGV, 13, /* GPF */
- TARGET_SIGNAL_BUS, 17, /* Alignment Check */
+ {TARGET_SIGNAL_0, -1},
+ {TARGET_SIGNAL_ILL, 6}, /* Invalid Opcode */
+ {TARGET_SIGNAL_EMT, 7}, /* triggers SIGNOFP */
+ {TARGET_SIGNAL_SEGV, 13}, /* GPF */
+ {TARGET_SIGNAL_BUS, 17}, /* Alignment Check */
/* The rest are fake exceptions, see dpmiexcp.c in djlsr*.zip for
details. */
- TARGET_SIGNAL_TERM, 0x1b, /* triggers Ctrl-Break type of SIGINT */
- TARGET_SIGNAL_FPE, 0x75,
- TARGET_SIGNAL_INT, 0x79,
- TARGET_SIGNAL_QUIT, 0x7a,
- TARGET_SIGNAL_ALRM, 0x78, /* triggers SIGTIMR */
- TARGET_SIGNAL_PROF, 0x78,
- -1, -1
+ {TARGET_SIGNAL_TERM, 0x1b}, /* triggers Ctrl-Break type of SIGINT */
+ {TARGET_SIGNAL_FPE, 0x75},
+ {TARGET_SIGNAL_INT, 0x79},
+ {TARGET_SIGNAL_QUIT, 0x7a},
+ {TARGET_SIGNAL_ALRM, 0x78}, /* triggers SIGTIMR */
+ {TARGET_SIGNAL_PROF, 0x78},
+ {TARGET_SIGNAL_LAST, -1}
};
static void
if (siggnal != TARGET_SIGNAL_0 && siggnal != TARGET_SIGNAL_TRAP)
{
- for (i = 0, resume_signal = -1; excepn_map[i].gdb_sig != -1; i++)
+ for (i = 0, resume_signal = -1;
+ excepn_map[i].gdb_sig != TARGET_SIGNAL_LAST; i++)
if (excepn_map[i].gdb_sig == siggnal)
{
resume_signal = excepn_map[i].djgpp_excepno;
{
int i;
unsigned char saved_opcode;
- unsigned long INT3_addr;
+ unsigned long INT3_addr = 0;
int stepping_over_INT = 0;
a_tss.tss_eflags &= 0xfeff; /* reset the single-step flag (TF) */
point of changing back to where GDB thinks is its cwd, when we
return control to the debugger, but restore child's cwd before we
run it. */
+ /* Initialize child_cwd, before the first call to run_child and not
+ in the initialization, so the child get also the changed directory
+ set with the gdb-command "cd ..." */
+ if (!*child_cwd)
+ /* Initialize child's cwd with the current one. */
+ getcwd (child_cwd, sizeof (child_cwd));
+
chdir (child_cwd);
#if __DJGPP_MINOR__ < 3
}
static void
-go32_fetch_registers (int regno)
+fetch_register (int regno)
{
- /*JHW */
- int end_reg = regno + 1; /* just one reg initially */
-
- if (regno < 0) /* do the all registers */
- {
- regno = 0; /* start at first register */
- /* # regs in table */
- end_reg = sizeof (regno_mapping) / sizeof (regno_mapping[0]);
- }
+ if (regno < FP0_REGNUM)
+ supply_register (regno, (char *) &a_tss + regno_mapping[regno].tss_ofs);
+ else if (regno <= LAST_FPU_CTRL_REGNUM)
+ i387_supply_register (regno, (char *) &npx);
+ else
+ internal_error (__FILE__, __LINE__,
+ "Invalid register no. %d in fetch_register.", regno);
+}
- for (; regno < end_reg; regno++)
+static void
+go32_fetch_registers (int regno)
+{
+ if (regno >= 0)
+ fetch_register (regno);
+ else
{
- if (regno < 16)
- supply_register (regno,
- (char *) &a_tss + regno_mapping[regno].tss_ofs);
- else if (regno < 24)
- supply_register (regno,
- (char *) &npx.reg[regno_mapping[regno].tss_ofs]);
- else if (regno < 31)
- supply_register (regno,
- (char *) &npx + regno_mapping[regno].tss_ofs);
- else
- fatal ("Invalid register no. %d in go32_fetch_register.", regno);
+ for (regno = 0; regno < FP0_REGNUM; regno++)
+ fetch_register (regno);
+ i387_supply_fsave ((char *) &npx);
}
}
store_register (int regno)
{
void *rp;
- void *v = (void *) ®isters[REGISTER_BYTE (regno)];
-
- if (regno < 16)
- rp = (char *) &a_tss + regno_mapping[regno].tss_ofs;
- else if (regno < 24)
- rp = (char *) &npx.reg[regno_mapping[regno].tss_ofs];
- else if (regno < 31)
- rp = (char *) &npx + regno_mapping[regno].tss_ofs;
+ void *v = (void *) register_buffer (regno);
+
+ if (regno < FP0_REGNUM)
+ memcpy ((char *) &a_tss + regno_mapping[regno].tss_ofs,
+ v, regno_mapping[regno].size);
+ else if (regno <= LAST_FPU_CTRL_REGNUM)
+ i387_fill_fsave ((char *)&npx, regno);
else
- fatal ("Invalid register no. %d in store_register.", regno);
- memcpy (rp, v, regno_mapping[regno].size);
+ internal_error (__FILE__, __LINE__,
+ "Invalid register no. %d in store_register.", regno);
}
static void
go32_store_registers (int regno)
{
- int r;
+ unsigned r;
if (regno >= 0)
store_register (regno);
else
{
- for (r = 0; r < sizeof (regno_mapping) / sizeof (regno_mapping[0]); r++)
+ for (r = 0; r < FP0_REGNUM; r++)
store_register (r);
+ i387_fill_fsave ((char *) &npx, -1);
}
}
static int
go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
- struct target_ops *target)
+ struct mem_attrib *attrib, struct target_ops *target)
{
if (write)
{
static void
go32_create_inferior (char *exec_file, char *args, char **env)
{
+ extern char **environ;
jmp_buf start_state;
char *cmdline;
char **env_save = environ;
+ /* If no exec file handed to us, get it from the exec-file command -- with
+ a good, common error message if none is specified. */
+ if (exec_file == 0)
+ exec_file = get_exec_file (1);
+
if (prog_has_started)
{
go32_stop ();
}
resume_signal = -1;
resume_is_step = 0;
+
+ /* Initialize child's cwd as empty to be initialized when starting
+ the child. */
+ *child_cwd = 0;
+
/* Init command line storage. */
if (redir_debug_init (&child_cmd) == -1)
- fatal ("Cannot allocate redirection storage: not enough memory.\n");
+ internal_error (__FILE__, __LINE__,
+ "Cannot allocate redirection storage: not enough memory.\n");
/* Parse the command line and create redirections. */
if (strpbrk (args, "<>"))
error ("Syntax error in command line.");
}
else
- child_cmd.command = strdup (args);
+ child_cmd.command = xstrdup (args);
cmdline = (char *) alloca (strlen (args) + 4);
cmdline[0] = strlen (args);
push_target (&go32_ops);
clear_proceed_status ();
insert_breakpoints ();
- proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
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. */
- cleanup_dregs ();
+ i386_cleanup_dregs ();
go32_kill_inferior ();
generic_mourn_inferior ();
}
return 1;
}
-static void
-ignore (void)
-{
-}
-
/* Hardware watchpoint support. */
-#define DR_STATUS 6
-#define DR_CONTROL 7
-#define DR_ENABLE_SIZE 2
-#define DR_LOCAL_ENABLE_SHIFT 0
-#define DR_GLOBAL_ENABLE_SHIFT 1
-#define DR_LOCAL_SLOWDOWN 0x100
-#define DR_GLOBAL_SLOWDOWN 0x200
-#define DR_CONTROL_SHIFT 16
-#define DR_CONTROL_SIZE 4
-#define DR_RW_READWRITE 0x3
-#define DR_RW_WRITE 0x1
-#define DR_CONTROL_MASK 0xf
-#define DR_ENABLE_MASK 0x3
-#define DR_LEN_1 0x0
-#define DR_LEN_2 0x4
-#define DR_LEN_4 0xc
-
#define D_REGS edi.dr
-#define CONTROL D_REGS[DR_CONTROL]
-#define STATUS D_REGS[DR_STATUS]
-
-#define IS_REG_FREE(index) \
- (!(CONTROL & (3 << (DR_ENABLE_SIZE * (index)))))
-
-#define LOCAL_ENABLE_REG(index) \
- (CONTROL |= (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (index))))
-
-#define GLOBAL_ENABLE_REG(index) \
- (CONTROL |= (1 << (DR_GLOBAL_ENABLE_SHIFT + DR_ENABLE_SIZE * (index))))
-
-#define DISABLE_REG(index) \
- (CONTROL &= ~(3 << (DR_ENABLE_SIZE * (index))))
-
-#define SET_LOCAL_EXACT() \
- (CONTROL |= DR_LOCAL_SLOWDOWN)
-
-#define SET_GLOBAL_EXACT() \
- (CONTROL |= DR_GLOBAL_SLOWDOWN)
-
-#define RESET_LOCAL_EXACT() \
- (CONTROL &= ~(DR_LOCAL_SLOWDOWN))
-
-#define RESET_GLOBAL_EXACT() \
- (CONTROL &= ~(DR_GLOBAL_SLOWDOWN))
-
-#define SET_BREAK(index,address) \
- do {\
- CONTROL &= ~(DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index)));\
- D_REGS[index] = address;\
- } while(0)
-
-#define SET_WATCH(index,address,rw,len) \
- do {\
- SET_BREAK(index,address);\
- CONTROL |= ((len)|(rw)) << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index));\
- } while (0)
-
-#define IS_WATCH(index) \
- (CONTROL & (DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE*(index))))
-
-#define WATCH_HIT(index) \
- (\
- (STATUS & (1 << index)) && \
- (CONTROL & (DR_CONTROL_MASK << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * index)))\
- )
-
-#define DR_DEF(index) \
- ((CONTROL >> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (index))) & 0x0f)
-
-
-#if 0 /* use debugging macro */
-#define SHOW_DR(text,len) \
-do { \
- if (!getenv ("GDB_SHOW_DR")) break; \
- fprintf(stderr,"%08x %08x ",edi.dr[7],edi.dr[6]); \
- fprintf(stderr,"%08x %d %08x %d ", \
- edi.dr[0],dr_ref_count[0],edi.dr[1],dr_ref_count[1]); \
- fprintf(stderr,"%08x %d %08x %d ", \
- edi.dr[2],dr_ref_count[2],edi.dr[3],dr_ref_count[3]); \
- fprintf(stderr,(len)?"(%s:%d)\n":"(%s)\n",#text,len); \
-} while (0)
-#else
-#define SHOW_DR(text,len) do {} while (0)
-#endif
-
-static void
-cleanup_dregs (void)
-{
- int i;
-
- CONTROL = 0;
- STATUS = 0;
- for (i = 0; i < 4; i++)
- {
- D_REGS[i] = 0;
- dr_ref_count[i] = 0;
- }
-}
-
-/* Insert a watchpoint. */
-
-int
-go32_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
-{
- int ret = go32_insert_aligned_watchpoint (addr, addr, len, rw);
-
- SHOW_DR (insert_watch, len);
- return ret;
-}
-
-static int
-go32_insert_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
- int len, int rw)
-{
- int i;
- int read_write_bits, len_bits;
+#define CONTROL D_REGS[7]
+#define STATUS D_REGS[6]
- /* Values of rw: 0 - write, 1 - read, 2 - access (read and write).
- However, x86 doesn't support read-only data breakpoints. */
- read_write_bits = rw ? DR_RW_READWRITE : DR_RW_WRITE;
-
- switch (len)
- {
- case 4:
- len_bits = DR_LEN_4;
- break;
- case 2:
- len_bits = DR_LEN_2;
- break;
- case 1:
- len_bits = DR_LEN_1;
- break;
- default:
- /* The debug registers only have 2 bits for the length, so
- so this value will always fail the loop below. */
- len_bits = 0x10;
- }
-
- /* Look for an occupied debug register with the same address and the
- same RW and LEN definitions. If we find one, we can use it for
- this watchpoint as well (and save a register). */
- for (i = 0; i < 4; i++)
- {
- if (!IS_REG_FREE (i) && D_REGS[i] == addr
- && DR_DEF (i) == (len_bits | read_write_bits))
- {
- dr_ref_count[i]++;
- return 0;
- }
- }
-
- /* Look for a free debug register. */
- for (i = 0; i <= 3; i++)
- {
- if (IS_REG_FREE (i))
- break;
- }
-
- /* No more debug registers! */
- if (i > 3)
- return -1;
-
- if (len == 2)
- {
- if (addr % 2)
- return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr,
- len, rw);
- }
- else if (len == 4)
- {
- if (addr % 4)
- return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr,
- len, rw);
- }
- else if (len != 1)
- return go32_handle_nonaligned_watchpoint (wp_insert, waddr, addr, len, rw);
-
- SET_WATCH (i, addr, read_write_bits, len_bits);
- LOCAL_ENABLE_REG (i);
- SET_LOCAL_EXACT ();
- SET_GLOBAL_EXACT ();
- return 0;
-}
-
-static int
-go32_handle_nonaligned_watchpoint (wp_op what, CORE_ADDR waddr, CORE_ADDR addr,
- int len, int rw)
-{
- int align;
- int size;
- int rv = 0, status = 0;
-
- static int size_try_array[16] =
- {
- 1, 1, 1, 1, /* trying size one */
- 2, 1, 2, 1, /* trying size two */
- 2, 1, 2, 1, /* trying size three */
- 4, 1, 2, 1 /* trying size four */
- };
-
- while (len > 0)
- {
- align = addr % 4;
- /* Four is the maximum length for 386. */
- size = (len > 4) ? 3 : len - 1;
- size = size_try_array[size * 4 + align];
- if (what == wp_insert)
- status = go32_insert_aligned_watchpoint (waddr, addr, size, rw);
- else if (what == wp_remove)
- status = go32_remove_aligned_watchpoint (waddr, addr, size, rw);
- else if (what == wp_count)
- rv++;
- else
- status = -1;
- /* We keep the loop going even after a failure, because some of
- the other aligned watchpoints might still succeed, e.g. if
- they watch addresses that are already watched, and thus just
- increment the reference counts of occupied debug registers.
- If we break out of the loop too early, we could cause those
- addresses watched by other watchpoints to be disabled when
- GDB reacts to our failure to insert this watchpoint and tries
- to remove it. */
- if (status)
- rv = status;
- addr += size;
- len -= size;
- }
- return rv;
-}
-
-/* Remove a watchpoint. */
-
-int
-go32_remove_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
-{
- int ret = go32_remove_aligned_watchpoint (addr, addr, len, rw);
-
- SHOW_DR (remove_watch, len);
- return ret;
-}
-
-static int
-go32_remove_aligned_watchpoint (CORE_ADDR waddr, CORE_ADDR addr,
- int len, int rw)
-{
- int i;
- int read_write_bits, len_bits;
-
- /* Values of rw: 0 - write, 1 - read, 2 - access (read and write).
- However, x86 doesn't support read-only data breakpoints. */
- read_write_bits = rw ? DR_RW_READWRITE : DR_RW_WRITE;
-
- switch (len)
- {
- case 4:
- len_bits = DR_LEN_4;
- break;
- case 2:
- len_bits = DR_LEN_2;
- break;
- case 1:
- len_bits = DR_LEN_1;
- break;
- default:
- /* The debug registers only have 2 bits for the length, so
- so this value will always fail the loop below. */
- len_bits = 0x10;
- }
-
- if (len == 2)
- {
- if (addr % 2)
- return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr,
- len, rw);
- }
- else if (len == 4)
- {
- if (addr % 4)
- return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr,
- len, rw);
- }
- else if (len != 1)
- return go32_handle_nonaligned_watchpoint (wp_remove, waddr, addr, len, rw);
-
- for (i = 0; i <= 3; i++)
- {
- if (!IS_REG_FREE (i) && D_REGS[i] == addr
- && DR_DEF (i) == (len_bits | read_write_bits))
- {
- dr_ref_count[i]--;
- if (dr_ref_count[i] == 0)
- DISABLE_REG (i);
- }
- }
- RESET_LOCAL_EXACT ();
- RESET_GLOBAL_EXACT ();
-
- return 0;
-}
-
-/* Can we use debug registers to watch a region whose address is ADDR
- and whose length is LEN bytes? */
-
-int
-go32_region_ok_for_watchpoint (CORE_ADDR addr, int len)
+/* Pass the address ADDR to the inferior in the I'th debug register.
+ Here we just store the address in D_REGS, the watchpoint will be
+ actually set up when go32_wait runs the debuggee. */
+void
+go32_set_dr (int i, CORE_ADDR addr)
{
- /* Compute how many aligned watchpoints we would need to cover this
- region. */
- int nregs = go32_handle_nonaligned_watchpoint (wp_count, addr, addr, len, 0);
-
- return nregs <= 4 ? 1 : 0;
+ if (i < 0 || i > 3)
+ internal_error (__FILE__, __LINE__,
+ "Invalid register %d in go32_set_dr.\n", i);
+ D_REGS[i] = addr;
}
-/* Check if stopped by a data watchpoint. If so, return the address
- whose access triggered the watchpoint. */
-
-CORE_ADDR
-go32_stopped_by_watchpoint (int pid, int data_watchpoint)
+/* Pass the value VAL to the inferior in the DR7 debug control
+ register. Here we just store the address in D_REGS, the watchpoint
+ will be actually set up when go32_wait runs the debuggee. */
+void
+go32_set_dr7 (unsigned val)
{
- int i, ret = 0;
- int status;
-
- status = edi.dr[DR_STATUS];
- SHOW_DR (stopped_by, 0);
- for (i = 0; i <= 3; i++)
- {
- if (WATCH_HIT (i) && data_watchpoint)
- {
- SHOW_DR (WP_HIT, 0);
- ret = D_REGS[i];
- }
- }
-
- return ret;
+ CONTROL = val;
}
-/* Remove a breakpoint. */
-
-int
-go32_remove_hw_breakpoint (CORE_ADDR addr, CORE_ADDR shadow)
+/* Get the value of the DR6 debug status register from the inferior.
+ Here we just return the value stored in D_REGS, as we've got it
+ from the last go32_wait call. */
+unsigned
+go32_get_dr6 (void)
{
- int i;
- for (i = 0; i <= 3; i++)
- {
- if (!IS_REG_FREE (i) && D_REGS[i] == addr && DR_DEF (i) == 0)
- {
- dr_ref_count[i]--;
- if (dr_ref_count[i] == 0)
- DISABLE_REG (i);
- }
- }
- SHOW_DR (remove_hw, 0);
- return 0;
+ return STATUS;
}
-int
-go32_insert_hw_breakpoint (CORE_ADDR addr, CORE_ADDR shadow)
-{
- int i;
- int read_write_bits, len_bits;
- int free_debug_register;
- int register_number;
-
- /* Look for an occupied debug register with the same address and the
- same RW and LEN definitions. If we find one, we can use it for
- this breakpoint as well (and save a register). */
- for (i = 0; i < 4; i++)
- {
- if (!IS_REG_FREE (i) && D_REGS[i] == addr && DR_DEF (i) == 0)
- {
- dr_ref_count[i]++;
- SHOW_DR (insert_hw, 0);
- return 0;
- }
- }
-
- /* Look for a free debug register. */
- for (i = 0; i <= 3; i++)
- {
- if (IS_REG_FREE (i))
- break;
- }
-
- /* No more debug registers? */
- if (i < 4)
- {
- SET_BREAK (i, addr);
- LOCAL_ENABLE_REG (i);
- }
- SHOW_DR (insert_hw, 0);
-
- return i < 4 ? 0 : -1;
-}
-
-static int inf_flags_valid = 0;
-static int inf_in_flag;
-static int inf_out_flag;
-
/* Put the device open on handle FD into either raw or cooked
mode, return 1 if it was in raw mode, zero otherwise. */
go32_ops.to_has_execution = 1;
go32_ops.to_magic = OPS_MAGIC;
- /* Initialize child's cwd with the current one. */
- getcwd (child_cwd, sizeof (child_cwd));
+ /* 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)
- fatal ("Cannot allocate redirection storage: not enough memory.\n");
+ internal_error (__FILE__, __LINE__,
+ "Cannot allocate redirection storage: not enough memory.\n");
+
+ /* We are always processing GCC-compiled programs. */
+ processing_gcc_compilation = 2;
}
void