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, ®s); 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, ®s); 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, ®s); 1228130803Smarcel print_mem (regs.x.bx << 4, "Free DOS Memory................", 0); 1229130803Smarcel regs.x.ax = 0x5800; 1230130803Smarcel __dpmi_int (0x21, ®s); 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, ®s); 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