4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2018 Joyent, Inc.
29 * isa-dependent portions of the kmdb target
33 #include <kmdb/kmdb_kdi.h>
34 #include <kmdb/kmdb_asmutil.h>
35 #include <mdb/mdb_debug.h>
36 #include <mdb/mdb_err.h>
37 #include <mdb/mdb_list.h>
38 #include <mdb/mdb_target_impl.h>
39 #include <mdb/mdb_isautil.h>
40 #include <mdb/mdb_kreg_impl.h>
43 #include <sys/types.h>
44 #include <sys/frame.h>
46 #include <sys/bitmap.h>
47 #include <sys/pci_impl.h>
49 /* Higher than the highest trap number for which we have a defined specifier */
50 #define KMT_MAXTRAPNO 0x20
52 #define IOPORTLIMIT 0xffff /* XXX find a new home for this */
65 kmt_step_out_validate(mdb_tgt_t
*t
, uintptr_t pc
)
67 kmt_data_t
*kmt
= t
->t_data
;
70 for (i
= 0; i
< sizeof (kmt
->kmt_intrsyms
) / sizeof (GElf_Sym
); i
++) {
71 GElf_Sym
*sym
= (GElf_Sym
*)&kmt
->kmt_intrsyms
+ i
;
73 if (pc
>= sym
->st_value
&& pc
< sym
->st_value
+ sym
->st_size
)
81 * Determine the return address for the current frame.
84 kmt_step_out(mdb_tgt_t
*t
, uintptr_t *p
)
89 (void) kmdb_dpi_get_register("pc", &pc
);
90 (void) kmdb_dpi_get_register("sp", &sp
);
91 (void) kmdb_dpi_get_register("fp", &fp
);
93 if (mdb_tgt_vread(t
, &instr
, sizeof (mdb_instr_t
), pc
) !=
95 return (-1); /* errno is set for us */
97 if (!kmt_step_out_validate(t
, pc
))
98 return (set_errno(EMDB_TGTNOTSUP
));
100 return (mdb_isa_step_out(t
, p
, pc
, fp
, sp
, instr
));
104 * Return the address of the next instruction following a call, or return -1
105 * and set errno to EAGAIN if the target should just single-step.
108 kmt_next(mdb_tgt_t
*t
, uintptr_t *p
)
113 (void) kmdb_dpi_get_register("pc", &pc
);
115 if (mdb_tgt_vread(t
, &instr
, sizeof (mdb_instr_t
), pc
) !=
116 sizeof (mdb_instr_t
))
117 return (-1); /* errno is set for us */
119 return (mdb_isa_next(t
, p
, pc
, instr
));
124 kmt_stack_common(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
,
125 int cpuid
, mdb_tgt_stack_f
*func
)
127 const mdb_tgt_gregset_t
*grp
= NULL
;
128 mdb_tgt_gregset_t gregs
;
129 void *arg
= (void *)(uintptr_t)mdb
.m_nargs
;
131 if (flags
& DCMD_ADDRSPEC
) {
132 bzero(&gregs
, sizeof (gregs
));
133 gregs
.kregs
[KREG_FP
] = addr
;
136 grp
= kmdb_dpi_get_gregs(cpuid
);
139 warn("failed to retrieve registers for cpu %d", cpuid
);
144 if (argv
->a_type
== MDB_TYPE_CHAR
|| argc
> 1)
147 if (argv
->a_type
== MDB_TYPE_STRING
)
148 arg
= (void *)(uintptr_t)mdb_strtoull(argv
->a_un
.a_str
);
150 arg
= (void *)(uintptr_t)argv
->a_un
.a_val
;
153 (void) mdb_isa_kvm_stack_iter(mdb
.m_target
, grp
, func
, arg
);
159 kmt_cpustack(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
,
160 int cpuid
, int verbose
)
162 return (kmt_stack_common(addr
, flags
, argc
, argv
, cpuid
,
163 (verbose
? mdb_isa_kvm_framev
: mdb_isa_kvm_frame
)));
167 kmt_stack(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
169 return (kmt_stack_common(addr
, flags
, argc
, argv
, DPI_MASTER_CPUID
,
174 kmt_stackv(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
176 return (kmt_stack_common(addr
, flags
, argc
, argv
, DPI_MASTER_CPUID
,
177 mdb_isa_kvm_framev
));
181 kmt_stackr(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
183 return (kmt_stack_common(addr
, flags
, argc
, argv
, DPI_MASTER_CPUID
,
184 mdb_isa_kvm_framev
));
189 kmt_printregs(const mdb_tgt_gregset_t
*gregs
)
191 mdb_isa_printregs(gregs
);
194 #define IOCHECK_NOWARN 0
195 #define IOCHECK_WARN 1
198 kmt_io_check(uint64_t nbytes
, uintptr_t addr
, int dowarn
)
200 if (addr
> IOPORTLIMIT
) {
202 warn("port address must be 0-%#x\n", IOPORTLIMIT
);
203 return (set_errno(EINVAL
));
206 if (nbytes
!= 1 && nbytes
!= 2 && nbytes
!= 4) {
208 warn("port access must be 1, 2, or 4 bytes\n");
209 return (set_errno(EINVAL
));
212 if ((addr
& (nbytes
- 1)) != 0) {
214 warn("address for %llu-byte access must be %llu-byte "
215 "aligned\n", (u_longlong_t
)nbytes
,
216 (u_longlong_t
)nbytes
);
218 return (set_errno(EINVAL
));
226 kmt_in_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
231 if (mdb_getopts(argc
, argv
,
232 'L', MDB_OPT_UINT64
, &len
,
239 if (kmt_io_check(len
, addr
, IOCHECK_WARN
) < 0)
242 if (mdb_tgt_ioread(mdb
.m_target
, &buf
, len
, addr
) < 0) {
243 warn("failed to read from port 0x%llx", (u_longlong_t
)addr
);
247 mdb_printf("%x\n", buf
);
253 kmt_numarg(const mdb_arg_t
*arg
)
255 if (arg
->a_type
== MDB_TYPE_STRING
)
256 return (mdb_strtoull(arg
->a_un
.a_str
));
258 return (arg
->a_un
.a_val
);
263 kmt_out_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
268 if (mdb_getopts(argc
, argv
,
269 'L', MDB_OPT_UINT64
, &len
,
277 val
= kmt_numarg(argv
);
279 if (kmt_io_check(len
, addr
, IOCHECK_WARN
) < 0)
282 if (val
> (1ULL << (len
* NBBY
)) - 1) {
283 warn("value is out of range for port size\n");
287 if (mdb_tgt_iowrite(mdb
.m_target
, &val
, len
, addr
) < 0) {
288 warn("failed to write to port %llx", (u_longlong_t
)addr
);
296 kmt_rwmsr(uint32_t addr
, uint64_t *valp
, void (*rw
)(uint32_t, uint64_t *))
298 jmp_buf pcb
, *oldpcb
= NULL
;
300 if (setjmp(pcb
) != 0) {
301 kmdb_dpi_restore_fault_hdlr(oldpcb
);
302 return (-1); /* errno is set for us */
305 oldpcb
= kmdb_dpi_set_fault_hdlr(&pcb
);
307 kmdb_dpi_restore_fault_hdlr(oldpcb
);
314 kmt_rdmsr(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
318 if (!(flags
& DCMD_ADDRSPEC
))
321 if (kmt_rwmsr(addr
, &val
, rdmsr
) < 0) {
322 warn("rdmsr failed");
326 mdb_printf("%llx\n", (u_longlong_t
)val
);
333 kmt_wrmsr(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
337 if (!(flags
& DCMD_ADDRSPEC
) || argc
!= 1)
340 val
= kmt_numarg(argv
);
342 if (kmt_rwmsr(addr
, &val
, wrmsr
)) {
343 warn("wrmsr failed");
352 kmt_write(mdb_tgt_t
*t
, const void *buf
, size_t nbytes
, uintptr_t addr
)
354 if (!(t
->t_flags
& MDB_TGT_F_ALLOWIO
) &&
355 (nbytes
= kmdb_kdi_range_is_nontoxic(addr
, nbytes
, 1)) == 0)
356 return (set_errno(EMDB_NOMAP
));
359 * No writes to user space are allowed. If we were to allow it, we'd
360 * be in the unfortunate situation where kmdb could place a breakpoint
361 * on a userspace executable page; this dirty page would end up being
362 * flushed back to disk, incurring sadness when it's next executed.
363 * Besides, we can't allow trapping in from userspace anyway.
365 if (addr
< kmdb_kdi_get_userlimit())
366 return (set_errno(EMDB_TGTNOTSUP
));
368 return (kmt_rw(t
, (void *)buf
, nbytes
, addr
, kmt_writer
));
373 kmt_iorw(mdb_tgt_t
*t
, void *buf
, size_t nbytes
, uint64_t addr
,
374 void (*iorw
)(void *, size_t, uintptr_t))
376 jmp_buf pcb
, *oldpcb
= NULL
;
378 if (kmt_io_check(nbytes
, addr
, IOCHECK_NOWARN
) < 0)
379 return (-1); /* errno is set for us */
381 if (setjmp(pcb
) != 0) {
382 kmdb_dpi_restore_fault_hdlr(oldpcb
);
383 return (-1); /* errno is set for us */
386 oldpcb
= kmdb_dpi_set_fault_hdlr(&pcb
);
387 iorw(buf
, nbytes
, addr
);
388 kmdb_dpi_restore_fault_hdlr(oldpcb
);
395 kmt_ioread(mdb_tgt_t
*t
, void *buf
, size_t nbytes
, uintptr_t addr
)
397 return (kmt_iorw(t
, buf
, nbytes
, addr
, kmt_in
));
402 kmt_iowrite(mdb_tgt_t
*t
, const void *buf
, size_t nbytes
, uintptr_t addr
)
404 return (kmt_iorw(t
, (void *)buf
, nbytes
, addr
, kmt_out
));
408 kmt_pcicfg_common(uintptr_t off
, uint32_t *valp
, const mdb_arg_t
*argv
,
409 void (*rw
)(void *, size_t, uintptr_t))
411 uint32_t bus
, dev
, func
;
414 bus
= kmt_numarg(&argv
[0]);
415 dev
= kmt_numarg(&argv
[1]);
416 func
= kmt_numarg(&argv
[2]);
418 if ((bus
& 0xffff) != bus
) {
419 warn("invalid bus number (must be 0-0xffff)\n");
423 if ((dev
& 0x1f) != dev
) {
424 warn("invalid device number (must be 0-0x1f)\n");
428 if ((func
& 0x7) != func
) {
429 warn("invalid function number (must be 0-7)\n");
433 if ((off
& 0xfc) != off
) {
434 warn("invalid register number (must be 0-0xff, and 4-byte "
439 addr
= PCI_CADDR1(bus
, dev
, func
, off
);
441 if (kmt_iowrite(mdb
.m_target
, &addr
, sizeof (addr
), PCI_CONFADD
) !=
443 warn("write of PCI_CONFADD failed");
447 if (kmt_iorw(mdb
.m_target
, valp
, sizeof (*valp
), PCI_CONFDATA
, rw
) !=
449 warn("access to PCI_CONFDATA failed");
458 kmt_rdpcicfg(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
462 if (argc
!= 3 || !(flags
& DCMD_ADDRSPEC
))
465 if (kmt_pcicfg_common(addr
, &val
, argv
, kmt_in
) != DCMD_OK
)
468 mdb_printf("%llx\n", (u_longlong_t
)val
);
475 kmt_wrpcicfg(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
479 if (argc
!= 4 || !(flags
& DCMD_ADDRSPEC
))
482 val
= (uint32_t)kmt_numarg(&argv
[3]);
484 if (kmt_pcicfg_common(addr
, &val
, argv
, kmt_out
) != DCMD_OK
)
491 kmt_trapname(int trapnum
)
493 static char trapname
[11];
497 return ("division by zero (#de) trap");
499 return ("single-step (#db) trap");
503 return ("breakpoint (#bp) trap");
505 return ("illegal instruction (#ud) trap");
507 return ("segment not present (#np) trap");
509 return ("stack (#ss) trap");
511 return ("general protection (#gp) trap");
513 return ("page fault (#pf) trap");
515 return ("alignment check (#ac) trap");
517 return ("machine check (#mc) trap");
519 return ("SSE/SSE2 (#xm) trap");
521 return ("debugger entry trap");
523 (void) mdb_snprintf(trapname
, sizeof (trapname
), "trap %#x",
530 kmt_init_isadep(mdb_tgt_t
*t
)
532 kmt_data_t
*kmt
= t
->t_data
;
534 kmt
->kmt_rds
= mdb_isa_kregs
;
536 kmt
->kmt_trapmax
= KMT_MAXTRAPNO
;
537 kmt
->kmt_trapmap
= mdb_zalloc(BT_SIZEOFMAP(kmt
->kmt_trapmax
), UM_SLEEP
);
539 /* Traps for which we want to provide an explicit message */
540 (void) mdb_tgt_add_fault(t
, T_ZERODIV
, MDB_TGT_SPEC_INTERNAL
,
542 (void) mdb_tgt_add_fault(t
, T_ILLINST
, MDB_TGT_SPEC_INTERNAL
,
544 (void) mdb_tgt_add_fault(t
, T_SEGFLT
, MDB_TGT_SPEC_INTERNAL
,
546 (void) mdb_tgt_add_fault(t
, T_STKFLT
, MDB_TGT_SPEC_INTERNAL
,
548 (void) mdb_tgt_add_fault(t
, T_GPFLT
, MDB_TGT_SPEC_INTERNAL
,
550 (void) mdb_tgt_add_fault(t
, T_PGFLT
, MDB_TGT_SPEC_INTERNAL
,
552 (void) mdb_tgt_add_fault(t
, T_ALIGNMENT
, MDB_TGT_SPEC_INTERNAL
,
554 (void) mdb_tgt_add_fault(t
, T_MCE
, MDB_TGT_SPEC_INTERNAL
,
556 (void) mdb_tgt_add_fault(t
, T_SIMDFPE
, MDB_TGT_SPEC_INTERNAL
,
560 * Traps which will be handled elsewhere, and which therefore don't
561 * need the trap-based message.
563 BT_SET(kmt
->kmt_trapmap
, T_SGLSTP
);
564 BT_SET(kmt
->kmt_trapmap
, T_BPTFLT
);
565 BT_SET(kmt
->kmt_trapmap
, T_DBGENTR
);
567 /* Catch-all for traps not explicitly listed here */
568 (void) mdb_tgt_add_fault(t
, KMT_TRAP_NOTENUM
, MDB_TGT_SPEC_INTERNAL
,
573 kmt_startup_isadep(mdb_tgt_t
*t
)
575 kmt_data_t
*kmt
= t
->t_data
;
578 * The stack trace and ::step out code need to detect "interrupt"
579 * frames. The heuristic they use to detect said frames requires the
580 * addresses of routines that can generate them.
582 (void) mdb_tgt_lookup_by_name(t
, MDB_TGT_OBJ_EXEC
,
583 "cmnint", &kmt
->kmt_intrsyms
._kmt_cmnint
, NULL
);
584 (void) mdb_tgt_lookup_by_name(t
, MDB_TGT_OBJ_EXEC
,
585 "cmntrap", &kmt
->kmt_intrsyms
._kmt_cmntrap
, NULL
);
586 (void) mdb_tgt_lookup_by_name(t
, MDB_TGT_OBJ_EXEC
,
587 "sys_sysenter", &kmt
->kmt_intrsyms
._kmt_sysenter
, NULL
);
588 (void) mdb_tgt_lookup_by_name(t
, MDB_TGT_OBJ_EXEC
,
589 "brand_sys_sysenter", &kmt
->kmt_intrsyms
._kmt_brand_sysenter
, NULL
);
591 (void) mdb_tgt_lookup_by_name(t
, MDB_TGT_OBJ_EXEC
,
592 "sys_syscall", &kmt
->kmt_intrsyms
._kmt_syscall
, NULL
);
593 (void) mdb_tgt_lookup_by_name(t
, MDB_TGT_OBJ_EXEC
,
594 "brand_sys_syscall", &kmt
->kmt_intrsyms
._kmt_brand_syscall
, NULL
);