/* Native debugging support for Intel x86 running DJGPP.
- Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1999, 2000, 2001, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
Written by Robert Hoehne.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <fcntl.h>
#include "gdb_wait.h"
#include "gdbcore.h"
#include "command.h"
+#include "gdbcmd.h"
#include "floatformat.h"
#include "buildsym.h"
-#include "i387-nat.h"
+#include "i387-tdep.h"
+#include "i386-tdep.h"
#include "value.h"
#include "regcache.h"
#include "gdb_string.h"
+#include "top.h"
#include <stdio.h> /* might be required for __DJGPP_MINOR__ */
#include <stdlib.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <io.h>
-/* breakpoint.h defines `disable' which is an enum member. */
-#define disable interrup_disable
#include <dos.h>
-#undef disable
#include <dpmi.h>
#include <go32.h>
+#include <sys/farptr.h>
#include <debug/v2load.h>
#include <debug/dbgcom.h>
#if __DJGPP_MINOR__ > 2
static void
save_npx (void)
{
- asm ("inb $0xa0, %%al
- testb $0x20, %%al
- jz 1f
- xorb %% al, %%al
- outb %% al, $0xf0
- movb $0x20, %%al
- outb %% al, $0xa0
- outb %% al, $0x20
-1:
- fnsave % 0
+ asm ("inb $0xa0, %%al \n\
+ testb $0x20, %%al \n\
+ jz 1f \n\
+ xorb %%al, %%al \n\
+ outb %%al, $0xf0 \n\
+ movb $0x20, %%al \n\
+ outb %%al, $0xa0 \n\
+ outb %%al, $0x20 \n\
+1: \n\
+ fnsave %0 \n\
fwait "
: "=m" (npx)
: /* No input */
/* *INDENT-ON* */
-
-
-
/* ------------------------------------------------------------------------- */
/* Reload the contents of the NPX from the global variable `npx'. */
enum target_signal siggnal);
static ptid_t go32_wait (ptid_t ptid,
struct target_waitstatus *status);
-static void go32_fetch_registers (int regno);
-static void store_register (int regno);
-static void go32_store_registers (int regno);
-static void go32_prepare_to_store (void);
+static void go32_fetch_registers (struct regcache *, int regno);
+static void store_register (const struct regcache *, int regno);
+static void go32_store_registers (struct regcache *, int regno);
+static void go32_prepare_to_store (struct regcache *);
static int go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
int write,
struct mem_attrib *attrib,
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 go32_create_inferior (char *exec_file, char *args, char **env, int from_tty);
static void go32_mourn_inferior (void);
static int go32_can_run (void);
static void
go32_attach (char *args, int from_tty)
{
- error ("\
+ error (_("\
You cannot attach to a running program on this platform.\n\
-Use the `run' command to run DJGPP programs.");
+Use the `run' command to run DJGPP programs."));
}
static void
}
static void
-fetch_register (int regno)
+fetch_register (struct regcache *regcache, int regno)
{
- 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);
+ if (regno < gdbarch_fp0_regnum (get_regcache_arch (regcache)))
+ regcache_raw_supply (regcache, regno,
+ (char *) &a_tss + regno_mapping[regno].tss_ofs);
+ else if (i386_fp_regnum_p (regno) || i386_fpc_regnum_p (regno))
+ i387_supply_fsave (regcache, regno, &npx);
else
internal_error (__FILE__, __LINE__,
- "Invalid register no. %d in fetch_register.", regno);
+ _("Invalid register no. %d in fetch_register."), regno);
}
static void
-go32_fetch_registers (int regno)
+go32_fetch_registers (struct regcache *regcache, int regno)
{
if (regno >= 0)
- fetch_register (regno);
+ fetch_register (regcache, regno);
else
{
- for (regno = 0; regno < FP0_REGNUM; regno++)
- fetch_register (regno);
- i387_supply_fsave ((char *) &npx);
+ for (regno = 0;
+ regno < gdbarch_fp0_regnum (get_regcache_arch (regcache));
+ regno++)
+ fetch_register (regcache, regno);
+ i387_supply_fsave (regcache, -1, &npx);
}
}
static void
-store_register (int regno)
+store_register (const struct regcache *regcache, int regno)
{
- void *rp;
- 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);
+ if (regno < gdbarch_fp0_regnum (get_regcache_arch (regcache)))
+ regcache_raw_collect (regcache, regno,
+ (char *) &a_tss + regno_mapping[regno].tss_ofs);
+ else if (i386_fp_regnum_p (regno) || i386_fpc_regnum_p (regno))
+ i387_collect_fsave (regcache, regno, &npx);
else
internal_error (__FILE__, __LINE__,
- "Invalid register no. %d in store_register.", regno);
+ _("Invalid register no. %d in store_register."), regno);
}
static void
-go32_store_registers (int regno)
+go32_store_registers (struct regcache *regcache, int regno)
{
unsigned r;
if (regno >= 0)
- store_register (regno);
+ store_register (regcache, regno);
else
{
- for (r = 0; r < FP0_REGNUM; r++)
- store_register (r);
- i387_fill_fsave ((char *) &npx, -1);
+ for (r = 0; r < gdbarch_fp0_regnum (get_regcache_arch (regcache)); r++)
+ store_register (regcache, r);
+ i387_collect_fsave (regcache, -1, &npx);
}
}
static void
-go32_prepare_to_store (void)
+go32_prepare_to_store (struct regcache *regcache)
{
}
}
static void
-go32_create_inferior (char *exec_file, char *args, char **env)
+go32_create_inferior (char *exec_file, char *args, char **env, int from_tty)
{
extern char **environ;
jmp_buf start_state;
char *cmdline;
char **env_save = environ;
+ size_t cmdlen;
/* If no exec file handed to us, get it from the exec-file command -- with
a good, common error message if none is specified. */
/* Init command line storage. */
if (redir_debug_init (&child_cmd) == -1)
internal_error (__FILE__, __LINE__,
- "Cannot allocate redirection storage: not enough memory.\n");
+ _("Cannot allocate redirection storage: not enough memory.\n"));
/* Parse the command line and create redirections. */
if (strpbrk (args, "<>"))
if (redir_cmdline_parse (args, &child_cmd) == 0)
args = child_cmd.command;
else
- error ("Syntax error in command line.");
+ error (_("Syntax error in command line."));
}
else
child_cmd.command = xstrdup (args);
- cmdline = (char *) alloca (strlen (args) + 4);
- cmdline[0] = strlen (args);
+ cmdlen = strlen (args);
+ /* v2loadimage passes command lines via DOS memory, so it cannot
+ possibly handle commands longer than 1MB. */
+ if (cmdlen > 1024*1024)
+ error (_("Command line too long."));
+
+ cmdline = xmalloc (cmdlen + 4);
strcpy (cmdline + 1, args);
- cmdline[strlen (args) + 1] = 13;
+ /* If the command-line length fits into DOS 126-char limits, use the
+ DOS command tail format; otherwise, tell v2loadimage to pass it
+ through a buffer in conventional memory. */
+ if (cmdlen < 127)
+ {
+ cmdline[0] = strlen (args);
+ cmdline[cmdlen + 1] = 13;
+ }
+ else
+ cmdline[0] = 0xff; /* signal v2loadimage it's a long command */
environ = env;
exit (1);
}
environ = env_save;
+ xfree (cmdline);
edi_init (start_state);
#if __DJGPP_MINOR__ < 3
push_target (&go32_ops);
clear_proceed_status ();
insert_breakpoints ();
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
prog_has_started = 1;
}
{
if (i < 0 || i > 3)
internal_error (__FILE__, __LINE__,
- "Invalid register %d in go32_set_dr.\n", i);
+ _("Invalid register %d in go32_set_dr.\n"), i);
D_REGS[i] = addr;
}
if (redir_to_child (&child_cmd) == -1)
{
redir_to_debugger (&child_cmd);
- error ("Cannot redirect standard handles for program: %s.",
- strerror (errno));
+ error (_("Cannot redirect standard handles for program: %s."),
+ safe_strerror (errno));
}
/* set the console device of the inferior to whatever mode
(raw or cooked) we found it last time */
if (redir_to_debugger (&child_cmd) == -1)
{
redir_to_child (&child_cmd);
- error ("Cannot redirect standard handles for debugger: %s.",
- strerror (errno));
+ error (_("Cannot redirect standard handles for debugger: %s."),
+ safe_strerror (errno));
}
}
}
go32_ops.to_fetch_registers = go32_fetch_registers;
go32_ops.to_store_registers = go32_store_registers;
go32_ops.to_prepare_to_store = go32_prepare_to_store;
- go32_ops.to_xfer_memory = go32_xfer_memory;
+ go32_ops.deprecated_xfer_memory = go32_xfer_memory;
go32_ops.to_files_info = go32_files_info;
go32_ops.to_insert_breakpoint = memory_insert_breakpoint;
go32_ops.to_remove_breakpoint = memory_remove_breakpoint;
/* Initialize child's command line storage. */
if (redir_debug_init (&child_cmd) == -1)
internal_error (__FILE__, __LINE__,
- "Cannot allocate redirection storage: not enough memory.\n");
+ _("Cannot allocate redirection storage: not enough memory.\n"));
/* We are always processing GCC-compiled programs. */
processing_gcc_compilation = 2;
+
+ /* Override the default name of the GDB init file. */
+ strcpy (gdbinit, "gdb.ini");
}
unsigned short windows_major, windows_minor;
read_memory_region (unsigned long addr, void *dest, size_t len)
{
unsigned long dos_ds_limit = __dpmi_get_segment_limit (_dos_ds);
+ int retval = 1;
/* For the low memory, we can simply use _dos_ds. */
if (addr <= dos_ds_limit - len)
be able to access that memory. */
int sel = __dpmi_allocate_ldt_descriptors (1);
- if (sel <= 0
- || __dpmi_set_segment_base_address (sel, addr) == -1
- || __dpmi_set_segment_limit (sel, len - 1) == -1)
- return 0;
- movedata (sel, 0, _my_ds (), (unsigned)dest, len);
- __dpmi_free_ldt_descriptor (sel);
+ if (sel <= 0)
+ retval = 0;
+ else
+ {
+ int access_rights = __dpmi_get_descriptor_access_rights (sel);
+ size_t segment_limit = len - 1;
+
+ /* Make sure the crucial bits in the descriptor access
+ rights are set correctly. Some DPMI providers might barf
+ if we set the segment limit to something that is not an
+ integral multiple of 4KB pages if the granularity bit is
+ not set to byte-granular, even though the DPMI spec says
+ it's the host's responsibility to set that bit correctly. */
+ if (len > 1024 * 1024)
+ {
+ access_rights |= 0x8000;
+ /* Page-granular segments should have the low 12 bits of
+ the limit set. */
+ segment_limit |= 0xfff;
+ }
+ else
+ access_rights &= ~0x8000;
+
+ if (__dpmi_set_segment_base_address (sel, addr) != -1
+ && __dpmi_set_descriptor_access_rights (sel, access_rights) != -1
+ && __dpmi_set_segment_limit (sel, segment_limit) != -1
+ /* W2K silently fails to set the segment limit, leaving
+ it at zero; this test avoids the resulting crash. */
+ && __dpmi_get_segment_limit (sel) >= segment_limit)
+ movedata (sel, 0, _my_ds (), (unsigned)dest, len);
+ else
+ retval = 0;
+
+ __dpmi_free_ldt_descriptor (sel);
+ }
}
- return 1;
+ return retval;
}
/* Get a segment descriptor stored at index IDX in the descriptor
if (ldt_entry < 0
|| (ldt_entry & 4) == 0
|| (ldt_entry & 3) != (cpl & 3))
- error ("Invalid LDT entry 0x%03x.", ldt_entry);
+ error (_("Invalid LDT entry 0x%03lx."), (unsigned long)ldt_entry);
}
}
if (ldt_entry >= 0)
{
if (ldt_entry > limit)
- error ("Invalid LDT entry %#x: outside valid limits [0..%#x]",
- ldt_entry, limit);
+ error (_("Invalid LDT entry %#lx: outside valid limits [0..%#x]"),
+ (unsigned long)ldt_entry, limit);
display_descriptor (ldt_descr.stype, base, ldt_entry / 8, 1);
}
{
gdt_entry = parse_and_eval_long (arg);
if (gdt_entry < 0 || (gdt_entry & 7) != 0)
- error ("Invalid GDT entry 0x%03x: not an integral multiple of 8.",
- gdt_entry);
+ error (_("Invalid GDT entry 0x%03lx: not an integral multiple of 8."),
+ (unsigned long)gdt_entry);
}
}
if (gdt_entry >= 0)
{
if (gdt_entry > gdtr.limit)
- error ("Invalid GDT entry %#x: outside valid limits [0..%#x]",
- gdt_entry, gdtr.limit);
+ error (_("Invalid GDT entry %#lx: outside valid limits [0..%#x]"),
+ (unsigned long)gdt_entry, gdtr.limit);
display_descriptor (0, gdtr.base, gdt_entry / 8, 1);
}
{
idt_entry = parse_and_eval_long (arg);
if (idt_entry < 0)
- error ("Invalid (negative) IDT entry 0x%03x.", idt_entry);
+ error (_("Invalid (negative) IDT entry %ld."), idt_entry);
}
}
if (idt_entry >= 0)
{
if (idt_entry > idtr.limit)
- error ("Invalid IDT entry %#x: outside valid limits [0..%#x]",
- idt_entry, idtr.limit);
+ error (_("Invalid IDT entry %#lx: outside valid limits [0..%#x]"),
+ (unsigned long)idt_entry, idtr.limit);
display_descriptor (1, idtr.base, idt_entry, 1);
}
}
}
+/* Cached linear address of the base of the page directory. For
+ now, available only under CWSDPMI. Code based on ideas and
+ suggestions from Charles Sandmann <sandmann@clio.rice.edu>. */
+static unsigned long pdbr;
+
+static unsigned long
+get_cr3 (void)
+{
+ unsigned offset;
+ unsigned taskreg;
+ unsigned long taskbase, cr3;
+ struct dtr_reg gdtr;
+
+ if (pdbr > 0 && pdbr <= 0xfffff)
+ return pdbr;
+
+ /* Get the linear address of GDT and the Task Register. */
+ __asm__ __volatile__ ("sgdt %0" : "=m" (gdtr) : /* no inputs */ );
+ __asm__ __volatile__ ("str %0" : "=m" (taskreg) : /* no inputs */ );
+
+ /* Task Register is a segment selector for the TSS of the current
+ task. Therefore, it can be used as an index into the GDT to get
+ at the segment descriptor for the TSS. To get the index, reset
+ the low 3 bits of the selector (which give the CPL). Add 2 to the
+ offset to point to the 3 low bytes of the base address. */
+ offset = gdtr.base + (taskreg & 0xfff8) + 2;
+
+
+ /* CWSDPMI's task base is always under the 1MB mark. */
+ if (offset > 0xfffff)
+ return 0;
+
+ _farsetsel (_dos_ds);
+ taskbase = _farnspeekl (offset) & 0xffffffU;
+ taskbase += _farnspeekl (offset + 2) & 0xff000000U;
+ if (taskbase > 0xfffff)
+ return 0;
+
+ /* CR3 (a.k.a. PDBR, the Page Directory Base Register) is stored at
+ offset 1Ch in the TSS. */
+ cr3 = _farnspeekl (taskbase + 0x1c) & ~0xfff;
+ if (cr3 > 0xfffff)
+ {
+#if 0 /* not fullly supported yet */
+ /* The Page Directory is in UMBs. In that case, CWSDPMI puts
+ the first Page Table right below the Page Directory. Thus,
+ the first Page Table's entry for its own address and the Page
+ Directory entry for that Page Table will hold the same
+ physical address. The loop below searches the entire UMB
+ range of addresses for such an occurence. */
+ unsigned long addr, pte_idx;
+
+ for (addr = 0xb0000, pte_idx = 0xb0;
+ pte_idx < 0xff;
+ addr += 0x1000, pte_idx++)
+ {
+ if (((_farnspeekl (addr + 4 * pte_idx) & 0xfffff027) ==
+ (_farnspeekl (addr + 0x1000) & 0xfffff027))
+ && ((_farnspeekl (addr + 4 * pte_idx + 4) & 0xfffff000) == cr3))
+ {
+ cr3 = addr + 0x1000;
+ break;
+ }
+ }
+#endif
+
+ if (cr3 > 0xfffff)
+ cr3 = 0;
+ }
+
+ return cr3;
+}
+
+/* Return the N'th Page Directory entry. */
+static unsigned long
+get_pde (int n)
+{
+ unsigned long pde = 0;
+
+ if (pdbr && n >= 0 && n < 1024)
+ {
+ pde = _farpeekl (_dos_ds, pdbr + 4*n);
+ }
+ return pde;
+}
+
+/* Return the N'th entry of the Page Table whose Page Directory entry
+ is PDE. */
+static unsigned long
+get_pte (unsigned long pde, int n)
+{
+ unsigned long pte = 0;
+
+ /* pde & 0x80 tests the 4MB page bit. We don't support 4MB
+ page tables, for now. */
+ if ((pde & 1) && !(pde & 0x80) && n >= 0 && n < 1024)
+ {
+ pde &= ~0xfff; /* clear non-address bits */
+ pte = _farpeekl (_dos_ds, pde + 4*n);
+ }
+ return pte;
+}
+
+/* Display a Page Directory or Page Table entry. IS_DIR, if non-zero,
+ says this is a Page Directory entry. If FORCE is non-zero, display
+ the entry even if its Present flag is off. OFF is the offset of the
+ address from the page's base address. */
+static void
+display_ptable_entry (unsigned long entry, int is_dir, int force, unsigned off)
+{
+ if ((entry & 1) != 0)
+ {
+ printf_filtered ("Base=0x%05lx000", entry >> 12);
+ if ((entry & 0x100) && !is_dir)
+ puts_filtered (" Global");
+ if ((entry & 0x40) && !is_dir)
+ puts_filtered (" Dirty");
+ printf_filtered (" %sAcc.", (entry & 0x20) ? "" : "Not-");
+ printf_filtered (" %sCached", (entry & 0x10) ? "" : "Not-");
+ printf_filtered (" Write-%s", (entry & 8) ? "Thru" : "Back");
+ printf_filtered (" %s", (entry & 4) ? "Usr" : "Sup");
+ printf_filtered (" Read-%s", (entry & 2) ? "Write" : "Only");
+ if (off)
+ printf_filtered (" +0x%x", off);
+ puts_filtered ("\n");
+ }
+ else if (force)
+ printf_filtered ("Page%s not present or not supported; value=0x%lx.\n",
+ is_dir ? " Table" : "", entry >> 1);
+}
+
+static void
+go32_pde (char *arg, int from_tty)
+{
+ long pde_idx = -1, i;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ {
+ pde_idx = parse_and_eval_long (arg);
+ if (pde_idx < 0 || pde_idx >= 1024)
+ error (_("Entry %ld is outside valid limits [0..1023]."), pde_idx);
+ }
+ }
+
+ pdbr = get_cr3 ();
+ if (!pdbr)
+ puts_filtered ("Access to Page Directories is not supported on this system.\n");
+ else if (pde_idx >= 0)
+ display_ptable_entry (get_pde (pde_idx), 1, 1, 0);
+ else
+ for (i = 0; i < 1024; i++)
+ display_ptable_entry (get_pde (i), 1, 0, 0);
+}
+
+/* A helper function to display entries in a Page Table pointed to by
+ the N'th entry in the Page Directory. If FORCE is non-zero, say
+ something even if the Page Table is not accessible. */
+static void
+display_page_table (long n, int force)
+{
+ unsigned long pde = get_pde (n);
+
+ if ((pde & 1) != 0)
+ {
+ int i;
+
+ printf_filtered ("Page Table pointed to by Page Directory entry 0x%lx:\n", n);
+ for (i = 0; i < 1024; i++)
+ display_ptable_entry (get_pte (pde, i), 0, 0, 0);
+ puts_filtered ("\n");
+ }
+ else if (force)
+ printf_filtered ("Page Table not present; value=0x%lx.\n", pde >> 1);
+}
+
+static void
+go32_pte (char *arg, int from_tty)
+{
+ long pde_idx = -1L, i;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ {
+ pde_idx = parse_and_eval_long (arg);
+ if (pde_idx < 0 || pde_idx >= 1024)
+ error (_("Entry %ld is outside valid limits [0..1023]."), pde_idx);
+ }
+ }
+
+ pdbr = get_cr3 ();
+ if (!pdbr)
+ puts_filtered ("Access to Page Tables is not supported on this system.\n");
+ else if (pde_idx >= 0)
+ display_page_table (pde_idx, 1);
+ else
+ for (i = 0; i < 1024; i++)
+ display_page_table (i, 0);
+}
+
+static void
+go32_pte_for_address (char *arg, int from_tty)
+{
+ CORE_ADDR addr = 0, i;
+
+ if (arg && *arg)
+ {
+ while (*arg && isspace(*arg))
+ arg++;
+
+ if (*arg)
+ addr = parse_and_eval_address (arg);
+ }
+ if (!addr)
+ error_no_arg (_("linear address"));
+
+ pdbr = get_cr3 ();
+ if (!pdbr)
+ puts_filtered ("Access to Page Tables is not supported on this system.\n");
+ else
+ {
+ int pde_idx = (addr >> 22) & 0x3ff;
+ int pte_idx = (addr >> 12) & 0x3ff;
+ unsigned offs = addr & 0xfff;
+
+ printf_filtered ("Page Table entry for address 0x%llx:\n",
+ (unsigned long long)addr);
+ display_ptable_entry (get_pte (get_pde (pde_idx), pte_idx), 0, 1, offs);
+ }
+}
+
+static struct cmd_list_element *info_dos_cmdlist = NULL;
+
+static void
+go32_info_dos_command (char *args, int from_tty)
+{
+ help_list (info_dos_cmdlist, "info dos ", class_info, gdb_stdout);
+}
+
void
_initialize_go32_nat (void)
{
init_go32_ops ();
add_target (&go32_ops);
- add_info ("dos-sysinfo", go32_sysinfo,
- "Display information about the target system, including CPU, OS, DPMI, etc.");
- add_info ("dos-ldt", go32_sldt,
- "Display entries in the LDT (Local Descriptor Table).\n"
- "Entry number (an expression) as an argument means display only that entry.");
- add_info ("dos-gdt", go32_sgdt,
- "Display entries in the GDT (Global Descriptor Table).\n"
- "Entry number (an expression) as an argument means display only that entry.");
- add_info ("dos-idt", go32_sidt,
- "Display entries in the IDT (Interrupt Descriptor Table).\n"
- "Entry number (an expression) as an argument means display only that entry.");
+ add_prefix_cmd ("dos", class_info, go32_info_dos_command, _("\
+Print information specific to DJGPP (aka MS-DOS) debugging."),
+ &info_dos_cmdlist, "info dos ", 0, &infolist);
+
+ add_cmd ("sysinfo", class_info, go32_sysinfo, _("\
+Display information about the target system, including CPU, OS, DPMI, etc."),
+ &info_dos_cmdlist);
+ add_cmd ("ldt", class_info, go32_sldt, _("\
+Display entries in the LDT (Local Descriptor Table).\n\
+Entry number (an expression) as an argument means display only that entry."),
+ &info_dos_cmdlist);
+ add_cmd ("gdt", class_info, go32_sgdt, _("\
+Display entries in the GDT (Global Descriptor Table).\n\
+Entry number (an expression) as an argument means display only that entry."),
+ &info_dos_cmdlist);
+ add_cmd ("idt", class_info, go32_sidt, _("\
+Display entries in the IDT (Interrupt Descriptor Table).\n\
+Entry number (an expression) as an argument means display only that entry."),
+ &info_dos_cmdlist);
+ add_cmd ("pde", class_info, go32_pde, _("\
+Display entries in the Page Directory.\n\
+Entry number (an expression) as an argument means display only that entry."),
+ &info_dos_cmdlist);
+ add_cmd ("pte", class_info, go32_pte, _("\
+Display entries in Page Tables.\n\
+Entry number (an expression) as an argument means display only entries\n\
+from the Page Table pointed to by the specified Page Directory entry."),
+ &info_dos_cmdlist);
+ add_cmd ("address-pte", class_info, go32_pte_for_address, _("\
+Display a Page Table entry for a linear address.\n\
+The address argument must be a linear address, after adding to\n\
+it the base address of the appropriate segment.\n\
+The base address of variables and functions in the debuggee's data\n\
+or code segment is stored in the variable __djgpp_base_address,\n\
+so use `__djgpp_base_address + (char *)&var' as the argument.\n\
+For other segments, look up their base address in the output of\n\
+the `info dos ldt' command."),
+ &info_dos_cmdlist);
}
pid_t