+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%03lx."), (unsigned long)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 %#lx: outside valid limits [0..%#x]"),
+ (unsigned long)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%03lx: "
+ "not an integral multiple of 8."),
+ (unsigned long)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 %#lx: outside valid limits [0..%#x]"),
+ (unsigned long)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 %ld."), 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 %#lx: outside valid limits [0..%#x]"),
+ (unsigned long)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);
+ }
+}
+
+/* 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 %s:\n",
+ hex_string(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);
+}
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_go32_nat;
+