freebsd-skq/gnu/usr.bin/gdb/kgdb/trgt.c
kan 858ff332fa Attempt to make kgdb little more useful and easy to use. Properly initialize
it to recognise what ABI  to use on amd64 (and possibly others) platform.
Display PID and process name as a part of the 'info threads' output, TIDs
alone are too confusing. Introduce new commmands 'tid <tid>' and 'proc <pid>'
to accompany gdb's default 'thread <thread num>' to make the task of switching
between different contexts easier.
2005-02-20 22:55:07 +00:00

209 lines
5.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 <kvm.h>
#include <defs.h>
#include <command.h>
#include <gdbthread.h>
#include <inferior.h>
#include <regcache.h>
#include <target.h>
#include "kgdb.h"
static struct target_ops kgdb_trgt_ops;
#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)
{
return (kgdb_thr_extra_thread_info(ptid_get_tid(ti->ptid)));
}
static void
kgdb_trgt_find_new_threads(void)
{
}
static char *
kgdb_trgt_pid_to_str(ptid_t ptid)
{
static char buf[33];
snprintf(buf, sizeof(buf), "PID %5d TID %5ld", ptid_get_pid(ptid),
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 __unused, struct target_ops *target __unused)
{
if (len == 0)
return (0);
if (!write)
return (kvm_read(kvm, memaddr, myaddr, len));
else
return (kvm_write(kvm, memaddr, myaddr, len));
}
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_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;
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);
}
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 process context");
}