1b725ae77Skettenis /* Native debugging support for Intel x86 running DJGPP.
2b725ae77Skettenis Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
3b725ae77Skettenis Written by Robert Hoehne.
4b725ae77Skettenis
5b725ae77Skettenis This file is part of GDB.
6b725ae77Skettenis
7b725ae77Skettenis This program is free software; you can redistribute it and/or modify
8b725ae77Skettenis it under the terms of the GNU General Public License as published by
9b725ae77Skettenis the Free Software Foundation; either version 2 of the License, or
10b725ae77Skettenis (at your option) any later version.
11b725ae77Skettenis
12b725ae77Skettenis This program is distributed in the hope that it will be useful,
13b725ae77Skettenis but WITHOUT ANY WARRANTY; without even the implied warranty of
14b725ae77Skettenis MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15b725ae77Skettenis GNU General Public License for more details.
16b725ae77Skettenis
17b725ae77Skettenis You should have received a copy of the GNU General Public License
18b725ae77Skettenis along with this program; if not, write to the Free Software
19b725ae77Skettenis Foundation, Inc., 59 Temple Place - Suite 330,
20b725ae77Skettenis Boston, MA 02111-1307, USA. */
21b725ae77Skettenis
22b725ae77Skettenis #include <fcntl.h>
23b725ae77Skettenis
24b725ae77Skettenis #include "defs.h"
25b725ae77Skettenis #include "inferior.h"
26b725ae77Skettenis #include "gdb_wait.h"
27b725ae77Skettenis #include "gdbcore.h"
28b725ae77Skettenis #include "command.h"
29b725ae77Skettenis #include "gdbcmd.h"
30b725ae77Skettenis #include "floatformat.h"
31b725ae77Skettenis #include "buildsym.h"
32b725ae77Skettenis #include "i387-tdep.h"
33b725ae77Skettenis #include "i386-tdep.h"
34b725ae77Skettenis #include "value.h"
35b725ae77Skettenis #include "regcache.h"
36b725ae77Skettenis #include "gdb_string.h"
37b725ae77Skettenis
38b725ae77Skettenis #include <stdio.h> /* might be required for __DJGPP_MINOR__ */
39b725ae77Skettenis #include <stdlib.h>
40b725ae77Skettenis #include <ctype.h>
41b725ae77Skettenis #include <errno.h>
42b725ae77Skettenis #include <unistd.h>
43b725ae77Skettenis #include <sys/utsname.h>
44b725ae77Skettenis #include <io.h>
45b725ae77Skettenis #include <dos.h>
46b725ae77Skettenis #include <dpmi.h>
47b725ae77Skettenis #include <go32.h>
48b725ae77Skettenis #include <sys/farptr.h>
49b725ae77Skettenis #include <debug/v2load.h>
50b725ae77Skettenis #include <debug/dbgcom.h>
51b725ae77Skettenis #if __DJGPP_MINOR__ > 2
52b725ae77Skettenis #include <debug/redir.h>
53b725ae77Skettenis #endif
54b725ae77Skettenis
55b725ae77Skettenis #if __DJGPP_MINOR__ < 3
56b725ae77Skettenis /* This code will be provided from DJGPP 2.03 on. Until then I code it
57b725ae77Skettenis here */
58b725ae77Skettenis typedef struct
59b725ae77Skettenis {
60b725ae77Skettenis unsigned short sig0;
61b725ae77Skettenis unsigned short sig1;
62b725ae77Skettenis unsigned short sig2;
63b725ae77Skettenis unsigned short sig3;
64b725ae77Skettenis unsigned short exponent:15;
65b725ae77Skettenis unsigned short sign:1;
66b725ae77Skettenis }
67b725ae77Skettenis NPXREG;
68b725ae77Skettenis
69b725ae77Skettenis typedef struct
70b725ae77Skettenis {
71b725ae77Skettenis unsigned int control;
72b725ae77Skettenis unsigned int status;
73b725ae77Skettenis unsigned int tag;
74b725ae77Skettenis unsigned int eip;
75b725ae77Skettenis unsigned int cs;
76b725ae77Skettenis unsigned int dataptr;
77b725ae77Skettenis unsigned int datasel;
78b725ae77Skettenis NPXREG reg[8];
79b725ae77Skettenis }
80b725ae77Skettenis NPX;
81b725ae77Skettenis
82b725ae77Skettenis static NPX npx;
83b725ae77Skettenis
84b725ae77Skettenis static void save_npx (void); /* Save the FPU of the debugged program */
85b725ae77Skettenis static void load_npx (void); /* Restore the FPU of the debugged program */
86b725ae77Skettenis
87b725ae77Skettenis /* ------------------------------------------------------------------------- */
88b725ae77Skettenis /* Store the contents of the NPX in the global variable `npx'. */
89b725ae77Skettenis /* *INDENT-OFF* */
90b725ae77Skettenis
91b725ae77Skettenis static void
save_npx(void)92b725ae77Skettenis save_npx (void)
93b725ae77Skettenis {
94b725ae77Skettenis asm ("inb $0xa0, %%al \n\
95b725ae77Skettenis testb $0x20, %%al \n\
96b725ae77Skettenis jz 1f \n\
97b725ae77Skettenis xorb %%al, %%al \n\
98b725ae77Skettenis outb %%al, $0xf0 \n\
99b725ae77Skettenis movb $0x20, %%al \n\
100b725ae77Skettenis outb %%al, $0xa0 \n\
101b725ae77Skettenis outb %%al, $0x20 \n\
102b725ae77Skettenis 1: \n\
103b725ae77Skettenis fnsave %0 \n\
104b725ae77Skettenis fwait "
105b725ae77Skettenis : "=m" (npx)
106b725ae77Skettenis : /* No input */
107b725ae77Skettenis : "%eax");
108b725ae77Skettenis }
109b725ae77Skettenis
110b725ae77Skettenis /* *INDENT-ON* */
111b725ae77Skettenis
112b725ae77Skettenis
113b725ae77Skettenis /* ------------------------------------------------------------------------- */
114b725ae77Skettenis /* Reload the contents of the NPX from the global variable `npx'. */
115b725ae77Skettenis
116b725ae77Skettenis static void
load_npx(void)117b725ae77Skettenis load_npx (void)
118b725ae77Skettenis {
119b725ae77Skettenis asm ("frstor %0":"=m" (npx));
120b725ae77Skettenis }
121b725ae77Skettenis /* ------------------------------------------------------------------------- */
122b725ae77Skettenis /* Stubs for the missing redirection functions. */
123b725ae77Skettenis typedef struct {
124b725ae77Skettenis char *command;
125b725ae77Skettenis int redirected;
126b725ae77Skettenis } cmdline_t;
127b725ae77Skettenis
128b725ae77Skettenis void
redir_cmdline_delete(cmdline_t * ptr)129b725ae77Skettenis redir_cmdline_delete (cmdline_t *ptr)
130b725ae77Skettenis {
131b725ae77Skettenis ptr->redirected = 0;
132b725ae77Skettenis }
133b725ae77Skettenis
134b725ae77Skettenis int
redir_cmdline_parse(const char * args,cmdline_t * ptr)135b725ae77Skettenis redir_cmdline_parse (const char *args, cmdline_t *ptr)
136b725ae77Skettenis {
137b725ae77Skettenis return -1;
138b725ae77Skettenis }
139b725ae77Skettenis
140b725ae77Skettenis int
redir_to_child(cmdline_t * ptr)141b725ae77Skettenis redir_to_child (cmdline_t *ptr)
142b725ae77Skettenis {
143b725ae77Skettenis return 1;
144b725ae77Skettenis }
145b725ae77Skettenis
146b725ae77Skettenis int
redir_to_debugger(cmdline_t * ptr)147b725ae77Skettenis redir_to_debugger (cmdline_t *ptr)
148b725ae77Skettenis {
149b725ae77Skettenis return 1;
150b725ae77Skettenis }
151b725ae77Skettenis
152b725ae77Skettenis int
redir_debug_init(cmdline_t * ptr)153b725ae77Skettenis redir_debug_init (cmdline_t *ptr)
154b725ae77Skettenis {
155b725ae77Skettenis return 0;
156b725ae77Skettenis }
157b725ae77Skettenis #endif /* __DJGPP_MINOR < 3 */
158b725ae77Skettenis
159b725ae77Skettenis typedef enum { wp_insert, wp_remove, wp_count } wp_op;
160b725ae77Skettenis
161b725ae77Skettenis /* This holds the current reference counts for each debug register. */
162b725ae77Skettenis static int dr_ref_count[4];
163b725ae77Skettenis
164b725ae77Skettenis #define SOME_PID 42
165b725ae77Skettenis
166b725ae77Skettenis static int prog_has_started = 0;
167b725ae77Skettenis static void go32_open (char *name, int from_tty);
168b725ae77Skettenis static void go32_close (int quitting);
169b725ae77Skettenis static void go32_attach (char *args, int from_tty);
170b725ae77Skettenis static void go32_detach (char *args, int from_tty);
171b725ae77Skettenis static void go32_resume (ptid_t ptid, int step,
172b725ae77Skettenis enum target_signal siggnal);
173b725ae77Skettenis static ptid_t go32_wait (ptid_t ptid,
174b725ae77Skettenis struct target_waitstatus *status);
175b725ae77Skettenis static void go32_fetch_registers (int regno);
176b725ae77Skettenis static void store_register (int regno);
177b725ae77Skettenis static void go32_store_registers (int regno);
178b725ae77Skettenis static void go32_prepare_to_store (void);
179b725ae77Skettenis static int go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
180b725ae77Skettenis int write,
181b725ae77Skettenis struct mem_attrib *attrib,
182b725ae77Skettenis struct target_ops *target);
183b725ae77Skettenis static void go32_files_info (struct target_ops *target);
184b725ae77Skettenis static void go32_stop (void);
185b725ae77Skettenis static void go32_kill_inferior (void);
186*11efff7fSkettenis static void go32_create_inferior (char *exec_file, char *args, char **env, int from_tty);
187b725ae77Skettenis static void go32_mourn_inferior (void);
188b725ae77Skettenis static int go32_can_run (void);
189b725ae77Skettenis
190b725ae77Skettenis static struct target_ops go32_ops;
191b725ae77Skettenis static void go32_terminal_init (void);
192b725ae77Skettenis static void go32_terminal_inferior (void);
193b725ae77Skettenis static void go32_terminal_ours (void);
194b725ae77Skettenis
195b725ae77Skettenis #define r_ofs(x) (offsetof(TSS,x))
196b725ae77Skettenis
197b725ae77Skettenis static struct
198b725ae77Skettenis {
199b725ae77Skettenis size_t tss_ofs;
200b725ae77Skettenis size_t size;
201b725ae77Skettenis }
202b725ae77Skettenis regno_mapping[] =
203b725ae77Skettenis {
204b725ae77Skettenis {r_ofs (tss_eax), 4}, /* normal registers, from a_tss */
205b725ae77Skettenis {r_ofs (tss_ecx), 4},
206b725ae77Skettenis {r_ofs (tss_edx), 4},
207b725ae77Skettenis {r_ofs (tss_ebx), 4},
208b725ae77Skettenis {r_ofs (tss_esp), 4},
209b725ae77Skettenis {r_ofs (tss_ebp), 4},
210b725ae77Skettenis {r_ofs (tss_esi), 4},
211b725ae77Skettenis {r_ofs (tss_edi), 4},
212b725ae77Skettenis {r_ofs (tss_eip), 4},
213b725ae77Skettenis {r_ofs (tss_eflags), 4},
214b725ae77Skettenis {r_ofs (tss_cs), 2},
215b725ae77Skettenis {r_ofs (tss_ss), 2},
216b725ae77Skettenis {r_ofs (tss_ds), 2},
217b725ae77Skettenis {r_ofs (tss_es), 2},
218b725ae77Skettenis {r_ofs (tss_fs), 2},
219b725ae77Skettenis {r_ofs (tss_gs), 2},
220b725ae77Skettenis {0, 10}, /* 8 FP registers, from npx.reg[] */
221b725ae77Skettenis {1, 10},
222b725ae77Skettenis {2, 10},
223b725ae77Skettenis {3, 10},
224b725ae77Skettenis {4, 10},
225b725ae77Skettenis {5, 10},
226b725ae77Skettenis {6, 10},
227b725ae77Skettenis {7, 10},
228b725ae77Skettenis /* The order of the next 7 registers must be consistent
229b725ae77Skettenis with their numbering in config/i386/tm-i386.h, which see. */
230b725ae77Skettenis {0, 2}, /* control word, from npx */
231b725ae77Skettenis {4, 2}, /* status word, from npx */
232b725ae77Skettenis {8, 2}, /* tag word, from npx */
233b725ae77Skettenis {16, 2}, /* last FP exception CS from npx */
234b725ae77Skettenis {12, 4}, /* last FP exception EIP from npx */
235b725ae77Skettenis {24, 2}, /* last FP exception operand selector from npx */
236b725ae77Skettenis {20, 4}, /* last FP exception operand offset from npx */
237b725ae77Skettenis {18, 2} /* last FP opcode from npx */
238b725ae77Skettenis };
239b725ae77Skettenis
240b725ae77Skettenis static struct
241b725ae77Skettenis {
242b725ae77Skettenis int go32_sig;
243b725ae77Skettenis enum target_signal gdb_sig;
244b725ae77Skettenis }
245b725ae77Skettenis sig_map[] =
246b725ae77Skettenis {
247b725ae77Skettenis {0, TARGET_SIGNAL_FPE},
248b725ae77Skettenis {1, TARGET_SIGNAL_TRAP},
249b725ae77Skettenis /* Exception 2 is triggered by the NMI. DJGPP handles it as SIGILL,
250b725ae77Skettenis but I think SIGBUS is better, since the NMI is usually activated
251b725ae77Skettenis as a result of a memory parity check failure. */
252b725ae77Skettenis {2, TARGET_SIGNAL_BUS},
253b725ae77Skettenis {3, TARGET_SIGNAL_TRAP},
254b725ae77Skettenis {4, TARGET_SIGNAL_FPE},
255b725ae77Skettenis {5, TARGET_SIGNAL_SEGV},
256b725ae77Skettenis {6, TARGET_SIGNAL_ILL},
257b725ae77Skettenis {7, TARGET_SIGNAL_EMT}, /* no-coprocessor exception */
258b725ae77Skettenis {8, TARGET_SIGNAL_SEGV},
259b725ae77Skettenis {9, TARGET_SIGNAL_SEGV},
260b725ae77Skettenis {10, TARGET_SIGNAL_BUS},
261b725ae77Skettenis {11, TARGET_SIGNAL_SEGV},
262b725ae77Skettenis {12, TARGET_SIGNAL_SEGV},
263b725ae77Skettenis {13, TARGET_SIGNAL_SEGV},
264b725ae77Skettenis {14, TARGET_SIGNAL_SEGV},
265b725ae77Skettenis {16, TARGET_SIGNAL_FPE},
266b725ae77Skettenis {17, TARGET_SIGNAL_BUS},
267b725ae77Skettenis {31, TARGET_SIGNAL_ILL},
268b725ae77Skettenis {0x1b, TARGET_SIGNAL_INT},
269b725ae77Skettenis {0x75, TARGET_SIGNAL_FPE},
270b725ae77Skettenis {0x78, TARGET_SIGNAL_ALRM},
271b725ae77Skettenis {0x79, TARGET_SIGNAL_INT},
272b725ae77Skettenis {0x7a, TARGET_SIGNAL_QUIT},
273b725ae77Skettenis {-1, TARGET_SIGNAL_LAST}
274b725ae77Skettenis };
275b725ae77Skettenis
276b725ae77Skettenis static struct {
277b725ae77Skettenis enum target_signal gdb_sig;
278b725ae77Skettenis int djgpp_excepno;
279b725ae77Skettenis } excepn_map[] = {
280b725ae77Skettenis {TARGET_SIGNAL_0, -1},
281b725ae77Skettenis {TARGET_SIGNAL_ILL, 6}, /* Invalid Opcode */
282b725ae77Skettenis {TARGET_SIGNAL_EMT, 7}, /* triggers SIGNOFP */
283b725ae77Skettenis {TARGET_SIGNAL_SEGV, 13}, /* GPF */
284b725ae77Skettenis {TARGET_SIGNAL_BUS, 17}, /* Alignment Check */
285b725ae77Skettenis /* The rest are fake exceptions, see dpmiexcp.c in djlsr*.zip for
286b725ae77Skettenis details. */
287b725ae77Skettenis {TARGET_SIGNAL_TERM, 0x1b}, /* triggers Ctrl-Break type of SIGINT */
288b725ae77Skettenis {TARGET_SIGNAL_FPE, 0x75},
289b725ae77Skettenis {TARGET_SIGNAL_INT, 0x79},
290b725ae77Skettenis {TARGET_SIGNAL_QUIT, 0x7a},
291b725ae77Skettenis {TARGET_SIGNAL_ALRM, 0x78}, /* triggers SIGTIMR */
292b725ae77Skettenis {TARGET_SIGNAL_PROF, 0x78},
293b725ae77Skettenis {TARGET_SIGNAL_LAST, -1}
294b725ae77Skettenis };
295b725ae77Skettenis
296b725ae77Skettenis static void
go32_open(char * name,int from_tty)297b725ae77Skettenis go32_open (char *name, int from_tty)
298b725ae77Skettenis {
299b725ae77Skettenis printf_unfiltered ("Done. Use the \"run\" command to run the program.\n");
300b725ae77Skettenis }
301b725ae77Skettenis
302b725ae77Skettenis static void
go32_close(int quitting)303b725ae77Skettenis go32_close (int quitting)
304b725ae77Skettenis {
305b725ae77Skettenis }
306b725ae77Skettenis
307b725ae77Skettenis static void
go32_attach(char * args,int from_tty)308b725ae77Skettenis go32_attach (char *args, int from_tty)
309b725ae77Skettenis {
310b725ae77Skettenis error ("\
311b725ae77Skettenis You cannot attach to a running program on this platform.\n\
312b725ae77Skettenis Use the `run' command to run DJGPP programs.");
313b725ae77Skettenis }
314b725ae77Skettenis
315b725ae77Skettenis static void
go32_detach(char * args,int from_tty)316b725ae77Skettenis go32_detach (char *args, int from_tty)
317b725ae77Skettenis {
318b725ae77Skettenis }
319b725ae77Skettenis
320b725ae77Skettenis static int resume_is_step;
321b725ae77Skettenis static int resume_signal = -1;
322b725ae77Skettenis
323b725ae77Skettenis static void
go32_resume(ptid_t ptid,int step,enum target_signal siggnal)324b725ae77Skettenis go32_resume (ptid_t ptid, int step, enum target_signal siggnal)
325b725ae77Skettenis {
326b725ae77Skettenis int i;
327b725ae77Skettenis
328b725ae77Skettenis resume_is_step = step;
329b725ae77Skettenis
330b725ae77Skettenis if (siggnal != TARGET_SIGNAL_0 && siggnal != TARGET_SIGNAL_TRAP)
331b725ae77Skettenis {
332b725ae77Skettenis for (i = 0, resume_signal = -1;
333b725ae77Skettenis excepn_map[i].gdb_sig != TARGET_SIGNAL_LAST; i++)
334b725ae77Skettenis if (excepn_map[i].gdb_sig == siggnal)
335b725ae77Skettenis {
336b725ae77Skettenis resume_signal = excepn_map[i].djgpp_excepno;
337b725ae77Skettenis break;
338b725ae77Skettenis }
339b725ae77Skettenis if (resume_signal == -1)
340b725ae77Skettenis printf_unfiltered ("Cannot deliver signal %s on this platform.\n",
341b725ae77Skettenis target_signal_to_name (siggnal));
342b725ae77Skettenis }
343b725ae77Skettenis }
344b725ae77Skettenis
345b725ae77Skettenis static char child_cwd[FILENAME_MAX];
346b725ae77Skettenis
347b725ae77Skettenis static ptid_t
go32_wait(ptid_t ptid,struct target_waitstatus * status)348b725ae77Skettenis go32_wait (ptid_t ptid, struct target_waitstatus *status)
349b725ae77Skettenis {
350b725ae77Skettenis int i;
351b725ae77Skettenis unsigned char saved_opcode;
352b725ae77Skettenis unsigned long INT3_addr = 0;
353b725ae77Skettenis int stepping_over_INT = 0;
354b725ae77Skettenis
355b725ae77Skettenis a_tss.tss_eflags &= 0xfeff; /* reset the single-step flag (TF) */
356b725ae77Skettenis if (resume_is_step)
357b725ae77Skettenis {
358b725ae77Skettenis /* If the next instruction is INT xx or INTO, we need to handle
359b725ae77Skettenis them specially. Intel manuals say that these instructions
360b725ae77Skettenis reset the single-step flag (a.k.a. TF). However, it seems
361b725ae77Skettenis that, at least in the DPMI environment, and at least when
362b725ae77Skettenis stepping over the DPMI interrupt 31h, the problem is having
363b725ae77Skettenis TF set at all when INT 31h is executed: the debuggee either
364b725ae77Skettenis crashes (and takes the system with it) or is killed by a
365b725ae77Skettenis SIGTRAP.
366b725ae77Skettenis
367b725ae77Skettenis So we need to emulate single-step mode: we put an INT3 opcode
368b725ae77Skettenis right after the INT xx instruction, let the debuggee run
369b725ae77Skettenis until it hits INT3 and stops, then restore the original
370b725ae77Skettenis instruction which we overwrote with the INT3 opcode, and back
371b725ae77Skettenis up the debuggee's EIP to that instruction. */
372b725ae77Skettenis read_child (a_tss.tss_eip, &saved_opcode, 1);
373b725ae77Skettenis if (saved_opcode == 0xCD || saved_opcode == 0xCE)
374b725ae77Skettenis {
375b725ae77Skettenis unsigned char INT3_opcode = 0xCC;
376b725ae77Skettenis
377b725ae77Skettenis INT3_addr
378b725ae77Skettenis = saved_opcode == 0xCD ? a_tss.tss_eip + 2 : a_tss.tss_eip + 1;
379b725ae77Skettenis stepping_over_INT = 1;
380b725ae77Skettenis read_child (INT3_addr, &saved_opcode, 1);
381b725ae77Skettenis write_child (INT3_addr, &INT3_opcode, 1);
382b725ae77Skettenis }
383b725ae77Skettenis else
384b725ae77Skettenis a_tss.tss_eflags |= 0x0100; /* normal instruction: set TF */
385b725ae77Skettenis }
386b725ae77Skettenis
387b725ae77Skettenis /* The special value FFFFh in tss_trap indicates to run_child that
388b725ae77Skettenis tss_irqn holds a signal to be delivered to the debuggee. */
389b725ae77Skettenis if (resume_signal <= -1)
390b725ae77Skettenis {
391b725ae77Skettenis a_tss.tss_trap = 0;
392b725ae77Skettenis a_tss.tss_irqn = 0xff;
393b725ae77Skettenis }
394b725ae77Skettenis else
395b725ae77Skettenis {
396b725ae77Skettenis a_tss.tss_trap = 0xffff; /* run_child looks for this */
397b725ae77Skettenis a_tss.tss_irqn = resume_signal;
398b725ae77Skettenis }
399b725ae77Skettenis
400b725ae77Skettenis /* The child might change working directory behind our back. The
401b725ae77Skettenis GDB users won't like the side effects of that when they work with
402b725ae77Skettenis relative file names, and GDB might be confused by its current
403b725ae77Skettenis directory not being in sync with the truth. So we always make a
404b725ae77Skettenis point of changing back to where GDB thinks is its cwd, when we
405b725ae77Skettenis return control to the debugger, but restore child's cwd before we
406b725ae77Skettenis run it. */
407b725ae77Skettenis /* Initialize child_cwd, before the first call to run_child and not
408b725ae77Skettenis in the initialization, so the child get also the changed directory
409b725ae77Skettenis set with the gdb-command "cd ..." */
410b725ae77Skettenis if (!*child_cwd)
411b725ae77Skettenis /* Initialize child's cwd with the current one. */
412b725ae77Skettenis getcwd (child_cwd, sizeof (child_cwd));
413b725ae77Skettenis
414b725ae77Skettenis chdir (child_cwd);
415b725ae77Skettenis
416b725ae77Skettenis #if __DJGPP_MINOR__ < 3
417b725ae77Skettenis load_npx ();
418b725ae77Skettenis #endif
419b725ae77Skettenis run_child ();
420b725ae77Skettenis #if __DJGPP_MINOR__ < 3
421b725ae77Skettenis save_npx ();
422b725ae77Skettenis #endif
423b725ae77Skettenis
424b725ae77Skettenis /* Did we step over an INT xx instruction? */
425b725ae77Skettenis if (stepping_over_INT && a_tss.tss_eip == INT3_addr + 1)
426b725ae77Skettenis {
427b725ae77Skettenis /* Restore the original opcode. */
428b725ae77Skettenis a_tss.tss_eip--; /* EIP points *after* the INT3 instruction */
429b725ae77Skettenis write_child (a_tss.tss_eip, &saved_opcode, 1);
430b725ae77Skettenis /* Simulate a TRAP exception. */
431b725ae77Skettenis a_tss.tss_irqn = 1;
432b725ae77Skettenis a_tss.tss_eflags |= 0x0100;
433b725ae77Skettenis }
434b725ae77Skettenis
435b725ae77Skettenis getcwd (child_cwd, sizeof (child_cwd)); /* in case it has changed */
436b725ae77Skettenis chdir (current_directory);
437b725ae77Skettenis
438b725ae77Skettenis if (a_tss.tss_irqn == 0x21)
439b725ae77Skettenis {
440b725ae77Skettenis status->kind = TARGET_WAITKIND_EXITED;
441b725ae77Skettenis status->value.integer = a_tss.tss_eax & 0xff;
442b725ae77Skettenis }
443b725ae77Skettenis else
444b725ae77Skettenis {
445b725ae77Skettenis status->value.sig = TARGET_SIGNAL_UNKNOWN;
446b725ae77Skettenis status->kind = TARGET_WAITKIND_STOPPED;
447b725ae77Skettenis for (i = 0; sig_map[i].go32_sig != -1; i++)
448b725ae77Skettenis {
449b725ae77Skettenis if (a_tss.tss_irqn == sig_map[i].go32_sig)
450b725ae77Skettenis {
451b725ae77Skettenis #if __DJGPP_MINOR__ < 3
452b725ae77Skettenis if ((status->value.sig = sig_map[i].gdb_sig) !=
453b725ae77Skettenis TARGET_SIGNAL_TRAP)
454b725ae77Skettenis status->kind = TARGET_WAITKIND_SIGNALLED;
455b725ae77Skettenis #else
456b725ae77Skettenis status->value.sig = sig_map[i].gdb_sig;
457b725ae77Skettenis #endif
458b725ae77Skettenis break;
459b725ae77Skettenis }
460b725ae77Skettenis }
461b725ae77Skettenis }
462b725ae77Skettenis return pid_to_ptid (SOME_PID);
463b725ae77Skettenis }
464b725ae77Skettenis
465b725ae77Skettenis static void
fetch_register(int regno)466b725ae77Skettenis fetch_register (int regno)
467b725ae77Skettenis {
468b725ae77Skettenis if (regno < FP0_REGNUM)
469*11efff7fSkettenis regcache_raw_supply (current_regcache, regno,
470*11efff7fSkettenis (char *) &a_tss + regno_mapping[regno].tss_ofs);
471b725ae77Skettenis else if (i386_fp_regnum_p (regno) || i386_fpc_regnum_p (regno))
472b725ae77Skettenis i387_supply_fsave (current_regcache, regno, &npx);
473b725ae77Skettenis else
474b725ae77Skettenis internal_error (__FILE__, __LINE__,
475b725ae77Skettenis "Invalid register no. %d in fetch_register.", regno);
476b725ae77Skettenis }
477b725ae77Skettenis
478b725ae77Skettenis static void
go32_fetch_registers(int regno)479b725ae77Skettenis go32_fetch_registers (int regno)
480b725ae77Skettenis {
481b725ae77Skettenis if (regno >= 0)
482b725ae77Skettenis fetch_register (regno);
483b725ae77Skettenis else
484b725ae77Skettenis {
485b725ae77Skettenis for (regno = 0; regno < FP0_REGNUM; regno++)
486b725ae77Skettenis fetch_register (regno);
487b725ae77Skettenis i387_supply_fsave (current_regcache, -1, &npx);
488b725ae77Skettenis }
489b725ae77Skettenis }
490b725ae77Skettenis
491b725ae77Skettenis static void
store_register(int regno)492b725ae77Skettenis store_register (int regno)
493b725ae77Skettenis {
494b725ae77Skettenis if (regno < FP0_REGNUM)
495*11efff7fSkettenis regcache_raw_collect (current_regcache, regno,
496*11efff7fSkettenis (char *) &a_tss + regno_mapping[regno].tss_ofs);
497b725ae77Skettenis else if (i386_fp_regnum_p (regno) || i386_fpc_regnum_p (regno))
498b725ae77Skettenis i387_fill_fsave ((char *) &npx, regno);
499b725ae77Skettenis else
500b725ae77Skettenis internal_error (__FILE__, __LINE__,
501b725ae77Skettenis "Invalid register no. %d in store_register.", regno);
502b725ae77Skettenis }
503b725ae77Skettenis
504b725ae77Skettenis static void
go32_store_registers(int regno)505b725ae77Skettenis go32_store_registers (int regno)
506b725ae77Skettenis {
507b725ae77Skettenis unsigned r;
508b725ae77Skettenis
509b725ae77Skettenis if (regno >= 0)
510b725ae77Skettenis store_register (regno);
511b725ae77Skettenis else
512b725ae77Skettenis {
513b725ae77Skettenis for (r = 0; r < FP0_REGNUM; r++)
514b725ae77Skettenis store_register (r);
515b725ae77Skettenis i387_fill_fsave ((char *) &npx, -1);
516b725ae77Skettenis }
517b725ae77Skettenis }
518b725ae77Skettenis
519b725ae77Skettenis static void
go32_prepare_to_store(void)520b725ae77Skettenis go32_prepare_to_store (void)
521b725ae77Skettenis {
522b725ae77Skettenis }
523b725ae77Skettenis
524b725ae77Skettenis static int
go32_xfer_memory(CORE_ADDR memaddr,char * myaddr,int len,int write,struct mem_attrib * attrib,struct target_ops * target)525b725ae77Skettenis go32_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
526b725ae77Skettenis struct mem_attrib *attrib, struct target_ops *target)
527b725ae77Skettenis {
528b725ae77Skettenis if (write)
529b725ae77Skettenis {
530b725ae77Skettenis if (write_child (memaddr, myaddr, len))
531b725ae77Skettenis {
532b725ae77Skettenis return 0;
533b725ae77Skettenis }
534b725ae77Skettenis else
535b725ae77Skettenis {
536b725ae77Skettenis return len;
537b725ae77Skettenis }
538b725ae77Skettenis }
539b725ae77Skettenis else
540b725ae77Skettenis {
541b725ae77Skettenis if (read_child (memaddr, myaddr, len))
542b725ae77Skettenis {
543b725ae77Skettenis return 0;
544b725ae77Skettenis }
545b725ae77Skettenis else
546b725ae77Skettenis {
547b725ae77Skettenis return len;
548b725ae77Skettenis }
549b725ae77Skettenis }
550b725ae77Skettenis }
551b725ae77Skettenis
552b725ae77Skettenis static cmdline_t child_cmd; /* parsed child's command line kept here */
553b725ae77Skettenis
554b725ae77Skettenis static void
go32_files_info(struct target_ops * target)555b725ae77Skettenis go32_files_info (struct target_ops *target)
556b725ae77Skettenis {
557b725ae77Skettenis printf_unfiltered ("You are running a DJGPP V2 program.\n");
558b725ae77Skettenis }
559b725ae77Skettenis
560b725ae77Skettenis static void
go32_stop(void)561b725ae77Skettenis go32_stop (void)
562b725ae77Skettenis {
563b725ae77Skettenis normal_stop ();
564b725ae77Skettenis cleanup_client ();
565b725ae77Skettenis inferior_ptid = null_ptid;
566b725ae77Skettenis prog_has_started = 0;
567b725ae77Skettenis }
568b725ae77Skettenis
569b725ae77Skettenis static void
go32_kill_inferior(void)570b725ae77Skettenis go32_kill_inferior (void)
571b725ae77Skettenis {
572b725ae77Skettenis redir_cmdline_delete (&child_cmd);
573b725ae77Skettenis resume_signal = -1;
574b725ae77Skettenis resume_is_step = 0;
575b725ae77Skettenis unpush_target (&go32_ops);
576b725ae77Skettenis }
577b725ae77Skettenis
578b725ae77Skettenis static void
go32_create_inferior(char * exec_file,char * args,char ** env,int from_tty)579*11efff7fSkettenis go32_create_inferior (char *exec_file, char *args, char **env, int from_tty)
580b725ae77Skettenis {
581b725ae77Skettenis extern char **environ;
582b725ae77Skettenis jmp_buf start_state;
583b725ae77Skettenis char *cmdline;
584b725ae77Skettenis char **env_save = environ;
585b725ae77Skettenis size_t cmdlen;
586b725ae77Skettenis
587b725ae77Skettenis /* If no exec file handed to us, get it from the exec-file command -- with
588b725ae77Skettenis a good, common error message if none is specified. */
589b725ae77Skettenis if (exec_file == 0)
590b725ae77Skettenis exec_file = get_exec_file (1);
591b725ae77Skettenis
592b725ae77Skettenis if (prog_has_started)
593b725ae77Skettenis {
594b725ae77Skettenis go32_stop ();
595b725ae77Skettenis go32_kill_inferior ();
596b725ae77Skettenis }
597b725ae77Skettenis resume_signal = -1;
598b725ae77Skettenis resume_is_step = 0;
599b725ae77Skettenis
600b725ae77Skettenis /* Initialize child's cwd as empty to be initialized when starting
601b725ae77Skettenis the child. */
602b725ae77Skettenis *child_cwd = 0;
603b725ae77Skettenis
604b725ae77Skettenis /* Init command line storage. */
605b725ae77Skettenis if (redir_debug_init (&child_cmd) == -1)
606b725ae77Skettenis internal_error (__FILE__, __LINE__,
607b725ae77Skettenis "Cannot allocate redirection storage: not enough memory.\n");
608b725ae77Skettenis
609b725ae77Skettenis /* Parse the command line and create redirections. */
610b725ae77Skettenis if (strpbrk (args, "<>"))
611b725ae77Skettenis {
612b725ae77Skettenis if (redir_cmdline_parse (args, &child_cmd) == 0)
613b725ae77Skettenis args = child_cmd.command;
614b725ae77Skettenis else
615b725ae77Skettenis error ("Syntax error in command line.");
616b725ae77Skettenis }
617b725ae77Skettenis else
618b725ae77Skettenis child_cmd.command = xstrdup (args);
619b725ae77Skettenis
620b725ae77Skettenis cmdlen = strlen (args);
621b725ae77Skettenis /* v2loadimage passes command lines via DOS memory, so it cannot
622b725ae77Skettenis possibly handle commands longer than 1MB. */
623b725ae77Skettenis if (cmdlen > 1024*1024)
624b725ae77Skettenis error ("Command line too long.");
625b725ae77Skettenis
626b725ae77Skettenis cmdline = xmalloc (cmdlen + 4);
627b725ae77Skettenis strcpy (cmdline + 1, args);
628b725ae77Skettenis /* If the command-line length fits into DOS 126-char limits, use the
629b725ae77Skettenis DOS command tail format; otherwise, tell v2loadimage to pass it
630b725ae77Skettenis through a buffer in conventional memory. */
631b725ae77Skettenis if (cmdlen < 127)
632b725ae77Skettenis {
633b725ae77Skettenis cmdline[0] = strlen (args);
634b725ae77Skettenis cmdline[cmdlen + 1] = 13;
635b725ae77Skettenis }
636b725ae77Skettenis else
637b725ae77Skettenis cmdline[0] = 0xff; /* signal v2loadimage it's a long command */
638b725ae77Skettenis
639b725ae77Skettenis environ = env;
640b725ae77Skettenis
641b725ae77Skettenis if (v2loadimage (exec_file, cmdline, start_state))
642b725ae77Skettenis {
643b725ae77Skettenis environ = env_save;
644b725ae77Skettenis printf_unfiltered ("Load failed for image %s\n", exec_file);
645b725ae77Skettenis exit (1);
646b725ae77Skettenis }
647b725ae77Skettenis environ = env_save;
648b725ae77Skettenis xfree (cmdline);
649b725ae77Skettenis
650b725ae77Skettenis edi_init (start_state);
651b725ae77Skettenis #if __DJGPP_MINOR__ < 3
652b725ae77Skettenis save_npx ();
653b725ae77Skettenis #endif
654b725ae77Skettenis
655b725ae77Skettenis inferior_ptid = pid_to_ptid (SOME_PID);
656b725ae77Skettenis push_target (&go32_ops);
657b725ae77Skettenis clear_proceed_status ();
658b725ae77Skettenis insert_breakpoints ();
659b725ae77Skettenis proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
660b725ae77Skettenis prog_has_started = 1;
661b725ae77Skettenis }
662b725ae77Skettenis
663b725ae77Skettenis static void
go32_mourn_inferior(void)664b725ae77Skettenis go32_mourn_inferior (void)
665b725ae77Skettenis {
666b725ae77Skettenis /* We need to make sure all the breakpoint enable bits in the DR7
667b725ae77Skettenis register are reset when the inferior exits. Otherwise, if they
668b725ae77Skettenis rerun the inferior, the uncleared bits may cause random SIGTRAPs,
669b725ae77Skettenis failure to set more watchpoints, and other calamities. It would
670b725ae77Skettenis be nice if GDB itself would take care to remove all breakpoints
671b725ae77Skettenis at all times, but it doesn't, probably under an assumption that
672b725ae77Skettenis the OS cleans up when the debuggee exits. */
673b725ae77Skettenis i386_cleanup_dregs ();
674b725ae77Skettenis go32_kill_inferior ();
675b725ae77Skettenis generic_mourn_inferior ();
676b725ae77Skettenis }
677b725ae77Skettenis
678b725ae77Skettenis static int
go32_can_run(void)679b725ae77Skettenis go32_can_run (void)
680b725ae77Skettenis {
681b725ae77Skettenis return 1;
682b725ae77Skettenis }
683b725ae77Skettenis
684b725ae77Skettenis /* Hardware watchpoint support. */
685b725ae77Skettenis
686b725ae77Skettenis #define D_REGS edi.dr
687b725ae77Skettenis #define CONTROL D_REGS[7]
688b725ae77Skettenis #define STATUS D_REGS[6]
689b725ae77Skettenis
690b725ae77Skettenis /* Pass the address ADDR to the inferior in the I'th debug register.
691b725ae77Skettenis Here we just store the address in D_REGS, the watchpoint will be
692b725ae77Skettenis actually set up when go32_wait runs the debuggee. */
693b725ae77Skettenis void
go32_set_dr(int i,CORE_ADDR addr)694b725ae77Skettenis go32_set_dr (int i, CORE_ADDR addr)
695b725ae77Skettenis {
696b725ae77Skettenis if (i < 0 || i > 3)
697b725ae77Skettenis internal_error (__FILE__, __LINE__,
698b725ae77Skettenis "Invalid register %d in go32_set_dr.\n", i);
699b725ae77Skettenis D_REGS[i] = addr;
700b725ae77Skettenis }
701b725ae77Skettenis
702b725ae77Skettenis /* Pass the value VAL to the inferior in the DR7 debug control
703b725ae77Skettenis register. Here we just store the address in D_REGS, the watchpoint
704b725ae77Skettenis will be actually set up when go32_wait runs the debuggee. */
705b725ae77Skettenis void
go32_set_dr7(unsigned val)706b725ae77Skettenis go32_set_dr7 (unsigned val)
707b725ae77Skettenis {
708b725ae77Skettenis CONTROL = val;
709b725ae77Skettenis }
710b725ae77Skettenis
711b725ae77Skettenis /* Get the value of the DR6 debug status register from the inferior.
712b725ae77Skettenis Here we just return the value stored in D_REGS, as we've got it
713b725ae77Skettenis from the last go32_wait call. */
714b725ae77Skettenis unsigned
go32_get_dr6(void)715b725ae77Skettenis go32_get_dr6 (void)
716b725ae77Skettenis {
717b725ae77Skettenis return STATUS;
718b725ae77Skettenis }
719b725ae77Skettenis
720b725ae77Skettenis /* Put the device open on handle FD into either raw or cooked
721b725ae77Skettenis mode, return 1 if it was in raw mode, zero otherwise. */
722b725ae77Skettenis
723b725ae77Skettenis static int
device_mode(int fd,int raw_p)724b725ae77Skettenis device_mode (int fd, int raw_p)
725b725ae77Skettenis {
726b725ae77Skettenis int oldmode, newmode;
727b725ae77Skettenis __dpmi_regs regs;
728b725ae77Skettenis
729b725ae77Skettenis regs.x.ax = 0x4400;
730b725ae77Skettenis regs.x.bx = fd;
731b725ae77Skettenis __dpmi_int (0x21, ®s);
732b725ae77Skettenis if (regs.x.flags & 1)
733b725ae77Skettenis return -1;
734b725ae77Skettenis newmode = oldmode = regs.x.dx;
735b725ae77Skettenis
736b725ae77Skettenis if (raw_p)
737b725ae77Skettenis newmode |= 0x20;
738b725ae77Skettenis else
739b725ae77Skettenis newmode &= ~0x20;
740b725ae77Skettenis
741b725ae77Skettenis if (oldmode & 0x80) /* Only for character dev */
742b725ae77Skettenis {
743b725ae77Skettenis regs.x.ax = 0x4401;
744b725ae77Skettenis regs.x.bx = fd;
745b725ae77Skettenis regs.x.dx = newmode & 0xff; /* Force upper byte zero, else it fails */
746b725ae77Skettenis __dpmi_int (0x21, ®s);
747b725ae77Skettenis if (regs.x.flags & 1)
748b725ae77Skettenis return -1;
749b725ae77Skettenis }
750b725ae77Skettenis return (oldmode & 0x20) == 0x20;
751b725ae77Skettenis }
752b725ae77Skettenis
753b725ae77Skettenis
754b725ae77Skettenis static int inf_mode_valid = 0;
755b725ae77Skettenis static int inf_terminal_mode;
756b725ae77Skettenis
757b725ae77Skettenis /* This semaphore is needed because, amazingly enough, GDB calls
758b725ae77Skettenis target.to_terminal_ours more than once after the inferior stops.
759b725ae77Skettenis But we need the information from the first call only, since the
760b725ae77Skettenis second call will always see GDB's own cooked terminal. */
761b725ae77Skettenis static int terminal_is_ours = 1;
762b725ae77Skettenis
763b725ae77Skettenis static void
go32_terminal_init(void)764b725ae77Skettenis go32_terminal_init (void)
765b725ae77Skettenis {
766b725ae77Skettenis inf_mode_valid = 0; /* reinitialize, in case they are restarting child */
767b725ae77Skettenis terminal_is_ours = 1;
768b725ae77Skettenis }
769b725ae77Skettenis
770b725ae77Skettenis static void
go32_terminal_info(char * args,int from_tty)771b725ae77Skettenis go32_terminal_info (char *args, int from_tty)
772b725ae77Skettenis {
773b725ae77Skettenis printf_unfiltered ("Inferior's terminal is in %s mode.\n",
774b725ae77Skettenis !inf_mode_valid
775b725ae77Skettenis ? "default" : inf_terminal_mode ? "raw" : "cooked");
776b725ae77Skettenis
777b725ae77Skettenis #if __DJGPP_MINOR__ > 2
778b725ae77Skettenis if (child_cmd.redirection)
779b725ae77Skettenis {
780b725ae77Skettenis int i;
781b725ae77Skettenis
782b725ae77Skettenis for (i = 0; i < DBG_HANDLES; i++)
783b725ae77Skettenis {
784b725ae77Skettenis if (child_cmd.redirection[i]->file_name)
785b725ae77Skettenis printf_unfiltered ("\tFile handle %d is redirected to `%s'.\n",
786b725ae77Skettenis i, child_cmd.redirection[i]->file_name);
787b725ae77Skettenis else if (_get_dev_info (child_cmd.redirection[i]->inf_handle) == -1)
788b725ae77Skettenis printf_unfiltered
789b725ae77Skettenis ("\tFile handle %d appears to be closed by inferior.\n", i);
790b725ae77Skettenis /* Mask off the raw/cooked bit when comparing device info words. */
791b725ae77Skettenis else if ((_get_dev_info (child_cmd.redirection[i]->inf_handle) & 0xdf)
792b725ae77Skettenis != (_get_dev_info (i) & 0xdf))
793b725ae77Skettenis printf_unfiltered
794b725ae77Skettenis ("\tFile handle %d appears to be redirected by inferior.\n", i);
795b725ae77Skettenis }
796b725ae77Skettenis }
797b725ae77Skettenis #endif
798b725ae77Skettenis }
799b725ae77Skettenis
800b725ae77Skettenis static void
go32_terminal_inferior(void)801b725ae77Skettenis go32_terminal_inferior (void)
802b725ae77Skettenis {
803b725ae77Skettenis /* Redirect standard handles as child wants them. */
804b725ae77Skettenis errno = 0;
805b725ae77Skettenis if (redir_to_child (&child_cmd) == -1)
806b725ae77Skettenis {
807b725ae77Skettenis redir_to_debugger (&child_cmd);
808b725ae77Skettenis error ("Cannot redirect standard handles for program: %s.",
809b725ae77Skettenis safe_strerror (errno));
810b725ae77Skettenis }
811b725ae77Skettenis /* set the console device of the inferior to whatever mode
812b725ae77Skettenis (raw or cooked) we found it last time */
813b725ae77Skettenis if (terminal_is_ours)
814b725ae77Skettenis {
815b725ae77Skettenis if (inf_mode_valid)
816b725ae77Skettenis device_mode (0, inf_terminal_mode);
817b725ae77Skettenis terminal_is_ours = 0;
818b725ae77Skettenis }
819b725ae77Skettenis }
820b725ae77Skettenis
821b725ae77Skettenis static void
go32_terminal_ours(void)822b725ae77Skettenis go32_terminal_ours (void)
823b725ae77Skettenis {
824b725ae77Skettenis /* Switch to cooked mode on the gdb terminal and save the inferior
825b725ae77Skettenis terminal mode to be restored when it is resumed */
826b725ae77Skettenis if (!terminal_is_ours)
827b725ae77Skettenis {
828b725ae77Skettenis inf_terminal_mode = device_mode (0, 0);
829b725ae77Skettenis if (inf_terminal_mode != -1)
830b725ae77Skettenis inf_mode_valid = 1;
831b725ae77Skettenis else
832b725ae77Skettenis /* If device_mode returned -1, we don't know what happens with
833b725ae77Skettenis handle 0 anymore, so make the info invalid. */
834b725ae77Skettenis inf_mode_valid = 0;
835b725ae77Skettenis terminal_is_ours = 1;
836b725ae77Skettenis
837b725ae77Skettenis /* Restore debugger's standard handles. */
838b725ae77Skettenis errno = 0;
839b725ae77Skettenis if (redir_to_debugger (&child_cmd) == -1)
840b725ae77Skettenis {
841b725ae77Skettenis redir_to_child (&child_cmd);
842b725ae77Skettenis error ("Cannot redirect standard handles for debugger: %s.",
843b725ae77Skettenis safe_strerror (errno));
844b725ae77Skettenis }
845b725ae77Skettenis }
846b725ae77Skettenis }
847b725ae77Skettenis
848b725ae77Skettenis static void
init_go32_ops(void)849b725ae77Skettenis init_go32_ops (void)
850b725ae77Skettenis {
851b725ae77Skettenis go32_ops.to_shortname = "djgpp";
852b725ae77Skettenis go32_ops.to_longname = "djgpp target process";
853b725ae77Skettenis go32_ops.to_doc =
854b725ae77Skettenis "Program loaded by djgpp, when gdb is used as an external debugger";
855b725ae77Skettenis go32_ops.to_open = go32_open;
856b725ae77Skettenis go32_ops.to_close = go32_close;
857b725ae77Skettenis go32_ops.to_attach = go32_attach;
858b725ae77Skettenis go32_ops.to_detach = go32_detach;
859b725ae77Skettenis go32_ops.to_resume = go32_resume;
860b725ae77Skettenis go32_ops.to_wait = go32_wait;
861b725ae77Skettenis go32_ops.to_fetch_registers = go32_fetch_registers;
862b725ae77Skettenis go32_ops.to_store_registers = go32_store_registers;
863b725ae77Skettenis go32_ops.to_prepare_to_store = go32_prepare_to_store;
864*11efff7fSkettenis go32_ops.deprecated_xfer_memory = go32_xfer_memory;
865b725ae77Skettenis go32_ops.to_files_info = go32_files_info;
866b725ae77Skettenis go32_ops.to_insert_breakpoint = memory_insert_breakpoint;
867b725ae77Skettenis go32_ops.to_remove_breakpoint = memory_remove_breakpoint;
868b725ae77Skettenis go32_ops.to_terminal_init = go32_terminal_init;
869b725ae77Skettenis go32_ops.to_terminal_inferior = go32_terminal_inferior;
870b725ae77Skettenis go32_ops.to_terminal_ours_for_output = go32_terminal_ours;
871b725ae77Skettenis go32_ops.to_terminal_ours = go32_terminal_ours;
872b725ae77Skettenis go32_ops.to_terminal_info = go32_terminal_info;
873b725ae77Skettenis go32_ops.to_kill = go32_kill_inferior;
874b725ae77Skettenis go32_ops.to_create_inferior = go32_create_inferior;
875b725ae77Skettenis go32_ops.to_mourn_inferior = go32_mourn_inferior;
876b725ae77Skettenis go32_ops.to_can_run = go32_can_run;
877b725ae77Skettenis go32_ops.to_stop = go32_stop;
878b725ae77Skettenis go32_ops.to_stratum = process_stratum;
879b725ae77Skettenis go32_ops.to_has_all_memory = 1;
880b725ae77Skettenis go32_ops.to_has_memory = 1;
881b725ae77Skettenis go32_ops.to_has_stack = 1;
882b725ae77Skettenis go32_ops.to_has_registers = 1;
883b725ae77Skettenis go32_ops.to_has_execution = 1;
884b725ae77Skettenis go32_ops.to_magic = OPS_MAGIC;
885b725ae77Skettenis
886b725ae77Skettenis /* Initialize child's cwd as empty to be initialized when starting
887b725ae77Skettenis the child. */
888b725ae77Skettenis *child_cwd = 0;
889b725ae77Skettenis
890b725ae77Skettenis /* Initialize child's command line storage. */
891b725ae77Skettenis if (redir_debug_init (&child_cmd) == -1)
892b725ae77Skettenis internal_error (__FILE__, __LINE__,
893b725ae77Skettenis "Cannot allocate redirection storage: not enough memory.\n");
894b725ae77Skettenis
895b725ae77Skettenis /* We are always processing GCC-compiled programs. */
896b725ae77Skettenis processing_gcc_compilation = 2;
897b725ae77Skettenis }
898b725ae77Skettenis
899b725ae77Skettenis unsigned short windows_major, windows_minor;
900b725ae77Skettenis
901b725ae77Skettenis /* Compute the version Windows reports via Int 2Fh/AX=1600h. */
902b725ae77Skettenis static void
go32_get_windows_version(void)903b725ae77Skettenis go32_get_windows_version(void)
904b725ae77Skettenis {
905b725ae77Skettenis __dpmi_regs r;
906b725ae77Skettenis
907b725ae77Skettenis r.x.ax = 0x1600;
908b725ae77Skettenis __dpmi_int(0x2f, &r);
909b725ae77Skettenis if (r.h.al > 2 && r.h.al != 0x80 && r.h.al != 0xff
910b725ae77Skettenis && (r.h.al > 3 || r.h.ah > 0))
911b725ae77Skettenis {
912b725ae77Skettenis windows_major = r.h.al;
913b725ae77Skettenis windows_minor = r.h.ah;
914b725ae77Skettenis }
915b725ae77Skettenis else
916b725ae77Skettenis windows_major = 0xff; /* meaning no Windows */
917b725ae77Skettenis }
918b725ae77Skettenis
919b725ae77Skettenis /* A subroutine of go32_sysinfo to display memory info. */
920b725ae77Skettenis static void
print_mem(unsigned long datum,const char * header,int in_pages_p)921b725ae77Skettenis print_mem (unsigned long datum, const char *header, int in_pages_p)
922b725ae77Skettenis {
923b725ae77Skettenis if (datum != 0xffffffffUL)
924b725ae77Skettenis {
925b725ae77Skettenis if (in_pages_p)
926b725ae77Skettenis datum <<= 12;
927b725ae77Skettenis puts_filtered (header);
928b725ae77Skettenis if (datum > 1024)
929b725ae77Skettenis {
930b725ae77Skettenis printf_filtered ("%lu KB", datum >> 10);
931b725ae77Skettenis if (datum > 1024 * 1024)
932b725ae77Skettenis printf_filtered (" (%lu MB)", datum >> 20);
933b725ae77Skettenis }
934b725ae77Skettenis else
935b725ae77Skettenis printf_filtered ("%lu Bytes", datum);
936b725ae77Skettenis puts_filtered ("\n");
937b725ae77Skettenis }
938b725ae77Skettenis }
939b725ae77Skettenis
940b725ae77Skettenis /* Display assorted information about the underlying OS. */
941b725ae77Skettenis static void
go32_sysinfo(char * arg,int from_tty)942b725ae77Skettenis go32_sysinfo (char *arg, int from_tty)
943b725ae77Skettenis {
944b725ae77Skettenis struct utsname u;
945b725ae77Skettenis char cpuid_vendor[13];
946b725ae77Skettenis unsigned cpuid_max = 0, cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx;
947b725ae77Skettenis unsigned true_dos_version = _get_dos_version (1);
948b725ae77Skettenis unsigned advertized_dos_version = ((unsigned int)_osmajor << 8) | _osminor;
949b725ae77Skettenis int dpmi_flags;
950b725ae77Skettenis char dpmi_vendor_info[129];
951b725ae77Skettenis int dpmi_vendor_available =
952b725ae77Skettenis __dpmi_get_capabilities (&dpmi_flags, dpmi_vendor_info);
953b725ae77Skettenis __dpmi_version_ret dpmi_version_data;
954b725ae77Skettenis long eflags;
955b725ae77Skettenis __dpmi_free_mem_info mem_info;
956b725ae77Skettenis __dpmi_regs regs;
957b725ae77Skettenis
958b725ae77Skettenis cpuid_vendor[0] = '\0';
959b725ae77Skettenis if (uname (&u))
960b725ae77Skettenis strcpy (u.machine, "Unknown x86");
961b725ae77Skettenis else if (u.machine[0] == 'i' && u.machine[1] > 4)
962b725ae77Skettenis {
963b725ae77Skettenis /* CPUID with EAX = 0 returns the Vendor ID. */
964b725ae77Skettenis __asm__ __volatile__ ("xorl %%ebx, %%ebx;"
965b725ae77Skettenis "xorl %%ecx, %%ecx;"
966b725ae77Skettenis "xorl %%edx, %%edx;"
967b725ae77Skettenis "movl $0, %%eax;"
968b725ae77Skettenis "cpuid;"
969b725ae77Skettenis "movl %%ebx, %0;"
970b725ae77Skettenis "movl %%edx, %1;"
971b725ae77Skettenis "movl %%ecx, %2;"
972b725ae77Skettenis "movl %%eax, %3;"
973b725ae77Skettenis : "=m" (cpuid_vendor[0]),
974b725ae77Skettenis "=m" (cpuid_vendor[4]),
975b725ae77Skettenis "=m" (cpuid_vendor[8]),
976b725ae77Skettenis "=m" (cpuid_max)
977b725ae77Skettenis :
978b725ae77Skettenis : "%eax", "%ebx", "%ecx", "%edx");
979b725ae77Skettenis cpuid_vendor[12] = '\0';
980b725ae77Skettenis }
981b725ae77Skettenis
982b725ae77Skettenis printf_filtered ("CPU Type.......................%s", u.machine);
983b725ae77Skettenis if (cpuid_vendor[0])
984b725ae77Skettenis printf_filtered (" (%s)", cpuid_vendor);
985b725ae77Skettenis puts_filtered ("\n");
986b725ae77Skettenis
987b725ae77Skettenis /* CPUID with EAX = 1 returns processor signature and features. */
988b725ae77Skettenis if (cpuid_max >= 1)
989b725ae77Skettenis {
990b725ae77Skettenis static char *brand_name[] = {
991b725ae77Skettenis "",
992b725ae77Skettenis " Celeron",
993b725ae77Skettenis " III",
994b725ae77Skettenis " III Xeon",
995b725ae77Skettenis "", "", "", "",
996b725ae77Skettenis " 4"
997b725ae77Skettenis };
998b725ae77Skettenis char cpu_string[80];
999b725ae77Skettenis char cpu_brand[20];
1000b725ae77Skettenis unsigned brand_idx;
1001b725ae77Skettenis int intel_p = strcmp (cpuid_vendor, "GenuineIntel") == 0;
1002b725ae77Skettenis int amd_p = strcmp (cpuid_vendor, "AuthenticAMD") == 0;
1003b725ae77Skettenis unsigned cpu_family, cpu_model;
1004b725ae77Skettenis
1005b725ae77Skettenis __asm__ __volatile__ ("movl $1, %%eax;"
1006b725ae77Skettenis "cpuid;"
1007b725ae77Skettenis : "=a" (cpuid_eax),
1008b725ae77Skettenis "=b" (cpuid_ebx),
1009b725ae77Skettenis "=d" (cpuid_edx)
1010b725ae77Skettenis :
1011b725ae77Skettenis : "%ecx");
1012b725ae77Skettenis brand_idx = cpuid_ebx & 0xff;
1013b725ae77Skettenis cpu_family = (cpuid_eax >> 8) & 0xf;
1014b725ae77Skettenis cpu_model = (cpuid_eax >> 4) & 0xf;
1015b725ae77Skettenis cpu_brand[0] = '\0';
1016b725ae77Skettenis if (intel_p)
1017b725ae77Skettenis {
1018b725ae77Skettenis if (brand_idx > 0
1019b725ae77Skettenis && brand_idx < sizeof(brand_name)/sizeof(brand_name[0])
1020b725ae77Skettenis && *brand_name[brand_idx])
1021b725ae77Skettenis strcpy (cpu_brand, brand_name[brand_idx]);
1022b725ae77Skettenis else if (cpu_family == 5)
1023b725ae77Skettenis {
1024b725ae77Skettenis if (((cpuid_eax >> 12) & 3) == 0 && cpu_model == 4)
1025b725ae77Skettenis strcpy (cpu_brand, " MMX");
1026b725ae77Skettenis else if (cpu_model > 1 && ((cpuid_eax >> 12) & 3) == 1)
1027b725ae77Skettenis strcpy (cpu_brand, " OverDrive");
1028b725ae77Skettenis else if (cpu_model > 1 && ((cpuid_eax >> 12) & 3) == 2)
1029b725ae77Skettenis strcpy (cpu_brand, " Dual");
1030b725ae77Skettenis }
1031b725ae77Skettenis else if (cpu_family == 6 && cpu_model < 8)
1032b725ae77Skettenis {
1033b725ae77Skettenis switch (cpu_model)
1034b725ae77Skettenis {
1035b725ae77Skettenis case 1:
1036b725ae77Skettenis strcpy (cpu_brand, " Pro");
1037b725ae77Skettenis break;
1038b725ae77Skettenis case 3:
1039b725ae77Skettenis strcpy (cpu_brand, " II");
1040b725ae77Skettenis break;
1041b725ae77Skettenis case 5:
1042b725ae77Skettenis strcpy (cpu_brand, " II Xeon");
1043b725ae77Skettenis break;
1044b725ae77Skettenis case 6:
1045b725ae77Skettenis strcpy (cpu_brand, " Celeron");
1046b725ae77Skettenis break;
1047b725ae77Skettenis case 7:
1048b725ae77Skettenis strcpy (cpu_brand, " III");
1049b725ae77Skettenis break;
1050b725ae77Skettenis }
1051b725ae77Skettenis }
1052b725ae77Skettenis }
1053b725ae77Skettenis else if (amd_p)
1054b725ae77Skettenis {
1055b725ae77Skettenis switch (cpu_family)
1056b725ae77Skettenis {
1057b725ae77Skettenis case 4:
1058b725ae77Skettenis strcpy (cpu_brand, "486/5x86");
1059b725ae77Skettenis break;
1060b725ae77Skettenis case 5:
1061b725ae77Skettenis switch (cpu_model)
1062b725ae77Skettenis {
1063b725ae77Skettenis case 0:
1064b725ae77Skettenis case 1:
1065b725ae77Skettenis case 2:
1066b725ae77Skettenis case 3:
1067b725ae77Skettenis strcpy (cpu_brand, "-K5");
1068b725ae77Skettenis break;
1069b725ae77Skettenis case 6:
1070b725ae77Skettenis case 7:
1071b725ae77Skettenis strcpy (cpu_brand, "-K6");
1072b725ae77Skettenis break;
1073b725ae77Skettenis case 8:
1074b725ae77Skettenis strcpy (cpu_brand, "-K6-2");
1075b725ae77Skettenis break;
1076b725ae77Skettenis case 9:
1077b725ae77Skettenis strcpy (cpu_brand, "-K6-III");
1078b725ae77Skettenis break;
1079b725ae77Skettenis }
1080b725ae77Skettenis break;
1081b725ae77Skettenis case 6:
1082b725ae77Skettenis switch (cpu_model)
1083b725ae77Skettenis {
1084b725ae77Skettenis case 1:
1085b725ae77Skettenis case 2:
1086b725ae77Skettenis case 4:
1087b725ae77Skettenis strcpy (cpu_brand, " Athlon");
1088b725ae77Skettenis break;
1089b725ae77Skettenis case 3:
1090b725ae77Skettenis strcpy (cpu_brand, " Duron");
1091b725ae77Skettenis break;
1092b725ae77Skettenis }
1093b725ae77Skettenis break;
1094b725ae77Skettenis }
1095b725ae77Skettenis }
1096b725ae77Skettenis sprintf (cpu_string, "%s%s Model %d Stepping %d",
1097b725ae77Skettenis intel_p ? "Pentium" : (amd_p ? "AMD" : "ix86"),
1098b725ae77Skettenis cpu_brand, cpu_model, cpuid_eax & 0xf);
1099b725ae77Skettenis printfi_filtered (31, "%s\n", cpu_string);
1100b725ae77Skettenis if (((cpuid_edx & (6 | (0x0d << 23))) != 0)
1101b725ae77Skettenis || ((cpuid_edx & 1) == 0)
1102b725ae77Skettenis || (amd_p && (cpuid_edx & (3 << 30)) != 0))
1103b725ae77Skettenis {
1104b725ae77Skettenis puts_filtered ("CPU Features...................");
1105b725ae77Skettenis /* We only list features which might be useful in the DPMI
1106b725ae77Skettenis environment. */
1107b725ae77Skettenis if ((cpuid_edx & 1) == 0)
1108b725ae77Skettenis puts_filtered ("No FPU "); /* it's unusual to not have an FPU */
1109b725ae77Skettenis if ((cpuid_edx & (1 << 1)) != 0)
1110b725ae77Skettenis puts_filtered ("VME ");
1111b725ae77Skettenis if ((cpuid_edx & (1 << 2)) != 0)
1112b725ae77Skettenis puts_filtered ("DE ");
1113b725ae77Skettenis if ((cpuid_edx & (1 << 4)) != 0)
1114b725ae77Skettenis puts_filtered ("TSC ");
1115b725ae77Skettenis if ((cpuid_edx & (1 << 23)) != 0)
1116b725ae77Skettenis puts_filtered ("MMX ");
1117b725ae77Skettenis if ((cpuid_edx & (1 << 25)) != 0)
1118b725ae77Skettenis puts_filtered ("SSE ");
1119b725ae77Skettenis if ((cpuid_edx & (1 << 26)) != 0)
1120b725ae77Skettenis puts_filtered ("SSE2 ");
1121b725ae77Skettenis if (amd_p)
1122b725ae77Skettenis {
1123b725ae77Skettenis if ((cpuid_edx & (1 << 31)) != 0)
1124b725ae77Skettenis puts_filtered ("3DNow! ");
1125b725ae77Skettenis if ((cpuid_edx & (1 << 30)) != 0)
1126b725ae77Skettenis puts_filtered ("3DNow!Ext");
1127b725ae77Skettenis }
1128b725ae77Skettenis puts_filtered ("\n");
1129b725ae77Skettenis }
1130b725ae77Skettenis }
1131b725ae77Skettenis puts_filtered ("\n");
1132b725ae77Skettenis printf_filtered ("DOS Version....................%s %s.%s",
1133b725ae77Skettenis _os_flavor, u.release, u.version);
1134b725ae77Skettenis if (true_dos_version != advertized_dos_version)
1135b725ae77Skettenis printf_filtered (" (disguised as v%d.%d)", _osmajor, _osminor);
1136b725ae77Skettenis puts_filtered ("\n");
1137b725ae77Skettenis if (!windows_major)
1138b725ae77Skettenis go32_get_windows_version ();
1139b725ae77Skettenis if (windows_major != 0xff)
1140b725ae77Skettenis {
1141b725ae77Skettenis const char *windows_flavor;
1142b725ae77Skettenis
1143b725ae77Skettenis printf_filtered ("Windows Version................%d.%02d (Windows ",
1144b725ae77Skettenis windows_major, windows_minor);
1145b725ae77Skettenis switch (windows_major)
1146b725ae77Skettenis {
1147b725ae77Skettenis case 3:
1148b725ae77Skettenis windows_flavor = "3.X";
1149b725ae77Skettenis break;
1150b725ae77Skettenis case 4:
1151b725ae77Skettenis switch (windows_minor)
1152b725ae77Skettenis {
1153b725ae77Skettenis case 0:
1154b725ae77Skettenis windows_flavor = "95, 95A, or 95B";
1155b725ae77Skettenis break;
1156b725ae77Skettenis case 3:
1157b725ae77Skettenis windows_flavor = "95B OSR2.1 or 95C OSR2.5";
1158b725ae77Skettenis break;
1159b725ae77Skettenis case 10:
1160b725ae77Skettenis windows_flavor = "98 or 98 SE";
1161b725ae77Skettenis break;
1162b725ae77Skettenis case 90:
1163b725ae77Skettenis windows_flavor = "ME";
1164b725ae77Skettenis break;
1165b725ae77Skettenis default:
1166b725ae77Skettenis windows_flavor = "9X";
1167b725ae77Skettenis break;
1168b725ae77Skettenis }
1169b725ae77Skettenis break;
1170b725ae77Skettenis default:
1171b725ae77Skettenis windows_flavor = "??";
1172b725ae77Skettenis break;
1173b725ae77Skettenis }
1174b725ae77Skettenis printf_filtered ("%s)\n", windows_flavor);
1175b725ae77Skettenis }
1176b725ae77Skettenis else if (true_dos_version == 0x532 && advertized_dos_version == 0x500)
1177b725ae77Skettenis printf_filtered ("Windows Version................Windows NT or Windows 2000\n");
1178b725ae77Skettenis puts_filtered ("\n");
1179b725ae77Skettenis if (dpmi_vendor_available == 0)
1180b725ae77Skettenis {
1181b725ae77Skettenis /* The DPMI spec says the vendor string should be ASCIIZ, but
1182b725ae77Skettenis I don't trust the vendors to follow that... */
1183b725ae77Skettenis if (!memchr (&dpmi_vendor_info[2], 0, 126))
1184b725ae77Skettenis dpmi_vendor_info[128] = '\0';
1185b725ae77Skettenis printf_filtered ("DPMI Host......................%s v%d.%d (capabilities: %#x)\n",
1186b725ae77Skettenis &dpmi_vendor_info[2],
1187b725ae77Skettenis (unsigned)dpmi_vendor_info[0],
1188b725ae77Skettenis (unsigned)dpmi_vendor_info[1],
1189b725ae77Skettenis ((unsigned)dpmi_flags & 0x7f));
1190b725ae77Skettenis }
1191b725ae77Skettenis __dpmi_get_version (&dpmi_version_data);
1192b725ae77Skettenis printf_filtered ("DPMI Version...................%d.%02d\n",
1193b725ae77Skettenis dpmi_version_data.major, dpmi_version_data.minor);
1194b725ae77Skettenis printf_filtered ("DPMI Info......................%s-bit DPMI, with%s Virtual Memory support\n",
1195b725ae77Skettenis (dpmi_version_data.flags & 1) ? "32" : "16",
1196b725ae77Skettenis (dpmi_version_data.flags & 4) ? "" : "out");
1197b725ae77Skettenis printfi_filtered (31, "Interrupts reflected to %s mode\n",
1198b725ae77Skettenis (dpmi_version_data.flags & 2) ? "V86" : "Real");
1199b725ae77Skettenis printfi_filtered (31, "Processor type: i%d86\n",
1200b725ae77Skettenis dpmi_version_data.cpu);
1201b725ae77Skettenis printfi_filtered (31, "PIC base interrupt: Master: %#x Slave: %#x\n",
1202b725ae77Skettenis dpmi_version_data.master_pic, dpmi_version_data.slave_pic);
1203b725ae77Skettenis
1204b725ae77Skettenis /* a_tss is only initialized when the debuggee is first run. */
1205b725ae77Skettenis if (prog_has_started)
1206b725ae77Skettenis {
1207b725ae77Skettenis __asm__ __volatile__ ("pushfl ; popl %0" : "=g" (eflags));
1208b725ae77Skettenis printf_filtered ("Protection.....................Ring %d (in %s), with%s I/O protection\n",
1209b725ae77Skettenis a_tss.tss_cs & 3, (a_tss.tss_cs & 4) ? "LDT" : "GDT",
1210b725ae77Skettenis (a_tss.tss_cs & 3) > ((eflags >> 12) & 3) ? "" : "out");
1211b725ae77Skettenis }
1212b725ae77Skettenis puts_filtered ("\n");
1213b725ae77Skettenis __dpmi_get_free_memory_information (&mem_info);
1214b725ae77Skettenis print_mem (mem_info.total_number_of_physical_pages,
1215b725ae77Skettenis "DPMI Total Physical Memory.....", 1);
1216b725ae77Skettenis print_mem (mem_info.total_number_of_free_pages,
1217b725ae77Skettenis "DPMI Free Physical Memory......", 1);
1218b725ae77Skettenis print_mem (mem_info.size_of_paging_file_partition_in_pages,
1219b725ae77Skettenis "DPMI Swap Space................", 1);
1220b725ae77Skettenis print_mem (mem_info.linear_address_space_size_in_pages,
1221b725ae77Skettenis "DPMI Total Linear Address Size.", 1);
1222b725ae77Skettenis print_mem (mem_info.free_linear_address_space_in_pages,
1223b725ae77Skettenis "DPMI Free Linear Address Size..", 1);
1224b725ae77Skettenis print_mem (mem_info.largest_available_free_block_in_bytes,
1225b725ae77Skettenis "DPMI Largest Free Memory Block.", 0);
1226b725ae77Skettenis
1227b725ae77Skettenis regs.h.ah = 0x48;
1228b725ae77Skettenis regs.x.bx = 0xffff;
1229b725ae77Skettenis __dpmi_int (0x21, ®s);
1230b725ae77Skettenis print_mem (regs.x.bx << 4, "Free DOS Memory................", 0);
1231b725ae77Skettenis regs.x.ax = 0x5800;
1232b725ae77Skettenis __dpmi_int (0x21, ®s);
1233b725ae77Skettenis if ((regs.x.flags & 1) == 0)
1234b725ae77Skettenis {
1235b725ae77Skettenis static const char *dos_hilo[] = {
1236b725ae77Skettenis "Low", "", "", "", "High", "", "", "", "High, then Low"
1237b725ae77Skettenis };
1238b725ae77Skettenis static const char *dos_fit[] = {
1239b725ae77Skettenis "First", "Best", "Last"
1240b725ae77Skettenis };
1241b725ae77Skettenis int hilo_idx = (regs.x.ax >> 4) & 0x0f;
1242b725ae77Skettenis int fit_idx = regs.x.ax & 0x0f;
1243b725ae77Skettenis
1244b725ae77Skettenis if (hilo_idx > 8)
1245b725ae77Skettenis hilo_idx = 0;
1246b725ae77Skettenis if (fit_idx > 2)
1247b725ae77Skettenis fit_idx = 0;
1248b725ae77Skettenis printf_filtered ("DOS Memory Allocation..........%s memory, %s fit\n",
1249b725ae77Skettenis dos_hilo[hilo_idx], dos_fit[fit_idx]);
1250b725ae77Skettenis regs.x.ax = 0x5802;
1251b725ae77Skettenis __dpmi_int (0x21, ®s);
1252b725ae77Skettenis if ((regs.x.flags & 1) != 0)
1253b725ae77Skettenis regs.h.al = 0;
1254b725ae77Skettenis printfi_filtered (31, "UMBs %sin DOS memory chain\n",
1255b725ae77Skettenis regs.h.al == 0 ? "not " : "");
1256b725ae77Skettenis }
1257b725ae77Skettenis }
1258b725ae77Skettenis
1259b725ae77Skettenis struct seg_descr {
1260b725ae77Skettenis unsigned short limit0 __attribute__((packed));
1261b725ae77Skettenis unsigned short base0 __attribute__((packed));
1262b725ae77Skettenis unsigned char base1 __attribute__((packed));
1263b725ae77Skettenis unsigned stype:5 __attribute__((packed));
1264b725ae77Skettenis unsigned dpl:2 __attribute__((packed));
1265b725ae77Skettenis unsigned present:1 __attribute__((packed));
1266b725ae77Skettenis unsigned limit1:4 __attribute__((packed));
1267b725ae77Skettenis unsigned available:1 __attribute__((packed));
1268b725ae77Skettenis unsigned dummy:1 __attribute__((packed));
1269b725ae77Skettenis unsigned bit32:1 __attribute__((packed));
1270b725ae77Skettenis unsigned page_granular:1 __attribute__((packed));
1271b725ae77Skettenis unsigned char base2 __attribute__((packed));
1272b725ae77Skettenis };
1273b725ae77Skettenis
1274b725ae77Skettenis struct gate_descr {
1275b725ae77Skettenis unsigned short offset0 __attribute__((packed));
1276b725ae77Skettenis unsigned short selector __attribute__((packed));
1277b725ae77Skettenis unsigned param_count:5 __attribute__((packed));
1278b725ae77Skettenis unsigned dummy:3 __attribute__((packed));
1279b725ae77Skettenis unsigned stype:5 __attribute__((packed));
1280b725ae77Skettenis unsigned dpl:2 __attribute__((packed));
1281b725ae77Skettenis unsigned present:1 __attribute__((packed));
1282b725ae77Skettenis unsigned short offset1 __attribute__((packed));
1283b725ae77Skettenis };
1284b725ae77Skettenis
1285b725ae77Skettenis /* Read LEN bytes starting at logical address ADDR, and put the result
1286b725ae77Skettenis into DEST. Return 1 if success, zero if not. */
1287b725ae77Skettenis static int
read_memory_region(unsigned long addr,void * dest,size_t len)1288b725ae77Skettenis read_memory_region (unsigned long addr, void *dest, size_t len)
1289b725ae77Skettenis {
1290b725ae77Skettenis unsigned long dos_ds_limit = __dpmi_get_segment_limit (_dos_ds);
1291b725ae77Skettenis int retval = 1;
1292b725ae77Skettenis
1293b725ae77Skettenis /* For the low memory, we can simply use _dos_ds. */
1294b725ae77Skettenis if (addr <= dos_ds_limit - len)
1295b725ae77Skettenis dosmemget (addr, len, dest);
1296b725ae77Skettenis else
1297b725ae77Skettenis {
1298b725ae77Skettenis /* For memory above 1MB we need to set up a special segment to
1299b725ae77Skettenis be able to access that memory. */
1300b725ae77Skettenis int sel = __dpmi_allocate_ldt_descriptors (1);
1301b725ae77Skettenis
1302b725ae77Skettenis if (sel <= 0)
1303b725ae77Skettenis retval = 0;
1304b725ae77Skettenis else
1305b725ae77Skettenis {
1306b725ae77Skettenis int access_rights = __dpmi_get_descriptor_access_rights (sel);
1307b725ae77Skettenis size_t segment_limit = len - 1;
1308b725ae77Skettenis
1309b725ae77Skettenis /* Make sure the crucial bits in the descriptor access
1310b725ae77Skettenis rights are set correctly. Some DPMI providers might barf
1311b725ae77Skettenis if we set the segment limit to something that is not an
1312b725ae77Skettenis integral multiple of 4KB pages if the granularity bit is
1313b725ae77Skettenis not set to byte-granular, even though the DPMI spec says
1314b725ae77Skettenis it's the host's responsibility to set that bit correctly. */
1315b725ae77Skettenis if (len > 1024 * 1024)
1316b725ae77Skettenis {
1317b725ae77Skettenis access_rights |= 0x8000;
1318b725ae77Skettenis /* Page-granular segments should have the low 12 bits of
1319b725ae77Skettenis the limit set. */
1320b725ae77Skettenis segment_limit |= 0xfff;
1321b725ae77Skettenis }
1322b725ae77Skettenis else
1323b725ae77Skettenis access_rights &= ~0x8000;
1324b725ae77Skettenis
1325b725ae77Skettenis if (__dpmi_set_segment_base_address (sel, addr) != -1
1326b725ae77Skettenis && __dpmi_set_descriptor_access_rights (sel, access_rights) != -1
1327b725ae77Skettenis && __dpmi_set_segment_limit (sel, segment_limit) != -1
1328b725ae77Skettenis /* W2K silently fails to set the segment limit, leaving
1329b725ae77Skettenis it at zero; this test avoids the resulting crash. */
1330b725ae77Skettenis && __dpmi_get_segment_limit (sel) >= segment_limit)
1331b725ae77Skettenis movedata (sel, 0, _my_ds (), (unsigned)dest, len);
1332b725ae77Skettenis else
1333b725ae77Skettenis retval = 0;
1334b725ae77Skettenis
1335b725ae77Skettenis __dpmi_free_ldt_descriptor (sel);
1336b725ae77Skettenis }
1337b725ae77Skettenis }
1338b725ae77Skettenis return retval;
1339b725ae77Skettenis }
1340b725ae77Skettenis
1341b725ae77Skettenis /* Get a segment descriptor stored at index IDX in the descriptor
1342b725ae77Skettenis table whose base address is TABLE_BASE. Return the descriptor
1343b725ae77Skettenis type, or -1 if failure. */
1344b725ae77Skettenis static int
get_descriptor(unsigned long table_base,int idx,void * descr)1345b725ae77Skettenis get_descriptor (unsigned long table_base, int idx, void *descr)
1346b725ae77Skettenis {
1347b725ae77Skettenis unsigned long addr = table_base + idx * 8; /* 8 bytes per entry */
1348b725ae77Skettenis
1349b725ae77Skettenis if (read_memory_region (addr, descr, 8))
1350b725ae77Skettenis return (int)((struct seg_descr *)descr)->stype;
1351b725ae77Skettenis return -1;
1352b725ae77Skettenis }
1353b725ae77Skettenis
1354b725ae77Skettenis struct dtr_reg {
1355b725ae77Skettenis unsigned short limit __attribute__((packed));
1356b725ae77Skettenis unsigned long base __attribute__((packed));
1357b725ae77Skettenis };
1358b725ae77Skettenis
1359b725ae77Skettenis /* Display a segment descriptor stored at index IDX in a descriptor
1360b725ae77Skettenis table whose type is TYPE and whose base address is BASE_ADDR. If
1361b725ae77Skettenis FORCE is non-zero, display even invalid descriptors. */
1362b725ae77Skettenis static void
display_descriptor(unsigned type,unsigned long base_addr,int idx,int force)1363b725ae77Skettenis display_descriptor (unsigned type, unsigned long base_addr, int idx, int force)
1364b725ae77Skettenis {
1365b725ae77Skettenis struct seg_descr descr;
1366b725ae77Skettenis struct gate_descr gate;
1367b725ae77Skettenis
1368b725ae77Skettenis /* Get the descriptor from the table. */
1369b725ae77Skettenis if (idx == 0 && type == 0)
1370b725ae77Skettenis puts_filtered ("0x000: null descriptor\n");
1371b725ae77Skettenis else if (get_descriptor (base_addr, idx, &descr) != -1)
1372b725ae77Skettenis {
1373b725ae77Skettenis /* For each type of descriptor table, this has a bit set if the
1374b725ae77Skettenis corresponding type of selectors is valid in that table. */
1375b725ae77Skettenis static unsigned allowed_descriptors[] = {
1376b725ae77Skettenis 0xffffdafeL, /* GDT */
1377b725ae77Skettenis 0x0000c0e0L, /* IDT */
1378b725ae77Skettenis 0xffffdafaL /* LDT */
1379b725ae77Skettenis };
1380b725ae77Skettenis
1381b725ae77Skettenis /* If the program hasn't started yet, assume the debuggee will
1382b725ae77Skettenis have the same CPL as the debugger. */
1383b725ae77Skettenis int cpl = prog_has_started ? (a_tss.tss_cs & 3) : _my_cs () & 3;
1384b725ae77Skettenis unsigned long limit = (descr.limit1 << 16) | descr.limit0;
1385b725ae77Skettenis
1386b725ae77Skettenis if (descr.present
1387b725ae77Skettenis && (allowed_descriptors[type] & (1 << descr.stype)) != 0)
1388b725ae77Skettenis {
1389b725ae77Skettenis printf_filtered ("0x%03x: ",
1390b725ae77Skettenis type == 1
1391b725ae77Skettenis ? idx : (idx * 8) | (type ? (cpl | 4) : 0));
1392b725ae77Skettenis if (descr.page_granular)
1393b725ae77Skettenis limit = (limit << 12) | 0xfff; /* big segment: low 12 bit set */
1394b725ae77Skettenis if (descr.stype == 1 || descr.stype == 2 || descr.stype == 3
1395b725ae77Skettenis || descr.stype == 9 || descr.stype == 11
1396b725ae77Skettenis || (descr.stype >= 16 && descr.stype < 32))
1397b725ae77Skettenis printf_filtered ("base=0x%02x%02x%04x limit=0x%08lx",
1398b725ae77Skettenis descr.base2, descr.base1, descr.base0, limit);
1399b725ae77Skettenis
1400b725ae77Skettenis switch (descr.stype)
1401b725ae77Skettenis {
1402b725ae77Skettenis case 1:
1403b725ae77Skettenis case 3:
1404b725ae77Skettenis printf_filtered (" 16-bit TSS (task %sactive)",
1405b725ae77Skettenis descr.stype == 3 ? "" : "in");
1406b725ae77Skettenis break;
1407b725ae77Skettenis case 2:
1408b725ae77Skettenis puts_filtered (" LDT");
1409b725ae77Skettenis break;
1410b725ae77Skettenis case 4:
1411b725ae77Skettenis memcpy (&gate, &descr, sizeof gate);
1412b725ae77Skettenis printf_filtered ("selector=0x%04x offs=0x%04x%04x",
1413b725ae77Skettenis gate.selector, gate.offset1, gate.offset0);
1414b725ae77Skettenis printf_filtered (" 16-bit Call Gate (params=%d)",
1415b725ae77Skettenis gate.param_count);
1416b725ae77Skettenis break;
1417b725ae77Skettenis case 5:
1418b725ae77Skettenis printf_filtered ("TSS selector=0x%04x", descr.base0);
1419b725ae77Skettenis printfi_filtered (16, "Task Gate");
1420b725ae77Skettenis break;
1421b725ae77Skettenis case 6:
1422b725ae77Skettenis case 7:
1423b725ae77Skettenis memcpy (&gate, &descr, sizeof gate);
1424b725ae77Skettenis printf_filtered ("selector=0x%04x offs=0x%04x%04x",
1425b725ae77Skettenis gate.selector, gate.offset1, gate.offset0);
1426b725ae77Skettenis printf_filtered (" 16-bit %s Gate",
1427b725ae77Skettenis descr.stype == 6 ? "Interrupt" : "Trap");
1428b725ae77Skettenis break;
1429b725ae77Skettenis case 9:
1430b725ae77Skettenis case 11:
1431b725ae77Skettenis printf_filtered (" 32-bit TSS (task %sactive)",
1432b725ae77Skettenis descr.stype == 3 ? "" : "in");
1433b725ae77Skettenis break;
1434b725ae77Skettenis case 12:
1435b725ae77Skettenis memcpy (&gate, &descr, sizeof gate);
1436b725ae77Skettenis printf_filtered ("selector=0x%04x offs=0x%04x%04x",
1437b725ae77Skettenis gate.selector, gate.offset1, gate.offset0);
1438b725ae77Skettenis printf_filtered (" 32-bit Call Gate (params=%d)",
1439b725ae77Skettenis gate.param_count);
1440b725ae77Skettenis break;
1441b725ae77Skettenis case 14:
1442b725ae77Skettenis case 15:
1443b725ae77Skettenis memcpy (&gate, &descr, sizeof gate);
1444b725ae77Skettenis printf_filtered ("selector=0x%04x offs=0x%04x%04x",
1445b725ae77Skettenis gate.selector, gate.offset1, gate.offset0);
1446b725ae77Skettenis printf_filtered (" 32-bit %s Gate",
1447b725ae77Skettenis descr.stype == 14 ? "Interrupt" : "Trap");
1448b725ae77Skettenis break;
1449b725ae77Skettenis case 16: /* data segments */
1450b725ae77Skettenis case 17:
1451b725ae77Skettenis case 18:
1452b725ae77Skettenis case 19:
1453b725ae77Skettenis case 20:
1454b725ae77Skettenis case 21:
1455b725ae77Skettenis case 22:
1456b725ae77Skettenis case 23:
1457b725ae77Skettenis printf_filtered (" %s-bit Data (%s Exp-%s%s)",
1458b725ae77Skettenis descr.bit32 ? "32" : "16",
1459b725ae77Skettenis descr.stype & 2 ? "Read/Write," : "Read-Only, ",
1460b725ae77Skettenis descr.stype & 4 ? "down" : "up",
1461b725ae77Skettenis descr.stype & 1 ? "" : ", N.Acc");
1462b725ae77Skettenis break;
1463b725ae77Skettenis case 24: /* code segments */
1464b725ae77Skettenis case 25:
1465b725ae77Skettenis case 26:
1466b725ae77Skettenis case 27:
1467b725ae77Skettenis case 28:
1468b725ae77Skettenis case 29:
1469b725ae77Skettenis case 30:
1470b725ae77Skettenis case 31:
1471b725ae77Skettenis printf_filtered (" %s-bit Code (%s, %sConf%s)",
1472b725ae77Skettenis descr.bit32 ? "32" : "16",
1473b725ae77Skettenis descr.stype & 2 ? "Exec/Read" : "Exec-Only",
1474b725ae77Skettenis descr.stype & 4 ? "" : "N.",
1475b725ae77Skettenis descr.stype & 1 ? "" : ", N.Acc");
1476b725ae77Skettenis break;
1477b725ae77Skettenis default:
1478b725ae77Skettenis printf_filtered ("Unknown type 0x%02x", descr.stype);
1479b725ae77Skettenis break;
1480b725ae77Skettenis }
1481b725ae77Skettenis puts_filtered ("\n");
1482b725ae77Skettenis }
1483b725ae77Skettenis else if (force)
1484b725ae77Skettenis {
1485b725ae77Skettenis printf_filtered ("0x%03x: ",
1486b725ae77Skettenis type == 1
1487b725ae77Skettenis ? idx : (idx * 8) | (type ? (cpl | 4) : 0));
1488b725ae77Skettenis if (!descr.present)
1489b725ae77Skettenis puts_filtered ("Segment not present\n");
1490b725ae77Skettenis else
1491b725ae77Skettenis printf_filtered ("Segment type 0x%02x is invalid in this table\n",
1492b725ae77Skettenis descr.stype);
1493b725ae77Skettenis }
1494b725ae77Skettenis }
1495b725ae77Skettenis else if (force)
1496b725ae77Skettenis printf_filtered ("0x%03x: Cannot read this descriptor\n", idx);
1497b725ae77Skettenis }
1498b725ae77Skettenis
1499b725ae77Skettenis static void
go32_sldt(char * arg,int from_tty)1500b725ae77Skettenis go32_sldt (char *arg, int from_tty)
1501b725ae77Skettenis {
1502b725ae77Skettenis struct dtr_reg gdtr;
1503b725ae77Skettenis unsigned short ldtr = 0;
1504b725ae77Skettenis int ldt_idx;
1505b725ae77Skettenis struct seg_descr ldt_descr;
1506b725ae77Skettenis long ldt_entry = -1L;
1507b725ae77Skettenis int cpl = (prog_has_started ? a_tss.tss_cs : _my_cs ()) & 3;
1508b725ae77Skettenis
1509b725ae77Skettenis if (arg && *arg)
1510b725ae77Skettenis {
1511b725ae77Skettenis while (*arg && isspace(*arg))
1512b725ae77Skettenis arg++;
1513b725ae77Skettenis
1514b725ae77Skettenis if (*arg)
1515b725ae77Skettenis {
1516b725ae77Skettenis ldt_entry = parse_and_eval_long (arg);
1517b725ae77Skettenis if (ldt_entry < 0
1518b725ae77Skettenis || (ldt_entry & 4) == 0
1519b725ae77Skettenis || (ldt_entry & 3) != (cpl & 3))
1520b725ae77Skettenis error ("Invalid LDT entry 0x%03lx.", (unsigned long)ldt_entry);
1521b725ae77Skettenis }
1522b725ae77Skettenis }
1523b725ae77Skettenis
1524b725ae77Skettenis __asm__ __volatile__ ("sgdt %0" : "=m" (gdtr) : /* no inputs */ );
1525b725ae77Skettenis __asm__ __volatile__ ("sldt %0" : "=m" (ldtr) : /* no inputs */ );
1526b725ae77Skettenis ldt_idx = ldtr / 8;
1527b725ae77Skettenis if (ldt_idx == 0)
1528b725ae77Skettenis puts_filtered ("There is no LDT.\n");
1529b725ae77Skettenis /* LDT's entry in the GDT must have the type LDT, which is 2. */
1530b725ae77Skettenis else if (get_descriptor (gdtr.base, ldt_idx, &ldt_descr) != 2)
1531b725ae77Skettenis printf_filtered ("LDT is present (at %#x), but unreadable by GDB.\n",
1532b725ae77Skettenis ldt_descr.base0
1533b725ae77Skettenis | (ldt_descr.base1 << 16)
1534b725ae77Skettenis | (ldt_descr.base2 << 24));
1535b725ae77Skettenis else
1536b725ae77Skettenis {
1537b725ae77Skettenis unsigned base =
1538b725ae77Skettenis ldt_descr.base0
1539b725ae77Skettenis | (ldt_descr.base1 << 16)
1540b725ae77Skettenis | (ldt_descr.base2 << 24);
1541b725ae77Skettenis unsigned limit = ldt_descr.limit0 | (ldt_descr.limit1 << 16);
1542b725ae77Skettenis int max_entry;
1543b725ae77Skettenis
1544b725ae77Skettenis if (ldt_descr.page_granular)
1545b725ae77Skettenis /* Page-granular segments must have the low 12 bits of their
1546b725ae77Skettenis limit set. */
1547b725ae77Skettenis limit = (limit << 12) | 0xfff;
1548b725ae77Skettenis /* LDT cannot have more than 8K 8-byte entries, i.e. more than
1549b725ae77Skettenis 64KB. */
1550b725ae77Skettenis if (limit > 0xffff)
1551b725ae77Skettenis limit = 0xffff;
1552b725ae77Skettenis
1553b725ae77Skettenis max_entry = (limit + 1) / 8;
1554b725ae77Skettenis
1555b725ae77Skettenis if (ldt_entry >= 0)
1556b725ae77Skettenis {
1557b725ae77Skettenis if (ldt_entry > limit)
1558b725ae77Skettenis error ("Invalid LDT entry %#lx: outside valid limits [0..%#x]",
1559b725ae77Skettenis (unsigned long)ldt_entry, limit);
1560b725ae77Skettenis
1561b725ae77Skettenis display_descriptor (ldt_descr.stype, base, ldt_entry / 8, 1);
1562b725ae77Skettenis }
1563b725ae77Skettenis else
1564b725ae77Skettenis {
1565b725ae77Skettenis int i;
1566b725ae77Skettenis
1567b725ae77Skettenis for (i = 0; i < max_entry; i++)
1568b725ae77Skettenis display_descriptor (ldt_descr.stype, base, i, 0);
1569b725ae77Skettenis }
1570b725ae77Skettenis }
1571b725ae77Skettenis }
1572b725ae77Skettenis
1573b725ae77Skettenis static void
go32_sgdt(char * arg,int from_tty)1574b725ae77Skettenis go32_sgdt (char *arg, int from_tty)
1575b725ae77Skettenis {
1576b725ae77Skettenis struct dtr_reg gdtr;
1577b725ae77Skettenis long gdt_entry = -1L;
1578b725ae77Skettenis int max_entry;
1579b725ae77Skettenis
1580b725ae77Skettenis if (arg && *arg)
1581b725ae77Skettenis {
1582b725ae77Skettenis while (*arg && isspace(*arg))
1583b725ae77Skettenis arg++;
1584b725ae77Skettenis
1585b725ae77Skettenis if (*arg)
1586b725ae77Skettenis {
1587b725ae77Skettenis gdt_entry = parse_and_eval_long (arg);
1588b725ae77Skettenis if (gdt_entry < 0 || (gdt_entry & 7) != 0)
1589b725ae77Skettenis error ("Invalid GDT entry 0x%03lx: not an integral multiple of 8.",
1590b725ae77Skettenis (unsigned long)gdt_entry);
1591b725ae77Skettenis }
1592b725ae77Skettenis }
1593b725ae77Skettenis
1594b725ae77Skettenis __asm__ __volatile__ ("sgdt %0" : "=m" (gdtr) : /* no inputs */ );
1595b725ae77Skettenis max_entry = (gdtr.limit + 1) / 8;
1596b725ae77Skettenis
1597b725ae77Skettenis if (gdt_entry >= 0)
1598b725ae77Skettenis {
1599b725ae77Skettenis if (gdt_entry > gdtr.limit)
1600b725ae77Skettenis error ("Invalid GDT entry %#lx: outside valid limits [0..%#x]",
1601b725ae77Skettenis (unsigned long)gdt_entry, gdtr.limit);
1602b725ae77Skettenis
1603b725ae77Skettenis display_descriptor (0, gdtr.base, gdt_entry / 8, 1);
1604b725ae77Skettenis }
1605b725ae77Skettenis else
1606b725ae77Skettenis {
1607b725ae77Skettenis int i;
1608b725ae77Skettenis
1609b725ae77Skettenis for (i = 0; i < max_entry; i++)
1610b725ae77Skettenis display_descriptor (0, gdtr.base, i, 0);
1611b725ae77Skettenis }
1612b725ae77Skettenis }
1613b725ae77Skettenis
1614b725ae77Skettenis static void
go32_sidt(char * arg,int from_tty)1615b725ae77Skettenis go32_sidt (char *arg, int from_tty)
1616b725ae77Skettenis {
1617b725ae77Skettenis struct dtr_reg idtr;
1618b725ae77Skettenis long idt_entry = -1L;
1619b725ae77Skettenis int max_entry;
1620b725ae77Skettenis
1621b725ae77Skettenis if (arg && *arg)
1622b725ae77Skettenis {
1623b725ae77Skettenis while (*arg && isspace(*arg))
1624b725ae77Skettenis arg++;
1625b725ae77Skettenis
1626b725ae77Skettenis if (*arg)
1627b725ae77Skettenis {
1628b725ae77Skettenis idt_entry = parse_and_eval_long (arg);
1629b725ae77Skettenis if (idt_entry < 0)
1630b725ae77Skettenis error ("Invalid (negative) IDT entry %ld.", idt_entry);
1631b725ae77Skettenis }
1632b725ae77Skettenis }
1633b725ae77Skettenis
1634b725ae77Skettenis __asm__ __volatile__ ("sidt %0" : "=m" (idtr) : /* no inputs */ );
1635b725ae77Skettenis max_entry = (idtr.limit + 1) / 8;
1636b725ae77Skettenis if (max_entry > 0x100) /* no more than 256 entries */
1637b725ae77Skettenis max_entry = 0x100;
1638b725ae77Skettenis
1639b725ae77Skettenis if (idt_entry >= 0)
1640b725ae77Skettenis {
1641b725ae77Skettenis if (idt_entry > idtr.limit)
1642b725ae77Skettenis error ("Invalid IDT entry %#lx: outside valid limits [0..%#x]",
1643b725ae77Skettenis (unsigned long)idt_entry, idtr.limit);
1644b725ae77Skettenis
1645b725ae77Skettenis display_descriptor (1, idtr.base, idt_entry, 1);
1646b725ae77Skettenis }
1647b725ae77Skettenis else
1648b725ae77Skettenis {
1649b725ae77Skettenis int i;
1650b725ae77Skettenis
1651b725ae77Skettenis for (i = 0; i < max_entry; i++)
1652b725ae77Skettenis display_descriptor (1, idtr.base, i, 0);
1653b725ae77Skettenis }
1654b725ae77Skettenis }
1655b725ae77Skettenis
1656b725ae77Skettenis /* Cached linear address of the base of the page directory. For
1657b725ae77Skettenis now, available only under CWSDPMI. Code based on ideas and
1658b725ae77Skettenis suggestions from Charles Sandmann <sandmann@clio.rice.edu>. */
1659b725ae77Skettenis static unsigned long pdbr;
1660b725ae77Skettenis
1661b725ae77Skettenis static unsigned long
get_cr3(void)1662b725ae77Skettenis get_cr3 (void)
1663b725ae77Skettenis {
1664b725ae77Skettenis unsigned offset;
1665b725ae77Skettenis unsigned taskreg;
1666b725ae77Skettenis unsigned long taskbase, cr3;
1667b725ae77Skettenis struct dtr_reg gdtr;
1668b725ae77Skettenis
1669b725ae77Skettenis if (pdbr > 0 && pdbr <= 0xfffff)
1670b725ae77Skettenis return pdbr;
1671b725ae77Skettenis
1672b725ae77Skettenis /* Get the linear address of GDT and the Task Register. */
1673b725ae77Skettenis __asm__ __volatile__ ("sgdt %0" : "=m" (gdtr) : /* no inputs */ );
1674b725ae77Skettenis __asm__ __volatile__ ("str %0" : "=m" (taskreg) : /* no inputs */ );
1675b725ae77Skettenis
1676b725ae77Skettenis /* Task Register is a segment selector for the TSS of the current
1677b725ae77Skettenis task. Therefore, it can be used as an index into the GDT to get
1678b725ae77Skettenis at the segment descriptor for the TSS. To get the index, reset
1679b725ae77Skettenis the low 3 bits of the selector (which give the CPL). Add 2 to the
1680b725ae77Skettenis offset to point to the 3 low bytes of the base address. */
1681b725ae77Skettenis offset = gdtr.base + (taskreg & 0xfff8) + 2;
1682b725ae77Skettenis
1683b725ae77Skettenis
1684b725ae77Skettenis /* CWSDPMI's task base is always under the 1MB mark. */
1685b725ae77Skettenis if (offset > 0xfffff)
1686b725ae77Skettenis return 0;
1687b725ae77Skettenis
1688b725ae77Skettenis _farsetsel (_dos_ds);
1689b725ae77Skettenis taskbase = _farnspeekl (offset) & 0xffffffU;
1690b725ae77Skettenis taskbase += _farnspeekl (offset + 2) & 0xff000000U;
1691b725ae77Skettenis if (taskbase > 0xfffff)
1692b725ae77Skettenis return 0;
1693b725ae77Skettenis
1694b725ae77Skettenis /* CR3 (a.k.a. PDBR, the Page Directory Base Register) is stored at
1695b725ae77Skettenis offset 1Ch in the TSS. */
1696b725ae77Skettenis cr3 = _farnspeekl (taskbase + 0x1c) & ~0xfff;
1697b725ae77Skettenis if (cr3 > 0xfffff)
1698b725ae77Skettenis {
1699b725ae77Skettenis #if 0 /* not fullly supported yet */
1700b725ae77Skettenis /* The Page Directory is in UMBs. In that case, CWSDPMI puts
1701b725ae77Skettenis the first Page Table right below the Page Directory. Thus,
1702b725ae77Skettenis the first Page Table's entry for its own address and the Page
1703b725ae77Skettenis Directory entry for that Page Table will hold the same
1704b725ae77Skettenis physical address. The loop below searches the entire UMB
1705b725ae77Skettenis range of addresses for such an occurence. */
1706b725ae77Skettenis unsigned long addr, pte_idx;
1707b725ae77Skettenis
1708b725ae77Skettenis for (addr = 0xb0000, pte_idx = 0xb0;
1709b725ae77Skettenis pte_idx < 0xff;
1710b725ae77Skettenis addr += 0x1000, pte_idx++)
1711b725ae77Skettenis {
1712b725ae77Skettenis if (((_farnspeekl (addr + 4 * pte_idx) & 0xfffff027) ==
1713b725ae77Skettenis (_farnspeekl (addr + 0x1000) & 0xfffff027))
1714b725ae77Skettenis && ((_farnspeekl (addr + 4 * pte_idx + 4) & 0xfffff000) == cr3))
1715b725ae77Skettenis {
1716b725ae77Skettenis cr3 = addr + 0x1000;
1717b725ae77Skettenis break;
1718b725ae77Skettenis }
1719b725ae77Skettenis }
1720b725ae77Skettenis #endif
1721b725ae77Skettenis
1722b725ae77Skettenis if (cr3 > 0xfffff)
1723b725ae77Skettenis cr3 = 0;
1724b725ae77Skettenis }
1725b725ae77Skettenis
1726b725ae77Skettenis return cr3;
1727b725ae77Skettenis }
1728b725ae77Skettenis
1729b725ae77Skettenis /* Return the N'th Page Directory entry. */
1730b725ae77Skettenis static unsigned long
get_pde(int n)1731b725ae77Skettenis get_pde (int n)
1732b725ae77Skettenis {
1733b725ae77Skettenis unsigned long pde = 0;
1734b725ae77Skettenis
1735b725ae77Skettenis if (pdbr && n >= 0 && n < 1024)
1736b725ae77Skettenis {
1737b725ae77Skettenis pde = _farpeekl (_dos_ds, pdbr + 4*n);
1738b725ae77Skettenis }
1739b725ae77Skettenis return pde;
1740b725ae77Skettenis }
1741b725ae77Skettenis
1742b725ae77Skettenis /* Return the N'th entry of the Page Table whose Page Directory entry
1743b725ae77Skettenis is PDE. */
1744b725ae77Skettenis static unsigned long
get_pte(unsigned long pde,int n)1745b725ae77Skettenis get_pte (unsigned long pde, int n)
1746b725ae77Skettenis {
1747b725ae77Skettenis unsigned long pte = 0;
1748b725ae77Skettenis
1749b725ae77Skettenis /* pde & 0x80 tests the 4MB page bit. We don't support 4MB
1750b725ae77Skettenis page tables, for now. */
1751b725ae77Skettenis if ((pde & 1) && !(pde & 0x80) && n >= 0 && n < 1024)
1752b725ae77Skettenis {
1753b725ae77Skettenis pde &= ~0xfff; /* clear non-address bits */
1754b725ae77Skettenis pte = _farpeekl (_dos_ds, pde + 4*n);
1755b725ae77Skettenis }
1756b725ae77Skettenis return pte;
1757b725ae77Skettenis }
1758b725ae77Skettenis
1759b725ae77Skettenis /* Display a Page Directory or Page Table entry. IS_DIR, if non-zero,
1760b725ae77Skettenis says this is a Page Directory entry. If FORCE is non-zero, display
1761b725ae77Skettenis the entry even if its Present flag is off. OFF is the offset of the
1762b725ae77Skettenis address from the page's base address. */
1763b725ae77Skettenis static void
display_ptable_entry(unsigned long entry,int is_dir,int force,unsigned off)1764b725ae77Skettenis display_ptable_entry (unsigned long entry, int is_dir, int force, unsigned off)
1765b725ae77Skettenis {
1766b725ae77Skettenis if ((entry & 1) != 0)
1767b725ae77Skettenis {
1768b725ae77Skettenis printf_filtered ("Base=0x%05lx000", entry >> 12);
1769b725ae77Skettenis if ((entry & 0x100) && !is_dir)
1770b725ae77Skettenis puts_filtered (" Global");
1771b725ae77Skettenis if ((entry & 0x40) && !is_dir)
1772b725ae77Skettenis puts_filtered (" Dirty");
1773b725ae77Skettenis printf_filtered (" %sAcc.", (entry & 0x20) ? "" : "Not-");
1774b725ae77Skettenis printf_filtered (" %sCached", (entry & 0x10) ? "" : "Not-");
1775b725ae77Skettenis printf_filtered (" Write-%s", (entry & 8) ? "Thru" : "Back");
1776b725ae77Skettenis printf_filtered (" %s", (entry & 4) ? "Usr" : "Sup");
1777b725ae77Skettenis printf_filtered (" Read-%s", (entry & 2) ? "Write" : "Only");
1778b725ae77Skettenis if (off)
1779b725ae77Skettenis printf_filtered (" +0x%x", off);
1780b725ae77Skettenis puts_filtered ("\n");
1781b725ae77Skettenis }
1782b725ae77Skettenis else if (force)
1783b725ae77Skettenis printf_filtered ("Page%s not present or not supported; value=0x%lx.\n",
1784b725ae77Skettenis is_dir ? " Table" : "", entry >> 1);
1785b725ae77Skettenis }
1786b725ae77Skettenis
1787b725ae77Skettenis static void
go32_pde(char * arg,int from_tty)1788b725ae77Skettenis go32_pde (char *arg, int from_tty)
1789b725ae77Skettenis {
1790b725ae77Skettenis long pde_idx = -1, i;
1791b725ae77Skettenis
1792b725ae77Skettenis if (arg && *arg)
1793b725ae77Skettenis {
1794b725ae77Skettenis while (*arg && isspace(*arg))
1795b725ae77Skettenis arg++;
1796b725ae77Skettenis
1797b725ae77Skettenis if (*arg)
1798b725ae77Skettenis {
1799b725ae77Skettenis pde_idx = parse_and_eval_long (arg);
1800b725ae77Skettenis if (pde_idx < 0 || pde_idx >= 1024)
1801b725ae77Skettenis error ("Entry %ld is outside valid limits [0..1023].", pde_idx);
1802b725ae77Skettenis }
1803b725ae77Skettenis }
1804b725ae77Skettenis
1805b725ae77Skettenis pdbr = get_cr3 ();
1806b725ae77Skettenis if (!pdbr)
1807b725ae77Skettenis puts_filtered ("Access to Page Directories is not supported on this system.\n");
1808b725ae77Skettenis else if (pde_idx >= 0)
1809b725ae77Skettenis display_ptable_entry (get_pde (pde_idx), 1, 1, 0);
1810b725ae77Skettenis else
1811b725ae77Skettenis for (i = 0; i < 1024; i++)
1812b725ae77Skettenis display_ptable_entry (get_pde (i), 1, 0, 0);
1813b725ae77Skettenis }
1814b725ae77Skettenis
1815b725ae77Skettenis /* A helper function to display entries in a Page Table pointed to by
1816b725ae77Skettenis the N'th entry in the Page Directory. If FORCE is non-zero, say
1817b725ae77Skettenis something even if the Page Table is not accessible. */
1818b725ae77Skettenis static void
display_page_table(long n,int force)1819b725ae77Skettenis display_page_table (long n, int force)
1820b725ae77Skettenis {
1821b725ae77Skettenis unsigned long pde = get_pde (n);
1822b725ae77Skettenis
1823b725ae77Skettenis if ((pde & 1) != 0)
1824b725ae77Skettenis {
1825b725ae77Skettenis int i;
1826b725ae77Skettenis
1827b725ae77Skettenis printf_filtered ("Page Table pointed to by Page Directory entry 0x%lx:\n", n);
1828b725ae77Skettenis for (i = 0; i < 1024; i++)
1829b725ae77Skettenis display_ptable_entry (get_pte (pde, i), 0, 0, 0);
1830b725ae77Skettenis puts_filtered ("\n");
1831b725ae77Skettenis }
1832b725ae77Skettenis else if (force)
1833b725ae77Skettenis printf_filtered ("Page Table not present; value=0x%lx.\n", pde >> 1);
1834b725ae77Skettenis }
1835b725ae77Skettenis
1836b725ae77Skettenis static void
go32_pte(char * arg,int from_tty)1837b725ae77Skettenis go32_pte (char *arg, int from_tty)
1838b725ae77Skettenis {
1839b725ae77Skettenis long pde_idx = -1L, i;
1840b725ae77Skettenis
1841b725ae77Skettenis if (arg && *arg)
1842b725ae77Skettenis {
1843b725ae77Skettenis while (*arg && isspace(*arg))
1844b725ae77Skettenis arg++;
1845b725ae77Skettenis
1846b725ae77Skettenis if (*arg)
1847b725ae77Skettenis {
1848b725ae77Skettenis pde_idx = parse_and_eval_long (arg);
1849b725ae77Skettenis if (pde_idx < 0 || pde_idx >= 1024)
1850b725ae77Skettenis error ("Entry %ld is outside valid limits [0..1023].", pde_idx);
1851b725ae77Skettenis }
1852b725ae77Skettenis }
1853b725ae77Skettenis
1854b725ae77Skettenis pdbr = get_cr3 ();
1855b725ae77Skettenis if (!pdbr)
1856b725ae77Skettenis puts_filtered ("Access to Page Tables is not supported on this system.\n");
1857b725ae77Skettenis else if (pde_idx >= 0)
1858b725ae77Skettenis display_page_table (pde_idx, 1);
1859b725ae77Skettenis else
1860b725ae77Skettenis for (i = 0; i < 1024; i++)
1861b725ae77Skettenis display_page_table (i, 0);
1862b725ae77Skettenis }
1863b725ae77Skettenis
1864b725ae77Skettenis static void
go32_pte_for_address(char * arg,int from_tty)1865b725ae77Skettenis go32_pte_for_address (char *arg, int from_tty)
1866b725ae77Skettenis {
1867b725ae77Skettenis CORE_ADDR addr = 0, i;
1868b725ae77Skettenis
1869b725ae77Skettenis if (arg && *arg)
1870b725ae77Skettenis {
1871b725ae77Skettenis while (*arg && isspace(*arg))
1872b725ae77Skettenis arg++;
1873b725ae77Skettenis
1874b725ae77Skettenis if (*arg)
1875b725ae77Skettenis addr = parse_and_eval_address (arg);
1876b725ae77Skettenis }
1877b725ae77Skettenis if (!addr)
1878b725ae77Skettenis error_no_arg ("linear address");
1879b725ae77Skettenis
1880b725ae77Skettenis pdbr = get_cr3 ();
1881b725ae77Skettenis if (!pdbr)
1882b725ae77Skettenis puts_filtered ("Access to Page Tables is not supported on this system.\n");
1883b725ae77Skettenis else
1884b725ae77Skettenis {
1885b725ae77Skettenis int pde_idx = (addr >> 22) & 0x3ff;
1886b725ae77Skettenis int pte_idx = (addr >> 12) & 0x3ff;
1887b725ae77Skettenis unsigned offs = addr & 0xfff;
1888b725ae77Skettenis
1889b725ae77Skettenis printf_filtered ("Page Table entry for address 0x%llx:\n",
1890b725ae77Skettenis (unsigned long long)addr);
1891b725ae77Skettenis display_ptable_entry (get_pte (get_pde (pde_idx), pte_idx), 0, 1, offs);
1892b725ae77Skettenis }
1893b725ae77Skettenis }
1894b725ae77Skettenis
1895b725ae77Skettenis static struct cmd_list_element *info_dos_cmdlist = NULL;
1896b725ae77Skettenis
1897b725ae77Skettenis static void
go32_info_dos_command(char * args,int from_tty)1898b725ae77Skettenis go32_info_dos_command (char *args, int from_tty)
1899b725ae77Skettenis {
1900b725ae77Skettenis help_list (info_dos_cmdlist, "info dos ", class_info, gdb_stdout);
1901b725ae77Skettenis }
1902b725ae77Skettenis
1903b725ae77Skettenis void
_initialize_go32_nat(void)1904b725ae77Skettenis _initialize_go32_nat (void)
1905b725ae77Skettenis {
1906b725ae77Skettenis init_go32_ops ();
1907b725ae77Skettenis add_target (&go32_ops);
1908b725ae77Skettenis
1909b725ae77Skettenis add_prefix_cmd ("dos", class_info, go32_info_dos_command,
1910b725ae77Skettenis "Print information specific to DJGPP (aka MS-DOS) debugging.",
1911b725ae77Skettenis &info_dos_cmdlist, "info dos ", 0, &infolist);
1912b725ae77Skettenis
1913b725ae77Skettenis add_cmd ("sysinfo", class_info, go32_sysinfo,
1914b725ae77Skettenis "Display information about the target system, including CPU, OS, DPMI, etc.",
1915b725ae77Skettenis &info_dos_cmdlist);
1916b725ae77Skettenis add_cmd ("ldt", class_info, go32_sldt,
1917b725ae77Skettenis "Display entries in the LDT (Local Descriptor Table).\n"
1918b725ae77Skettenis "Entry number (an expression) as an argument means display only that entry.",
1919b725ae77Skettenis &info_dos_cmdlist);
1920b725ae77Skettenis add_cmd ("gdt", class_info, go32_sgdt,
1921b725ae77Skettenis "Display entries in the GDT (Global Descriptor Table).\n"
1922b725ae77Skettenis "Entry number (an expression) as an argument means display only that entry.",
1923b725ae77Skettenis &info_dos_cmdlist);
1924b725ae77Skettenis add_cmd ("idt", class_info, go32_sidt,
1925b725ae77Skettenis "Display entries in the IDT (Interrupt Descriptor Table).\n"
1926b725ae77Skettenis "Entry number (an expression) as an argument means display only that entry.",
1927b725ae77Skettenis &info_dos_cmdlist);
1928b725ae77Skettenis add_cmd ("pde", class_info, go32_pde,
1929b725ae77Skettenis "Display entries in the Page Directory.\n"
1930b725ae77Skettenis "Entry number (an expression) as an argument means display only that entry.",
1931b725ae77Skettenis &info_dos_cmdlist);
1932b725ae77Skettenis add_cmd ("pte", class_info, go32_pte,
1933b725ae77Skettenis "Display entries in Page Tables.\n"
1934b725ae77Skettenis "Entry number (an expression) as an argument means display only entries\n"
1935b725ae77Skettenis "from the Page Table pointed to by the specified Page Directory entry.",
1936b725ae77Skettenis &info_dos_cmdlist);
1937b725ae77Skettenis add_cmd ("address-pte", class_info, go32_pte_for_address,
1938b725ae77Skettenis "Display a Page Table entry for a linear address.\n"
1939b725ae77Skettenis "The address argument must be a linear address, after adding to\n"
1940b725ae77Skettenis "it the base address of the appropriate segment.\n"
1941b725ae77Skettenis "The base address of variables and functions in the debuggee's data\n"
1942b725ae77Skettenis "or code segment is stored in the variable __djgpp_base_address,\n"
1943b725ae77Skettenis "so use `__djgpp_base_address + (char *)&var' as the argument.\n"
1944b725ae77Skettenis "For other segments, look up their base address in the output of\n"
1945b725ae77Skettenis "the `info dos ldt' command.",
1946b725ae77Skettenis &info_dos_cmdlist);
1947b725ae77Skettenis }
1948b725ae77Skettenis
1949b725ae77Skettenis pid_t
tcgetpgrp(int fd)1950b725ae77Skettenis tcgetpgrp (int fd)
1951b725ae77Skettenis {
1952b725ae77Skettenis if (isatty (fd))
1953b725ae77Skettenis return SOME_PID;
1954b725ae77Skettenis errno = ENOTTY;
1955b725ae77Skettenis return -1;
1956b725ae77Skettenis }
1957b725ae77Skettenis
1958b725ae77Skettenis int
tcsetpgrp(int fd,pid_t pgid)1959b725ae77Skettenis tcsetpgrp (int fd, pid_t pgid)
1960b725ae77Skettenis {
1961b725ae77Skettenis if (isatty (fd) && pgid == SOME_PID)
1962b725ae77Skettenis return 0;
1963b725ae77Skettenis errno = pgid == SOME_PID ? ENOTTY : ENOSYS;
1964b725ae77Skettenis return -1;
1965b725ae77Skettenis }
1966