trgt.c revision 175416
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 175416 2008-01-17 21:43:12Z jhb $");
29
30#include <sys/param.h>
31#include <sys/proc.h>
32#include <sys/stat.h>
33#include <sys/sysctl.h>
34#include <sys/user.h>
35#include <libgen.h>
36#include <kvm.h>
37#include <string.h>
38
39#include <defs.h>
40#include <command.h>
41#include <frame-unwind.h>
42#include <gdbthread.h>
43#include <inferior.h>
44#include <regcache.h>
45#include <target.h>
46#include <objfiles.h>
47#include <gdbcore.h>
48#include <language.h>
49
50#include "kgdb.h"
51
52static struct target_ops kgdb_trgt_ops;
53
54#define	KERNOFF		(kgdb_kernbase ())
55#define	INKERNEL(x)	((x) >= KERNOFF)
56
57static CORE_ADDR
58kgdb_kernbase (void)
59{
60	static CORE_ADDR kernbase;
61	struct minimal_symbol *sym;
62
63	if (kernbase == 0) {
64		sym = lookup_minimal_symbol ("kernbase", NULL, NULL);
65		if (sym == NULL) {
66			kernbase = KERNBASE;
67		} else {
68			kernbase = SYMBOL_VALUE_ADDRESS (sym);
69		}
70	}
71	return kernbase;
72}
73
74static char *
75kgdb_trgt_extra_thread_info(struct thread_info *ti)
76{
77	static char buf[64];
78	char *p, *s;
79
80	p = buf + snprintf(buf, sizeof(buf), "PID=%d", ptid_get_pid(ti->ptid));
81	s = kgdb_thr_extra_thread_info(ptid_get_tid(ti->ptid));
82	if (s != NULL)
83		snprintf(p, sizeof(buf) - (p - buf), ": %s", s);
84	return (buf);
85}
86
87static void
88kgdb_trgt_files_info(struct target_ops *target)
89{
90	struct target_ops *tb;
91
92	tb = find_target_beneath(target);
93	if (tb->to_files_info != NULL)
94		tb->to_files_info(tb);
95}
96
97static void
98kgdb_trgt_find_new_threads(void)
99{
100	struct target_ops *tb;
101
102	if (kvm != NULL)
103		return;
104
105	tb = find_target_beneath(&kgdb_trgt_ops);
106	if (tb->to_find_new_threads != NULL)
107		tb->to_find_new_threads();
108}
109
110static char *
111kgdb_trgt_pid_to_str(ptid_t ptid)
112{
113	static char buf[33];
114
115	snprintf(buf, sizeof(buf), "Thread %ld", ptid_get_tid(ptid));
116	return (buf);
117}
118
119static int
120kgdb_trgt_thread_alive(ptid_t ptid)
121{
122	return (kgdb_thr_lookup_tid(ptid_get_tid(ptid)) != NULL);
123}
124
125static int
126kgdb_trgt_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len, int write,
127    struct mem_attrib *attrib, struct target_ops *target)
128{
129	struct target_ops *tb;
130
131	if (kvm != NULL) {
132		if (len == 0)
133			return (0);
134		if (!write)
135			return (kvm_read(kvm, memaddr, myaddr, len));
136		else
137			return (kvm_write(kvm, memaddr, myaddr, len));
138	}
139	tb = find_target_beneath(target);
140	return (tb->to_xfer_memory(memaddr, myaddr, len, write, attrib, tb));
141}
142
143static void
144kgdb_switch_to_thread(struct kthr *thr)
145{
146	if (thr->tid == ptid_get_tid(inferior_ptid))
147		return;
148
149	inferior_ptid = ptid_build(thr->pid, 0, thr->tid);
150	flush_cached_frames ();
151	registers_changed ();
152	stop_pc = read_pc ();
153	select_frame (get_current_frame ());
154}
155
156static void
157kgdb_set_proc_cmd (char *arg, int from_tty)
158{
159	CORE_ADDR addr;
160	struct kthr *thr;
161
162	if (!arg)
163		error_no_arg ("proc address for the new context");
164
165	if (kvm == NULL)
166		error ("no kernel core file");
167
168	addr = (CORE_ADDR) parse_and_eval_address (arg);
169
170	if (!INKERNEL (addr)) {
171		thr = kgdb_thr_lookup_pid((int)addr);
172		if (thr == NULL)
173			error ("invalid pid");
174	} else {
175		thr = kgdb_thr_lookup_paddr(addr);
176		if (thr == NULL)
177			error("invalid proc address");
178	}
179	kgdb_switch_to_thread(thr);
180}
181
182static void
183kgdb_set_tid_cmd (char *arg, int from_tty)
184{
185	CORE_ADDR addr;
186	struct kthr *thr;
187
188	if (!arg)
189		error_no_arg ("TID or thread address for the new context");
190
191	if (kvm == NULL)
192		error ("no kernel core file");
193
194	addr = (CORE_ADDR) parse_and_eval_address (arg);
195
196	if (!INKERNEL (addr)) {
197		thr = kgdb_thr_lookup_tid((int)addr);
198		if (thr == NULL)
199			error ("invalid TID");
200	} else {
201		thr = kgdb_thr_lookup_taddr(addr);
202		if (thr == NULL)
203			error("invalid thread address");
204	}
205	kgdb_switch_to_thread(thr);
206}
207
208static int
209kld_ok (char *path)
210{
211	struct stat sb;
212
213	if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode))
214		return (1);
215	return (0);
216}
217
218/*
219 * Look for a matching file in the following order:
220 * - filename + ".symbols" (e.g. foo.ko.symbols)
221 * - filename + ".debug" (e.g. foo.ko.debug)
222 * - filename (e.g. foo.ko)
223 * - dirname(kernel) + filename + ".symbols" (e.g. /boot/kernel/foo.ko.symbols)
224 * - dirname(kernel) + filename + ".debug" (e.g. /boot/kernel/foo.ko.debug)
225 * - dirname(kernel) + filename (e.g. /boot/kernel/foo.ko)
226 * - iterate over each path in the module path looking for:
227 *   - dir + filename + ".symbols" (e.g. /boot/modules/foo.ko.symbols)
228 *   - dir + filename + ".debug" (e.g. /boot/modules/foo.ko.debug)
229 *   - dir + filename (e.g. /boot/modules/foo.ko)
230 */
231static int
232find_kld_path (char *filename, char *path, size_t path_size)
233{
234	CORE_ADDR module_path_addr;
235	char module_path[PATH_MAX];
236	char *kernel_dir, *module_dir, *cp;
237
238	snprintf(path, path_size, "%s.symbols", filename);
239	if (kld_ok(path))
240		return (1);
241	snprintf(path, path_size, "%s.debug", filename);
242	if (kld_ok(path))
243		return (1);
244	snprintf(path, path_size, "%s", filename);
245	if (kld_ok(path))
246		return (1);
247	kernel_dir = dirname(kernel);
248	if (kernel_dir != NULL) {
249		snprintf(path, path_size, "%s/%s.symbols", kernel_dir,
250		    filename);
251		if (kld_ok(path))
252			return (1);
253		snprintf(path, path_size, "%s/%s.debug", kernel_dir, filename);
254		if (kld_ok(path))
255			return (1);
256		snprintf(path, path_size, "%s/%s", kernel_dir, filename);
257		if (kld_ok(path))
258			return (1);
259	}
260	module_path_addr = kgdb_parse("linker_path");
261	if (module_path_addr != 0 &&
262	    kvm_read(kvm, module_path_addr, module_path, sizeof(module_path)) ==
263	    sizeof(module_path)) {
264		module_path[PATH_MAX - 1] = '\0';
265		cp = module_path;
266		while ((module_dir = strsep(&cp, ";")) != NULL) {
267			snprintf(path, path_size, "%s/%s.symbols", module_dir,
268			    filename);
269			if (kld_ok(path))
270				return (1);
271			snprintf(path, path_size, "%s/%s.debug", module_dir,
272			    filename);
273			if (kld_ok(path))
274				return (1);
275			snprintf(path, path_size, "%s/%s", module_dir,
276			    filename);
277			if (kld_ok(path))
278				return (1);
279		}
280	}
281	return (0);
282}
283
284/*
285 * Read a kernel pointer given a KVA in 'address'.
286 */
287static CORE_ADDR
288read_pointer (CORE_ADDR address)
289{
290	union {
291		uint32_t d32;
292		uint64_t d64;
293	} val;
294
295	switch (TARGET_PTR_BIT) {
296	case 32:
297		if (kvm_read(kvm, address, &val.d32, sizeof(val.d32)) !=
298		    sizeof(val.d32))
299			return (0);
300		return (val.d32);
301	case 64:
302		if (kvm_read(kvm, address, &val.d64, sizeof(val.d64)) !=
303		    sizeof(val.d64))
304			return (0);
305		return (val.d64);
306	default:
307		return (0);
308	}
309}
310
311/*
312 * Try to find this kld in the kernel linker's list of linker files.
313 */
314static int
315find_kld_address (char *arg, CORE_ADDR *address)
316{
317	CORE_ADDR kld, filename_addr;
318	CORE_ADDR off_address, off_filename, off_next;
319	char kld_filename[PATH_MAX];
320	char *filename;
321	size_t filelen;
322
323	/* Compute offsets of relevant members in struct linker_file. */
324	off_address = kgdb_parse("&((struct linker_file *)0)->address");
325	off_filename = kgdb_parse("&((struct linker_file *)0)->filename");
326	off_next = kgdb_parse("&((struct linker_file *)0)->link.tqe_next");
327	if (off_address == 0 || off_filename == 0 || off_next == 0)
328		return (0);
329
330	filename = basename(arg);
331	filelen = strlen(filename) + 1;
332	kld = kgdb_parse("linker_files.tqh_first");
333	while (kld != 0) {
334		/* Try to read this linker file's filename. */
335		filename_addr = read_pointer(kld + off_filename);
336		if (filename_addr == 0)
337			goto next_kld;
338		if (kvm_read(kvm, filename_addr, kld_filename, filelen) !=
339		    filelen)
340			goto next_kld;
341
342		/* Compare this kld's filename against our passed in name. */
343		if (kld_filename[filelen - 1] != '\0')
344			goto next_kld;
345		if (strcmp(kld_filename, filename) != 0)
346			goto next_kld;
347
348		/*
349		 * We found a match, use its address as the base
350		 * address if we can read it.
351		 */
352		*address = read_pointer(kld + off_address);
353		if (*address == 0)
354			return (0);
355		return (1);
356
357	next_kld:
358		kld = read_pointer(kld + off_next);
359	}
360	return (0);
361}
362
363static void
364add_section(struct section_addr_info *section_addrs, int *sect_indexp,
365    char *name, CORE_ADDR address)
366{
367	int sect_index;
368
369	sect_index = *sect_indexp;
370	section_addrs->other[sect_index].name = name;
371	section_addrs->other[sect_index].addr = address;
372	printf_unfiltered("\t%s_addr = %s\n", name,
373	    local_hex_string(address));
374	sect_index++;
375	*sect_indexp = sect_index;
376}
377
378static void
379kgdb_add_kld_cmd (char *arg, int from_tty)
380{
381	struct section_addr_info *section_addrs;
382	struct cleanup *cleanup;
383	char path[PATH_MAX];
384	asection *sect;
385	CORE_ADDR base_addr;
386	bfd *bfd;
387	CORE_ADDR text_addr, data_addr, bss_addr, rodata_addr;
388	int sect_count, sect_index;
389
390	if (!find_kld_path(arg, path, sizeof(path))) {
391		error("unable to locate kld");
392		return;
393	}
394
395	if (!find_kld_address(arg, &base_addr)) {
396		error("unable to find kld in kernel");
397		return;
398	}
399
400	/* Open the kld and find the offsets of the various sections. */
401	bfd = bfd_openr(path, gnutarget);
402	if (bfd == NULL) {
403		error("\"%s\": can't open: %s", path,
404		    bfd_errmsg(bfd_get_error()));
405		return;
406	}
407	cleanup = make_cleanup_bfd_close(bfd);
408
409	if (!bfd_check_format(bfd, bfd_object)) {
410		do_cleanups(cleanup);
411		error("\%s\": not an object file", path);
412		return;
413	}
414
415	data_addr = bss_addr = rodata_addr = 0;
416	sect = bfd_get_section_by_name (bfd, ".text");
417	if (sect == NULL) {
418		do_cleanups(cleanup);
419		error("\"%s\": can't find text section", path);
420		return;
421	}
422	text_addr = bfd_get_section_vma(bfd, sect);
423	sect_count = 1;
424
425	/* Save the offsets of relevant sections. */
426	sect = bfd_get_section_by_name (bfd, ".data");
427	if (sect != NULL) {
428		data_addr = bfd_get_section_vma(bfd, sect);
429		sect_count++;
430	}
431
432	sect = bfd_get_section_by_name (bfd, ".bss");
433	if (sect != NULL) {
434		bss_addr = bfd_get_section_vma(bfd, sect);
435		sect_count++;
436	}
437
438	sect = bfd_get_section_by_name (bfd, ".rodata");
439	if (sect != NULL) {
440		rodata_addr = bfd_get_section_vma(bfd, sect);
441		sect_count++;
442	}
443
444	do_cleanups(cleanup);
445
446	printf_unfiltered("add symbol table from file \"%s\" at\n", path);
447
448	/* Build a section table for symbol_file_add(). */
449	section_addrs = alloc_section_addr_info(sect_count);
450	cleanup = make_cleanup(xfree, section_addrs);
451	sect_index = 0;
452	add_section(section_addrs, &sect_index, ".text", base_addr + text_addr);
453	if (data_addr != 0)
454		add_section(section_addrs, &sect_index, ".data",
455		    base_addr + data_addr);
456	if (bss_addr != 0)
457		add_section(section_addrs, &sect_index, ".bss",
458		    base_addr + bss_addr);
459	if (rodata_addr != 0)
460		add_section(section_addrs, &sect_index, ".rodata",
461		    base_addr + rodata_addr);
462
463	symbol_file_add(path, from_tty, section_addrs, 0, OBJF_USERLOADED);
464
465	reinit_frame_cache();
466
467	do_cleanups(cleanup);
468}
469
470void
471kgdb_target(void)
472{
473	struct kthr *kt;
474	struct thread_info *ti;
475
476	kgdb_trgt_ops.to_magic = OPS_MAGIC;
477	kgdb_trgt_ops.to_shortname = "kernel";
478	kgdb_trgt_ops.to_longname = "kernel core files.";
479	kgdb_trgt_ops.to_doc = "Kernel core files.";
480	kgdb_trgt_ops.to_stratum = thread_stratum;
481	kgdb_trgt_ops.to_has_memory = 1;
482	kgdb_trgt_ops.to_has_registers = 1;
483	kgdb_trgt_ops.to_has_stack = 1;
484
485	kgdb_trgt_ops.to_extra_thread_info = kgdb_trgt_extra_thread_info;
486	kgdb_trgt_ops.to_fetch_registers = kgdb_trgt_fetch_registers;
487	kgdb_trgt_ops.to_files_info = kgdb_trgt_files_info;
488	kgdb_trgt_ops.to_find_new_threads = kgdb_trgt_find_new_threads;
489	kgdb_trgt_ops.to_pid_to_str = kgdb_trgt_pid_to_str;
490	kgdb_trgt_ops.to_store_registers = kgdb_trgt_store_registers;
491	kgdb_trgt_ops.to_thread_alive = kgdb_trgt_thread_alive;
492	kgdb_trgt_ops.to_xfer_memory = kgdb_trgt_xfer_memory;
493	add_target(&kgdb_trgt_ops);
494	push_target(&kgdb_trgt_ops);
495
496	kt = kgdb_thr_first();
497	while (kt != NULL) {
498		ti = add_thread(ptid_build(kt->pid, 0, kt->tid));
499		kt = kgdb_thr_next(kt);
500	}
501	if (curkthr != 0)
502		inferior_ptid = ptid_build(curkthr->pid, 0, curkthr->tid);
503	add_com ("proc", class_obscure, kgdb_set_proc_cmd,
504	   "Set current process context");
505	add_com ("tid", class_obscure, kgdb_set_tid_cmd,
506	   "Set current thread context");
507	add_com ("add-kld", class_files, kgdb_add_kld_cmd,
508	   "Usage: add-kld FILE\n\
509Load the symbols from the kernel loadable module FILE.");
510}
511