1 |
douglas |
2 |
/* Kernel core dump functions below target vector, for GDB. |
2 |
|
|
Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995 |
3 |
|
|
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 2 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, write to the Free Software |
19 |
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
20 |
|
|
*/ |
21 |
|
|
|
22 |
|
|
#include <sys/cdefs.h> |
23 |
|
|
__FBSDID("$FreeBSD: ports/devel/gdb6/files/kvm-fbsd.c,v 1.2 2004/06/20 22:22:02 obrien Exp $"); |
24 |
|
|
|
25 |
|
|
/* |
26 |
|
|
* This works like "remote" but, you use it like this: |
27 |
|
|
* target kcore /dev/mem |
28 |
|
|
* or |
29 |
|
|
* target kcore /var/crash/host/core.0 |
30 |
|
|
* |
31 |
|
|
* This way makes it easy to short-circut the whole bfd monster, |
32 |
|
|
* and direct the inferior stuff to our libkvm implementation. |
33 |
|
|
* |
34 |
|
|
*/ |
35 |
|
|
|
36 |
|
|
#include <sys/param.h> |
37 |
|
|
#include <sys/user.h> |
38 |
|
|
#include <machine/frame.h> |
39 |
|
|
//#include <sys/proc.h> |
40 |
|
|
//#include <sys/sysctl.h> |
41 |
|
|
//#include <sys/time.h> |
42 |
|
|
//#include <sys/user.h> |
43 |
|
|
|
44 |
|
|
#include <ctype.h> |
45 |
|
|
//#include <errno.h> |
46 |
|
|
//#include <signal.h> |
47 |
|
|
#include <fcntl.h> |
48 |
|
|
#include <kvm.h> |
49 |
|
|
#include <sys/sysctl.h> |
50 |
|
|
#include <paths.h> |
51 |
|
|
|
52 |
|
|
#include "defs.h" |
53 |
|
|
#include "gdb_string.h" |
54 |
|
|
#include "frame.h" /* required by inferior.h */ |
55 |
|
|
#include "inferior.h" |
56 |
|
|
//#include "symtab.h" |
57 |
|
|
#include "symfile.h" |
58 |
|
|
#include "objfiles.h" |
59 |
|
|
#include "command.h" |
60 |
|
|
#include "bfd.h" |
61 |
|
|
//#include "target.h" |
62 |
|
|
#include "gdbcore.h" |
63 |
|
|
#include "solist.h" |
64 |
|
|
#include "regcache.h" |
65 |
|
|
#include <readline/tilde.h> |
66 |
|
|
|
67 |
|
|
#include "kvm-fbsd.h" |
68 |
|
|
|
69 |
|
|
#if __FreeBSD_version >= 500032 |
70 |
|
|
static void |
71 |
|
|
kcore_files_info (struct target_ops *); |
72 |
|
|
|
73 |
|
|
static void |
74 |
|
|
kcore_close (int); |
75 |
|
|
|
76 |
|
|
static void |
77 |
|
|
get_kcore_registers (int); |
78 |
|
|
|
79 |
|
|
|
80 |
|
|
/* |
81 |
|
|
static int |
82 |
|
|
xfer_mem (CORE_ADDR, char *, int, int, struct mem_attrib *, |
83 |
|
|
struct target_ops *); |
84 |
|
|
*/ |
85 |
|
|
|
86 |
|
|
static int |
87 |
|
|
xfer_umem (CORE_ADDR, char *, int, int); |
88 |
|
|
|
89 |
|
|
static char *core_file; |
90 |
|
|
static kvm_t *core_kd; |
91 |
|
|
static struct pcb cur_pcb; |
92 |
|
|
static struct kinfo_proc *cur_proc; |
93 |
|
|
|
94 |
|
|
static struct target_ops kcore_ops; |
95 |
|
|
|
96 |
|
|
int kernel_debugging; |
97 |
|
|
int kernel_writablecore; |
98 |
|
|
|
99 |
|
|
/* Read the "thing" at kernel address 'addr' into the space pointed to |
100 |
|
|
by point. The length of the "thing" is determined by the type of p. |
101 |
|
|
Result is non-zero if transfer fails. */ |
102 |
|
|
|
103 |
|
|
#define kvread(addr, p) \ |
104 |
|
|
(target_read_memory ((CORE_ADDR) (addr), (char *) (p), sizeof (*(p)))) |
105 |
|
|
|
106 |
|
|
static CORE_ADDR |
107 |
|
|
ksym_kernbase (void) |
108 |
|
|
{ |
109 |
|
|
static CORE_ADDR kernbase; |
110 |
|
|
struct minimal_symbol *sym; |
111 |
|
|
|
112 |
|
|
if (kernbase == 0) |
113 |
|
|
{ |
114 |
|
|
sym = lookup_minimal_symbol ("kernbase", NULL, NULL); |
115 |
|
|
if (sym == NULL) { |
116 |
|
|
kernbase = KERNBASE; |
117 |
|
|
} else { |
118 |
|
|
kernbase = SYMBOL_VALUE_ADDRESS (sym); |
119 |
|
|
} |
120 |
|
|
} |
121 |
|
|
return kernbase; |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
#define KERNOFF (ksym_kernbase ()) |
125 |
|
|
#define INKERNEL(x) ((x) >= KERNOFF) |
126 |
|
|
|
127 |
|
|
CORE_ADDR |
128 |
|
|
ksym_lookup(const char *name) |
129 |
|
|
{ |
130 |
|
|
struct minimal_symbol *sym; |
131 |
|
|
|
132 |
|
|
sym = lookup_minimal_symbol (name, NULL, NULL); |
133 |
|
|
if (sym == NULL) |
134 |
|
|
error ("kernel symbol `%s' not found.", name); |
135 |
|
|
|
136 |
|
|
return SYMBOL_VALUE_ADDRESS (sym); |
137 |
|
|
} |
138 |
|
|
|
139 |
|
|
/* Provide the address of an initial PCB to use. |
140 |
|
|
If this is a crash dump, try for "dumppcb". |
141 |
|
|
If no "dumppcb" or it's /dev/mem, use proc0. |
142 |
|
|
Return the core address of the PCB we found. */ |
143 |
|
|
|
144 |
|
|
static CORE_ADDR |
145 |
|
|
initial_pcb (void) |
146 |
|
|
{ |
147 |
|
|
struct minimal_symbol *sym; |
148 |
|
|
CORE_ADDR addr; |
149 |
|
|
void *val; |
150 |
|
|
|
151 |
|
|
/* Make sure things are open... */ |
152 |
|
|
if (!core_kd || !core_file) |
153 |
|
|
return (0); |
154 |
|
|
|
155 |
|
|
/* If this is NOT /dev/mem try for dumppcb. */ |
156 |
|
|
if (strncmp (core_file, _PATH_DEV, sizeof _PATH_DEV - 1)) |
157 |
|
|
{ |
158 |
|
|
sym = lookup_minimal_symbol ("dumppcb", NULL, NULL); |
159 |
|
|
if (sym != NULL) |
160 |
|
|
{ |
161 |
|
|
addr = SYMBOL_VALUE_ADDRESS (sym); |
162 |
|
|
return (addr); |
163 |
|
|
} |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
/* OK, just use thread0's pcb. Note that curproc might |
167 |
|
|
not exist, and if it does, it will point to gdb. |
168 |
|
|
Therefore, just use proc0 and let the user set |
169 |
|
|
some other context if they care about it. */ |
170 |
|
|
|
171 |
|
|
addr = ksym_lookup ("thread0"); |
172 |
|
|
if (kvread (addr, &val)) |
173 |
|
|
{ |
174 |
|
|
error ("cannot read thread0 pointer at %lx\n", addr); |
175 |
|
|
val = 0; |
176 |
|
|
} |
177 |
|
|
else |
178 |
|
|
{ |
179 |
|
|
/* Read the PCB address in thread structure. */ |
180 |
|
|
addr += offsetof (struct thread, td_pcb); |
181 |
|
|
if (kvread (addr, &val)) |
182 |
|
|
{ |
183 |
|
|
error ("cannot read thread0->td_pcb pointer at %lx\n", addr); |
184 |
|
|
val = 0; |
185 |
|
|
} |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
/* thread0 is wholly in the kernel and cur_proc is only used for |
189 |
|
|
reading user mem, so no point in setting this up. */ |
190 |
|
|
cur_proc = 0; |
191 |
|
|
|
192 |
|
|
return ((CORE_ADDR)val); |
193 |
|
|
} |
194 |
|
|
|
195 |
|
|
/* Set the current context to that of the PCB struct at the system address |
196 |
|
|
passed. */ |
197 |
|
|
|
198 |
|
|
static int |
199 |
|
|
set_context (CORE_ADDR addr) |
200 |
|
|
{ |
201 |
|
|
CORE_ADDR procaddr = 0; |
202 |
|
|
|
203 |
|
|
if (kvread (addr, &cur_pcb)) |
204 |
|
|
error ("cannot read pcb at %#lx", addr); |
205 |
|
|
|
206 |
|
|
/* Fetch all registers from core file. */ |
207 |
|
|
target_fetch_registers (-1); |
208 |
|
|
|
209 |
|
|
/* Now, set up the frame cache, and print the top of stack. */ |
210 |
|
|
flush_cached_frames (); |
211 |
|
|
/*DEO XXX |
212 |
|
|
set_current_frame (create_new_frame (read_fp (), read_pc ())); |
213 |
|
|
set_current_frame (create_new_frame (deprecated_read_fp (), read_pc ())); |
214 |
|
|
select_frame (get_current_frame ()); |
215 |
|
|
*/ |
216 |
|
|
print_stack_frame (get_selected_frame (), -1, 1); |
217 |
|
|
return (0); |
218 |
|
|
} |
219 |
|
|
|
220 |
|
|
/* Discard all vestiges of any previous core file and mark data and stack |
221 |
|
|
spaces as empty. */ |
222 |
|
|
|
223 |
|
|
/* ARGSUSED */ |
224 |
|
|
static void |
225 |
|
|
kcore_close (int quitting) |
226 |
|
|
{ |
227 |
|
|
|
228 |
|
|
inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */ |
229 |
|
|
|
230 |
|
|
if (core_kd) |
231 |
|
|
{ |
232 |
|
|
kvm_close (core_kd); |
233 |
|
|
free (core_file); |
234 |
|
|
core_file = NULL; |
235 |
|
|
core_kd = NULL; |
236 |
|
|
} |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
/* This routine opens and sets up the core file bfd. */ |
240 |
|
|
|
241 |
|
|
static void |
242 |
|
|
kcore_open (char *filename /* the core file */, int from_tty) |
243 |
|
|
{ |
244 |
|
|
kvm_t *kd; |
245 |
|
|
const char *p; |
246 |
|
|
struct cleanup *old_chain; |
247 |
|
|
char buf[256], *cp; |
248 |
|
|
int ontop; |
249 |
|
|
CORE_ADDR addr; |
250 |
|
|
|
251 |
|
|
target_preopen (from_tty); |
252 |
|
|
|
253 |
|
|
/* The exec file is required for symbols. */ |
254 |
|
|
if (exec_bfd == NULL) |
255 |
|
|
error ("No kernel exec file specified"); |
256 |
|
|
|
257 |
|
|
if (core_kd) |
258 |
|
|
{ |
259 |
|
|
error ("No core file specified." |
260 |
|
|
" (Use `detach' to stop debugging a core file.)"); |
261 |
|
|
return; |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
if (!filename) |
265 |
|
|
{ |
266 |
|
|
error ("No core file specified."); |
267 |
|
|
return; |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
filename = tilde_expand (filename); |
271 |
|
|
if (filename[0] != '/') |
272 |
|
|
{ |
273 |
|
|
cp = concat (current_directory, "/", filename, NULL); |
274 |
|
|
free (filename); |
275 |
|
|
filename = cp; |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
old_chain = make_cleanup (free, filename); |
279 |
|
|
|
280 |
|
|
kd = kvm_open (bfd_get_filename(exec_bfd), filename, NULL, |
281 |
|
|
kernel_writablecore ? O_RDWR: O_RDONLY, 0); |
282 |
|
|
if (kd == NULL) |
283 |
|
|
{ |
284 |
|
|
perror_with_name (filename); |
285 |
|
|
return; |
286 |
|
|
} |
287 |
|
|
|
288 |
|
|
/* Looks semi-reasonable. Toss the old core file and work on the new. */ |
289 |
|
|
|
290 |
|
|
discard_cleanups (old_chain); /* Don't free filename any more. */ |
291 |
|
|
core_file = filename; |
292 |
|
|
unpush_target (&kcore_ops); |
293 |
|
|
ontop = !push_target (&kcore_ops); |
294 |
|
|
|
295 |
|
|
/* Note unpush_target (above) calls kcore_close. */ |
296 |
|
|
core_kd = kd; |
297 |
|
|
|
298 |
|
|
/* Print out the panic string if there is one. */ |
299 |
|
|
if (kvread (ksym_lookup ("panicstr"), &addr) == 0 && |
300 |
|
|
addr != 0 && |
301 |
|
|
target_read_memory (addr, buf, sizeof(buf)) == 0) |
302 |
|
|
{ |
303 |
|
|
|
304 |
|
|
for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++) |
305 |
|
|
if (!isascii (*cp) || (!isprint (*cp) && !isspace (*cp))) |
306 |
|
|
*cp = '?'; |
307 |
|
|
*cp = '\0'; |
308 |
|
|
if (buf[0] != '\0') |
309 |
|
|
printf_filtered ("panic: %s\n", buf); |
310 |
|
|
} |
311 |
|
|
|
312 |
|
|
/* Print all the panic messages if possible. */ |
313 |
|
|
if (symfile_objfile != NULL) |
314 |
|
|
{ |
315 |
|
|
printf ("panic messages:\n---\n"); |
316 |
|
|
snprintf (buf, sizeof buf, |
317 |
|
|
"/sbin/dmesg -N %s -M %s | \ |
318 |
|
|
/usr/bin/awk '/^(panic:|Fatal trap) / { printing = 1 } \ |
319 |
|
|
{ if (printing) print $0 }'", |
320 |
|
|
symfile_objfile->name, filename); |
321 |
|
|
fflush (stdout); |
322 |
|
|
system (buf); |
323 |
|
|
printf ("---\n"); |
324 |
|
|
} |
325 |
|
|
|
326 |
|
|
if (!ontop) |
327 |
|
|
{ |
328 |
|
|
warning ("you won't be able to access this core file until you terminate\n" |
329 |
|
|
"your %s; do ``info files''", target_longname); |
330 |
|
|
return; |
331 |
|
|
} |
332 |
|
|
|
333 |
|
|
/* Now, set up process context, and print the top of stack. */ |
334 |
|
|
(void)set_context (initial_pcb()); |
335 |
|
|
print_stack_frame (get_selected_frame (), |
336 |
|
|
frame_relative_level (get_selected_frame ()), 1); |
337 |
|
|
} |
338 |
|
|
|
339 |
|
|
static void |
340 |
|
|
kcore_detach (char *args, int from_tty) |
341 |
|
|
{ |
342 |
|
|
if (args) |
343 |
|
|
error ("Too many arguments"); |
344 |
|
|
unpush_target (&kcore_ops); |
345 |
|
|
reinit_frame_cache (); |
346 |
|
|
if (from_tty) |
347 |
|
|
printf_filtered ("No kernel core file now.\n"); |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
/* Get the registers out of a core file. This is the machine- |
351 |
|
|
independent part. Fetch_core_registers is the machine-dependent |
352 |
|
|
part, typically implemented in the xm-file for each architecture. */ |
353 |
|
|
|
354 |
|
|
/* We just get all the registers, so we don't use regno. */ |
355 |
|
|
|
356 |
|
|
/* ARGSUSED */ |
357 |
|
|
static void |
358 |
|
|
get_kcore_registers (int regno) |
359 |
|
|
{ |
360 |
|
|
|
361 |
|
|
/* XXX - Only read the pcb when set_context() is called. |
362 |
|
|
When looking at a live kernel this may be a problem, |
363 |
|
|
but the user can do another "proc" or "pcb" command to |
364 |
|
|
grab a new copy of the pcb... */ |
365 |
|
|
|
366 |
|
|
/* Zero out register set then fill in the ones we know about. */ |
367 |
|
|
fetch_kcore_registers (&cur_pcb); |
368 |
|
|
} |
369 |
|
|
|
370 |
|
|
static void |
371 |
|
|
kcore_files_info (t) |
372 |
|
|
struct target_ops *t; |
373 |
|
|
{ |
374 |
|
|
printf_filtered ("\t`%s'\n", core_file); |
375 |
|
|
} |
376 |
|
|
|
377 |
|
|
/* If mourn is being called in all the right places, this could be say |
378 |
|
|
`gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */ |
379 |
|
|
|
380 |
|
|
/* |
381 |
|
|
static int |
382 |
|
|
ignore (CORE_ADDR addr, char *contents) |
383 |
|
|
{ |
384 |
|
|
return 0; |
385 |
|
|
} |
386 |
|
|
*/ |
387 |
|
|
|
388 |
|
|
static int |
389 |
|
|
xfer_kmem (CORE_ADDR memaddr, char *myaddr, int len, int write, |
390 |
|
|
struct mem_attrib *attrib, struct target_ops *target) |
391 |
|
|
{ |
392 |
|
|
int n; |
393 |
|
|
|
394 |
|
|
|
395 |
|
|
if (!INKERNEL (memaddr)) |
396 |
|
|
return xfer_umem (memaddr, myaddr, len, write); |
397 |
|
|
|
398 |
|
|
if (core_kd == NULL) |
399 |
|
|
return 0; |
400 |
|
|
|
401 |
|
|
if (write) |
402 |
|
|
n = kvm_write (core_kd, memaddr, myaddr, len); |
403 |
|
|
else |
404 |
|
|
n = kvm_read (core_kd, memaddr, myaddr, len) ; |
405 |
|
|
if (n < 0) { |
406 |
|
|
fprintf_unfiltered (gdb_stderr, "can not access 0x%lx, %s\n", |
407 |
|
|
memaddr, kvm_geterr (core_kd)); |
408 |
|
|
n = 0; |
409 |
|
|
} |
410 |
|
|
|
411 |
|
|
return n; |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
|
415 |
|
|
static int |
416 |
|
|
xfer_umem (CORE_ADDR memaddr, char *myaddr, int len, int write /* ignored */) |
417 |
|
|
{ |
418 |
|
|
int n = 0; |
419 |
|
|
|
420 |
|
|
if (cur_proc == 0) |
421 |
|
|
{ |
422 |
|
|
error ("---Can't read userspace from dump, or kernel process---\n"); |
423 |
|
|
return 0; |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
if (write) |
427 |
|
|
error ("kvm_uwrite unimplemented\n"); |
428 |
|
|
else |
429 |
|
|
n = kvm_uread (core_kd, cur_proc, memaddr, myaddr, len) ; |
430 |
|
|
|
431 |
|
|
if (n < 0) |
432 |
|
|
return 0; |
433 |
|
|
|
434 |
|
|
return n; |
435 |
|
|
} |
436 |
|
|
|
437 |
|
|
static void |
438 |
|
|
set_proc_cmd (char *arg, int from_tty) |
439 |
|
|
{ |
440 |
|
|
CORE_ADDR addr, pid_addr, first_td; |
441 |
|
|
void *val; |
442 |
|
|
struct kinfo_proc *kp; |
443 |
|
|
int cnt; |
444 |
|
|
pid_t pid; |
445 |
|
|
|
446 |
|
|
if (!arg) |
447 |
|
|
error_no_arg ("proc address for the new context"); |
448 |
|
|
|
449 |
|
|
if (core_kd == NULL) |
450 |
|
|
error ("no kernel core file"); |
451 |
|
|
|
452 |
|
|
addr = (CORE_ADDR) parse_and_eval_address (arg); |
453 |
|
|
|
454 |
|
|
if (!INKERNEL (addr)) |
455 |
|
|
{ |
456 |
|
|
kp = kvm_getprocs (core_kd, KERN_PROC_PID, addr, &cnt); |
457 |
|
|
if (!cnt) |
458 |
|
|
error ("invalid pid"); |
459 |
|
|
addr = (CORE_ADDR)kp->ki_paddr; |
460 |
|
|
cur_proc = kp; |
461 |
|
|
} |
462 |
|
|
else |
463 |
|
|
{ |
464 |
|
|
/* Update cur_proc. */ |
465 |
|
|
pid_addr = addr + offsetof (struct proc, p_pid); |
466 |
|
|
if (kvread (pid_addr, &pid)) |
467 |
|
|
error ("cannot read pid ptr"); |
468 |
|
|
cur_proc = kvm_getprocs (core_kd, KERN_PROC_PID, pid, &cnt); |
469 |
|
|
if (!cnt) |
470 |
|
|
error("invalid pid"); |
471 |
|
|
} |
472 |
|
|
|
473 |
|
|
/* Find the first thread in the process. XXXKSE */ |
474 |
|
|
addr += offsetof (struct proc, p_threads.tqh_first); |
475 |
|
|
if (kvread (addr, &first_td)) |
476 |
|
|
error ("cannot read thread ptr"); |
477 |
|
|
|
478 |
|
|
/* Read the PCB address in thread structure. */ |
479 |
|
|
addr = first_td + offsetof (struct thread, td_pcb); |
480 |
|
|
if (kvread (addr, &val)) |
481 |
|
|
error("cannot read pcb ptr"); |
482 |
|
|
|
483 |
|
|
/* Read the PCB address in proc structure. */ |
484 |
|
|
if (set_context ((CORE_ADDR) val)) |
485 |
|
|
error ("invalid proc address"); |
486 |
|
|
} |
487 |
|
|
#else |
488 |
|
|
int kernel_debugging = 0; |
489 |
|
|
int kernel_writablecore = 0; |
490 |
|
|
|
491 |
|
|
CORE_ADDR |
492 |
|
|
fbsd_kern_frame_saved_pc (struct frame_info *fi) |
493 |
|
|
{ |
494 |
|
|
return 0; |
495 |
|
|
} |
496 |
|
|
#endif |
497 |
|
|
|
498 |
|
|
void |
499 |
|
|
_initialize_kcorelow (void) |
500 |
|
|
{ |
501 |
|
|
#if __FreeBSD_version >= 500032 |
502 |
|
|
kcore_ops.to_shortname = "kcore"; |
503 |
|
|
kcore_ops.to_longname = "Kernel core dump file"; |
504 |
|
|
kcore_ops.to_doc = |
505 |
|
|
"Use a core file as a target. Specify the filename of the core file."; |
506 |
|
|
kcore_ops.to_open = kcore_open; |
507 |
|
|
kcore_ops.to_close = kcore_close; |
508 |
|
|
kcore_ops.to_attach = find_default_attach; |
509 |
|
|
kcore_ops.to_detach = kcore_detach; |
510 |
|
|
kcore_ops.to_fetch_registers = get_kcore_registers; |
511 |
|
|
kcore_ops.to_xfer_memory = xfer_kmem; |
512 |
|
|
kcore_ops.to_files_info = kcore_files_info; |
513 |
|
|
kcore_ops.to_create_inferior = find_default_create_inferior; |
514 |
|
|
kcore_ops.to_stratum = kcore_stratum; |
515 |
|
|
kcore_ops.to_has_memory = 1; |
516 |
|
|
kcore_ops.to_has_stack = 1; |
517 |
|
|
kcore_ops.to_has_registers = 1; |
518 |
|
|
kcore_ops.to_magic = OPS_MAGIC; |
519 |
|
|
|
520 |
|
|
add_target (&kcore_ops); |
521 |
|
|
add_com ("proc", class_obscure, set_proc_cmd, "Set current process context"); |
522 |
|
|
#endif |
523 |
|
|
} |