xref: /freebsd/sys/ddb/db_main.c (revision 40b664f64b96112ea332157824502a0d5d88f015)
1dd3cb568SWarner Losh /*-
2796df753SPedro F. Giffuni  * SPDX-License-Identifier: MIT-CMU
3796df753SPedro F. Giffuni  *
437224cd3SMarcel Moolenaar  * Mach Operating System
537224cd3SMarcel Moolenaar  * Copyright (c) 1991,1990 Carnegie Mellon University
637224cd3SMarcel Moolenaar  * All Rights Reserved.
737224cd3SMarcel Moolenaar  *
837224cd3SMarcel Moolenaar  * Permission to use, copy, modify and distribute this software and its
937224cd3SMarcel Moolenaar  * documentation is hereby granted, provided that both the copyright
1037224cd3SMarcel Moolenaar  * notice and this permission notice appear in all copies of the
1137224cd3SMarcel Moolenaar  * software, derivative works or modified versions, and any portions
1237224cd3SMarcel Moolenaar  * thereof, and that both notices appear in supporting documentation.
1337224cd3SMarcel Moolenaar  *
1437224cd3SMarcel Moolenaar  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
1537224cd3SMarcel Moolenaar  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1637224cd3SMarcel Moolenaar  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1737224cd3SMarcel Moolenaar  *
1837224cd3SMarcel Moolenaar  * Carnegie Mellon requests users of this software to return to
1937224cd3SMarcel Moolenaar  *
2037224cd3SMarcel Moolenaar  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
2137224cd3SMarcel Moolenaar  *  School of Computer Science
2237224cd3SMarcel Moolenaar  *  Carnegie Mellon University
2337224cd3SMarcel Moolenaar  *  Pittsburgh PA 15213-3890
2437224cd3SMarcel Moolenaar  *
2537224cd3SMarcel Moolenaar  * any improvements or extensions that they make and grant Carnegie the
2637224cd3SMarcel Moolenaar  * rights to redistribute these changes.
2737224cd3SMarcel Moolenaar  */
2837224cd3SMarcel Moolenaar 
2937224cd3SMarcel Moolenaar #include <sys/cdefs.h>
3037224cd3SMarcel Moolenaar __FBSDID("$FreeBSD$");
3137224cd3SMarcel Moolenaar 
3237224cd3SMarcel Moolenaar #include <sys/param.h>
3337224cd3SMarcel Moolenaar #include <sys/systm.h>
3437224cd3SMarcel Moolenaar #include <sys/cons.h>
3537224cd3SMarcel Moolenaar #include <sys/linker.h>
3637224cd3SMarcel Moolenaar #include <sys/kdb.h>
3737224cd3SMarcel Moolenaar #include <sys/kernel.h>
3837224cd3SMarcel Moolenaar #include <sys/pcpu.h>
3937224cd3SMarcel Moolenaar #include <sys/proc.h>
4037224cd3SMarcel Moolenaar #include <sys/reboot.h>
41086fec57SRobert Watson #include <sys/sysctl.h>
4237224cd3SMarcel Moolenaar 
4337224cd3SMarcel Moolenaar #include <machine/kdb.h>
4437224cd3SMarcel Moolenaar #include <machine/pcb.h>
4537224cd3SMarcel Moolenaar #include <machine/setjmp.h>
4637224cd3SMarcel Moolenaar 
4737224cd3SMarcel Moolenaar #include <ddb/ddb.h>
4837224cd3SMarcel Moolenaar #include <ddb/db_command.h>
4937224cd3SMarcel Moolenaar #include <ddb/db_sym.h>
5037224cd3SMarcel Moolenaar 
51*40b664f6SBrandon Bergren struct db_private {
52*40b664f6SBrandon Bergren 	char*		strtab;
53*40b664f6SBrandon Bergren 	vm_offset_t	relbase;
54*40b664f6SBrandon Bergren };
55*40b664f6SBrandon Bergren typedef struct db_private *db_private_t;
56*40b664f6SBrandon Bergren 
57*40b664f6SBrandon Bergren #define DB_PRIVATE(x) ((db_private_t)(x->private))
58*40b664f6SBrandon Bergren 
597029da5cSPawel Biernacki SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
607029da5cSPawel Biernacki     "DDB settings");
61086fec57SRobert Watson 
6237224cd3SMarcel Moolenaar static dbbe_init_f db_init;
6337224cd3SMarcel Moolenaar static dbbe_trap_f db_trap;
64a0396f27SKonstantin Belousov static dbbe_trace_f db_trace_self_wrapper;
6528926c57SJohn Baldwin static dbbe_trace_thread_f db_trace_thread_wrapper;
6637224cd3SMarcel Moolenaar 
6728926c57SJohn Baldwin KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper,
6828926c57SJohn Baldwin     db_trap);
6937224cd3SMarcel Moolenaar 
70c98a2727SRoger Pau Monné /*
71c98a2727SRoger Pau Monné  * Symbols can be loaded by specifying the exact addresses of
72c98a2727SRoger Pau Monné  * the symtab and strtab in memory. This is used when loaded from
73c98a2727SRoger Pau Monné  * boot loaders different than the native one (like Xen).
74c98a2727SRoger Pau Monné  */
75*40b664f6SBrandon Bergren vm_offset_t ksymtab, kstrtab, ksymtab_size, ksymtab_relbase;
76*40b664f6SBrandon Bergren static struct db_private ksymtab_private;
7737224cd3SMarcel Moolenaar 
78cd508278SPedro F. Giffuni bool
7937224cd3SMarcel Moolenaar X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line,
8037224cd3SMarcel Moolenaar     db_expr_t off)
8137224cd3SMarcel Moolenaar {
822b490bc7SPedro F. Giffuni 	return (false);
8337224cd3SMarcel Moolenaar }
8437224cd3SMarcel Moolenaar 
8537224cd3SMarcel Moolenaar c_db_sym_t
8637224cd3SMarcel Moolenaar X_db_lookup(db_symtab_t *symtab, const char *symbol)
8737224cd3SMarcel Moolenaar {
8837224cd3SMarcel Moolenaar 	c_linker_sym_t lsym;
8937224cd3SMarcel Moolenaar 	Elf_Sym *sym;
9037224cd3SMarcel Moolenaar 
9137224cd3SMarcel Moolenaar 	if (symtab->private == NULL) {
9237224cd3SMarcel Moolenaar 		return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym))
9337224cd3SMarcel Moolenaar 			? lsym : NULL));
9437224cd3SMarcel Moolenaar 	} else {
9537224cd3SMarcel Moolenaar 		sym = (Elf_Sym *)symtab->start;
9637224cd3SMarcel Moolenaar 		while ((char *)sym < symtab->end) {
9737224cd3SMarcel Moolenaar 			if (sym->st_name != 0 &&
98*40b664f6SBrandon Bergren 			    !strcmp(DB_PRIVATE(symtab)->strtab +
99*40b664f6SBrandon Bergren 			    sym->st_name, symbol))
10037224cd3SMarcel Moolenaar 				return ((c_db_sym_t)sym);
10137224cd3SMarcel Moolenaar 			sym++;
10237224cd3SMarcel Moolenaar 		}
10337224cd3SMarcel Moolenaar 	}
10437224cd3SMarcel Moolenaar 	return (NULL);
10537224cd3SMarcel Moolenaar }
10637224cd3SMarcel Moolenaar 
10737224cd3SMarcel Moolenaar c_db_sym_t
10837224cd3SMarcel Moolenaar X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat,
10937224cd3SMarcel Moolenaar     db_expr_t *diffp)
11037224cd3SMarcel Moolenaar {
11137224cd3SMarcel Moolenaar 	c_linker_sym_t lsym;
11237224cd3SMarcel Moolenaar 	Elf_Sym *sym, *match;
11337224cd3SMarcel Moolenaar 	unsigned long diff;
114*40b664f6SBrandon Bergren 	db_addr_t stoffs = off;
11537224cd3SMarcel Moolenaar 
11637224cd3SMarcel Moolenaar 	if (symtab->private == NULL) {
11737224cd3SMarcel Moolenaar 		if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) {
11837224cd3SMarcel Moolenaar 			*diffp = (db_expr_t)diff;
11937224cd3SMarcel Moolenaar 			return ((c_db_sym_t)lsym);
12037224cd3SMarcel Moolenaar 		}
12137224cd3SMarcel Moolenaar 		return (NULL);
12237224cd3SMarcel Moolenaar 	}
123*40b664f6SBrandon Bergren 	else
124*40b664f6SBrandon Bergren 		stoffs -= DB_PRIVATE(symtab)->relbase;
12537224cd3SMarcel Moolenaar 
12637224cd3SMarcel Moolenaar 	diff = ~0UL;
12737224cd3SMarcel Moolenaar 	match = NULL;
12837224cd3SMarcel Moolenaar 	for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) {
129e31a60b4SMark Johnston 		if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF)
13037224cd3SMarcel Moolenaar 			continue;
131b4a0a598SJustin Hibbits 		if (stoffs < sym->st_value)
13237224cd3SMarcel Moolenaar 			continue;
13337224cd3SMarcel Moolenaar 		if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
13437224cd3SMarcel Moolenaar 		    ELF_ST_TYPE(sym->st_info) != STT_FUNC &&
13537224cd3SMarcel Moolenaar 		    ELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
13637224cd3SMarcel Moolenaar 			continue;
137b4a0a598SJustin Hibbits 		if ((stoffs - sym->st_value) > diff)
13837224cd3SMarcel Moolenaar 			continue;
139b4a0a598SJustin Hibbits 		if ((stoffs - sym->st_value) < diff) {
140b4a0a598SJustin Hibbits 			diff = stoffs - sym->st_value;
14137224cd3SMarcel Moolenaar 			match = sym;
14237224cd3SMarcel Moolenaar 		} else {
14337224cd3SMarcel Moolenaar 			if (match == NULL)
14437224cd3SMarcel Moolenaar 				match = sym;
14537224cd3SMarcel Moolenaar 			else if (ELF_ST_BIND(match->st_info) == STB_LOCAL &&
14637224cd3SMarcel Moolenaar 			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
14737224cd3SMarcel Moolenaar 				match = sym;
14837224cd3SMarcel Moolenaar 		}
14937224cd3SMarcel Moolenaar 		if (diff == 0) {
15037224cd3SMarcel Moolenaar 			if (strat == DB_STGY_PROC &&
15137224cd3SMarcel Moolenaar 			    ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
15237224cd3SMarcel Moolenaar 			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
15337224cd3SMarcel Moolenaar 				break;
15437224cd3SMarcel Moolenaar 			if (strat == DB_STGY_ANY &&
15537224cd3SMarcel Moolenaar 			    ELF_ST_BIND(sym->st_info) != STB_LOCAL)
15637224cd3SMarcel Moolenaar 				break;
15737224cd3SMarcel Moolenaar 		}
15837224cd3SMarcel Moolenaar 	}
15937224cd3SMarcel Moolenaar 
16037224cd3SMarcel Moolenaar 	*diffp = (match == NULL) ? off : diff;
16137224cd3SMarcel Moolenaar 	return ((c_db_sym_t)match);
16237224cd3SMarcel Moolenaar }
16337224cd3SMarcel Moolenaar 
164cd508278SPedro F. Giffuni bool
16537224cd3SMarcel Moolenaar X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp,
16637224cd3SMarcel Moolenaar     char **argp)
16737224cd3SMarcel Moolenaar {
1682b490bc7SPedro F. Giffuni 	return (false);
16937224cd3SMarcel Moolenaar }
17037224cd3SMarcel Moolenaar 
17137224cd3SMarcel Moolenaar void
17237224cd3SMarcel Moolenaar X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep,
17337224cd3SMarcel Moolenaar     db_expr_t *valp)
17437224cd3SMarcel Moolenaar {
17537224cd3SMarcel Moolenaar 	linker_symval_t lval;
17637224cd3SMarcel Moolenaar 
17737224cd3SMarcel Moolenaar 	if (symtab->private == NULL) {
17837224cd3SMarcel Moolenaar 		linker_ddb_symbol_values((c_linker_sym_t)sym, &lval);
17937224cd3SMarcel Moolenaar 		if (namep != NULL)
18037224cd3SMarcel Moolenaar 			*namep = (const char*)lval.name;
18137224cd3SMarcel Moolenaar 		if (valp != NULL)
18237224cd3SMarcel Moolenaar 			*valp = (db_expr_t)lval.value;
18337224cd3SMarcel Moolenaar 	} else {
18437224cd3SMarcel Moolenaar 		if (namep != NULL)
185*40b664f6SBrandon Bergren 			*namep = (const char *)DB_PRIVATE(symtab)->strtab +
18637224cd3SMarcel Moolenaar 			    ((const Elf_Sym *)sym)->st_name;
18737224cd3SMarcel Moolenaar 		if (valp != NULL)
188*40b664f6SBrandon Bergren 			*valp = (db_expr_t)((const Elf_Sym *)sym)->st_value +
189*40b664f6SBrandon Bergren 			    DB_PRIVATE(symtab)->relbase;
19037224cd3SMarcel Moolenaar 	}
19137224cd3SMarcel Moolenaar }
19237224cd3SMarcel Moolenaar 
193c98a2727SRoger Pau Monné int
194*40b664f6SBrandon Bergren db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end,
195*40b664f6SBrandon Bergren     vm_offset_t relbase)
196c98a2727SRoger Pau Monné {
197c98a2727SRoger Pau Monné 	Elf_Size strsz;
198c98a2727SRoger Pau Monné 
199c98a2727SRoger Pau Monné 	if (ksym_end > ksym_start && ksym_start != 0) {
200c98a2727SRoger Pau Monné 		ksymtab = ksym_start;
201c98a2727SRoger Pau Monné 		ksymtab_size = *(Elf_Size*)ksymtab;
202c98a2727SRoger Pau Monné 		ksymtab += sizeof(Elf_Size);
203c98a2727SRoger Pau Monné 		kstrtab = ksymtab + ksymtab_size;
204c98a2727SRoger Pau Monné 		strsz = *(Elf_Size*)kstrtab;
205c98a2727SRoger Pau Monné 		kstrtab += sizeof(Elf_Size);
206*40b664f6SBrandon Bergren 		ksymtab_relbase = relbase;
207c98a2727SRoger Pau Monné 		if (kstrtab + strsz > ksym_end) {
208c98a2727SRoger Pau Monné 			/* Sizes doesn't match, unset everything. */
209*40b664f6SBrandon Bergren 			ksymtab = ksymtab_size = kstrtab = ksymtab_relbase
210*40b664f6SBrandon Bergren 			    = 0;
211c98a2727SRoger Pau Monné 		}
212c98a2727SRoger Pau Monné 	}
213c98a2727SRoger Pau Monné 
214c98a2727SRoger Pau Monné 	if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0)
215c98a2727SRoger Pau Monné 		return (-1);
216c98a2727SRoger Pau Monné 
217c98a2727SRoger Pau Monné 	return (0);
218c98a2727SRoger Pau Monné }
219c98a2727SRoger Pau Monné 
22037224cd3SMarcel Moolenaar static int
22137224cd3SMarcel Moolenaar db_init(void)
22237224cd3SMarcel Moolenaar {
22337224cd3SMarcel Moolenaar 
22493d4804bSJohn Baldwin 	db_command_init();
225c98a2727SRoger Pau Monné 
226c98a2727SRoger Pau Monné 	if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) {
227*40b664f6SBrandon Bergren 		ksymtab_private.strtab = (char *)kstrtab;
228*40b664f6SBrandon Bergren 		ksymtab_private.relbase = ksymtab_relbase;
229c98a2727SRoger Pau Monné 		db_add_symbol_table((char *)ksymtab,
230*40b664f6SBrandon Bergren 		    (char *)(ksymtab + ksymtab_size), "elf", (char *)&ksymtab_private);
23137224cd3SMarcel Moolenaar 	}
23237224cd3SMarcel Moolenaar 	db_add_symbol_table(NULL, NULL, "kld", NULL);
23337224cd3SMarcel Moolenaar 	return (1);	/* We're the default debugger. */
23437224cd3SMarcel Moolenaar }
23537224cd3SMarcel Moolenaar 
23637224cd3SMarcel Moolenaar static int
23737224cd3SMarcel Moolenaar db_trap(int type, int code)
23837224cd3SMarcel Moolenaar {
23937224cd3SMarcel Moolenaar 	jmp_buf jb;
24037224cd3SMarcel Moolenaar 	void *prev_jb;
241cd508278SPedro F. Giffuni 	bool bkpt, watchpt;
242c9b0cc3bSRobert Watson 	const char *why;
24337224cd3SMarcel Moolenaar 
24437224cd3SMarcel Moolenaar 	/*
24537224cd3SMarcel Moolenaar 	 * Don't handle the trap if the console is unavailable (i.e. it
24637224cd3SMarcel Moolenaar 	 * is in graphics mode).
24737224cd3SMarcel Moolenaar 	 */
24837224cd3SMarcel Moolenaar 	if (cnunavailable())
24937224cd3SMarcel Moolenaar 		return (0);
25037224cd3SMarcel Moolenaar 
2515c48342fSBruce Evans 	if (db_stop_at_pc(type, code, &bkpt, &watchpt)) {
25237224cd3SMarcel Moolenaar 		if (db_inst_count) {
25337224cd3SMarcel Moolenaar 			db_printf("After %d instructions (%d loads, %d stores),\n",
25437224cd3SMarcel Moolenaar 			    db_inst_count, db_load_count, db_store_count);
25537224cd3SMarcel Moolenaar 		}
25637224cd3SMarcel Moolenaar 		prev_jb = kdb_jmpbuf(jb);
25737224cd3SMarcel Moolenaar 		if (setjmp(jb) == 0) {
25837224cd3SMarcel Moolenaar 			db_dot = PC_REGS();
25937224cd3SMarcel Moolenaar 			db_print_thread();
26037224cd3SMarcel Moolenaar 			if (bkpt)
26137224cd3SMarcel Moolenaar 				db_printf("Breakpoint at\t");
26237224cd3SMarcel Moolenaar 			else if (watchpt)
26337224cd3SMarcel Moolenaar 				db_printf("Watchpoint at\t");
26437224cd3SMarcel Moolenaar 			else
26537224cd3SMarcel Moolenaar 				db_printf("Stopped at\t");
26637224cd3SMarcel Moolenaar 			db_print_loc_and_inst(db_dot);
26737224cd3SMarcel Moolenaar 		}
268c9b0cc3bSRobert Watson 		why = kdb_why;
269c9b0cc3bSRobert Watson 		db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown");
27037224cd3SMarcel Moolenaar 		db_command_loop();
27137224cd3SMarcel Moolenaar 		(void)kdb_jmpbuf(prev_jb);
27237224cd3SMarcel Moolenaar 	}
27337224cd3SMarcel Moolenaar 
27437224cd3SMarcel Moolenaar 	db_restart_at_pc(watchpt);
27537224cd3SMarcel Moolenaar 
27637224cd3SMarcel Moolenaar 	return (1);
27737224cd3SMarcel Moolenaar }
278a0396f27SKonstantin Belousov 
279a0396f27SKonstantin Belousov static void
280a0396f27SKonstantin Belousov db_trace_self_wrapper(void)
281a0396f27SKonstantin Belousov {
282a0396f27SKonstantin Belousov 	jmp_buf jb;
283a0396f27SKonstantin Belousov 	void *prev_jb;
284a0396f27SKonstantin Belousov 
285a0396f27SKonstantin Belousov 	prev_jb = kdb_jmpbuf(jb);
286a0396f27SKonstantin Belousov 	if (setjmp(jb) == 0)
287a0396f27SKonstantin Belousov 		db_trace_self();
288a0396f27SKonstantin Belousov 	(void)kdb_jmpbuf(prev_jb);
289a0396f27SKonstantin Belousov }
29028926c57SJohn Baldwin 
29128926c57SJohn Baldwin static void
29228926c57SJohn Baldwin db_trace_thread_wrapper(struct thread *td)
29328926c57SJohn Baldwin {
29428926c57SJohn Baldwin 	jmp_buf jb;
29528926c57SJohn Baldwin 	void *prev_jb;
29628926c57SJohn Baldwin 
29728926c57SJohn Baldwin 	prev_jb = kdb_jmpbuf(jb);
29828926c57SJohn Baldwin 	if (setjmp(jb) == 0)
29928926c57SJohn Baldwin 		db_trace_thread(td, -1);
30028926c57SJohn Baldwin 	(void)kdb_jmpbuf(prev_jb);
30128926c57SJohn Baldwin }
302