1130803Smarcel/* Native debugging support for Intel x86 running DJGPP.
2130803Smarcel   Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
3130803Smarcel   Written by Robert Hoehne.
4130803Smarcel
5130803Smarcel   This file is part of GDB.
6130803Smarcel
7130803Smarcel   This program is free software; you can redistribute it and/or modify
8130803Smarcel   it under the terms of the GNU General Public License as published by
9130803Smarcel   the Free Software Foundation; either version 2 of the License, or
10130803Smarcel   (at your option) any later version.
11130803Smarcel
12130803Smarcel   This program is distributed in the hope that it will be useful,
13130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
14130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15130803Smarcel   GNU General Public License for more details.
16130803Smarcel
17130803Smarcel   You should have received a copy of the GNU General Public License
18130803Smarcel   along with this program; if not, write to the Free Software
19130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
20130803Smarcel   Boston, MA 02111-1307, USA.  */
21130803Smarcel
22130803Smarcel#include <fcntl.h>
23130803Smarcel
24130803Smarcel#include "defs.h"
25130803Smarcel#include "inferior.h"
26130803Smarcel#include "gdb_wait.h"
27130803Smarcel#include "gdbcore.h"
28130803Smarcel#include "command.h"
29130803Smarcel#include "gdbcmd.h"
30130803Smarcel#include "floatformat.h"
31130803Smarcel#include "buildsym.h"
32130803Smarcel#include "i387-tdep.h"
33130803Smarcel#include "i386-tdep.h"
34130803Smarcel#include "value.h"
35130803Smarcel#include "regcache.h"
36130803Smarcel#include "gdb_string.h"
37130803Smarcel
38130803Smarcel#include <stdio.h>		/* might be required for __DJGPP_MINOR__ */
39130803Smarcel#include <stdlib.h>
40130803Smarcel#include <ctype.h>
41130803Smarcel#include <errno.h>
42130803Smarcel#include <unistd.h>
43130803Smarcel#include <sys/utsname.h>
44130803Smarcel#include <io.h>
45130803Smarcel#include <dos.h>
46130803Smarcel#include <dpmi.h>
47130803Smarcel#include <go32.h>
48130803Smarcel#include <sys/farptr.h>
49130803Smarcel#include <debug/v2load.h>
50130803Smarcel#include <debug/dbgcom.h>
51130803Smarcel#if __DJGPP_MINOR__ > 2
52130803Smarcel#include <debug/redir.h>
53130803Smarcel#endif
54130803Smarcel
55130803Smarcel#if __DJGPP_MINOR__ < 3
56130803Smarcel/* This code will be provided from DJGPP 2.03 on. Until then I code it
57130803Smarcel   here */
58130803Smarceltypedef struct
59130803Smarcel  {
60130803Smarcel    unsigned short sig0;
61130803Smarcel    unsigned short sig1;
62130803Smarcel    unsigned short sig2;
63130803Smarcel    unsigned short sig3;
64130803Smarcel    unsigned short exponent:15;
65130803Smarcel    unsigned short sign:1;
66130803Smarcel  }
67130803SmarcelNPXREG;
68130803Smarcel
69130803Smarceltypedef struct
70130803Smarcel  {
71130803Smarcel    unsigned int control;
72130803Smarcel    unsigned int status;
73130803Smarcel    unsigned int tag;
74130803Smarcel    unsigned int eip;
75130803Smarcel    unsigned int cs;
76130803Smarcel    unsigned int dataptr;
77130803Smarcel    unsigned int datasel;
78130803Smarcel    NPXREG reg[8];
79130803Smarcel  }
80130803SmarcelNPX;
81130803Smarcel
82130803Smarcelstatic NPX npx;
83130803Smarcel
84130803Smarcelstatic void save_npx (void);	/* Save the FPU of the debugged program */
85130803Smarcelstatic void load_npx (void);	/* Restore the FPU of the debugged program */
86130803Smarcel
87130803Smarcel/* ------------------------------------------------------------------------- */
88130803Smarcel/* Store the contents of the NPX in the global variable `npx'.  */
89130803Smarcel/* *INDENT-OFF* */
90130803Smarcel
91130803Smarcelstatic void
92130803Smarcelsave_npx (void)
93130803Smarcel{
94130803Smarcel  asm ("inb    $0xa0, %%al  \n\
95130803Smarcel       testb $0x20, %%al    \n\
96130803Smarcel       jz 1f 	    	    \n\
97130803Smarcel       xorb %%al, %%al	    \n\
98130803Smarcel       outb %%al, $0xf0     \n\
99130803Smarcel       movb $0x20, %%al	    \n\
100130803Smarcel       outb %%al, $0xa0     \n\
101130803Smarcel       outb %%al, $0x20     \n\
102130803Smarcel1:     	       	   	    \n\
103130803Smarcel       fnsave %0	    \n\
104130803Smarcel       fwait "
105130803Smarcel:     "=m" (npx)
106130803Smarcel:				/* No input */
107130803Smarcel:     "%eax");
108130803Smarcel}
109130803Smarcel
110130803Smarcel/* *INDENT-ON* */
111130803Smarcel
112130803Smarcel
113130803Smarcel/* ------------------------------------------------------------------------- */
114130803Smarcel/* Reload the contents of the NPX from the global variable `npx'.  */
115130803Smarcel
116130803Smarcelstatic void
117130803Smarcelload_npx (void)
118130803Smarcel{
119130803Smarcel  asm ("frstor %0":"=m" (npx));
120130803Smarcel}
121130803Smarcel/* ------------------------------------------------------------------------- */
122130803Smarcel/* Stubs for the missing redirection functions.  */
123130803Smarceltypedef struct {
124130803Smarcel  char *command;
125130803Smarcel  int redirected;
126130803Smarcel} cmdline_t;
127130803Smarcel
128130803Smarcelvoid
129130803Smarcelredir_cmdline_delete (cmdline_t *ptr)
130130803Smarcel{
131130803Smarcel  ptr->redirected = 0;
132130803Smarcel}
133130803Smarcel
134130803Smarcelint
135130803Smarcelredir_cmdline_parse (const char *args, cmdline_t *ptr)
136130803Smarcel{
137130803Smarcel  return -1;
138130803Smarcel}
139130803Smarcel
140130803Smarcelint
141130803Smarcelredir_to_child (cmdline_t *ptr)
142130803Smarcel{
143130803Smarcel  return 1;
144130803Smarcel}
145130803Smarcel
146130803Smarcelint
147130803Smarcelredir_to_debugger (cmdline_t *ptr)
148130803Smarcel{
149130803Smarcel  return 1;
150130803Smarcel}
151130803Smarcel
152130803Smarcelint
153130803Smarcelredir_debug_init (cmdline_t *ptr)
154130803Smarcel{
155130803Smarcel  return 0;
156130803Smarcel}
157130803Smarcel#endif /* __DJGPP_MINOR < 3 */
158130803Smarcel
159130803Smarceltypedef enum { wp_insert, wp_remove, wp_count } wp_op;
160130803Smarcel
161130803Smarcel/* This holds the current reference counts for each debug register.  */
162130803Smarcelstatic int dr_ref_count[4];
163130803Smarcel
164130803Smarcel#define SOME_PID 42
165130803Smarcel
166130803Smarcelstatic int prog_has_started = 0;
167130803Smarcelstatic void go32_open (char *name, int from_tty);
168130803Smarcelstatic void go32_close (int quitting);
169130803Smarcelstatic void go32_attach (char *args, int from_tty);
170130803Smarcelstatic void go32_detach (char *args, int from_tty);
171130803Smarcelstatic void go32_resume (ptid_t ptid, int step,
172130803Smarcel                         enum target_signal siggnal);
173130803Smarcelstatic ptid_t go32_wait (ptid_t ptid,
174130803Smarcel                               struct target_waitstatus *status);
175130803Smarcelstatic void go32_fetch_registers (int regno);
176130803Smarcelstatic void store_register (int regno);
177130803Smarcelstatic void go32_store_registers (int regno);
178130803Smarcelstatic void go32_prepare_to_store (void);
179130803Smarcelstatic int go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
180130803Smarcel			     int write,
181130803Smarcel			     struct mem_attrib *attrib,
182130803Smarcel			     struct target_ops *target);
183130803Smarcelstatic void go32_files_info (struct target_ops *target);
184130803Smarcelstatic void go32_stop (void);
185130803Smarcelstatic void go32_kill_inferior (void);
186130803Smarcelstatic void go32_create_inferior (char *exec_file, char *args, char **env);
187130803Smarcelstatic void go32_mourn_inferior (void);
188130803Smarcelstatic int go32_can_run (void);
189130803Smarcel
190130803Smarcelstatic struct target_ops go32_ops;
191130803Smarcelstatic void go32_terminal_init (void);
192130803Smarcelstatic void go32_terminal_inferior (void);
193130803Smarcelstatic void go32_terminal_ours (void);
194130803Smarcel
195130803Smarcel#define r_ofs(x) (offsetof(TSS,x))
196130803Smarcel
197130803Smarcelstatic struct
198130803Smarcel{
199130803Smarcel  size_t tss_ofs;
200130803Smarcel  size_t size;
201130803Smarcel}
202130803Smarcelregno_mapping[] =
203130803Smarcel{
204130803Smarcel  {r_ofs (tss_eax), 4},	/* normal registers, from a_tss */
205130803Smarcel  {r_ofs (tss_ecx), 4},
206130803Smarcel  {r_ofs (tss_edx), 4},
207130803Smarcel  {r_ofs (tss_ebx), 4},
208130803Smarcel  {r_ofs (tss_esp), 4},
209130803Smarcel  {r_ofs (tss_ebp), 4},
210130803Smarcel  {r_ofs (tss_esi), 4},
211130803Smarcel  {r_ofs (tss_edi), 4},
212130803Smarcel  {r_ofs (tss_eip), 4},
213130803Smarcel  {r_ofs (tss_eflags), 4},
214130803Smarcel  {r_ofs (tss_cs), 2},
215130803Smarcel  {r_ofs (tss_ss), 2},
216130803Smarcel  {r_ofs (tss_ds), 2},
217130803Smarcel  {r_ofs (tss_es), 2},
218130803Smarcel  {r_ofs (tss_fs), 2},
219130803Smarcel  {r_ofs (tss_gs), 2},
220130803Smarcel  {0, 10},		/* 8 FP registers, from npx.reg[] */
221130803Smarcel  {1, 10},
222130803Smarcel  {2, 10},
223130803Smarcel  {3, 10},
224130803Smarcel  {4, 10},
225130803Smarcel  {5, 10},
226130803Smarcel  {6, 10},
227130803Smarcel  {7, 10},
228130803Smarcel	/* The order of the next 7 registers must be consistent
229130803Smarcel	   with their numbering in config/i386/tm-i386.h, which see.  */
230130803Smarcel  {0, 2},		/* control word, from npx */
231130803Smarcel  {4, 2},		/* status word, from npx */
232130803Smarcel  {8, 2},		/* tag word, from npx */
233130803Smarcel  {16, 2},		/* last FP exception CS from npx */
234130803Smarcel  {12, 4},		/* last FP exception EIP from npx */
235130803Smarcel  {24, 2},		/* last FP exception operand selector from npx */
236130803Smarcel  {20, 4},		/* last FP exception operand offset from npx */
237130803Smarcel  {18, 2}		/* last FP opcode from npx */
238130803Smarcel};
239130803Smarcel
240130803Smarcelstatic struct
241130803Smarcel  {
242130803Smarcel    int go32_sig;
243130803Smarcel    enum target_signal gdb_sig;
244130803Smarcel  }
245130803Smarcelsig_map[] =
246130803Smarcel{
247130803Smarcel  {0, TARGET_SIGNAL_FPE},
248130803Smarcel  {1, TARGET_SIGNAL_TRAP},
249130803Smarcel  /* Exception 2 is triggered by the NMI.  DJGPP handles it as SIGILL,
250130803Smarcel     but I think SIGBUS is better, since the NMI is usually activated
251130803Smarcel     as a result of a memory parity check failure.  */
252130803Smarcel  {2, TARGET_SIGNAL_BUS},
253130803Smarcel  {3, TARGET_SIGNAL_TRAP},
254130803Smarcel  {4, TARGET_SIGNAL_FPE},
255130803Smarcel  {5, TARGET_SIGNAL_SEGV},
256130803Smarcel  {6, TARGET_SIGNAL_ILL},
257130803Smarcel  {7, TARGET_SIGNAL_EMT},	/* no-coprocessor exception */
258130803Smarcel  {8, TARGET_SIGNAL_SEGV},
259130803Smarcel  {9, TARGET_SIGNAL_SEGV},
260130803Smarcel  {10, TARGET_SIGNAL_BUS},
261130803Smarcel  {11, TARGET_SIGNAL_SEGV},
262130803Smarcel  {12, TARGET_SIGNAL_SEGV},
263130803Smarcel  {13, TARGET_SIGNAL_SEGV},
264130803Smarcel  {14, TARGET_SIGNAL_SEGV},
265130803Smarcel  {16, TARGET_SIGNAL_FPE},
266130803Smarcel  {17, TARGET_SIGNAL_BUS},
267130803Smarcel  {31, TARGET_SIGNAL_ILL},
268130803Smarcel  {0x1b, TARGET_SIGNAL_INT},
269130803Smarcel  {0x75, TARGET_SIGNAL_FPE},
270130803Smarcel  {0x78, TARGET_SIGNAL_ALRM},
271130803Smarcel  {0x79, TARGET_SIGNAL_INT},
272130803Smarcel  {0x7a, TARGET_SIGNAL_QUIT},
273130803Smarcel  {-1, TARGET_SIGNAL_LAST}
274130803Smarcel};
275130803Smarcel
276130803Smarcelstatic struct {
277130803Smarcel  enum target_signal gdb_sig;
278130803Smarcel  int djgpp_excepno;
279130803Smarcel} excepn_map[] = {
280130803Smarcel  {TARGET_SIGNAL_0, -1},
281130803Smarcel  {TARGET_SIGNAL_ILL, 6},	/* Invalid Opcode */
282130803Smarcel  {TARGET_SIGNAL_EMT, 7},	/* triggers SIGNOFP */
283130803Smarcel  {TARGET_SIGNAL_SEGV, 13},	/* GPF */
284130803Smarcel  {TARGET_SIGNAL_BUS, 17},	/* Alignment Check */
285130803Smarcel  /* The rest are fake exceptions, see dpmiexcp.c in djlsr*.zip for
286130803Smarcel     details.  */
287130803Smarcel  {TARGET_SIGNAL_TERM, 0x1b},	/* triggers Ctrl-Break type of SIGINT */
288130803Smarcel  {TARGET_SIGNAL_FPE, 0x75},
289130803Smarcel  {TARGET_SIGNAL_INT, 0x79},
290130803Smarcel  {TARGET_SIGNAL_QUIT, 0x7a},
291130803Smarcel  {TARGET_SIGNAL_ALRM, 0x78},	/* triggers SIGTIMR */
292130803Smarcel  {TARGET_SIGNAL_PROF, 0x78},
293130803Smarcel  {TARGET_SIGNAL_LAST, -1}
294130803Smarcel};
295130803Smarcel
296130803Smarcelstatic void
297130803Smarcelgo32_open (char *name, int from_tty)
298130803Smarcel{
299130803Smarcel  printf_unfiltered ("Done.  Use the \"run\" command to run the program.\n");
300130803Smarcel}
301130803Smarcel
302130803Smarcelstatic void
303130803Smarcelgo32_close (int quitting)
304130803Smarcel{
305130803Smarcel}
306130803Smarcel
307130803Smarcelstatic void
308130803Smarcelgo32_attach (char *args, int from_tty)
309130803Smarcel{
310130803Smarcel  error ("\
311130803SmarcelYou cannot attach to a running program on this platform.\n\
312130803SmarcelUse the `run' command to run DJGPP programs.");
313130803Smarcel}
314130803Smarcel
315130803Smarcelstatic void
316130803Smarcelgo32_detach (char *args, int from_tty)
317130803Smarcel{
318130803Smarcel}
319130803Smarcel
320130803Smarcelstatic int resume_is_step;
321130803Smarcelstatic int resume_signal = -1;
322130803Smarcel
323130803Smarcelstatic void
324130803Smarcelgo32_resume (ptid_t ptid, int step, enum target_signal siggnal)
325130803Smarcel{
326130803Smarcel  int i;
327130803Smarcel
328130803Smarcel  resume_is_step = step;
329130803Smarcel
330130803Smarcel  if (siggnal != TARGET_SIGNAL_0 && siggnal != TARGET_SIGNAL_TRAP)
331130803Smarcel  {
332130803Smarcel    for (i = 0, resume_signal = -1;
333130803Smarcel	 excepn_map[i].gdb_sig != TARGET_SIGNAL_LAST; i++)
334130803Smarcel      if (excepn_map[i].gdb_sig == siggnal)
335130803Smarcel      {
336130803Smarcel	resume_signal = excepn_map[i].djgpp_excepno;
337130803Smarcel	break;
338130803Smarcel      }
339130803Smarcel    if (resume_signal == -1)
340130803Smarcel      printf_unfiltered ("Cannot deliver signal %s on this platform.\n",
341130803Smarcel			 target_signal_to_name (siggnal));
342130803Smarcel  }
343130803Smarcel}
344130803Smarcel
345130803Smarcelstatic char child_cwd[FILENAME_MAX];
346130803Smarcel
347130803Smarcelstatic ptid_t
348130803Smarcelgo32_wait (ptid_t ptid, struct target_waitstatus *status)
349130803Smarcel{
350130803Smarcel  int i;
351130803Smarcel  unsigned char saved_opcode;
352130803Smarcel  unsigned long INT3_addr = 0;
353130803Smarcel  int stepping_over_INT = 0;
354130803Smarcel
355130803Smarcel  a_tss.tss_eflags &= 0xfeff;	/* reset the single-step flag (TF) */
356130803Smarcel  if (resume_is_step)
357130803Smarcel    {
358130803Smarcel      /* If the next instruction is INT xx or INTO, we need to handle
359130803Smarcel	 them specially.  Intel manuals say that these instructions
360130803Smarcel	 reset the single-step flag (a.k.a. TF).  However, it seems
361130803Smarcel	 that, at least in the DPMI environment, and at least when
362130803Smarcel	 stepping over the DPMI interrupt 31h, the problem is having
363130803Smarcel	 TF set at all when INT 31h is executed: the debuggee either
364130803Smarcel	 crashes (and takes the system with it) or is killed by a
365130803Smarcel	 SIGTRAP.
366130803Smarcel
367130803Smarcel	 So we need to emulate single-step mode: we put an INT3 opcode
368130803Smarcel	 right after the INT xx instruction, let the debuggee run
369130803Smarcel	 until it hits INT3 and stops, then restore the original
370130803Smarcel	 instruction which we overwrote with the INT3 opcode, and back
371130803Smarcel	 up the debuggee's EIP to that instruction.  */
372130803Smarcel      read_child (a_tss.tss_eip, &saved_opcode, 1);
373130803Smarcel      if (saved_opcode == 0xCD || saved_opcode == 0xCE)
374130803Smarcel	{
375130803Smarcel	  unsigned char INT3_opcode = 0xCC;
376130803Smarcel
377130803Smarcel	  INT3_addr
378130803Smarcel	    = saved_opcode == 0xCD ? a_tss.tss_eip + 2 : a_tss.tss_eip + 1;
379130803Smarcel	  stepping_over_INT = 1;
380130803Smarcel	  read_child (INT3_addr, &saved_opcode, 1);
381130803Smarcel	  write_child (INT3_addr, &INT3_opcode, 1);
382130803Smarcel	}
383130803Smarcel      else
384130803Smarcel	a_tss.tss_eflags |= 0x0100; /* normal instruction: set TF */
385130803Smarcel    }
386130803Smarcel
387130803Smarcel  /* The special value FFFFh in tss_trap indicates to run_child that
388130803Smarcel     tss_irqn holds a signal to be delivered to the debuggee.  */
389130803Smarcel  if (resume_signal <= -1)
390130803Smarcel    {
391130803Smarcel      a_tss.tss_trap = 0;
392130803Smarcel      a_tss.tss_irqn = 0xff;
393130803Smarcel    }
394130803Smarcel  else
395130803Smarcel    {
396130803Smarcel      a_tss.tss_trap = 0xffff;	/* run_child looks for this */
397130803Smarcel      a_tss.tss_irqn = resume_signal;
398130803Smarcel    }
399130803Smarcel
400130803Smarcel  /* The child might change working directory behind our back.  The
401130803Smarcel     GDB users won't like the side effects of that when they work with
402130803Smarcel     relative file names, and GDB might be confused by its current
403130803Smarcel     directory not being in sync with the truth.  So we always make a
404130803Smarcel     point of changing back to where GDB thinks is its cwd, when we
405130803Smarcel     return control to the debugger, but restore child's cwd before we
406130803Smarcel     run it.  */
407130803Smarcel  /* Initialize child_cwd, before the first call to run_child and not
408130803Smarcel     in the initialization, so the child get also the changed directory
409130803Smarcel     set with the gdb-command "cd ..." */
410130803Smarcel  if (!*child_cwd)
411130803Smarcel    /* Initialize child's cwd with the current one.  */
412130803Smarcel    getcwd (child_cwd, sizeof (child_cwd));
413130803Smarcel
414130803Smarcel  chdir (child_cwd);
415130803Smarcel
416130803Smarcel#if __DJGPP_MINOR__ < 3
417130803Smarcel  load_npx ();
418130803Smarcel#endif
419130803Smarcel  run_child ();
420130803Smarcel#if __DJGPP_MINOR__ < 3
421130803Smarcel  save_npx ();
422130803Smarcel#endif
423130803Smarcel
424130803Smarcel  /* Did we step over an INT xx instruction?  */
425130803Smarcel  if (stepping_over_INT && a_tss.tss_eip == INT3_addr + 1)
426130803Smarcel    {
427130803Smarcel      /* Restore the original opcode.  */
428130803Smarcel      a_tss.tss_eip--;	/* EIP points *after* the INT3 instruction */
429130803Smarcel      write_child (a_tss.tss_eip, &saved_opcode, 1);
430130803Smarcel      /* Simulate a TRAP exception.  */
431130803Smarcel      a_tss.tss_irqn = 1;
432130803Smarcel      a_tss.tss_eflags |= 0x0100;
433130803Smarcel    }
434130803Smarcel
435130803Smarcel  getcwd (child_cwd, sizeof (child_cwd)); /* in case it has changed */
436130803Smarcel  chdir (current_directory);
437130803Smarcel
438130803Smarcel  if (a_tss.tss_irqn == 0x21)
439130803Smarcel    {
440130803Smarcel      status->kind = TARGET_WAITKIND_EXITED;
441130803Smarcel      status->value.integer = a_tss.tss_eax & 0xff;
442130803Smarcel    }
443130803Smarcel  else
444130803Smarcel    {
445130803Smarcel      status->value.sig = TARGET_SIGNAL_UNKNOWN;
446130803Smarcel      status->kind = TARGET_WAITKIND_STOPPED;
447130803Smarcel      for (i = 0; sig_map[i].go32_sig != -1; i++)
448130803Smarcel	{
449130803Smarcel	  if (a_tss.tss_irqn == sig_map[i].go32_sig)
450130803Smarcel	    {
451130803Smarcel#if __DJGPP_MINOR__ < 3
452130803Smarcel	      if ((status->value.sig = sig_map[i].gdb_sig) !=
453130803Smarcel		  TARGET_SIGNAL_TRAP)
454130803Smarcel		status->kind = TARGET_WAITKIND_SIGNALLED;
455130803Smarcel#else
456130803Smarcel	      status->value.sig = sig_map[i].gdb_sig;
457130803Smarcel#endif
458130803Smarcel	      break;
459130803Smarcel	    }
460130803Smarcel	}
461130803Smarcel    }
462130803Smarcel  return pid_to_ptid (SOME_PID);
463130803Smarcel}
464130803Smarcel
465130803Smarcelstatic void
466130803Smarcelfetch_register (int regno)
467130803Smarcel{
468130803Smarcel  if (regno < FP0_REGNUM)
469130803Smarcel    supply_register (regno, (char *) &a_tss + regno_mapping[regno].tss_ofs);
470130803Smarcel  else if (i386_fp_regnum_p (regno) || i386_fpc_regnum_p (regno))
471130803Smarcel    i387_supply_fsave (current_regcache, regno, &npx);
472130803Smarcel  else
473130803Smarcel    internal_error (__FILE__, __LINE__,
474130803Smarcel		    "Invalid register no. %d in fetch_register.", regno);
475130803Smarcel}
476130803Smarcel
477130803Smarcelstatic void
478130803Smarcelgo32_fetch_registers (int regno)
479130803Smarcel{
480130803Smarcel  if (regno >= 0)
481130803Smarcel    fetch_register (regno);
482130803Smarcel  else
483130803Smarcel    {
484130803Smarcel      for (regno = 0; regno < FP0_REGNUM; regno++)
485130803Smarcel	fetch_register (regno);
486130803Smarcel      i387_supply_fsave (current_regcache, -1, &npx);
487130803Smarcel    }
488130803Smarcel}
489130803Smarcel
490130803Smarcelstatic void
491130803Smarcelstore_register (int regno)
492130803Smarcel{
493130803Smarcel  if (regno < FP0_REGNUM)
494130803Smarcel    regcache_collect (regno, (char *) &a_tss + regno_mapping[regno].tss_ofs);
495130803Smarcel  else if (i386_fp_regnum_p (regno) || i386_fpc_regnum_p (regno))
496130803Smarcel    i387_fill_fsave ((char *) &npx, regno);
497130803Smarcel  else
498130803Smarcel    internal_error (__FILE__, __LINE__,
499130803Smarcel		    "Invalid register no. %d in store_register.", regno);
500130803Smarcel}
501130803Smarcel
502130803Smarcelstatic void
503130803Smarcelgo32_store_registers (int regno)
504130803Smarcel{
505130803Smarcel  unsigned r;
506130803Smarcel
507130803Smarcel  if (regno >= 0)
508130803Smarcel    store_register (regno);
509130803Smarcel  else
510130803Smarcel    {
511130803Smarcel      for (r = 0; r < FP0_REGNUM; r++)
512130803Smarcel	store_register (r);
513130803Smarcel      i387_fill_fsave ((char *) &npx, -1);
514130803Smarcel    }
515130803Smarcel}
516130803Smarcel
517130803Smarcelstatic void
518130803Smarcelgo32_prepare_to_store (void)
519130803Smarcel{
520130803Smarcel}
521130803Smarcel
522130803Smarcelstatic int
523130803Smarcelgo32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
524130803Smarcel		  struct mem_attrib *attrib, struct target_ops *target)
525130803Smarcel{
526130803Smarcel  if (write)
527130803Smarcel    {
528130803Smarcel      if (write_child (memaddr, myaddr, len))
529130803Smarcel	{
530130803Smarcel	  return 0;
531130803Smarcel	}
532130803Smarcel      else
533130803Smarcel	{
534130803Smarcel	  return len;
535130803Smarcel	}
536130803Smarcel    }
537130803Smarcel  else
538130803Smarcel    {
539130803Smarcel      if (read_child (memaddr, myaddr, len))
540130803Smarcel	{
541130803Smarcel	  return 0;
542130803Smarcel	}
543130803Smarcel      else
544130803Smarcel	{
545130803Smarcel	  return len;
546130803Smarcel	}
547130803Smarcel    }
548130803Smarcel}
549130803Smarcel
550130803Smarcelstatic cmdline_t child_cmd;	/* parsed child's command line kept here */
551130803Smarcel
552130803Smarcelstatic void
553130803Smarcelgo32_files_info (struct target_ops *target)
554130803Smarcel{
555130803Smarcel  printf_unfiltered ("You are running a DJGPP V2 program.\n");
556130803Smarcel}
557130803Smarcel
558130803Smarcelstatic void
559130803Smarcelgo32_stop (void)
560130803Smarcel{
561130803Smarcel  normal_stop ();
562130803Smarcel  cleanup_client ();
563130803Smarcel  inferior_ptid = null_ptid;
564130803Smarcel  prog_has_started = 0;
565130803Smarcel}
566130803Smarcel
567130803Smarcelstatic void
568130803Smarcelgo32_kill_inferior (void)
569130803Smarcel{
570130803Smarcel  redir_cmdline_delete (&child_cmd);
571130803Smarcel  resume_signal = -1;
572130803Smarcel  resume_is_step = 0;
573130803Smarcel  unpush_target (&go32_ops);
574130803Smarcel}
575130803Smarcel
576130803Smarcelstatic void
577130803Smarcelgo32_create_inferior (char *exec_file, char *args, char **env)
578130803Smarcel{
579130803Smarcel  extern char **environ;
580130803Smarcel  jmp_buf start_state;
581130803Smarcel  char *cmdline;
582130803Smarcel  char **env_save = environ;
583130803Smarcel  size_t cmdlen;
584130803Smarcel
585130803Smarcel  /* If no exec file handed to us, get it from the exec-file command -- with
586130803Smarcel     a good, common error message if none is specified.  */
587130803Smarcel  if (exec_file == 0)
588130803Smarcel    exec_file = get_exec_file (1);
589130803Smarcel
590130803Smarcel  if (prog_has_started)
591130803Smarcel    {
592130803Smarcel      go32_stop ();
593130803Smarcel      go32_kill_inferior ();
594130803Smarcel    }
595130803Smarcel  resume_signal = -1;
596130803Smarcel  resume_is_step = 0;
597130803Smarcel
598130803Smarcel  /* Initialize child's cwd as empty to be initialized when starting
599130803Smarcel     the child.  */
600130803Smarcel  *child_cwd = 0;
601130803Smarcel
602130803Smarcel  /* Init command line storage.  */
603130803Smarcel  if (redir_debug_init (&child_cmd) == -1)
604130803Smarcel    internal_error (__FILE__, __LINE__,
605130803Smarcel		    "Cannot allocate redirection storage: not enough memory.\n");
606130803Smarcel
607130803Smarcel  /* Parse the command line and create redirections.  */
608130803Smarcel  if (strpbrk (args, "<>"))
609130803Smarcel    {
610130803Smarcel      if (redir_cmdline_parse (args, &child_cmd) == 0)
611130803Smarcel	args = child_cmd.command;
612130803Smarcel      else
613130803Smarcel	error ("Syntax error in command line.");
614130803Smarcel    }
615130803Smarcel  else
616130803Smarcel    child_cmd.command = xstrdup (args);
617130803Smarcel
618130803Smarcel  cmdlen = strlen (args);
619130803Smarcel  /* v2loadimage passes command lines via DOS memory, so it cannot
620130803Smarcel     possibly handle commands longer than 1MB.  */
621130803Smarcel  if (cmdlen > 1024*1024)
622130803Smarcel    error ("Command line too long.");
623130803Smarcel
624130803Smarcel  cmdline = xmalloc (cmdlen + 4);
625130803Smarcel  strcpy (cmdline + 1, args);
626130803Smarcel  /* If the command-line length fits into DOS 126-char limits, use the
627130803Smarcel     DOS command tail format; otherwise, tell v2loadimage to pass it
628130803Smarcel     through a buffer in conventional memory.  */
629130803Smarcel  if (cmdlen < 127)
630130803Smarcel    {
631130803Smarcel      cmdline[0] = strlen (args);
632130803Smarcel      cmdline[cmdlen + 1] = 13;
633130803Smarcel    }
634130803Smarcel  else
635130803Smarcel    cmdline[0] = 0xff;	/* signal v2loadimage it's a long command */
636130803Smarcel
637130803Smarcel  environ = env;
638130803Smarcel
639130803Smarcel  if (v2loadimage (exec_file, cmdline, start_state))
640130803Smarcel    {
641130803Smarcel      environ = env_save;
642130803Smarcel      printf_unfiltered ("Load failed for image %s\n", exec_file);
643130803Smarcel      exit (1);
644130803Smarcel    }
645130803Smarcel  environ = env_save;
646130803Smarcel  xfree (cmdline);
647130803Smarcel
648130803Smarcel  edi_init (start_state);
649130803Smarcel#if __DJGPP_MINOR__ < 3
650130803Smarcel  save_npx ();
651130803Smarcel#endif
652130803Smarcel
653130803Smarcel  inferior_ptid = pid_to_ptid (SOME_PID);
654130803Smarcel  push_target (&go32_ops);
655130803Smarcel  clear_proceed_status ();
656130803Smarcel  insert_breakpoints ();
657130803Smarcel  proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
658130803Smarcel  prog_has_started = 1;
659130803Smarcel}
660130803Smarcel
661130803Smarcelstatic void
662130803Smarcelgo32_mourn_inferior (void)
663130803Smarcel{
664130803Smarcel  /* We need to make sure all the breakpoint enable bits in the DR7
665130803Smarcel     register are reset when the inferior exits.  Otherwise, if they
666130803Smarcel     rerun the inferior, the uncleared bits may cause random SIGTRAPs,
667130803Smarcel     failure to set more watchpoints, and other calamities.  It would
668130803Smarcel     be nice if GDB itself would take care to remove all breakpoints
669130803Smarcel     at all times, but it doesn't, probably under an assumption that
670130803Smarcel     the OS cleans up when the debuggee exits.  */
671130803Smarcel  i386_cleanup_dregs ();
672130803Smarcel  go32_kill_inferior ();
673130803Smarcel  generic_mourn_inferior ();
674130803Smarcel}
675130803Smarcel
676130803Smarcelstatic int
677130803Smarcelgo32_can_run (void)
678130803Smarcel{
679130803Smarcel  return 1;
680130803Smarcel}
681130803Smarcel
682130803Smarcel/* Hardware watchpoint support.  */
683130803Smarcel
684130803Smarcel#define D_REGS edi.dr
685130803Smarcel#define CONTROL D_REGS[7]
686130803Smarcel#define STATUS D_REGS[6]
687130803Smarcel
688130803Smarcel/* Pass the address ADDR to the inferior in the I'th debug register.
689130803Smarcel   Here we just store the address in D_REGS, the watchpoint will be
690130803Smarcel   actually set up when go32_wait runs the debuggee.  */
691130803Smarcelvoid
692130803Smarcelgo32_set_dr (int i, CORE_ADDR addr)
693130803Smarcel{
694130803Smarcel  if (i < 0 || i > 3)
695130803Smarcel    internal_error (__FILE__, __LINE__,
696130803Smarcel		    "Invalid register %d in go32_set_dr.\n", i);
697130803Smarcel  D_REGS[i] = addr;
698130803Smarcel}
699130803Smarcel
700130803Smarcel/* Pass the value VAL to the inferior in the DR7 debug control
701130803Smarcel   register.  Here we just store the address in D_REGS, the watchpoint
702130803Smarcel   will be actually set up when go32_wait runs the debuggee.  */
703130803Smarcelvoid
704130803Smarcelgo32_set_dr7 (unsigned val)
705130803Smarcel{
706130803Smarcel  CONTROL = val;
707130803Smarcel}
708130803Smarcel
709130803Smarcel/* Get the value of the DR6 debug status register from the inferior.
710130803Smarcel   Here we just return the value stored in D_REGS, as we've got it
711130803Smarcel   from the last go32_wait call.  */
712130803Smarcelunsigned
713130803Smarcelgo32_get_dr6 (void)
714130803Smarcel{
715130803Smarcel  return STATUS;
716130803Smarcel}
717130803Smarcel
718130803Smarcel/* Put the device open on handle FD into either raw or cooked
719130803Smarcel   mode, return 1 if it was in raw mode, zero otherwise.  */
720130803Smarcel
721130803Smarcelstatic int
722130803Smarceldevice_mode (int fd, int raw_p)
723130803Smarcel{
724130803Smarcel  int oldmode, newmode;
725130803Smarcel  __dpmi_regs regs;
726130803Smarcel
727130803Smarcel  regs.x.ax = 0x4400;
728130803Smarcel  regs.x.bx = fd;
729130803Smarcel  __dpmi_int (0x21, &regs);
730130803Smarcel  if (regs.x.flags & 1)
731130803Smarcel    return -1;
732130803Smarcel  newmode = oldmode = regs.x.dx;
733130803Smarcel
734130803Smarcel  if (raw_p)
735130803Smarcel    newmode |= 0x20;
736130803Smarcel  else
737130803Smarcel    newmode &= ~0x20;
738130803Smarcel
739130803Smarcel  if (oldmode & 0x80)	/* Only for character dev */
740130803Smarcel  {
741130803Smarcel    regs.x.ax = 0x4401;
742130803Smarcel    regs.x.bx = fd;
743130803Smarcel    regs.x.dx = newmode & 0xff;   /* Force upper byte zero, else it fails */
744130803Smarcel    __dpmi_int (0x21, &regs);
745130803Smarcel    if (regs.x.flags & 1)
746130803Smarcel      return -1;
747130803Smarcel  }
748130803Smarcel  return (oldmode & 0x20) == 0x20;
749130803Smarcel}
750130803Smarcel
751130803Smarcel
752130803Smarcelstatic int inf_mode_valid = 0;
753130803Smarcelstatic int inf_terminal_mode;
754130803Smarcel
755130803Smarcel/* This semaphore is needed because, amazingly enough, GDB calls
756130803Smarcel   target.to_terminal_ours more than once after the inferior stops.
757130803Smarcel   But we need the information from the first call only, since the
758130803Smarcel   second call will always see GDB's own cooked terminal.  */
759130803Smarcelstatic int terminal_is_ours = 1;
760130803Smarcel
761130803Smarcelstatic void
762130803Smarcelgo32_terminal_init (void)
763130803Smarcel{
764130803Smarcel  inf_mode_valid = 0;	/* reinitialize, in case they are restarting child */
765130803Smarcel  terminal_is_ours = 1;
766130803Smarcel}
767130803Smarcel
768130803Smarcelstatic void
769130803Smarcelgo32_terminal_info (char *args, int from_tty)
770130803Smarcel{
771130803Smarcel  printf_unfiltered ("Inferior's terminal is in %s mode.\n",
772130803Smarcel		     !inf_mode_valid
773130803Smarcel		     ? "default" : inf_terminal_mode ? "raw" : "cooked");
774130803Smarcel
775130803Smarcel#if __DJGPP_MINOR__ > 2
776130803Smarcel  if (child_cmd.redirection)
777130803Smarcel  {
778130803Smarcel    int i;
779130803Smarcel
780130803Smarcel    for (i = 0; i < DBG_HANDLES; i++)
781130803Smarcel    {
782130803Smarcel      if (child_cmd.redirection[i]->file_name)
783130803Smarcel	printf_unfiltered ("\tFile handle %d is redirected to `%s'.\n",
784130803Smarcel			   i, child_cmd.redirection[i]->file_name);
785130803Smarcel      else if (_get_dev_info (child_cmd.redirection[i]->inf_handle) == -1)
786130803Smarcel	printf_unfiltered
787130803Smarcel	  ("\tFile handle %d appears to be closed by inferior.\n", i);
788130803Smarcel      /* Mask off the raw/cooked bit when comparing device info words.  */
789130803Smarcel      else if ((_get_dev_info (child_cmd.redirection[i]->inf_handle) & 0xdf)
790130803Smarcel	       != (_get_dev_info (i) & 0xdf))
791130803Smarcel	printf_unfiltered
792130803Smarcel	  ("\tFile handle %d appears to be redirected by inferior.\n", i);
793130803Smarcel    }
794130803Smarcel  }
795130803Smarcel#endif
796130803Smarcel}
797130803Smarcel
798130803Smarcelstatic void
799130803Smarcelgo32_terminal_inferior (void)
800130803Smarcel{
801130803Smarcel  /* Redirect standard handles as child wants them.  */
802130803Smarcel  errno = 0;
803130803Smarcel  if (redir_to_child (&child_cmd) == -1)
804130803Smarcel  {
805130803Smarcel    redir_to_debugger (&child_cmd);
806130803Smarcel    error ("Cannot redirect standard handles for program: %s.",
807130803Smarcel	   safe_strerror (errno));
808130803Smarcel  }
809130803Smarcel  /* set the console device of the inferior to whatever mode
810130803Smarcel     (raw or cooked) we found it last time */
811130803Smarcel  if (terminal_is_ours)
812130803Smarcel  {
813130803Smarcel    if (inf_mode_valid)
814130803Smarcel      device_mode (0, inf_terminal_mode);
815130803Smarcel    terminal_is_ours = 0;
816130803Smarcel  }
817130803Smarcel}
818130803Smarcel
819130803Smarcelstatic void
820130803Smarcelgo32_terminal_ours (void)
821130803Smarcel{
822130803Smarcel  /* Switch to cooked mode on the gdb terminal and save the inferior
823130803Smarcel     terminal mode to be restored when it is resumed */
824130803Smarcel  if (!terminal_is_ours)
825130803Smarcel  {
826130803Smarcel    inf_terminal_mode = device_mode (0, 0);
827130803Smarcel    if (inf_terminal_mode != -1)
828130803Smarcel      inf_mode_valid = 1;
829130803Smarcel    else
830130803Smarcel      /* If device_mode returned -1, we don't know what happens with
831130803Smarcel	 handle 0 anymore, so make the info invalid.  */
832130803Smarcel      inf_mode_valid = 0;
833130803Smarcel    terminal_is_ours = 1;
834130803Smarcel
835130803Smarcel    /* Restore debugger's standard handles.  */
836130803Smarcel    errno = 0;
837130803Smarcel    if (redir_to_debugger (&child_cmd) == -1)
838130803Smarcel    {
839130803Smarcel      redir_to_child (&child_cmd);
840130803Smarcel      error ("Cannot redirect standard handles for debugger: %s.",
841130803Smarcel	     safe_strerror (errno));
842130803Smarcel    }
843130803Smarcel  }
844130803Smarcel}
845130803Smarcel
846130803Smarcelstatic void
847130803Smarcelinit_go32_ops (void)
848130803Smarcel{
849130803Smarcel  go32_ops.to_shortname = "djgpp";
850130803Smarcel  go32_ops.to_longname = "djgpp target process";
851130803Smarcel  go32_ops.to_doc =
852130803Smarcel    "Program loaded by djgpp, when gdb is used as an external debugger";
853130803Smarcel  go32_ops.to_open = go32_open;
854130803Smarcel  go32_ops.to_close = go32_close;
855130803Smarcel  go32_ops.to_attach = go32_attach;
856130803Smarcel  go32_ops.to_detach = go32_detach;
857130803Smarcel  go32_ops.to_resume = go32_resume;
858130803Smarcel  go32_ops.to_wait = go32_wait;
859130803Smarcel  go32_ops.to_fetch_registers = go32_fetch_registers;
860130803Smarcel  go32_ops.to_store_registers = go32_store_registers;
861130803Smarcel  go32_ops.to_prepare_to_store = go32_prepare_to_store;
862130803Smarcel  go32_ops.to_xfer_memory = go32_xfer_memory;
863130803Smarcel  go32_ops.to_files_info = go32_files_info;
864130803Smarcel  go32_ops.to_insert_breakpoint = memory_insert_breakpoint;
865130803Smarcel  go32_ops.to_remove_breakpoint = memory_remove_breakpoint;
866130803Smarcel  go32_ops.to_terminal_init = go32_terminal_init;
867130803Smarcel  go32_ops.to_terminal_inferior = go32_terminal_inferior;
868130803Smarcel  go32_ops.to_terminal_ours_for_output = go32_terminal_ours;
869130803Smarcel  go32_ops.to_terminal_ours = go32_terminal_ours;
870130803Smarcel  go32_ops.to_terminal_info = go32_terminal_info;
871130803Smarcel  go32_ops.to_kill = go32_kill_inferior;
872130803Smarcel  go32_ops.to_create_inferior = go32_create_inferior;
873130803Smarcel  go32_ops.to_mourn_inferior = go32_mourn_inferior;
874130803Smarcel  go32_ops.to_can_run = go32_can_run;
875130803Smarcel  go32_ops.to_stop = go32_stop;
876130803Smarcel  go32_ops.to_stratum = process_stratum;
877130803Smarcel  go32_ops.to_has_all_memory = 1;
878130803Smarcel  go32_ops.to_has_memory = 1;
879130803Smarcel  go32_ops.to_has_stack = 1;
880130803Smarcel  go32_ops.to_has_registers = 1;
881130803Smarcel  go32_ops.to_has_execution = 1;
882130803Smarcel  go32_ops.to_magic = OPS_MAGIC;
883130803Smarcel
884130803Smarcel  /* Initialize child's cwd as empty to be initialized when starting
885130803Smarcel     the child.  */
886130803Smarcel  *child_cwd = 0;
887130803Smarcel
888130803Smarcel  /* Initialize child's command line storage.  */
889130803Smarcel  if (redir_debug_init (&child_cmd) == -1)
890130803Smarcel    internal_error (__FILE__, __LINE__,
891130803Smarcel		    "Cannot allocate redirection storage: not enough memory.\n");
892130803Smarcel
893130803Smarcel  /* We are always processing GCC-compiled programs.  */
894130803Smarcel  processing_gcc_compilation = 2;
895130803Smarcel}
896130803Smarcel
897130803Smarcelunsigned short windows_major, windows_minor;
898130803Smarcel
899130803Smarcel/* Compute the version Windows reports via Int 2Fh/AX=1600h.  */
900130803Smarcelstatic void
901130803Smarcelgo32_get_windows_version(void)
902130803Smarcel{
903130803Smarcel  __dpmi_regs r;
904130803Smarcel
905130803Smarcel  r.x.ax = 0x1600;
906130803Smarcel  __dpmi_int(0x2f, &r);
907130803Smarcel  if (r.h.al > 2 && r.h.al != 0x80 && r.h.al != 0xff
908130803Smarcel      && (r.h.al > 3 || r.h.ah > 0))
909130803Smarcel    {
910130803Smarcel      windows_major = r.h.al;
911130803Smarcel      windows_minor = r.h.ah;
912130803Smarcel    }
913130803Smarcel  else
914130803Smarcel    windows_major = 0xff;	/* meaning no Windows */
915130803Smarcel}
916130803Smarcel
917130803Smarcel/* A subroutine of go32_sysinfo to display memory info.  */
918130803Smarcelstatic void
919130803Smarcelprint_mem (unsigned long datum, const char *header, int in_pages_p)
920130803Smarcel{
921130803Smarcel  if (datum != 0xffffffffUL)
922130803Smarcel    {
923130803Smarcel      if (in_pages_p)
924130803Smarcel	datum <<= 12;
925130803Smarcel      puts_filtered (header);
926130803Smarcel      if (datum > 1024)
927130803Smarcel	{
928130803Smarcel	  printf_filtered ("%lu KB", datum >> 10);
929130803Smarcel	  if (datum > 1024 * 1024)
930130803Smarcel	    printf_filtered (" (%lu MB)", datum >> 20);
931130803Smarcel	}
932130803Smarcel      else
933130803Smarcel	printf_filtered ("%lu Bytes", datum);
934130803Smarcel      puts_filtered ("\n");
935130803Smarcel    }
936130803Smarcel}
937130803Smarcel
938130803Smarcel/* Display assorted information about the underlying OS.  */
939130803Smarcelstatic void
940130803Smarcelgo32_sysinfo (char *arg, int from_tty)
941130803Smarcel{
942130803Smarcel  struct utsname u;
943130803Smarcel  char cpuid_vendor[13];
944130803Smarcel  unsigned cpuid_max = 0, cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
945130803Smarcel  unsigned true_dos_version = _get_dos_version (1);
946130803Smarcel  unsigned advertized_dos_version = ((unsigned int)_osmajor << 8) | _osminor;
947130803Smarcel  int dpmi_flags;
948130803Smarcel  char dpmi_vendor_info[129];
949130803Smarcel  int dpmi_vendor_available =
950130803Smarcel    __dpmi_get_capabilities (&dpmi_flags, dpmi_vendor_info);
951130803Smarcel  __dpmi_version_ret dpmi_version_data;
952130803Smarcel  long eflags;
953130803Smarcel  __dpmi_free_mem_info mem_info;
954130803Smarcel  __dpmi_regs regs;
955130803Smarcel
956130803Smarcel  cpuid_vendor[0] = '\0';
957130803Smarcel  if (uname (&u))
958130803Smarcel    strcpy (u.machine, "Unknown x86");
959130803Smarcel  else if (u.machine[0] == 'i' && u.machine[1] > 4)
960130803Smarcel    {
961130803Smarcel      /* CPUID with EAX = 0 returns the Vendor ID.  */
962130803Smarcel      __asm__ __volatile__ ("xorl   %%ebx, %%ebx;"
963130803Smarcel			    "xorl   %%ecx, %%ecx;"
964130803Smarcel			    "xorl   %%edx, %%edx;"
965130803Smarcel			    "movl   $0,    %%eax;"
966130803Smarcel			    "cpuid;"
967130803Smarcel			    "movl   %%ebx,  %0;"
968130803Smarcel			    "movl   %%edx,  %1;"
969130803Smarcel			    "movl   %%ecx,  %2;"
970130803Smarcel			    "movl   %%eax,  %3;"
971130803Smarcel			    : "=m" (cpuid_vendor[0]),
972130803Smarcel			      "=m" (cpuid_vendor[4]),
973130803Smarcel			      "=m" (cpuid_vendor[8]),
974130803Smarcel			      "=m" (cpuid_max)
975130803Smarcel			    :
976130803Smarcel			    : "%eax", "%ebx", "%ecx", "%edx");
977130803Smarcel      cpuid_vendor[12] = '\0';
978130803Smarcel    }
979130803Smarcel
980130803Smarcel  printf_filtered ("CPU Type.......................%s", u.machine);
981130803Smarcel  if (cpuid_vendor[0])
982130803Smarcel    printf_filtered (" (%s)", cpuid_vendor);
983130803Smarcel  puts_filtered ("\n");
984130803Smarcel
985130803Smarcel  /* CPUID with EAX = 1 returns processor signature and features.  */
986130803Smarcel  if (cpuid_max >= 1)
987130803Smarcel    {
988130803Smarcel      static char *brand_name[] = {
989130803Smarcel	"",
990130803Smarcel	" Celeron",
991130803Smarcel	" III",
992130803Smarcel	" III Xeon",
993130803Smarcel	"", "", "", "",
994130803Smarcel	" 4"
995130803Smarcel      };
996130803Smarcel      char cpu_string[80];
997130803Smarcel      char cpu_brand[20];
998130803Smarcel      unsigned brand_idx;
999130803Smarcel      int intel_p = strcmp (cpuid_vendor, "GenuineIntel") == 0;
1000130803Smarcel      int amd_p = strcmp (cpuid_vendor, "AuthenticAMD") == 0;
1001130803Smarcel      unsigned cpu_family, cpu_model;
1002130803Smarcel
1003130803Smarcel      __asm__ __volatile__ ("movl   $1, %%eax;"
1004130803Smarcel			    "cpuid;"
1005130803Smarcel			    : "=a" (cpuid_eax),
1006130803Smarcel			      "=b" (cpuid_ebx),
1007130803Smarcel			      "=d" (cpuid_edx)
1008130803Smarcel			    :
1009130803Smarcel			    : "%ecx");
1010130803Smarcel      brand_idx = cpuid_ebx & 0xff;
1011130803Smarcel      cpu_family = (cpuid_eax >> 8) & 0xf;
1012130803Smarcel      cpu_model  = (cpuid_eax >> 4) & 0xf;
1013130803Smarcel      cpu_brand[0] = '\0';
1014130803Smarcel      if (intel_p)
1015130803Smarcel	{
1016130803Smarcel	  if (brand_idx > 0
1017130803Smarcel	      && brand_idx < sizeof(brand_name)/sizeof(brand_name[0])
1018130803Smarcel	      && *brand_name[brand_idx])
1019130803Smarcel	    strcpy (cpu_brand, brand_name[brand_idx]);
1020130803Smarcel	  else if (cpu_family == 5)
1021130803Smarcel	    {
1022130803Smarcel	      if (((cpuid_eax >> 12) & 3) == 0 && cpu_model == 4)
1023130803Smarcel		strcpy (cpu_brand, " MMX");
1024130803Smarcel	      else if (cpu_model > 1 && ((cpuid_eax >> 12) & 3) == 1)
1025130803Smarcel		strcpy (cpu_brand, " OverDrive");
1026130803Smarcel	      else if (cpu_model > 1 && ((cpuid_eax >> 12) & 3) == 2)
1027130803Smarcel		strcpy (cpu_brand, " Dual");
1028130803Smarcel	    }
1029130803Smarcel	  else if (cpu_family == 6 && cpu_model < 8)
1030130803Smarcel	    {
1031130803Smarcel	      switch (cpu_model)
1032130803Smarcel		{
1033130803Smarcel		  case 1:
1034130803Smarcel		    strcpy (cpu_brand, " Pro");
1035130803Smarcel		    break;
1036130803Smarcel		  case 3:
1037130803Smarcel		    strcpy (cpu_brand, " II");
1038130803Smarcel		    break;
1039130803Smarcel		  case 5:
1040130803Smarcel		    strcpy (cpu_brand, " II Xeon");
1041130803Smarcel		    break;
1042130803Smarcel		  case 6:
1043130803Smarcel		    strcpy (cpu_brand, " Celeron");
1044130803Smarcel		    break;
1045130803Smarcel		  case 7:
1046130803Smarcel		    strcpy (cpu_brand, " III");
1047130803Smarcel		    break;
1048130803Smarcel		}
1049130803Smarcel	    }
1050130803Smarcel	}
1051130803Smarcel      else if (amd_p)
1052130803Smarcel	{
1053130803Smarcel	  switch (cpu_family)
1054130803Smarcel	    {
1055130803Smarcel	      case 4:
1056130803Smarcel		strcpy (cpu_brand, "486/5x86");
1057130803Smarcel		break;
1058130803Smarcel	      case 5:
1059130803Smarcel		switch (cpu_model)
1060130803Smarcel		  {
1061130803Smarcel		    case 0:
1062130803Smarcel		    case 1:
1063130803Smarcel		    case 2:
1064130803Smarcel		    case 3:
1065130803Smarcel		      strcpy (cpu_brand, "-K5");
1066130803Smarcel		      break;
1067130803Smarcel		    case 6:
1068130803Smarcel		    case 7:
1069130803Smarcel		      strcpy (cpu_brand, "-K6");
1070130803Smarcel		      break;
1071130803Smarcel		    case 8:
1072130803Smarcel		      strcpy (cpu_brand, "-K6-2");
1073130803Smarcel		      break;
1074130803Smarcel		    case 9:
1075130803Smarcel		      strcpy (cpu_brand, "-K6-III");
1076130803Smarcel		      break;
1077130803Smarcel		  }
1078130803Smarcel		break;
1079130803Smarcel	      case 6:
1080130803Smarcel		switch (cpu_model)
1081130803Smarcel		  {
1082130803Smarcel		    case 1:
1083130803Smarcel		    case 2:
1084130803Smarcel		    case 4:
1085130803Smarcel		      strcpy (cpu_brand, " Athlon");
1086130803Smarcel		      break;
1087130803Smarcel		    case 3:
1088130803Smarcel		      strcpy (cpu_brand, " Duron");
1089130803Smarcel		      break;
1090130803Smarcel		  }
1091130803Smarcel		break;
1092130803Smarcel	    }
1093130803Smarcel	}
1094130803Smarcel      sprintf (cpu_string, "%s%s Model %d Stepping %d",
1095130803Smarcel	       intel_p ? "Pentium" : (amd_p ? "AMD" : "ix86"),
1096130803Smarcel	       cpu_brand, cpu_model, cpuid_eax & 0xf);
1097130803Smarcel      printfi_filtered (31, "%s\n", cpu_string);
1098130803Smarcel      if (((cpuid_edx & (6 | (0x0d << 23))) != 0)
1099130803Smarcel	  || ((cpuid_edx & 1) == 0)
1100130803Smarcel	  || (amd_p && (cpuid_edx & (3 << 30)) != 0))
1101130803Smarcel	{
1102130803Smarcel	  puts_filtered ("CPU Features...................");
1103130803Smarcel	  /* We only list features which might be useful in the DPMI
1104130803Smarcel	     environment.  */
1105130803Smarcel	  if ((cpuid_edx & 1) == 0)
1106130803Smarcel	    puts_filtered ("No FPU "); /* it's unusual to not have an FPU */
1107130803Smarcel	  if ((cpuid_edx & (1 << 1)) != 0)
1108130803Smarcel	    puts_filtered ("VME ");
1109130803Smarcel	  if ((cpuid_edx & (1 << 2)) != 0)
1110130803Smarcel	    puts_filtered ("DE ");
1111130803Smarcel	  if ((cpuid_edx & (1 << 4)) != 0)
1112130803Smarcel	    puts_filtered ("TSC ");
1113130803Smarcel	  if ((cpuid_edx & (1 << 23)) != 0)
1114130803Smarcel	    puts_filtered ("MMX ");
1115130803Smarcel	  if ((cpuid_edx & (1 << 25)) != 0)
1116130803Smarcel	    puts_filtered ("SSE ");
1117130803Smarcel	  if ((cpuid_edx & (1 << 26)) != 0)
1118130803Smarcel	    puts_filtered ("SSE2 ");
1119130803Smarcel	  if (amd_p)
1120130803Smarcel	    {
1121130803Smarcel	      if ((cpuid_edx & (1 << 31)) != 0)
1122130803Smarcel		puts_filtered ("3DNow! ");
1123130803Smarcel	      if ((cpuid_edx & (1 << 30)) != 0)
1124130803Smarcel		puts_filtered ("3DNow!Ext");
1125130803Smarcel	    }
1126130803Smarcel	  puts_filtered ("\n");
1127130803Smarcel	}
1128130803Smarcel    }
1129130803Smarcel  puts_filtered ("\n");
1130130803Smarcel  printf_filtered ("DOS Version....................%s %s.%s",
1131130803Smarcel		   _os_flavor, u.release, u.version);
1132130803Smarcel  if (true_dos_version != advertized_dos_version)
1133130803Smarcel    printf_filtered (" (disguised as v%d.%d)", _osmajor, _osminor);
1134130803Smarcel  puts_filtered ("\n");
1135130803Smarcel  if (!windows_major)
1136130803Smarcel    go32_get_windows_version ();
1137130803Smarcel  if (windows_major != 0xff)
1138130803Smarcel    {
1139130803Smarcel      const char *windows_flavor;
1140130803Smarcel
1141130803Smarcel      printf_filtered ("Windows Version................%d.%02d (Windows ",
1142130803Smarcel		       windows_major, windows_minor);
1143130803Smarcel      switch (windows_major)
1144130803Smarcel	{
1145130803Smarcel	  case 3:
1146130803Smarcel	    windows_flavor = "3.X";
1147130803Smarcel	    break;
1148130803Smarcel	  case 4:
1149130803Smarcel	    switch (windows_minor)
1150130803Smarcel	      {
1151130803Smarcel		case 0:
1152130803Smarcel		  windows_flavor = "95, 95A, or 95B";
1153130803Smarcel		  break;
1154130803Smarcel		case 3:
1155130803Smarcel		  windows_flavor = "95B OSR2.1 or 95C OSR2.5";
1156130803Smarcel		  break;
1157130803Smarcel		case 10:
1158130803Smarcel		  windows_flavor = "98 or 98 SE";
1159130803Smarcel		  break;
1160130803Smarcel		case 90:
1161130803Smarcel		  windows_flavor = "ME";
1162130803Smarcel		  break;
1163130803Smarcel		default:
1164130803Smarcel		  windows_flavor = "9X";
1165130803Smarcel		  break;
1166130803Smarcel	      }
1167130803Smarcel	    break;
1168130803Smarcel	  default:
1169130803Smarcel	    windows_flavor = "??";
1170130803Smarcel	    break;
1171130803Smarcel	}
1172130803Smarcel      printf_filtered ("%s)\n", windows_flavor);
1173130803Smarcel    }
1174130803Smarcel  else if (true_dos_version == 0x532 && advertized_dos_version == 0x500)
1175130803Smarcel    printf_filtered ("Windows Version................Windows NT or Windows 2000\n");
1176130803Smarcel  puts_filtered ("\n");
1177130803Smarcel  if (dpmi_vendor_available == 0)
1178130803Smarcel    {
1179130803Smarcel      /* The DPMI spec says the vendor string should be ASCIIZ, but
1180130803Smarcel	 I don't trust the vendors to follow that...  */
1181130803Smarcel      if (!memchr (&dpmi_vendor_info[2], 0, 126))
1182130803Smarcel	dpmi_vendor_info[128] = '\0';
1183130803Smarcel      printf_filtered ("DPMI Host......................%s v%d.%d (capabilities: %#x)\n",
1184130803Smarcel		       &dpmi_vendor_info[2],
1185130803Smarcel		       (unsigned)dpmi_vendor_info[0],
1186130803Smarcel		       (unsigned)dpmi_vendor_info[1],
1187130803Smarcel		       ((unsigned)dpmi_flags & 0x7f));
1188130803Smarcel    }
1189130803Smarcel  __dpmi_get_version (&dpmi_version_data);
1190130803Smarcel  printf_filtered ("DPMI Version...................%d.%02d\n",
1191130803Smarcel		   dpmi_version_data.major, dpmi_version_data.minor);
1192130803Smarcel  printf_filtered ("DPMI Info......................%s-bit DPMI, with%s Virtual Memory support\n",
1193130803Smarcel		   (dpmi_version_data.flags & 1) ? "32" : "16",
1194130803Smarcel		   (dpmi_version_data.flags & 4) ? "" : "out");
1195130803Smarcel  printfi_filtered (31, "Interrupts reflected to %s mode\n",
1196130803Smarcel		   (dpmi_version_data.flags & 2) ? "V86" : "Real");
1197130803Smarcel  printfi_filtered (31, "Processor type: i%d86\n",
1198130803Smarcel		   dpmi_version_data.cpu);
1199130803Smarcel  printfi_filtered (31, "PIC base interrupt: Master: %#x  Slave: %#x\n",
1200130803Smarcel		   dpmi_version_data.master_pic, dpmi_version_data.slave_pic);
1201130803Smarcel
1202130803Smarcel  /* a_tss is only initialized when the debuggee is first run.  */
1203130803Smarcel  if (prog_has_started)
1204130803Smarcel    {
1205130803Smarcel      __asm__ __volatile__ ("pushfl ; popl %0" : "=g" (eflags));
1206130803Smarcel      printf_filtered ("Protection.....................Ring %d (in %s), with%s I/O protection\n",
1207130803Smarcel		       a_tss.tss_cs & 3, (a_tss.tss_cs & 4) ? "LDT" : "GDT",
1208130803Smarcel		       (a_tss.tss_cs & 3) > ((eflags >> 12) & 3) ? "" : "out");
1209130803Smarcel    }
1210130803Smarcel  puts_filtered ("\n");
1211130803Smarcel  __dpmi_get_free_memory_information (&mem_info);
1212130803Smarcel  print_mem (mem_info.total_number_of_physical_pages,
1213130803Smarcel	     "DPMI Total Physical Memory.....", 1);
1214130803Smarcel  print_mem (mem_info.total_number_of_free_pages,
1215130803Smarcel	     "DPMI Free Physical Memory......", 1);
1216130803Smarcel  print_mem (mem_info.size_of_paging_file_partition_in_pages,
1217130803Smarcel	     "DPMI Swap Space................", 1);
1218130803Smarcel  print_mem (mem_info.linear_address_space_size_in_pages,
1219130803Smarcel	     "DPMI Total Linear Address Size.", 1);
1220130803Smarcel  print_mem (mem_info.free_linear_address_space_in_pages,
1221130803Smarcel	     "DPMI Free Linear Address Size..", 1);
1222130803Smarcel  print_mem (mem_info.largest_available_free_block_in_bytes,
1223130803Smarcel	     "DPMI Largest Free Memory Block.", 0);
1224130803Smarcel
1225130803Smarcel  regs.h.ah = 0x48;
1226130803Smarcel  regs.x.bx = 0xffff;
1227130803Smarcel  __dpmi_int (0x21, &regs);
1228130803Smarcel  print_mem (regs.x.bx << 4, "Free DOS Memory................", 0);
1229130803Smarcel  regs.x.ax = 0x5800;
1230130803Smarcel  __dpmi_int (0x21, &regs);
1231130803Smarcel  if ((regs.x.flags & 1) == 0)
1232130803Smarcel    {
1233130803Smarcel      static const char *dos_hilo[] = {
1234130803Smarcel	"Low", "", "", "", "High", "", "", "", "High, then Low"
1235130803Smarcel      };
1236130803Smarcel      static const char *dos_fit[] = {
1237130803Smarcel	"First", "Best", "Last"
1238130803Smarcel      };
1239130803Smarcel      int hilo_idx = (regs.x.ax >> 4) & 0x0f;
1240130803Smarcel      int fit_idx  = regs.x.ax & 0x0f;
1241130803Smarcel
1242130803Smarcel      if (hilo_idx > 8)
1243130803Smarcel	hilo_idx = 0;
1244130803Smarcel      if (fit_idx > 2)
1245130803Smarcel	fit_idx = 0;
1246130803Smarcel      printf_filtered ("DOS Memory Allocation..........%s memory, %s fit\n",
1247130803Smarcel		       dos_hilo[hilo_idx], dos_fit[fit_idx]);
1248130803Smarcel      regs.x.ax = 0x5802;
1249130803Smarcel      __dpmi_int (0x21, &regs);
1250130803Smarcel      if ((regs.x.flags & 1) != 0)
1251130803Smarcel	regs.h.al = 0;
1252130803Smarcel      printfi_filtered (31, "UMBs %sin DOS memory chain\n",
1253130803Smarcel			regs.h.al == 0 ? "not " : "");
1254130803Smarcel    }
1255130803Smarcel}
1256130803Smarcel
1257130803Smarcelstruct seg_descr {
1258130803Smarcel  unsigned short limit0          __attribute__((packed));
1259130803Smarcel  unsigned short base0           __attribute__((packed));
1260130803Smarcel  unsigned char  base1           __attribute__((packed));
1261130803Smarcel  unsigned       stype:5         __attribute__((packed));
1262130803Smarcel  unsigned       dpl:2           __attribute__((packed));
1263130803Smarcel  unsigned       present:1       __attribute__((packed));
1264130803Smarcel  unsigned       limit1:4        __attribute__((packed));
1265130803Smarcel  unsigned       available:1     __attribute__((packed));
1266130803Smarcel  unsigned       dummy:1         __attribute__((packed));
1267130803Smarcel  unsigned       bit32:1         __attribute__((packed));
1268130803Smarcel  unsigned       page_granular:1 __attribute__((packed));
1269130803Smarcel  unsigned char  base2           __attribute__((packed));
1270130803Smarcel};
1271130803Smarcel
1272130803Smarcelstruct gate_descr {
1273130803Smarcel  unsigned short offset0         __attribute__((packed));
1274130803Smarcel  unsigned short selector        __attribute__((packed));
1275130803Smarcel  unsigned       param_count:5   __attribute__((packed));
1276130803Smarcel  unsigned       dummy:3         __attribute__((packed));
1277130803Smarcel  unsigned       stype:5         __attribute__((packed));
1278130803Smarcel  unsigned       dpl:2           __attribute__((packed));
1279130803Smarcel  unsigned       present:1       __attribute__((packed));
1280130803Smarcel  unsigned short offset1         __attribute__((packed));
1281130803Smarcel};
1282130803Smarcel
1283130803Smarcel/* Read LEN bytes starting at logical address ADDR, and put the result
1284130803Smarcel   into DEST.  Return 1 if success, zero if not.  */
1285130803Smarcelstatic int
1286130803Smarcelread_memory_region (unsigned long addr, void *dest, size_t len)
1287130803Smarcel{
1288130803Smarcel  unsigned long dos_ds_limit = __dpmi_get_segment_limit (_dos_ds);
1289130803Smarcel  int retval = 1;
1290130803Smarcel
1291130803Smarcel  /* For the low memory, we can simply use _dos_ds.  */
1292130803Smarcel  if (addr <= dos_ds_limit - len)
1293130803Smarcel    dosmemget (addr, len, dest);
1294130803Smarcel  else
1295130803Smarcel    {
1296130803Smarcel      /* For memory above 1MB we need to set up a special segment to
1297130803Smarcel	 be able to access that memory.  */
1298130803Smarcel      int sel = __dpmi_allocate_ldt_descriptors (1);
1299130803Smarcel
1300130803Smarcel      if (sel <= 0)
1301130803Smarcel	retval = 0;
1302130803Smarcel      else
1303130803Smarcel	{
1304130803Smarcel	  int access_rights = __dpmi_get_descriptor_access_rights (sel);
1305130803Smarcel	  size_t segment_limit = len - 1;
1306130803Smarcel
1307130803Smarcel	  /* Make sure the crucial bits in the descriptor access
1308130803Smarcel	     rights are set correctly.  Some DPMI providers might barf
1309130803Smarcel	     if we set the segment limit to something that is not an
1310130803Smarcel	     integral multiple of 4KB pages if the granularity bit is
1311130803Smarcel	     not set to byte-granular, even though the DPMI spec says
1312130803Smarcel	     it's the host's responsibility to set that bit correctly.  */
1313130803Smarcel	  if (len > 1024 * 1024)
1314130803Smarcel	    {
1315130803Smarcel	      access_rights |= 0x8000;
1316130803Smarcel	      /* Page-granular segments should have the low 12 bits of
1317130803Smarcel		 the limit set.  */
1318130803Smarcel	      segment_limit |= 0xfff;
1319130803Smarcel	    }
1320130803Smarcel	  else
1321130803Smarcel	    access_rights &= ~0x8000;
1322130803Smarcel
1323130803Smarcel	  if (__dpmi_set_segment_base_address (sel, addr) != -1
1324130803Smarcel	      && __dpmi_set_descriptor_access_rights (sel, access_rights) != -1
1325130803Smarcel	      && __dpmi_set_segment_limit (sel, segment_limit) != -1
1326130803Smarcel	      /* W2K silently fails to set the segment limit, leaving
1327130803Smarcel		 it at zero; this test avoids the resulting crash.  */
1328130803Smarcel	      && __dpmi_get_segment_limit (sel) >= segment_limit)
1329130803Smarcel	    movedata (sel, 0, _my_ds (), (unsigned)dest, len);
1330130803Smarcel	  else
1331130803Smarcel	    retval = 0;
1332130803Smarcel
1333130803Smarcel	  __dpmi_free_ldt_descriptor (sel);
1334130803Smarcel	}
1335130803Smarcel    }
1336130803Smarcel  return retval;
1337130803Smarcel}
1338130803Smarcel
1339130803Smarcel/* Get a segment descriptor stored at index IDX in the descriptor
1340130803Smarcel   table whose base address is TABLE_BASE.  Return the descriptor
1341130803Smarcel   type, or -1 if failure.  */
1342130803Smarcelstatic int
1343130803Smarcelget_descriptor (unsigned long table_base, int idx, void *descr)
1344130803Smarcel{
1345130803Smarcel  unsigned long addr = table_base + idx * 8; /* 8 bytes per entry */
1346130803Smarcel
1347130803Smarcel  if (read_memory_region (addr, descr, 8))
1348130803Smarcel    return (int)((struct seg_descr *)descr)->stype;
1349130803Smarcel  return -1;
1350130803Smarcel}
1351130803Smarcel
1352130803Smarcelstruct dtr_reg {
1353130803Smarcel  unsigned short limit __attribute__((packed));
1354130803Smarcel  unsigned long  base  __attribute__((packed));
1355130803Smarcel};
1356130803Smarcel
1357130803Smarcel/* Display a segment descriptor stored at index IDX in a descriptor
1358130803Smarcel   table whose type is TYPE and whose base address is BASE_ADDR.  If
1359130803Smarcel   FORCE is non-zero, display even invalid descriptors.  */
1360130803Smarcelstatic void
1361130803Smarceldisplay_descriptor (unsigned type, unsigned long base_addr, int idx, int force)
1362130803Smarcel{
1363130803Smarcel  struct seg_descr descr;
1364130803Smarcel  struct gate_descr gate;
1365130803Smarcel
1366130803Smarcel  /* Get the descriptor from the table.  */
1367130803Smarcel  if (idx == 0 && type == 0)
1368130803Smarcel    puts_filtered ("0x000: null descriptor\n");
1369130803Smarcel  else if (get_descriptor (base_addr, idx, &descr) != -1)
1370130803Smarcel    {
1371130803Smarcel      /* For each type of descriptor table, this has a bit set if the
1372130803Smarcel	 corresponding type of selectors is valid in that table.  */
1373130803Smarcel      static unsigned allowed_descriptors[] = {
1374130803Smarcel	  0xffffdafeL,   /* GDT */
1375130803Smarcel	  0x0000c0e0L,   /* IDT */
1376130803Smarcel	  0xffffdafaL    /* LDT */
1377130803Smarcel      };
1378130803Smarcel
1379130803Smarcel      /* If the program hasn't started yet, assume the debuggee will
1380130803Smarcel	 have the same CPL as the debugger.  */
1381130803Smarcel      int cpl = prog_has_started ? (a_tss.tss_cs & 3) : _my_cs () & 3;
1382130803Smarcel      unsigned long limit = (descr.limit1 << 16) | descr.limit0;
1383130803Smarcel
1384130803Smarcel      if (descr.present
1385130803Smarcel	  && (allowed_descriptors[type] & (1 << descr.stype)) != 0)
1386130803Smarcel	{
1387130803Smarcel	  printf_filtered ("0x%03x: ",
1388130803Smarcel			   type == 1
1389130803Smarcel			   ? idx : (idx * 8) | (type ? (cpl | 4) : 0));
1390130803Smarcel	  if (descr.page_granular)
1391130803Smarcel	    limit = (limit << 12) | 0xfff; /* big segment: low 12 bit set */
1392130803Smarcel	  if (descr.stype == 1 || descr.stype == 2 || descr.stype == 3
1393130803Smarcel	      || descr.stype == 9 || descr.stype == 11
1394130803Smarcel	      || (descr.stype >= 16 && descr.stype < 32))
1395130803Smarcel	    printf_filtered ("base=0x%02x%02x%04x limit=0x%08lx",
1396130803Smarcel			     descr.base2, descr.base1, descr.base0, limit);
1397130803Smarcel
1398130803Smarcel	  switch (descr.stype)
1399130803Smarcel	    {
1400130803Smarcel	      case 1:
1401130803Smarcel	      case 3:
1402130803Smarcel		printf_filtered (" 16-bit TSS  (task %sactive)",
1403130803Smarcel				 descr.stype == 3 ? "" : "in");
1404130803Smarcel		break;
1405130803Smarcel	      case 2:
1406130803Smarcel		puts_filtered (" LDT");
1407130803Smarcel		break;
1408130803Smarcel	      case 4:
1409130803Smarcel		memcpy (&gate, &descr, sizeof gate);
1410130803Smarcel		printf_filtered ("selector=0x%04x  offs=0x%04x%04x",
1411130803Smarcel				 gate.selector, gate.offset1, gate.offset0);
1412130803Smarcel		printf_filtered (" 16-bit Call Gate (params=%d)",
1413130803Smarcel				 gate.param_count);
1414130803Smarcel		break;
1415130803Smarcel	      case 5:
1416130803Smarcel		printf_filtered ("TSS selector=0x%04x", descr.base0);
1417130803Smarcel		printfi_filtered (16, "Task Gate");
1418130803Smarcel		break;
1419130803Smarcel	      case 6:
1420130803Smarcel	      case 7:
1421130803Smarcel		memcpy (&gate, &descr, sizeof gate);
1422130803Smarcel		printf_filtered ("selector=0x%04x  offs=0x%04x%04x",
1423130803Smarcel				 gate.selector, gate.offset1, gate.offset0);
1424130803Smarcel		printf_filtered (" 16-bit %s Gate",
1425130803Smarcel				 descr.stype == 6 ? "Interrupt" : "Trap");
1426130803Smarcel		break;
1427130803Smarcel	      case 9:
1428130803Smarcel	      case 11:
1429130803Smarcel		printf_filtered (" 32-bit TSS (task %sactive)",
1430130803Smarcel				 descr.stype == 3 ? "" : "in");
1431130803Smarcel		break;
1432130803Smarcel	      case 12:
1433130803Smarcel		memcpy (&gate, &descr, sizeof gate);
1434130803Smarcel		printf_filtered ("selector=0x%04x  offs=0x%04x%04x",
1435130803Smarcel				 gate.selector, gate.offset1, gate.offset0);
1436130803Smarcel		printf_filtered (" 32-bit Call Gate (params=%d)",
1437130803Smarcel				 gate.param_count);
1438130803Smarcel		break;
1439130803Smarcel	      case 14:
1440130803Smarcel	      case 15:
1441130803Smarcel		memcpy (&gate, &descr, sizeof gate);
1442130803Smarcel		printf_filtered ("selector=0x%04x  offs=0x%04x%04x",
1443130803Smarcel				 gate.selector, gate.offset1, gate.offset0);
1444130803Smarcel		printf_filtered (" 32-bit %s Gate",
1445130803Smarcel				 descr.stype == 14 ? "Interrupt" : "Trap");
1446130803Smarcel		break;
1447130803Smarcel	      case 16:		/* data segments */
1448130803Smarcel	      case 17:
1449130803Smarcel	      case 18:
1450130803Smarcel	      case 19:
1451130803Smarcel	      case 20:
1452130803Smarcel	      case 21:
1453130803Smarcel	      case 22:
1454130803Smarcel	      case 23:
1455130803Smarcel		printf_filtered (" %s-bit Data (%s Exp-%s%s)",
1456130803Smarcel				 descr.bit32 ? "32" : "16",
1457130803Smarcel				 descr.stype & 2 ? "Read/Write," : "Read-Only, ",
1458130803Smarcel				 descr.stype & 4 ? "down" : "up",
1459130803Smarcel				 descr.stype & 1 ? "" : ", N.Acc");
1460130803Smarcel		break;
1461130803Smarcel	      case 24:		/* code segments */
1462130803Smarcel	      case 25:
1463130803Smarcel	      case 26:
1464130803Smarcel	      case 27:
1465130803Smarcel	      case 28:
1466130803Smarcel	      case 29:
1467130803Smarcel	      case 30:
1468130803Smarcel	      case 31:
1469130803Smarcel		printf_filtered (" %s-bit Code (%s,  %sConf%s)",
1470130803Smarcel				 descr.bit32 ? "32" : "16",
1471130803Smarcel				 descr.stype & 2 ? "Exec/Read" : "Exec-Only",
1472130803Smarcel				 descr.stype & 4 ? "" : "N.",
1473130803Smarcel				 descr.stype & 1 ? "" : ", N.Acc");
1474130803Smarcel		break;
1475130803Smarcel	      default:
1476130803Smarcel		printf_filtered ("Unknown type 0x%02x", descr.stype);
1477130803Smarcel		break;
1478130803Smarcel	    }
1479130803Smarcel	  puts_filtered ("\n");
1480130803Smarcel	}
1481130803Smarcel      else if (force)
1482130803Smarcel	{
1483130803Smarcel	  printf_filtered ("0x%03x: ",
1484130803Smarcel			   type == 1
1485130803Smarcel			   ? idx : (idx * 8) | (type ? (cpl | 4) : 0));
1486130803Smarcel	  if (!descr.present)
1487130803Smarcel	    puts_filtered ("Segment not present\n");
1488130803Smarcel	  else
1489130803Smarcel	    printf_filtered ("Segment type 0x%02x is invalid in this table\n",
1490130803Smarcel			     descr.stype);
1491130803Smarcel	}
1492130803Smarcel    }
1493130803Smarcel  else if (force)
1494130803Smarcel    printf_filtered ("0x%03x: Cannot read this descriptor\n", idx);
1495130803Smarcel}
1496130803Smarcel
1497130803Smarcelstatic void
1498130803Smarcelgo32_sldt (char *arg, int from_tty)
1499130803Smarcel{
1500130803Smarcel  struct dtr_reg gdtr;
1501130803Smarcel  unsigned short ldtr = 0;
1502130803Smarcel  int ldt_idx;
1503130803Smarcel  struct seg_descr ldt_descr;
1504130803Smarcel  long ldt_entry = -1L;
1505130803Smarcel  int cpl = (prog_has_started ? a_tss.tss_cs : _my_cs ()) & 3;
1506130803Smarcel
1507130803Smarcel  if (arg && *arg)
1508130803Smarcel    {
1509130803Smarcel      while (*arg && isspace(*arg))
1510130803Smarcel	arg++;
1511130803Smarcel
1512130803Smarcel      if (*arg)
1513130803Smarcel	{
1514130803Smarcel	  ldt_entry = parse_and_eval_long (arg);
1515130803Smarcel	  if (ldt_entry < 0
1516130803Smarcel	      || (ldt_entry & 4) == 0
1517130803Smarcel	      || (ldt_entry & 3) != (cpl & 3))
1518130803Smarcel	    error ("Invalid LDT entry 0x%03lx.", (unsigned long)ldt_entry);
1519130803Smarcel	}
1520130803Smarcel    }
1521130803Smarcel
1522130803Smarcel  __asm__ __volatile__ ("sgdt   %0" : "=m" (gdtr) : /* no inputs */ );
1523130803Smarcel  __asm__ __volatile__ ("sldt   %0" : "=m" (ldtr) : /* no inputs */ );
1524130803Smarcel  ldt_idx = ldtr / 8;
1525130803Smarcel  if (ldt_idx == 0)
1526130803Smarcel    puts_filtered ("There is no LDT.\n");
1527130803Smarcel  /* LDT's entry in the GDT must have the type LDT, which is 2.  */
1528130803Smarcel  else if (get_descriptor (gdtr.base, ldt_idx, &ldt_descr) != 2)
1529130803Smarcel    printf_filtered ("LDT is present (at %#x), but unreadable by GDB.\n",
1530130803Smarcel		     ldt_descr.base0
1531130803Smarcel		     | (ldt_descr.base1 << 16)
1532130803Smarcel		     | (ldt_descr.base2 << 24));
1533130803Smarcel  else
1534130803Smarcel    {
1535130803Smarcel      unsigned base =
1536130803Smarcel	ldt_descr.base0
1537130803Smarcel	| (ldt_descr.base1 << 16)
1538130803Smarcel	| (ldt_descr.base2 << 24);
1539130803Smarcel      unsigned limit = ldt_descr.limit0 | (ldt_descr.limit1 << 16);
1540130803Smarcel      int max_entry;
1541130803Smarcel
1542130803Smarcel      if (ldt_descr.page_granular)
1543130803Smarcel	/* Page-granular segments must have the low 12 bits of their
1544130803Smarcel	   limit set.  */
1545130803Smarcel	limit = (limit << 12) | 0xfff;
1546130803Smarcel      /* LDT cannot have more than 8K 8-byte entries, i.e. more than
1547130803Smarcel	 64KB.  */
1548130803Smarcel      if (limit > 0xffff)
1549130803Smarcel	limit = 0xffff;
1550130803Smarcel
1551130803Smarcel      max_entry = (limit + 1) / 8;
1552130803Smarcel
1553130803Smarcel      if (ldt_entry >= 0)
1554130803Smarcel	{
1555130803Smarcel	  if (ldt_entry > limit)
1556130803Smarcel	    error ("Invalid LDT entry %#lx: outside valid limits [0..%#x]",
1557130803Smarcel		   (unsigned long)ldt_entry, limit);
1558130803Smarcel
1559130803Smarcel	  display_descriptor (ldt_descr.stype, base, ldt_entry / 8, 1);
1560130803Smarcel	}
1561130803Smarcel      else
1562130803Smarcel	{
1563130803Smarcel	  int i;
1564130803Smarcel
1565130803Smarcel	  for (i = 0; i < max_entry; i++)
1566130803Smarcel	    display_descriptor (ldt_descr.stype, base, i, 0);
1567130803Smarcel	}
1568130803Smarcel    }
1569130803Smarcel}
1570130803Smarcel
1571130803Smarcelstatic void
1572130803Smarcelgo32_sgdt (char *arg, int from_tty)
1573130803Smarcel{
1574130803Smarcel  struct dtr_reg gdtr;
1575130803Smarcel  long gdt_entry = -1L;
1576130803Smarcel  int max_entry;
1577130803Smarcel
1578130803Smarcel  if (arg && *arg)
1579130803Smarcel    {
1580130803Smarcel      while (*arg && isspace(*arg))
1581130803Smarcel	arg++;
1582130803Smarcel
1583130803Smarcel      if (*arg)
1584130803Smarcel	{
1585130803Smarcel	  gdt_entry = parse_and_eval_long (arg);
1586130803Smarcel	  if (gdt_entry < 0 || (gdt_entry & 7) != 0)
1587130803Smarcel	    error ("Invalid GDT entry 0x%03lx: not an integral multiple of 8.",
1588130803Smarcel		   (unsigned long)gdt_entry);
1589130803Smarcel	}
1590130803Smarcel    }
1591130803Smarcel
1592130803Smarcel  __asm__ __volatile__ ("sgdt   %0" : "=m" (gdtr) : /* no inputs */ );
1593130803Smarcel  max_entry = (gdtr.limit + 1) / 8;
1594130803Smarcel
1595130803Smarcel  if (gdt_entry >= 0)
1596130803Smarcel    {
1597130803Smarcel      if (gdt_entry > gdtr.limit)
1598130803Smarcel	error ("Invalid GDT entry %#lx: outside valid limits [0..%#x]",
1599130803Smarcel	       (unsigned long)gdt_entry, gdtr.limit);
1600130803Smarcel
1601130803Smarcel      display_descriptor (0, gdtr.base, gdt_entry / 8, 1);
1602130803Smarcel    }
1603130803Smarcel  else
1604130803Smarcel    {
1605130803Smarcel      int i;
1606130803Smarcel
1607130803Smarcel      for (i = 0; i < max_entry; i++)
1608130803Smarcel	display_descriptor (0, gdtr.base, i, 0);
1609130803Smarcel    }
1610130803Smarcel}
1611130803Smarcel
1612130803Smarcelstatic void
1613130803Smarcelgo32_sidt (char *arg, int from_tty)
1614130803Smarcel{
1615130803Smarcel  struct dtr_reg idtr;
1616130803Smarcel  long idt_entry = -1L;
1617130803Smarcel  int max_entry;
1618130803Smarcel
1619130803Smarcel  if (arg && *arg)
1620130803Smarcel    {
1621130803Smarcel      while (*arg && isspace(*arg))
1622130803Smarcel	arg++;
1623130803Smarcel
1624130803Smarcel      if (*arg)
1625130803Smarcel	{
1626130803Smarcel	  idt_entry = parse_and_eval_long (arg);
1627130803Smarcel	  if (idt_entry < 0)
1628130803Smarcel	    error ("Invalid (negative) IDT entry %ld.", idt_entry);
1629130803Smarcel	}
1630130803Smarcel    }
1631130803Smarcel
1632130803Smarcel  __asm__ __volatile__ ("sidt   %0" : "=m" (idtr) : /* no inputs */ );
1633130803Smarcel  max_entry = (idtr.limit + 1) / 8;
1634130803Smarcel  if (max_entry > 0x100)	/* no more than 256 entries */
1635130803Smarcel    max_entry = 0x100;
1636130803Smarcel
1637130803Smarcel  if (idt_entry >= 0)
1638130803Smarcel    {
1639130803Smarcel      if (idt_entry > idtr.limit)
1640130803Smarcel	error ("Invalid IDT entry %#lx: outside valid limits [0..%#x]",
1641130803Smarcel	       (unsigned long)idt_entry, idtr.limit);
1642130803Smarcel
1643130803Smarcel      display_descriptor (1, idtr.base, idt_entry, 1);
1644130803Smarcel    }
1645130803Smarcel  else
1646130803Smarcel    {
1647130803Smarcel      int i;
1648130803Smarcel
1649130803Smarcel      for (i = 0; i < max_entry; i++)
1650130803Smarcel	display_descriptor (1, idtr.base, i, 0);
1651130803Smarcel    }
1652130803Smarcel}
1653130803Smarcel
1654130803Smarcel/* Cached linear address of the base of the page directory.  For
1655130803Smarcel   now, available only under CWSDPMI.  Code based on ideas and
1656130803Smarcel   suggestions from Charles Sandmann <sandmann@clio.rice.edu>.  */
1657130803Smarcelstatic unsigned long pdbr;
1658130803Smarcel
1659130803Smarcelstatic unsigned long
1660130803Smarcelget_cr3 (void)
1661130803Smarcel{
1662130803Smarcel  unsigned offset;
1663130803Smarcel  unsigned taskreg;
1664130803Smarcel  unsigned long taskbase, cr3;
1665130803Smarcel  struct dtr_reg gdtr;
1666130803Smarcel
1667130803Smarcel  if (pdbr > 0 && pdbr <= 0xfffff)
1668130803Smarcel    return pdbr;
1669130803Smarcel
1670130803Smarcel  /* Get the linear address of GDT and the Task Register.  */
1671130803Smarcel  __asm__ __volatile__ ("sgdt   %0" : "=m" (gdtr) : /* no inputs */ );
1672130803Smarcel  __asm__ __volatile__ ("str    %0" : "=m" (taskreg) : /* no inputs */ );
1673130803Smarcel
1674130803Smarcel  /* Task Register is a segment selector for the TSS of the current
1675130803Smarcel     task.  Therefore, it can be used as an index into the GDT to get
1676130803Smarcel     at the segment descriptor for the TSS.  To get the index, reset
1677130803Smarcel     the low 3 bits of the selector (which give the CPL).  Add 2 to the
1678130803Smarcel     offset to point to the 3 low bytes of the base address.  */
1679130803Smarcel  offset = gdtr.base + (taskreg & 0xfff8) + 2;
1680130803Smarcel
1681130803Smarcel
1682130803Smarcel  /* CWSDPMI's task base is always under the 1MB mark.  */
1683130803Smarcel  if (offset > 0xfffff)
1684130803Smarcel    return 0;
1685130803Smarcel
1686130803Smarcel  _farsetsel (_dos_ds);
1687130803Smarcel  taskbase  = _farnspeekl (offset) & 0xffffffU;
1688130803Smarcel  taskbase += _farnspeekl (offset + 2) & 0xff000000U;
1689130803Smarcel  if (taskbase > 0xfffff)
1690130803Smarcel    return 0;
1691130803Smarcel
1692130803Smarcel  /* CR3 (a.k.a. PDBR, the Page Directory Base Register) is stored at
1693130803Smarcel     offset 1Ch in the TSS.  */
1694130803Smarcel  cr3 = _farnspeekl (taskbase + 0x1c) & ~0xfff;
1695130803Smarcel  if (cr3 > 0xfffff)
1696130803Smarcel    {
1697130803Smarcel#if 0  /* not fullly supported yet */
1698130803Smarcel      /* The Page Directory is in UMBs.  In that case, CWSDPMI puts
1699130803Smarcel	 the first Page Table right below the Page Directory.  Thus,
1700130803Smarcel	 the first Page Table's entry for its own address and the Page
1701130803Smarcel	 Directory entry for that Page Table will hold the same
1702130803Smarcel	 physical address.  The loop below searches the entire UMB
1703130803Smarcel	 range of addresses for such an occurence.  */
1704130803Smarcel      unsigned long addr, pte_idx;
1705130803Smarcel
1706130803Smarcel      for (addr = 0xb0000, pte_idx = 0xb0;
1707130803Smarcel	   pte_idx < 0xff;
1708130803Smarcel	   addr += 0x1000, pte_idx++)
1709130803Smarcel	{
1710130803Smarcel	  if (((_farnspeekl (addr + 4 * pte_idx) & 0xfffff027) ==
1711130803Smarcel	       (_farnspeekl (addr + 0x1000) & 0xfffff027))
1712130803Smarcel	      && ((_farnspeekl (addr + 4 * pte_idx + 4) & 0xfffff000) == cr3))
1713130803Smarcel	    {
1714130803Smarcel	      cr3 = addr + 0x1000;
1715130803Smarcel	      break;
1716130803Smarcel	    }
1717130803Smarcel	}
1718130803Smarcel#endif
1719130803Smarcel
1720130803Smarcel      if (cr3 > 0xfffff)
1721130803Smarcel	cr3 = 0;
1722130803Smarcel    }
1723130803Smarcel
1724130803Smarcel  return cr3;
1725130803Smarcel}
1726130803Smarcel
1727130803Smarcel/* Return the N'th Page Directory entry.  */
1728130803Smarcelstatic unsigned long
1729130803Smarcelget_pde (int n)
1730130803Smarcel{
1731130803Smarcel  unsigned long pde = 0;
1732130803Smarcel
1733130803Smarcel  if (pdbr && n >= 0 && n < 1024)
1734130803Smarcel    {
1735130803Smarcel      pde = _farpeekl (_dos_ds, pdbr + 4*n);
1736130803Smarcel    }
1737130803Smarcel  return pde;
1738130803Smarcel}
1739130803Smarcel
1740130803Smarcel/* Return the N'th entry of the Page Table whose Page Directory entry
1741130803Smarcel   is PDE.  */
1742130803Smarcelstatic unsigned long
1743130803Smarcelget_pte (unsigned long pde, int n)
1744130803Smarcel{
1745130803Smarcel  unsigned long pte = 0;
1746130803Smarcel
1747130803Smarcel  /* pde & 0x80 tests the 4MB page bit.  We don't support 4MB
1748130803Smarcel     page tables, for now.  */
1749130803Smarcel  if ((pde & 1) && !(pde & 0x80) && n >= 0 && n < 1024)
1750130803Smarcel    {
1751130803Smarcel      pde &= ~0xfff;	/* clear non-address bits */
1752130803Smarcel      pte = _farpeekl (_dos_ds, pde + 4*n);
1753130803Smarcel    }
1754130803Smarcel  return pte;
1755130803Smarcel}
1756130803Smarcel
1757130803Smarcel/* Display a Page Directory or Page Table entry.  IS_DIR, if non-zero,
1758130803Smarcel   says this is a Page Directory entry.  If FORCE is non-zero, display
1759130803Smarcel   the entry even if its Present flag is off.  OFF is the offset of the
1760130803Smarcel   address from the page's base address.  */
1761130803Smarcelstatic void
1762130803Smarceldisplay_ptable_entry (unsigned long entry, int is_dir, int force, unsigned off)
1763130803Smarcel{
1764130803Smarcel  if ((entry & 1) != 0)
1765130803Smarcel    {
1766130803Smarcel      printf_filtered ("Base=0x%05lx000", entry >> 12);
1767130803Smarcel      if ((entry & 0x100) && !is_dir)
1768130803Smarcel	puts_filtered (" Global");
1769130803Smarcel      if ((entry & 0x40) && !is_dir)
1770130803Smarcel	puts_filtered (" Dirty");
1771130803Smarcel      printf_filtered (" %sAcc.", (entry & 0x20) ? "" : "Not-");
1772130803Smarcel      printf_filtered (" %sCached", (entry & 0x10) ? "" : "Not-");
1773130803Smarcel      printf_filtered (" Write-%s", (entry & 8) ? "Thru" : "Back");
1774130803Smarcel      printf_filtered (" %s", (entry & 4) ? "Usr" : "Sup");
1775130803Smarcel      printf_filtered (" Read-%s", (entry & 2) ? "Write" : "Only");
1776130803Smarcel      if (off)
1777130803Smarcel	printf_filtered (" +0x%x", off);
1778130803Smarcel      puts_filtered ("\n");
1779130803Smarcel    }
1780130803Smarcel  else if (force)
1781130803Smarcel    printf_filtered ("Page%s not present or not supported; value=0x%lx.\n",
1782130803Smarcel		     is_dir ? " Table" : "", entry >> 1);
1783130803Smarcel}
1784130803Smarcel
1785130803Smarcelstatic void
1786130803Smarcelgo32_pde (char *arg, int from_tty)
1787130803Smarcel{
1788130803Smarcel  long pde_idx = -1, i;
1789130803Smarcel
1790130803Smarcel  if (arg && *arg)
1791130803Smarcel    {
1792130803Smarcel      while (*arg && isspace(*arg))
1793130803Smarcel	arg++;
1794130803Smarcel
1795130803Smarcel      if (*arg)
1796130803Smarcel	{
1797130803Smarcel	  pde_idx = parse_and_eval_long (arg);
1798130803Smarcel	  if (pde_idx < 0 || pde_idx >= 1024)
1799130803Smarcel	    error ("Entry %ld is outside valid limits [0..1023].", pde_idx);
1800130803Smarcel	}
1801130803Smarcel    }
1802130803Smarcel
1803130803Smarcel  pdbr = get_cr3 ();
1804130803Smarcel  if (!pdbr)
1805130803Smarcel    puts_filtered ("Access to Page Directories is not supported on this system.\n");
1806130803Smarcel  else if (pde_idx >= 0)
1807130803Smarcel    display_ptable_entry (get_pde (pde_idx), 1, 1, 0);
1808130803Smarcel  else
1809130803Smarcel    for (i = 0; i < 1024; i++)
1810130803Smarcel      display_ptable_entry (get_pde (i), 1, 0, 0);
1811130803Smarcel}
1812130803Smarcel
1813130803Smarcel/* A helper function to display entries in a Page Table pointed to by
1814130803Smarcel   the N'th entry in the Page Directory.  If FORCE is non-zero, say
1815130803Smarcel   something even if the Page Table is not accessible.  */
1816130803Smarcelstatic void
1817130803Smarceldisplay_page_table (long n, int force)
1818130803Smarcel{
1819130803Smarcel  unsigned long pde = get_pde (n);
1820130803Smarcel
1821130803Smarcel  if ((pde & 1) != 0)
1822130803Smarcel    {
1823130803Smarcel      int i;
1824130803Smarcel
1825130803Smarcel      printf_filtered ("Page Table pointed to by Page Directory entry 0x%lx:\n", n);
1826130803Smarcel      for (i = 0; i < 1024; i++)
1827130803Smarcel	display_ptable_entry (get_pte (pde, i), 0, 0, 0);
1828130803Smarcel      puts_filtered ("\n");
1829130803Smarcel    }
1830130803Smarcel  else if (force)
1831130803Smarcel    printf_filtered ("Page Table not present; value=0x%lx.\n", pde >> 1);
1832130803Smarcel}
1833130803Smarcel
1834130803Smarcelstatic void
1835130803Smarcelgo32_pte (char *arg, int from_tty)
1836130803Smarcel{
1837130803Smarcel  long pde_idx = -1L, i;
1838130803Smarcel
1839130803Smarcel  if (arg && *arg)
1840130803Smarcel    {
1841130803Smarcel      while (*arg && isspace(*arg))
1842130803Smarcel	arg++;
1843130803Smarcel
1844130803Smarcel      if (*arg)
1845130803Smarcel	{
1846130803Smarcel	  pde_idx = parse_and_eval_long (arg);
1847130803Smarcel	  if (pde_idx < 0 || pde_idx >= 1024)
1848130803Smarcel	    error ("Entry %ld is outside valid limits [0..1023].", pde_idx);
1849130803Smarcel	}
1850130803Smarcel    }
1851130803Smarcel
1852130803Smarcel  pdbr = get_cr3 ();
1853130803Smarcel  if (!pdbr)
1854130803Smarcel    puts_filtered ("Access to Page Tables is not supported on this system.\n");
1855130803Smarcel  else if (pde_idx >= 0)
1856130803Smarcel    display_page_table (pde_idx, 1);
1857130803Smarcel  else
1858130803Smarcel    for (i = 0; i < 1024; i++)
1859130803Smarcel      display_page_table (i, 0);
1860130803Smarcel}
1861130803Smarcel
1862130803Smarcelstatic void
1863130803Smarcelgo32_pte_for_address (char *arg, int from_tty)
1864130803Smarcel{
1865130803Smarcel  CORE_ADDR addr = 0, i;
1866130803Smarcel
1867130803Smarcel  if (arg && *arg)
1868130803Smarcel    {
1869130803Smarcel      while (*arg && isspace(*arg))
1870130803Smarcel	arg++;
1871130803Smarcel
1872130803Smarcel      if (*arg)
1873130803Smarcel	addr = parse_and_eval_address (arg);
1874130803Smarcel    }
1875130803Smarcel  if (!addr)
1876130803Smarcel    error_no_arg ("linear address");
1877130803Smarcel
1878130803Smarcel  pdbr = get_cr3 ();
1879130803Smarcel  if (!pdbr)
1880130803Smarcel    puts_filtered ("Access to Page Tables is not supported on this system.\n");
1881130803Smarcel  else
1882130803Smarcel    {
1883130803Smarcel      int pde_idx = (addr >> 22) & 0x3ff;
1884130803Smarcel      int pte_idx = (addr >> 12) & 0x3ff;
1885130803Smarcel      unsigned offs = addr & 0xfff;
1886130803Smarcel
1887130803Smarcel      printf_filtered ("Page Table entry for address 0x%llx:\n",
1888130803Smarcel		       (unsigned long long)addr);
1889130803Smarcel      display_ptable_entry (get_pte (get_pde (pde_idx), pte_idx), 0, 1, offs);
1890130803Smarcel    }
1891130803Smarcel}
1892130803Smarcel
1893130803Smarcelstatic struct cmd_list_element *info_dos_cmdlist = NULL;
1894130803Smarcel
1895130803Smarcelstatic void
1896130803Smarcelgo32_info_dos_command (char *args, int from_tty)
1897130803Smarcel{
1898130803Smarcel  help_list (info_dos_cmdlist, "info dos ", class_info, gdb_stdout);
1899130803Smarcel}
1900130803Smarcel
1901130803Smarcelvoid
1902130803Smarcel_initialize_go32_nat (void)
1903130803Smarcel{
1904130803Smarcel  init_go32_ops ();
1905130803Smarcel  add_target (&go32_ops);
1906130803Smarcel
1907130803Smarcel  add_prefix_cmd ("dos", class_info, go32_info_dos_command,
1908130803Smarcel		  "Print information specific to DJGPP (aka MS-DOS) debugging.",
1909130803Smarcel		  &info_dos_cmdlist, "info dos ", 0, &infolist);
1910130803Smarcel
1911130803Smarcel  add_cmd ("sysinfo", class_info, go32_sysinfo,
1912130803Smarcel	    "Display information about the target system, including CPU, OS, DPMI, etc.",
1913130803Smarcel	   &info_dos_cmdlist);
1914130803Smarcel  add_cmd ("ldt", class_info, go32_sldt,
1915130803Smarcel	   "Display entries in the LDT (Local Descriptor Table).\n"
1916130803Smarcel	   "Entry number (an expression) as an argument means display only that entry.",
1917130803Smarcel	   &info_dos_cmdlist);
1918130803Smarcel  add_cmd ("gdt", class_info, go32_sgdt,
1919130803Smarcel	   "Display entries in the GDT (Global Descriptor Table).\n"
1920130803Smarcel	   "Entry number (an expression) as an argument means display only that entry.",
1921130803Smarcel	   &info_dos_cmdlist);
1922130803Smarcel  add_cmd ("idt", class_info, go32_sidt,
1923130803Smarcel	   "Display entries in the IDT (Interrupt Descriptor Table).\n"
1924130803Smarcel	   "Entry number (an expression) as an argument means display only that entry.",
1925130803Smarcel	   &info_dos_cmdlist);
1926130803Smarcel  add_cmd ("pde", class_info, go32_pde,
1927130803Smarcel	   "Display entries in the Page Directory.\n"
1928130803Smarcel	   "Entry number (an expression) as an argument means display only that entry.",
1929130803Smarcel	   &info_dos_cmdlist);
1930130803Smarcel  add_cmd ("pte", class_info, go32_pte,
1931130803Smarcel	   "Display entries in Page Tables.\n"
1932130803Smarcel	   "Entry number (an expression) as an argument means display only entries\n"
1933130803Smarcel	   "from the Page Table pointed to by the specified Page Directory entry.",
1934130803Smarcel	   &info_dos_cmdlist);
1935130803Smarcel  add_cmd ("address-pte", class_info, go32_pte_for_address,
1936130803Smarcel	   "Display a Page Table entry for a linear address.\n"
1937130803Smarcel	   "The address argument must be a linear address, after adding to\n"
1938130803Smarcel	   "it the base address of the appropriate segment.\n"
1939130803Smarcel	   "The base address of variables and functions in the debuggee's data\n"
1940130803Smarcel	   "or code segment is stored in the variable __djgpp_base_address,\n"
1941130803Smarcel	   "so use `__djgpp_base_address + (char *)&var' as the argument.\n"
1942130803Smarcel	   "For other segments, look up their base address in the output of\n"
1943130803Smarcel	   "the `info dos ldt' command.",
1944130803Smarcel	   &info_dos_cmdlist);
1945130803Smarcel}
1946130803Smarcel
1947130803Smarcelpid_t
1948130803Smarceltcgetpgrp (int fd)
1949130803Smarcel{
1950130803Smarcel  if (isatty (fd))
1951130803Smarcel    return SOME_PID;
1952130803Smarcel  errno = ENOTTY;
1953130803Smarcel  return -1;
1954130803Smarcel}
1955130803Smarcel
1956130803Smarcelint
1957130803Smarceltcsetpgrp (int fd, pid_t pgid)
1958130803Smarcel{
1959130803Smarcel  if (isatty (fd) && pgid == SOME_PID)
1960130803Smarcel    return 0;
1961130803Smarcel  errno = pgid == SOME_PID ? ENOTTY : ENOSYS;
1962130803Smarcel  return -1;
1963130803Smarcel}
1964