This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Add system-information commands to go32-nat.c


FYI: I've commited the patch below, which adds a few "info dos-*" 
commands to the DJGPP port.  They allow to print system information and 
GDT/LDT/IDT entries.  (Other debuggers feature similar displays, so I 
couldn't afford not having them in GDB ;-)

2001-07-07  Eli Zaretskii  <eliz@is.elta.co.il>

	* go32-nat.c (go32_get_windows_version, print_mem, go32_sysinfo)
	(read_memory_region, get_descriptor, display_descriptor)
	(go32_sldt, go32_sgdt, go32_sidt): New functions.
	(top-level): Include ctype.h, utsname.h, dos.h, and go32.h.  Ifdef
	away `disable' from dos.h, since breakpoint.h defines an enum
	member of the same name, and GCC 2.7.2 barfs.
	(_initialize_go32_nat): Provide new commands dos-sysinfo, dos-ldt,
	dos-gdt, and dos-idt, all of them in the "info" class

--- gdb/go32-nat.c~1	Sat Jun  2 20:34:00 2001
+++ gdb/go32-nat.c	Wed Jul  4 19:22:06 2001
@@ -33,12 +33,19 @@
 #include "regcache.h"
 #include "gdb_string.h"
 
-#include <stdio.h>		/* required for __DJGPP_MINOR__ */
+#include <stdio.h>		/* might be required for __DJGPP_MINOR__ */
 #include <stdlib.h>
+#include <ctype.h>
 #include <errno.h>
 #include <unistd.h>
+#include <sys/utsname.h>
 #include <io.h>
+/* 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 <debug/v2load.h>
 #include <debug/dbgcom.h>
 #if __DJGPP_MINOR__ > 2
@@ -878,11 +885,750 @@ init_go32_ops (void)
   processing_gcc_compilation = 2;
 }
 
+unsigned short windows_major, windows_minor;
+
+/* Compute the version Windows reports via Int 2Fh/AX=1600h.  */
+static void
+go32_get_windows_version(void)
+{
+  __dpmi_regs r;
+
+  r.x.ax = 0x1600;
+  __dpmi_int(0x2f, &r);
+  if (r.h.al > 2 && r.h.al != 0x80 && r.h.al != 0xff
+      && (r.h.al > 3 || r.h.ah > 0))
+    {
+      windows_major = r.h.al;
+      windows_minor = r.h.ah;
+    }
+  else
+    windows_major = 0xff;	/* meaning no Windows */
+}
+
+/* A subroutine of go32_sysinfo to display memory info.  */
+static void
+print_mem (unsigned long datum, const char *header, int in_pages_p)
+{
+  if (datum != 0xffffffffUL)
+    {
+      if (in_pages_p)
+	datum <<= 12;
+      puts_filtered (header);
+      if (datum > 1024)
+	{
+	  printf_filtered ("%lu KB", datum >> 10);
+	  if (datum > 1024 * 1024)
+	    printf_filtered (" (%lu MB)", datum >> 20);
+	}
+      else
+	printf_filtered ("%lu Bytes", datum);
+      puts_filtered ("\n");
+    }
+}
+
+/* Display assorted information about the underlying OS.  */
+static void
+go32_sysinfo (char *arg, int from_tty)
+{
+  struct utsname u;
+  char cpuid_vendor[13];
+  unsigned cpuid_max = 0, cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
+  unsigned true_dos_version = _get_dos_version (1);
+  unsigned advertized_dos_version = ((unsigned int)_osmajor << 8) | _osminor;
+  int dpmi_flags;
+  char dpmi_vendor_info[129];
+  int dpmi_vendor_available =
+    __dpmi_get_capabilities (&dpmi_flags, dpmi_vendor_info);
+  __dpmi_version_ret dpmi_version_data;
+  long eflags;
+  __dpmi_free_mem_info mem_info;
+  __dpmi_regs regs;
+
+  cpuid_vendor[0] = '\0';
+  if (uname (&u))
+    strcpy (u.machine, "Unknown x86");
+  else if (u.machine[0] == 'i' && u.machine[1] > 4)
+    {
+      /* CPUID with EAX = 0 returns the Vendor ID.  */
+      __asm__ __volatile__ ("xorl   %%ebx, %%ebx;"
+			    "xorl   %%ecx, %%ecx;"
+			    "xorl   %%edx, %%edx;"
+			    "movl   $0,    %%eax;"
+			    "cpuid;"
+			    "movl   %%ebx,  %0;"
+			    "movl   %%edx,  %1;"
+			    "movl   %%ecx,  %2;"
+			    "movl   %%eax,  %3;"
+			    : "=m" (cpuid_vendor[0]),
+			      "=m" (cpuid_vendor[4]),
+			      "=m" (cpuid_vendor[8]),
+			      "=m" (cpuid_max)
+			    :
+			    : "%eax", "%ebx", "%ecx", "%edx");
+      cpuid_vendor[12] = '\0';
+    }
+
+  printf_filtered ("CPU Type.......................%s", u.machine);
+  if (cpuid_vendor[0])
+    printf_filtered (" (%s)", cpuid_vendor);
+  puts_filtered ("\n");
+
+  /* CPUID with EAX = 1 returns processor signature and features.  */
+  if (cpuid_max >= 1)
+    {
+      static char *brand_name[] = {
+	"",
+	" Celeron",
+	" III",
+	" III Xeon",
+	"", "", "", "",
+	" 4"
+      };
+      char cpu_string[80];
+      char cpu_brand[20];
+      unsigned brand_idx;
+      int intel_p = strcmp (cpuid_vendor, "GenuineIntel") == 0;
+      int amd_p = strcmp (cpuid_vendor, "AuthenticAMD") == 0;
+      unsigned cpu_family, cpu_model;
+
+      __asm__ __volatile__ ("movl   $1, %%eax;"
+			    "cpuid;"
+			    : "=a" (cpuid_eax),
+			      "=b" (cpuid_ebx),
+			      "=d" (cpuid_edx)
+			    :
+			    : "%ecx");
+      brand_idx = cpuid_ebx & 0xff;
+      cpu_family = (cpuid_eax >> 8) & 0xf;
+      cpu_model  = (cpuid_eax >> 4) & 0xf;
+      cpu_brand[0] = '\0';
+      if (intel_p)
+	{
+	  if (brand_idx > 0
+	      && brand_idx < sizeof(brand_name)/sizeof(brand_name[0])
+	      && *brand_name[brand_idx])
+	    strcpy (cpu_brand, brand_name[brand_idx]);
+	  else if (cpu_family == 5)
+	    {
+	      if (((cpuid_eax >> 12) & 3) == 0 && cpu_model == 4)
+		strcpy (cpu_brand, " MMX");
+	      else if (cpu_model > 1 && ((cpuid_eax >> 12) & 3) == 1)
+		strcpy (cpu_brand, " OverDrive");
+	      else if (cpu_model > 1 && ((cpuid_eax >> 12) & 3) == 2)
+		strcpy (cpu_brand, " Dual");
+	    }
+	  else if (cpu_family == 6 && cpu_model < 8)
+	    {
+	      switch (cpu_model)
+		{
+		  case 1:
+		    strcpy (cpu_brand, " Pro");
+		    break;
+		  case 3:
+		    strcpy (cpu_brand, " II");
+		    break;
+		  case 5:
+		    strcpy (cpu_brand, " II Xeon");
+		    break;
+		  case 6:
+		    strcpy (cpu_brand, " Celeron");
+		    break;
+		  case 7:
+		    strcpy (cpu_brand, " III");
+		    break;
+		}
+	    }
+	}
+      else if (amd_p)
+	{
+	  switch (cpu_family)
+	    {
+	      case 4:
+		strcpy (cpu_brand, "486/5x86");
+		break;
+	      case 5:
+		switch (cpu_model)
+		  {
+		    case 0:
+		    case 1:
+		    case 2:
+		    case 3:
+		      strcpy (cpu_brand, "-K5");
+		      break;
+		    case 6:
+		    case 7:
+		      strcpy (cpu_brand, "-K6");
+		      break;
+		    case 8:
+		      strcpy (cpu_brand, "-K6-2");
+		      break;
+		    case 9:
+		      strcpy (cpu_brand, "-K6-III");
+		      break;
+		  }
+		break;
+	      case 6:
+		switch (cpu_model)
+		  {
+		    case 1:
+		    case 2:
+		    case 4:
+		      strcpy (cpu_brand, " Athlon");
+		      break;
+		    case 3:
+		      strcpy (cpu_brand, " Duron");
+		      break;
+		  }
+		break;
+	    }
+	}
+      sprintf (cpu_string, "%s%s Model %d Stepping %d",
+	       intel_p ? "Pentium" : (amd_p ? "AMD" : "ix86"),
+	       cpu_brand, cpu_model, cpuid_eax & 0xf);
+      printfi_filtered (31, "%s\n", cpu_string);
+      if (((cpuid_edx & (6 | (0x0d << 23))) != 0)
+	  || ((cpuid_edx & 1) == 0)
+	  || (amd_p && (cpuid_edx & (3 << 30)) != 0))
+	{
+	  puts_filtered ("CPU Features...................");
+	  /* We only list features which might be useful in the DPMI
+	     environment.  */
+	  if ((cpuid_edx & 1) == 0)
+	    puts_filtered ("No FPU "); /* it's unusual to not have an FPU */
+	  if ((cpuid_edx & (1 << 1)) != 0)
+	    puts_filtered ("VME ");
+	  if ((cpuid_edx & (1 << 2)) != 0)
+	    puts_filtered ("DE ");
+	  if ((cpuid_edx & (1 << 4)) != 0)
+	    puts_filtered ("TSC ");
+	  if ((cpuid_edx & (1 << 23)) != 0)
+	    puts_filtered ("MMX ");
+	  if ((cpuid_edx & (1 << 25)) != 0)
+	    puts_filtered ("SSE ");
+	  if ((cpuid_edx & (1 << 26)) != 0)
+	    puts_filtered ("SSE2 ");
+	  if (amd_p)
+	    {
+	      if ((cpuid_edx & (1 << 31)) != 0)
+		puts_filtered ("3DNow! ");
+	      if ((cpuid_edx & (1 << 30)) != 0)
+		puts_filtered ("3DNow!Ext");
+	    }
+	  puts_filtered ("\n");
+	}
+    }
+  puts_filtered ("\n");
+  printf_filtered ("DOS Version....................%s %s.%s",
+		   _os_flavor, u.release, u.version);
+  if (true_dos_version != advertized_dos_version)
+    printf_filtered (" (disguised as v%d.%d)", _osmajor, _osminor);
+  puts_filtered ("\n");
+  if (!windows_major)
+    go32_get_windows_version ();
+  if (windows_major != 0xff)
+    {
+      const char *windows_flavor;
+
+      printf_filtered ("Windows Version................%d.%02d (Windows ",
+		       windows_major, windows_minor);
+      switch (windows_major)
+	{
+	  case 3:
+	    windows_flavor = "3.X";
+	    break;
+	  case 4:
+	    switch (windows_minor)
+	      {
+		case 0:
+		  windows_flavor = "95, 95A, or 95B";
+		  break;
+		case 3:
+		  windows_flavor = "95B OSR2.1 or 95C OSR2.5";
+		  break;
+		case 10:
+		  windows_flavor = "98 or 98 SE";
+		  break;
+		case 90:
+		  windows_flavor = "ME";
+		  break;
+		default:
+		  windows_flavor = "9X";
+		  break;
+	      }
+	    break;
+	  default:
+	    windows_flavor = "??";
+	    break;
+	}
+      printf_filtered ("%s)\n", windows_flavor);
+    }
+  else if (true_dos_version == 0x532 && advertized_dos_version == 0x500)
+    printf_filtered ("Windows Version................Windows NT or Windows 2000\n");
+  puts_filtered ("\n");
+  if (dpmi_vendor_available == 0)
+    {
+      /* The DPMI spec says the vendor string should be ASCIIZ, but
+	 I don't trust the vendors to follow that...  */
+      if (!memchr (&dpmi_vendor_info[2], 0, 126))
+	dpmi_vendor_info[128] = '\0';
+      printf_filtered ("DPMI Host......................%s v%d.%d (capabilities: %#x)\n",
+		       &dpmi_vendor_info[2],
+		       (unsigned)dpmi_vendor_info[0],
+		       (unsigned)dpmi_vendor_info[1],
+		       ((unsigned)dpmi_flags & 0x7f));
+    }
+  __dpmi_get_version (&dpmi_version_data);
+  printf_filtered ("DPMI Version...................%d.%02d\n",
+		   dpmi_version_data.major, dpmi_version_data.minor);
+  printf_filtered ("DPMI Info......................%s-bit DPMI, with%s Virtual Memory support\n",
+		   (dpmi_version_data.flags & 1) ? "32" : "16",
+		   (dpmi_version_data.flags & 4) ? "" : "out");
+  printfi_filtered (31, "Interrupts reflected to %s mode\n",
+		   (dpmi_version_data.flags & 2) ? "V86" : "Real");
+  printfi_filtered (31, "Processor type: i%d86\n",
+		   dpmi_version_data.cpu);
+  printfi_filtered (31, "PIC base interrupt: Master: %#x  Slave: %#x\n",
+		   dpmi_version_data.master_pic, dpmi_version_data.slave_pic);
+
+  /* a_tss is only initialized when the debuggee is first run.  */
+  if (prog_has_started)
+    {
+      __asm__ __volatile__ ("pushfl ; popl %0" : "=g" (eflags));
+      printf_filtered ("Protection.....................Ring %d (in %s), with%s I/O protection\n",
+		       a_tss.tss_cs & 3, (a_tss.tss_cs & 4) ? "LDT" : "GDT",
+		       (a_tss.tss_cs & 3) > ((eflags >> 12) & 3) ? "" : "out");
+    }
+  puts_filtered ("\n");
+  __dpmi_get_free_memory_information (&mem_info);
+  print_mem (mem_info.total_number_of_physical_pages,
+	     "DPMI Total Physical Memory.....", 1);
+  print_mem (mem_info.total_number_of_free_pages,
+	     "DPMI Free Physical Memory......", 1);
+  print_mem (mem_info.size_of_paging_file_partition_in_pages,
+	     "DPMI Swap Space................", 1);
+  print_mem (mem_info.linear_address_space_size_in_pages,
+	     "DPMI Total Linear Address Size.", 1);
+  print_mem (mem_info.free_linear_address_space_in_pages,
+	     "DPMI Free Linear Address Size..", 1);
+  print_mem (mem_info.largest_available_free_block_in_bytes,
+	     "DPMI Largest Free Memory Block.", 0);
+
+  regs.h.ah = 0x48;
+  regs.x.bx = 0xffff;
+  __dpmi_int (0x21, &regs);
+  print_mem (regs.x.bx << 4, "Free DOS Memory................", 0);
+  regs.x.ax = 0x5800;
+  __dpmi_int (0x21, &regs);
+  if ((regs.x.flags & 1) == 0)
+    {
+      static const char *dos_hilo[] = {
+	"Low", "", "", "", "High", "", "", "", "High, then Low"
+      };
+      static const char *dos_fit[] = {
+	"First", "Best", "Last"
+      };
+      int hilo_idx = (regs.x.ax >> 4) & 0x0f;
+      int fit_idx  = regs.x.ax & 0x0f;
+
+      if (hilo_idx > 8)
+	hilo_idx = 0;
+      if (fit_idx > 2)
+	fit_idx = 0;
+      printf_filtered ("DOS Memory Allocation..........%s memory, %s fit\n",
+		       dos_hilo[hilo_idx], dos_fit[fit_idx]);
+      regs.x.ax = 0x5802;
+      __dpmi_int (0x21, &regs);
+      if ((regs.x.flags & 1) != 0)
+	regs.h.al = 0;
+      printfi_filtered (31, "UMBs %sin DOS memory chain\n",
+			regs.h.al == 0 ? "not " : "");
+    }
+}
+
+struct seg_descr {
+  unsigned short limit0          __attribute__((packed));
+  unsigned short base0           __attribute__((packed));
+  unsigned char  base1           __attribute__((packed));
+  unsigned       stype:5         __attribute__((packed));
+  unsigned       dpl:2           __attribute__((packed));
+  unsigned       present:1       __attribute__((packed));
+  unsigned       limit1:4        __attribute__((packed));
+  unsigned       available:1     __attribute__((packed));
+  unsigned       dummy:1         __attribute__((packed));
+  unsigned       bit32:1         __attribute__((packed));
+  unsigned       page_granular:1 __attribute__((packed));
+  unsigned char  base2           __attribute__((packed));
+};
+
+struct gate_descr {
+  unsigned short offset0         __attribute__((packed));
+  unsigned short selector        __attribute__((packed));
+  unsigned       param_count:5   __attribute__((packed));
+  unsigned       dummy:3         __attribute__((packed));
+  unsigned       stype:5         __attribute__((packed));
+  unsigned       dpl:2           __attribute__((packed));
+  unsigned       present:1       __attribute__((packed));
+  unsigned short offset1         __attribute__((packed));
+};
+
+/* Read LEN bytes starting at logical address ADDR, and put the result
+   into DEST.  Return 1 if success, zero if not.  */
+static int
+read_memory_region (unsigned long addr, void *dest, size_t len)
+{
+  unsigned long dos_ds_limit = __dpmi_get_segment_limit (_dos_ds);
+
+  /* For the low memory, we can simply use _dos_ds.  */
+  if (addr <= dos_ds_limit - len)
+    dosmemget (addr, len, dest);
+  else
+    {
+      /* For memory above 1MB we need to set up a special segment to
+	 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);
+    }
+  return 1;
+}
+
+/* Get a segment descriptor stored at index IDX in the descriptor
+   table whose base address is TABLE_BASE.  Return the descriptor
+   type, or -1 if failure.  */
+static int
+get_descriptor (unsigned long table_base, int idx, void *descr)
+{
+  unsigned long addr = table_base + idx * 8; /* 8 bytes per entry */
+
+  if (read_memory_region (addr, descr, 8))
+    return (int)((struct seg_descr *)descr)->stype;
+  return -1;
+}
+
+struct dtr_reg {
+  unsigned short limit __attribute__((packed));
+  unsigned long  base  __attribute__((packed));
+};
+
+/* Display a segment descriptor stored at index IDX in a descriptor
+   table whose type is TYPE and whose base address is BASE_ADDR.  If
+   FORCE is non-zero, display even invalid descriptors.  */
+static void
+display_descriptor (unsigned type, unsigned long base_addr, int idx, int force)
+{
+  struct seg_descr descr;
+  struct gate_descr gate;
+
+  /* Get the descriptor from the table.  */
+  if (idx == 0 && type == 0)
+    puts_filtered ("0x000: null descriptor\n");
+  else if (get_descriptor (base_addr, idx, &descr) != -1)
+    {
+      /* For each type of descriptor table, this has a bit set if the
+	 corresponding type of selectors is valid in that table.  */
+      static unsigned allowed_descriptors[] = {
+	  0xffffdafeL,   /* GDT */
+	  0x0000c0e0L,   /* IDT */
+	  0xffffdafaL    /* LDT */
+      };
+
+      /* If the program hasn't started yet, assume the debuggee will
+	 have the same CPL as the debugger.  */
+      int cpl = prog_has_started ? (a_tss.tss_cs & 3) : _my_cs () & 3;
+      unsigned long limit = (descr.limit1 << 16) | descr.limit0;
+
+      if (descr.present
+	  && (allowed_descriptors[type] & (1 << descr.stype)) != 0)
+	{
+	  printf_filtered ("0x%03x: ",
+			   type == 1
+			   ? idx : (idx * 8) | (type ? (cpl | 4) : 0));
+	  if (descr.page_granular)
+	    limit = (limit << 12) | 0xfff; /* big segment: low 12 bit set */
+	  if (descr.stype == 1 || descr.stype == 2 || descr.stype == 3
+	      || descr.stype == 9 || descr.stype == 11
+	      || (descr.stype >= 16 && descr.stype < 32))
+	    printf_filtered ("base=0x%02x%02x%04x limit=0x%08lx",
+			     descr.base2, descr.base1, descr.base0, limit);
+
+	  switch (descr.stype)
+	    {
+	      case 1:
+	      case 3:
+		printf_filtered (" 16-bit TSS (task %sactive)",
+				 descr.stype == 3 ? "" : "in");
+		break;
+	      case 2:
+		puts_filtered (" LDT");
+		break;
+	      case 4:
+		memcpy (&gate, &descr, sizeof gate);
+		printf_filtered ("selector=0x%04x  offs=0x%04x%04x",
+				 gate.selector, gate.offset1, gate.offset0);
+		printf_filtered (" 16-bit Call Gate (params=%d)",
+				 gate.param_count);
+		break;
+	      case 5:
+		printf_filtered ("TSS selector=0x%04x", descr.base0);
+		printfi_filtered (16, "Task Gate");
+		break;
+	      case 6:
+	      case 7:
+		memcpy (&gate, &descr, sizeof gate);
+		printf_filtered ("selector=0x%04x  offs=0x%04x%04x",
+				 gate.selector, gate.offset1, gate.offset0);
+		printf_filtered (" 16-bit %s Gate",
+				 descr.stype == 6 ? "Interrupt" : "Trap");
+		break;
+	      case 9:
+	      case 11:
+		printf_filtered (" 32-bit TSS (task %sactive)",
+				 descr.stype == 3 ? "" : "in");
+		break;
+	      case 12:
+		memcpy (&gate, &descr, sizeof gate);
+		printf_filtered ("selector=0x%04x  offs=0x%04x%04x",
+				 gate.selector, gate.offset1, gate.offset0);
+		printf_filtered (" 32-bit Call Gate (params=%d)",
+				 gate.param_count);
+		break;
+	      case 14:
+	      case 15:
+		memcpy (&gate, &descr, sizeof gate);
+		printf_filtered ("selector=0x%04x  offs=0x%04x%04x",
+				 gate.selector, gate.offset1, gate.offset0);
+		printf_filtered (" 32-bit %s Gate",
+				 descr.stype == 14 ? "Interrupt" : "Trap");
+		break;
+	      case 16:		/* data segments */
+	      case 17:
+	      case 18:
+	      case 19:
+	      case 20:
+	      case 21:
+	      case 22:
+	      case 23:
+		printf_filtered (" %s-bit Data (%s, Exp-%s%s)",
+				 descr.bit32 ? "32" : "16",
+				 descr.stype & 2 ? "Read/Write" : "Read-Only",
+				 descr.stype & 4 ? "down" : "up",
+				 descr.stype & 1 ? "" : ", N.Acc");
+		break;
+	      case 24:		/* code segments */
+	      case 25:
+	      case 26:
+	      case 27:
+	      case 28:
+	      case 29:
+	      case 30:
+	      case 31:
+		printf_filtered (" %s-bit Code (%s,  %sConf%s)",
+				 descr.bit32 ? "32" : "16",
+				 descr.stype & 2 ? "Exec/Read" : "Exec-Only",
+				 descr.stype & 4 ? "" : "N.",
+				 descr.stype & 1 ? "" : ", N.Acc");
+		break;
+	      default:
+		printf_filtered ("Unknown type 0x%02x", descr.stype);
+		break;
+	    }
+	  puts_filtered ("\n");
+	}
+      else if (force)
+	{
+	  printf_filtered ("0x%03x: ",
+			   type == 1
+			   ? idx : (idx * 8) | (type ? (cpl | 4) : 0));
+	  if (!descr.present)
+	    puts_filtered ("Segment not present\n");
+	  else
+	    printf_filtered ("Segment type 0x%02x is invalid in this table\n",
+			     descr.stype);
+	}
+    }
+  else if (force)
+    printf_filtered ("0x%03x: Cannot read this descriptor\n", idx);
+}
+
+static void
+go32_sldt (char *arg, int from_tty)
+{
+  struct dtr_reg gdtr;
+  unsigned short ldtr = 0;
+  int ldt_idx;
+  struct seg_descr ldt_descr;
+  long ldt_entry = -1L;
+  int cpl = (prog_has_started ? a_tss.tss_cs : _my_cs ()) & 3;
+
+  if (arg && *arg)
+    {
+      while (*arg && isspace(*arg))
+	arg++;
+
+      if (*arg)
+	{
+	  ldt_entry = parse_and_eval_long (arg);
+	  if (ldt_entry < 0
+	      || (ldt_entry & 4) == 0
+	      || (ldt_entry & 3) != (cpl & 3))
+	    error ("Invalid LDT entry 0x%03x.", ldt_entry);
+	}
+    }
+
+  __asm__ __volatile__ ("sgdt   %0" : "=m" (gdtr) : /* no inputs */ );
+  __asm__ __volatile__ ("sldt   %0" : "=m" (ldtr) : /* no inputs */ );
+  ldt_idx = ldtr / 8;
+  if (ldt_idx == 0)
+    puts_filtered ("There is no LDT.\n");
+  /* LDT's entry in the GDT must have the type LDT, which is 2.  */
+  else if (get_descriptor (gdtr.base, ldt_idx, &ldt_descr) != 2)
+    printf_filtered ("LDT is present (at %#x), but unreadable by GDB.\n",
+		     ldt_descr.base0
+		     | (ldt_descr.base1 << 16)
+		     | (ldt_descr.base2 << 24));
+  else
+    {
+      unsigned base =
+	ldt_descr.base0
+	| (ldt_descr.base1 << 16)
+	| (ldt_descr.base2 << 24);
+      unsigned limit = ldt_descr.limit0 | (ldt_descr.limit1 << 16);
+      int max_entry;
+
+      if (ldt_descr.page_granular)
+	/* Page-granular segments must have the low 12 bits of their
+	   limit set.  */
+	limit = (limit << 12) | 0xfff;
+      /* LDT cannot have more than 8K 8-byte entries, i.e. more than
+	 64KB.  */
+      if (limit > 0xffff)
+	limit = 0xffff;
+
+      max_entry = (limit + 1) / 8;
+
+      if (ldt_entry >= 0)
+	{
+	  if (ldt_entry > limit)
+	    error ("Invalid LDT entry %#x: outside valid limits [0..%#x]",
+		   ldt_entry, limit);
+
+	  display_descriptor (ldt_descr.stype, base, ldt_entry / 8, 1);
+	}
+      else
+	{
+	  int i;
+
+	  for (i = 0; i < max_entry; i++)
+	    display_descriptor (ldt_descr.stype, base, i, 0);
+	}
+    }
+}
+
+static void
+go32_sgdt (char *arg, int from_tty)
+{
+  struct dtr_reg gdtr;
+  long gdt_entry = -1L;
+  int max_entry;
+
+  if (arg && *arg)
+    {
+      while (*arg && isspace(*arg))
+	arg++;
+
+      if (*arg)
+	{
+	  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);
+	}
+    }
+
+  __asm__ __volatile__ ("sgdt   %0" : "=m" (gdtr) : /* no inputs */ );
+  max_entry = (gdtr.limit + 1) / 8;
+
+  if (gdt_entry >= 0)
+    {
+      if (gdt_entry > gdtr.limit)
+	error ("Invalid GDT entry %#x: outside valid limits [0..%#x]",
+	       gdt_entry, gdtr.limit);
+
+      display_descriptor (0, gdtr.base, gdt_entry / 8, 1);
+    }
+  else
+    {
+      int i;
+
+      for (i = 0; i < max_entry; i++)
+	display_descriptor (0, gdtr.base, i, 0);
+    }
+}
+
+static void
+go32_sidt (char *arg, int from_tty)
+{
+  struct dtr_reg idtr;
+  long idt_entry = -1L;
+  int max_entry;
+
+  if (arg && *arg)
+    {
+      while (*arg && isspace(*arg))
+	arg++;
+
+      if (*arg)
+	{
+	  idt_entry = parse_and_eval_long (arg);
+	  if (idt_entry < 0)
+	    error ("Invalid (negative) IDT entry 0x%03x.", idt_entry);
+	}
+    }
+
+  __asm__ __volatile__ ("sidt   %0" : "=m" (idtr) : /* no inputs */ );
+  max_entry = (idtr.limit + 1) / 8;
+  if (max_entry > 0x100)	/* no more than 256 entries */
+    max_entry = 0x100;
+
+  if (idt_entry >= 0)
+    {
+      if (idt_entry > idtr.limit)
+	error ("Invalid IDT entry %#x: outside valid limits [0..%#x]",
+	       idt_entry, idtr.limit);
+
+      display_descriptor (1, idtr.base, idt_entry, 1);
+    }
+  else
+    {
+      int i;
+
+      for (i = 0; i < max_entry; i++)
+	display_descriptor (1, idtr.base, i, 0);
+    }
+}
+
 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.");
 }
 
 pid_t


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]