db_main.c revision 308418
1/*-
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19 *  School of Computer Science
20 *  Carnegie Mellon University
21 *  Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/ddb/db_main.c 308418 2016-11-07 12:10:17Z kib $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/cons.h>
33#include <sys/linker.h>
34#include <sys/kdb.h>
35#include <sys/kernel.h>
36#include <sys/pcpu.h>
37#include <sys/proc.h>
38#include <sys/reboot.h>
39#include <sys/sysctl.h>
40
41#include <machine/kdb.h>
42#include <machine/pcb.h>
43#include <machine/setjmp.h>
44
45#include <ddb/ddb.h>
46#include <ddb/db_command.h>
47#include <ddb/db_sym.h>
48
49SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW, 0, "DDB settings");
50
51static dbbe_init_f db_init;
52static dbbe_trap_f db_trap;
53static dbbe_trace_f db_trace_self_wrapper;
54static dbbe_trace_thread_f db_trace_thread_wrapper;
55
56KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper,
57    db_trap);
58
59/*
60 * Symbols can be loaded by specifying the exact addresses of
61 * the symtab and strtab in memory. This is used when loaded from
62 * boot loaders different than the native one (like Xen).
63 */
64vm_offset_t ksymtab, kstrtab, ksymtab_size;
65
66bool
67X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line,
68    db_expr_t off)
69{
70	return (false);
71}
72
73c_db_sym_t
74X_db_lookup(db_symtab_t *symtab, const char *symbol)
75{
76	c_linker_sym_t lsym;
77	Elf_Sym *sym;
78
79	if (symtab->private == NULL) {
80		return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym))
81			? lsym : NULL));
82	} else {
83		sym = (Elf_Sym *)symtab->start;
84		while ((char *)sym < symtab->end) {
85			if (sym->st_name != 0 &&
86			    !strcmp(symtab->private + sym->st_name, symbol))
87				return ((c_db_sym_t)sym);
88			sym++;
89		}
90	}
91	return (NULL);
92}
93
94c_db_sym_t
95X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat,
96    db_expr_t *diffp)
97{
98	c_linker_sym_t lsym;
99	Elf_Sym *sym, *match;
100	unsigned long diff;
101
102	if (symtab->private == NULL) {
103		if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) {
104			*diffp = (db_expr_t)diff;
105			return ((c_db_sym_t)lsym);
106		}
107		return (NULL);
108	}
109
110	diff = ~0UL;
111	match = NULL;
112	for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) {
113		if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF)
114			continue;
115		if (off < sym->st_value)
116			continue;
117		if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
118		    ELF_ST_TYPE(sym->st_info) != STT_FUNC &&
119		    ELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
120			continue;
121		if ((off - sym->st_value) > diff)
122			continue;
123		if ((off - sym->st_value) < diff) {
124			diff = off - sym->st_value;
125			match = sym;
126		} else {
127			if (match == NULL)
128				match = sym;
129			else if (ELF_ST_BIND(match->st_info) == STB_LOCAL &&
130			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
131				match = sym;
132		}
133		if (diff == 0) {
134			if (strat == DB_STGY_PROC &&
135			    ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
136			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
137				break;
138			if (strat == DB_STGY_ANY &&
139			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
140				break;
141		}
142	}
143
144	*diffp = (match == NULL) ? off : diff;
145	return ((c_db_sym_t)match);
146}
147
148bool
149X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp,
150    char **argp)
151{
152	return (false);
153}
154
155void
156X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep,
157    db_expr_t *valp)
158{
159	linker_symval_t lval;
160
161	if (symtab->private == NULL) {
162		linker_ddb_symbol_values((c_linker_sym_t)sym, &lval);
163		if (namep != NULL)
164			*namep = (const char*)lval.name;
165		if (valp != NULL)
166			*valp = (db_expr_t)lval.value;
167	} else {
168		if (namep != NULL)
169			*namep = (const char *)symtab->private +
170			    ((const Elf_Sym *)sym)->st_name;
171		if (valp != NULL)
172			*valp = (db_expr_t)((const Elf_Sym *)sym)->st_value;
173	}
174}
175
176int
177db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end)
178{
179	Elf_Size strsz;
180
181	if (ksym_end > ksym_start && ksym_start != 0) {
182		ksymtab = ksym_start;
183		ksymtab_size = *(Elf_Size*)ksymtab;
184		ksymtab += sizeof(Elf_Size);
185		kstrtab = ksymtab + ksymtab_size;
186		strsz = *(Elf_Size*)kstrtab;
187		kstrtab += sizeof(Elf_Size);
188		if (kstrtab + strsz > ksym_end) {
189			/* Sizes doesn't match, unset everything. */
190			ksymtab = ksymtab_size = kstrtab = 0;
191		}
192	}
193
194	if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0)
195		return (-1);
196
197	return (0);
198}
199
200static int
201db_init(void)
202{
203
204	db_command_init();
205
206	if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) {
207		db_add_symbol_table((char *)ksymtab,
208		    (char *)(ksymtab + ksymtab_size), "elf", (char *)kstrtab);
209	}
210	db_add_symbol_table(NULL, NULL, "kld", NULL);
211	return (1);	/* We're the default debugger. */
212}
213
214static int
215db_trap(int type, int code)
216{
217	jmp_buf jb;
218	void *prev_jb;
219	bool bkpt, watchpt;
220	const char *why;
221
222	/*
223	 * Don't handle the trap if the console is unavailable (i.e. it
224	 * is in graphics mode).
225	 */
226	if (cnunavailable())
227		return (0);
228
229	if (db_stop_at_pc(type, code, &bkpt, &watchpt)) {
230		if (db_inst_count) {
231			db_printf("After %d instructions (%d loads, %d stores),\n",
232			    db_inst_count, db_load_count, db_store_count);
233		}
234		prev_jb = kdb_jmpbuf(jb);
235		if (setjmp(jb) == 0) {
236			db_dot = PC_REGS();
237			db_print_thread();
238			if (bkpt)
239				db_printf("Breakpoint at\t");
240			else if (watchpt)
241				db_printf("Watchpoint at\t");
242			else
243				db_printf("Stopped at\t");
244			db_print_loc_and_inst(db_dot);
245		}
246		why = kdb_why;
247		db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown");
248		db_command_loop();
249		(void)kdb_jmpbuf(prev_jb);
250	}
251
252	db_restart_at_pc(watchpt);
253
254	return (1);
255}
256
257static void
258db_trace_self_wrapper(void)
259{
260	jmp_buf jb;
261	void *prev_jb;
262
263	prev_jb = kdb_jmpbuf(jb);
264	if (setjmp(jb) == 0)
265		db_trace_self();
266	(void)kdb_jmpbuf(prev_jb);
267}
268
269static void
270db_trace_thread_wrapper(struct thread *td)
271{
272	jmp_buf jb;
273	void *prev_jb;
274
275	prev_jb = kdb_jmpbuf(jb);
276	if (setjmp(jb) == 0)
277		db_trace_thread(td, -1);
278	(void)kdb_jmpbuf(prev_jb);
279}
280