1132624Smarcel/* 2132624Smarcel * Copyright (c) 2004 Marcel Moolenaar 3132624Smarcel * All rights reserved. 4132624Smarcel * 5132624Smarcel * Redistribution and use in source and binary forms, with or without 6132624Smarcel * modification, are permitted provided that the following conditions 7132624Smarcel * are met: 8132624Smarcel * 9132624Smarcel * 1. Redistributions of source code must retain the above copyright 10132624Smarcel * notice, this list of conditions and the following disclaimer. 11132624Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12132624Smarcel * notice, this list of conditions and the following disclaimer in the 13132624Smarcel * documentation and/or other materials provided with the distribution. 14132624Smarcel * 15132624Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16132624Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17132624Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18132624Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19132624Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20132624Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21132624Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22132624Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23132624Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24132624Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25132624Smarcel */ 26132624Smarcel 27132624Smarcel#include <sys/cdefs.h> 28132624Smarcel__FBSDID("$FreeBSD$"); 29132624Smarcel 30142151Skan#include <sys/param.h> 31142151Skan#include <sys/proc.h> 32142151Skan#include <sys/sysctl.h> 33142151Skan#include <sys/user.h> 34175808Sjhb#include <err.h> 35178670Sjhb#include <fcntl.h> 36132624Smarcel#include <kvm.h> 37132624Smarcel 38132624Smarcel#include <defs.h> 39178670Sjhb#include <readline/readline.h> 40178670Sjhb#include <readline/tilde.h> 41142151Skan#include <command.h> 42175808Sjhb#include <exec.h> 43149954Smarcel#include <frame-unwind.h> 44178713Sjhb#include <gdb.h> 45178670Sjhb#include <gdbcore.h> 46132624Smarcel#include <gdbthread.h> 47132624Smarcel#include <inferior.h> 48178670Sjhb#include <language.h> 49142151Skan#include <regcache.h> 50178670Sjhb#include <solib.h> 51132624Smarcel#include <target.h> 52178713Sjhb#include <ui-out.h> 53132624Smarcel 54142151Skan#include "kgdb.h" 55142151Skan 56178670Sjhbstatic void kgdb_core_cleanup(void *); 57178670Sjhb 58178670Sjhbstatic char *vmcore; 59132624Smarcelstatic struct target_ops kgdb_trgt_ops; 60132624Smarcel 61178670Sjhbkvm_t *kvm; 62178670Sjhbstatic char kvm_err[_POSIX2_LINE_MAX]; 63175808Sjhb 64163439Sjhb#define KERNOFF (kgdb_kernbase ()) 65163439Sjhb#define INKERNEL(x) ((x) >= KERNOFF) 66163439Sjhb 67163439Sjhbstatic CORE_ADDR 68163439Sjhbkgdb_kernbase (void) 69163439Sjhb{ 70163439Sjhb static CORE_ADDR kernbase; 71163439Sjhb struct minimal_symbol *sym; 72163439Sjhb 73163439Sjhb if (kernbase == 0) { 74163439Sjhb sym = lookup_minimal_symbol ("kernbase", NULL, NULL); 75163439Sjhb if (sym == NULL) { 76163439Sjhb kernbase = KERNBASE; 77163439Sjhb } else { 78163439Sjhb kernbase = SYMBOL_VALUE_ADDRESS (sym); 79163439Sjhb } 80163439Sjhb } 81163439Sjhb return kernbase; 82163439Sjhb} 83163439Sjhb 84178670Sjhbstatic void 85178670Sjhbkgdb_trgt_open(char *filename, int from_tty) 86178670Sjhb{ 87178670Sjhb struct cleanup *old_chain; 88178670Sjhb struct thread_info *ti; 89178670Sjhb struct kthr *kt; 90178670Sjhb kvm_t *nkvm; 91178670Sjhb char *temp; 92178670Sjhb int ontop; 93178670Sjhb 94178670Sjhb target_preopen (from_tty); 95178670Sjhb if (!filename) 96178670Sjhb error ("No vmcore file specified."); 97178670Sjhb if (!exec_bfd) 98178670Sjhb error ("Can't open a vmcore without a kernel"); 99178670Sjhb 100178670Sjhb filename = tilde_expand (filename); 101178670Sjhb if (filename[0] != '/') { 102178670Sjhb temp = concat (current_directory, "/", filename, NULL); 103178670Sjhb xfree(filename); 104178670Sjhb filename = temp; 105178670Sjhb } 106178670Sjhb 107178670Sjhb old_chain = make_cleanup (xfree, filename); 108178670Sjhb 109178670Sjhb nkvm = kvm_openfiles(bfd_get_filename(exec_bfd), filename, NULL, 110178670Sjhb write_files ? O_RDWR : O_RDONLY, kvm_err); 111178670Sjhb if (nkvm == NULL) 112178670Sjhb error ("Failed to open vmcore: %s", kvm_err); 113178670Sjhb 114178670Sjhb /* Don't free the filename now and close any previous vmcore. */ 115178670Sjhb discard_cleanups(old_chain); 116178670Sjhb unpush_target(&kgdb_trgt_ops); 117178670Sjhb 118178670Sjhb kvm = nkvm; 119178670Sjhb vmcore = filename; 120178670Sjhb old_chain = make_cleanup(kgdb_core_cleanup, NULL); 121178670Sjhb 122178670Sjhb ontop = !push_target (&kgdb_trgt_ops); 123178670Sjhb discard_cleanups (old_chain); 124178670Sjhb 125178670Sjhb kgdb_dmesg(); 126178670Sjhb 127178670Sjhb init_thread_list(); 128178670Sjhb kt = kgdb_thr_init(); 129178670Sjhb while (kt != NULL) { 130178713Sjhb ti = add_thread(pid_to_ptid(kt->tid)); 131178670Sjhb kt = kgdb_thr_next(kt); 132178670Sjhb } 133178670Sjhb if (curkthr != 0) 134178713Sjhb inferior_ptid = pid_to_ptid(curkthr->tid); 135178670Sjhb 136178670Sjhb if (ontop) { 137178670Sjhb /* XXX: fetch registers? */ 138178670Sjhb kld_init(); 139178670Sjhb flush_cached_frames(); 140178670Sjhb select_frame (get_current_frame()); 141178670Sjhb print_stack_frame(get_selected_frame(), 142178670Sjhb frame_relative_level(get_selected_frame()), 1); 143178670Sjhb } else 144178670Sjhb warning( 145178670Sjhb "you won't be able to access this vmcore until you terminate\n\ 146178670Sjhbyour %s; do ``info files''", target_longname); 147178670Sjhb} 148178670Sjhb 149178670Sjhbstatic void 150178670Sjhbkgdb_trgt_close(int quitting) 151178670Sjhb{ 152178670Sjhb 153178670Sjhb if (kvm != NULL) { 154178670Sjhb inferior_ptid = null_ptid; 155178670Sjhb CLEAR_SOLIB(); 156178670Sjhb if (kvm_close(kvm) != 0) 157178670Sjhb warning("cannot close \"%s\": %s", vmcore, 158178670Sjhb kvm_geterr(kvm)); 159178670Sjhb kvm = NULL; 160178670Sjhb xfree(vmcore); 161178670Sjhb vmcore = NULL; 162178670Sjhb if (kgdb_trgt_ops.to_sections) { 163178670Sjhb xfree(kgdb_trgt_ops.to_sections); 164178670Sjhb kgdb_trgt_ops.to_sections = NULL; 165178670Sjhb kgdb_trgt_ops.to_sections_end = NULL; 166178670Sjhb } 167178670Sjhb } 168178670Sjhb} 169178670Sjhb 170178670Sjhbstatic void 171178670Sjhbkgdb_core_cleanup(void *arg) 172178670Sjhb{ 173178670Sjhb 174178670Sjhb kgdb_trgt_close(0); 175178670Sjhb} 176178670Sjhb 177178670Sjhbstatic void 178178670Sjhbkgdb_trgt_detach(char *args, int from_tty) 179178670Sjhb{ 180178670Sjhb 181178670Sjhb if (args) 182178670Sjhb error ("Too many arguments"); 183178670Sjhb unpush_target(&kgdb_trgt_ops); 184178670Sjhb reinit_frame_cache(); 185178670Sjhb if (from_tty) 186178670Sjhb printf_filtered("No vmcore file now.\n"); 187178670Sjhb} 188178670Sjhb 189148802Smarcelstatic char * 190148802Smarcelkgdb_trgt_extra_thread_info(struct thread_info *ti) 191148802Smarcel{ 192142151Skan 193178713Sjhb return (kgdb_thr_extra_thread_info(ptid_get_pid(ti->ptid))); 194142151Skan} 195142151Skan 196148802Smarcelstatic void 197148802Smarcelkgdb_trgt_files_info(struct target_ops *target) 198132624Smarcel{ 199148802Smarcel 200178670Sjhb printf_filtered ("\t`%s', ", vmcore); 201178670Sjhb wrap_here (" "); 202178670Sjhb printf_filtered ("file type %s.\n", "FreeBSD kernel vmcore"); 203132624Smarcel} 204132624Smarcel 205132624Smarcelstatic void 206132624Smarcelkgdb_trgt_find_new_threads(void) 207132624Smarcel{ 208148802Smarcel struct target_ops *tb; 209148802Smarcel 210148802Smarcel if (kvm != NULL) 211148802Smarcel return; 212148802Smarcel 213148802Smarcel tb = find_target_beneath(&kgdb_trgt_ops); 214148802Smarcel if (tb->to_find_new_threads != NULL) 215148802Smarcel tb->to_find_new_threads(); 216132624Smarcel} 217132624Smarcel 218132624Smarcelstatic char * 219132624Smarcelkgdb_trgt_pid_to_str(ptid_t ptid) 220132624Smarcel{ 221142151Skan static char buf[33]; 222132624Smarcel 223178713Sjhb snprintf(buf, sizeof(buf), "Thread %d", ptid_get_pid(ptid)); 224132624Smarcel return (buf); 225132624Smarcel} 226132624Smarcel 227132624Smarcelstatic int 228132624Smarcelkgdb_trgt_thread_alive(ptid_t ptid) 229132624Smarcel{ 230178713Sjhb return (kgdb_thr_lookup_tid(ptid_get_pid(ptid)) != NULL); 231132624Smarcel} 232132624Smarcel 233132624Smarcelstatic int 234132624Smarcelkgdb_trgt_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len, int write, 235148802Smarcel struct mem_attrib *attrib, struct target_ops *target) 236132624Smarcel{ 237148802Smarcel struct target_ops *tb; 238132624Smarcel 239148802Smarcel if (kvm != NULL) { 240148802Smarcel if (len == 0) 241148802Smarcel return (0); 242148802Smarcel if (!write) 243148802Smarcel return (kvm_read(kvm, memaddr, myaddr, len)); 244148802Smarcel else 245148802Smarcel return (kvm_write(kvm, memaddr, myaddr, len)); 246142151Skan } 247148802Smarcel tb = find_target_beneath(target); 248148802Smarcel return (tb->to_xfer_memory(memaddr, myaddr, len, write, attrib, tb)); 249142151Skan} 250142151Skan 251178670Sjhbstatic int 252178670Sjhbkgdb_trgt_ignore_breakpoints(CORE_ADDR addr, char *contents) 253178670Sjhb{ 254178670Sjhb 255178670Sjhb return 0; 256178670Sjhb} 257178670Sjhb 258163439Sjhbstatic void 259178713Sjhbkgdb_switch_to_thread(int tid) 260163439Sjhb{ 261178713Sjhb char buf[16]; 262178713Sjhb int thread_id; 263163439Sjhb 264178713Sjhb thread_id = pid_to_thread_id(pid_to_ptid(tid)); 265178713Sjhb if (thread_id == 0) 266178713Sjhb error ("invalid tid"); 267178713Sjhb snprintf(buf, sizeof(buf), "%d", thread_id); 268178713Sjhb gdb_thread_select(uiout, buf); 269163439Sjhb} 270163439Sjhb 271163439Sjhbstatic void 272163439Sjhbkgdb_set_proc_cmd (char *arg, int from_tty) 273163439Sjhb{ 274163439Sjhb CORE_ADDR addr; 275163439Sjhb struct kthr *thr; 276163439Sjhb 277163439Sjhb if (!arg) 278163439Sjhb error_no_arg ("proc address for the new context"); 279163439Sjhb 280163439Sjhb if (kvm == NULL) 281178713Sjhb error ("only supported for core file target"); 282163439Sjhb 283163439Sjhb addr = (CORE_ADDR) parse_and_eval_address (arg); 284163439Sjhb 285163439Sjhb if (!INKERNEL (addr)) { 286163439Sjhb thr = kgdb_thr_lookup_pid((int)addr); 287163439Sjhb if (thr == NULL) 288163439Sjhb error ("invalid pid"); 289163439Sjhb } else { 290163439Sjhb thr = kgdb_thr_lookup_paddr(addr); 291163439Sjhb if (thr == NULL) 292163439Sjhb error("invalid proc address"); 293163439Sjhb } 294178713Sjhb kgdb_switch_to_thread(thr->tid); 295163439Sjhb} 296163439Sjhb 297163439Sjhbstatic void 298163439Sjhbkgdb_set_tid_cmd (char *arg, int from_tty) 299163439Sjhb{ 300163439Sjhb CORE_ADDR addr; 301163439Sjhb struct kthr *thr; 302163439Sjhb 303163439Sjhb if (!arg) 304163439Sjhb error_no_arg ("TID or thread address for the new context"); 305163439Sjhb 306163439Sjhb addr = (CORE_ADDR) parse_and_eval_address (arg); 307163439Sjhb 308178713Sjhb if (kvm != NULL && INKERNEL (addr)) { 309163439Sjhb thr = kgdb_thr_lookup_taddr(addr); 310163439Sjhb if (thr == NULL) 311163439Sjhb error("invalid thread address"); 312178713Sjhb addr = thr->tid; 313163439Sjhb } 314178713Sjhb kgdb_switch_to_thread(addr); 315163439Sjhb} 316163439Sjhb 317178670Sjhbint fbsdcoreops_suppress_target = 1; 318178670Sjhb 319132624Smarcelvoid 320178670Sjhbinitialize_kgdb_target(void) 321132624Smarcel{ 322132624Smarcel 323132624Smarcel kgdb_trgt_ops.to_magic = OPS_MAGIC; 324132624Smarcel kgdb_trgt_ops.to_shortname = "kernel"; 325178670Sjhb kgdb_trgt_ops.to_longname = "kernel core dump file"; 326178670Sjhb kgdb_trgt_ops.to_doc = 327178670Sjhb "Use a vmcore file as a target. Specify the filename of the vmcore file."; 328178670Sjhb kgdb_trgt_ops.to_stratum = core_stratum; 329132624Smarcel kgdb_trgt_ops.to_has_memory = 1; 330132624Smarcel kgdb_trgt_ops.to_has_registers = 1; 331132624Smarcel kgdb_trgt_ops.to_has_stack = 1; 332132624Smarcel 333178670Sjhb kgdb_trgt_ops.to_open = kgdb_trgt_open; 334178670Sjhb kgdb_trgt_ops.to_close = kgdb_trgt_close; 335178670Sjhb kgdb_trgt_ops.to_attach = find_default_attach; 336178670Sjhb kgdb_trgt_ops.to_detach = kgdb_trgt_detach; 337132624Smarcel kgdb_trgt_ops.to_extra_thread_info = kgdb_trgt_extra_thread_info; 338132624Smarcel kgdb_trgt_ops.to_fetch_registers = kgdb_trgt_fetch_registers; 339148802Smarcel kgdb_trgt_ops.to_files_info = kgdb_trgt_files_info; 340132624Smarcel kgdb_trgt_ops.to_find_new_threads = kgdb_trgt_find_new_threads; 341132624Smarcel kgdb_trgt_ops.to_pid_to_str = kgdb_trgt_pid_to_str; 342132624Smarcel kgdb_trgt_ops.to_store_registers = kgdb_trgt_store_registers; 343132624Smarcel kgdb_trgt_ops.to_thread_alive = kgdb_trgt_thread_alive; 344132624Smarcel kgdb_trgt_ops.to_xfer_memory = kgdb_trgt_xfer_memory; 345178670Sjhb kgdb_trgt_ops.to_insert_breakpoint = kgdb_trgt_ignore_breakpoints; 346178670Sjhb kgdb_trgt_ops.to_remove_breakpoint = kgdb_trgt_ignore_breakpoints; 347175808Sjhb 348132624Smarcel add_target(&kgdb_trgt_ops); 349132624Smarcel 350163439Sjhb add_com ("proc", class_obscure, kgdb_set_proc_cmd, 351163439Sjhb "Set current process context"); 352163439Sjhb add_com ("tid", class_obscure, kgdb_set_tid_cmd, 353163439Sjhb "Set current thread context"); 354132624Smarcel} 355