1139747Simp/*-
2131952Smarcel * Mach Operating System
3131952Smarcel * Copyright (c) 1991,1990 Carnegie Mellon University
4131952Smarcel * All Rights Reserved.
5131952Smarcel *
6131952Smarcel * Permission to use, copy, modify and distribute this software and its
7131952Smarcel * documentation is hereby granted, provided that both the copyright
8131952Smarcel * notice and this permission notice appear in all copies of the
9131952Smarcel * software, derivative works or modified versions, and any portions
10131952Smarcel * thereof, and that both notices appear in supporting documentation.
11131952Smarcel *
12131952Smarcel * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13131952Smarcel * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14131952Smarcel * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15131952Smarcel *
16131952Smarcel * Carnegie Mellon requests users of this software to return to
17131952Smarcel *
18131952Smarcel *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19131952Smarcel *  School of Computer Science
20131952Smarcel *  Carnegie Mellon University
21131952Smarcel *  Pittsburgh PA 15213-3890
22131952Smarcel *
23131952Smarcel * any improvements or extensions that they make and grant Carnegie the
24131952Smarcel * rights to redistribute these changes.
25131952Smarcel */
26131952Smarcel
27131952Smarcel#include <sys/cdefs.h>
28131952Smarcel__FBSDID("$FreeBSD$");
29131952Smarcel
30131952Smarcel#include <sys/param.h>
31131952Smarcel#include <sys/systm.h>
32131952Smarcel#include <sys/cons.h>
33131952Smarcel#include <sys/linker.h>
34131952Smarcel#include <sys/kdb.h>
35131952Smarcel#include <sys/kernel.h>
36131952Smarcel#include <sys/pcpu.h>
37131952Smarcel#include <sys/proc.h>
38131952Smarcel#include <sys/reboot.h>
39174910Srwatson#include <sys/sysctl.h>
40131952Smarcel
41131952Smarcel#include <machine/kdb.h>
42131952Smarcel#include <machine/pcb.h>
43131952Smarcel#include <machine/setjmp.h>
44131952Smarcel
45131952Smarcel#include <ddb/ddb.h>
46131952Smarcel#include <ddb/db_command.h>
47131952Smarcel#include <ddb/db_sym.h>
48131952Smarcel
49174910SrwatsonSYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW, 0, "DDB settings");
50174910Srwatson
51131952Smarcelstatic dbbe_init_f db_init;
52131952Smarcelstatic dbbe_trap_f db_trap;
53164029Skibstatic dbbe_trace_f db_trace_self_wrapper;
54234196Sjhbstatic dbbe_trace_thread_f db_trace_thread_wrapper;
55131952Smarcel
56234196SjhbKDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper,
57234196Sjhb    db_trap);
58131952Smarcel
59131952Smarcelvm_offset_t ksym_start, ksym_end;
60131952Smarcel
61131952Smarcelboolean_t
62131952SmarcelX_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line,
63131952Smarcel    db_expr_t off)
64131952Smarcel{
65131952Smarcel	return (FALSE);
66131952Smarcel}
67131952Smarcel
68131952Smarcelc_db_sym_t
69131952SmarcelX_db_lookup(db_symtab_t *symtab, const char *symbol)
70131952Smarcel{
71131952Smarcel	c_linker_sym_t lsym;
72131952Smarcel	Elf_Sym *sym;
73131952Smarcel
74131952Smarcel	if (symtab->private == NULL) {
75131952Smarcel		return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym))
76131952Smarcel			? lsym : NULL));
77131952Smarcel	} else {
78131952Smarcel		sym = (Elf_Sym *)symtab->start;
79131952Smarcel		while ((char *)sym < symtab->end) {
80131952Smarcel			if (sym->st_name != 0 &&
81131952Smarcel			    !strcmp(symtab->private + sym->st_name, symbol))
82131952Smarcel				return ((c_db_sym_t)sym);
83131952Smarcel			sym++;
84131952Smarcel		}
85131952Smarcel	}
86131952Smarcel	return (NULL);
87131952Smarcel}
88131952Smarcel
89131952Smarcelc_db_sym_t
90131952SmarcelX_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat,
91131952Smarcel    db_expr_t *diffp)
92131952Smarcel{
93131952Smarcel	c_linker_sym_t lsym;
94131952Smarcel	Elf_Sym *sym, *match;
95131952Smarcel	unsigned long diff;
96131952Smarcel
97131952Smarcel	if (symtab->private == NULL) {
98131952Smarcel		if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) {
99131952Smarcel			*diffp = (db_expr_t)diff;
100131952Smarcel			return ((c_db_sym_t)lsym);
101131952Smarcel		}
102131952Smarcel		return (NULL);
103131952Smarcel	}
104131952Smarcel
105131952Smarcel	diff = ~0UL;
106131952Smarcel	match = NULL;
107131952Smarcel	for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) {
108131952Smarcel		if (sym->st_name == 0)
109131952Smarcel			continue;
110131952Smarcel		if (off < sym->st_value)
111131952Smarcel			continue;
112131952Smarcel		if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
113131952Smarcel		    ELF_ST_TYPE(sym->st_info) != STT_FUNC &&
114131952Smarcel		    ELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
115131952Smarcel			continue;
116131952Smarcel		if ((off - sym->st_value) > diff)
117131952Smarcel			continue;
118131952Smarcel		if ((off - sym->st_value) < diff) {
119131952Smarcel			diff = off - sym->st_value;
120131952Smarcel			match = sym;
121131952Smarcel		} else {
122131952Smarcel			if (match == NULL)
123131952Smarcel				match = sym;
124131952Smarcel			else if (ELF_ST_BIND(match->st_info) == STB_LOCAL &&
125131952Smarcel			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
126131952Smarcel				match = sym;
127131952Smarcel		}
128131952Smarcel		if (diff == 0) {
129131952Smarcel			if (strat == DB_STGY_PROC &&
130131952Smarcel			    ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
131131952Smarcel			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
132131952Smarcel				break;
133131952Smarcel			if (strat == DB_STGY_ANY &&
134131952Smarcel			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
135131952Smarcel				break;
136131952Smarcel		}
137131952Smarcel	}
138131952Smarcel
139131952Smarcel	*diffp = (match == NULL) ? off : diff;
140131952Smarcel	return ((c_db_sym_t)match);
141131952Smarcel}
142131952Smarcel
143131952Smarcelboolean_t
144131952SmarcelX_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp,
145131952Smarcel    char **argp)
146131952Smarcel{
147131952Smarcel	return (FALSE);
148131952Smarcel}
149131952Smarcel
150131952Smarcelvoid
151131952SmarcelX_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep,
152131952Smarcel    db_expr_t *valp)
153131952Smarcel{
154131952Smarcel	linker_symval_t lval;
155131952Smarcel
156131952Smarcel	if (symtab->private == NULL) {
157131952Smarcel		linker_ddb_symbol_values((c_linker_sym_t)sym, &lval);
158131952Smarcel		if (namep != NULL)
159131952Smarcel			*namep = (const char*)lval.name;
160131952Smarcel		if (valp != NULL)
161131952Smarcel			*valp = (db_expr_t)lval.value;
162131952Smarcel	} else {
163131952Smarcel		if (namep != NULL)
164131952Smarcel			*namep = (const char *)symtab->private +
165131952Smarcel			    ((const Elf_Sym *)sym)->st_name;
166131952Smarcel		if (valp != NULL)
167131952Smarcel			*valp = (db_expr_t)((const Elf_Sym *)sym)->st_value;
168131952Smarcel	}
169131952Smarcel}
170131952Smarcel
171131952Smarcelstatic int
172131952Smarceldb_init(void)
173131952Smarcel{
174131952Smarcel	uintptr_t symtab, strtab;
175131952Smarcel	Elf_Size tabsz, strsz;
176131952Smarcel
177183360Sjhb	db_command_init();
178131952Smarcel	if (ksym_end > ksym_start && ksym_start != 0) {
179131952Smarcel		symtab = ksym_start;
180132771Skan		tabsz = *((Elf_Size*)symtab);
181132791Skan		symtab += sizeof(Elf_Size);
182131952Smarcel		strtab = symtab + tabsz;
183132771Skan		strsz = *((Elf_Size*)strtab);
184132791Skan		strtab += sizeof(Elf_Size);
185131952Smarcel		if (strtab + strsz <= ksym_end) {
186131952Smarcel			db_add_symbol_table((char *)symtab,
187131952Smarcel			    (char *)(symtab + tabsz), "elf", (char *)strtab);
188131952Smarcel		}
189131952Smarcel	}
190131952Smarcel	db_add_symbol_table(NULL, NULL, "kld", NULL);
191131952Smarcel	return (1);	/* We're the default debugger. */
192131952Smarcel}
193131952Smarcel
194131952Smarcelstatic int
195131952Smarceldb_trap(int type, int code)
196131952Smarcel{
197131952Smarcel	jmp_buf jb;
198131952Smarcel	void *prev_jb;
199131952Smarcel	boolean_t bkpt, watchpt;
200174914Srwatson	const char *why;
201131952Smarcel
202131952Smarcel	/*
203131952Smarcel	 * Don't handle the trap if the console is unavailable (i.e. it
204131952Smarcel	 * is in graphics mode).
205131952Smarcel	 */
206131952Smarcel	if (cnunavailable())
207131952Smarcel		return (0);
208131952Smarcel
209131952Smarcel	bkpt = IS_BREAKPOINT_TRAP(type, code);
210131952Smarcel	watchpt = IS_WATCHPOINT_TRAP(type, code);
211131952Smarcel
212131952Smarcel	if (db_stop_at_pc(&bkpt)) {
213131952Smarcel		if (db_inst_count) {
214131952Smarcel			db_printf("After %d instructions (%d loads, %d stores),\n",
215131952Smarcel			    db_inst_count, db_load_count, db_store_count);
216131952Smarcel		}
217131952Smarcel		prev_jb = kdb_jmpbuf(jb);
218131952Smarcel		if (setjmp(jb) == 0) {
219131952Smarcel			db_dot = PC_REGS();
220131952Smarcel			db_print_thread();
221131952Smarcel			if (bkpt)
222131952Smarcel				db_printf("Breakpoint at\t");
223131952Smarcel			else if (watchpt)
224131952Smarcel				db_printf("Watchpoint at\t");
225131952Smarcel			else
226131952Smarcel				db_printf("Stopped at\t");
227131952Smarcel			db_print_loc_and_inst(db_dot);
228131952Smarcel		}
229174914Srwatson		why = kdb_why;
230174914Srwatson		db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown");
231131952Smarcel		db_command_loop();
232131952Smarcel		(void)kdb_jmpbuf(prev_jb);
233131952Smarcel	}
234131952Smarcel
235131952Smarcel	db_restart_at_pc(watchpt);
236131952Smarcel
237131952Smarcel	return (1);
238131952Smarcel}
239164029Skib
240164029Skibstatic void
241164029Skibdb_trace_self_wrapper(void)
242164029Skib{
243164029Skib	jmp_buf jb;
244164029Skib	void *prev_jb;
245164029Skib
246164029Skib	prev_jb = kdb_jmpbuf(jb);
247164029Skib	if (setjmp(jb) == 0)
248164029Skib		db_trace_self();
249164029Skib	(void)kdb_jmpbuf(prev_jb);
250164029Skib}
251234196Sjhb
252234196Sjhbstatic void
253234196Sjhbdb_trace_thread_wrapper(struct thread *td)
254234196Sjhb{
255234196Sjhb	jmp_buf jb;
256234196Sjhb	void *prev_jb;
257234196Sjhb
258234196Sjhb	prev_jb = kdb_jmpbuf(jb);
259234196Sjhb	if (setjmp(jb) == 0)
260234196Sjhb		db_trace_thread(td, -1);
261234196Sjhb	(void)kdb_jmpbuf(prev_jb);
262234196Sjhb}
263