summaryrefslogtreecommitdiff
path: root/usr.bin/pmdb
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2002-03-15 16:30:34 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2002-03-15 16:30:34 +0000
commit762c7e2653616ce6ca212000d059575f5a3667da (patch)
tree6e68b250f0e7b3a3f5eb8b708861130a0aed9524 /usr.bin/pmdb
parent8ac4d27abf792757bbc8e71d8497b8631145bd6a (diff)
Import pmdb 4.1.
(see http://www.blahonga.org/~art/openbsd/pmdb.html for more info). The development repository now moves here out from my local repository.
Diffstat (limited to 'usr.bin/pmdb')
-rw-r--r--usr.bin/pmdb/Makefile46
-rw-r--r--usr.bin/pmdb/aout_syms.c348
-rw-r--r--usr.bin/pmdb/arch/alpha/Makefile.inc1
-rw-r--r--usr.bin/pmdb/arch/alpha/alpha.c70
-rw-r--r--usr.bin/pmdb/arch/alpha/alpha_instruction.h750
-rw-r--r--usr.bin/pmdb/arch/alpha/alpha_trace.c343
-rw-r--r--usr.bin/pmdb/arch/alpha/pmdb_machdep.h3
-rw-r--r--usr.bin/pmdb/arch/i386/Makefile.inc3
-rw-r--r--usr.bin/pmdb/arch/i386/i386.c91
-rw-r--r--usr.bin/pmdb/arch/i386/pmdb_machdep.h3
-rw-r--r--usr.bin/pmdb/arch/sparc/Makefile.inc1
-rw-r--r--usr.bin/pmdb/arch/sparc/pmdb_machdep.h3
-rw-r--r--usr.bin/pmdb/arch/sparc/sparc.c107
-rw-r--r--usr.bin/pmdb/arch/sparc64/Makefile.inc1
-rw-r--r--usr.bin/pmdb/arch/sparc64/pmdb_machdep.h3
-rw-r--r--usr.bin/pmdb/arch/sparc64/sparc64.c122
-rw-r--r--usr.bin/pmdb/break.c301
-rw-r--r--usr.bin/pmdb/break.h46
-rw-r--r--usr.bin/pmdb/clit.c261
-rw-r--r--usr.bin/pmdb/clit.h52
-rw-r--r--usr.bin/pmdb/elf_syms.c403
-rw-r--r--usr.bin/pmdb/pmdb.1110
-rw-r--r--usr.bin/pmdb/pmdb.c348
-rw-r--r--usr.bin/pmdb/pmdb.h119
-rw-r--r--usr.bin/pmdb/process.c169
-rw-r--r--usr.bin/pmdb/signal.c166
-rw-r--r--usr.bin/pmdb/symbol.c160
-rw-r--r--usr.bin/pmdb/symbol.h61
28 files changed, 4091 insertions, 0 deletions
diff --git a/usr.bin/pmdb/Makefile b/usr.bin/pmdb/Makefile
new file mode 100644
index 00000000000..6b3194b9c44
--- /dev/null
+++ b/usr.bin/pmdb/Makefile
@@ -0,0 +1,46 @@
+# $PMDB: Makefile,v 1.10 2002/03/07 14:27:08 art Exp $
+
+.include <bsd.own.mk>
+
+BINDIR=/usr/local/bin
+
+PROG=pmdb
+SRCS=pmdb.c symbol.c clit.c process.c signal.c break.c
+
+# support for NetBSD
+.if defined(OBJECT_FMT)
+.if ${OBJECT_FMT} == "ELF"
+ELF_TOOLCHAIN=yes
+.else
+ELF_TOOLCHAIN=no
+.endif
+.endif
+
+.if (${ELF_TOOLCHAIN} == "yes")
+SRCS+=elf_syms.c
+CPPFLAGS+=-DPMDB_ELF
+.else
+SRCS+=aout_syms.c
+CPPFLAGS+=-DPMDB_AOUT
+.endif
+
+LDADD=-ledit -lcurses
+DPADD=${LIBEDIT} ${LIBTERMCAP}
+
+CPPFLAGS+=-I${.CURDIR}
+
+.if exists(arch/${MACHINE}/Makefile.inc)
+.PATH: ${.CURDIR}/arch/${MACHINE}
+.include "arch/${MACHINE}/Makefile.inc"
+CPPFLAGS+=-I${.CURDIR}/arch/${MACHINE}
+.endif
+
+.if (${MACHINE_ARCH} != ${MACHINE}) && exists(arch/${MACHINE_ARCH}/Makefile.inc)
+.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}
+.include arch/${MACHINE_ARCH}/Makefile.inc
+CPPFLAGS+=-I${.CURDIR}/arch/${MACHINE_ARCH}
+.endif
+
+COPTS=-Wall -Wno-uninitialized
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/pmdb/aout_syms.c b/usr.bin/pmdb/aout_syms.c
new file mode 100644
index 00000000000..9af258f0786
--- /dev/null
+++ b/usr.bin/pmdb/aout_syms.c
@@ -0,0 +1,348 @@
+/* $PMDB: aout_syms.c,v 1.17 2002/03/11 21:46:12 art Exp $ */
+/*
+ * Copyright (c) 2002 Federico Schwindt <fgsch@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/mman.h>
+
+#include <sys/types.h>
+#include <a.out.h>
+#include <link.h>
+
+#include "pmdb.h"
+#include "symbol.h"
+
+#if defined(__OpenBSD__) && (OpenBSD < 200106)
+/* OpenBSD prior to 2.9 have a broken pread on big-endian archs. */
+#define IGNORE_PREAD_ERRORS
+#endif
+
+struct aout_symbol_handle {
+ struct sym_table ash_st;
+ int ash_fd;
+ char *ash_strtab;
+ u_int32_t ash_strsize;
+ struct nlist *ash_symtab;
+ int ash_symsize;
+ int ash_offs;
+};
+
+#define ASH_TO_ST(ash) (&(ash)->ash_st)
+#define ST_TO_ASH(st) ((struct aout_symbol_handle *)(st))
+
+struct sym_table *aout_open(const char *);
+void aout_close(struct sym_table *);
+char *aout_name_and_off(struct sym_table *, reg, reg *);
+int aout_lookup(struct pstate *, const char *, reg *);
+void aout_update(struct pstate *);
+
+struct sym_ops aout_sops = {
+ aout_open,
+ aout_close,
+ aout_name_and_off,
+ aout_lookup,
+ aout_update
+};
+
+int
+sym_check_aout(const char *name, struct pstate *ps)
+{
+ struct exec ahdr;
+ int fd;
+
+ if ((fd = open(name, O_RDONLY)) < 0)
+ return (-1);
+
+ if (pread(fd, &ahdr, sizeof(ahdr), 0) != sizeof(ahdr)) {
+#ifndef IGNORE_PREAD_ERRORS
+ return (-1);
+#endif
+ }
+
+ if (N_BADMAG(ahdr)) {
+ return (-1);
+ }
+
+ close(fd);
+
+ ps->ps_sops = &aout_sops;
+
+ return (0);
+}
+
+struct sym_table *
+aout_open(const char *name)
+{
+ struct aout_symbol_handle *ash;
+ u_int32_t symoff, stroff;
+ struct exec ahdr;
+
+ if ((ash = malloc(sizeof(*ash))) == NULL) {
+ return NULL;
+ }
+
+ memset(ash, 0, sizeof(*ash));
+ ash->ash_fd = -1;
+
+ if ((ash->ash_fd = open(name, O_RDONLY)) < 0) {
+ warn("open(%s)", name);
+ goto fail;
+ }
+
+ if (pread(ash->ash_fd, &ahdr, sizeof(ahdr), 0) != sizeof(ahdr)) {
+#ifndef IGNORE_PREAD_ERRORS
+ warn("pread(header)");
+ goto fail;
+#endif
+ }
+
+ if (N_BADMAG(ahdr)) {
+ warnx("Bad magic.");
+ goto fail;
+ }
+
+ symoff = N_SYMOFF(ahdr);
+ ash->ash_symsize = ahdr.a_syms;
+ stroff = N_STROFF(ahdr);
+
+ if (pread(ash->ash_fd, &ash->ash_strsize, sizeof(u_int32_t),
+ stroff) != sizeof(u_int32_t)) {
+#ifndef IGNORE_PREAD_ERRORS
+ warn("pread(strsize)");
+ goto fail;
+#endif
+ }
+
+ if ((ash->ash_strtab = mmap(NULL, ash->ash_strsize, PROT_READ,
+ MAP_SHARED, ash->ash_fd, stroff)) == MAP_FAILED) {
+ warn("mmap(strtab)");
+ goto fail;
+ }
+
+ if ((ash->ash_symtab = mmap(NULL, ash->ash_symsize, PROT_READ,
+ MAP_SHARED, ash->ash_fd, symoff)) == MAP_FAILED) {
+ warn("mmap(symtab)");
+ goto fail;
+ }
+
+ return (ASH_TO_ST(ash));
+fail:
+
+ aout_close(ASH_TO_ST(ash));
+ return (NULL);
+}
+
+void
+aout_close(struct sym_table *st)
+{
+ struct aout_symbol_handle *ash = ST_TO_ASH(st);
+
+ if (ash->ash_fd != -1)
+ close(ash->ash_fd);
+
+ munmap(ash->ash_strtab, ash->ash_strsize);
+ munmap(ash->ash_symtab, ash->ash_symsize);
+ free(ash);
+}
+
+char *
+aout_name_and_off(struct sym_table *st, reg pc, reg *offs)
+{
+ struct aout_symbol_handle *ash = ST_TO_ASH(st);
+ struct nlist *s, *bests = NULL;
+ int bestoff = 0;
+ int nsyms, i;
+ char *symn;
+
+#define SYMVAL(S) (unsigned long)((S)->n_value + ash->ash_offs)
+
+ nsyms = ash->ash_symsize / sizeof(struct nlist);
+
+ bests = NULL;
+ for (i = 0; i < nsyms; i++) {
+ s = &ash->ash_symtab[i];
+
+ if (s->n_value == 0 ||
+ s->n_un.n_strx == 0)
+ continue;
+
+ symn = &ash->ash_strtab[s->n_un.n_strx];
+ if (SYMVAL(s) <= pc && SYMVAL(s) > bestoff &&
+ symn[0] != '\0' && strcmp(symn, "gcc2_compiled.")) {
+ bests = s;
+ bestoff = SYMVAL(s);
+ }
+ }
+
+ if ((s = bests) == NULL)
+ return (NULL);
+
+ *offs = pc - SYMVAL(s);
+
+ return &ash->ash_strtab[s->n_un.n_strx];
+}
+
+static struct nlist *
+aout_lookup_table(struct aout_symbol_handle *ash, const char *name)
+{
+ int nsyms, i;
+ char *symn;
+ struct nlist *s = NULL;
+
+ nsyms = ash->ash_symsize / sizeof(struct nlist);
+ for (i = 0; i < nsyms; i++) {
+ s = &ash->ash_symtab[i];
+ symn = &ash->ash_strtab[s->n_un.n_strx];
+ if (strcmp(name, symn) == 0)
+ break;
+ }
+
+ if (i == nsyms)
+ return (NULL);
+
+ return (s);
+}
+
+int
+aout_lookup(struct pstate *ps, const char *name, reg *res)
+{
+ struct sym_table *st;
+ struct nlist *s;
+ int first = 1;
+ char *sname = (char *)name;
+
+restart:
+ TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
+ if ((s = aout_lookup_table(ST_TO_ASH(st), sname)) != NULL)
+ break;
+ }
+
+ if (!first)
+ free(sname);
+
+ if (s == NULL) {
+ if (first) {
+ asprintf(&sname, "_%s", sname);
+ if (sname != NULL) {
+ first = 0;
+ goto restart;
+ }
+ }
+
+ return (-1);
+ }
+
+ *res = s->n_value + ST_TO_ASH(st)->ash_offs;
+ return (0);
+}
+
+/*
+ * Called after execution started so that we can load any dynamic symbols.
+ */
+void
+aout_update(struct pstate *ps)
+{
+ pid_t pid = ps->ps_pid;
+ struct _dynamic dyn;
+ struct so_debug sdeb;
+ struct section_dispatch_table sdt;
+ struct so_map som;
+ off_t somp;
+ reg addr;
+ struct nlist *s;
+
+ if ((s = aout_lookup_table(ST_TO_ASH(ps->ps_sym_exe), "__DYNAMIC")) == NULL) {
+ warnx("Can't find __DYNAMIC");
+ return;
+ }
+ addr = s->n_value + ST_TO_ASH(ps->ps_sym_exe)->ash_offs;
+
+ if (read_from_pid(pid, addr, &dyn, sizeof(dyn)) < 0) {
+ warn("Can't read __DYNAMIC");
+ return;
+ }
+
+ if (dyn.d_version != LD_VERSION_BSD) {
+ warn("Can't handle __DYNAMIC version %d", dyn.d_version);
+ return;
+ }
+
+ if (read_from_pid(pid, (off_t)(reg)dyn.d_debug, &sdeb, sizeof(sdeb)) < 0) {
+ warn("Can't read __DYNAMIC.d_debug");
+ return;
+ }
+
+ if (sdeb.dd_version != 0) {
+ warn("Can't handle so_debug version %d", sdeb.dd_version);
+ return;
+ }
+
+ if (read_from_pid(pid, (off_t)(reg)dyn.d_un.d_sdt, &sdt, sizeof(sdt)) < 0) {
+ warn("Can't read section dispatch table");
+ return;
+ }
+
+ somp = (off_t)(reg)sdt.sdt_loaded;
+ while (somp) {
+ struct sym_table *st;
+ char fname[MAXPATHLEN];
+ int i;
+
+ if (read_from_pid(pid, somp, &som, sizeof(som)) < 0) {
+ warn("Can't read so_map");
+ break;
+ }
+ somp = (off_t)(reg)som.som_next;
+ if (read_from_pid(pid, (off_t)(reg)som.som_path, fname,
+ sizeof(fname)) < 0) {
+ warn("Can't read so filename");
+ continue;
+ }
+
+ /* sanity check the file name */
+ for (i = 0; i < MAXPATHLEN; i++)
+ if (fname[i] == '\0')
+ break;
+ if (i == MAXPATHLEN) {
+ warnx("so filename invalid");
+ continue;
+ }
+
+ st = st_open(ps, fname);
+ if (st == NULL) {
+ warn("symbol loading failed");
+ continue;
+ }
+ ST_TO_ASH(st)->ash_offs = (int)som.som_addr;
+ }
+}
diff --git a/usr.bin/pmdb/arch/alpha/Makefile.inc b/usr.bin/pmdb/arch/alpha/Makefile.inc
new file mode 100644
index 00000000000..90bf092b2e2
--- /dev/null
+++ b/usr.bin/pmdb/arch/alpha/Makefile.inc
@@ -0,0 +1 @@
+SRCS+=alpha.c alpha_trace.c
diff --git a/usr.bin/pmdb/arch/alpha/alpha.c b/usr.bin/pmdb/arch/alpha/alpha.c
new file mode 100644
index 00000000000..a09f59f036e
--- /dev/null
+++ b/usr.bin/pmdb/arch/alpha/alpha.c
@@ -0,0 +1,70 @@
+/* $PMDB: alpha.c,v 1.4 2002/02/21 02:20:51 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/param.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+
+#include <string.h>
+
+#include "pmdb.h"
+
+/*
+ * This happens to be the same order as in struct reg.
+ */
+
+static const char *md_reg_names[] = {
+ "v0",
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6",
+ "a0", "a1", "a2", "a3", "a4", "a5",
+ "t8", "t9", "t10", "t11",
+ "ra",
+ "t12",
+ "at", "gp", "sp", "zero"
+};
+
+struct md_def md_def = { md_reg_names, 32, 31 };
+
+void
+md_def_init(void)
+{
+ /* nothing */
+}
+
+int
+md_getregs(struct pstate *ps, reg *regs)
+{
+ struct reg r;
+
+ if (ptrace(PT_GETREGS, ps->ps_pid, (caddr_t)&r, 0) != 0)
+ return -1;
+
+ memcpy(regs, &r, sizeof(r));
+
+ return 0;
+} \ No newline at end of file
diff --git a/usr.bin/pmdb/arch/alpha/alpha_instruction.h b/usr.bin/pmdb/arch/alpha/alpha_instruction.h
new file mode 100644
index 00000000000..631aad909ea
--- /dev/null
+++ b/usr.bin/pmdb/arch/alpha/alpha_instruction.h
@@ -0,0 +1,750 @@
+/* $PMDB: alpha_instruction.h,v 1.3 2002/01/30 23:14:34 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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.
+ */
+
+/*
+ * Copyright (c) 1999 Christopher G. Demetriou. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * 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.
+ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * File: alpha_instruction.h
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 11/91
+ *
+ * Alpha Instruction set definition
+ *
+ * Reference: "Alpha System Reference Manual", V4.0, April 1991
+ *
+ */
+
+#ifndef _ALPHA_INSTRUCTION_H_
+#define _ALPHA_INSTRUCTION_H_ 1
+
+#if !defined(ASSEMBLER)
+
+/*
+ * All instructions are in one of five formats:
+ * Memory, Branch, Operate, Floating-point Operate, PAL
+ *
+ * The original Mach sources attempted to use 'smarter' names
+ * for registers, which reflected source and destination. These
+ * definitions use the names from the Architecture Reference Manual,
+ * both for clarity and because you can't differentiate between
+ * 'source' and 'destinations' for some types of instructions (loads
+ * and stores; they'd be correct for one, but swapped for the other).
+ */
+
+
+typedef union {
+ /*
+ * All instructions are 32 bits wide
+ */
+ unsigned int bits;
+
+ /*
+ * Generic instruction pseudo format; look at
+ * opcode to see how to interpret the rest.
+ */
+ struct {
+ unsigned bits:26,
+ opcode:6;
+ } generic_format;
+
+ /*
+ * Memory instructions contain a 16 bit
+ * signed immediate value and two register
+ * specifiers
+ */
+ struct {
+ signed short displacement;
+ unsigned rb : 5,
+ ra : 5,
+ opcode : 6;
+ } mem_format;
+
+ /*
+ * Branch instruction contain a 21 bit offset,
+ * which is sign-extended, shifted and combined
+ * with the PC to form a 64 bit destination address.
+ *
+ * In computed jump instructions the opcode is further
+ * specified in the offset field, the rest of it is
+ * used as branch target hint. The destination of the
+ * jump is the source register.
+ */
+ struct {
+ signed int displacement : 21;
+ unsigned ra : 5,
+ opcode : 6;
+ } branch_format;
+
+ struct {
+ signed int hint : 14;
+ unsigned action : 2,
+ rb : 5,
+ ra : 5,
+ opcode : 6;
+ } jump_format;
+
+
+ /*
+ * Operate instructions are of two types, with
+ * a second source register or with a literal
+ * specifier. Bit 12 sez which is which.
+ */
+ struct {
+ unsigned rc : 5,
+ function : 7,
+ is_lit : 1,
+ sbz_or_litlo : 3,
+ rb_or_lithi : 5,
+ ra : 5,
+ opcode : 6;
+ } operate_generic_format;
+
+ struct {
+ unsigned rc : 5,
+ function : 7,
+ zero : 1,
+ sbz : 3,
+ rb : 5,
+ ra : 5,
+ opcode : 6;
+ } operate_reg_format;
+
+ struct {
+ unsigned rc : 5,
+ function : 7,
+ one : 1,
+ literal : 8,
+ ra : 5,
+ opcode : 6;
+ } operate_lit_format;
+
+
+ /*
+ * Floating point operate instruction are quite
+ * uniform in the encoding. As for the semantics..
+ */
+ struct {
+ unsigned fc : 5,
+ function : 11,
+ fb : 5,
+ fa : 5,
+ opcode : 6;
+ } float_format;
+
+
+ /*
+ * PAL instructions just define the major opcode
+ */
+
+ struct {
+ unsigned function : 26,
+ opcode : 6;
+ } pal_format;
+
+} alpha_instruction;
+
+#endif /* !defined(ASSEMBLER) */
+
+/*
+ *
+ * Encoding of regular instructions (Appendix C op cit)
+ *
+ */
+
+ /* OPCODE, bits 26..31 */
+
+#define op_pal 0x00 /* see PAL sub-table */
+ /* 1..7 reserved */
+#define op_lda 0x08
+#define op_ldah 0x09
+#define op_ldbu 0x0a
+#define op_ldq_u 0x0b
+#define op_ldwu 0x0c
+#define op_stw 0x0d
+#define op_stb 0x0e
+#define op_stq_u 0x0f
+
+#define op_arit 0x10 /* see ARIT sub-table */
+#define op_logical 0x11 /* see LOGICAL sub-table */
+#define op_bit 0x12 /* see BIT sub-table */
+#define op_mul 0x13 /* see MUL sub-table */
+ /* reserved */
+#define op_vax_float 0x15 /* see FLOAT sub-table */
+#define op_ieee_float 0x16 /* see FLOAT sub-table */
+#define op_any_float 0x17 /* see FLOAT sub-table */
+
+#define op_special 0x18 /* see SPECIAL sub-table */
+#define op_pal19 0x19 /* reserved for pal code */
+#define op_j 0x1a /* see JUMP sub-table */
+#define op_pal1b 0x1b /* reserved for pal code */
+#define op_intmisc 0x1c /* see INTMISC sub-table */
+#define op_pal1d 0x1d /* reserved for pal code */
+#define op_pal1e 0x1e /* reserved for pal code */
+#define op_pal1f 0x1f /* reserved for pal code */
+
+#define op_ldf 0x20
+#define op_ldg 0x21
+#define op_lds 0x22
+#define op_ldt 0x23
+#define op_stf 0x24
+#define op_stg 0x25
+#define op_sts 0x26
+#define op_stt 0x27
+#define op_ldl 0x28
+#define op_ldq 0x29
+#define op_ldl_l 0x2a
+#define op_ldq_l 0x2b
+#define op_stl 0x2c
+#define op_stq 0x2d
+#define op_stl_c 0x2e
+#define op_stq_c 0x2f
+#define op_br 0x30
+#define op_fbeq 0x31
+#define op_fblt 0x32
+#define op_fble 0x33
+#define op_bsr 0x34
+#define op_fbne 0x35
+#define op_fbge 0x36
+#define op_fbgt 0x37
+#define op_blbc 0x38
+#define op_beq 0x39
+#define op_blt 0x3a
+#define op_ble 0x3b
+#define op_blbs 0x3c
+#define op_bne 0x3d
+#define op_bge 0x3e
+#define op_bgt 0x3f
+
+
+ /* PAL, "function" opcodes (bits 0..25) */
+/*
+ * What we will implement is TBD. These are the unprivileged ones
+ * that we probably have to support for compat reasons.
+ */
+
+/* See <machine/pal.h> */
+
+ /* ARIT, "function" opcodes (bits 5..11) */
+
+#define op_addl 0x00
+#define op_s4addl 0x02
+#define op_subl 0x09
+#define op_s4subl 0x0b
+#define op_cmpbge 0x0f
+#define op_s8addl 0x12
+#define op_s8subl 0x1b
+#define op_cmpult 0x1d
+#define op_addq 0x20
+#define op_s4addq 0x22
+#define op_subq 0x29
+#define op_s4subq 0x2b
+#define op_cmpeq 0x2d
+#define op_s8addq 0x32
+#define op_s8subq 0x3b
+#define op_cmpule 0x3d
+#define op_addl_v 0x40
+#define op_subl_v 0x49
+#define op_cmplt 0x4d
+#define op_addq_v 0x60
+#define op_subq_v 0x69
+#define op_cmple 0x6d
+
+
+ /* LOGICAL, "function" opcodes (bits 5..11) */
+
+#define op_and 0x00
+#define op_andnot 0x08 /* bic */
+#define op_cmovlbs 0x14
+#define op_cmovlbc 0x16
+#define op_or 0x20 /* bis */
+#define op_cmoveq 0x24
+#define op_cmovne 0x26
+#define op_ornot 0x28
+#define op_xor 0x40
+#define op_cmovlt 0x44
+#define op_cmovge 0x46
+#define op_xornot 0x48 /* eqv */
+#define op_amask 0x61
+#define op_cmovle 0x64
+#define op_cmovgt 0x66
+#define op_implver 0x6c
+
+ /* BIT, "function" opcodes (bits 5..11) */
+
+#define op_mskbl 0x02
+#define op_extbl 0x06
+#define op_insbl 0x0b
+#define op_mskwl 0x12
+#define op_extwl 0x16
+#define op_inswl 0x1b
+#define op_mskll 0x22
+#define op_extll 0x26
+#define op_insll 0x2b
+#define op_zap 0x30
+#define op_zapnot 0x31
+#define op_mskql 0x32
+#define op_srl 0x34
+#define op_extql 0x36
+#define op_sll 0x39
+#define op_insql 0x3b
+#define op_sra 0x3c
+#define op_mskwh 0x52
+#define op_inswh 0x57
+#define op_extwh 0x5a
+#define op_msklh 0x62
+#define op_inslh 0x67
+#define op_extlh 0x6a
+#define op_extqh 0x7a
+#define op_insqh 0x77
+#define op_mskqh 0x72
+
+ /* MUL, "function" opcodes (bits 5..11) */
+
+#define op_mull 0x00
+#define op_mulq_v 0x60
+#define op_mull_v 0x40
+#define op_umulh 0x30
+#define op_mulq 0x20
+
+
+ /* SPECIAL, "displacement" opcodes (bits 0..15) */
+
+#define op_trapb 0x0000
+#define op_excb 0x0400
+#define op_mb 0x4000
+#define op_wmb 0x4400
+#define op_fetch 0x8000
+#define op_fetch_m 0xa000
+#define op_rpcc 0xc000
+#define op_rc 0xe000
+#define op_ecb 0xe800
+#define op_rs 0xf000
+#define op_wh64 0xf800
+
+ /* JUMP, "action" opcodes (bits 14..15) */
+
+#define op_jmp 0x0
+#define op_jsr 0x1
+#define op_ret 0x2
+#define op_jcr 0x3
+
+ /* INTMISC, "function" opcodes (operate format) */
+
+#define op_sextb 0x00
+#define op_sextw 0x01
+#define op_ctpop 0x30
+#define op_perr 0x31
+#define op_ctlz 0x32
+#define op_cttz 0x33
+#define op_unpkbw 0x34
+#define op_unpkbl 0x35
+#define op_pkwb 0x36
+#define op_pklb 0x37
+#define op_minsb8 0x38
+#define op_minsw4 0x39
+#define op_minub8 0x3a
+#define op_minuw4 0x3b
+#define op_maxub8 0x3c
+#define op_maxuw4 0x3d
+#define op_maxsb8 0x3e
+#define op_maxsw4 0x3f
+#define op_ftoit 0x70
+#define op_ftois 0x78
+
+/*
+ *
+ * Encoding of floating point instructions (pagg. C-5..6 op cit)
+ *
+ * Load and store operations use opcodes op_ldf..op_stt
+ */
+
+ /* any FLOAT, "function" opcodes (bits 5..11) */
+
+#define op_cvtlq 0x010
+#define op_cpys 0x020
+#define op_cpysn 0x021
+#define op_cpyse 0x022
+#define op_mt_fpcr 0x024
+#define op_mf_fpcr 0x025
+#define op_fcmoveq 0x02a
+#define op_fcmovne 0x02b
+#define op_fcmovlt 0x02c
+#define op_fcmovge 0x02d
+#define op_fcmovle 0x02e
+#define op_fcmovgt 0x02f
+#define op_cvtql 0x030
+#define op_cvtql_v 0x130
+#define op_cvtql_sv 0x330
+
+
+ /* ieee FLOAT, "function" opcodes (bits 5..11) */
+
+#define op_adds_c 0x000
+#define op_subs_c 0x001
+#define op_muls_c 0x002
+#define op_divs_c 0x003
+#define op_addt_c 0x020
+#define op_subt_c 0x021
+#define op_mult_c 0x022
+#define op_divt_c 0x023
+#define op_cvtts_c 0x02c
+#define op_cvttq_c 0x02f
+#define op_cvtqs_c 0x03c
+#define op_cvtqt_c 0x03e
+#define op_adds_m 0x040
+#define op_subs_m 0x041
+#define op_muls_m 0x042
+#define op_divs_m 0x043
+#define op_addt_m 0x060
+#define op_subt_m 0x061
+#define op_mult_m 0x062
+#define op_divt_m 0x063
+#define op_cvtts_m 0x06c
+#define op_cvtqs_m 0x07c
+#define op_cvtqt_m 0x07e
+#define op_adds 0x080
+#define op_subs 0x081
+#define op_muls 0x082
+#define op_divs 0x083
+#define op_addt 0x0a0
+#define op_subt 0x0a1
+#define op_mult 0x0a2
+#define op_divt 0x0a3
+#define op_cmptun 0x0a4
+#define op_cmpteq 0x0a5
+#define op_cmptlt 0x0a6
+#define op_cmptle 0x0a7
+#define op_cvtts 0x0ac
+#define op_cvttq 0x0af
+#define op_cvtqs 0x0bc
+#define op_cvtqt 0x0be
+#define op_adds_d 0x0c0
+#define op_subs_d 0x0c1
+#define op_muls_d 0x0c2
+#define op_divs_d 0x0c3
+#define op_addt_d 0x0e0
+#define op_subt_d 0x0e1
+#define op_mult_d 0x0e2
+#define op_divt_d 0x0e3
+#define op_cvtts_d 0x0ec
+#define op_cvtqs_d 0x0fc
+#define op_cvtqt_d 0x0fe
+#define op_adds_uc 0x100
+#define op_subs_uc 0x101
+#define op_muls_uc 0x102
+#define op_divs_uc 0x103
+#define op_addt_uc 0x120
+#define op_subt_uc 0x121
+#define op_mult_uc 0x122
+#define op_divt_uc 0x123
+#define op_cvtts_uc 0x12c
+#define op_cvttq_vc 0x12f
+#define op_adds_um 0x140
+#define op_subs_um 0x141
+#define op_muls_um 0x142
+#define op_divs_um 0x143
+#define op_addt_um 0x160
+#define op_subt_um 0x161
+#define op_mult_um 0x162
+#define op_divt_um 0x163
+#define op_cvtts_um 0x16c
+#define op_adds_u 0x180
+#define op_subs_u 0x181
+#define op_muls_u 0x182
+#define op_divs_u 0x183
+#define op_addt_u 0x1a0
+#define op_subt_u 0x1a1
+#define op_mult_u 0x1a2
+#define op_divt_u 0x1a3
+#define op_cvtts_u 0x1ac
+#define op_cvttq_v 0x1af
+#define op_adds_ud 0x1c0
+#define op_subs_ud 0x1c1
+#define op_muls_ud 0x1c2
+#define op_divs_ud 0x1c3
+#define op_addt_ud 0x1e0
+#define op_subt_ud 0x1e1
+#define op_mult_ud 0x1e2
+#define op_divt_ud 0x1e3
+#define op_cvtts_ud 0x1ec
+#define op_adds_suc 0x500
+#define op_subs_suc 0x501
+#define op_muls_suc 0x502
+#define op_divs_suc 0x503
+#define op_addt_suc 0x520
+#define op_subt_suc 0x521
+#define op_mult_suc 0x522
+#define op_divt_suc 0x523
+#define op_cvtts_suc 0x52c
+#define op_cvttq_svc 0x52f
+#define op_adds_sum 0x540
+#define op_subs_sum 0x541
+#define op_muls_sum 0x542
+#define op_divs_sum 0x543
+#define op_addt_sum 0x560
+#define op_subt_sum 0x561
+#define op_mult_sum 0x562
+#define op_divt_sum 0x563
+#define op_cvtts_sum 0x56c
+#define op_adds_su 0x580
+#define op_subs_su 0x581
+#define op_muls_su 0x582
+#define op_divs_su 0x583
+#define op_addt_su 0x5a0
+#define op_subt_su 0x5a1
+#define op_mult_su 0x5a2
+#define op_divt_su 0x5a3
+#define op_cmptun_su 0x5a4
+#define op_cmpteq_su 0x5a5
+#define op_cmptlt_su 0x5a6
+#define op_cmptle_su 0x5a7
+#define op_cvtts_su 0x5ac
+#define op_cvttq_sv 0x5af
+#define op_adds_sud 0x5c0
+#define op_subs_sud 0x5c1
+#define op_muls_sud 0x5c2
+#define op_divs_sud 0x5c3
+#define op_addt_sud 0x5e0
+#define op_subt_sud 0x5e1
+#define op_mult_sud 0x5e2
+#define op_divt_sud 0x5e3
+#define op_cvtts_sud 0x5ec
+#define op_adds_suic 0x700
+#define op_subs_suic 0x701
+#define op_muls_suic 0x702
+#define op_divs_suic 0x703
+#define op_addt_suic 0x720
+#define op_subt_suic 0x721
+#define op_mult_suic 0x722
+#define op_divt_suic 0x723
+#define op_cvtts_suic 0x72c
+#define op_cvttq_svic 0x72f
+#define op_cvtqs_suic 0x73c
+#define op_cvtqt_suic 0x73e
+#define op_adds_suim 0x740
+#define op_subs_suim 0x741
+#define op_muls_suim 0x742
+#define op_divs_suim 0x743
+#define op_addt_suim 0x760
+#define op_subt_suim 0x761
+#define op_mult_suim 0x762
+#define op_divt_suim 0x763
+#define op_cvtts_suim 0x76c
+#define op_cvtqs_suim 0x77c
+#define op_cvtqt_suim 0x77e
+#define op_adds_sui 0x780
+#define op_subs_sui 0x781
+#define op_muls_sui 0x782
+#define op_divs_sui 0x783
+#define op_addt_sui 0x7a0
+#define op_subt_sui 0x7a1
+#define op_mult_sui 0x7a2
+#define op_divt_sui 0x7a3
+#define op_cvtts_sui 0x7ac
+#define op_cvttq_svi 0x7af
+#define op_cvtqs_sui 0x7bc
+#define op_cvtqt_sui 0x7be
+#define op_adds_suid 0x7c0
+#define op_subs_suid 0x7c1
+#define op_muls_suid 0x7c2
+#define op_divs_suid 0x7c3
+#define op_addt_suid 0x7e0
+#define op_subt_suid 0x7e1
+#define op_mult_suid 0x7e2
+#define op_divt_suid 0x7e3
+#define op_cvtts_suid 0x7ec
+#define op_cvtqs_suid 0x7fc
+#define op_cvtqt_suid 0x7fe
+
+
+ /* vax FLOAT, "function" opcodes (bits 5..11) */
+
+#define op_addf_c 0x000
+#define op_subf_c 0x001
+#define op_mulf_c 0x002
+#define op_divf_c 0x003
+#define op_cvtdg_c 0x01e
+#define op_addg_c 0x020
+#define op_subg_c 0x021
+#define op_mulg_c 0x022
+#define op_divg_c 0x023
+#define op_cvtgf_c 0x02c
+#define op_cvtgd_c 0x02d
+#define op_cvtgqg_c 0x02f
+#define op_cvtqf_c 0x03c
+#define op_cvtqg_c 0x03e
+#define op_addf 0x080
+#define op_subf 0x081
+#define op_mulf 0x082
+#define op_divf 0x083
+#define op_cvtdg 0x09e
+#define op_addg 0x0a0
+#define op_subg 0x0a1
+#define op_mulg 0x0a2
+#define op_divg 0x0a3
+#define op_cmpgeq 0x0a5
+#define op_cmpglt 0x0a6
+#define op_cmpgle 0x0a7
+#define op_cvtgf 0x0ac
+#define op_cvtgd 0x0ad
+#define op_cvtgq 0x0af
+#define op_cvtqf 0x0bc
+#define op_cvtqg 0x0be
+#define op_addf_uc 0x100
+#define op_subf_uc 0x101
+#define op_mulf_uc 0x102
+#define op_divf_uc 0x103
+#define op_cvtdg_uc 0x11e
+#define op_addg_uc 0x120
+#define op_subg_uc 0x121
+#define op_mulg_uc 0x122
+#define op_divg_uc 0x123
+#define op_cvtgf_uc 0x12c
+#define op_cvtgd_uc 0x12d
+#define op_cvtgqg_vc 0x12f
+#define op_addf_u 0x180
+#define op_subf_u 0x181
+#define op_mulf_u 0x182
+#define op_divf_u 0x183
+#define op_cvtdg_u 0x19e
+#define op_addg_u 0x1a0
+#define op_subg_u 0x1a1
+#define op_mulg_u 0x1a2
+#define op_divg_u 0x1a3
+#define op_cvtgf_u 0x1ac
+#define op_cvtgd_u 0x1ad
+#define op_cvtgqg_v 0x1af
+#define op_addf_sc 0x400
+#define op_subf_sc 0x401
+#define op_mulf_sc 0x402
+#define op_divf_sc 0x403
+#define op_cvtdg_sc 0x41e
+#define op_addg_sc 0x420
+#define op_subg_sc 0x421
+#define op_mulg_sc 0x422
+#define op_divg_sc 0x423
+#define op_cvtgf_sc 0x42c
+#define op_cvtgd_sc 0x42d
+#define op_cvtgqg_sc 0x42f
+#define op_cvtqf_sc 0x43c
+#define op_cvtqg_sc 0x43e
+#define op_addf_s 0x480
+#define op_subf_s 0x481
+#define op_mulf_s 0x482
+#define op_divf_s 0x483
+#define op_cvtdg_s 0x49e
+#define op_addg_s 0x4a0
+#define op_subg_s 0x4a1
+#define op_mulg_s 0x4a2
+#define op_divg_s 0x4a3
+#define op_cmpgeq_s 0x4a5
+#define op_cmpglt_s 0x4a6
+#define op_cmpgle_s 0x4a7
+#define op_cvtgf_s 0x4ac
+#define op_cvtgd_s 0x4ad
+#define op_cvtgqg_s 0x4af
+#define op_cvtqf_s 0x4bc
+#define op_cvtqg_s 0x4be
+#define op_addf_suc 0x500
+#define op_subf_suc 0x501
+#define op_mulf_suc 0x502
+#define op_divf_suc 0x503
+#define op_cvtdg_suc 0x51e
+#define op_addg_suc 0x520
+#define op_subg_suc 0x521
+#define op_mulg_suc 0x522
+#define op_divg_suc 0x523
+#define op_cvtgf_suc 0x52c
+#define op_cvtgd_suc 0x52d
+#define op_cvtgqg_svc 0x52f
+#define op_addf_su 0x580
+#define op_subf_su 0x581
+#define op_mulf_su 0x582
+#define op_divf_su 0x583
+#define op_cvtdg_su 0x59e
+#define op_addg_su 0x5a0
+#define op_subg_su 0x5a1
+#define op_mulg_su 0x5a2
+#define op_divg_su 0x5a3
+#define op_cvtgf_su 0x5ac
+#define op_cvtgd_su 0x5ad
+#define op_cvtgqg_sv 0x5af
+
+#endif /* _ALPHA_INSTRUCTION_H_ */
diff --git a/usr.bin/pmdb/arch/alpha/alpha_trace.c b/usr.bin/pmdb/arch/alpha/alpha_trace.c
new file mode 100644
index 00000000000..a0c4f6c73bd
--- /dev/null
+++ b/usr.bin/pmdb/arch/alpha/alpha_trace.c
@@ -0,0 +1,343 @@
+/* $PMDB: alpha_trace.c,v 1.5 2002/03/10 10:52:16 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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.
+ */
+
+/*
+ * Copyright (c) 1997 Niklas Hallqvist. All rights reserverd.
+ * Copyright (c) 1997 Theo de Raadt. All rights reserverd.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niklas Hallqvist and
+ * Theo de Raadt.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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/param.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pmdb.h"
+#include "alpha_instruction.h"
+#include "symbol.h"
+
+struct opcode {
+ enum opc_fmt { OPC_PAL, OPC_RES, OPC_MEM, OPC_OP, OPC_BR } opc_fmt;
+ char *opc_name;
+ int opc_print;
+};
+
+#define inst_return(ins) (((ins) & 0xfc000000) == 0x68000000)
+
+const struct opcode opcode[] = {
+ { OPC_PAL, "call_pal", 0 }, /* 00 */
+ { OPC_RES, "opc01", 0 }, /* 01 */
+ { OPC_RES, "opc02", 0 }, /* 02 */
+ { OPC_RES, "opc03", 0 }, /* 03 */
+ { OPC_RES, "opc04", 0 }, /* 04 */
+ { OPC_RES, "opc05", 0 }, /* 05 */
+ { OPC_RES, "opc06", 0 }, /* 06 */
+ { OPC_RES, "opc07", 0 }, /* 07 */
+ { OPC_MEM, "lda", 1 }, /* 08 */
+ { OPC_MEM, "ldah", 1 }, /* 09 */
+ { OPC_RES, "opc0a", 0 }, /* 0A */
+ { OPC_MEM, "ldq_u", 1 }, /* 0B */
+ { OPC_RES, "opc0c", 0 }, /* 0C */
+ { OPC_RES, "opc0d", 0 }, /* 0D */
+ { OPC_RES, "opc0e", 0 }, /* 0E */
+ { OPC_MEM, "stq_u", 1 }, /* 0F */
+ { OPC_OP, "inta", 0 }, /* 10 */
+ { OPC_OP, "intl", 0 }, /* 11 */
+ { OPC_OP, "ints", 0 }, /* 12 */
+ { OPC_OP, "intm", 0 }, /* 13 */
+ { OPC_RES, "opc14", 0 }, /* 14 */
+ { OPC_OP, "fltv", 1 }, /* 15 */
+ { OPC_OP, "flti", 1 }, /* 16 */
+ { OPC_OP, "fltl", 1 }, /* 17 */
+ { OPC_MEM, "misc", 0 }, /* 18 */
+ { OPC_PAL, "pal19", 0 }, /* 19 */
+ { OPC_MEM, "jsr", 0 }, /* 1A */
+ { OPC_PAL, "pal1b", 0 }, /* 1B */
+ { OPC_RES, "opc1c", 0 }, /* 1C */
+ { OPC_PAL, "pal1d", 0 }, /* 1D */
+ { OPC_PAL, "pal1e", 0 }, /* 1E */
+ { OPC_PAL, "pal1f", 0 }, /* 1F */
+ { OPC_MEM, "ldf", 1 }, /* 20 */
+ { OPC_MEM, "ldg", 1 }, /* 21 */
+ { OPC_MEM, "lds", 1 }, /* 22 */
+ { OPC_MEM, "ldt", 1 }, /* 23 */
+ { OPC_MEM, "stf", 1 }, /* 24 */
+ { OPC_MEM, "stg", 1 }, /* 25 */
+ { OPC_MEM, "sts", 1 }, /* 26 */
+ { OPC_MEM, "stt", 1 }, /* 27 */
+ { OPC_MEM, "ldl", 1 }, /* 28 */
+ { OPC_MEM, "ldq", 1 }, /* 29 */
+ { OPC_MEM, "ldl_l", 1 }, /* 2A */
+ { OPC_MEM, "ldq_l", 1 }, /* 2B */
+ { OPC_MEM, "stl", 1 }, /* 2C */
+ { OPC_MEM, "stq", 1 }, /* 2D */
+ { OPC_MEM, "stl_c", 1 }, /* 2E */
+ { OPC_MEM, "stq_c", 1 }, /* 2F */
+ { OPC_BR, "br", 1 }, /* 30 */
+ { OPC_BR, "fbeq", 1 }, /* 31 */
+ { OPC_BR, "fblt", 1 }, /* 32 */
+ { OPC_BR, "fble", 1 }, /* 33 */
+ { OPC_BR, "bsr", 1 }, /* 34 */
+ { OPC_BR, "fbne", 1 }, /* 35 */
+ { OPC_BR, "fbge", 1 }, /* 36 */
+ { OPC_BR, "fbgt", 1 }, /* 37 */
+ { OPC_BR, "blbc", 1 }, /* 38 */
+ { OPC_BR, "beq", 1 }, /* 39 */
+ { OPC_BR, "blt", 1 }, /* 3A */
+ { OPC_BR, "ble", 1 }, /* 3B */
+ { OPC_BR, "blbs", 1 }, /* 3C */
+ { OPC_BR, "bne", 1 }, /* 3D */
+ { OPC_BR, "bge", 1 }, /* 3E */
+ { OPC_BR, "bgt", 1 }, /* 3F */
+};
+
+int
+inst_load(int ins)
+{
+ alpha_instruction insn;
+
+ insn.bits = ins;
+
+ /* Loads. */
+ if (insn.mem_format.opcode == op_ldbu ||
+ insn.mem_format.opcode == op_ldq_u ||
+ insn.mem_format.opcode == op_ldwu)
+ return (1);
+ if ((insn.mem_format.opcode >= op_ldf) &&
+ (insn.mem_format.opcode <= op_ldt))
+ return (1);
+ if ((insn.mem_format.opcode >= op_ldl) &&
+ (insn.mem_format.opcode <= op_ldq_l))
+ return (1);
+
+ /* Prefetches. */
+ if (insn.mem_format.opcode == op_special) {
+ /* Note: MB is treated as a store. */
+ if ((insn.mem_format.displacement == (short)op_fetch) ||
+ (insn.mem_format.displacement == (short)op_fetch_m))
+ return (1);
+ }
+
+ return (0);
+}
+
+static __inline int sext __P((u_int));
+static __inline int rega __P((u_int));
+static __inline int regb __P((u_int));
+static __inline int regc __P((u_int));
+static __inline int disp __P((u_int));
+
+static __inline int
+sext(x)
+ u_int x;
+{
+ return ((x & 0x8000) ? -(-x & 0xffff) : (x & 0xffff));
+}
+
+static __inline int
+rega(x)
+ u_int x;
+{
+ return ((x >> 21) & 0x1f);
+}
+
+static __inline int
+regb(x)
+ u_int x;
+{
+ return ((x >> 16) & 0x1f);
+}
+
+static __inline int
+regc(x)
+ u_int x;
+{
+ return (x & 0x1f);
+}
+
+static __inline int
+disp(x)
+ u_int x;
+{
+ return (sext(x & 0xffff));
+}
+
+/*
+ * XXX There are a couple of problems with this code:
+ *
+ * The argument list printout code is likely to get confused.
+ *
+ * It relies on the conventions of gcc code generation.
+ *
+ * It uses heuristics to calculate the framesize, and might get it wrong.
+ *
+ * It doesn't yet use the framepointer if available.
+ *
+ * The address argument can only be used for pointing at trapframes
+ * since a frame pointer of its own serves no good on the alpha,
+ * you need a pc value too.
+ *
+ * The heuristics used for tracing through a trap relies on having
+ * symbols available.
+ */
+int
+md_getframe(struct pstate *ps, int framec, struct md_frame *fram)
+{
+ reg frame;
+ int i, framesize;
+ reg pc, ra;
+ u_int inst;
+ char *name;
+ char namebuf[1024];
+ reg offset;
+ reg slot[32];
+ struct reg regs;
+ int count;
+
+ bzero(slot, sizeof(slot));
+
+ if (ptrace(PT_GETREGS, ps->ps_pid, (caddr_t)&regs, 0) != 0)
+ return -1;
+
+ for (i = 0; i < 32; i++)
+ slot[i] = -1;
+
+ frame = regs.r_regs[R_SP];
+ pc = regs.r_regs[R_ZERO]; /* Ieeek. on drugs. */
+ ra = regs.r_regs[R_RA];
+
+ for (count = 0; count < framec + 1; count++) {
+ /* XXX - better out of bounds check needed. */
+ if (pc < 0x1000 || pc == 0xffffffffffffffff) {
+ return -1;
+ }
+
+ name = sym_name_and_offset(ps, pc, namebuf,
+ sizeof(namebuf), &offset);
+ if (!name) {
+ /* Limit the search for procedure start */
+ offset = 65536;
+ }
+
+ framesize = 0;
+ for (i = sizeof (int); i <= offset; i += sizeof (int)) {
+ if (read_from_pid(ps->ps_pid, pc - i, &inst, sizeof(inst)) < 0)
+ return -1;
+
+ /*
+ * If by chance we don't have any symbols we have to
+ * get out somehow anyway. Check for the preceding
+ * procedure return in that case.
+ */
+ if (name == NULL && inst_return(inst))
+ break;
+
+ /*
+ * Disassemble to get the needed info for the frame.
+ */
+ if ((inst & 0xffff0000) == 0x23de0000) {
+ /* lda sp,n(sp) */
+ framesize -= disp(inst) / sizeof (u_long);
+ } else if ((inst & 0xfc1f0000) == 0xb41e0000) {
+ /* stq X,n(sp) */
+ slot[rega(inst)] = frame + disp(inst);
+ } else if ((inst & 0xfc000fe0) == 0x44000400 &&
+ rega(inst) == regb(inst)) {
+ /* bis X,X,Y (aka mov X,Y) */
+ /* zero is hardwired */
+ if (rega(inst) != 31)
+ slot[rega(inst)] = slot[regc(inst)];
+ slot[regc(inst)] = 0;
+ /*
+ * XXX In here we might special case a frame
+ * pointer setup, i.e. mov sp, fp.
+ */
+ } else if (inst_load(inst)) {
+ /* clobbers a register */
+ slot[rega(inst)] = 0;
+ } else if (opcode[inst >> 26].opc_fmt == OPC_OP) {
+ /* clobbers a register */
+ slot[regc(inst)] = 0;
+ }
+ /*
+ * XXX Recognize more reg clobbering instructions and
+ * set slot[reg] = 0 then too.
+ */
+ }
+
+ fram->pc = pc;
+ fram->fp = frame;
+
+ /* Look for the return address if recorded. */
+ if (slot[R_RA]) {
+ if (slot[R_RA] == -1)
+ ra = regs.r_regs[R_RA];
+ else
+ if (read_from_pid(ps->ps_pid, (off_t)slot[R_RA],
+ &ra, sizeof(ra)) < 0)
+ return -1;
+ } else {
+ break;
+ }
+
+ /* Advance to the next frame. */
+ frame += framesize * sizeof(u_long);
+ if (pc == ra) {
+ break;
+ }
+ pc = ra;
+ }
+
+ return count == framec + 1 ? 0 : -1;
+}
diff --git a/usr.bin/pmdb/arch/alpha/pmdb_machdep.h b/usr.bin/pmdb/arch/alpha/pmdb_machdep.h
new file mode 100644
index 00000000000..6ff260d09d0
--- /dev/null
+++ b/usr.bin/pmdb/arch/alpha/pmdb_machdep.h
@@ -0,0 +1,3 @@
+#define BREAKPOINT { 0x80, 0, 0, 0 }
+#define BREAKPOINT_LEN 4
+#define BREAKPOINT_DECR_PC 4
diff --git a/usr.bin/pmdb/arch/i386/Makefile.inc b/usr.bin/pmdb/arch/i386/Makefile.inc
new file mode 100644
index 00000000000..7226cf7cbb4
--- /dev/null
+++ b/usr.bin/pmdb/arch/i386/Makefile.inc
@@ -0,0 +1,3 @@
+# $PMDB: Makefile.inc,v 1.2 2002/01/30 23:20:13 fgs Exp $
+
+SRCS+= i386.c
diff --git a/usr.bin/pmdb/arch/i386/i386.c b/usr.bin/pmdb/arch/i386/i386.c
new file mode 100644
index 00000000000..2612ef63568
--- /dev/null
+++ b/usr.bin/pmdb/arch/i386/i386.c
@@ -0,0 +1,91 @@
+/* $PMDB: i386.c,v 1.5 2002/02/21 01:54:44 art Exp $ */
+/*
+ * Copyright (c) 2002 Federico Schwindt <fgsch@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/param.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+#include "pmdb.h"
+
+/*
+ * No frame for x86?
+ */
+struct frame {
+ int fp;
+ int pc;
+};
+
+static const char *md_reg_names[] = {
+ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi", "%eip",
+ "%eflags", "%cs", "%ss", "%ds", "%es", "%fs", "%gs"
+};
+
+struct md_def md_def = { md_reg_names, 16, 8 };
+
+void
+md_def_init(void)
+{
+ /* no need to do anything */
+}
+
+int
+md_getframe(struct pstate *ps, int frame, struct md_frame *fram)
+{
+ struct frame fr;
+ struct reg r;
+ int count;
+
+ if (ptrace(PT_GETREGS, ps->ps_pid, (caddr_t)&r, 0) != 0)
+ return (-1);
+
+ fr.fp = r.r_ebp;
+ fr.pc = r.r_eip;
+ for (count = 0; count < frame; count++) {
+ if (read_from_pid(ps->ps_pid, fr.fp, &fr, sizeof(fr)) < 0)
+ return (-1);
+
+ if (fr.pc < 0x1000)
+ return (-1);
+ }
+
+ fram->pc = fr.pc;
+ fram->fp = fr.fp;
+
+ return 0;
+}
+
+int
+md_getregs(struct pstate *ps, reg *regs)
+{
+ struct reg r;
+
+ if (ptrace(PT_GETREGS, ps->ps_pid, (caddr_t)&r, 0) != 0)
+ return -1;
+
+ memcpy(regs, &r, sizeof(r));
+
+ return 0;
+}
diff --git a/usr.bin/pmdb/arch/i386/pmdb_machdep.h b/usr.bin/pmdb/arch/i386/pmdb_machdep.h
new file mode 100644
index 00000000000..9c25e38ee6f
--- /dev/null
+++ b/usr.bin/pmdb/arch/i386/pmdb_machdep.h
@@ -0,0 +1,3 @@
+#define BREAKPOINT { 0xcc }
+#define BREAKPOINT_LEN 1
+#define BREAKPOINT_DECR_PC 1
diff --git a/usr.bin/pmdb/arch/sparc/Makefile.inc b/usr.bin/pmdb/arch/sparc/Makefile.inc
new file mode 100644
index 00000000000..7e104c0feee
--- /dev/null
+++ b/usr.bin/pmdb/arch/sparc/Makefile.inc
@@ -0,0 +1 @@
+SRCS+=sparc.c
diff --git a/usr.bin/pmdb/arch/sparc/pmdb_machdep.h b/usr.bin/pmdb/arch/sparc/pmdb_machdep.h
new file mode 100644
index 00000000000..d47a3b78c47
--- /dev/null
+++ b/usr.bin/pmdb/arch/sparc/pmdb_machdep.h
@@ -0,0 +1,3 @@
+#define BREAKPOINT { 0x91, 0xd0, 0x20, 0x01 }
+#define BREAKPOINT_LEN 4
+#define BREAKPOINT_DECR_PC 0
diff --git a/usr.bin/pmdb/arch/sparc/sparc.c b/usr.bin/pmdb/arch/sparc/sparc.c
new file mode 100644
index 00000000000..70aeb7687b8
--- /dev/null
+++ b/usr.bin/pmdb/arch/sparc/sparc.c
@@ -0,0 +1,107 @@
+/* $PMDB: sparc.c,v 1.4 2002/03/05 12:04:26 art Exp $ */
+/*
+ * Copyright (c) 2002 Federico Schwindt <fgsch@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/param.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+#include "pmdb.h"
+
+static const char *md_reg_names[] = {
+ "%pc", "%npc", /* %y */
+ "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o6", "%o7",
+ "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
+};
+
+struct md_def md_def = { md_reg_names, 18, 0 };
+
+#define next_frame(f) ((struct frame*)(f->fr_fp))
+
+void
+md_def_init(void)
+{
+ /* no need to do anything */
+}
+
+int
+md_getframe(struct pstate *ps, int frame, struct md_frame *fram)
+{
+ struct frame fr;
+ struct reg r;
+ reg fp, pc;
+ int i;
+
+ if (ptrace(PT_GETREGS, ps->ps_pid, (caddr_t)&r, 0) != 0)
+ return -1;
+
+ if (frame == 0) {
+ fram->pc = r.r_pc;
+ fram->fp = r.r_out[6];
+ return 0;
+ }
+
+ fp = r.r_out[6];
+ pc = r.r_out[7];
+
+ for (i = 1; i < frame; i++) {
+ if (fp < 8192 || (fp & 7) != 0)
+ return -1;
+
+ if (read_from_pid(ps->ps_pid, fp, &fr, sizeof(fr)) < 0)
+ return -1;
+ fp = (unsigned long)next_frame((&fr));
+ pc = fr.fr_pc;
+ }
+ fram->pc = pc;
+ fram->fp = fp;
+
+ fram->nargs = 6; /* XXX - don't know the real number */
+ for (i = 0; i < 6; i++) {
+ fram->args[i] = fr.fr_arg[i];
+ }
+
+ return 0;
+}
+
+int
+md_getregs(struct pstate *ps, reg *regs)
+{
+ struct reg r;
+ int i;
+
+ if (ptrace(PT_GETREGS, ps->ps_pid, (caddr_t)&r, 0) != 0)
+ return -1;
+ regs[0] = r.r_pc;
+ regs[1] = r.r_npc;
+ for (i = 0; i < 8; i++) {
+ regs[2 + i] = r.r_out[i];
+ }
+ for (i = 0; i < 8; i++) {
+ regs[10 + i] = r.r_global[i];
+ }
+
+ return 0;
+}
diff --git a/usr.bin/pmdb/arch/sparc64/Makefile.inc b/usr.bin/pmdb/arch/sparc64/Makefile.inc
new file mode 100644
index 00000000000..3257538c715
--- /dev/null
+++ b/usr.bin/pmdb/arch/sparc64/Makefile.inc
@@ -0,0 +1 @@
+SRCS+=sparc64.c
diff --git a/usr.bin/pmdb/arch/sparc64/pmdb_machdep.h b/usr.bin/pmdb/arch/sparc64/pmdb_machdep.h
new file mode 100644
index 00000000000..d47a3b78c47
--- /dev/null
+++ b/usr.bin/pmdb/arch/sparc64/pmdb_machdep.h
@@ -0,0 +1,3 @@
+#define BREAKPOINT { 0x91, 0xd0, 0x20, 0x01 }
+#define BREAKPOINT_LEN 4
+#define BREAKPOINT_DECR_PC 0
diff --git a/usr.bin/pmdb/arch/sparc64/sparc64.c b/usr.bin/pmdb/arch/sparc64/sparc64.c
new file mode 100644
index 00000000000..d4f44a56402
--- /dev/null
+++ b/usr.bin/pmdb/arch/sparc64/sparc64.c
@@ -0,0 +1,122 @@
+/* $PMDB: sparc64.c,v 1.6 2002/03/07 01:10:52 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/param.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+#include <machine/frame.h>
+#include "pmdb.h"
+
+static const char *md_reg_names[] = {
+ "%pc", "%npc", /* %y */
+ "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o6", "%o7",
+ "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
+};
+
+struct md_def md_def = { md_reg_names, 18, 0 };
+
+void
+md_def_init(void)
+{
+ /* no need to do anything */
+}
+
+int
+md_getframe(struct pstate *ps, int frame, struct md_frame *fram)
+{
+ struct frame64 fr;
+ struct reg r;
+ reg fp, pc;
+ reg *outs;
+ int i;
+
+ if (ptrace(PT_GETREGS, ps->ps_pid, (caddr_t)&r, 0) != 0)
+ return (-1);
+
+ if (frame == 0) {
+ pc = r.r_pc;
+ fp = r.r_out[6] + BIAS;
+ /*
+ * XXX - we need some kind of heuristics here to decide
+ * if the function has done a save or not and then pick
+ * the in registers. the problem is just that there are
+ * no in registers in PT_GETREGS.
+ */
+ outs = (reg *)&r.r_out;
+ goto out;
+ }
+
+ fp = r.r_out[6] + BIAS;
+ pc = r.r_out[7];
+
+ for (i = 1; i < frame; i++) {
+ /* Too low or unaligned frame pointer? */
+ if (fp < 8192 || (fp & 7) != 0)
+ return (-1);
+
+ if (read_from_pid(ps->ps_pid, fp, &fr, sizeof(fr)) < 0)
+ return -1;
+ fp = (unsigned long)v9next_frame((&fr));
+ pc = fr.fr_pc;
+
+ /* Too low or unaligned pc ? */
+ if ((pc < 8192) || (pc & 3) != 0)
+ return (-1);
+
+ outs = (reg *)&fr.fr_arg;
+ }
+
+out:
+ fram->pc = pc;
+ fram->fp = fp;
+
+ fram->nargs = 6; /* XXX - don't know the real number */
+ for (i = 0; i < 6; i++) {
+ fram->args[i] = fr.fr_arg[i];
+ }
+
+ return 0;
+}
+
+int
+md_getregs(struct pstate *ps, reg *regs)
+{
+ struct reg r;
+ int i;
+
+ if (ptrace(PT_GETREGS, ps->ps_pid, (caddr_t)&r, 0) != 0)
+ return -1;
+ regs[0] = r.r_pc;
+ regs[1] = r.r_npc;
+ for (i = 0; i < 8; i++) {
+ regs[2 + i] = r.r_out[i];
+ }
+ for (i = 0; i < 8; i++) {
+ regs[10 + i] = r.r_global[i];
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/usr.bin/pmdb/break.c b/usr.bin/pmdb/break.c
new file mode 100644
index 00000000000..e7eaa61077a
--- /dev/null
+++ b/usr.bin/pmdb/break.c
@@ -0,0 +1,301 @@
+/* $PMDB: break.c,v 1.7 2002/03/12 11:28:28 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/types.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+
+#include "pmdb.h"
+#include "symbol.h"
+#include "pmdb_machdep.h"
+#include "break.h"
+
+struct callback {
+ TAILQ_ENTRY(callback) cb_list;
+ int (*cb_fun)(struct pstate *, void *);
+ void *cb_arg;
+};
+
+struct breakpoint {
+ TAILQ_ENTRY(breakpoint) bkpt_list;
+ TAILQ_HEAD(,callback) bkpt_cbs; /* list of all callbacks */
+ char bkpt_old[BREAKPOINT_LEN]; /* old contents at bkpt */
+ reg bkpt_pc;
+};
+
+static char bkpt_insn[BREAKPOINT_LEN] = BREAKPOINT;
+
+/*
+ * Find a breakpoint at this address.
+ */
+struct breakpoint *
+bkpt_find_at_pc(struct pstate *ps, reg pc)
+{
+ struct breakpoint *bkpt;
+
+ TAILQ_FOREACH(bkpt, &ps->ps_bkpts, bkpt_list)
+ if (bkpt->bkpt_pc == pc)
+ break;
+
+ return (bkpt);
+}
+
+/*
+ * Enable this breakpoint.
+ */
+static int
+bkpt_enable(struct pstate *ps, struct breakpoint *bkpt)
+{
+ reg pc = bkpt->bkpt_pc;
+
+ if (read_from_pid(ps->ps_pid, pc, &bkpt->bkpt_old, BREAKPOINT_LEN)) {
+ warn("Can't read process contents at 0x%lx", pc);
+ return (-1);
+ }
+ if (write_to_pid(ps->ps_pid, pc, &bkpt_insn, BREAKPOINT_LEN)) {
+ warn("Can't write breakpoint at 0x%lx, attempting backout.", pc);
+ if (write_to_pid(ps->ps_pid, pc, &bkpt->bkpt_old,
+ BREAKPOINT_LEN))
+ warn("Backout failed, process unstable");
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Create a new breakpoint and enable it.
+ */
+int
+bkpt_add_cb(struct pstate *ps, reg pc, int (*fun)(struct pstate *, void *),
+ void *arg)
+{
+ struct breakpoint *bkpt;
+ struct callback *cb;
+
+ if ((bkpt = bkpt_find_at_pc(ps, pc)) == NULL) {
+ bkpt = emalloc(sizeof(*bkpt));
+ TAILQ_INIT(&bkpt->bkpt_cbs);
+ TAILQ_INSERT_TAIL(&ps->ps_bkpts, bkpt, bkpt_list);
+ bkpt->bkpt_pc = pc;
+ if (bkpt_enable(ps, bkpt)) {
+ free(bkpt);
+ return (-1);
+ }
+ }
+
+ cb = emalloc(sizeof(*cb));
+ cb->cb_fun = fun;
+ cb->cb_arg = arg;
+ TAILQ_INSERT_TAIL(&bkpt->bkpt_cbs, cb, cb_list);
+
+ return (0);
+}
+
+/*
+ * Disable and delete a breakpoint.
+ */
+void
+bkpt_delete(struct pstate *ps, struct breakpoint *bkpt)
+{
+ TAILQ_REMOVE(&ps->ps_bkpts, bkpt, bkpt_list);
+
+ if (write_to_pid(ps->ps_pid, bkpt->bkpt_pc, &bkpt->bkpt_old,
+ BREAKPOINT_LEN))
+ warn("Breakpoint removal failed, process unstable");
+
+ free(bkpt);
+}
+
+/*
+ * Normal standard breakpoint. Keep it.
+ */
+static int
+bkpt_normal(struct pstate *ps, void *arg)
+{
+ return (BKPT_KEEP_STOP);
+}
+
+/*
+ * Single-step callback for "stepping over" a breakpoint (we restore the
+ * breakpoint instruction to what it was, single-step over it and then
+ * call this function).
+ */
+static int
+sstep_bkpt_readd(struct pstate *ps, void *arg)
+{
+ reg pc = (reg)arg;
+
+ bkpt_add_cb(ps, pc, bkpt_normal, NULL);
+
+ return (0); /* let the process continue */
+}
+
+/*
+ * Return 0 for stop, 1 for silent continue.
+ */
+int
+bkpt_check(struct pstate *ps)
+{
+ struct breakpoint *bkpt;
+ struct callback *cb;
+ TAILQ_HEAD(,callback) sstep_cbs;
+ reg *rg, pc;
+ int ret;
+ int didsome = 0;
+ int stop = 0;
+
+ /* Requeue all single-step callbacks because bkpts can add ssteps. */
+ TAILQ_INIT(&sstep_cbs);
+ while ((cb = TAILQ_FIRST(&ps->ps_sstep_cbs)) != NULL) {
+ TAILQ_REMOVE(&ps->ps_sstep_cbs, cb, cb_list);
+ TAILQ_INSERT_TAIL(&sstep_cbs, cb, cb_list);
+ }
+
+ /*
+ * The default is to stop. Unless we do some processing and none
+ * of the callbacks require a stop.
+ */
+ rg = alloca(sizeof(*rg) * md_def.nregs);
+ if (md_getregs(ps, rg))
+ err(1, "bkpt_check: Can't get registers.");
+
+ pc = rg[md_def.pcoff];
+ pc -= BREAKPOINT_DECR_PC;
+
+ bkpt = bkpt_find_at_pc(ps, pc);
+ if (bkpt == NULL)
+ goto sstep;
+
+ ps->ps_npc = pc;
+
+ while ((cb = TAILQ_FIRST(&bkpt->bkpt_cbs)) != NULL) {
+ didsome = 1;
+ TAILQ_REMOVE(&bkpt->bkpt_cbs, cb, cb_list);
+ ret = (*cb->cb_fun)(ps, cb->cb_arg);
+ free(cb);
+ switch (ret) {
+ case BKPT_DEL_STOP:
+ stop = 1;
+ case BKPT_DEL_CONT:
+ break;
+ case BKPT_KEEP_STOP:
+ stop = 1;
+ case BKPT_KEEP_CONT:
+ sstep_set(ps, sstep_bkpt_readd, (void *)bkpt->bkpt_pc);
+ break;
+ default:
+ errx(1, "unkonwn bkpt_fun return, internal error");
+ }
+ }
+
+ bkpt_delete(ps, bkpt);
+
+sstep:
+
+ while ((cb = TAILQ_FIRST(&sstep_cbs)) != NULL) {
+ didsome = 1;
+ TAILQ_REMOVE(&sstep_cbs, cb, cb_list);
+ stop |= (*cb->cb_fun)(ps, cb->cb_arg);
+ free(cb);
+ }
+ ps->ps_flags &= ~PSF_STEP;
+
+ return (didsome && !stop);
+}
+
+int
+cmd_bkpt_add(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+ char *ep, *bkpt_name;
+ reg pc;
+
+ if (ps->ps_state != STOPPED && ps->ps_state != LOADED) {
+ fprintf(stderr, "Process not loaded and stopped %d\n",
+ ps->ps_state);
+ return (0);
+ }
+
+ bkpt_name = argv[1];
+ pc = strtol(bkpt_name, &ep, 0);
+ if (bkpt_name[0] == '\0' || *ep != '\0' || pc < 1) {
+ if (sym_lookup(ps, bkpt_name, &pc)) {
+ warnx("%s is not a valid pc", bkpt_name);
+ return (0);
+ }
+ }
+
+ if (bkpt_add_cb(ps, pc, bkpt_normal, 0))
+ warn("Can't set break point");
+
+ return (0);
+}
+
+static int
+sstep_normal(struct pstate *ps, void *arg)
+{
+ return (1); /* stop the command line. */
+}
+
+int
+cmd_sstep(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+
+ if (ps->ps_state != STOPPED) {
+ fprintf(stderr, "Process not loaded and stopped %d\n",
+ ps->ps_state);
+ return 0;
+ }
+
+ if (sstep_set(ps, sstep_normal, NULL))
+ warn("Can't set single step");
+
+ return (cmd_process_cont(argc, argv, arg));
+}
+
+int
+sstep_set(struct pstate *ps, int (*fun)(struct pstate *, void *), void *arg)
+{
+ struct callback *cb;
+
+ cb = emalloc(sizeof(*cb));
+ cb->cb_fun = fun;
+ cb->cb_arg = arg;
+ TAILQ_INSERT_TAIL(&ps->ps_sstep_cbs, cb, cb_list);
+
+ ps->ps_flags |= PSF_STEP;
+
+ return (0);
+}
diff --git a/usr.bin/pmdb/break.h b/usr.bin/pmdb/break.h
new file mode 100644
index 00000000000..a4513e0ddfc
--- /dev/null
+++ b/usr.bin/pmdb/break.h
@@ -0,0 +1,46 @@
+/* $PMDB: break.h,v 1.4 2002/03/11 23:39:49 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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.
+ */
+
+/*
+ * Breakpoint handling.
+ */
+int bkpt_add_cb(struct pstate *, reg, int (*)(struct pstate *, void *), void *);
+int bkpt_check(struct pstate *);
+int cmd_bkpt_add(int, char **, void *);
+
+/*
+ * Single step handling.
+ */
+int sstep_set(struct pstate *, int (*)(struct pstate *, void *), void *);
+int cmd_sstep(int, char **, void *);
+
+/*
+ * Return values from the bkpt_fun
+ */
+#define BKPT_DEL_STOP 1 /* delete this bkpt and stop */
+#define BKPT_DEL_CONT 2 /* delete this bkpt and continue */
+#define BKPT_KEEP_STOP 3 /* keep this bkpt and stop */
+#define BKPT_KEEP_CONT 4 /* keep this bkpt and cont */
diff --git a/usr.bin/pmdb/clit.c b/usr.bin/pmdb/clit.c
new file mode 100644
index 00000000000..3dab6a9231a
--- /dev/null
+++ b/usr.bin/pmdb/clit.c
@@ -0,0 +1,261 @@
+/* $PMDB: clit.c,v 1.11 2002/03/07 13:57:28 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 <stdlib.h>
+#include <stdio.h>
+#include <histedit.h>
+#include <err.h>
+#include <string.h>
+
+#include "clit.h"
+
+extern char *__progname;
+
+char *prompt_add;
+
+static char *
+prompt(EditLine *el)
+{
+ static char p[64];
+
+ snprintf(p, sizeof(p), "%s%s> ", __progname,
+ prompt_add ? prompt_add : "");
+
+ return p;
+}
+
+/*
+ * Returns number of commands that (at least partially) match "name".
+ */
+static int
+name_to_cmd(const char *name, struct clit *cmds, int ncmds, struct clit **res)
+{
+ int i, len, ret;
+
+ len = strlen(name);
+ ret = 0;
+
+ for (i = 0; i < ncmds; i++) {
+ if (strncmp(cmds[i].cmd, name, len) == 0) {
+ *res = &cmds[i];
+ ret++;
+ }
+ }
+
+ return ret;
+}
+
+struct clitenv {
+ struct clit *cmds;
+ int ncmds;
+ EditLine *el;
+ History *hist;
+};
+
+int
+cmd_help(int argc, char **argv, void *arg)
+{
+ struct clitenv *env = arg;
+ struct clit *cmds = env->cmds, *cmdp;
+ int ncmds = env->ncmds;
+ int i, res;
+
+ if (argc > 1) {
+ res = name_to_cmd(argv[1], cmds, ncmds, &cmdp);
+ if (res == 1) {
+ printf("%s\t%s\n", cmdp->cmd, cmdp->help);
+ } else {
+ fprintf(stderr, "%s command: %s\n",
+ res == 0 ? "unknown" : "ambiguous", argv[1]);
+ }
+
+ return 0;
+ }
+ for (i = 0; i < ncmds; i++) {
+ cmdp = &cmds[i];
+
+ printf("%s\t%s\n", cmdp->cmd, cmdp->help);
+ }
+
+ return 0;
+}
+
+/*
+ * XXX - there is no way to push external args into this function.
+ */
+unsigned char
+complt(EditLine *el, int ch)
+{
+ const LineInfo *line;
+ char str[1024];
+ int len, ret;
+
+ line = el_line(el);
+ if (line->cursor != line->lastchar)
+ return CC_ERROR;
+
+ len = line->lastchar - line->buffer;
+
+ if (len >= 1023)
+ return CC_ERROR;
+
+ memcpy(str, line->buffer, len);
+ str[len] = '\0';
+
+ ret = cmd_complt(str, sizeof(str));
+
+ el_push(el, &str[len]);
+
+ return ret ? CC_ERROR : CC_REDISPLAY;
+}
+
+void *
+cmdinit(struct clit *cmds, int ncmds)
+{
+ struct clitenv *env;
+#ifdef __NetBSD__
+ HistEvent ev;
+#endif
+
+ if ((env = malloc(sizeof(*env))) == NULL)
+ err(1, "Can't init cmd interpreter.");
+
+ env->cmds = cmds;
+ env->ncmds = ncmds;
+
+ env->hist = history_init();
+#ifdef __NetBSD__
+ history(env->hist, &ev, H_SETSIZE, 100);
+#else
+ history(env->hist, H_EVENT, 100);
+#endif
+
+#ifdef __NetBSD__
+ env->el = el_init(__progname, stdin, stdout, stderr);
+#else
+ env->el = el_init(__progname, stdin, stdout);
+#endif
+ el_set(env->el, EL_EDITOR, "emacs");
+ el_set(env->el, EL_PROMPT, prompt);
+ el_set(env->el, EL_HIST, history, env->hist);
+ el_set(env->el, EL_ADDFN, "complt", "complete", complt);
+ el_set(env->el, EL_BIND, "\t", "complt");
+ el_source(env->el, NULL);
+
+ /* XXX - EL_SIGNAL ? */
+
+ return env;
+}
+
+void
+cmdend(void *arg)
+{
+ struct clitenv *env = arg;
+
+ el_end(env->el);
+ history_end(env->hist);
+
+ free(env);
+}
+
+int
+cmdloop(void *arg)
+{
+ struct clitenv *env = arg;
+ EditLine *el = env->el;
+ History *hist = env->hist;
+ const char *elline;
+ int cnt;
+ char **argv;
+ int maxargs = 16; /* XXX */
+ int stop;
+
+ stop = 0;
+
+ if ((argv = malloc(sizeof(char *) * maxargs)) == NULL)
+ err(1, "malloc");
+
+ while (!stop && (elline = el_gets(el, &cnt)) != NULL) {
+ char *line, *orgline;
+ struct clit *cmdp;
+ char **ap;
+ int argc, res;
+#ifdef __NetBSD__
+ HistEvent ev;
+#endif
+
+ memset(argv, 0, sizeof(argv));
+
+#ifdef __NetBSD__
+ history(hist, &ev, H_ENTER, elline);
+#else
+ history(hist, H_ENTER, elline);
+#endif
+
+ orgline = line = strdup(elline);
+
+ argc = 0;
+ for (ap = argv; (*ap = strsep(&line, " \t\n")) != NULL;) {
+ if (**ap != '\0') {
+ ++ap;
+ if (++argc == maxargs)
+ break;
+ }
+ }
+ if (argc == maxargs) {
+ fprintf(stderr, "Too many arguments\n");
+ goto cmdout;
+ }
+ if (!argc)
+ goto cmdout;
+
+ /*
+ * Editline commands.
+ */
+ if (el_parse(el, argc, argv) != -1)
+ goto cmdout;
+
+ if ((res = name_to_cmd(argv[0], env->cmds, env->ncmds,
+ &cmdp)) == 1) {
+ if (argc - 1 > cmdp->maxargc)
+ fprintf(stderr, "Too many arguments\n");
+ else if (argc - 1 < cmdp->minargc)
+ fprintf(stderr, "Too few arguments\n");
+ else
+ stop = (*cmdp->handler)(argc, argv,
+ cmdp->arg ? cmdp->arg : env);
+ } else {
+ fprintf(stderr, "%s command: %s\n",
+ res == 0 ? "unknown" : "ambiguous", argv[0]);
+ }
+cmdout:
+ free(orgline);
+ }
+ free(argv);
+
+ return stop;
+}
+
diff --git a/usr.bin/pmdb/clit.h b/usr.bin/pmdb/clit.h
new file mode 100644
index 00000000000..d0479ec0354
--- /dev/null
+++ b/usr.bin/pmdb/clit.h
@@ -0,0 +1,52 @@
+/* $PMDB: clit.h,v 1.8 2002/03/07 13:57:28 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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.
+ */
+
+struct clit {
+ const char *cmd;
+ const char *help;
+ int minargc;
+ int maxargc;
+ int (*handler)(int argc, char **argv, void *);
+ void *arg;
+};
+
+char *prompt_add;
+
+int cmd_help(int, char **, void *);
+
+void *cmdinit(struct clit *, int);
+int cmdloop(void *);
+void cmdend(void *);
+
+/*
+ * This function must be defined by the calling code. Sorry, but there is
+ * no way to pass arguments to it or pass this function in some arguments.
+ *
+ * Fills in the possible completions into buf. Returns != 0 when there are
+ * no possible completions. May whack buf, but the "returned"
+ * string should be appended to the string that was in buf.
+ */
+int cmd_complt(char *buf, size_t buflen);
diff --git a/usr.bin/pmdb/elf_syms.c b/usr.bin/pmdb/elf_syms.c
new file mode 100644
index 00000000000..cba56fee07d
--- /dev/null
+++ b/usr.bin/pmdb/elf_syms.c
@@ -0,0 +1,403 @@
+/* $PMDB: elf_syms.c,v 1.18 2002/03/11 23:39:49 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/mman.h>
+
+#include <nlist.h>
+#ifdef __NetBSD__
+#include <machine/elf_machdep.h>
+#define ELFSIZE ARCH_ELFSIZE
+#include <sys/exec_elf.h>
+#else
+#include <elf_abi.h>
+#endif
+#include <link.h>
+
+#include "pmdb.h"
+#include "symbol.h"
+#include "break.h"
+
+struct elf_symbol_handle {
+ struct sym_table esh_st;
+ int esh_fd;
+ char *esh_strtab;
+ Elf_Word esh_strsize;
+ Elf_Sym *esh_symtab;
+ Elf_Word esh_symsize;
+ Elf_Addr esh_offs;
+};
+
+#define ESH_TO_ST(esh) (&(esh)->esh_st)
+#define ST_TO_ESH(st) ((struct elf_symbol_handle *)(st))
+
+struct sym_table *elf_open(const char *);
+void elf_close(struct sym_table *);
+char *elf_name_and_off(struct sym_table *, reg, reg *);
+int elf_lookup(struct pstate *, const char *, reg *);
+void elf_update(struct pstate *);
+
+struct sym_ops elf_sops = {
+ elf_open,
+ elf_close,
+ elf_name_and_off,
+ elf_lookup,
+ elf_update
+};
+
+int
+sym_check_elf(const char *name, struct pstate *ps)
+{
+ Elf_Ehdr ehdr;
+ int fd;
+
+ if ((fd = open(name, O_RDONLY)) < 0)
+ return (-1);
+
+ if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr))
+ return (-1);
+
+#ifndef __NetBSD__
+ if (!IS_ELF(ehdr) ||
+ ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
+ ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
+ ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
+ ehdr.e_machine != ELF_TARG_MACH ||
+ ehdr.e_version != ELF_TARG_VER)
+ return (-1);
+#endif
+
+ close(fd);
+
+ ps->ps_sops = &elf_sops;
+
+ return (0);
+}
+
+struct sym_table *
+elf_open(const char *name)
+{
+ struct elf_symbol_handle *esh;
+ Elf_Off symoff, stroff;
+ Elf_Ehdr ehdr;
+ Elf_Shdr *shdr;
+ int i, fd;
+
+ /* Just a sanity check */
+ if (sizeof(reg) != sizeof(Elf_Addr))
+ errx(1, "sym_open: sizeof(reg) != sizeof(Elf_Addr)");
+
+ if ((esh = malloc(sizeof(*esh))) == NULL) {
+ return (NULL);
+ }
+
+ memset(esh, 0, sizeof(*esh));
+ esh->esh_fd = -1;
+
+ if ((fd = esh->esh_fd = open(name, O_RDONLY)) < 0) {
+ goto fail;
+ }
+
+ if (pread(fd, &ehdr, sizeof(Elf_Ehdr), 0) != sizeof(Elf_Ehdr)) {
+ goto fail;
+ }
+#ifndef __NetBSD__
+ if (!IS_ELF(ehdr) ||
+ ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS ||
+ ehdr.e_ident[EI_DATA] != ELF_TARG_DATA ||
+ ehdr.e_ident[EI_VERSION] != ELF_TARG_VER ||
+ ehdr.e_machine != ELF_TARG_MACH ||
+ ehdr.e_version != ELF_TARG_VER) {
+ goto fail;
+ }
+#endif
+
+ if ((shdr = (Elf_Shdr *)mmap(NULL, ehdr.e_shentsize * ehdr.e_shnum,
+ PROT_READ, MAP_SHARED, fd, ehdr.e_shoff)) == MAP_FAILED) {
+ goto fail;
+ }
+
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ symoff = shdr[i].sh_offset;
+ esh->esh_symsize = shdr[i].sh_size;
+ stroff = shdr[shdr[i].sh_link].sh_offset;
+ esh->esh_strsize = shdr[shdr[i].sh_link].sh_size;
+ break;
+ }
+ }
+
+ munmap(shdr, ehdr.e_shentsize * ehdr.e_shnum);
+
+ if (i == ehdr.e_shnum) {
+ goto fail;
+ }
+
+ if ((esh->esh_strtab = mmap(NULL, esh->esh_strsize, PROT_READ,
+ MAP_SHARED, fd, stroff)) == MAP_FAILED) {
+ goto fail;
+ }
+
+ if ((esh->esh_symtab = mmap(NULL, esh->esh_symsize, PROT_READ,
+ MAP_SHARED, fd, symoff)) == MAP_FAILED) {
+ goto fail;
+ }
+
+ return (ESH_TO_ST(esh));
+fail:
+
+ elf_close(ESH_TO_ST(esh));
+ return (NULL);
+}
+
+void
+elf_close(struct sym_table *st)
+{
+ struct elf_symbol_handle *esh = ST_TO_ESH(st);
+
+ if (esh->esh_fd != -1)
+ close(esh->esh_fd);
+
+ munmap(esh->esh_strtab, esh->esh_strsize);
+ munmap(esh->esh_symtab, esh->esh_symsize);
+ free(esh);
+}
+
+char *
+elf_name_and_off(struct sym_table *st, reg pc, reg *offs)
+{
+ struct elf_symbol_handle *esh = ST_TO_ESH(st);
+ Elf_Sym *s, *bests = NULL;
+ Elf_Addr bestoff = 0;
+ int nsyms, i;
+ char *symn;
+
+#define SYMVAL(S) (unsigned long)((S)->st_value + esh->esh_offs)
+
+ nsyms = esh->esh_symsize / sizeof(Elf_Sym);
+
+ bests = NULL;
+ for (i = 0; i < nsyms; i++) {
+ s = &esh->esh_symtab[i];
+
+ if (s->st_value == 0 ||
+ s->st_shndx == 0 ||
+ (ELF_ST_BIND(s->st_info) != STB_GLOBAL &&
+ ELF_ST_BIND(s->st_info) != STB_WEAK &&
+ ELF_ST_BIND(s->st_info) != STB_LOCAL))
+ continue;
+ symn = &esh->esh_strtab[s->st_name];
+ if (SYMVAL(s) <= pc && SYMVAL(s) > bestoff &&
+ symn[0] != '\0' && strcmp(symn, "gcc2_compiled.")) {
+ bests = s;
+ bestoff = SYMVAL(s);
+ }
+ }
+
+ if ((s = bests) == NULL)
+ return (NULL);
+
+ *offs = pc - SYMVAL(s);
+
+ return &esh->esh_strtab[s->st_name];
+}
+
+static Elf_Sym *
+elf_lookup_table(struct elf_symbol_handle *esh, const char *name)
+{
+ int nsyms, i;
+ char *symn;
+ Elf_Sym *s = NULL;
+
+ /* XXX - dumb, doesn't follow the rules (weak, hash, etc.). */
+ nsyms = esh->esh_symsize / sizeof(Elf_Sym);
+ for (i = 0; i < nsyms; i++) {
+ s = &esh->esh_symtab[i];
+ symn = &esh->esh_strtab[s->st_name];
+ if (strcmp(name, symn) == 0)
+ break;
+ }
+ if (i == nsyms)
+ return (NULL);
+
+ return (s);
+}
+
+int
+elf_lookup(struct pstate *ps, const char *name, reg *res)
+{
+ struct sym_table *st;
+ Elf_Sym *s;
+
+ TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
+ if ((s = elf_lookup_table(ST_TO_ESH(st), name)) != NULL)
+ break;
+ }
+
+ if (s != NULL) {
+ *res = s->st_value + ST_TO_ESH(st)->esh_offs;
+ return (0);
+ }
+
+ return (-1);
+}
+
+#ifndef __NetBSD__
+struct elf_object_v1 {
+ Elf_Addr load_addr;
+ Elf_Addr load_offs;
+ char *load_name;
+ Elf_Dyn *load_dyn;
+ struct elf_object_v1 *next;
+ struct elf_object_v1 *prev;
+ void *load_list;
+ u_int32_t load_size;
+ u_long info[DT_NUM + DT_PROCNUM];
+ struct elf_object_v1 *dep_next;
+ int status;
+ Elf_Phdr *phdrp;
+ int phdrc;
+ int refcount;
+ int obj_type;
+#define EOBJ1_LDR 1
+#define EOBJ1_EXE 2
+#define EOBJ1_LIB 3
+#define EOBJ1_DLO 4
+};
+#endif
+
+/*
+ * dlopen breakpoint (XXX make this generic?)
+ */
+int
+sym_bkpt(struct pstate *ps, void *arg)
+{
+ fprintf(stderr, "pmdb: shared lib changed\n");
+
+ sym_update(ps);
+
+ return BKPT_KEEP_CONT;
+}
+
+/*
+ * Called after execution started so that we can load any dynamic symbols.
+ */
+void
+elf_update(struct pstate *ps)
+{
+#ifndef __NetBSD__
+ pid_t pid = ps->ps_pid;
+ struct elf_object_v1 eobj;
+ struct sym_table *st;
+ struct r_debug rdeb;
+ reg addr;
+ Elf_Dyn dyn;
+ static int bkpt_set;
+ Elf_Sym *s;
+
+ if ((s = elf_lookup_table(ST_TO_ESH(ps->ps_sym_exe), "_DYNAMIC")) == NULL) {
+ warnx("Can't find _DYNAMIC");
+ return;
+ }
+ addr = s->st_value + ST_TO_ESH(ps->ps_sym_exe)->esh_offs;
+
+ do {
+ if (read_from_pid(pid, addr, &dyn, sizeof(dyn)) < 0) {
+ warnx("Can't read _DYNAMIC");
+ return;
+ }
+ addr += sizeof(dyn);
+ } while (dyn.d_tag != 0 && dyn.d_tag != DT_DEBUG);
+
+ if (dyn.d_tag == 0) {
+ warnx("Can't find DT_DEBUG");
+ return;
+ }
+
+ if (read_from_pid(pid, dyn.d_un.d_ptr, &rdeb, sizeof(rdeb)) < 0) {
+ warnx("Can't read DT_DEBUG");
+ return;
+ }
+
+ if (rdeb.r_version != 1) {
+ warn("Can't handle debug map version %d", rdeb.r_version);
+ return;
+ }
+ if (rdeb.r_state != RT_CONSISTENT) {
+ warn("debug map not consistent: %d", rdeb.r_state);
+ return;
+ }
+
+ if (!bkpt_set) {
+ if (bkpt_add_cb(ps, rdeb.r_brk, sym_bkpt, NULL))
+ warn("sym_exec: can't set bkpt");
+ bkpt_set = 1;
+ }
+
+ addr = (Elf_Addr)rdeb.r_map;
+ while (addr != 0 && addr != -1) {
+ char fname[MAXPATHLEN];
+ int i;
+
+ if (read_from_pid(pid, addr, &eobj, sizeof(eobj)) < 0) {
+ warnx("Can't read symbols...");
+ return;
+ }
+
+ addr = (Elf_Addr)eobj.next;
+
+ if (eobj.load_name == NULL || eobj.load_name == (char *)-1)
+ continue;
+ if (read_from_pid(pid, (Elf_Addr)eobj.load_name, fname,
+ sizeof(fname)) < 0) {
+ warnx("Can't read symbols...");
+ return;
+ }
+
+ /* sanity check the file name */
+ for (i = 0; i < MAXPATHLEN; i++)
+ if (fname[i] == '\0')
+ break;
+ if (i == MAXPATHLEN)
+ continue;
+
+ st = st_open(ps, fname);
+ if (st == NULL) {
+ warn("symbol loading failed");
+ continue;
+ }
+ ST_TO_ESH(st)->esh_offs = eobj.load_offs;
+ }
+#endif
+}
diff --git a/usr.bin/pmdb/pmdb.1 b/usr.bin/pmdb/pmdb.1
new file mode 100644
index 00000000000..e2ecd5ae8de
--- /dev/null
+++ b/usr.bin/pmdb/pmdb.1
@@ -0,0 +1,110 @@
+.\" $PMDB: pmdb.1,v 1.2 2002/02/20 15:16:27 art Exp $
+.\"
+.\" Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``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.
+.\"
+.Dd Feb 20, 2002
+.Dt PMDB 1
+.Os
+.Sh NAME
+.Nm pmdb
+.Nd debugger.
+.Sh SYNOPSIS
+.Nm pmdb
+.Ar program Op Ar ...
+.Sh DESCRIPTION
+The
+.Nm
+utility can be used to see what is happening inside a running process or
+to catch program crashes and examine the state at the time of the crash.
+The only way to start
+.Nm
+at this moment is to specify the name of the prgram to be debugged and all
+its arguments on the command line.
+The program is controlled from a command line which usually gives the
+prompt "pmdb>".
+.Sh PROCESS STATES
+A loaded program can be in one of three possible states:
+.Bl -tag -width RUNNING
+.It LOADED
+This is the initial state.
+The program is not running, it can't be examined (because it doesn't have
+any state).
+The only thing that can be done to the process is to start it with the
+.Ic run
+command.
+.It RUNNING
+When a process is
+.Ic RUNNING ,
+the only way to affect it is through signals sent to it.
+Unless a signal is ignored with the
+.Ic signal ignore
+command, it will be catched by pmdb and the process will go into the
+.Ic STOPPED
+state.
+.It STOPPED
+A stopped process can be examined, changed and restarted with the
+.Ic continue
+command.
+.El
+.Sh COMMANDS
+.Bl -tag -width continue
+.It regs
+Show the contents of the processor registers at the moment the process was
+.Ic STOPPED .
+.It trace
+Show the function call trace of the currently
+.Ic STOPPED
+process.
+.It run
+Start running a
+.Ic LOADED
+process.
+.It continue
+Continue a
+.Ic STOPPED
+process.
+.It kill
+Unconditionally kills the debugged process and puts it in the
+.Ic LOADED
+state.
+.It signal Ar ignore|stop Ar signum|signame
+Sets the signal state for the specified signal to either ignore it and
+pass it to the process or to stop the process.
+.It sigstate
+Shows which signals are currently ignored.
+.It help
+Shows a short help.
+.It quit
+Kills the process (if necessary) and exits
+.Nm .
+.It exit
+Alias for
+.Ic quit .
+.El
+.Sh HISTORY
+The
+.Nm
+debugger was written because the author believed that
+.Xr gdb 1
+was too to bloated and hairy to run on OpenBSD/sparc64.
diff --git a/usr.bin/pmdb/pmdb.c b/usr.bin/pmdb/pmdb.c
new file mode 100644
index 00000000000..5f7740f89e9
--- /dev/null
+++ b/usr.bin/pmdb/pmdb.c
@@ -0,0 +1,348 @@
+/* $PMDB: pmdb.c,v 1.41 2002/03/12 14:24:30 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/types.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/endian.h>
+
+#include "pmdb.h"
+#include "symbol.h"
+#include "clit.h"
+#include "break.h"
+
+static int cmd_show_registers(int, char **, void *);
+static int cmd_show_backtrace(int, char **, void *);
+static int cmd_quit(int, char **, void *);
+
+struct clit cmds[] = {
+ /* debugging info commands. */
+ { "regs", "show registers", 0, 0, cmd_show_registers, (void *)-1 },
+ { "trace", "show backtrace", 0, 0, cmd_show_backtrace, (void *)-1 },
+
+ /* Process handling commands. */
+ { "run", "run process", 0, 0, cmd_process_run, (void *)-1 },
+ { "continue", "continue process", 0, 0, cmd_process_cont, (void *)-1 },
+ { "kill", "kill process", 0, 0, cmd_process_kill, (void *)-1 },
+
+ /* signal handling commands. */
+ { "signal", "ignore signal", 2, 2, cmd_signal_ignore, (void *)-1 },
+ { "sigstate", "show signal state", 0, 0, cmd_signal_show, (void *)-1 },
+
+ /* breakpoints */
+ { "break", "set breakpoint", 1, 1, cmd_bkpt_add, (void *)-1 },
+ { "step", "single step one insn", 0, 0, cmd_sstep, (void *)-1 },
+
+ /* misc commands. */
+ { "help", "print help", 0, 1, cmd_help, NULL },
+ { "quit", "quit", 0, 0, cmd_quit, (void *)-1 },
+ { "exit", "quit", 0, 0, cmd_quit, (void *)-1 },
+};
+
+int
+main(int argc, char **argv)
+{
+ extern const char *__progname;
+ struct pstate ps;
+ int i, ncmds;
+ int status;
+ void *cm;
+ char *pmenv;
+ int level;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <program> args\n", __progname);
+ exit(1);
+ }
+
+ if ((pmenv = getenv("IN_PMDB")) != NULL) {
+ level = atoi(pmenv);
+ level++;
+ } else
+ level = 0;
+
+ if (level > 0)
+ asprintf(&prompt_add, "(%d)", level);
+ asprintf(&pmenv, "%d", level);
+ setenv("IN_PMDB", pmenv, 1);
+
+ ps.ps_pid = 0;
+ ps.ps_state = NONE;
+ ps.ps_argc = --argc;
+ ps.ps_argv = ++argv;
+ ps.ps_flags = 0;
+ ps.ps_signum = 0;
+ ps.ps_npc = 1;
+ TAILQ_INIT(&ps.ps_bkpts);
+ TAILQ_INIT(&ps.ps_sstep_cbs);
+
+ signal(SIGINT, SIG_IGN);
+
+ ncmds = sizeof(cmds)/sizeof(cmds[0]);
+
+ for (i = 0; i < ncmds; i++)
+ if (cmds[i].arg == (void *)-1)
+ cmds[i].arg = &ps;
+
+ md_def_init();
+ init_sigstate(&ps);
+
+ process_load(&ps);
+
+ cm = cmdinit(cmds, ncmds);
+ while (ps.ps_state != TERMINATED) {
+ int signum;
+ int stopped;
+ int cont;
+
+ if (ps.ps_state == STOPPED) {
+ sym_update(&ps);
+ }
+
+ if (ps.ps_state != RUNNING && cmdloop(cm) == 0) {
+ cmd_quit(0, NULL, &ps);
+ }
+
+ if (ps.ps_state == TERMINATED)
+ break;
+
+ if (wait(&status) == 0)
+ err(1, "wait");
+ if (WIFEXITED(status)) {
+ if ((ps.ps_flags & PSF_KILL) == 0) {
+ ps.ps_state = NONE;
+ } else {
+ ps.ps_state = TERMINATED;
+ }
+ fprintf(stderr, "process exited with status %d\n",
+ WEXITSTATUS(status));
+ continue;
+ }
+ if (WIFSIGNALED(status)) {
+ signum = WTERMSIG(status);
+ stopped = 0;
+ } else {
+ signum = WSTOPSIG(status);
+ stopped = 1;
+ }
+ cont = 0;
+ if (stopped)
+ cont = bkpt_check(&ps);
+ process_signal(&ps, signum, stopped, cont);
+ }
+
+ cmdend(cm);
+
+ sym_destroy(&ps);
+
+ return (0);
+}
+
+/* XXX - move to some other file. */
+int
+read_from_pid(pid_t pid, off_t from, void *to, size_t size)
+{
+ struct ptrace_io_desc piod;
+
+ piod.piod_op = PIOD_READ_D;
+ piod.piod_offs = (void *)(long)from;
+ piod.piod_addr = to;
+ piod.piod_len = size;
+
+ return (ptrace(PT_IO, pid, (caddr_t)&piod, 0) != size);
+}
+
+
+int
+write_to_pid(pid_t pid, off_t to, void *from, size_t size)
+{
+ struct ptrace_io_desc piod;
+
+ piod.piod_op = PIOD_WRITE_D;
+ piod.piod_offs = (void *)(long)to;
+ piod.piod_addr = from;
+ piod.piod_len = size;
+
+ return (ptrace(PT_IO, pid, (caddr_t)&piod, 0) != size);
+}
+
+static int
+cmd_show_registers(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+ char buf[256];
+ int i;
+ reg *rg;
+
+ if (ps->ps_state != STOPPED) {
+ fprintf(stderr, "process not stopped\n");
+ return 0;
+ }
+
+ rg = alloca(sizeof(*rg) * md_def.nregs);
+
+ if (md_getregs(ps, rg))
+ err(1, "can't get registers");
+ for (i = 0; i < md_def.nregs; i++)
+ printf("%s:\t0x%.*lx\t%s\n", md_def.md_reg_names[i],
+ (int)(sizeof(reg) * 2), (long)rg[i],
+ sym_print(ps, rg[i], buf, sizeof(buf)));
+ return 0;
+}
+
+static int
+cmd_show_backtrace(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+ int i;
+
+ if (ps->ps_state != STOPPED) {
+ fprintf(stderr, "process not stopped\n");
+ return 0;
+ }
+
+ /* no more than 100 frames */
+ for (i = 0; i < 100; i++) {
+ struct md_frame mfr;
+ char namebuf[1024], *name;
+ reg offs;
+ int j;
+
+ mfr.nargs = -1;
+
+ if (md_getframe(ps, i, &mfr))
+ break;
+
+ name = sym_name_and_offset(ps, mfr.pc, namebuf,
+ sizeof(namebuf), &offs);
+ if (name == NULL) {
+ snprintf(namebuf, sizeof(namebuf), "0x%lx", mfr.pc);
+ name = namebuf;
+ }
+
+ printf("%s(", name);
+ for (j = 0; j < mfr.nargs; j++) {
+ printf("0x%lx", mfr.args[j]);
+ if (j < mfr.nargs - 1)
+ printf(", ");
+ }
+ printf(")+0x%lx\n", offs);
+ }
+ return 0;
+}
+
+static int
+cmd_quit(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+
+ ps->ps_flags |= PSF_KILL;
+
+ if (process_kill(ps))
+ return 1;
+
+ ps->ps_state = TERMINATED;
+ return 1;
+}
+
+/*
+ * Perform command completion.
+ * Pretty simple. if there are spaces in "buf", the last string is a symbol
+ * otherwise it's a command.
+ */
+int
+cmd_complt(char *buf, size_t buflen)
+{
+ struct clit *match;
+ char *start;
+ int command;
+ int i, j, len;
+ int onlymatch;
+
+ command = (strchr(buf, ' ') == NULL);
+
+ if (!command) {
+ /* XXX - can't handle symbols yet. */
+ return -1;
+ }
+
+ start = buf;
+ len = strlen(buf);
+
+ match = NULL;
+ for (i = 0; i < sizeof(cmds) / sizeof(cmds[i]); i++) {
+ if (strncmp(start, cmds[i].cmd, len) == 0) {
+ struct clit *cmdp;
+
+ cmdp = &cmds[i];
+ if (match == NULL) {
+ onlymatch = 1;
+ match = cmdp;
+ strlcpy(buf, match->cmd, buflen);
+ continue;
+ }
+ onlymatch = 0;
+ for (j = len; j < buflen; j++) {
+ if (buf[j] != cmdp->cmd[j]) {
+ buf[j] = '\0';
+ break;
+ }
+ if (cmdp->cmd[j] == '\0')
+ break;
+ }
+ }
+ }
+
+ /*
+ * Be nice. If there could be arguments for this command and it's
+ * the only match append a space.
+ */
+ if (match && onlymatch /*&& match->maxargc > 0*/)
+ strlcat(buf, " ", buflen);
+
+ return (match && onlymatch) ? 0 : -1;
+}
+
+/*
+ * The "stadard" wrapper
+ */
+void *
+emalloc(size_t sz)
+{
+ void *ret;
+ if ((ret = malloc(sz)) == NULL)
+ err(1, "malloc");
+ return (ret);
+}
diff --git a/usr.bin/pmdb/pmdb.h b/usr.bin/pmdb/pmdb.h
new file mode 100644
index 00000000000..18d5cf023c7
--- /dev/null
+++ b/usr.bin/pmdb/pmdb.h
@@ -0,0 +1,119 @@
+/* $PMDB: pmdb.h,v 1.26 2002/03/11 23:39:49 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/signal.h> /* for NSIG */
+#include <sys/queue.h>
+#include <sys/ptrace.h>
+#include <err.h>
+
+/* XXX - ugh, yuck, bleah. */
+#ifndef PT_STEP
+#define PT_STEP PT_CONTINUE
+#endif
+
+/*
+ * Process handling.
+ */
+
+struct breakpoint;
+struct callback;
+struct sym_table;
+struct sym_ops;
+
+/* XXX - should be machdep some day. */
+typedef unsigned long reg;
+
+/* The state for a debugged process. */
+struct pstate {
+ pid_t ps_pid;
+ enum { NONE, LOADED, RUNNING, STOPPED, TERMINATED } ps_state;
+ int ps_argc;
+ char **ps_argv;
+ int ps_flags;
+ int ps_signum;
+ int ps_sigstate[NSIG];
+ reg ps_npc;
+ TAILQ_HEAD(,sym_table) ps_syms; /* all symbols tables in a list */
+ struct sym_table *ps_sym_exe; /* symbol table for the executable */
+ struct sym_ops *ps_sops; /* operations on symbol tables */
+ TAILQ_HEAD(,breakpoint) ps_bkpts; /* breakpoints */
+ TAILQ_HEAD(,callback) ps_sstep_cbs; /* single step actions */
+};
+
+/* flags in ps_flags */
+#define PSF_SYMBOLS 0x02 /* basic symbols loaded */
+#define PSF_KILL 0x04 /* kill this process asap */
+#define PSF_STEP 0x08 /* next continue should sstep */
+
+/* ps_sigstate */
+#define SS_STOP 0x00
+#define SS_IGNORE 0x01
+
+/* misc helper functions */
+int process_kill(struct pstate *);
+int read_from_pid(pid_t pid, off_t from, void *to, size_t size);
+int write_to_pid(pid_t pid, off_t to, void *from, size_t size);
+
+/* process.c */
+int process_load(struct pstate *);
+int cmd_process_run(int, char **, void *);
+int cmd_process_cont(int, char **, void *);
+int cmd_process_kill(int, char **, void *);
+
+/* signal.c */
+void init_sigstate(struct pstate *);
+void process_signal(struct pstate *, int, int, int);
+int cmd_signal_ignore(int, char **, void *);
+int cmd_signal_show(int, char **, void *);
+
+/*
+ * Machine dependent stuff.
+ */
+/* register names */
+struct md_def {
+ const char **md_reg_names; /* array of register names */
+ const int nregs; /* number of registers */
+ const int pcoff; /* offset of the pc */
+};
+extern struct md_def md_def;
+void md_def_init(void);
+
+#define MDF_MAX_ARGS 16
+
+struct md_frame {
+ reg pc, fp;
+ int nargs;
+ reg args[MDF_MAX_ARGS];
+};
+
+/*
+ * Return the registers for the process "ps" in the frame "frame".
+ */
+int md_getframe(struct pstate *, int, struct md_frame *);
+int md_getregs(struct pstate *, reg *);
+
+/* misc */
+void *emalloc(size_t);
diff --git a/usr.bin/pmdb/process.c b/usr.bin/pmdb/process.c
new file mode 100644
index 00000000000..727613b57be
--- /dev/null
+++ b/usr.bin/pmdb/process.c
@@ -0,0 +1,169 @@
+/* $PMDB: process.c,v 1.19 2002/03/11 23:39:49 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/types.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "pmdb.h"
+#include "symbol.h"
+#include "break.h"
+
+int
+process_load(struct pstate *ps)
+{
+ int status;
+
+ if (ps->ps_state == LOADED)
+ return (0);
+
+ switch (ps->ps_pid = fork()) {
+ case 0:
+ if (ptrace(PT_TRACE_ME, getpid(), NULL, 0) != 0)
+ err(1, "ptrace(PT_TRACE_ME)");
+ execvp(*ps->ps_argv, ps->ps_argv);
+ err(1, "exec");
+ /* NOTREACHED */
+ case -1:
+ err(1, "fork");
+ /* NOTREACHED */
+ default:
+ break;
+ }
+
+ if ((ps->ps_flags & PSF_SYMBOLS) == 0) {
+ sym_init_exec(ps, ps->ps_argv[0]);
+ ps->ps_flags |= PSF_SYMBOLS;
+ }
+
+ if (wait(&status) == 0)
+ err(1, "wait");
+
+ ps->ps_state = LOADED;
+ return 0;
+}
+
+int
+process_kill(struct pstate *ps)
+{
+ switch(ps->ps_state) {
+ case LOADED:
+ case RUNNING:
+ case STOPPED:
+ if (ptrace(PT_KILL, ps->ps_pid, NULL, 0) != 0)
+ err(1, "ptrace(PT_KILL)");
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int
+cmd_process_kill(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+
+ process_kill(ps);
+
+ return 1;
+}
+
+int
+process_bkpt_main(struct pstate *ps, void *arg)
+{
+ sym_update(ps);
+
+ return BKPT_DEL_CONT;
+}
+
+int
+cmd_process_run(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+
+ if (ps->ps_state == NONE) {
+ reg main_addr;
+
+ process_load(ps);
+ if (sym_lookup(ps, "main", &main_addr))
+ warnx("no main");
+ else if (bkpt_add_cb(ps, main_addr, process_bkpt_main, NULL))
+ warn("no bkpt at main 0x%lx", main_addr);
+ }
+
+ if (ps->ps_state != LOADED) {
+ fprintf(stderr, "Process already running.\n");
+ return 0;
+ }
+
+ /*
+ * XXX - there isn't really any difference between STOPPED and
+ * LOADED, we should probably get rid of one.
+ */
+ ps->ps_state = STOPPED;
+ ps->ps_signum = 0;
+
+ return (cmd_process_cont(argc, argv, arg));
+}
+
+int
+cmd_process_cont(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+ int signum;
+ int req = (ps->ps_flags & PSF_STEP) ? PT_STEP : PT_CONTINUE;
+
+ if (ps->ps_state != STOPPED) {
+ fprintf(stderr, "Process not loaded and stopped %d\n",
+ ps->ps_state);
+ return (0);
+ }
+
+ /* Catch SIGINT and SIGTRAP, pass all other signals. */
+ switch (ps->ps_signum) {
+ case SIGINT:
+ case SIGTRAP:
+ signum = 0;
+ break;
+ default:
+ signum = ps->ps_signum;
+ break;
+ }
+
+ if (ptrace(req, ps->ps_pid, (caddr_t)ps->ps_npc, signum) != 0) {
+ err(1, "ptrace(%s)", req == PT_STEP ? "PT_STEP":"PT_CONTINUE");
+ }
+
+ ps->ps_state = RUNNING;
+ ps->ps_npc = 1;
+
+ return (1);
+}
diff --git a/usr.bin/pmdb/signal.c b/usr.bin/pmdb/signal.c
new file mode 100644
index 00000000000..cac71ce737e
--- /dev/null
+++ b/usr.bin/pmdb/signal.c
@@ -0,0 +1,166 @@
+/* $PMDB: signal.c,v 1.10 2002/03/07 13:56:56 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include "pmdb.h"
+
+void
+init_sigstate(struct pstate *ps)
+{
+ int i;
+
+ for (i = 1; i < NSIG; i++)
+ ps->ps_sigstate[i] = SS_STOP;
+
+ /* XXX - add more default ignored signals. */
+ ps->ps_sigstate[SIGALRM] = SS_IGNORE;
+ ps->ps_sigstate[SIGCHLD] = SS_IGNORE;
+}
+
+void
+process_signal(struct pstate *ps, int signum, int stopped, int force_ignore)
+{
+ int ignore, status;
+
+ if (stopped && (ps->ps_sigstate[signum] == SS_IGNORE || force_ignore))
+ ignore = 1;
+ else
+ ignore = 0;
+
+ if (force_ignore && ignore)
+ signum = 0;
+
+ ps->ps_signum = signum;
+
+ if (!stopped) {
+ /*
+ * Process terminated.
+ */
+ /* Let it be restarted if it wasn't a forced termination. */
+ if ((ps->ps_flags & PSF_KILL) == 0)
+ ps->ps_state = NONE;
+ else
+ ps->ps_state = TERMINATED;
+ /*
+ * Wait for it as a parent.
+ * XXX - only if we're the real parent.
+ */
+ wait(&status);
+ } else {
+ ps->ps_state = STOPPED;
+ }
+
+ if (!ignore) {
+ fprintf(stderr, "PBMD %s child. signal: %s\n",
+ stopped ? "stopping" : "terminating",
+ sys_signame[signum]);
+ } else {
+ cmd_process_cont(0, NULL, ps);
+ }
+}
+
+int
+cmd_signal_ignore(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+ int signum;
+ long l;
+ char *ep;
+ char *signame = argv[2];
+ int newstate;
+
+ if (!strcmp(argv[1], "ignore")) {
+ newstate = SS_IGNORE;
+ } else if (!strcmp(argv[1], "stop")) {
+ newstate = SS_STOP;
+ } else {
+ goto usage;
+ }
+
+ l = strtol(signame, &ep, 0);
+ if (signame[0] == '\0' || *ep != '\0' || l < 1 || l > NSIG) {
+ if (!strncmp("SIG", signame, 3))
+ signame += 3;
+ for (signum = 1; signum < NSIG; signum++) {
+ if (!strcmp(sys_signame[signum], signame))
+ break;
+ }
+ } else {
+ signum = l;
+ }
+
+ switch (signum) {
+ case SIGINT:
+ case SIGSTOP:
+ case SIGKILL:
+ fprintf(stderr, "%s can't be ignored\n", signame);
+ goto usage;
+ case NSIG:
+ fprintf(stderr, "%s is not a valid signal\n", signame);
+ goto usage;
+ default:
+ break;
+ }
+
+ ps->ps_sigstate[signum] = newstate;
+
+ return 0;
+usage:
+ fprintf(stderr, "Usage: signal <ignore|stop> <signum|signame>\n");
+ return 0;
+}
+
+int
+cmd_signal_show(int argc, char **argv, void *arg)
+{
+ struct pstate *ps = arg;
+ int i;
+
+ for (i = 1; i < NSIG; i++) {
+ char *state;
+
+ switch (ps->ps_sigstate[i]) {
+ case SS_STOP:
+ state = "stop";
+ break;
+ case SS_IGNORE:
+ state = "ignore";
+ break;
+ default:
+ state = "error";
+ break;
+ }
+ printf("%2d %-6s\t%s\n", i, sys_signame[i], state);
+ }
+
+ return 0;
+}
diff --git a/usr.bin/pmdb/symbol.c b/usr.bin/pmdb/symbol.c
new file mode 100644
index 00000000000..8f6d1e6f64e
--- /dev/null
+++ b/usr.bin/pmdb/symbol.c
@@ -0,0 +1,160 @@
+/* $PMDB: symbol.c,v 1.5 2002/03/07 14:27:08 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <err.h>
+
+#include "pmdb.h"
+#include "symbol.h"
+
+/*
+ * Initialize the executable and the symbol table.
+ */
+void
+sym_init_exec(struct pstate *ps, const char *name)
+{
+ ps->ps_sops = NULL;
+ ps->ps_sym_exe = NULL;
+ TAILQ_INIT(&ps->ps_syms);
+
+#ifdef PMDB_ELF
+ if (sym_check_elf(name, ps))
+#endif
+#ifdef PMDB_AOUT
+ if (sym_check_aout(name, ps))
+#endif
+ warnx("sym_init_exec: %s is not a supported file format", name);
+
+ if (ps->ps_sops) {
+ ps->ps_sym_exe = st_open(ps, name);
+ if (ps->ps_sym_exe)
+ ps->ps_sym_exe->st_flags |= ST_EXEC;
+ }
+}
+
+/*
+ * Destroy all symbol tables.
+ */
+void
+sym_destroy(struct pstate *ps)
+{
+ struct sym_table *st;
+
+ while ((st = TAILQ_FIRST(&ps->ps_syms)) != NULL) {
+ TAILQ_REMOVE(&ps->ps_syms, st, st_list);
+ (*ps->ps_sops->sop_close)(st);
+ }
+ ps->ps_sym_exe = NULL;
+}
+
+/*
+ * We have reasons to believe that the symbol tables we have are not consistent
+ * with the running binary. Update.
+ */
+void
+sym_update(struct pstate *ps)
+{
+ (*ps->ps_sops->sop_update)(ps);
+}
+
+char *
+sym_name_and_offset(struct pstate *ps, reg pc, char *nam, size_t len, reg *off)
+{
+ struct sym_table *st;
+ int bestoffisset = 0;
+ reg bestoff, noff;
+ char *res;
+
+ TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
+ res = (*ps->ps_sops->sop_name_and_off)(st, pc, &noff);
+ if (res == NULL)
+ continue;
+ if (noff < bestoff || !bestoffisset) {
+ bestoffisset = 1;
+ bestoff = noff;
+ strlcpy(nam, res, len);
+ }
+ }
+
+ if (!bestoffisset || !strcmp(nam, "_end"))
+ return (NULL);
+
+ *off = bestoff;
+ return (nam);
+}
+
+int
+sym_lookup(struct pstate *ps, const char *name, reg *res)
+{
+ /*
+ * We let the sop do the table walking itself since it might have
+ * preferences about what symbols to pick (weak and stuff).
+ */
+ return ((*ps->ps_sops->sop_lookup)(ps, name, res));
+}
+
+char *
+sym_print(struct pstate *ps, reg pc, char *buf, size_t buflen)
+{
+ char namebuf[1024], *name;
+ reg offs;
+
+ name = sym_name_and_offset(ps, pc, namebuf, sizeof(namebuf), &offs);
+ if (name == NULL) {
+ snprintf(buf, buflen, "0x%lx", pc);
+ } else {
+ snprintf(buf, buflen, "%s+0x%lx(0x%lx)", name, offs, pc);
+ }
+
+ return (buf);
+}
+
+/*
+ * Open a symbol table and install it in the list. Don't do anything if
+ * it's already there.
+ */
+struct sym_table *
+st_open(struct pstate *ps, const char *name)
+{
+ struct sym_table *st;
+
+ TAILQ_FOREACH(st, &ps->ps_syms, st_list) {
+ if (!strcmp(name, st->st_fname))
+ return (st);
+ }
+
+ warnx("Loading symbols from %s", name);
+
+ if ((st = (*ps->ps_sops->sop_open)(name)) != NULL) {
+ TAILQ_INSERT_TAIL(&ps->ps_syms, st, st_list);
+ strlcpy(st->st_fname, name, sizeof(st->st_fname));
+ }
+
+ return (st);
+}
+
diff --git a/usr.bin/pmdb/symbol.h b/usr.bin/pmdb/symbol.h
new file mode 100644
index 00000000000..638e48150ff
--- /dev/null
+++ b/usr.bin/pmdb/symbol.h
@@ -0,0 +1,61 @@
+/* $PMDB: symbol.h,v 1.7 2002/03/07 14:27:08 art Exp $ */
+/*
+ * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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/param.h>
+
+struct sym_table {
+ TAILQ_ENTRY(sym_table) st_list;
+ char st_fname[MAXPATHLEN];
+ int st_flags;
+};
+
+/* Flags in st_flags */
+#define ST_EXEC 0x01 /* this is the executable */
+
+struct sym_ops {
+ struct sym_table *(*sop_open)(const char *);
+ void (*sop_close)(struct sym_table *);
+ char *(*sop_name_and_off)(struct sym_table *, reg, reg *);
+ int (*sop_lookup)(struct pstate *, const char *, reg *);
+ void (*sop_update)(struct pstate *);
+};
+
+void sym_init_exec(struct pstate *, const char *);
+void sym_destroy(struct pstate *);
+void sym_update(struct pstate *);
+char *sym_name_and_offset(struct pstate *, reg, char *, size_t, reg *);
+int sym_lookup(struct pstate *, const char *, reg *);
+char *sym_print(struct pstate *, reg, char *, size_t);
+
+/* Internal for symbol handlers only. */
+struct sym_table *st_open(struct pstate *, const char *);
+
+#ifdef PMDB_ELF
+int sym_check_elf(const char *, struct pstate *);
+#endif
+#ifdef PMDB_AOUT
+int sym_check_aout(const char *, struct pstate *);
+#endif