mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-06 13:09:50 +00:00
2369087a60
kgdb(8) now treats kld's as shared libraries relative to the kernel "binary". Thus, you can use 'info sharedlibrary' to list the kld's along with 'sharedlibrary' and 'nosharedlibrary' to manage symbol loading and unloading. Note that there isn't an easy way to force GDB to use a specific path for a shared library. However, you can use 'nosharedlibrary' to unload all the klds and then use 'sharedlibrary' to load specific klds where it gets the kld correct and use 'add-kld' for the kld's where the default open behavior doesn't work. klds opened via 'sharedlibrary' (and during startup) do have their sections listed in 'info files'. - Change the 'add-kld' command to use filename completion to complete its argument.
248 lines
6.2 KiB
C
248 lines
6.2 KiB
C
/*
|
|
* Copyright (c) 2004 Marcel Moolenaar
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/user.h>
|
|
#include <err.h>
|
|
#include <kvm.h>
|
|
|
|
#include <defs.h>
|
|
#include <command.h>
|
|
#include <exec.h>
|
|
#include <frame-unwind.h>
|
|
#include <gdbthread.h>
|
|
#include <inferior.h>
|
|
#include <regcache.h>
|
|
#include <target.h>
|
|
|
|
#include "kgdb.h"
|
|
|
|
static struct target_ops kgdb_trgt_ops;
|
|
|
|
bfd *kern_bfd;
|
|
|
|
#define KERNOFF (kgdb_kernbase ())
|
|
#define INKERNEL(x) ((x) >= KERNOFF)
|
|
|
|
static CORE_ADDR
|
|
kgdb_kernbase (void)
|
|
{
|
|
static CORE_ADDR kernbase;
|
|
struct minimal_symbol *sym;
|
|
|
|
if (kernbase == 0) {
|
|
sym = lookup_minimal_symbol ("kernbase", NULL, NULL);
|
|
if (sym == NULL) {
|
|
kernbase = KERNBASE;
|
|
} else {
|
|
kernbase = SYMBOL_VALUE_ADDRESS (sym);
|
|
}
|
|
}
|
|
return kernbase;
|
|
}
|
|
|
|
static char *
|
|
kgdb_trgt_extra_thread_info(struct thread_info *ti)
|
|
{
|
|
static char buf[64];
|
|
char *p, *s;
|
|
|
|
p = buf + snprintf(buf, sizeof(buf), "PID=%d", ptid_get_pid(ti->ptid));
|
|
s = kgdb_thr_extra_thread_info(ptid_get_tid(ti->ptid));
|
|
if (s != NULL)
|
|
snprintf(p, sizeof(buf) - (p - buf), ": %s", s);
|
|
return (buf);
|
|
}
|
|
|
|
static void
|
|
kgdb_trgt_files_info(struct target_ops *target)
|
|
{
|
|
|
|
print_section_info(target, kern_bfd);
|
|
}
|
|
|
|
static void
|
|
kgdb_trgt_find_new_threads(void)
|
|
{
|
|
struct target_ops *tb;
|
|
|
|
if (kvm != NULL)
|
|
return;
|
|
|
|
tb = find_target_beneath(&kgdb_trgt_ops);
|
|
if (tb->to_find_new_threads != NULL)
|
|
tb->to_find_new_threads();
|
|
}
|
|
|
|
static char *
|
|
kgdb_trgt_pid_to_str(ptid_t ptid)
|
|
{
|
|
static char buf[33];
|
|
|
|
snprintf(buf, sizeof(buf), "Thread %ld", ptid_get_tid(ptid));
|
|
return (buf);
|
|
}
|
|
|
|
static int
|
|
kgdb_trgt_thread_alive(ptid_t ptid)
|
|
{
|
|
return (kgdb_thr_lookup_tid(ptid_get_tid(ptid)) != NULL);
|
|
}
|
|
|
|
static int
|
|
kgdb_trgt_xfer_memory(CORE_ADDR memaddr, char *myaddr, int len, int write,
|
|
struct mem_attrib *attrib, struct target_ops *target)
|
|
{
|
|
struct target_ops *tb;
|
|
|
|
if (kvm != NULL) {
|
|
if (len == 0)
|
|
return (0);
|
|
if (!write)
|
|
return (kvm_read(kvm, memaddr, myaddr, len));
|
|
else
|
|
return (kvm_write(kvm, memaddr, myaddr, len));
|
|
}
|
|
tb = find_target_beneath(target);
|
|
return (tb->to_xfer_memory(memaddr, myaddr, len, write, attrib, tb));
|
|
}
|
|
|
|
static void
|
|
kgdb_switch_to_thread(struct kthr *thr)
|
|
{
|
|
if (thr->tid == ptid_get_tid(inferior_ptid))
|
|
return;
|
|
|
|
inferior_ptid = ptid_build(thr->pid, 0, thr->tid);
|
|
flush_cached_frames ();
|
|
registers_changed ();
|
|
stop_pc = read_pc ();
|
|
select_frame (get_current_frame ());
|
|
}
|
|
|
|
static void
|
|
kgdb_set_proc_cmd (char *arg, int from_tty)
|
|
{
|
|
CORE_ADDR addr;
|
|
struct kthr *thr;
|
|
|
|
if (!arg)
|
|
error_no_arg ("proc address for the new context");
|
|
|
|
if (kvm == NULL)
|
|
error ("no kernel core file");
|
|
|
|
addr = (CORE_ADDR) parse_and_eval_address (arg);
|
|
|
|
if (!INKERNEL (addr)) {
|
|
thr = kgdb_thr_lookup_pid((int)addr);
|
|
if (thr == NULL)
|
|
error ("invalid pid");
|
|
} else {
|
|
thr = kgdb_thr_lookup_paddr(addr);
|
|
if (thr == NULL)
|
|
error("invalid proc address");
|
|
}
|
|
kgdb_switch_to_thread(thr);
|
|
}
|
|
|
|
static void
|
|
kgdb_set_tid_cmd (char *arg, int from_tty)
|
|
{
|
|
CORE_ADDR addr;
|
|
struct kthr *thr;
|
|
|
|
if (!arg)
|
|
error_no_arg ("TID or thread address for the new context");
|
|
|
|
if (kvm == NULL)
|
|
error ("no kernel core file");
|
|
|
|
addr = (CORE_ADDR) parse_and_eval_address (arg);
|
|
|
|
if (!INKERNEL (addr)) {
|
|
thr = kgdb_thr_lookup_tid((int)addr);
|
|
if (thr == NULL)
|
|
error ("invalid TID");
|
|
} else {
|
|
thr = kgdb_thr_lookup_taddr(addr);
|
|
if (thr == NULL)
|
|
error("invalid thread address");
|
|
}
|
|
kgdb_switch_to_thread(thr);
|
|
}
|
|
|
|
void
|
|
kgdb_target(void)
|
|
{
|
|
struct kthr *kt;
|
|
struct thread_info *ti;
|
|
|
|
kgdb_trgt_ops.to_magic = OPS_MAGIC;
|
|
kgdb_trgt_ops.to_shortname = "kernel";
|
|
kgdb_trgt_ops.to_longname = "kernel core files";
|
|
kgdb_trgt_ops.to_doc = "Kernel core files.";
|
|
kgdb_trgt_ops.to_stratum = thread_stratum;
|
|
kgdb_trgt_ops.to_has_memory = 1;
|
|
kgdb_trgt_ops.to_has_registers = 1;
|
|
kgdb_trgt_ops.to_has_stack = 1;
|
|
|
|
kgdb_trgt_ops.to_extra_thread_info = kgdb_trgt_extra_thread_info;
|
|
kgdb_trgt_ops.to_fetch_registers = kgdb_trgt_fetch_registers;
|
|
kgdb_trgt_ops.to_files_info = kgdb_trgt_files_info;
|
|
kgdb_trgt_ops.to_find_new_threads = kgdb_trgt_find_new_threads;
|
|
kgdb_trgt_ops.to_pid_to_str = kgdb_trgt_pid_to_str;
|
|
kgdb_trgt_ops.to_store_registers = kgdb_trgt_store_registers;
|
|
kgdb_trgt_ops.to_thread_alive = kgdb_trgt_thread_alive;
|
|
kgdb_trgt_ops.to_xfer_memory = kgdb_trgt_xfer_memory;
|
|
|
|
if (build_section_table(kern_bfd, &kgdb_trgt_ops.to_sections,
|
|
&kgdb_trgt_ops.to_sections_end) != 0)
|
|
errx(1, "\"%s\": can't find the file sections: %s",
|
|
kernel, bfd_errmsg(bfd_get_error()));
|
|
|
|
add_target(&kgdb_trgt_ops);
|
|
push_target(&kgdb_trgt_ops);
|
|
|
|
kt = kgdb_thr_first();
|
|
while (kt != NULL) {
|
|
ti = add_thread(ptid_build(kt->pid, 0, kt->tid));
|
|
kt = kgdb_thr_next(kt);
|
|
}
|
|
if (curkthr != 0)
|
|
inferior_ptid = ptid_build(curkthr->pid, 0, curkthr->tid);
|
|
add_com ("proc", class_obscure, kgdb_set_proc_cmd,
|
|
"Set current process context");
|
|
add_com ("tid", class_obscure, kgdb_set_tid_cmd,
|
|
"Set current thread context");
|
|
kgdb_kld_init();
|
|
}
|