xref: /titanic_52/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * isa-dependent portions of the kmdb target
31  */
32 
33 #include <kmdb/kvm.h>
34 #include <kmdb/kvm_cpu.h>
35 #include <kmdb/kmdb_kdi.h>
36 #include <kmdb/kmdb_asmutil.h>
37 #include <mdb/mdb_debug.h>
38 #include <mdb/mdb_err.h>
39 #include <mdb/mdb_list.h>
40 #include <mdb/mdb_target_impl.h>
41 #include <mdb/mdb_isautil.h>
42 #include <mdb/mdb_kreg_impl.h>
43 #include <mdb/mdb.h>
44 
45 #include <sys/types.h>
46 #include <sys/frame.h>
47 #include <sys/trap.h>
48 #include <sys/bitmap.h>
49 
50 /* Higher than the highest trap number for which we have a defined specifier */
51 #define	KMT_MAXTRAPNO	0x20
52 
53 #define	IOPORTLIMIT	0xffff	/* XXX find a new home for this */
54 
55 const char *
56 kmt_def_dismode(void)
57 {
58 #ifdef	__amd64
59 	return ("amd64");
60 #else
61 	return ("ia32");
62 #endif
63 }
64 
65 int
66 kmt_step_out_validate(mdb_tgt_t *t, uintptr_t pc)
67 {
68 	kmt_data_t *kmt = t->t_data;
69 	int i;
70 
71 	for (i = 0; i < sizeof (kmt->kmt_intrsyms) / sizeof (GElf_Sym); i++) {
72 		GElf_Sym *sym = (GElf_Sym *)&kmt->kmt_intrsyms + i;
73 
74 		if (pc >= sym->st_value && pc < sym->st_value + sym->st_size)
75 			return (0);
76 	}
77 
78 	return (1);
79 }
80 
81 /*
82  * Determine the return address for the current frame.
83  */
84 int
85 kmt_step_out(mdb_tgt_t *t, uintptr_t *p)
86 {
87 	mdb_instr_t instr;
88 	kreg_t pc, sp, fp;
89 
90 	(void) kmdb_dpi_get_register("pc", &pc);
91 	(void) kmdb_dpi_get_register("sp", &sp);
92 	(void) kmdb_dpi_get_register("fp", &fp);
93 
94 	if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) !=
95 	    sizeof (mdb_instr_t))
96 		return (-1); /* errno is set for us */
97 
98 	if (!kmt_step_out_validate(t, pc))
99 		return (set_errno(EMDB_TGTNOTSUP));
100 
101 	return (mdb_isa_step_out(t, p, pc, fp, sp, instr));
102 }
103 
104 int
105 kmt_step_branch(mdb_tgt_t *t)
106 {
107 	kmt_data_t *kmt = t->t_data;
108 
109 	return (kmt_cpu_step_branch(t, kmt->kmt_cpu));
110 }
111 
112 /*
113  * Return the address of the next instruction following a call, or return -1
114  * and set errno to EAGAIN if the target should just single-step.
115  */
116 int
117 kmt_next(mdb_tgt_t *t, uintptr_t *p)
118 {
119 	kreg_t pc;
120 	mdb_instr_t instr;
121 
122 	(void) kmdb_dpi_get_register("pc", &pc);
123 
124 	if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) !=
125 	    sizeof (mdb_instr_t))
126 		return (-1); /* errno is set for us */
127 
128 	return (mdb_isa_next(t, p, pc, instr));
129 }
130 
131 /*
132  * Return a flag indicating if the specified %eip is likely to have an
133  * interrupt frame on the stack.  We do this by comparing the address to the
134  * range of addresses spanned by several well-known routines, and looking
135  * to see if the next and previous %ebp values are "far" apart.  Sigh.
136  */
137 int
138 mdb_kvm_intrframe(mdb_tgt_t *t, uintptr_t pc, uintptr_t fp,
139     uintptr_t prevfp)
140 {
141 	kmt_data_t *kmt = t->t_data;
142 	const size_t dist = 0x800 * sizeof (uintptr_t);
143 
144 	return ((pc >= kmt->kmt_cmnint.st_value &&
145 	    (pc < kmt->kmt_cmnint.st_value + kmt->kmt_cmnint.st_size)) ||
146 	    (pc >= kmt->kmt_cmntrap.st_value &&
147 	    (pc < kmt->kmt_cmntrap.st_value + kmt->kmt_cmntrap.st_size)) ||
148 	    (fp >= prevfp + dist) || (fp <= prevfp - dist));
149 }
150 
151 /*ARGSUSED*/
152 static int
153 kmt_stack_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
154     int cpuid, mdb_tgt_stack_f *func)
155 {
156 	const mdb_tgt_gregset_t *grp = NULL;
157 	mdb_tgt_gregset_t gregs;
158 	void *arg = (void *)(uintptr_t)mdb.m_nargs;
159 
160 	if (flags & DCMD_ADDRSPEC) {
161 		bzero(&gregs, sizeof (gregs));
162 		gregs.kregs[KREG_FP] = addr;
163 		grp = &gregs;
164 	} else
165 		grp = kmdb_dpi_get_gregs(cpuid);
166 
167 	if (argc != 0) {
168 		if (argv->a_type == MDB_TYPE_CHAR || argc > 1)
169 			return (DCMD_USAGE);
170 
171 		if (argv->a_type == MDB_TYPE_STRING)
172 			arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str);
173 		else
174 			arg = (void *)(uintptr_t)argv->a_un.a_val;
175 	}
176 
177 	(void) mdb_isa_kvm_stack_iter(mdb.m_target, grp, func, arg);
178 
179 	return (DCMD_OK);
180 }
181 
182 int
183 kmt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
184     int cpuid, int verbose)
185 {
186 	return (kmt_stack_common(addr, flags, argc, argv, cpuid,
187 	    (verbose ? mdb_isa_kvm_framev : mdb_isa_kvm_frame)));
188 }
189 
190 int
191 kmt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
192 {
193 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
194 	    mdb_isa_kvm_frame));
195 }
196 
197 int
198 kmt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
199 {
200 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
201 	    mdb_isa_kvm_framev));
202 }
203 
204 int
205 kmt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
206 {
207 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
208 	    mdb_isa_kvm_framev));
209 }
210 
211 /*ARGSUSED*/
212 void
213 kmt_printregs(const mdb_tgt_gregset_t *gregs)
214 {
215 	mdb_isa_printregs(gregs);
216 }
217 
218 #define	IOCHECK_NOWARN	0
219 #define	IOCHECK_WARN	1
220 
221 static int
222 kmt_io_check(uint64_t nbytes, uintptr_t addr, int dowarn)
223 {
224 	if (addr > IOPORTLIMIT) {
225 		if (dowarn)
226 			warn("port address must be 0-%#x\n", IOPORTLIMIT);
227 		return (set_errno(EINVAL));
228 	}
229 
230 	if (nbytes != 1 && nbytes != 2 && nbytes != 4) {
231 		if (dowarn)
232 			warn("port access must be 1, 2, or 4 bytes\n");
233 		return (set_errno(EINVAL));
234 	}
235 
236 	if ((addr & (nbytes - 1)) != 0) {
237 		if (dowarn) {
238 			warn("address for %llu-byte access must be %llu-byte "
239 			    "aligned\n", (u_longlong_t)nbytes,
240 			    (u_longlong_t)nbytes);
241 		}
242 		return (set_errno(EINVAL));
243 	}
244 
245 	return (0);
246 }
247 
248 /*ARGSUSED1*/
249 int
250 kmt_in_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
251 {
252 	uint64_t len = 0;
253 	uint32_t buf;
254 
255 	if (mdb_getopts(argc, argv,
256 	    'L', MDB_OPT_UINT64, &len,
257 	    NULL) != argc)
258 		return (DCMD_USAGE);
259 
260 	if (len == 0)
261 		len = mdb.m_dcount;
262 
263 	if (kmt_io_check(len, addr, IOCHECK_WARN) < 0)
264 		return (DCMD_ERR);
265 
266 	if (mdb_tgt_ioread(mdb.m_target, &buf, len, addr) < 0) {
267 		warn("failed to read from port 0x%llx", (u_longlong_t)addr);
268 		return (DCMD_ERR);
269 	}
270 
271 	mdb_printf("%x\n", buf);
272 
273 	return (DCMD_OK);
274 }
275 
276 /*ARGSUSED1*/
277 int
278 kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
279 {
280 	uint64_t len = 0;
281 	uint64_t val;
282 
283 	if (mdb_getopts(argc, argv,
284 	    'L', MDB_OPT_UINT64, &len,
285 	    NULL) != argc - 1)
286 		return (DCMD_USAGE);
287 
288 	if (len == 0)
289 		len = mdb.m_dcount;
290 
291 	argv += argc - 1;
292 	if (argv->a_type == MDB_TYPE_STRING)
293 		val = mdb_strtoull(argv->a_un.a_str);
294 	else
295 		val = argv->a_un.a_val;
296 
297 	if (kmt_io_check(len, addr, IOCHECK_WARN) < 0)
298 		return (DCMD_ERR);
299 
300 	if (val > (1ULL << (len * NBBY)) - 1) {
301 		warn("value is out of range for port size\n");
302 		return (DCMD_ERR);
303 	}
304 
305 	if (mdb_tgt_iowrite(mdb.m_target, &val, len, addr) < 0) {
306 		warn("failed to write to port %llx", (u_longlong_t)addr);
307 		return (DCMD_ERR);
308 	}
309 
310 	return (DCMD_OK);
311 }
312 
313 static int
314 kmt_rwmsr(uint32_t addr, uint64_t *valp, void (*rw)(uint32_t, uint64_t *))
315 {
316 	jmp_buf pcb, *oldpcb = NULL;
317 
318 	if (setjmp(pcb) != 0) {
319 		kmdb_dpi_restore_fault_hdlr(oldpcb);
320 		return (-1); /* errno is set for us */
321 	}
322 
323 	oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
324 	rw(addr, valp);
325 	kmdb_dpi_restore_fault_hdlr(oldpcb);
326 
327 	return (0);
328 }
329 
330 /*ARGSUSED*/
331 int
332 kmt_rdmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
333 {
334 	uint64_t val;
335 
336 	if (!(flags & DCMD_ADDRSPEC))
337 		return (DCMD_USAGE);
338 
339 	if (kmt_rwmsr(addr, &val, rdmsr) < 0) {
340 		warn("rdmsr failed");
341 		return (DCMD_ERR);
342 	}
343 
344 	mdb_printf("%llx\n", (u_longlong_t)val);
345 
346 	return (DCMD_OK);
347 }
348 
349 /*ARGSUSED*/
350 int
351 kmt_wrmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
352 {
353 	uint64_t val;
354 
355 	if (!(flags & DCMD_ADDRSPEC) || argc != 1)
356 		return (DCMD_USAGE);
357 
358 	if (argv->a_type == MDB_TYPE_STRING)
359 		val = mdb_strtoull(argv->a_un.a_str);
360 	else
361 		val = argv->a_un.a_val;
362 
363 	if (kmt_rwmsr(addr, &val, wrmsr)) {
364 		warn("wrmsr failed");
365 		return (DCMD_ERR);
366 	}
367 
368 	return (DCMD_OK);
369 }
370 
371 int
372 kmt_msr_validate(const kmdb_msr_t *msr)
373 {
374 	uint64_t val;
375 
376 	for (/* */; msr->msr_num != 0; msr++) {
377 		if (kmt_rwmsr(msr->msr_num, &val, rdmsr) < 0)
378 			return (0);
379 	}
380 
381 	return (1);
382 }
383 
384 /*ARGSUSED*/
385 ssize_t
386 kmt_write(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
387 {
388 	if (!(t->t_flags & MDB_TGT_F_ALLOWIO) &&
389 	    (nbytes = kmdb_kdi_range_is_nontoxic(addr, nbytes, 1)) == 0)
390 		return (set_errno(EMDB_NOMAP));
391 
392 	return (kmt_rw(t, (void *)buf, nbytes, addr, kmt_writer));
393 }
394 
395 /*ARGSUSED*/
396 static ssize_t
397 kmt_iorw(mdb_tgt_t *t, void *buf, size_t nbytes, uint64_t addr,
398     void (*iorw)(void *, size_t, uintptr_t))
399 {
400 	jmp_buf pcb, *oldpcb = NULL;
401 
402 	if (kmt_io_check(nbytes, addr, IOCHECK_NOWARN) < 0)
403 		return (-1); /* errno is set for us */
404 
405 	if (setjmp(pcb) != 0) {
406 		kmdb_dpi_restore_fault_hdlr(oldpcb);
407 		return (-1); /* errno is set for us */
408 	}
409 
410 	oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
411 	iorw(buf, nbytes, addr);
412 	kmdb_dpi_restore_fault_hdlr(oldpcb);
413 
414 	return (nbytes);
415 }
416 
417 /*ARGSUSED*/
418 ssize_t
419 kmt_ioread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
420 {
421 	return (kmt_iorw(t, buf, nbytes, addr, kmt_in));
422 }
423 
424 /*ARGSUSED*/
425 ssize_t
426 kmt_iowrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
427 {
428 	return (kmt_iorw(t, (void *)buf, nbytes, addr, kmt_out));
429 }
430 
431 const char *
432 kmt_trapname(int trapnum)
433 {
434 	static char trapname[11];
435 
436 	switch (trapnum) {
437 	case T_ZERODIV:
438 		return ("division by zero (#de) trap");
439 	case T_SGLSTP:
440 		return ("single-step (#db) trap");
441 	case T_NMIFLT:
442 		return ("NMI");
443 	case T_BPTFLT:
444 		return ("breakpoint (#bp) trap");
445 	case T_ILLINST:
446 		return ("illegal instruction (#ud) trap");
447 	case T_SEGFLT:
448 		return ("segment not present (#np) trap");
449 	case T_STKFLT:
450 		return ("stack (#ss) trap");
451 	case T_GPFLT:
452 		return ("general protection (#gp) trap");
453 	case T_PGFLT:
454 		return ("page fault (#pf) trap");
455 	case T_ALIGNMENT:
456 		return ("alignment check (#ac) trap");
457 	case T_MCE:
458 		return ("machine check (#mc) trap");
459 	case T_SIMDFPE:
460 		return ("SSE/SSE2 (#xm) trap");
461 	case T_DBGENTR:
462 		return ("debugger entry trap");
463 	default:
464 		(void) mdb_snprintf(trapname, sizeof (trapname), "trap %#x",
465 		    trapnum);
466 		return (trapname);
467 	}
468 }
469 
470 void
471 kmt_init_isadep(mdb_tgt_t *t)
472 {
473 	kmt_data_t *kmt = t->t_data;
474 
475 	kmt->kmt_rds = mdb_isa_kregs;
476 
477 	kmt->kmt_trapmax = KMT_MAXTRAPNO;
478 	kmt->kmt_trapmap = mdb_zalloc(BT_SIZEOFMAP(kmt->kmt_trapmax), UM_SLEEP);
479 
480 	/* Traps for which we want to provide an explicit message */
481 	(void) mdb_tgt_add_fault(t, T_ZERODIV, MDB_TGT_SPEC_INTERNAL,
482 	    no_se_f, NULL);
483 	(void) mdb_tgt_add_fault(t, T_ILLINST, MDB_TGT_SPEC_INTERNAL,
484 	    no_se_f, NULL);
485 	(void) mdb_tgt_add_fault(t, T_SEGFLT, MDB_TGT_SPEC_INTERNAL,
486 	    no_se_f, NULL);
487 	(void) mdb_tgt_add_fault(t, T_STKFLT, MDB_TGT_SPEC_INTERNAL,
488 	    no_se_f, NULL);
489 	(void) mdb_tgt_add_fault(t, T_GPFLT, MDB_TGT_SPEC_INTERNAL,
490 	    no_se_f, NULL);
491 	(void) mdb_tgt_add_fault(t, T_PGFLT, MDB_TGT_SPEC_INTERNAL,
492 	    no_se_f, NULL);
493 	(void) mdb_tgt_add_fault(t, T_ALIGNMENT, MDB_TGT_SPEC_INTERNAL,
494 	    no_se_f, NULL);
495 	(void) mdb_tgt_add_fault(t, T_MCE, MDB_TGT_SPEC_INTERNAL,
496 	    no_se_f, NULL);
497 	(void) mdb_tgt_add_fault(t, T_SIMDFPE, MDB_TGT_SPEC_INTERNAL,
498 	    no_se_f, NULL);
499 
500 	/*
501 	 * Traps which will be handled elsewhere, and which therefore don't
502 	 * need the trap-based message.
503 	 */
504 	BT_SET(kmt->kmt_trapmap, T_SGLSTP);
505 	BT_SET(kmt->kmt_trapmap, T_BPTFLT);
506 	BT_SET(kmt->kmt_trapmap, T_DBGENTR);
507 
508 	/* Catch-all for traps not explicitly listed here */
509 	(void) mdb_tgt_add_fault(t, KMT_TRAP_NOTENUM, MDB_TGT_SPEC_INTERNAL,
510 	    no_se_f, NULL);
511 }
512 
513 void
514 kmt_startup_isadep(mdb_tgt_t *t)
515 {
516 	kmt_data_t *kmt = t->t_data;
517 
518 	/*
519 	 * The stack trace and ::step out code need to detect "interrupt"
520 	 * frames.  The heuristic they use to detect said frames requires the
521 	 * addresses of routines that can generate them.
522 	 */
523 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
524 	    "cmnint", &kmt->kmt_intrsyms._kmt_cmnint, NULL);
525 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
526 	    "cmntrap", &kmt->kmt_intrsyms._kmt_cmntrap, NULL);
527 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
528 	    "sys_sysenter", &kmt->kmt_intrsyms._kmt_sysenter, NULL);
529 #if defined(__amd64)
530 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
531 	    "sys_syscall", &kmt->kmt_intrsyms._kmt_syscall, NULL);
532 #endif
533 }
534