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