xref: /dflybsd-src/contrib/gdb-7/gdb/i386dfly-nat.c (revision ffd49a44576ac6919c30847a4587ded460b0c99d)
1 /* Native-dependent code for DragonFly/i386.
2 
3    Copyright (C) 2001-2013 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "defs.h"
21 #include "inferior.h"
22 #include "regcache.h"
23 #include "target.h"
24 #include "gregset.h"
25 
26 #include <sys/types.h>
27 #include <sys/procfs.h>
28 #include <sys/ptrace.h>
29 #include <sys/sysctl.h>
30 
31 #include "fbsd-nat.h"
32 #include "i386-tdep.h"
33 #include "i386-nat.h"
34 #include "i386bsd-nat.h"
35 
36 #ifdef DFLY_PCB_SUPPLY
37 /* Resume execution of the inferior process.  If STEP is nonzero,
38    single-step it.  If SIGNAL is nonzero, give it that signal.  */
39 
40 static void
41 i386dfly_resume(struct target_ops *ops,
42     ptid_t ptid, int step, enum gdb_signal signal)
43 {
44 	pid_t pid = ptid_get_pid(ptid);
45 	int request = PT_STEP;
46 
47 	if (pid == -1)
48 		/* Resume all threads.  This only gets used in the
49 		 * non-threaded case, where "resume all threads" and "resume
50 		 * inferior_ptid" are the same.  */
51 		pid = ptid_get_pid(inferior_ptid);
52 
53 	if (!step) {
54 		struct regcache *regcache = get_current_regcache();
55 		ULONGEST eflags;
56 
57 		/* Workaround for a bug in FreeBSD.  Make sure that the trace
58 		 * flag is off when doing a continue.  There is a code path
59 		 * through the kernel which leaves the flag set when it should
60 		 * have been cleared.  If a process has a signal pending (such
61 		 * as SIGALRM) and we do a PT_STEP, the process never really
62 		 * has a chance to run because the kernel needs to notify the
63 		 * debugger that a signal is being sent.  Therefore, the
64 		 * process never goes through the kernel's trap() function
65 		 * which would normally clear it.  */
66 
67 		regcache_cooked_read_unsigned(regcache, I386_EFLAGS_REGNUM,
68 		    &eflags);
69 		if (eflags & 0x0100)
70 			regcache_cooked_write_unsigned(regcache, I386_EFLAGS_REGNUM,
71 			    eflags & ~0x0100);
72 
73 		request = PT_CONTINUE;
74 	}
75 	/* An addres of (caddr_t) 1 tells ptrace to continue from where it
76 	 * was.  (If GDB wanted it to start some other way, we have already
77 	 * written a new PC value to the child.)  */
78 	if (ptrace(request, pid, (caddr_t) 1,
79 	    gdb_signal_to_host(signal)) == -1)
80 		perror_with_name(("ptrace"));
81 }
82 
83 
84 
85 /* Transfering the registers between GDB, inferiors and core files.  */
86 
87 /* Fill GDB's register array with the general-purpose register values
88    in *GREGSETP.  */
89 
90 void
91 supply_gregset(struct regcache *regcache, const gregset_t * gregsetp)
92 {
93 	i386bsd_supply_gregset(regcache, gregsetp);
94 }
95 
96 /* Fill register REGNUM (if it is a general-purpose register) in
97    *GREGSETPS with the value in GDB's register array.  If REGNUM is -1,
98    do this for all registers.  */
99 
100 void
101 fill_gregset(const struct regcache *regcache, gdb_gregset_t * gregsetp, int regnum)
102 {
103 	i386bsd_collect_gregset(regcache, gregsetp, regnum);
104 }
105 
106 #include "i387-tdep.h"
107 
108 /* Fill GDB's register array with the floating-point register values
109    in *FPREGSETP.  */
110 
111 void
112 supply_fpregset(struct regcache *regcache, const fpregset_t * fpregsetp)
113 {
114 	i387_supply_fsave(regcache, -1, fpregsetp);
115 }
116 
117 /* Fill register REGNUM (if it is a floating-point register) in
118    *FPREGSETP with the value in GDB's register array.  If REGNUM is -1,
119    do this for all registers.  */
120 
121 void
122 fill_fpregset(const struct regcache *regcache, gdb_fpregset_t * fpregsetp, int regnum)
123 {
124 	i387_collect_fsave(regcache, regnum, fpregsetp);
125 }
126 
127 
128 
129 /* Support for debugging kernel virtual memory images.  */
130 
131 #include <sys/types.h>
132 #include <machine/pcb.h>
133 
134 #include "bsd-kvm.h"
135 
136 static int
137 i386dfly_supply_pcb(struct regcache *regcache, struct pcb *pcb)
138 {
139 	/* The following is true for FreeBSD 4.7:
140 	 *
141 	 * The pcb contains %eip, %ebx, %esp, %ebp, %esi, %edi and %gs. This
142 	 * accounts for all callee-saved registers specified by the psABI and
143 	 * then some.  Here %esp contains the stack pointer at the point just
144 	 * after the call to cpu_switch().  From this information we
145 	 * reconstruct the register state as it would look when we just
146 	 * returned from cpu_switch().  */
147 
148 	/* The stack pointer shouldn't be zero.  */
149 	if (pcb->pcb_esp == 0)
150 		return 0;
151 
152 	pcb->pcb_esp += 4;
153 	regcache_raw_supply(regcache, I386_EDI_REGNUM, &pcb->pcb_edi);
154 	regcache_raw_supply(regcache, I386_ESI_REGNUM, &pcb->pcb_esi);
155 	regcache_raw_supply(regcache, I386_EBP_REGNUM, &pcb->pcb_ebp);
156 	regcache_raw_supply(regcache, I386_ESP_REGNUM, &pcb->pcb_esp);
157 	regcache_raw_supply(regcache, I386_EBX_REGNUM, &pcb->pcb_ebx);
158 	regcache_raw_supply(regcache, I386_EIP_REGNUM, &pcb->pcb_eip);
159 	regcache_raw_supply(regcache, I386_GS_REGNUM, &pcb->pcb_gs);
160 
161 	return 1;
162 }
163 #endif				/* DFLY_PCB_SUPPLY */
164 
165 
166 
167 /* Prevent warning from -Wmissing-prototypes.  */
168 void _initialize_i386dfly_nat(void);
169 
170 void
171 _initialize_i386dfly_nat(void)
172 {
173 	struct target_ops *t;
174 
175 	/* Add some extra features to the common *BSD/i386 target.  */
176 	t = i386bsd_target();
177 
178 #ifdef HAVE_PT_GETDBREGS
179 
180 	i386_use_watchpoints(t);
181 
182 	i386_dr_low.set_control = i386bsd_dr_set_control;
183 	i386_dr_low.set_addr = i386bsd_dr_set_addr;
184 	i386_dr_low.get_addr = i386bsd_dr_get_addr;
185 	i386_dr_low.get_status = i386bsd_dr_get_status;
186 	i386_dr_low.get_control = i386bsd_dr_get_control;
187 	i386_set_debug_register_length(4);
188 
189 #endif				/* HAVE_PT_GETDBREGS */
190 
191 
192 	t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
193 	t->to_find_memory_regions = fbsd_find_memory_regions;
194 	t->to_make_corefile_notes = fbsd_make_corefile_notes;
195 	add_target(t);
196 
197 #ifdef DFLY_PCB_SUPPLY
198 	/* Support debugging kernel virtual memory images.  */
199 	bsd_kvm_add_target(i386dfly_supply_pcb);
200 #endif
201 
202 	/* DragonFly provides a kern.ps_strings sysctl that we can use to
203 	 * locate the sigtramp.  That way we can still recognize a sigtramp if
204 	 * its location is changed in a new kernel.  Of course this is still
205 	 * based on the assumption that the sigtramp is placed directly under
206 	 * the location where the program arguments and environment can be
207 	 * found.  */
208 #ifdef KERN_PS_STRINGS
209 	{
210 		int mib[2];
211 		u_long ps_strings;
212 		size_t len;
213 
214 		mib[0] = CTL_KERN;
215 		mib[1] = KERN_PS_STRINGS;
216 		len = sizeof(ps_strings);
217 		if (sysctl(mib, 2, &ps_strings, &len, NULL, 0) == 0) {
218 			i386dfly_sigtramp_start_addr = ps_strings - 128;
219 			i386dfly_sigtramp_end_addr = ps_strings;
220 		}
221 	}
222 #endif
223 }
224