1 /* $NetBSD: x86.c,v 1.5 2026/08/17 18:58:56 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: x86.c,v 1.5 2026/08/17 18:58:56 riastradh Exp $"); 35 #endif /* not lint */ 36 37 #include <ddb/ddb.h> 38 39 #include <kvm.h> 40 #include <nlist.h> 41 #include <err.h> 42 #include <stdlib.h> 43 44 #include <machine/cpu.h> 45 #include <machine/frame.h> 46 #include <machine/pcb.h> 47 #include <x86/db_machdep.h> 48 49 #include "extern.h" 50 51 #ifdef VM_MIN_KERNEL_ADDRESS_DEFAULT 52 vaddr_t vm_min_kernel_address = VM_MIN_KERNEL_ADDRESS_DEFAULT; 53 #endif 54 55 static struct nlist nl[] = { 56 { .n_name = "_dumppcb" }, 57 { .n_name = "cpu_infos" }, 58 { .n_name = "cpu_info_primary" }, 59 { .n_name = "ncpu" }, 60 #ifdef VM_MIN_KERNEL_ADDRESS_DEFAULT 61 { .n_name = "vm_min_kernel_address" }, 62 #endif 63 { .n_name = NULL }, 64 }; 65 66 struct pcb pcb; 67 struct cpu_info **cpu_infos; 68 struct cpu_info *cpu_info_primary_p; 69 int ncpu; 70 71 void 72 db_mach_init(kvm_t *kd) 73 { 74 75 if (kvm_nlist(kd, nl) == -1) { 76 errx(EXIT_FAILURE, "kvm_nlist: %s", kvm_geterr(kd)); 77 } 78 if ((size_t)kvm_read(kd, nl[0].n_value, &pcb, sizeof(pcb)) != 79 sizeof(pcb)) { 80 errx(EXIT_FAILURE, "cannot read dumppcb: %s", kvm_geterr(kd)); 81 } 82 if ((size_t)kvm_read(kd, nl[1].n_value, &cpu_infos, sizeof(cpu_infos)) 83 != sizeof(cpu_infos)) { 84 errx(EXIT_FAILURE, "cannot read cpu_infos: %s", kvm_geterr(kd)); 85 } 86 cpu_info_primary_p = (void *)(uintptr_t)nl[2].n_value; 87 if ((size_t)kvm_read(kd, nl[3].n_value, &ncpu, sizeof(ncpu)) != 88 sizeof(ncpu)) { 89 errx(EXIT_FAILURE, "cannot read ncpu: %s", kvm_geterr(kd)); 90 } 91 #ifdef VM_MIN_KERNEL_ADDRESS_DEFAULT 92 if ((size_t)kvm_read(kd, nl[4].n_value, &vm_min_kernel_address, 93 sizeof(vm_min_kernel_address)) != sizeof(vm_min_kernel_address)) { 94 errx(EXIT_FAILURE, "cannot read vm_min_kernel_address: %s", 95 kvm_geterr(kd)); 96 } 97 #endif 98 ddb_regs.tf_sp = pcb.pcb_sp; 99 ddb_regs.tf_bp = pcb.pcb_bp; 100 if (ddb_regs.tf_bp != 0 && ddb_regs.tf_sp != 0) { 101 printf("Backtrace from time of crash is available.\n"); 102 } 103 } 104 105 void db_mach_cpu(db_expr_t, bool, db_expr_t, const char *); 106 107 const struct db_command db_machine_command_table[] = { 108 { DDB_ADD_CMD("cpu", db_mach_cpu, 0, 109 "switch to another cpu", "cpu-no", NULL) }, 110 { DDB_END_CMD }, 111 }; 112 113 static struct cpu_info * 114 cpu_lookup(unsigned i) 115 { 116 struct cpu_info *ci; 117 118 if (cpu_infos == NULL) { 119 if (i != 0) 120 return NULL; 121 return cpu_info_primary_p; 122 } 123 if (ncpu < 0 || i >= (unsigned)ncpu) 124 return NULL; 125 db_read_bytes((db_addr_t)(uintptr_t)&cpu_infos[i], 126 sizeof(ci), (char *)&ci); 127 return ci; 128 } 129 130 /* 131 * XXX sync with sys/arch/amd64/amd64/db_interface.c 132 * XXX sync with sys/arch/i386/i386/db_interface.c 133 */ 134 void 135 db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 136 { 137 struct cpu_info *ci; 138 db_regs_t *regs; 139 140 #if 0 141 if (!have_addr) { 142 cpu_debug_dump(); 143 return; 144 } 145 #endif 146 147 if (addr < 0) { 148 db_printf("%ld: CPU out of range\n", addr); 149 return; 150 } 151 ci = cpu_lookup(addr); 152 if (ci == NULL) { 153 db_printf("CPU %ld not configured\n", addr); 154 return; 155 } 156 #if 0 157 if (ci != curcpu()) { 158 if (!(ci->ci_flags & CPUF_PAUSE)) { 159 db_printf("CPU %ld not paused\n", addr); 160 return; 161 } 162 } 163 #endif 164 db_read_bytes((db_addr_t)(uintptr_t)&ci->ci_ddb_regs, 165 sizeof(regs), (char *)®s); 166 if (regs == NULL) { 167 db_printf("CPU %ld has no saved regs\n", addr); 168 return; 169 } 170 db_printf("using CPU %ld", addr); 171 db_read_bytes((db_addr_t)(uintptr_t)®s->tf_sp, 172 sizeof(ddb_regs.tf_sp), (char *)&ddb_regs.tf_sp); 173 db_read_bytes((db_addr_t)(uintptr_t)®s->tf_bp, 174 sizeof(ddb_regs.tf_bp), (char *)&ddb_regs.tf_bp); 175 } 176