1 /* 2 * Copyright (c) 2004 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: src/gnu/usr.bin/gdb/kgdb/kthr.c,v 1.12 2008/05/01 20:36:48 jhb Exp $ 27 */ 28 29 #include <sys/cdefs.h> 30 31 #include <sys/param.h> 32 #include <machine/globaldata.h> 33 #include <sys/user.h> 34 #include <sys/types.h> 35 #include <sys/signal.h> 36 #include <err.h> 37 #include <inttypes.h> 38 #include <kvm.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #include <defs.h> 44 #include <frame-unwind.h> 45 #include <inferior.h> 46 47 #include "kgdb.h" 48 49 static CORE_ADDR dumppcb; 50 static CORE_ADDR dumptid; 51 52 static struct kthr *first; 53 struct kthr *curkthr; 54 55 #define LIVESYS_DUMPTID 10 56 57 CORE_ADDR 58 kgdb_lookup(const char *sym) 59 { 60 struct nlist nl[2]; 61 62 nl[0].n_name = (char *)(CORE_ADDR)sym; 63 nl[1].n_name = NULL; 64 if (kvm_nlist(kvm, nl) != 0) 65 return (0); 66 return (nl[0].n_value); 67 } 68 69 struct kthr * 70 kgdb_thr_first(void) 71 { 72 return (first); 73 } 74 75 struct kthr * 76 kgdb_thr_init(void) 77 { 78 struct proc p; 79 struct thread td; 80 struct lwp lwp; 81 struct mdglobaldata gd; 82 struct kthr *kt; 83 CORE_ADDR addr, paddr, prvspace, gdptr; 84 int cpu, ncpus; 85 86 while (first != NULL) { 87 kt = first; 88 first = kt->next; 89 free(kt); 90 } 91 92 addr = kgdb_lookup("_ncpus"); 93 if (addr == 0) 94 return (NULL); 95 kvm_read(kvm, addr, &ncpus, sizeof(ncpus)); 96 97 dumppcb = kgdb_lookup("_dumppcb"); 98 if (dumppcb == 0) 99 return (NULL); 100 101 prvspace = kgdb_lookup("_CPU_prvspace"); 102 if (prvspace == 0) 103 return (NULL); 104 105 addr = kgdb_lookup("_dumpthread"); 106 if (addr != 0) { 107 kvm_read(kvm, addr, &dumptid, sizeof(dumptid)); 108 } else { 109 /* 110 * XXX Well then. We don't know who dumped us. 111 * We could do some fancy stack matching, but 112 * I doubt this will work. For now just use 113 * cpu0's curthread. 114 * 115 * Actually we don't even know if we were dumped 116 * or if we are live. Find out by querying "dumping". 117 */ 118 int dumping = 0; 119 120 addr = kgdb_lookup("_dumping"); 121 kvm_read(kvm, addr, &dumping, sizeof(dumping)); 122 if (dumping) { 123 kvm_read(kvm, prvspace + 0, &gdptr, sizeof(gdptr)); 124 kvm_read(kvm, gdptr + 125 offsetof(struct privatespace, mdglobaldata), 126 &gd, sizeof(struct mdglobaldata)); 127 dumptid = (CORE_ADDR)gd.mi.gd_curthread; 128 } else { 129 /* We must be a live system */ 130 dumptid = LIVESYS_DUMPTID; 131 } 132 } 133 134 for (cpu = 0; cpu < ncpus; cpu++) { 135 kvm_read(kvm, prvspace + cpu * sizeof(void *), 136 &gdptr, sizeof(gdptr)); 137 kvm_read(kvm, gdptr + 138 offsetof(struct privatespace, mdglobaldata), 139 &gd, sizeof(struct mdglobaldata)); 140 141 addr = (uintptr_t)TAILQ_FIRST(&gd.mi.gd_tdallq); 142 while (addr != 0) { 143 if (kvm_read(kvm, addr, &td, sizeof(td)) != sizeof(td)) { 144 warnx("kvm_read: %s, while accessing thread", 145 kvm_geterr(kvm)); 146 break; 147 } 148 kt = malloc(sizeof(*kt)); 149 kt->next = first; 150 kt->kaddr = addr; 151 kt->tid = addr; 152 kt->pcb = (kt->tid == dumptid) ? dumppcb : 153 (uintptr_t)td.td_pcb; 154 kt->kstack = (uintptr_t)td.td_kstack; 155 if (td.td_proc != NULL) { 156 paddr = (uintptr_t)td.td_proc; 157 if (kvm_read(kvm, paddr, &p, sizeof(p)) != sizeof(p)) 158 warnx("kvm_read: %s", kvm_geterr(kvm)); 159 kt->pid = p.p_pid; 160 kt->paddr = paddr; 161 addr = (uintptr_t)td.td_lwp; 162 if (kvm_read(kvm, addr, &lwp, sizeof(lwp)) != sizeof(lwp)) 163 warnx("kvm_read: %s", kvm_geterr(kvm)); 164 kt->lwpid = lwp.lwp_tid; 165 } else { 166 /* 167 * XXX for some stupid reason, gdb uses pid == -1 168 * as a marker for "dead" threads, so we have to 169 * hook all kernel threads on a different pid :/ 170 */ 171 kt->pid = -2; 172 kt->paddr = 0; 173 /* 174 * We are a kernel thread, so our td_pcb is 175 * not used anyways. An exception is the 176 * dumping thread. 177 * kt->pcb == 0 is a marker for 178 * "non-dumping kernel thread". 179 */ 180 if (kt->tid != dumptid) 181 kt->pcb = 0; 182 } 183 first = kt; 184 addr = (uintptr_t)TAILQ_NEXT(&td, td_allq); 185 } 186 } 187 188 curkthr = kgdb_thr_lookup_tid(dumptid); 189 if (curkthr == NULL) 190 curkthr = first; 191 return (first); 192 } 193 194 struct kthr * 195 kgdb_thr_lookup_tid(CORE_ADDR tid) 196 { 197 struct kthr *kt; 198 199 kt = first; 200 while (kt != NULL && kt->tid != tid) 201 kt = kt->next; 202 return (kt); 203 } 204 205 struct kthr * 206 kgdb_thr_lookup_taddr(uintptr_t taddr) 207 { 208 struct kthr *kt; 209 210 kt = first; 211 while (kt != NULL && kt->kaddr != taddr) 212 kt = kt->next; 213 return (kt); 214 } 215 216 struct kthr * 217 kgdb_thr_lookup_pid(int pid) 218 { 219 struct kthr *kt; 220 221 kt = first; 222 while (kt != NULL && kt->pid != pid) 223 kt = kt->next; 224 return (kt); 225 } 226 227 struct kthr * 228 kgdb_thr_lookup_paddr(uintptr_t paddr) 229 { 230 struct kthr *kt; 231 232 kt = first; 233 while (kt != NULL && kt->paddr != paddr) 234 kt = kt->next; 235 return (kt); 236 } 237 238 struct kthr * 239 kgdb_thr_next(struct kthr *kt) 240 { 241 return (kt->next); 242 } 243 244 struct kthr * 245 kgdb_thr_select(struct kthr *kt) 246 { 247 struct kthr *pcur; 248 249 pcur = curkthr; 250 curkthr = kt; 251 return (pcur); 252 } 253 254 char * 255 kgdb_thr_extra_thread_info(CORE_ADDR tid) 256 { 257 #if 0 /* Information already provided */ 258 struct kthr *kt; 259 static char buf[64]; 260 struct proc *p; 261 char comm[MAXCOMLEN + 1]; 262 263 kt = kgdb_thr_lookup_tid(tid); 264 if (kt == NULL) 265 return (NULL); 266 267 snprintf(buf, sizeof(buf), "PID=%d", kt->pid); 268 p = (struct proc *)kt->paddr; 269 if (kvm_read(kvm, (uintptr_t)&p->p_comm[0], &comm, sizeof(comm)) == 270 sizeof(comm)) { 271 strlcat(buf, ": ", sizeof(buf)); 272 strlcat(buf, comm, sizeof(buf)); 273 } 274 return (buf); 275 #endif 276 return (NULL); 277 } 278 279 char * 280 kgdb_thr_pid_to_str(ptid_t ptid) 281 { 282 char comm[MAXCOMLEN + 1]; 283 struct kthr *kt; 284 struct proc *p; 285 struct thread *t; 286 static char buf[64]; 287 CORE_ADDR tid; 288 289 tid = ptid_get_tid(ptid); 290 if (tid == 0) 291 kt = kgdb_thr_lookup_pid(ptid_get_pid(ptid)); 292 else 293 kt = kgdb_thr_lookup_tid(tid); 294 295 if (kt == NULL) 296 return (NULL); 297 298 buf[0] = 0; 299 300 if (kt->pid != -2) { 301 snprintf(buf, sizeof(buf), "pid %d", kt->pid); 302 303 if (tid != 0) 304 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 305 "/%ld", kt->lwpid); 306 307 p = (struct proc *)kt->paddr; 308 if (kvm_read(kvm, (uintptr_t)&p->p_comm[0], &comm, sizeof(comm)) != 309 sizeof(comm)) 310 return (buf); 311 312 strlcat(buf, ", ", sizeof(buf)); 313 strlcat(buf, comm, sizeof(buf)); 314 } else { 315 strcpy(buf, "kernel"); 316 317 if (tid != 0) { 318 t = (struct thread *)kt->kaddr; 319 if (kvm_read(kvm, (uintptr_t)&t->td_comm[0], &comm, 320 sizeof(comm)) == sizeof(comm)) { 321 strlcat(buf, " ", sizeof(buf)); 322 strlcat(buf, comm, sizeof(buf)); 323 } 324 } 325 } 326 327 return (buf); 328 } 329