trgt.c revision 175645
1/*
2 * Copyright (c) 2004 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/trgt.c 175645 2008-01-24 19:11:13Z jhb $");
29
30#include <sys/param.h>
31#include <sys/proc.h>
32#include <sys/sysctl.h>
33#include <sys/user.h>
34#include <kvm.h>
35
36#include <defs.h>
37#include <command.h>
38#include <frame-unwind.h>
39#include <gdbthread.h>
40#include <inferior.h>
41#include <regcache.h>
42#include <target.h>
43
44#include "kgdb.h"
45
46static struct target_ops kgdb_trgt_ops;
47
48#define	KERNOFF		(kgdb_kernbase ())
49#define	INKERNEL(x)	((x) >= KERNOFF)
50
51static CORE_ADDR
52kgdb_kernbase (void)
53{
54	static CORE_ADDR kernbase;
55	struct minimal_symbol *sym;
56
57	if (kernbase == 0) {
58		sym = lookup_minimal_symbol ("kernbase", NULL, NULL);
59		if (sym == NULL) {
60			kernbase = KERNBASE;
61		} else {
62			kernbase = SYMBOL_VALUE_ADDRESS (sym);
63		}
64	}
65	return kernbase;
66}
67
68static char *
69kgdb_trgt_extra_thread_info(struct thread_info *ti)
70{
71	static char buf[64];
72	char *p, *s;
73
74	p = buf + snprintf(buf, sizeof(buf), "PID=%d", ptid_get_pid(ti->ptid));
75	s = kgdb_thr_extra_thread_info(ptid_get_tid(ti->ptid));
76	if (s != NULL)
77		snprintf(p, sizeof(buf) - (p - buf), ": %s", s);
78	return (buf);
79}
80
81static void
82kgdb_trgt_files_info(struct target_ops *target)
83{
84	struct target_ops *tb;
85
86	tb = find_target_beneath(target);
87	if (tb->to_files_info != NULL)
88		tb->to_files_info(tb);
89}
90
91static void
92kgdb_trgt_find_new_threads(void)
93{
94	struct target_ops *tb;
95
96	if (kvm != NULL)
97		return;
98
99	tb = find_target_beneath(&kgdb_trgt_ops);
100	if (tb->to_find_new_threads != NULL)
101		tb->to_find_new_threads();
102}
103
104static char *
105kgdb_trgt_pid_to_str(ptid_t ptid)
106{
107	static char buf[33];
108
109	snprintf(buf, sizeof(buf), "Thread %ld", ptid_get_tid(ptid));
110	return (buf);
111}
112
113static int
114kgdb_trgt_thread_alive(ptid_t ptid)
115{
116	return (kgdb_thr_lookup_tid(ptid_get_tid(ptid)) != NULL);
117}
118
119static int
120kgdb_trgt_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len, int write,
121    struct mem_attrib *attrib, struct target_ops *target)
122{
123	struct target_ops *tb;
124
125	if (kvm != NULL) {
126		if (len == 0)
127			return (0);
128		if (!write)
129			return (kvm_read(kvm, memaddr, myaddr, len));
130		else
131			return (kvm_write(kvm, memaddr, myaddr, len));
132	}
133	tb = find_target_beneath(target);
134	return (tb->to_xfer_memory(memaddr, myaddr, len, write, attrib, tb));
135}
136
137static void
138kgdb_switch_to_thread(struct kthr *thr)
139{
140	if (thr->tid == ptid_get_tid(inferior_ptid))
141		return;
142
143	inferior_ptid = ptid_build(thr->pid, 0, thr->tid);
144	flush_cached_frames ();
145	registers_changed ();
146	stop_pc = read_pc ();
147	select_frame (get_current_frame ());
148}
149
150static void
151kgdb_set_proc_cmd (char *arg, int from_tty)
152{
153	CORE_ADDR addr;
154	struct kthr *thr;
155
156	if (!arg)
157		error_no_arg ("proc address for the new context");
158
159	if (kvm == NULL)
160		error ("no kernel core file");
161
162	addr = (CORE_ADDR) parse_and_eval_address (arg);
163
164	if (!INKERNEL (addr)) {
165		thr = kgdb_thr_lookup_pid((int)addr);
166		if (thr == NULL)
167			error ("invalid pid");
168	} else {
169		thr = kgdb_thr_lookup_paddr(addr);
170		if (thr == NULL)
171			error("invalid proc address");
172	}
173	kgdb_switch_to_thread(thr);
174}
175
176static void
177kgdb_set_tid_cmd (char *arg, int from_tty)
178{
179	CORE_ADDR addr;
180	struct kthr *thr;
181
182	if (!arg)
183		error_no_arg ("TID or thread address for the new context");
184
185	if (kvm == NULL)
186		error ("no kernel core file");
187
188	addr = (CORE_ADDR) parse_and_eval_address (arg);
189
190	if (!INKERNEL (addr)) {
191		thr = kgdb_thr_lookup_tid((int)addr);
192		if (thr == NULL)
193			error ("invalid TID");
194	} else {
195		thr = kgdb_thr_lookup_taddr(addr);
196		if (thr == NULL)
197			error("invalid thread address");
198	}
199	kgdb_switch_to_thread(thr);
200}
201
202void
203kgdb_target(void)
204{
205	struct kthr *kt;
206	struct thread_info *ti;
207
208	kgdb_trgt_ops.to_magic = OPS_MAGIC;
209	kgdb_trgt_ops.to_shortname = "kernel";
210	kgdb_trgt_ops.to_longname = "kernel core files.";
211	kgdb_trgt_ops.to_doc = "Kernel core files.";
212	kgdb_trgt_ops.to_stratum = thread_stratum;
213	kgdb_trgt_ops.to_has_memory = 1;
214	kgdb_trgt_ops.to_has_registers = 1;
215	kgdb_trgt_ops.to_has_stack = 1;
216
217	kgdb_trgt_ops.to_extra_thread_info = kgdb_trgt_extra_thread_info;
218	kgdb_trgt_ops.to_fetch_registers = kgdb_trgt_fetch_registers;
219	kgdb_trgt_ops.to_files_info = kgdb_trgt_files_info;
220	kgdb_trgt_ops.to_find_new_threads = kgdb_trgt_find_new_threads;
221	kgdb_trgt_ops.to_pid_to_str = kgdb_trgt_pid_to_str;
222	kgdb_trgt_ops.to_store_registers = kgdb_trgt_store_registers;
223	kgdb_trgt_ops.to_thread_alive = kgdb_trgt_thread_alive;
224	kgdb_trgt_ops.to_xfer_memory = kgdb_trgt_xfer_memory;
225	add_target(&kgdb_trgt_ops);
226	push_target(&kgdb_trgt_ops);
227
228	kt = kgdb_thr_first();
229	while (kt != NULL) {
230		ti = add_thread(ptid_build(kt->pid, 0, kt->tid));
231		kt = kgdb_thr_next(kt);
232	}
233	if (curkthr != 0)
234		inferior_ptid = ptid_build(curkthr->pid, 0, curkthr->tid);
235	add_com ("proc", class_obscure, kgdb_set_proc_cmd,
236	   "Set current process context");
237	add_com ("tid", class_obscure, kgdb_set_tid_cmd,
238	   "Set current thread context");
239	add_com ("add-kld", class_files, kgdb_add_kld_cmd,
240	   "Usage: add-kld FILE\n\
241Load the symbols from the kernel loadable module FILE.");
242}
243