From 5e3b213f05d2e1bfa3cb3c2dc3790cf9852fd401 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Thu, 4 Aug 2005 08:44:16 +0000 Subject: [PATCH] import of mdb (minix debugger), some ptrace and signals unbreaking seem to have made it work (runtime debugging and core reading). --- commands/Makefile | 1 + commands/mdb/Dist | 38 + commands/mdb/MDB.TXT | 25 + commands/mdb/Makefile | 130 ++++ commands/mdb/README | 32 + commands/mdb/a.out.h | 297 ++++++++ commands/mdb/core.c | 394 ++++++++++ commands/mdb/decode.c | 360 +++++++++ commands/mdb/gnu_load.c | 76 ++ commands/mdb/gnu_sym.c | 365 +++++++++ commands/mdb/io.c | 303 ++++++++ commands/mdb/ioctl.c | 146 ++++ commands/mdb/kernel.c | 249 +++++++ commands/mdb/mdb.1 | 154 ++++ commands/mdb/mdb.c | 1028 +++++++++++++++++++++++++ commands/mdb/mdb.h | 182 +++++ commands/mdb/mdbdis86.c | 1564 +++++++++++++++++++++++++++++++++++++++ commands/mdb/mdbexp.c | 157 ++++ commands/mdb/misc.c | 289 ++++++++ commands/mdb/proto.h | 105 +++ commands/mdb/ptrace.2 | 87 +++ commands/mdb/sample | 9 + commands/mdb/sym.c | 546 ++++++++++++++ commands/mdb/syscalls.c | 85 +++ commands/mdb/trace.c | 51 ++ 25 files changed, 6673 insertions(+) create mode 100644 commands/mdb/Dist create mode 100644 commands/mdb/MDB.TXT create mode 100644 commands/mdb/Makefile create mode 100644 commands/mdb/README create mode 100644 commands/mdb/a.out.h create mode 100644 commands/mdb/core.c create mode 100644 commands/mdb/decode.c create mode 100644 commands/mdb/gnu_load.c create mode 100644 commands/mdb/gnu_sym.c create mode 100644 commands/mdb/io.c create mode 100644 commands/mdb/ioctl.c create mode 100644 commands/mdb/kernel.c create mode 100644 commands/mdb/mdb.1 create mode 100644 commands/mdb/mdb.c create mode 100644 commands/mdb/mdb.h create mode 100644 commands/mdb/mdbdis86.c create mode 100644 commands/mdb/mdbexp.c create mode 100644 commands/mdb/misc.c create mode 100644 commands/mdb/proto.h create mode 100644 commands/mdb/ptrace.2 create mode 100644 commands/mdb/sample create mode 100644 commands/mdb/sym.c create mode 100644 commands/mdb/syscalls.c create mode 100644 commands/mdb/trace.c diff --git a/commands/Makefile b/commands/Makefile index 43b7d6c85..8390508b7 100755 --- a/commands/Makefile +++ b/commands/Makefile @@ -46,6 +46,7 @@ all install clean:: cd kermit && $(MAKE) $@ cd m4 && $(MAKE) $@ cd make && $(MAKE) $@ + cd mdb && $(MAKE) $@ cd mined && $(MAKE) $@ cd patch && $(MAKE) $@ cd ps && $(MAKE) $@ diff --git a/commands/mdb/Dist b/commands/mdb/Dist new file mode 100644 index 000000000..2767deaac --- /dev/null +++ b/commands/mdb/Dist @@ -0,0 +1,38 @@ +Mdb (Minix debugger) Distribution +================================= + +Version: 2.6.0 +Date: Sept 9/96 +Author: Philip Murton +E-mail: philip.murton@utoronto.ca + + +Files included: +=============== + +Dist This file +Makefile Makefile +MDB.TXT Cover file +README README file +a.out.h GNU a.out.h (copied to /usr/include/gnu) +core.c core file functions +decode.c Optional for syscalls support +gnu_load.c Optional for GNU EXEC support +io.c I/O done here +ioctl.c Optional for syscalls support +kernel.c kernel functions +log Log from sample command file (See README) +mdb.c main program +mdb.h main header +mdb.1 man page +mdbdis86.c Disassembler +mdbexp.c Expression parsing +misc.c misc functions including help +gnu_sym.c Optional for GNU EXEC support +proto.h Prototypes +ptrace.2 man page +sample sample command file +sym.c Symbolic names read from exec file +syscalls.c Optional for syscalls support +trace.c ptrace() called here + diff --git a/commands/mdb/MDB.TXT b/commands/mdb/MDB.TXT new file mode 100644 index 000000000..e4b27bd64 --- /dev/null +++ b/commands/mdb/MDB.TXT @@ -0,0 +1,25 @@ +INFORMATION on mdb version 2.6.0 (Sept 9/96). + +MDB is the MINIX debugger which allows you to place breakpoints and +control the execution of a program. It has a lot of the features that +you would expect in a program debugger; for example, stack traces and +single step execution. + +The current version works with MINIX for PC and was developed and tested +under MINIX 1.7.x (32 bit version). It should work with 16 bit MINIX. + +How to Install + +1) Unpack mdb.tar.Z and review additional information in the README file. + (If you got this from the Minix CD-ROM or an MS-DOS system rename + MDB.TAZ to mdb.tar.Z) +2) Edit Makefile for Compiler and extra options as required. +3) make +4) make install +5) make install_man + +Comments to: + +Philip Murton. +philip.murton@utoronto.ca + diff --git a/commands/mdb/Makefile b/commands/mdb/Makefile new file mode 100644 index 000000000..7ab449a7d --- /dev/null +++ b/commands/mdb/Makefile @@ -0,0 +1,130 @@ +# +# Makefile for mdb +# +# +# Edit as indicated below. +# +USR =/usr +# +# (1) For Compiler and target system: +# +# +# For ANSI C and Minix 1.7.x 32-bit +# +CC =exec cc -O2 +LD =exec cc +LDFLAGS =-i +TARGET =mdb +STACK =100000 +# +# (2) If kernel and mm are not in "/usr/src" change this +# +SYSTEM =$(USR)/src +# +# (3) Select Options +# +# i) For GNU_EXEC Support, uncomment: +# +#FOR_GNU =gnu_sym.o gnu_load.o +#DEF_GNU =-DGNU_SUPPORT +# +# ii) For tracing of syscalls, uncomment: +# +#FOR_SYSCALLS =syscalls.o decode.o ioctl.o +#DEF_SYSCALLS =-DSYSCALLS_SUPPORT +# +# iii) For no debugging of mdb, uncomment: +# +#DEF_DEBUG =-DNDEBUG + +EXTRA_OBJS =$(FOR_GNU) $(FOR_SYSCALLS) +EXTRA_DEFS =$(DEF_GNU) $(DEF_SYSCALLS) $(DEF_DEBUG) + +all: $(TARGET) + +CFLAGS =-I$(SYSTEM) -I$(SYSTEM)/servers -I$(INCLUDE) -D_MINIX -D_POSIX_SOURCE $(EXTRA_DEFS) + +# For various included files or system files +# +INCLUDE =$(USR)/include +KERNEL =$(SYSTEM)/kernel +PTRACE =$(INCLUDE)/sys/ptrace.h + + +# Header files from pm (used by core.c) +# +MMFILES= $(SYSTEM)/servers/pm/const.h \ + $(SYSTEM)/servers/pm/type.h \ + $(SYSTEM)/servers/pm/mproc.h + +# Header files from system and kernel in "mdb.h" +# +SYSFILES= $(INCLUDE)/minix/config.h \ + $(INCLUDE)/minix/const.h \ + $(INCLUDE)/ansi.h \ + $(INCLUDE)/minix/type.h \ + $(INCLUDE)/limits.h \ + $(INCLUDE)/errno.h \ + $(INCLUDE)/sys/types.h \ + $(KERNEL)/const.h \ + $(KERNEL)/type.h \ + $(KERNEL)/proc.h + +# Common objects +# +OBJCOMMON =mdb.o mdbexp.o kernel.o sym.o trace.o core.o misc.o io.o + +# Common source +# +SRCCOMMON =mdb.c mdbexp.c kernel.o sym.c trace.c core.c misc.c io.c + +# Object files for PC +# +OBJPC =$(OBJCOMMON) mdbdis86.o + +# Source file +# +SRCPC =$(SRCCOMMON) mdbdis86.c + + +mdb: $(OBJPC) $(EXTRA_OBJS) + $(LD) $(LDFLAGS) -o mdb $(OBJPC) $(EXTRA_OBJS) + install -S $(STACK) mdb + +# +# Dependencies for objects +# +mdb.o: mdb.c mdb.h +mdbdis86.o: mdbdis86.c mdb.h +mdbexp.o: mdbexp.c mdb.h +sym.o: sym.c mdb.h +trace.o: trace.c mdb.h $(PTRACE) +core.o: core.c mdb.h $(MMFILES) +misc.o: misc.c mdb.h +io.o: io.c mdb.h +mdb.h: $(SYSFILES) proto.h + +syscalls.o: syscalls.c mdb.h +decode.o: decode.c mdb.h $(INCLUDE)/minix/callnr.h +ioctl.o: ioctl.c mdb.h + +gnu_sym.o: gnu_sym.c mdb.h $(INCLUDE)/gnu/a.out.h +gnu_load.o: gnu_load.c $(INCLUDE)/gnu/a.out.h + +$(INCLUDE)/gnu/a.out.h: a.out.h + install -c -o bin a.out.h $(INCLUDE)/gnu + + +# +# install +# + +install: mdb + install -cs -o bin mdb /usr/local/bin + +install_man: mdb.1 ptrace.2 + install -c -o bin mdb.1 /usr/man/man1 + install -c -o bin ptrace.2 /usr/man/man2 +clean: + rm -f *.o mdb + diff --git a/commands/mdb/README b/commands/mdb/README new file mode 100644 index 000000000..21600f634 --- /dev/null +++ b/commands/mdb/README @@ -0,0 +1,32 @@ +README for mdb version 2.6.0 + +Sept 9/96 + +Please note the following: + +1) Has been tested with Minix 1.7.4 (32-bit version). + A previous version was tested with Minix 1.7.x (16 bit version). + Some optional parts of mdb have not been extensively tested. + This is especially true on the code to trace system calls. + See options in Makefile. + +2) I know that the commands are somewhat cryptic; thus + there are currently two types of 'help' for mdb + a) the "?" gives a help page. + b) typing "command ?" will give help on a specific command. + +3) The sample comand file and log output. + To test this, type something like the following + "mdb -llog.new /usr/bin/sleep @sample" + The output "log.new' should be similar to the distributed "log" file; + but not necessarily exactly the same. + +4) Man pages need some more work. + +5) See top part of mdb.c for version history. + +Send comments to Philip Murton. Thanks. + +philip.murton@utoronto.ca + + diff --git a/commands/mdb/a.out.h b/commands/mdb/a.out.h new file mode 100644 index 000000000..521dc70ab --- /dev/null +++ b/commands/mdb/a.out.h @@ -0,0 +1,297 @@ +/* + * MINIX 1.7.x + * GNU version based on Linux 1.1.45 version + * if _MINIX_EXEC defined use old MINIX GNU format + */ + +#ifndef __A_OUT_GNU_H__ +#define __A_OUT_GNU_H__ + +#define __GNU_EXEC_MACROS__ + +#ifndef __STRUCT_EXEC_OVERRIDE__ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +#ifdef _MINIX_EXEC + unsigned a_smagic; /* SMAGIC */ + unsigned a_memsize; /* Dynamic Memory Size */ +#endif +}; + +#ifdef _MINIX_EXEC +#define GNU_SMAGIC 0xdeadbabe +#define GNU_DYNMEM (64 * 1024) +#else +#define GNU_STACK 64 /* Default Stack */ +#endif + +#endif /* __STRUCT_EXEC_OVERRIDE__ */ + +/* these go in the N_MACHTYPE field */ +enum machine_type { +#if defined (M_OLDSUN2) + M__OLDSUN2 = M_OLDSUN2, +#else + M_OLDSUN2 = 0, +#endif +#if defined (M_68010) + M__68010 = M_68010, +#else + M_68010 = 1, +#endif +#if defined (M_68020) + M__68020 = M_68020, +#else + M_68020 = 2, +#endif +#if defined (M_SPARC) + M__SPARC = M_SPARC, +#else + M_SPARC = 3, +#endif + /* skip a bunch so we don't run into any of sun's numbers */ + M_386 = 100 +}; + +#if !defined (N_MAGIC) +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#endif +#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#define N_SET_INFO(exec, magic, type, flags) \ + ((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#define N_SET_MAGIC(exec, magic) \ + ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) + +#define N_SET_MACHTYPE(exec, machtype) \ + ((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) + +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) + +#ifdef _MINIX +#define N_SET_MEMORY(exec, mem) \ + ((exec).a_info = \ + ((exec).a_info & 0x0000FFFF) | (((mem) & 0xFFFF) << 16)) +#define N_MEMORY(exec) (((exec).a_info >> 16) & 0xFFFF) +#endif + +/* Code indicating object file or impure executable. */ +#define OMAGIC 0407 +/* Code indicating pure executable. */ +#define NMAGIC 0410 +/* Code indicating demand-paged executable. */ +#define ZMAGIC 0413 +/* This indicates a demand-paged executable with the header in the text. + The first page is unmapped to help trap NULL pointer references */ +#define QMAGIC 0314 + +/* Code indicating core file. */ +#define CMAGIC 0421 + +#if !defined (N_BADMAG) +#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC \ + && N_MAGIC(x) != QMAGIC) +#endif + +#define _N_HDROFF(x) (1024 - sizeof (struct exec)) + +#if !defined (N_TXTOFF) +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ + (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) +#endif + +#if !defined (N_DATOFF) +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) +#endif + +#if !defined (N_TRELOFF) +#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) +#endif + +#if !defined (N_DRELOFF) +#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) +#endif + +#if !defined (N_SYMOFF) +#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) +#endif + +#if !defined (N_STROFF) +#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) +#endif + +/* Address of text segment in memory after it is loaded. */ +#if !defined (N_TXTADDR) +#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? PAGE_SIZE : 0) +#endif + +/* Address of data segment in memory after it is loaded. + Note that it is up to you to define SEGMENT_SIZE + on machines not listed here. */ +#if defined(vax) || defined(hp300) || defined(pyr) +#define SEGMENT_SIZE page_size +#endif +#ifdef sony +#define SEGMENT_SIZE 0x2000 +#endif /* Sony. */ +#ifdef is68k +#define SEGMENT_SIZE 0x20000 +#endif +#if defined(m68k) && defined(PORTAR) +#define PAGE_SIZE 0x400 +#define SEGMENT_SIZE PAGE_SIZE +#endif + +#ifndef PAGE_SIZE +#define PAGE_SIZE 1024 +#endif + +#ifndef SEGMENT_SIZE +#define SEGMENT_SIZE PAGE_SIZE +#endif + +#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1)) + +#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) + +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) +#endif + +/* Address of bss segment in memory after it is loaded. */ +#if !defined (N_BSSADDR) +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) +#endif + +#if !defined (N_NLIST_DECLARED) +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; + } n_un; + unsigned char n_type; + char n_other; + short n_desc; + unsigned long n_value; +}; +#endif /* no N_NLIST_DECLARED. */ + +#if !defined (N_UNDF) +#define N_UNDF 0 +#endif +#if !defined (N_ABS) +#define N_ABS 2 +#endif +#if !defined (N_TEXT) +#define N_TEXT 4 +#endif +#if !defined (N_DATA) +#define N_DATA 6 +#endif +#if !defined (N_BSS) +#define N_BSS 8 +#endif +#if !defined (N_FN) +#define N_FN 15 +#endif + +#if !defined (N_EXT) +#define N_EXT 1 +#endif +#if !defined (N_TYPE) +#define N_TYPE 036 +#endif +#if !defined (N_STAB) +#define N_STAB 0340 +#endif + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. */ +#define N_INDR 0xa + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + element's value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +#if !defined (N_RELOCATION_INFO_DECLARED) +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct relocation_info +{ + /* Address (within segment) to be relocated. */ + int r_address; + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in file's the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* Four bits that aren't used, but when writing an object file + it is desirable to clear them. */ +#ifdef NS32K + unsigned r_bsr:1; + unsigned r_disp:1; + unsigned r_pad:2; +#else + unsigned int r_pad:4; +#endif +}; +#endif /* no N_RELOCATION_INFO_DECLARED. */ + + +#endif /* __A_OUT_GNU_H__ */ diff --git a/commands/mdb/core.c b/commands/mdb/core.c new file mode 100644 index 000000000..4eda5af8b --- /dev/null +++ b/commands/mdb/core.c @@ -0,0 +1,394 @@ +/* + * core.c for mdb + * + * reads information from 'core' file + * Partly derived from 'adb' by D. Dugger. + */ +#include + +#include "mdb.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* defined in kernel.c */ +extern struct proc *prc; + +#include "proto.h" + +#define BSIZE 512 +#define LOGBS 9 + +PRIVATE struct file { + int fid; + char *name; + long cblock; + long tmap[3]; + long dmap[3]; + long smap[3]; + char buf[BSIZE + BSIZE]; +} Core_File, *core_file; + +#define b1 tmap[0] +#define e1 tmap[1] +#define f1 tmap[2] +#define b2 dmap[0] +#define e2 dmap[1] +#define f2 dmap[2] +#define b3 smap[0] +#define e3 smap[1] +#define f3 smap[2] + +PRIVATE long cnt[3]; /* Sizes of segments */ +PRIVATE int h_size; /* Size of core header */ +PRIVATE char def_name[] = "core"; /* Default core name */ + +#define SIZE_MP_SEG (sizeof(struct mem_map) * NR_LOCAL_SEGS) +#define SIZE_KINFO sizeof(struct proc) +#define SIZE_HEADER SIZE_MP_SEG + +FORWARD _PROTOTYPE( int kernel_info , (int fd )); +FORWARD _PROTOTYPE( void setmap , (struct file *fp )); +FORWARD _PROTOTYPE( void read_info , (struct file *fp )); +FORWARD _PROTOTYPE( void ill_addr , (long d , int segment )); +FORWARD _PROTOTYPE( long map_addr , (long d , int segment )); +FORWARD _PROTOTYPE( unsigned long c_status, (void)); +FORWARD _PROTOTYPE( long getn, (long d, int s) ); + +/* + * set and display mapping for core file + */ +PRIVATE void setmap(fp) +struct file *fp; +{ +long h = (long) h_size; + + fp->b1 = st_addr; + fp->e1 = st_addr + cnt[T]; + fp->f1 = h; + + fp->b2 = sd_addr; + fp->e2 = sd_addr + cnt[D]; + fp->f2 = cnt[T] + h; + + fp->b3 = sk_addr; + fp->e3 = sk_addr + cnt[S]; + fp->f3 = cnt[T] + cnt[D] + h; + +#ifdef MINIX_PC + if(is_separate) { + if ( end_addr < et_addr ) end_addr = et_addr; + } + else { + fp->b2 = st_addr; + fp->e2 = st_addr + cnt[T] + cnt[D]; + fp->f2 = h; + end_addr = fp->e2; + + fp->b1 = 0; + fp->e1 = -1; + fp->f1 = 0; + } +#endif + Printf("From core file:\n"); + Printf("T\t%8lx %8lx %8lx\n", core_file->b1, core_file->e1, core_file->f1); + Printf("D\t%8lx %8lx %8lx\n", core_file->b2, core_file->e2, core_file->f2); + Printf("S\t%8lx %8lx %8lx\n", core_file->b3, core_file->e3, core_file->f3); + Printf("\n"); + +} + +/* Print mapping */ +PUBLIC void prtmap() +{ + Printf("%s I & D space\t", (is_separate) ? "Separate " : "Combined "); + if (corepid > 0) { + Printf("File: %s\n\n", core_file->name); + setmap(core_file); + disp_maps(); + } + else { + Printf("Pid: %d\n\n", curpid); + update(); + disp_maps(); + } +} + +/* Illegal address */ +PRIVATE void ill_addr(d, segment) +long d; +int segment; +{ + Printf("Bad addr=%lx seg=%d",d,segment); + mdb_error("\n"); +} + +/* Map virtual address -> core file addresses + * depends on current segment if Separate I & D + */ +PRIVATE long map_addr(d, segment) +long d; +int segment; +{ +#ifdef MINIX_PC + if (is_separate) + switch (segment) { + case T: + if (d >= core_file->b1 && d < core_file->e1) + d += core_file->f1 - core_file->b1; + else + ill_addr(d,segment); + break; + case D: + case S: + if (d >= core_file->b2 && d < core_file->e2) + d += core_file->f2 - core_file->b2; + else if (d >= core_file->b3 && d < core_file->e3) + d += core_file->f3 - core_file->b3; + else + ill_addr(d,segment); + break; + } + else { +#endif + if (d >= core_file->b1 && d < core_file->e1) + d += core_file->f1 - core_file->b1; + else if (d >= core_file->b2 && d < core_file->e2) + d += core_file->f2 - core_file->b2; + else if (d >= core_file->b3 && d < core_file->e3) + d += core_file->f3 - core_file->b3; + else + ill_addr(d,segment); +#ifdef MINIX_PC + } +#endif + return d; +} + + +/* Get value with address d and segment s */ +PRIVATE long getn(d, s) +long d; +int s; +{ + long b; + register int o,i; + union { + unsigned long l; + unsigned char c[4]; + } data; + + /* Map address */ + d = map_addr(d, s); + + b = d >> LOGBS; + o = d & (BSIZE - 1); + + if (core_file->cblock != b) { + core_file->cblock = b; + lseek(core_file->fid, b << LOGBS, 0); + read(core_file->fid, core_file->buf, sizeof(core_file->buf)); + } + + for(i = 0; i<4; i++) + data.c[i] = core_file->buf[o+i]; + +#ifdef DEBUG + if (debug) + Printf("getn at %8lx val %8lx\n", d, data.l); +#endif + return data.l; +} + +/* Read kernel info from core file into lbuf[] */ +PRIVATE int kernel_info(fd) +int fd; +{ + int r; + int ks; + + /* Round SIZE_KINFO to multiple of sizeof(long) */ + /* See mm/signal.c to see how a 'core' file is written */ + ks = ( SIZE_KINFO / sizeof(long) ) * sizeof(long); + r = read(fd, (char *)lbuf, ks); + return(r == ks) ? ks : -1; +} + +/* + * Print status info from core - returns PC + */ +PRIVATE unsigned long c_status() +{ + fprintf(stderr, "WARNING: don't know pid from core; using proc nr for pid.\n"); + + Printf("Proc = %6d\n", prc->p_nr); + + /* Set current pid to that of core */ + curpid = corepid = prc->p_nr; + disp_maps(); + Printf("\nPC = 0x%0*lx\t", 2 * ADDRSIZE, PC_MEMBER(prc) & MASK(ADDRSIZE)); + symbolic((long) PC_MEMBER(prc), '\n'); + dasm((long) PC_MEMBER(prc), 1, 1); + return PC_MEMBER(prc); +} + +/* Read memory maps and kernel info from core file */ +PRIVATE void read_info(fp) +struct file *fp; +{ + struct mproc mm_info; + struct mproc *rmp; + int r; + int i; + + rmp = &mm_info; + lseek(fp->fid, 0L, 0L); + + /* First read memory map of all segments. */ + if (read(fp->fid, (char *) rmp->mp_seg, (int) SIZE_MP_SEG) < 0) { + close(fp->fid); + Printf("mdb: cannot read core header\n"); + fp->fid = -1; + return; + } + h_size = SIZE_HEADER; + + /* Read kernel dependent info */ + r = kernel_info(fp->fid); + if (r < 0) { + close(fp->fid); + Printf("mdb: cannot read kernel info from 'core' file\n"); + fp->fid = -1; + return; + } else + h_size += r; + + /* copy info */ + for (i = T; i <= S; i++) + cnt[i] = (long) rmp->mp_seg[i].mem_len << CLICK_SHIFT; + + /* This needs to be set for map_addr() below */ + if(coreonly && cnt[T] != 0) is_separate = TRUE; + + st_addr = (long) rmp->mp_seg[T].mem_vir << CLICK_SHIFT; + et_addr = st_addr + ((long) rmp->mp_seg[T].mem_len << CLICK_SHIFT); + + sd_addr = (long) rmp->mp_seg[D].mem_vir << CLICK_SHIFT; + end_addr = ed_addr = + sd_addr + ((long) rmp->mp_seg[D].mem_len << CLICK_SHIFT); + + sk_addr = (long) rmp->mp_seg[S].mem_vir << CLICK_SHIFT; + sk_size = (long) rmp->mp_seg[S].mem_len << CLICK_SHIFT; + + setmap(fp); +} + +/* initialization for core files + * returns PC address from core file + */ +PUBLIC unsigned long core_init(filename) +char *filename; +{ + core_file = &Core_File; + core_file->name = (filename != NULL) ? filename : def_name; + + core_file->fid = open(core_file->name, 0); + if (filename != NULL && core_file->fid < 0) { + Printf("mdb - warning cannot open: %s\n", core_file->name); + return -1; + } + + core_file->b1 = core_file->b2 = core_file->b3 = 0; + core_file->e1 = core_file->e2 = core_file->e3 = -1; + core_file->f1 = core_file->f2 = core_file->f3 = 0; + core_file->cblock = -1; + + if (core_file->fid > 0) { + read_info(core_file); + return c_status(); + } + return 0; +} + + +/* initialization for a file ( -f option ) + * always returns 0 + * Similar to core files. + */ +PUBLIC unsigned long file_init(filename) +char *filename; +{ + core_file = &Core_File; + core_file->name = (filename != NULL) ? filename : def_name; + + core_file->fid = open(core_file->name, 0); + if (filename != NULL && core_file->fid < 0) { + Printf("mdb - warning cannot open: %s\n", core_file->name); + return -1; + } + + core_file->b1 = core_file->b2 = core_file->b3 = 0; + core_file->e1 = core_file->e2 = core_file->e3 = -1; + core_file->f1 = core_file->f2 = core_file->f3 = 0; + core_file->cblock = -1; + + is_separate = FALSE; + core_file->e1 = file_size(core_file->fid); + curpid = corepid = 1; + return 0; + +} + +/* + * Read from core file + * Called by mdbtrace() + */ +PUBLIC long read_core(req, addr, data) +int req; +long addr, data; +{ +int i; +int segment; +long val; + + switch (req) { + case T_GETINS: + case T_GETDATA: + /* Check segment and address - call getn to read core file */ + segment = (req == T_GETINS) ? T : D; + addr &= MASK(ADDRSIZE); + val = getn(addr, segment); +#ifdef DEBUG + if (debug) Printf("val=>%lx\n", val); +#endif + return val; + break; + case T_GETUSER: + /* Convert addr to index to long array */ + i = (int) (addr >> 2); +#ifdef DEBUG + if (debug) Printf("lbuf[%d] %lx\n", i, lbuf[i]); +#endif + return lbuf[i]; + break; + case T_OK: + case T_EXIT: + return 0L; + break; + default: + mdb_error("Not supported with 'core' files\n"); + } +} + diff --git a/commands/mdb/decode.c b/commands/mdb/decode.c new file mode 100644 index 000000000..7d373735b --- /dev/null +++ b/commands/mdb/decode.c @@ -0,0 +1,360 @@ +/* + * decode.c for mdb -- decodes a Minix system call + */ +#include "mdb.h" +#ifdef SYSCALLS_SUPPORT +#include +#include +#include +#include +#include +#define ptrace mdbtrace +#include +#include +#include +#include "proto.h" + +FORWARD _PROTOTYPE( void get_message, (message *m, unsigned bx) ); +FORWARD _PROTOTYPE( void get_data, (char *s, unsigned bx, int cnt) ); + +PRIVATE message sent; +PRIVATE message recv; +PRIVATE unsigned saved_addr; +PRIVATE int last_call; + +#define NOSYS 0 +#define NOP 1 + +#define _M1 0x0100 +#define _M2 0x0200 +#define _M3 0x0400 +#define _M4 0x0800 + +#define _M13 0x0500 + +#define M1_I1 (_M1|1) +#define M1_I2 (_M1|2) +#define M1_I3 (_M1|4) +#define M1_P1 (_M1|8) +#define M1_P2 (_M1|16) +#define M1_P3 (_M1|32) + +#define M2_I1 (_M2|1) +#define M2_I2 (_M2|2) +#define M2_I3 (_M2|4) +#define M2_L1 (_M2|8) +#define M2_L2 (_M2|16) +#define M2_P1 (_M2|32) + +#define M3_I1 (_M3|1) +#define M3_I2 (_M3|2) +#define M3_P1 (_M3|4) +#define M3_C1 (_M3|8) + +#define M4_L1 (_M4|1) +#define M4_L2 (_M4|2) +#define M4_L3 (_M4|4) +#define M4_L4 (_M4|8) +#define M4_L5 (_M4|16) + +#define M13_OPEN (_M13|1) + +#define M1_I12 (M1_I1|M1_I2) +#define M1_NAME1 (M1_I1|M1_P1) +#define M1_NAME2 (M1_I2|M1_P2) +#define M1_2NAMES (M1_I1|M1_P1|M1_I2|M1_P2) +#define M1_SIGACTION (M1_I2|M1_P1|M1_P2|M1_P3) + +#define M2_IOCTL (M2_I1|M2_I3|M2_L1|M2_L2) +#define M2_4P (M2_I1|M2_I2|M2_L1|M2_L2) +#define M2_SIGRETURN (M2_I2|M2_L1|M2_P1) +#define M2_SIGPROC (M2_I1|M2_L1) +#define M2_UTIME (M2_I1|M2_I2|M2_L1|M2_L2|M2_P1) + +#define M3_LOAD (M3_I1|M3_C1) + +struct decode_system { + int syscall; + unsigned int sflag; + unsigned int rflag; + char *name; +} decode[NCALLS] = { + 0, NOSYS, NOP, NULL, + EXIT, M1_I1, NOP, "EXIT", + FORK, NOP, NOP, "FORK", + READ, M1_I12, NOP, "READ", + WRITE, M1_I12, NOP, "WRITE", + OPEN, M13_OPEN, NOP, "OPEN", + CLOSE, M1_I1, NOP, "CLOSE", + WAIT, NOP, M2_I1, "WAIT", + CREAT, M3_LOAD, NOP, "CREAT", + LINK, M1_2NAMES, NOP, "LINK", + UNLINK, M3_LOAD, NOP, "UNLINK", + WAITPID, M1_I1, M2_I1, "WAITPID", + CHDIR, M3_LOAD, NOP, "CHDIR", + TIME, NOP, M2_L1, "TIME", + MKNOD, M1_NAME1, NOP, "MKNOD", + CHMOD, M3_LOAD, NOP, "CHMOD", + CHOWN, M1_NAME1, NOP, "CHOWN", + BRK, M1_P1, M2_P1, "BRK", + STAT, M1_NAME1, NOP, "STAT", + LSEEK, M1_I1, NOP, "LSEEK", + GETPID, NOP, NOP, "GETPID", + MOUNT, M1_2NAMES, NOP, "MOUNT", + UMOUNT, M3_LOAD, NOP, "UMOUNT", + SETUID, M1_I1, NOP, "SETUID", + GETUID, NOP, NOP, "GETUID", + STIME, M2_L1, NOP, "STIME", + PTRACE, M2_4P, NOP, "PTRACE", + ALARM, M1_I1, NOP, "ALARM", + FSTAT, M1_I1, NOP, "FSTAT", + PAUSE, NOP, NOP, "PAUSE", + UTIME, M2_UTIME, NOP, "UTIME", + 31, NOSYS, NOP, NULL, + 32, NOSYS, NOP, NULL, + ACCESS, M3_LOAD, NOP, "ACCESS", + 34, NOSYS, NOP, NULL, + 35, NOSYS, NOP, NULL, + SYNC, NOP, NOP, "SYNC", + KILL, M1_I12, NOP, "KILL", + RENAME, M1_2NAMES, NOP, "RENAME", + MKDIR, M1_NAME1, NOP, "MKDIR", + RMDIR, M3_LOAD, NOP, "RMDIR", + DUP, NOP, NOP, "DUP", + PIPE, NOP, M1_I12, "PIPE", + TIMES, M4_L5, NOP, "TIMES", + 44, NOSYS, NOP, NULL, + 45, NOSYS, NOP, NULL, + SETGID, M1_I1, NOP, "SETGID", + GETGID, NOP, NOP, "GETGID", + SIGNAL, NOP, NOP, "SIGNAL", + 49, NOSYS, NOP, NULL, + 50, NOSYS, NOP, NULL, + 51, NOSYS, NOP, NULL, + 52, NOSYS, NOP, NULL, + 53, NOSYS, NOP, NULL, + IOCTL, M2_IOCTL, M2_IOCTL, "IOCTL", + FCNTL, M1_I12, NOP, "FCNTL", +#if ENABLE_SYMLINK + RDLINK, M1_NAME1, NOP, "RDLINK", + SLINK, M1_NAME1, NOP, "SLINK", + LSTAT, M1_NAME1, NOP, "LSTAT", +#else + 56, NOSYS, NOP, NULL, + 57, NOSYS, NOP, NULL, + 58, NOSYS, NOP, NULL, +#endif + EXEC, M1_NAME1, NOP, "EXEC", + UMASK, M1_I1, NOP, "UMASK", + CHROOT, M3_LOAD, NOP, "CHROOT", + SETSID, NOP, NOP, "SETSID", + GETPGRP, NOP, NOP, "GETPGRP", + KSIG, NOSYS, NOP, "KSIG", + UNPAUSE, NOSYS, NOP, "UNPAUSE", + 66, NOSYS, NOP, NULL, + REVIVE, NOSYS, NOP, "REVIVE", + TASK_REPLY, NOSYS, NOP, "TASK_REPLY", + 69, NOSYS, NOP, NULL, + 70, NOSYS, NOP, NULL, + SIGACTION, M1_SIGACTION, NOP, "SIGACTION", + SIGSUSPEND, M2_L1, NOP, "SIGSUSPEND", + SIGPENDING, NOP, M2_L1, "SIGPENDING", + SIGPROCMASK, M2_SIGPROC, NOP, "SIGPROCMASK", + SIGRETURN, M2_SIGRETURN, NOP, "SIGRETURN", + REBOOT, M1_I1, NOP, "REBOOT" +}; + +PRIVATE void get_message(m,bx) +message *m; +unsigned bx; +{ + unsigned addr; + int i; + long buffer[ MESS_SIZE/4 + 1 ]; + + addr = bx; + for (i = 0; i< sizeof(buffer)/4; i++) + buffer[i] = ptrace(T_GETDATA,curpid, + (long) (addr+i*4) ,0L); + + memcpy(m,buffer,MESS_SIZE); + +} + +PRIVATE void get_data(s, bx, cnt) +char *s; +unsigned bx; +int cnt; +{ + unsigned addr; + int i,nl; + long buffer[PATH_MAX/4 + 1]; + + addr = bx; + nl = (cnt / 4) + 1; + for (i = 0; i< nl; i++) + buffer[i] = ptrace(T_GETDATA, curpid, (long) (addr+i*4) ,0L); + + memcpy(s, buffer, cnt); +} + + +PUBLIC void decode_result() +{ + + /* Update message */ + get_message(&recv,saved_addr); + Printf("result=%d\n", recv.m_type); + + if (last_call < 0 || last_call >NCALLS) { + Printf("Bad call in decode_result\n"); + return; + } + + switch (decode[last_call].rflag) { + case NOP: + return; + break; + case M1_I12: + Printf("m1_l1=%d m1_i2=%d ",recv.m1_i1,recv.m1_i2); + break; + case M2_IOCTL: + decode_ioctl('R',&recv); + break; + case M2_P1: + Printf("m2_p1=%lx ",(unsigned long)recv.m2_p1); + break; + case M2_L1: + Printf("m2_l1=%lx ",recv.m2_l1); + break; + case M2_I1: + Printf("m2_i1=%x ",recv.m2_i1); + break; + default: + Printf("rflag=%d ",decode[last_call].rflag); + break; + } + Printf("\n"); +} + + +void decode_message(bx) +unsigned bx; +{ +int t; +int slen; +unsigned int flag; +char path[PATH_MAX]; + + /* Save address of message */ + saved_addr = bx; + get_message(&sent,bx); + + t = sent.m_type; + + if ( t <= 0 || t >= NCALLS ) { + Printf("Bad call - not in range\n"); + last_call = 0; + return; + } + + flag = decode[t].sflag; + + if ( flag == NOSYS) { + Printf("Bad call - not in system\n"); + last_call = 0; + return; + } + else + last_call = t; + + Printf(" type %s (%d) ", decode[last_call].name, last_call); + + switch (flag) { + case NOP: + break; + case M1_I1: + case M1_I12: + Printf("i1=%d ",sent.m1_i1); + if ( flag == M1_I1) break; + case M1_I2: + Printf("i2=%d ",sent.m1_i2); + break; + case M1_P1: + Printf("p1=%lx ",(unsigned long)sent.m1_p1); + break; + case M1_NAME1: + case M1_2NAMES: + slen = sent.m1_i1; + get_data(path, (unsigned long) sent.m1_p1, slen); + path[slen] = '\0'; + Printf("s1=%s ",path); + if ( flag == M1_NAME1) break; + slen = sent.m1_i2; + get_data(path, (unsigned long) sent.m1_p2, slen); + path[slen] = '\0'; + Printf("s2=%s ",path); + break; + case M2_UTIME: + if ( sent.m2_i1 == 0 ) + slen = sent.m2_i2; + else + slen = sent.m2_i1; + get_data(path, (unsigned long) sent.m2_p1, slen); + path[slen] = '\0'; + Printf("p1=%s ",path); + if ( sent.m2_i1 != 0 ) + Printf("l1=%lx l2=%lx ",sent.m2_l1,sent.m2_l2); + break; + case M1_SIGACTION: + Printf("m1_i2=%d p1=%lx p2=%lx p3=%lx\n", + sent.m1_i2, + (unsigned long)sent.m1_p1, + (unsigned long)sent.m1_p2, + (unsigned long)sent.m1_p3); + break; + case M2_4P: Printf("m2_i1=%d m2_i2=%d m2_l1=%lx m2_l2=%lx ", + sent.m2_i1,sent.m2_i2,sent.m2_l1,sent.m2_l2); + break; + case M2_L1: + Printf("m2_l1=%ld ",sent.m2_l1); + break; + case M2_IOCTL: + decode_ioctl('S',&sent); + break; + case M2_SIGRETURN: + Printf("m2_i2=%d l1=%lx p1=%lx ", + sent.m2_i2,sent.m2_l1, + (unsigned long)sent.m1_p1); + break; + case M2_SIGPROC: + Printf("m2_i1=%d l1=%lx ", sent.m2_i1,sent.m2_l1); + break; + case M13_OPEN: + if (sent.m1_i2 & O_CREAT) { + slen = sent.m1_i1; + get_data(path, (unsigned long) sent.m1_p1, slen); + path[slen] = '\0'; + Printf("s1=%s ",path); + break; + } + /* fall to M3_LOAD */ + case M3_LOAD: + slen = sent.m3_i1; + if ( slen <= M3_STRING) + strncpy(path,sent.m3_ca1,M3_STRING); + else + get_data(path, (unsigned long) sent.m3_ca1, slen); + path[slen] = '\0'; + Printf("m3_name=%s ",path); + break; + case M4_L5: + Printf("m4_l5=%ld ",sent.m4_l5); + break; + default: Printf("sflag=%d ",decode[last_call].sflag); + break; + } + Printf("\n"); +} + +#endif /* SYSCALLS_SUPPORT */ diff --git a/commands/mdb/gnu_load.c b/commands/mdb/gnu_load.c new file mode 100644 index 000000000..bc3e2aba3 --- /dev/null +++ b/commands/mdb/gnu_load.c @@ -0,0 +1,76 @@ +/* + * gnu_load for mdb.c + */ + +#include +#include +#include +#include +#include +#include + +_PROTOTYPE( unsigned int gnu_load, (char *filename, struct nlist **start) ); +_PROTOTYPE( void do_error, (char *message) ); + +unsigned int gnu_load( filename, start) +char *filename; +struct nlist **start; +{ + struct exec header; + unsigned int nsym, string_size; + char *names; + struct nlist *p; + int fd; + + if ( (fd = open( filename, 0)) < 0 || + read( fd, (char *) &header, sizeof header ) != sizeof header ) + { + do_error( "gnu_load" ); + if ( fd >= 0) close( fd ); + return 0; + } + + if ( lseek( fd, N_STROFF( header ), 0 ) != N_STROFF( header ) ) + { + do_error( "gnu_load - reading header" ); + close( fd ); + return 0; + } + + if ( read( fd, (char *) &string_size, sizeof string_size ) < 0 ) + { + do_error( "gnu_load - reading header" ); + close( fd ); + return 0; + } + + if ( (int) header.a_syms < 0 || + (unsigned) header.a_syms != header.a_syms || + (*start = (struct nlist *) malloc( (unsigned) header.a_syms + + string_size )) + == (struct nlist *) NULL && + header.a_syms != 0 ) + { + close( fd ); + return 0; + } + + lseek( fd, N_SYMOFF( header ), 0 ); + + if ( read( fd, (char *) *start, (int) header.a_syms + string_size ) < 0 ) + { + do_error( "gnu_load - reading symbols" ); + close( fd ); + return 0; + } + close( fd ); + + nsym = (unsigned int) header.a_syms / sizeof (struct nlist); + names = (char *) *start + header.a_syms; + + for ( p = *start; p < *start + nsym; p++) + if(p->n_un.n_strx) + p->n_un.n_name = names + p->n_un.n_strx; + + return nsym; +} diff --git a/commands/mdb/gnu_sym.c b/commands/mdb/gnu_sym.c new file mode 100644 index 000000000..0dd254521 --- /dev/null +++ b/commands/mdb/gnu_sym.c @@ -0,0 +1,365 @@ +/* + * gnu_sym.c for mdb + * copied and modified from sym.c + * Support GNU Exec symbol tables + */ + +#include "mdb.h" + +#ifdef EXTRA_SYMBOLS + +#include +#include +#include +#include +#if GNU_SUPPORT +#include +#endif +#include "proto.h" + +#if GNU_SUPPORT +_PROTOTYPE( PUBLIC unsigned int gnu_load, (char *filename, struct nlist **start) ); +#endif + +struct symtab_s +{ + struct nlist *start; + struct nlist *end; + unsigned int nsym; +}; + +PRIVATE struct symtab_s symtab; + +FORWARD _PROTOTYPE( void gnu_sort , (struct nlist *array , struct nlist *top )); +FORWARD _PROTOTYPE( int gnu_symeq , (char *t , struct nlist *sp )); +FORWARD _PROTOTYPE( int gnu_symprefix , (char *t , struct nlist *sp )); +FORWARD _PROTOTYPE( struct nlist *gnu_sname, (char *name, int is_text, int allflag) ); +FORWARD _PROTOTYPE( struct nlist *gnu_sval, (off_t value, int where) ); +FORWARD _PROTOTYPE( void gnu_sym, (struct nlist *sp, off_t off) ); + +PUBLIC void gnu_init( filename ) +char *filename; +{ + register struct symtab_s *tp; + + tp = &symtab; + + tp->nsym = gnu_load(filename, &tp->start); + tp->end = tp->start + tp->nsym; + + /* sort on value only, name search not used much and storage a problem */ + Printf("Sorting %d GNU symbols ....", tp->nsym ); + gnu_sort( tp->start, tp->end ); + Printf("\n"); +} + + + +PUBLIC long gnu_symbolvalue( name, is_text ) +char *name; +int is_text; +{ + register struct nlist *sp; + sp = gnu_sname(name,is_text,0); + if (sp != NULL) + return sp->n_value; + else + return 0L; +} + + +PRIVATE struct nlist *gnu_sname( name, is_text, allflag ) +char *name; +int is_text; +int allflag; +{ + char *s; + unsigned char sclass; + int schar; + char *send; + register struct nlist *sp; + register struct symtab_s *tp; + + tp = &symtab; + + if ( allflag ) + { + /* find and print all matching symbols */ + for ( sp = tp->start; sp < tp->end; ++sp ) + { + if ( gnu_symprefix( name, sp ) ) + { + sp = sp; + for ( s = sp->n_un.n_name, send = s + strlen(s); + *s != 0 && s < send; ++s ) + outbyte( *s ); + for ( ; s <= send; ++s ) + outspace(); + switch( sp->n_type & N_TYPE ) + { + case N_ABS: schar = 'a'; break; + case N_TEXT: schar = 't'; break; + case N_DATA: schar = 'd'; break; + case N_BSS: schar = 'b'; break; + default: schar = '?'; break; + } + if ( (sp->n_type & N_EXT) && schar != '?' ) + schar += 'A' - 'a'; + outbyte( schar ); + outspace(); + outh32( sp->n_value ); + outbyte('\n'); + } + } + } + else + { + /* find symbol by dumb linear search */ + for ( sp = tp->start; sp < tp->end; ++sp ) + { + sclass = sp->n_type & N_TYPE; + if ( (is_text && sclass == N_TEXT || + !is_text && (sclass == N_DATA || sclass == N_BSS)) && + gnu_symeq( name, sp ) ) + return sp; + } + } + return NULL; +} + +PRIVATE struct nlist *gnu_sval( value, where ) +off_t value; +int where; +{ + int left; + int middle; + int right; + unsigned char sclass; + register struct nlist *sp; + register struct symtab_s *tp; + + tp = &symtab; + + /* find last symbol with value <= desired one by binary search */ + for ( left = 0, right = tp->nsym - 1; left <= right; ) + { + middle = (left + right) / 2; + sp = tp->start + middle; + if ( value < sp->n_value ) + right = middle - 1; + else + left = middle + 1; + } + if ( right >= 0 ) + /* otherwise tp->start + right may wrap around to > tp->start !! */ + for ( sp = tp->start + right; sp >= tp->start; --sp ) + { + if ( !(sp->n_type & N_EXT) ) continue; + sclass = sp->n_type & N_TYPE; + if ( (where == CSEG && sclass == N_TEXT || + where != CSEG && (sclass == N_DATA || sclass == N_BSS)) ) + return sp; + } + return NULL; +} + + +PRIVATE void gnu_sym( sp, off ) +struct nlist *sp; +off_t off; +{ + register char *s; + char *send; + + for ( s = sp->n_un.n_name, send = s + strlen(s); *s != 0 && s < send; ++s ) + outbyte( *s ); + if ( (off -= sp->n_value) != 0 ) + { + outbyte( '+' ); + printhex(off); + } +} + +/* shell sort symbols on value */ + +PRIVATE void gnu_sort( array, top ) +struct nlist *array; +struct nlist *top; +{ + int gap; + int i; + int j; + register struct nlist *left; + register struct nlist *right; + struct nlist swaptemp; + int size; + + size = top - array; + /* choose gaps according to Knuth V3 p95 */ + for ( gap = 1, i = 4; (j = 3 * i + 1) < size; gap = i, i = j ) + ; + do + { + for ( j = gap; j < size; ++j ) + for ( i = j - gap; i >= 0; i -= gap ) + { + left = array + i; + right = array + (i + gap); + if ( (off_t) left->n_value <= + right->n_value ) + break; + swaptemp = *left; + *left = *right; + *right = swaptemp; + } + } + while ( (gap /= 3) != 0 ); +} + +PUBLIC void gnu_symbolic( value, separator ) +off_t value; +int separator; +{ + register struct nlist *sp; + long off; + + if (value < st_addr || value > end_addr) { + outstr("0x"); + printhex(value); + outbyte(separator); + return; + } + + if ( (sp = gnu_sval( value, CSEG )) != NULL ) + { + gnu_sym( sp, value ); + } + else if ( (sp = gnu_sval( value, DSEG )) != NULL ) + { + gnu_sym( sp, value ); + } + else + { + outstr("_start"); + off = value - st_addr; + if ( off != 0 ) + { + outbyte( '+' ); + printhex(off); + } + } + outbyte( separator ); +} + + +PRIVATE int gnu_symeq( t, sp ) +register char *t; +struct nlist *sp; +{ + return strncmp( t, sp->n_un.n_name, strlen(t) ) == 0; +} + +PRIVATE int gnu_symprefix( t, sp ) +register char *t; +struct nlist *sp; +{ + register char *s; + char *send; + + for ( ; *t == '_'; ++t ) + ; + for ( s = sp->n_un.n_name, send = s + strlen(s); + s < send && *s == '_'; ++s ) + ; + return strncmp( s, t, send - s ) == 0; +} + + + +/* list all symbols - test for selection criteria */ + +PUBLIC void gnu_listsym( tchar ) +char tchar; +{ + register struct symtab_s *tp; + register struct nlist *sp; + char *s; + char *send; + char schar; + + outbyte('\n'); + tp = &symtab; + for ( sp = tp->start; sp < tp->end; ++sp ) + { + switch( sp->n_type & N_TYPE ) + { + case N_ABS: schar = 'a'; break; + case N_TEXT: schar = 't'; break; + case N_DATA: schar = 'd'; break; + case N_BSS: schar = 'b'; break; + default: schar = '?'; break; + } + + if ( (sp->n_type & N_EXT) && schar != '?' ) + schar += 'A' - 'a'; + + /* check for selection */ + if ( tchar != '*' && schar != tchar) + continue; + + /* print symbol type and value */ + outh32( sp->n_value ); + outspace(); + outbyte( schar ); + outbyte( '\t' ); + for ( s = sp->n_un.n_name, send = s + strlen(s); + *s != 0 && s < send; ++s ) outbyte( *s ); + outbyte('\n'); + } +} + +PUBLIC int gnu_text_symbol(value) +off_t value; +{ +struct nlist *sp; + + if ((sp = gnu_sval(value, CSEG)) != NULL && sp->n_value == value) + { + gnu_sym(sp, value); + return TRUE; + } + else + return FALSE; +} + +PUBLIC int gnu_finds_data(off,data_seg) +off_t off; +int data_seg; +{ +struct nlist *sp; + + if ((sp = gnu_sval(off, data_seg)) != NULL) + { + gnu_sym(sp, off); + return TRUE; + } + else + return FALSE; +} + +PUBLIC int gnu_finds_pc(pc) +off_t pc; +{ +struct nlist *sp; + + if ((sp = gnu_sval(pc, CSEG)) != NULL) + { + gnu_sym(sp, pc); + return TRUE; + } + else + return FALSE; +} + + +#endif /* EXTRA_SYMBOLS */ diff --git a/commands/mdb/io.c b/commands/mdb/io.c new file mode 100644 index 000000000..f99b12829 --- /dev/null +++ b/commands/mdb/io.c @@ -0,0 +1,303 @@ +/* + * io.c for mdb + * all the i/o is here + * NB: Printf() + */ +#include "mdb.h" +#include +#include +#include +#include +#include "proto.h" + +#define OUTBUFSIZE 512 +#define PAGESIZE 24 + +PRIVATE int forceupper = FALSE; +PRIVATE int someupper = FALSE; +PRIVATE int stringcount = 0; +PRIVATE char *string_ptr = NULL; /* stringptr ambiguous at 8th char */ +PRIVATE char *stringstart = NULL; + +PRIVATE char outbuf[OUTBUFSIZE]; +PRIVATE FILE *cmdfile = stdin; +PRIVATE FILE *outfile = stdout; +PRIVATE FILE *logfile; +PRIVATE int lineno; + +_PROTOTYPE( int _doprnt, (const char *format, va_list ap, FILE *stream )); + +PUBLIC char *get_cmd(cbuf, csize) +char *cbuf; +int csize; +{ +char *r; + + fflush(stdout); + if( cmdfile == stdin && outfile == stdout ) + printf("* "); + r = fgets(cbuf, csize, cmdfile); + if ( r == NULL && cmdfile != stdin ) { + cmdfile = stdin; + return get_cmd(cbuf, csize); + } + + if ( logfile != NULL ) { + fprintf( logfile, "%s", cbuf ); + lineno++; + } + + return r; +} + +PUBLIC void openin(s) +char *s; +{ +char *t; + + if ((t = strchr(s,'\n')) != NULL) *t = '\0'; + if ((t = strchr(s,' ')) != NULL) *t = '\0'; + cmdfile = fopen(s,"r"); + if (cmdfile == NULL) { + Printf("Cannot open %s for input\n",s); + cmdfile = stdin; + } +} + + +/* Special version of printf + * really sprintf() + * from MINIX library + * followed by outstr() + */ +PUBLIC int Printf(const char *format, ...) +{ + va_list ap; + int retval; + FILE tmp_stream; + + va_start(ap, format); + + tmp_stream._fd = -1; + tmp_stream._flags = _IOWRITE + _IONBF + _IOWRITING; + tmp_stream._buf = (unsigned char *) outbuf; + tmp_stream._ptr = (unsigned char *) outbuf; + tmp_stream._count = 512; + + retval = _doprnt(format, ap, &tmp_stream); + putc('\0',&tmp_stream); + + va_end(ap); + + outstr(outbuf); + + return retval; +} + +/* + * Set logging options + */ +PUBLIC void logging( c, name ) +int c; +char *name; +{ +char *t; + + if ( c == 'q' && logfile != NULL ) { + fclose(logfile); + return; + } + + if ((t = strchr(name,'\n')) != NULL) *t = '\0'; + if ((t = strchr(name,' ' )) != NULL) *t = '\0'; + if ( logfile != NULL ) fclose(logfile); + + if ( strlen(name) > 0 ) { + logfile = fopen(name,"w"); + + if (logfile == NULL) { + Printf("Cannot open %s for output\n",name); + return; + } + + /* Close standard output file for L */ + if ( c == 'L' ) { + fclose(outfile); + outfile = NULL; + } + } + else + /* Reset */ + { + if ( logfile != NULL ) fclose(logfile); + outfile = stdout; + outbyte('\n'); + } + +} + +/* Output system error string */ +PUBLIC void do_error(m) +char *m; +{ + outstr(m); + outstr(": "); + outstr(strerror(errno)); +} + +PUBLIC void closestring() +{ +/* close string device */ + + stringcount = 0; + stringstart = string_ptr = NULL; +} + +PUBLIC int mytolower(ch) +int ch; +{ +/* convert char to lower case */ + + if (ch >= 'A' && ch <= 'Z') + ch += 'a' - 'A'; + return ch; +} + + +PUBLIC void openstring(string) +char *string; +{ +/* open string device */ + + stringcount = 0; + stringstart = string_ptr = string; +} + +PUBLIC void outbyte(byte) +int byte; +{ +/* print char to currently open output devices */ + + if (forceupper && byte >= 'a' && byte <= 'z') + byte += 'A' - 'a'; + if (string_ptr != NULL) + { + if ((*string_ptr++ = byte) == '\t') + stringcount = 8 * (stringcount / 8 + 1); + else + ++stringcount; + } + else + { + if ( paging && byte == '\n' ) { + lineno++; + if ( lineno >= PAGESIZE) { + if ( cmdfile == stdin ) { + printf("\nMore...any key to continue"); + fgets( outbuf, OUTBUFSIZE-1, cmdfile ); + } + } + lineno = 0; + } + + if ( outfile != NULL ) + putc(byte,outfile); + /* Do not log CR */ + if ( logfile != NULL && byte != '\r' ) + putc(byte,logfile); + } +} + + +PUBLIC void outcomma() +{ +/* print comma */ + + outbyte(','); +} + +PRIVATE char hexdigits[] = "0123456789ABCDEF"; +PUBLIC void outh4(num) +unsigned num; +{ +/* print 4 bits hex */ + + outbyte(hexdigits[num % 16]); +} + +PUBLIC void outh8(num) +unsigned num; +{ +/* print 8 bits hex */ + + outh4(num / 16); + outh4(num); +} + +PUBLIC void outh16(num) +unsigned num; +{ +/* print 16 bits hex */ + + outh8(num / 256); + outh8(num); +} + +PUBLIC void outh32(num) +unsigned num; +{ +/* print 32 bits hex */ + + outh16((u16_t) (num >> 16)); + outh16((u16_t) num); +} + +PUBLIC void outspace() +{ +/* print space */ + + outbyte(' '); +} + +PUBLIC void outstr(s) +register char *s; +{ +/* print string */ + + while (*s) + outbyte(*s++); +} + +PUBLIC void outtab() +{ +/* print tab */ + + outbyte('\t'); +} + +PUBLIC void outustr(s) +register char *s; +{ +/* print string, perhaps converting case to upper */ + + forceupper = someupper; + while (*s) + outbyte(*s++); + forceupper = FALSE; +} + + +PUBLIC int stringpos() +{ +/* return current offset of string device */ + + return string_ptr - stringstart; +} + +PUBLIC int stringtab() +{ +/* return current "tab" spot of string device */ + + return stringcount; +} + diff --git a/commands/mdb/ioctl.c b/commands/mdb/ioctl.c new file mode 100644 index 000000000..4cc1d8838 --- /dev/null +++ b/commands/mdb/ioctl.c @@ -0,0 +1,146 @@ +/* + * ioctl.c for mdb -- decode an IOCTL system call + */ +#include "mdb.h" +#ifdef SYSCALLS_SUPPORT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "proto.h" + +PRIVATE int get_request; + +PRIVATE char *rnames[] = { + "TIOCGETP", + "TIOCSETP", + "TIOCGETC", + "TIOCSETC" +}; + +#define GETPNAME 0 +#define SETPNAME 1 +#define GETCNAME 2 +#define SETCNAME 3 + +/* + * decode ioctl call + * send or receive = 'R' or 'S' + */ +void decode_ioctl(sr, m) +int sr; +message *m; +{ +int rq; +int request, device; +int high; +long spek, flags; +int ispeed, ospeed, speed, erase, kill; +int t_intrc, t_quitc, t_startc, t_stopc, t_brk, t_eof; + + device = m->m2_i1; + request = m->m2_i3; + spek = m->m2_l1; + flags = m->m2_l2; + +#ifdef DEBUG + if( debug ) + Printf("%c device=%d request=%c|%d m2_l1=%lx m2_l2=%lx\n", + sr,device, + (request >> 8) & BYTE, + request & BYTE, + spek,flags); +#endif + + if ( sr == 'R') request = get_request; + + switch(request) { + case TIOCGETP: + case TIOCSETP: + rq = (request == TIOCGETP) ? GETPNAME : SETPNAME; + if (sr == 'S') { + get_request = request; + Printf( "Sending %s ",rnames[rq] ); + if ( request == TIOCGETP ) break; + } + + if ( (sr == 'R') && (request == TIOCSETP) ) break; + + erase = (spek >> 8) & BYTE; + kill = spek & BYTE; + flags = flags & 0xFFFF; + speed = (spek >> 16) & 0xFFFFL; + ispeed = speed & BYTE; + ospeed = (speed >> 8) & BYTE; + Printf("%s erase=%d kill=%d speed=%d/%d flags=%lx ", + rnames[rq], erase, kill, ispeed, ospeed, flags); + break; + + case TIOCGETC: + case TIOCSETC: + rq = (request == TIOCGETC) ? GETCNAME : SETCNAME; + if (sr == 'S') { + get_request = request; + Printf( "Sending %s ",rnames[rq] ); + if ( request == TIOCGETC ) break; + } + + if ( (sr == 'R') && (request == TIOCSETC) ) break; + + t_intrc = (spek >> 24) & BYTE; + t_quitc = (spek >> 16) & BYTE; + t_startc = (spek >> 8) & BYTE; + t_stopc = (spek >> 0) & BYTE; + t_brk = flags & BYTE; + t_eof = (flags >> 8 ) & BYTE; + Printf("%s int %d quit %d start %d stop %d brk %d eof %d\n", + rnames[rq], + t_intrc, t_quitc, t_startc, t_stopc, t_brk, t_eof); + break; + + default: + +#ifdef __i86 /* 16 bit */ + if ( sr == 'S' ) { + Printf("Sending "); + get_request = request; + } + else + Printf("Receiving "); + + Printf("Other IOCTL device=%d request=%c|%d\n", + device, (request >> 8) & BYTE, request & BYTE ); + + break; +#endif + +#ifdef __i386 /* 32 bit encoding */ + if ( sr == 'S' ) { + Printf("Sending (%lx) ", request); + get_request = request; + } + else + Printf("Receiving (%lx) ", request); + + high = ( request & 0xFFFF0000 ) >> 16 ; + request &= _IOCTYPE_MASK; + + Printf("Other IOCTL device=%d request=%c|%d flags=%x size =%d\n", + device, (request >> 8) & BYTE, request & BYTE, + (high & ~_IOCPARM_MASK ), + (high & _IOCPARM_MASK ) + ); + break; +#endif + } + Printf("\n"); +} + + +#endif /* SYSCALLS_SUPPORT */ diff --git a/commands/mdb/kernel.c b/commands/mdb/kernel.c new file mode 100644 index 000000000..119a8e29a --- /dev/null +++ b/commands/mdb/kernel.c @@ -0,0 +1,249 @@ +/* + * kernel.c for mdb + */ + +#include "mdb.h" +#include +#include +#include +#include +#define ptrace mdbtrace +#include +#include "proto.h" + +#include +#include +#include + +/* Define these here */ +/* buffer for proc and pointer to proc */ + +#define SIZ (1 + sizeof(struct proc)/sizeof(long)) + +struct proc *prc; +long lbuf[SIZ]; + +PRIVATE char segment_name[] = "TDS"; + +/* + * Display memory maps + */ +PUBLIC void disp_maps() +{ + int i; + long int vir, phy, len; + + Printf("\t Virtual\t Physical\tLength\n"); + Printf("\t address\t address\n"); + for (i = 0; i < strlen(segment_name); i++) { + vir = (long) prc->p_memmap[i].mem_vir << CLICK_SHIFT; + phy = (long) prc->p_memmap[i].mem_phys << CLICK_SHIFT; + len = (long) prc->p_memmap[i].mem_len << CLICK_SHIFT; + Printf("%c:\t0x%08.8lx\t0x%08.8lx\t%8ld (0x%08.8lx)\n", + segment_name[i], vir, phy, len, len); + } +} + +PUBLIC void update() +{ + int i; + + for (i = 0; i < (SIZ - 1); i++) + lbuf[i] = ptrace(T_GETUSER, curpid, (long) (i * sizeof(long)), 0L); + + st_addr = (long) prc->p_memmap[T].mem_vir << CLICK_SHIFT; + et_addr = st_addr + ( (long) prc->p_memmap[T].mem_len << CLICK_SHIFT ); + + sd_addr = (long) prc->p_memmap[D].mem_vir << CLICK_SHIFT; + ed_addr = end_addr = + sd_addr + ( (long) prc->p_memmap[D].mem_len << CLICK_SHIFT ); + + sk_addr = (long) prc->p_memmap[S].mem_vir << CLICK_SHIFT; + sk_size = (long) prc->p_memmap[S].mem_len << CLICK_SHIFT; + +#ifdef MINIX_PC + if ( end_addr < et_addr ) end_addr = et_addr; +#endif + +} + +PUBLIC int disp_regs() +{ + int i; + + if (curpid <= 0) { + Printf("No active process.\n"); + return 1; + } + +/* Look at kernel/type.h see how this data from the stackframe is laid out */ + +#if defined(MINIX_PC) && defined(__i86) + Printf("\ + es ds di si bp bx dx cx ax ip cs psw sp ss\ +\n"); + for (i = 0; i < 16; i++) + if ( i != 5 && i != 10 ) Printf("%04x ", ((reg_t *) &prc->p_reg)[i]); + Printf("\n"); +#endif + +#if defined(MINIX_PC) && defined(__i386) + Printf("\n"); + Printf("\ + fs gs ds es edi esi ebp ebx edx\n"); + for (i = 0; i < 8; i++) + if ( i != 6 ) Printf("%08lx ", ((reg_t *) &prc->p_reg)[i]); + Printf("\n\ + ecx eax eip cs psw esp ss\n"); + for (; i < 16; i++) + if ( i != 10 ) Printf("%08lx ", ((reg_t *) &prc->p_reg)[i]); + Printf("\n"); +#endif + +#ifdef MINIX_ST + Printf("\npc=%lx psw=%x\n\n",(long)PC_MEMBER(prc), PSW_MEMBER(prc)); + Printf( +" 0 1 2 3 4 5 6 7\nD"); + for (i = 0; i < 8; i++) Printf(" %08lx", ((reg_t *) &prc->p_reg)[i]); + Printf("\nA"); + for (; i < NR_REGS; i++) Printf(" %08lx", ((reg_t *) &prc->p_reg)[i]); + Printf(" %08lx\n\n", (long)SP_MEMBER(prc)); +#endif + return 0; +} + +/* System dependent core */ + +#ifdef MINIX_PC + +#ifdef __i386 +PRIVATE char regs[] = "fs gs ds es di si bp bx dx cx ax ip cs ps sp ss"; +#else +PRIVATE char regs[] = "es ds di si bp bx dx cx ax ip cs ps sp ss"; +#endif + +/* Get register for pid at offset k */ +PUBLIC long get_reg(pid, k) +int pid; +long k; +{ + long off; + long val; + int reg_size; + + /* Calculate size of register */ + reg_size = (k < N_REG16 * 2) ? 2 : sizeof(reg_t); + + /* Adjust offset */ + off = k - (k & (sizeof(long) - 1)); + + val = ptrace(T_GETUSER, pid, off, 0L); + + if (k & (sizeof(long) - 1)) + val >>= BITSIZE(reg_size); + else + val &= MASK(reg_size); + return val; +} + + +/* Set register for pid at offset k */ +PUBLIC void set_reg(pid, k, value) +int pid; +long k; +long value; +{ + long off; + + /* Adjust offset */ + off = k - (k & (sizeof(long) - 1)); + + ptrace(T_SETUSER, pid, off, value); + +} + + +PUBLIC long reg_addr(s) +char *s; +{ + long val; + char *t; + char *send; + char q[3]; + + if (*s == ' ') + mdb_error("Invalid syntax\n"); + q[0] = tolower(*s); + q[1] = tolower(*++s); + q[2] = '\0'; + + t = regs; + send = regs + sizeof(regs); + while (t < send) { + if (strncmp(q, t, 2) == 0) { + val = (long) (t - regs); + val /= 3L; + if (val < N_REG16 - 1) + val = val * 2; + else + val = (N_REG16 - 1) * 2 + + (val - N_REG16 + 1) * sizeof(reg_t); + return val; + } + t += 3; + } + Printf("Unknown register: %s", q); + mdb_error("\n"); +} + + +PUBLIC int outsegreg(num) +off_t num; +{ +/* print segment register */ + + if ((num % HCLICK_SIZE) != 0 || num >= 0x100000) + { + Printf("%08x",num); + return 8; + } + Printf("%04x", (u16_t) (num / HCLICK_SIZE) ); + return 4; +} + +#endif + +#ifdef MINIX_ST + +/* Get register for pid at offset k */ +PUBLIC long get_reg(pid, k) +int pid; +long k; +{ + return ptrace(T_GETUSER, pid, k, 0L); +} + +PUBLIC long reg_addr(s) +char *s; +{ + long val; + + switch (*s++) { + case 'a': + case 'A': val = 32; break; + case 'd': + case 'D': val = 0; break; + case 'P': + case 'p': if (*s != 'c' && *s != 'C') goto error; + return 64; + break; + default: goto error; + } + if (*s >= '0' && *s <= '7') + return val + 4 * (*s - '0'); +error: + Printf("Unknown register: %2.2s", s); + mdb_error("\n"); +} + +#endif diff --git a/commands/mdb/mdb.1 b/commands/mdb/mdb.1 new file mode 100644 index 000000000..e7be50ed6 --- /dev/null +++ b/commands/mdb/mdb.1 @@ -0,0 +1,154 @@ +.TH MDB 1 +.SH NAME +mdb \- Minix debugger +.SH SYNOPSIS +.B mdb +.RB [ \-fc ] +.I file +.br +.B mdb +.BR [-L|-l]log\-file +.I exec-file +.RI [ core\-file ] +.RI [ @command\-file ] +.SH DESCRIPTION +.de SP +.if t .sp 0.4 +.if n .sp +.. +.B mdb +is the Minix debugger. +.SH OPTIONS +Its command line options are: +.TP +.B \-f +Just examine the specified file. +.TP +.B \-c +Examine 'core' file. No exec-file will be supplied. +.TP +.B \-Llog\-file +Log to file only +.TP +.B \-llog\-file +Log to file. +.SP +.IR exec\-file +Unless the -c option has been specified, the exec-file is required. +.SP +.IR core\-file +The core-file is optional. +.SP +If the core-file is supplied, +.B mdb +assumes that the user wishes to examine the core file. +Otherwise +.B mdb +assumes that the user will run the exec-file and trace it. +.SP +.IR @command\-file +.B mdb +executes command from command-file. +.SH OVERVIEW +.br +.B mdb +commands are of the form: +.I [ expression ] +.I command +.SP +.I expression +can be of the form: +.IP +.I address +which defaults to text segment +.IP +address +.I overriden +by +.I T: +for Text segment +or +.I D: +for Data segment +or +.I S: +for Stack segment +.IP +.I symbol +where +.B mdb +does a lookup for the symbol first as a +.I text +symbol and then as a +.I data +symbol. +.SP +.TP +.I command +.SP +The help command is ?. +.SP +For detailed help on a command type: +.I command ?. +.SP +A semi-colon can be used to separate commands on a line. +.SP +.SH MDB COMMANDS +.SP +! Shell escape +.SP +# Set Variable or register +.SP +Tt Current call / Backtrace all +.SP +/nsf Display for n size s with format f +.SP +Xx [n] Disasm / & display reg for n instructions +.SP +Rr a Run / with arguments a +.SP +Cc [n] Continue with current signal / no signal n times +.SP +Ii [n] Single step with / no signal for n instructions +.SP +Mm t n Trace until / Stop when modified t type for n instructions +.SP +k Kill +.SP +Bb Display / Set Break-pt +.SP +Dd Delete all / one break-points +.SP +P Toggle Pagging +.SP +Ll name Log to file name / and to standard output +.SP +Vv Toggle debug flag / Version info +.SP +V Version info +.SP +e [t] List symbols for type t +.SP +y Print segment mappings +.SP +s [n] Dump stack for n words +.SP +z [a] Trace syscalls with address a +.SP +? Help - short help +.SP +@ file Execute commands from file +.SP +Qq Quit / and kill traced process +.SP +.SH "SEE ALSO" +.SP +trace(2). +.SH DIAGNOSTICS + +.SH NOTES + +.SH BUGS + +.SH AUTHOR +Philip Murton and others diff --git a/commands/mdb/mdb.c b/commands/mdb/mdb.c new file mode 100644 index 000000000..e6f99c4f8 --- /dev/null +++ b/commands/mdb/mdb.c @@ -0,0 +1,1028 @@ +/* + * mdb.c - MINIX program debugger + * + * Written by Bruce D. Szablak + * + * This free software is provided for non-commerical use. No warrantee + * of fitness for any use is implied. You get what you pay for. Anyone + * may make modifications and distribute them, but please keep this header + * in the distribution. + */ + +/* + * Originally ported to MINIX-PC and MINIX-386 by Bruce Evans. + * NB: the original sym.c and mdbdis86.c come from his 'db' + * + * Added by Philip Murton: + * + * 2.0 'Core' file functions + * 2.1 Support for GNU exec + * 2.2 Changes for Minix 1.6.x Beta + * 2.3 Changes for Minix 1.7.0 and trace syscalls + * 2.4 Changes for Minix 1.7.2 and clean up + * 2.5.1 Add better help + * 2.5.2 Added io.c for logging options + * 2.5.3 Minor changes and tested with Minix 1.7.4 + * 2.5.4 Command arguments processing improved (Thanks to Will Rose) + * 2.6.0 Final Version for MINIX CD (Sept/96) + */ + +#define _MAIN_MDB +#include "mdb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#define ptrace mdbtrace +#include +#include +#include "proto.h" + +#include +#include +#include + +/* buffer for proc and pointer to proc */ +extern struct proc *prc; + +#define MAXLINE 128 +#define MAXARG 20 + +PRIVATE unsigned long lastexp = 0L; /* last expression and segment */ +PRIVATE int lastseg = NOSEG; +PRIVATE char *prog; /* prog name */ +PRIVATE char sbuf[MAXLINE]; +PRIVATE char cbuf[MAXLINE]; +PRIVATE char *cmd; /* current command */ +PRIVATE char *cmdstart; /* start of command */ +PRIVATE jmp_buf mainlp; + + +struct b_pnt { + struct b_pnt *nxt, *prv; + long addr; + long oldval; + char cmd[1]; +} *b_head, *curpnt; + +_PROTOTYPE( void main , (int argc, char *argv[])); + +FORWARD _PROTOTYPE( void cleanup , (void)); +FORWARD _PROTOTYPE( void freepnt , (struct b_pnt *pnt )); +FORWARD _PROTOTYPE( void findbpnt , (int verbose )); +FORWARD _PROTOTYPE( int exebpnt , (int restart )); +FORWARD _PROTOTYPE( void catch , (int sig )); +FORWARD _PROTOTYPE( int run , (char *name , char *argstr , int tflg )); +FORWARD _PROTOTYPE( int dowait , (void)); +FORWARD _PROTOTYPE( void backtrace , (int all )); +FORWARD _PROTOTYPE( void modify , (long addr , int cnt , int verbose , int size )); +FORWARD _PROTOTYPE( void display , (long addr , int req )); +FORWARD _PROTOTYPE( void fill , (long addr , int req )); +FORWARD _PROTOTYPE( void dorun , (char *cmd )); +FORWARD _PROTOTYPE( void not_for_core , (void)); +FORWARD _PROTOTYPE( void command , (void)); + + +PRIVATE void cleanup() +{ + curpid = 0; + curpnt = NULL; + while (b_head) freepnt(b_head); +} + +PRIVATE void findbpnt(verbose) +int verbose; +{ + for (curpnt = b_head; curpnt; curpnt = curpnt->nxt) { + if (curpnt->addr == PC_MEMBER(prc) - BREAKPOINT_ADVANCE) { + ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); + ptrace(T_SETUSER, curpid, PC_OFF, curpnt->addr); +#if SYSCALLS_SUPPORT + if( syscalls ) + do_syscall(curpnt->addr); + else if (curpnt->cmd[0] != '\n') +#else + if (curpnt->cmd[0] != '\n') +#endif + cmd = strcpy(cbuf, curpnt->cmd); + else if (verbose) + Printf("Breakpoint hit.\n"); + return; + } + } + if (verbose) Printf("Unknown breakpoint hit.\n"); +} + +PRIVATE int exebpnt(restart) +int restart; +{ + ptrace(T_STEP, curpid, 0L, (long) restart); + if (dowait() == 0) return TRUE; + ptrace(T_SETINS, curpid, curpnt->addr, BREAK(curpnt->oldval)); + curpnt = NULL; + return FALSE; +} + + +PRIVATE void freepnt(pnt) +struct b_pnt *pnt; +{ + if (pnt->prv) + pnt->prv->nxt = pnt->nxt; + else + b_head = pnt->nxt; + if (pnt->nxt) pnt->nxt->prv = pnt->prv; + if (curpid > 0) ptrace(T_SETINS, curpid, pnt->addr, pnt->oldval); + free(pnt); + if (pnt == curpnt) curpnt = NULL; +} + + +PUBLIC long breakpt(addr, cmd) +long addr; +char *cmd; +{ + struct b_pnt *new; + + if (curpid <= 0) { + Printf("No active process.\n"); + return 0L; + } + for (new = b_head; new; new = new->nxt) + if (new->addr == addr) { + Printf("Breakpoint already exists here.\n"); + return 0L; + } + new = (struct b_pnt *) malloc(sizeof(struct b_pnt) + strlen(cmd)); + if (new == NULL) { + Printf("No room for new breakpoint.\n"); + return 0L; + } + new->nxt = b_head; + new->prv = 0; + if (b_head) b_head->prv = new; + b_head = new; + new->addr = addr; + strcpy(new->cmd, cmd); + new->oldval = ptrace(T_GETINS, curpid, addr, 0L); + ptrace(T_SETINS, curpid, addr, BREAK(new->oldval)); + if (ptrace(T_GETINS, curpid, addr, 0L) != BREAK(new->oldval)) { + do_error("Can't set breakpoint"); + freepnt(new); + return 0L; + } + return new->oldval; +} + +PRIVATE void catch(sig) +int sig; +{ + signal(sig, catch); + if (sig == SIGINT || sig == SIGQUIT) return; + tstart(T_EXIT, 0, sig, 0); + exit(0); +} + + +PRIVATE int dowait() +{ + int stat; + + if (corepid > 0) return cursig = 0; + while (wait(&stat) != curpid) {}; + if ( WIFEXITED(stat) ) { + if (WEXITSTATUS(stat) != 127) + Printf("child exited with status %d\n", WEXITSTATUS(stat)); + cleanup(); + return 0; + } + if ( WIFSIGNALED(stat) ) { + Printf("child terminated by signal %d\n", WTERMSIG(stat) ); + if (_LOW(stat) & 0x80) Printf("(core dumped)\n"); + cleanup(); + return 0; + } + return cursig = WSTOPSIG(stat); +} + + + +PUBLIC void tstart(req, verbose, val, cnt) +int req, verbose, val, cnt; +{ + if (curpid == 0) { + if (verbose) Printf("No active process.\n"); + return; + } + if (req == T_EXIT) { + ptrace(T_EXIT, curpid, 0L, (long) val); + dowait(); + return; + } + if (cnt == 0) cnt = 1; + do { + if (curpnt) { + if (exebpnt(val)) return; + if (req == T_RESUME) cnt++; + val = 0; + } else { + ptrace(req, curpid, 0L, (long) val); + if (dowait() == 0) return; + val = 0; + switch (cursig) { + case SIGEMT: /* breakpoint */ + update(); + findbpnt(cnt <= 1); + break; + case SIGTRAP: /* trace trap? */ + if (req == T_STEP) break; + default: /* signal */ + val = cursig; + break; + } + } + } + while (--cnt > 0); + update(); + if ( verbose ) dasm((long) PC_MEMBER(prc), 1, 1); +} + +PRIVATE int run(name, argstr, tflg) +char *name, *argstr; +int tflg; +{ + int procid; + char *argv[MAXARG], *inf = NULL, *outf = NULL; + int argc; + + if ((procid = fork()) == 0) { + /* trace me */ + if (tflg) ptrace(T_OK, 0, 0L, 0L); + argv[0] = name; + for (argc = 1;;) { + argstr = skip(argstr); + if (*argstr == '\n' || *argstr == ';') { + argv[argc] = 0; + if (inf) freopen(inf, "r", stdin); + if (outf) freopen(outf, "w", stdout); + if (tflg) { + execv(name, argv); + do_error("execv"); + } else { + execvp(name, argv); + do_error("execvp"); + } + exit(127); + } + if (*argstr == '<') + inf = argstr + 1; + else if (*argstr == '>') + outf = argstr + 1; + else if (argc == MAXARG) { + Printf("Too many arguments.\n"); + exit(127); + } else + argv[argc++] = argstr; + while (!isspace(*argstr)) argstr++; + if (*argstr == '\n') argstr[1] = '\n', argstr[2] = 0; + *argstr++ = 0; + } + } + if (procid < 0) do_error("Fork failed.\n"); + return procid; +} + + +PRIVATE void dorun(cmd) +char *cmd; +{ + if (curpid = run(prog, cmd, 1)) { + if (dowait()) { + ptrace(T_SETUSER, curpid, BP_OFF, 0L); + update(); + Printf("Process stopped.\n"); + } + } +} + +/* + * backtrace - inspect the stack + */ +PRIVATE void backtrace(all) +int all; +{ + unsigned long pc, bp, off, val, obp; + + if (curpid <= 0) { + Printf("No process.\n"); + return; + } + pc = get_reg(curpid,PC_OFF); + bp = get_reg(curpid,BP_OFF); + if (bp == 0) { + Printf("No active frame.\n"); + return; + } + errno = 0; + do { + symbolic(pc, '('); + pc = (ptrace(T_GETDATA, curpid, bp + ADDRSIZE, 0L) + >> SHIFT(ADDRSIZE)) & MASK(ADDRSIZE); + off = ptrace(T_GETINS, curpid, pc, 0L); +#ifdef DEBUG + if(debug) + Printf("Return address %lx Value %lx\n",pc,off); +#endif + obp = bp; + bp += 2 * ADDRSIZE; + + /* Check for various instruction used to restore the stack. + * Should gives us the number of arguments. + * This is obvious dependent on interal features of the + * compiler used. + */ + if (ADDQ(off)) off = ADDQ_CNT(off) + bp; +#ifdef __mc68000__ + else if (LEA(off)) + off = LEA_DISP(off) + bp; +#endif + else if (ADDA(off)) + off = ADDA_CNT(ptrace(T_GETINS, curpid, pc + 2, 0L)) + bp; +#if (CHIP == INTEL) + else if (INCSP2(off)) + off = bp + 2*INTSIZE; + else if (POPBX2(off)) + off = bp + 2*INTSIZE; + else if (POPCX2(off)) + off = bp + 2*INTSIZE; + else if (POPBX(off)) + off = bp + INTSIZE; + else if (POPCX(off)) + off = bp + INTSIZE; +#endif + else + goto skiplp; + +#ifdef DEBUG + if (debug) + Printf("Number of arguments: %d\n",(off-bp)/INTSIZE); +#endif + + for (;;) { + if (errno) return; + val = (ptrace(T_GETDATA, curpid, bp, 0L) + >> SHIFT(INTSIZE)) & MASK(INTSIZE); + Printf("0x%0*lx", 2 * INTSIZE, val); + bp += INTSIZE; + if (bp >= off) break; + Printf(","); + } + +skiplp: + Printf(")\n"); + bp = (long) ( (reg_t) ptrace(T_GETDATA, curpid, obp, 0L) ); +#ifdef DEBUG + if(debug) + Printf("Old BP %lx New %lx\n",obp,bp); +#endif + } + while (all && (reg_t) bp); +} + +PRIVATE void modify(addr, cnt, verbose, size) +long addr; +int cnt, verbose, size; +{ + long curval, off; + + if (curpid == 0) { + Printf("No active process.\n"); + return; + } + curval = ptrace(T_GETDATA, curpid, addr, 0L) & MASK(size); + do { + if (cursig == SIGTRAP) cursig = 0; + if (verbose) { + off = get_reg(curpid, PC_OFF); + dasm(off, 1, 0); + } + if (curpnt && exebpnt(cursig)) + return; + else { + ptrace(T_STEP, curpid, addr, 0L); + switch (dowait()) { + case 0: + return; + case SIGEMT: + update(); + findbpnt(0); + break; + } + } + if (curval != ptrace(T_GETDATA, curpid, addr, 0L) & MASK(size)) { + Printf("Modification detected\n"); + break; + } + } + while (--cnt); + update(); + dasm((long) PC_MEMBER(prc), 1, 1); + return; +} + +PRIVATE void display(addr, req) +long addr; +int req; +{ + int count, size, out, shift; + long val, msk; + char fmt; + + if (curpid == 0) { + Printf("No active process\n"); + return; + } + if (req == T_GETDATA && seg == T) req = T_GETINS; + count = strtol(cmd, &cmd, 0); + if (count == 0) count = 1; + cmd = skip(cmd); + if (*cmd == 'i' || *cmd == 'I') { + dasm(addr, count, *cmd == 'i'); + return; + } + if (*cmd == 'y') { + symbolic(addr, '\n'); + return; + } + switch (*cmd++) { + case 'b': size = sizeof(char); break; + case 'h': size = sizeof(short); break; + case 'l': size = sizeof(long); break; + default: + size = sizeof(int); + --cmd; + break; + } + switch (fmt = *cmd) { + case 'X': + case 'D': + size = sizeof(long); + break; + case 's': + addr = ptrace(req, curpid, addr, 0L); + req = T_GETDATA; + /* Fallthrough */ + case 'a': + case 'c': + size = sizeof(char); + break; + } + out = 0; + msk = MASK(size); + shift = SHIFT(size); + do { + val = (ptrace(req, curpid, addr, 0L) >> shift) & msk; + if (out == 0) Printf("\n0x%0*lx: ", 2 * ADDRSIZE, + (addr >> SHIFT(ADDRSIZE)) & MASK(ADDRSIZE)); + switch (fmt) { + case 'c': + Printf(isprint((int) (UCHAR(val))) ? " %c " : "\\%03o ", + (int) (UCHAR(val))); + if (++out == 8) out = 0; + break; + case 'u': + Printf("%12lu ", val); + if (++out == 4) out = 0; + break; + case 'x': + case 'X': + Printf("%*lx ", 2 * size, val); + if (++out == (size == 4 ? 4 : 8)) out = 0; + break; + case 'o': + Printf("%*lo ", 3 * size, val); + if (++out == (size == 4 ? 4 : 8)) out = 0; + break; + case 's': + case 'a': + if (val) + Printf("%c",val); + else + goto exitlp; + if (++out == 64) out = 0; + break; + default: + case 'd': + case 'D': + Printf("%12ld ", val); + if (++out == 4) out = 0; + break; + } + addr += size; + } + while (--count > 0 || fmt == 's' || fmt == 'a'); +exitlp: + Printf("\n"); +} + +PRIVATE void fill(addr, req) +long addr; +int req; +{ + int count, size, shift; + long val, msk, nval; + + if (curpid == 0) { + Printf("No active process\n"); + return; + } + + if (req == T_GETDATA && seg == T) { + req = T_GETINS; + Printf("mdb: warning - modifying text\n"); + } + count = strtol(cmd, &cmd, 0); + if ( count == 0 ) count = 1; + switch (*cmd++) { + case 'b': size = sizeof(char); break; + case 'h': size = sizeof(short); break; + case 'l': size = sizeof(long); break; + default: + size = sizeof(int); + --cmd; + break; + } + shift = SHIFT(size); + msk = MASK(size); + cmd = getexp(cmd, &nval, &seg); + +#ifdef DEBUG + if (debug) + Printf("Filling for Count=%d Size=%d val=%lx\n",count,size,nval); +#endif + + nval <<= shift; + do { + val = ptrace(req, curpid, addr, 0L) | (nval & msk); + val &= (nval | ~msk); + ptrace(req + 3, curpid, addr, val); + addr += size; + } + while (--count > 0); +} + +PRIVATE void not_for_core() +{ + if (corepid > 0) + mdb_error("Illegal command for 'core' file\n"); +} + +PRIVATE void command() +{ + char c, *p; + int i; + int size; + int stat; + long exp, lj, lk; + struct b_pnt *bp; + + seg = NOSEG; /* don't restrict segment expressions are in */ + cmdstart = cmd = skip(cmd); + cmd = getexp(cmd, &exp, &seg); + + if (cmd == cmdstart) { + /* Not an expression */ + if (corepid < 0) { /* default to pc for running processs */ + seg = T; + exp = PC_MEMBER(prc); + } else { + seg = lastseg; + exp = lastexp; + } + + /* Is it a help command */ + cmd = skip(cmd+1); + if (*cmd == '?') { + help_on(*cmdstart); + *cmd = '\n'; + return; + } + else + cmd = cmdstart; + } + + if (seg == NOSEG) seg = T; /* Absolute becomes Text */ + lastexp = exp; /* save last expression */ + lastseg = seg; +#ifdef DEBUG + if(debug) + Printf("Current address 0x%0*lx and segment %d\n", 2 * ADDRSIZE, exp, seg); + +#endif + + /* Check commands */ + switch (c = *cmd++) { + case 'r': /* illegal for 'core' files */ + case 'R': + case 'k': + case 'B': + case 'd': + case 'D': not_for_core(); + break; + + case 'b': /* illegal for 'core' files */ + case 'c': /* Otherwise run process first */ + case 'C': + case 'm': + case 'M': +#if SYSCALLS_SUPPORT + case 'z': +#endif + case 'i': + case 'I': not_for_core(); + if (curpid <= 0) dorun("\n"); + break; + + case 's': if (curpid <= 0) dorun("\n"); + break; + + default: break; + } + + switch (c) { + case '!': /* escape to shell */ + if (cmd == cmdstart + 1) { + cmd = skip(cmd); + if (*cmd == '\n' || *cmd == ';') { + i = run("/bin/sh", "\n", 0); + } else { + for (p = cmd + 1; *p && !isspace(*p); p++) { + }; + *p++ = 0; + i = run(cmd, *p ? p : "\n", 0); + } + if (i > 0) while (wait(&stat) != i) {}; + break; + } + if (corepid > 0) longjmp(mainlp, 0); + break; + case 'T': /* top line of backtrace */ + backtrace(0); + break; + case 't': /* back trace */ + backtrace(1); + break; + case '/': /* print variable value */ + display(exp, T_GETDATA); + break; + case 'x': /* print registers and instruction */ + if (disp_regs()) break; + /* FALLTHROUGH */ + case 'X': /* print instruction - X n [, n] */ + lj = strtol(cmd, &cmd, 0); + lk = 0; + if (*cmd != '\0') + lk = strtol(++cmd, &cmd, 0); + if (curpid > 0) + dasm(exp + lk, lj ? lj : 1, 1); + else + Printf("No active process.\n"); + break; + case 'R': /* run program with no args */ + case 'r': /* run program with args (possibly defaulted) */ + tstart(T_EXIT, 0, 0, 0); + if (c == 'r') { + cmd = skip(cmd); + if (*cmd == '\n' || *cmd == ';') + cmd = sbuf; + else + strcpy(sbuf, cmd); + } else { + cmd = "\n"; + } + dorun(cmd); + break; + case 'c': /* continue program - ignore signal */ + cursig = 0; + case 'C': /* continue program - handle signal */ + i = 0; + if (seg == T && curpnt == 0 && cmd != cmdstart + 1) { + breakpt(exp, "\n"); + curpnt = b_head; + ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); + i = 1; + } + tstart(T_RESUME, 1, cursig, (int) strtol(cmd, &cmd, 0)); + /* remove temporary bp */ + if (i) freepnt(b_head); + if (cursig == SIGEMT) return; + if (curpid) Printf("Process stopped by signal %d\n", cursig); + break; + case 'i': /* single step - ignore signal */ + tstart(T_STEP, 1, 0, (int) strtol(cmd, &cmd, 0)); + break; + case 'I': /* single step - handle signal */ + tstart(T_STEP, 1, cursig, (int) strtol(cmd, &cmd, 0)); + break; + case 'm': /* single step until location modified */ + case 'M': /* single step until location modified - verbose */ + cmd = skip(cmd); + switch (*cmd++) { + case 'b': size = sizeof(char); break; + case 'h': size = sizeof(short); break; + case 'l': size = sizeof(long); break; + default: + size = sizeof(int); + --cmd; + break; + } + modify(exp, (int) strtol(cmd, &cmd, 0), c == 'M', size); + break; + case 'k': /* kill current program */ + tstart(T_EXIT, 1, 0, 0); + break; + case 'b': /* set a breakpoint at the given line */ +#ifdef MINIX_PC + if (seg != T || exp > end_addr ) { +#else + if (seg != T || exp < st_addr || exp > et_addr ) { +#endif + Printf("Address not in text space.\n"); + return; + } + breakpt(exp, skip(cmd)); + cmd = "\n"; + return; + case 'B': /* print list of currently active breakpoints */ + for (i = 1, bp = b_head; bp; bp = bp->nxt, i++) { + Printf("%2d: ", i); + symbolic((long) bp->addr, '\t'); + Printf("(0x%lx)\t- %s", bp->addr, bp->cmd); + } + break; + case 'd': /* delete breakpoint */ + if (seg == T) { + for (bp = b_head; bp && bp->addr != exp; bp = bp->nxt); + if (bp) { + freepnt(bp); + break; + } + } + Printf("No such breakpoint.\n"); + break; + case 'D': /* delete all breakpoints */ + while (b_head) freepnt(b_head); + break; + case 's': + dump_stack( strtol(cmd, &cmd, 0) ); + break; + case 'P': + paging = !paging; + if (paging) Printf("Paging is ON\n"); + break; + case 'l': + case 'L': + logging(c,skip(cmd)); + break; +#if SYSCALLS_SUPPORT + case 'z': + start_syscall( strtol(cmd, &cmd, 0) ); + if ( syscalls ) + Printf("Break point set - use the 'c n' command\n"); + break; +#endif + case 'q': /* quit */ + tstart(T_EXIT, 0, 0, 0); + logging(c,cmd); + case 'Q': + exit(0); + break; + case '\n': + case ';': + if (isdigit(*cmdstart)) + symbolic(exp, '\n'); + else + Printf("0x%0*lx\n", 2 * ADDRSIZE, exp); + --cmd; + break; +#ifdef DEBUG + case 'v': /* toggle debug */ + debug = !debug; + if (debug) Printf("Debug flag ON\n"); + break; +#endif + case 'e': /* list symbols */ + listsym(cmd); + break; + case 'y': /* print mapping */ + prtmap(); + break; + case '?': /* print help */ + help_page(); + break; + case 'V': /* print version info */ + version_info(); + break; + case '@': /* command file */ + cmd = skip(cmd); + openin(cmd); + *cmd = '\n'; + return; + case '#': /* set register or variable */ + cmd = skip(cmd + 1); + if (*cmd == '$') { + cmd++; + i = reg_addr(cmd); + set_reg(curpid, i, strtol(cmd+2, &cmd, 0) ); + update(); + break; + } + cmd = getexp(cmd, &exp, &seg); + fill(exp, T_GETDATA); + break; + default: + help_page(); + break; + } + while (*cmd != '\n' && *cmd != ';') ++cmd; + if (*cmd == ';') cmd = skip(cmd + 1); +} + +PUBLIC void mdb_error(s) +char *s; +{ + Printf("%s",s); + longjmp(mainlp, 0); +} + +PUBLIC void main(argc, argv) +int argc; +char *argv[]; +{ + int i, c; + char *p, *q, *r; + int opt_c = FALSE; /* load core file */ + int opt_f = FALSE; /* load object file */ + int opt_l = FALSE; /* log to file */ + int opt_L = FALSE; /* log to file and screen */ + + + prc = (struct proc *) lbuf; + strcpy(sbuf, "\n"); + corepid = -1; /* set to indicate none */ + prog = p = q = r = NULL; + + if ( argc == 1 ) + { + help_page(); + exit(0); + } + + /* Possible combinations of arguments: + * A single file name: + * If the name is 'core', the coreonly flag is set. + * The -c flag: examine a core file. + * One filename is required with this flag. + * The -f flag: examine an object file. + * One file name is required with this flag. + * The -L or -l flag: write to a log file. + * One file name is required with these flags. + * The -x flag: turn on debugging. + * Used for debugging, and followed by an integer + * argument which is the debugging level. + * + * If any files remain on the argument list, the first + * file is an executable, and the second a core file. + * If any filename starts with '@' it is assumed to + * to be a command file. Only one command file is + * loaded. + */ + + /* check for default file name and fake out getopt */ + if (strcmp(argv[1], "core") == 0) { + for (i = argc ; i > 1 ; i--) + argv[i] = argv[i - 1]; + argv[i] = "-c"; + argc++; + } + + /* parse options */ + opterr = 0; + while ((i = getopt(argc, argv, "c:f:L:l:x:")) != EOF) { + switch (i & 0377) { + case 'c': /* examine a core file */ + if (opt_c == TRUE || opt_f == TRUE) { + help_page(); + exit(1); + } + p = optarg; + opt_c = TRUE; + break; + case 'f': /* examine an object file */ + if (opt_c == TRUE || opt_f == TRUE) { + help_page(); + exit(1); + } + p = optarg; + opt_f = TRUE; + break; + case 'l': /* start logging */ + if (opt_l == TRUE || opt_L == TRUE) { + help_page(); + exit(1); + } + opt_l = TRUE; + logging(i, optarg); + break; + case 'L': /* start logging */ + if (opt_l == TRUE || opt_L == TRUE) { + help_page(); + exit(1); + } + opt_L = TRUE; + logging(i, optarg); + break; +#ifdef DEBUG + case 'x': /* set debug level */ + debug = atoi(optarg); + break; +#endif + case '?': /* default arguments arrive here */ + default: + help_page(); + exit(1); + } + } + + /* can't cope without filenames */ + if (!opt_c && !opt_f && optind >= argc) { + help_page(); + exit(1); + } + + /* any remaining arguments are (optional) file names */ + for (i = optind ; i < argc ; i++) { + if (*argv[i] == '@') { /* command file */ + if (r == NULL) r = argv[i] + 1; + } + /* you can't combine a -c or -f object file and a core file */ + else if (!opt_c && !opt_f && p == NULL) p = argv[i]; + else if (q == NULL) q = argv[i]; /* core file */ + } + + /* initialise stuff - fairly tricky logic */ + coreonly = opt_c; + fileonly = opt_f; + /* when examining files, prog == NULL */ + if (!opt_c && !opt_f) { + prog = p; + syminit(prog); + } + + /* file_init is called for non-core files. + * It is very similar to core_init. It opens the file and set + * various pointers so that we can read it using the same routines + * as a core file. + * NB: Currently there is no special provision to handle object files. + */ + + /* A comment from Will Rose: + * It would be nice to have + * symbol tables available when reading a core + * or a.out, either as part of the executable or + * as a separate file. + * At least three separate types of file structure + * may be used by mdb - core files, a.out files, and + * object files (which may have several flavours). + * A set of routines is needed for each type, with + * a function switch table initialised when mdb is + * started up. + */ + + if (opt_c) lastexp = core_init(p); + if (opt_f) lastexp = file_init(p); + if (q != NULL) lastexp = core_init(q); + if (r != NULL) openin(r); + for (i = 1; i < _NSIG; i++) signal(i, catch); + + setjmp(mainlp); + + while (get_cmd( cbuf, MAXLINE ) != NULL) { + if (strlen(cbuf) == sizeof(cbuf) - 1) { + Printf("Command line too long.\n"); + continue; + } + cmd = cbuf; + command(); + while (*cmd != '\n') command(); + } + tstart(T_EXIT, 0, 0, 0); + exit(0); +} diff --git a/commands/mdb/mdb.h b/commands/mdb/mdb.h new file mode 100644 index 000000000..62cff8841 --- /dev/null +++ b/commands/mdb/mdb.h @@ -0,0 +1,182 @@ +/* + * mdb.h for mdb + */ +#define MDBVERSION "2.6" +#define MDBBUILD 0 + +#define MINIX_SYMBOLS 1 +#define GNU_SYMBOLS 2 + +/* + * Handle options here + */ +#ifndef GNU_SUPPORT +#define GNU_SUPPORT 0 +#endif + +#ifndef SYSCALLS_SUPPORT +#define SYSCALLS_SUPPORT 0 +#endif + +#ifdef DEBUG +#undef DEBUG +#endif + +#ifdef NDEBUG +#undef DEBUG +#else +#define DEBUG 1 +#endif + +#ifdef __i386 +#define EXTRA_SYMBOLS GNU_SUPPORT +#else +#define EXTRA_SYMBOLS 0 +#endif + + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#undef printf /* defined as printk in */ + +#if (CHIP == M68000) +#define __mc68000__ /* controls processor-dependent stuff */ +#if (MACHINE == ATARI) +#define MINIX_ST /* controls system-dependent stuff */ +#else +#error "only the MINIX_ST 1.5.x implementation works on 68K's" +#endif +#endif + +#if (CHIP == INTEL) +#if (MACHINE == IBM_PC) +#define MINIX_PC +#else +#error "only the MINIX_PC 1.5.x and later versions works on *86's" +#endif +#endif + +#ifdef MINIX_ST +#define BP_OFF ((long)&((struct proc *)0)->p_reg.a6) +#define PC_MEMBER(rp) ((rp)->p_reg.pc) +#define PC_OFF ((long)&((struct proc *)0)->p_reg.pc) +#define SP_MEMBER(rp) ((rp)->p_reg.sp) +#define PSW_MEMBER(rp) ((rp)->p_reg.psw) +#endif + +#ifdef MINIX_PC +#define BP_OFF ((long)&((struct proc *)0)->p_reg.fp) +#define PC_MEMBER(rp) ((rp)->p_reg.pc) +#define PC_OFF ((long)&((struct proc *)0)->p_reg.pc) +#endif + +#define ADDRSIZE _WORD_SIZE +#define BITSIZE(size) (8 * (size)) +#define INTSIZE (sizeof(int)) /* not quite right for cross-debugger */ +#define LONGSIZE (sizeof(long)) +#define UCHAR(x) ((x) & 0xFF) +#define NOSEG (-1) /* no segment */ + +/* use hardware codes for segments for simplest decoding */ +#define CSEG 0x2E /* 8088 through 80386 */ +#define DSEG 0x3E + +#if (CHIP == INTEL ) +#ifdef __i86 +#define N_REG16 2 +#endif +#ifdef __i386 +#define N_REG16 4 /* 16 bit registers at start of stackframe */ +#endif +#ifndef N_REG16 +#error "N_REG16 not defined" +#endif +#endif + +#if (CHIP == INTEL ) +#define ADDA(l) ((u16_t) (l) == 0xC481) + +#ifdef __i386 +#define ADDA_CNT(l) ((i32_t) (l)) +#else +#define ADDA_CNT(l) ((i16_t) (l)) +#endif + +#define ADDQ(l) ((u16_t) (l) == 0xC483) +#define ADDQ_CNT(l) (((((l) >> 16) + 128) & 0x000000FF) - 128) +#define BREAK(l) (0x000000CC | ((l) & 0xFFFFFF00)) +#define BREAKPOINT_ADVANCE 1 +#define INCSP2(l) ((u16_t) (l) == 0x4444) +#define POPBX2(l) ((u16_t) (l) == 0x5B5B) +#define POPBX(l) ( (l & 0xFF) == 0x5B) + +/* Added for ANSI CC */ +#define POPCX2(l) ((u16_t) (l) == 0x5959) +#define POPCX(l) ( (l & 0xFF) == 0x59) + +#endif + +#ifdef __mc68000__ +#define ADDA(l) ((int)((l) >> 16) == 0xDFFC) +#define ADDA_CNT(l) (l) +#define ADDQ(l) (((l >> 16) & 0xF13F) == 0x500F) +#define ADDQ_CNT(l) (((((l) >> 25) - 1) & 7) + 1) +#define BREAK(l) (0xA0000000 | ((l) & 0xFFFF)) +#define BREAKPOINT_ADVANCE 0 +#define BYTES_SWAPPED /* this assumes WORDS_SWAPPED too */ +#define LEA(l) (((l) >> 16) == 0x4FEF) +#define LEA_DISP(l) ((long)( l & 0xFFFF)) +#endif + +#define MASK(size) ((size) >= LONGSIZE ? -1L : (1L << BITSIZE(size)) - 1) + +#ifdef BYTES_SWAPPED +#define SHIFT(size) BITSIZE(LONGSIZE - (size)) +#else +#define SHIFT(size) (0) +#endif + +#ifdef _MAIN_MDB +#undef EXTERN +#define EXTERN +#endif + +extern long lbuf[]; /* buffer for proc */ + +EXTERN long st_addr; /* starting address of text */ +EXTERN long et_addr; /* ending address of text */ +EXTERN long sd_addr; /* starting address of data */ +EXTERN long ed_addr; /* ending address of data */ +EXTERN long end_addr; /* ending address of text/data */ +EXTERN long sk_addr; /* starting address of stack */ +EXTERN long sk_size; /* size of stack */ +EXTERN int curpid; /* current pid of process/core */ +EXTERN int corepid; /* pid of core file */ +EXTERN int coreonly; /* core file only */ +EXTERN int fileonly; /* file only */ +EXTERN int cursig; /* current signal */ +EXTERN int seg; /* segment */ +EXTERN int is_separate; /* separate I & D */ +EXTERN int paging; /* paging flag */ +#ifdef DEBUG +EXTERN int debug; /* debug flag */ +#endif +#if SYSCALLS_SUPPORT +EXTERN int syscalls; /* trace syscalls */ +#endif + +#ifdef _MAIN_MDB +#undef EXTERN +#define EXTERN extern +#endif + diff --git a/commands/mdb/mdbdis86.c b/commands/mdb/mdbdis86.c new file mode 100644 index 000000000..306a2c01a --- /dev/null +++ b/commands/mdb/mdbdis86.c @@ -0,0 +1,1564 @@ +/* + * mdbdis86.c for mdb.c - 8086-386 and 8087 disassembler + * From Bruce Evans db + */ + +#include "mdb.h" +#include +#include +#include +#include "proto.h" + +struct address_s +{ + off_t off; + off_t base; +}; + +PRIVATE int bits32; +PRIVATE struct address_s uptr; + +FORWARD _PROTOTYPE( u8_t get8, (void) ); +FORWARD _PROTOTYPE( u16_t get16, (void) ); +FORWARD _PROTOTYPE( u32_t get32, (void) ); +FORWARD _PROTOTYPE( u8_t peek_byte, (off_t addr) ); +FORWARD _PROTOTYPE( u16_t peek_word, (off_t addr) ); +FORWARD _PROTOTYPE( int puti, (void) ); +FORWARD _PROTOTYPE( int outsegaddr, (struct address_s *addr) ); +FORWARD _PROTOTYPE( int outssegaddr, (struct address_s *addr) ); +FORWARD _PROTOTYPE( int show1instruction , (void)); + +/************************* UNASM ******************************/ + + +#define LINDIRECT '[' +#define RINDIRECT ']' + +#define BASE_MASK 0x07 +#define INDEX_MASK 0x38 +#define INDEX_SHIFT 3 +#define MOD_MASK 0xC0 /* mod reg r/m is mmrrrRRR */ +#define REG_MOD 0xC0 +#define MEM0_MOD 0x00 +#define MEM1_MOD 0x40 +#define MEM2_MOD 0x80 +#define REG_MASK 0x38 +#define REG_SHIFT 3 +#define RM_MASK 0x07 +#define RM_SHIFT 0 +#define SS_MASK 0xC0 +#define SS_SHIFT 6 + +#define SIGNBIT 0x02 /* opcode bits xxxxxxsw for immediates */ +#define WORDBIT 0x01 +#define TOREGBIT 0x02 /* opcode bit for non-immediates */ + +#define MAX_SIGNED_CHAR 0x7F /* will assume 2's complement */ +#define MAX_UNSIGNED_CHAR 0xFF + +typedef unsigned opcode_pt; /* promote to unsigned and not int */ + +typedef int reg_pt; +typedef int su16_t; +typedef int su8_pt; + +FORWARD _PROTOTYPE( su8_pt get8s , (void)); +FORWARD _PROTOTYPE( void getmodregrm , (void)); +FORWARD _PROTOTYPE( void i_00_to_3f , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_40_to_5f , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_60_to_6f , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_70_to_7f , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_80 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_88 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_90 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_98 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_a0 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_a8 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_b0 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_b8 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_c0 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_c8 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_d0 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_d8 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_e0 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_e8 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_f0 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void i_f8 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void outad , (opcode_pt opc )); +FORWARD _PROTOTYPE( void outad1 , (opcode_pt opc )); +FORWARD _PROTOTYPE( void outalorx , (opcode_pt opc )); +FORWARD _PROTOTYPE( void outax , (void)); +FORWARD _PROTOTYPE( void outbptr , (void)); +FORWARD _PROTOTYPE( void outbwptr , (opcode_pt opc )); +FORWARD _PROTOTYPE( void outea , (opcode_pt wordflags )); +FORWARD _PROTOTYPE( void outf1 , (void)); +FORWARD _PROTOTYPE( void out32offset , (void)); +FORWARD _PROTOTYPE( void outfishy , (void)); +FORWARD _PROTOTYPE( void outgetaddr , (void)); +FORWARD _PROTOTYPE( void outimmed , (opcode_pt signwordflag )); +FORWARD _PROTOTYPE( void outpc , (off_t pc )); +FORWARD _PROTOTYPE( void outsegpc , (void)); +FORWARD _PROTOTYPE( void oututstr , (char *s )); +FORWARD _PROTOTYPE( void outword , (void)); +FORWARD _PROTOTYPE( void outwptr , (void)); +FORWARD _PROTOTYPE( void outwsize , (void)); +FORWARD _PROTOTYPE( void pagef , (void)); +FORWARD _PROTOTYPE( void shift , (opcode_pt opc )); +FORWARD _PROTOTYPE( void checkmemory , (void)); +FORWARD _PROTOTYPE( void CL , (void)); +FORWARD _PROTOTYPE( void Eb , (void)); +FORWARD _PROTOTYPE( void Ev , (void)); +FORWARD _PROTOTYPE( void EvGv , (void)); +FORWARD _PROTOTYPE( void EvIb , (void)); +FORWARD _PROTOTYPE( void Ew , (void)); +FORWARD _PROTOTYPE( void EwRw , (void)); +FORWARD _PROTOTYPE( void Gv , (void)); +FORWARD _PROTOTYPE( void Gv1 , (void)); +FORWARD _PROTOTYPE( void GvEv , (void)); +FORWARD _PROTOTYPE( void GvEw , (void)); +FORWARD _PROTOTYPE( void GvM , (void)); +FORWARD _PROTOTYPE( void GvMa , (void)); +FORWARD _PROTOTYPE( void GvMp , (void)); +FORWARD _PROTOTYPE( void Ib , (void)); +FORWARD _PROTOTYPE( void Iw , (void)); +FORWARD _PROTOTYPE( void Iv , (void)); +FORWARD _PROTOTYPE( void Jb , (void)); +FORWARD _PROTOTYPE( void Jv , (void)); +FORWARD _PROTOTYPE( void Ms , (void)); + +_PROTOTYPE( typedef void (*pfv_t),(opcode_pt opc )); + +PRIVATE pfv_t optable[] = +{ + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_00_to_3f, + i_40_to_5f, + i_40_to_5f, + i_40_to_5f, + i_40_to_5f, + i_60_to_6f, + i_60_to_6f, + i_70_to_7f, + i_70_to_7f, + i_80, + i_88, + i_90, + i_98, + i_a0, + i_a8, + i_b0, + i_b8, + i_c0, + i_c8, + i_d0, + i_d8, + i_e0, + i_e8, + i_f0, + i_f8, +}; + +PRIVATE char fishy[] = "???"; +PRIVATE char movtab[] = "mov\t"; + +PRIVATE char *genreg[] = +{ + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", +}; + +PRIVATE char *segreg[] = +{ + "es", "cs", "ss", "ds", "fs", "gs", "?s", "?s", +}; + +PRIVATE char *indreg[] = +{ + "bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx", +}; + +PRIVATE char *str_00_to_3f[] = +{ + /* index by (opcode >> 3) & 7 */ + "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp", +}; + +PRIVATE char *sstr_00_to_3f[] = +{ + /* index ((opc>>2) & 0x0E) + (opc & 7) - 6 */ + "push\tes", "pop\tes", "push\tcs", "pop\tcs", + "push\tss", "pop\tss", "push\tds", "pop\tds", + "es:", "daa", "cs:", "das", "ss:", "aaa", "ds:", "aas", +}; + +PRIVATE char *sstr_0f[] = +{ + "push\tfs", "pop\tfs", fishy, "bt\t", "shld\t", "shld\t", fishy, fishy, + "push\tgs", "pop\tgs", fishy, "bts\t", "shrd\t", "shrd\t", fishy, "imul\t", + fishy, fishy, "lss\t", "btr\t", "lfs\t", "lgs\t", "movzx\t", "movzx\t", + fishy, fishy, "", "btc\t", "bsf\t", "bsr\t", "movsx\t", "movsx\t", +}; + +PRIVATE char *ssstr_0f[] = +{ + "sldt\t", "str\t", "lldt\t", "ltr\t", "verr\t", "verw\t", fishy, fishy, + "sgdt\t", "sidt\t", "lgdt\t", "lidt\t", "smsw\t", fishy, "lmsw\t", fishy, + fishy, fishy, fishy, fishy, "bt\t", "bts\t", "btr\t", "btc\t", +}; + +PRIVATE char *str_40_to_5f[] = +{ + /* index by (opcode >> 3) & 3 */ + "inc\t", "dec\t", "push\t", "pop\t", +}; + +PRIVATE char *str_60_to_6f[] = +{ + "pusha", "popa", "bound\t", "arpl\t", "fs:", "gs:", "os:", "as:", + "push\t", "imul\t", "push\t", "imul\t", "insb", "ins", "outsb", "outs", +}; + +PRIVATE char *str_flags[] = +{ + /* opcodes 0x70 to 0x7F, and 0x0F80 to 0x0F9F */ + "o", "no", "b", "nb", "z", "nz", "be", "a", + "s", "ns", "pe", "po", "l", "ge", "le", "g", +}; + +PRIVATE char *str_98[] = +{ + "cbw", "cwd", "call\t", "wait", "pushf", "popf", "sahf", "lahf", + "cwde", "cdq", "call\t", "wait", "pushfd", "popfd", "sahf", "lahf", +}; + +PRIVATE char *str_a0[] = +{ + movtab, movtab, movtab, movtab, "movsb", "movs", "cmpsb", "cmps", +}; + +PRIVATE char *str_a8[] = +{ + "test\t", "test\t", "stosb", "stos", "lodsb", "lods", "scasb", "scas", +}; + +PRIVATE char *str_c0[] = +{ + "", "", "ret\t", "ret", "les\t", "lds\t", movtab, movtab, +}; + +PRIVATE char *str_c8[] = +{ + "enter\t", "leave", "retf\t", "retf", "int\t3", "int\t", "into", "iret", +}; + +PRIVATE char *str_d0[] = +{ + "aam", "aad", "db\td6", "xlat", +}; + +PRIVATE char *sstr_d0[] = +{ + "rol", "ror", "rcl", "rcr", "shl", "shr", fishy, "sar", +}; + +PRIVATE char *str_d8[] = +{ + "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", + "fld", NULL, "fst", "fstp", "fldenv", "fldcw", "fstenv", "fstcw", + "fiadd", "fimul", "ficom", "ficomp", "fisub", "fisubr", "fidiv", "fidivr", + "fild", NULL, "fist", "fistp", NULL, "fld", NULL, "fstp", + "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", + "fld", NULL, "fst", "fstp", "frstor", NULL, "fsave", "fstsw", + "fiadd", "fimul", "ficom", "ficomp", "fisub", "fisubr", "fidiv", "fidivr", + "fild", NULL, "fist", "fistp", "fbld", "fild", "fbstp", "fistp", +}; + +PRIVATE char *str1_d8[] = +{ + "fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr", + "fld", "fxch", "\0\0", NULL, "\0\10", "\0\20", "\0\30", "\0\40", + NULL, NULL, NULL, NULL, NULL, "\0\50", NULL, NULL, + NULL, NULL, NULL, NULL, "\0\60", NULL, NULL, NULL, + "fadd", "fmul", NULL, NULL, "fsubr", "fsub", "fdivr", "fdiv", + "ffree", NULL, "fst", "fstp", "fucom", "fucomp", NULL, NULL, + "faddp", "fmulp", NULL, "\0\70", "fsubrp", "fsubp", "fdivrp", "fdivp", + NULL, NULL, NULL, NULL, "\0\100", NULL, NULL, NULL, +}; + +PRIVATE unsigned char size_d8[] = +{ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 14-28, 2, 14-28, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 0, 10, 0, 10, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 8, 8, 94-108, 0, 94-108, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 10, 8, 10, 8, +}; + +PRIVATE char *sstr_d8[] = +{ + "fnop", NULL, NULL, NULL, /* D9D0 */ + NULL, NULL, NULL, NULL, + "fchs", "fabs", NULL, NULL, /* D9E0 */ + "ftst", "fxam", NULL, NULL, + "fld1", "fldl2t", "fldl2e", "fldpi", /* D9E8 */ + "fldlg2", "fldln2", "fldz", NULL, + "f2xm1", "fyl2x", "fptan", "fpatan", /* D9F0 */ + "fxtract", "fprem1", "fdecstp", "fincstp", + "fprem", "fyl2xp1", "fsqrt", "fsincos", /* D9F8 */ + "frndint", "fscale", "fsin", "fcos", + NULL, "fucompp", NULL, NULL, /* DAE8 */ + NULL, NULL, NULL, NULL, + "feni", "fdisi", "fclex", "finit", /* DBE0 */ + "fsetpm", NULL, NULL, NULL, + NULL, "fcompp", NULL, NULL, /* DED8 */ + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, /* DFE0 */ + "fstsw\tax", NULL, NULL, NULL, +}; + +PRIVATE char *str_e0[] = +{ + "loopnz\t", "loopz\t", "loop\t", "jcxz\t", + "in\t", "in\t", "out\t", "out\t", +}; + +PRIVATE char *str_e8[] = +{ + "call\t", "jmp\t", "jmp\t", "jmp\t", + "in\t", "in\t", "out\t", "out\t", +}; + +PRIVATE char *str_f0[] = +{ + "lock\t", "db\tf1", "repnz\t", "repz\t", + "hlt", "cmc", + /* other 2 from sstr_f0 */ +}; + +PRIVATE char *sstr_f0[] = +{ + "test\t", fishy, "not\t", "neg\t", + "mul\t", "imul\t", "div\t", "idiv\t", +}; + +PRIVATE char *str_f8[] = +{ + "clc", "stc", "cli", "sti", + "cld", "std", + /* other 2 from sstr_f8 */ +}; + +PRIVATE char *sstr_f8[] = +{ + "inc\t", "dec\t", "call\t", "call\tfar ", + "jmp\t", "jmp\tfar ", "push\t", "???\t", +}; + +PRIVATE int data_seg; /* data segment (munged name for asld) */ +PRIVATE unsigned hasize; /* half address size in bits */ +PRIVATE unsigned hdefsize; +PRIVATE unsigned hosize; /* half operand size in bits */ + /* for easy index into reg tables */ +PRIVATE opcode_pt mod; +PRIVATE off_t offtable[2]; +PRIVATE off_t *offptr; +PRIVATE off_t *off1ptr; +PRIVATE opcode_pt reg; +PRIVATE opcode_pt rm; + +PRIVATE su8_pt get8s() +{ + u8_t got; + + if ((got = get8()) > MAX_SIGNED_CHAR) + got -= (MAX_UNSIGNED_CHAR + 1); + return got; +} + +PRIVATE void getmodregrm() +{ + opcode_pt modregrm; + + modregrm = get8(); + mod = modregrm & MOD_MASK; + reg = (modregrm & REG_MASK) >> REG_SHIFT; + rm = (modregrm & RM_MASK) >> RM_SHIFT; +} + +PRIVATE void i_00_to_3f(opc) +opcode_pt opc; +{ + opcode_pt sub; + + if (opc == 15) + pagef(); + else if ((sub = opc & 7) >= 6) + { + outustr((sstr_00_to_3f - 6)[((opc >> 2) & 0x0E) + sub]); + if (!(opc & 1)) + data_seg = opc; + } + else + { + oututstr(str_00_to_3f[(opc >> 3) & 7]); + if (sub == 4) + { + outustr(genreg[0]); + outcomma(); + Ib(); + } + else if (sub == 5) + { + outax(); + outcomma(); + Iv(); + } + else + outad(sub); + } +} + +PRIVATE void i_40_to_5f(opc) +opcode_pt opc; +{ + outustr(str_40_to_5f[(opc >> 3) & 3]); + outustr(genreg[hosize + (opc & 7)]); +} + +PRIVATE void i_60_to_6f(opc) +opcode_pt opc; +{ +/* most for 386, some for 286 */ + + outustr((str_60_to_6f - 0x60)[opc]); + switch (opc) + { + case 0x60: + case 0x61: + if (hosize == 16) + outwsize(); + break; + case 0x62: + GvMa(); + break; + case 0x63: + EwRw(); + break; + case 0x64: + case 0x65: + data_seg = opc; + break; + case 0x66: + hosize = (16 + 8) - hdefsize; + break; + case 0x67: + hasize = (16 + 8) - hdefsize; + break; + case 0x68: + outword(); + Iv(); + break; + case 0x6A: + outword(); + outimmed(SIGNBIT | WORDBIT); + break; + case 0x69: + GvEv(); + outcomma(); + Iv(); + break; + case 0x6B: + GvEv(); + outcomma(); + outimmed(SIGNBIT | WORDBIT); + break; + case 0x6D: + case 0x6F: + outwsize(); + break; + } +} + +PRIVATE void i_70_to_7f(opc) +opcode_pt opc; +{ + outustr("j"); + oututstr((str_flags - 0x70)[opc]); + Jb(); +} + +PRIVATE void i_80(opc) +opcode_pt opc; +{ + if (opc >= 4) + { + outustr(opc >= 6 ? "xchg\t" : "test\t"); + outad(opc); + } + else + { + getmodregrm(); + oututstr(str_00_to_3f[reg]); + outbwptr(opc); + outea(opc); + outcomma(); + outimmed(opc); +#ifdef SIGNED_LOGICALS + if (opc & SIGNBIT && (reg == 1 || reg == 4 || reg == 6)) + /* and, or and xor with signe extension are not documented in some + * 8086 and 80286 manuals, but make sense and work + */ + outfishy(); +#endif + } +} + +PRIVATE void i_88(opc) +opcode_pt opc; +{ + if (opc < 4) + { + outustr(movtab); + outad(opc); + } + else if (opc == 5) + { + oututstr("lea"); + GvM(); + } + else if (opc == 7) + { + oututstr("pop"); + getmodregrm(); + outwptr(); + Ev(); + if (reg != 0) + outfishy(); + } + else + { + getmodregrm(); + outustr(movtab); + if (!(opc & TOREGBIT)) + { + Ev(); + outcomma(); + } + outustr(segreg[reg]); + if (opc & TOREGBIT) + { + outcomma(); + Ev(); + } + } +} + +PRIVATE void i_90(opc) +opcode_pt opc; +{ + if (opc == 0) + outustr("nop"); + else + { + outustr("xchg\t"); + outax(); + outcomma(); + outustr(genreg[hosize + opc]); + } +} + +PRIVATE void i_98(opc) +opcode_pt opc; +{ + outustr((str_98 - 8)[opc + hosize]); + if (opc == 2) + outsegpc(); +} + +PRIVATE void i_a0(opc) +opcode_pt opc; +{ + outustr(str_a0[opc]); + if (opc < 4) + { + mod = MEM0_MOD; /* fake */ + reg = 0; /* fake ax */ + if (hasize == 16) + rm = 5; /* fake [d16] */ + else + rm = 6; /* fake [d32] */ + outad1(opc ^ TOREGBIT); + } + else if (opc & 1) + outwsize(); +} + +PRIVATE void i_a8(opc) +opcode_pt opc; +{ + outustr(str_a8[opc]); + if (opc < 2) + { + outalorx(opc); + outcomma(); + outimmed(opc); + } + else if (opc & 1) + outwsize(); +} + +PRIVATE void i_b0(opc) +opcode_pt opc; +{ + outustr(movtab); + outustr(genreg[opc]); + outcomma(); + Ib(); +} + +PRIVATE void i_b8(opc) +opcode_pt opc; +{ + outustr(movtab); + outustr(genreg[hosize + opc]); + outcomma(); + Iv(); +} + +PRIVATE void i_c0(opc) +opcode_pt opc; +{ + outustr(str_c0[opc]); + if (opc >= 6) + { + getmodregrm(); + outbwptr(opc); + outea(opc); + outcomma(); + outimmed(opc & WORDBIT); + if (reg != 0) + /* not completely decoded (like DEBUG) */ + outfishy(); + } + else if (opc >= 4) + GvMp(); + else if (opc == 2) + Iv(); + else if (opc < 2) + shift(opc); +} + +PRIVATE void i_c8(opc) +opcode_pt opc; +{ + outustr(str_c8[opc]); + if (opc == 0) + { + Iw(); + outcomma(); + Ib(); + } + if (opc == 2) + Iv(); + else if (opc == 5) + Ib(); + else if (opc == 7 && hosize == 16) + outwsize(); +} + +PRIVATE void i_d0(opc) +opcode_pt opc; +{ + opcode_pt aabyte; + + if (opc < 4) + shift(opc | 0xD0); + else + { + outustr((str_d0 - 4)[opc]); + if (opc < 6 && (aabyte = get8()) != 0x0A) + { + outtab(); + outh8(aabyte); + outfishy(); + } + } +} + +PRIVATE void i_d8(opc) +opcode_pt opc; +{ + opcode_pt esc; + char *str; + + getmodregrm(); + esc = (opc << 3) | reg; + if ((str = (mod == REG_MOD ? str1_d8 : str_d8)[esc]) == NULL) + { +escape: + oututstr("esc"); + outh8(esc); + outcomma(); + outea(0); + return; + } + if (*str == 0) + { + str = sstr_d8[str[1] + rm]; + if (str == NULL) + goto escape; + outustr(str); + return; + } + outustr(str); + outtab(); + if (mod == REG_MOD) + { + if (opc == 0 && reg != 2 && reg != 3) + outustr("st,"); + outf1(); + if (opc == 4 || opc == 6) + outustr(",st"); + return; + } + switch(size_d8[esc]) + { + case 4: + outustr("d"); + case 2: + outwptr(); + break; + case 8: + outustr("q"); + outwptr(); + break; + case 10: + outustr("t"); + outbptr(); + break; + } + outea(opc); +} + +PRIVATE void i_e0(opc) +opcode_pt opc; +{ + outustr(str_e0[opc]); + if (opc < 4) + Jb(); + else if (opc < 6) + { + outalorx(opc); + outcomma(); + Ib(); + } + else + { + Ib(); + outcomma(); + outalorx(opc); + } +} + +PRIVATE void i_e8(opc) +opcode_pt opc; +{ + outustr(str_e8[opc]); + if (opc < 2) + Jv(); + else if (opc == 2) + outsegpc(); + else if (opc == 3) + Jb(); + else + { + if (opc & TOREGBIT) + { + outustr(genreg[10]); + outcomma(); + outalorx(opc); + } + else + { + outalorx(opc); + outcomma(); + outustr(genreg[10]); + } + } +} + +PRIVATE void i_f0(opc) +opcode_pt opc; +{ + if (opc < 6) + outustr(str_f0[opc]); + else + { + getmodregrm(); + outustr(sstr_f0[reg]); + outbwptr(opc); + outea(opc); + if (reg == 0) + { + outcomma(); + outimmed(opc & WORDBIT); + } + } +} + +PRIVATE void i_f8(opc) +opcode_pt opc; +{ + if (opc < 6) + outustr(str_f8[opc]); + else + { + getmodregrm(); + if (opc == 6 && reg >= 2) + outustr("fishy\t"); + else + outustr(sstr_f8[reg]); + outbwptr(opc); + outea(opc); + } +} + +PRIVATE void outad(opc) +opcode_pt opc; +{ + getmodregrm(); + outad1(opc); +} + +PRIVATE void outad1(opc) +opcode_pt opc; +{ + if (!(opc & TOREGBIT)) + { + outea(opc); + outcomma(); + } + if (opc & WORDBIT) + Gv1(); + else + outustr(genreg[reg]); + if (opc & TOREGBIT) + { + outcomma(); + outea(opc); + } +} + +PRIVATE void outalorx(opc) +opcode_pt opc; +{ + if (opc & WORDBIT) + outax(); + else + outustr(genreg[0]); +} + +PRIVATE void outax() +{ + outustr(genreg[hosize]); +} + +PRIVATE void outbptr() +{ + outustr("byte ptr "); +} + +PRIVATE void outbwptr(opc) +opcode_pt opc; +{ + if (mod != REG_MOD) + { + if (opc & WORDBIT) + outwptr(); + else + outbptr(); + } +} + +PRIVATE void outea(wordflags) +opcode_pt wordflags; +{ + reg_pt base; + reg_pt index; + opcode_pt ss; + opcode_pt ssindexbase; + + if (mod == REG_MOD) + outustr(genreg[hosize * (wordflags & WORDBIT) + rm]); + else + { + outbyte(LINDIRECT); + if (hasize == 16) + { + if (rm == 4) + { + base = (ssindexbase = get8()) & BASE_MASK; + if (mod == MEM0_MOD && base == 5) + outgetaddr(); + else + outustr((genreg + 16)[base]); + ss = (ssindexbase & SS_MASK) >> SS_SHIFT; + if ((index = (ssindexbase & INDEX_MASK) >> INDEX_SHIFT) != 4) + { + outbyte('+'); + outustr((genreg + 16)[index]); + outstr("\0\0\0*2\0*4\0*8\0" + (3 * ss)); + } + } + else if (mod == MEM0_MOD && rm == 5) + outgetaddr(); + else + outustr((genreg + 16)[rm]); + } + else if (mod == MEM0_MOD && rm == 6) + outgetaddr(); + else + outustr(indreg[rm]); + if (mod == MEM1_MOD) + /* fake sign extension to get +- */ + outimmed(SIGNBIT | WORDBIT); + else if (mod == MEM2_MOD) + { + outbyte('+'); +#if (_WORD_SIZE == 4) + out32offset(); +#else + outgetaddr(); +#endif + } + outbyte(RINDIRECT); + if (hasize == 16 && rm == 4 && index == 4 && ss != 0) + outfishy(); + } +} + +PRIVATE void outf1() +{ + outustr("st("); + outbyte((int) (rm + '0')); + outbyte(')'); +} + +#if (_WORD_SIZE == 4) + +PRIVATE void out32offset() +{ + off_t off; + + if (hasize == 16) + off = get32(); + else + outfishy(); + + outh32(off); +} +#endif + +PRIVATE void outfishy() +{ + outustr("\t???"); +} + +PRIVATE void outgetaddr() +{ + off_t off; + + if (hasize == 16) + off = get32(); + else + off = get16(); + + if ( finds_data(off,data_seg) ) + *offptr++ = off; + else if (hasize == 16) + outh32(off); + else + outh16((u16_t) off); +} + +PRIVATE void outimmed(signwordflag) +opcode_pt signwordflag; +{ + su8_pt byte; + + if (signwordflag & WORDBIT) + { + if (signwordflag & SIGNBIT) + { + if ((byte = get8s()) < 0) + { + outbyte('-'); + byte = -byte; + } + else + outbyte('+'); + outh8((u8_t) byte); + } + else + Iv(); + } + else + Ib(); +} + +PRIVATE void outpc(pc) +off_t pc; +{ + if (hosize == 8) + pc = (u16_t) pc; + + if ( finds_pc(pc) ) + *offptr++ = pc; + else if (hosize == 16) + outh32(pc); + else + outh16((u16_t) pc); +} + +PRIVATE void outsegpc() +{ + off_t oldbase; + off_t pc; + + if (hosize == 16) + pc = get32(); + else + pc = get16(); + oldbase = uptr.base; + outh16((u16_t) (uptr.base = get16())); /* fake seg for lookup of pc */ + /* TODO - convert to offset in protected mode */ + outbyte(':'); + outpc(pc); + uptr.base = oldbase; +} + +PRIVATE void oututstr(s) +char *s; +{ + outustr(s); + outtab(); +} + +PRIVATE void outword() +{ + outustr("dword " + ((16 - hosize) >> 3)); +} + +PRIVATE void outwptr() +{ + outword(); + outustr("ptr "); +} + +PRIVATE void outwsize() +{ + if (hosize == 16) + outustr("d"); + else + outustr("w"); +} + +PRIVATE void pagef() +{ + opcode_pt opc; + int regbad; + + if ((opc = get8()) <= 1 || opc == 0xBA) + { + if (opc == 0xBA) + opc = 16; + else + opc *= 8; + getmodregrm(); + outustr(ssstr_0f[opc += reg]); + if (opc < 6 || opc == 12 || opc == 14) + Ew(); + else if (opc >= 8 && opc < 13) + Ms(); + else if (opc >= 20) + { + outbwptr(WORDBIT); + EvIb(); + } + } + else if (opc < 4) + { + oututstr("lar\0lsl" + 4 * (opc - 2)); + GvEw(); + } + else if (opc == 5) + { + outustr("loadall"); + outfishy(); + } + else if (opc == 6) + outustr("clts"); + else if (opc < 0x20) + outstr(fishy); + else if (opc < 0x27 && opc != 0x25) + { + outustr(movtab); + getmodregrm(); + hosize = 16; + if (!(opc & TOREGBIT)) + { + Ev(); /* Rd() since hosize is 16 */ + outcomma(); + } + regbad = FALSE; + if (opc & 1) + { + outustr("dr"); + if (reg == 4 || reg == 5) + regbad = TRUE; + } + else if (opc < 0x24) + { + outustr("cr"); + if (reg >= 4 || reg == 1) + regbad = TRUE; + } + else + { + outustr("tr"); + if (reg < 6) + regbad = TRUE; + } + outbyte((int) (reg + '0')); + if (opc & TOREGBIT) + { + outcomma(); + Ev(); + } + if (regbad || mod != REG_MOD) + outfishy(); + } + else if (opc < 0x80) + outstr(fishy); + else if (opc < 0x90) + { + outustr("j"); + oututstr((str_flags - 0x80)[opc]); + Jv(); + } + else if (opc < 0xA0) + { + outustr("set"); + oututstr((str_flags - 0x90)[opc]); + getmodregrm(); + outbwptr(0); + Eb(); + } + else if (opc < 0xC0) + { + outustr((sstr_0f - 0xA0)[opc]); + switch (opc) + { + case 0xA3: + case 0xAB: + case 0xB3: + case 0xBB: + EvGv(); + break; + case 0xA4: + case 0xAC: + EvGv(); + outcomma(); + Ib(); + break; + case 0xA5: + case 0xAD: + EvGv(); + outcomma(); + CL(); + break; + case 0xAF: + case 0xBC: + case 0xBD: + GvEv(); + break; + case 0xB2: + case 0xB4: + case 0xB5: + GvMp(); + break; + case 0xB6: + case 0xBE: + Gv(); + outcomma(); + outbwptr(opc); + Eb(); + break; + case 0xB7: + case 0xBF: + Gv(); + outcomma(); + hosize = 8; /* done in Ew(), but too late */ + outbwptr(opc); + Ew(); + break; + } + } + else + outstr(fishy); +} + +PRIVATE int puti() +{ + static int hadprefix; + opcode_pt opcode; + +more: + offptr = offtable; + opcode = get8(); + if (!hadprefix) + { + data_seg = DSEG; + hdefsize = 8; + if (bits32) + hdefsize = 16; + hosize = + hasize = hdefsize; + } + (*optable[opcode >> 3])(opcode < 0x80 ? opcode : opcode & 7); + if (offptr > offtable) + { + if (stringtab() >= 31) + { + outspace(); + outspace(); + } + else + while (stringtab() < 32) + outtab(); + outbyte(';'); + for (off1ptr = offtable; off1ptr < offptr; ++off1ptr) + { + outspace(); + if (*off1ptr < 0x10000) + outh16((u16_t) *off1ptr); + else + outh32(*off1ptr); + } + offptr = offtable; + } + if ((opcode & 0xE7) == 0x26 || + opcode >= 0x64 && opcode < 0x68 || + opcode == 0xF0 || opcode == 0xF2 || opcode == 0xF3) + /* not finished instruction for 0x26, 0x2E, 0x36, 0x3E seg overrides + * and 0x64, 0x65 386 seg overrides + * and 0x66, 0x67 386 size prefixes + * and 0xF0 lock, 0xF2 repne, 0xF3 rep + */ + { + hadprefix = TRUE; + goto more; /* TODO - print prefixes better */ + return FALSE; + } + hadprefix = FALSE; + return TRUE; +} + +PRIVATE void shift(opc) +opcode_pt opc; +{ + getmodregrm(); + oututstr(sstr_d0[reg]); + outbwptr(opc); + outea(opc); + outcomma(); + if (opc < 0xD0) + Ib(); + else if (opc & 2) + CL(); + else + outbyte('1'); +} + +PRIVATE void checkmemory() +{ + if (mod == REG_MOD) + outfishy(); +} + +PRIVATE void CL() +{ + outustr(genreg[1]); +} + +PRIVATE void Eb() +{ + outea(0); +} + +PRIVATE void Ev() +{ + outea(WORDBIT); +} + +PRIVATE void EvGv() +{ + getmodregrm(); + Ev(); + outcomma(); + Gv1(); +} + +PRIVATE void EvIb() +{ + Ev(); + outcomma(); + Ib(); +} + +PRIVATE void Ew() +{ + hosize = 8; + Ev(); +} + +PRIVATE void EwRw() +{ + hosize = 8; + EvGv(); +} + +PRIVATE void Gv() +{ + getmodregrm(); + Gv1(); +} + +PRIVATE void Gv1() +{ + outustr(genreg[hosize + reg]); +} + +PRIVATE void GvEv() +{ + Gv(); + outcomma(); + Ev(); +} + +PRIVATE void GvEw() +{ + Gv(); + outcomma(); + Ew(); +} + +PRIVATE void GvM() +{ + GvEv(); + checkmemory(); +} + +PRIVATE void GvMa() +{ + GvM(); +} + +PRIVATE void GvMp() +{ + GvM(); +} + +PRIVATE void Ib() +{ + outh8(get8()); +} + +PRIVATE void Iw() +{ + outh16(get16()); +} + +PRIVATE void Iv() +{ + if (hosize == 16) + outh32(get32()); + else + Iw(); +} + +PRIVATE void Jb() +{ + off_t pcjump; + + pcjump = get8s(); + outpc(pcjump + uptr.off); +} + +PRIVATE void Jv() +{ + off_t pcjump; + + if (hosize == 16) + pcjump = get32(); + else + pcjump = (su16_t) get16(); + outpc(pcjump + uptr.off); +} + +PRIVATE void Ms() +{ + Ev(); + checkmemory(); +} + +/********************* DASM ******************************/ + +PUBLIC long dasm( addr, count, symflg ) +long addr; +int count; +int symflg; +{ +#if (_WORD_SIZE == 4) + bits32 = TRUE; /* Set mode */ +#else + bits32 = FALSE; +#endif + uptr.off = addr; + uptr.base = 0; /* not known */ + while ( count-- != 0 && show1instruction() ) + ; +} + + +PRIVATE int show1instruction() +{ + register int column; + int idone; + static char line[81]; + int maxcol; + struct address_s newuptr; + struct address_s olduptr; + + outbyte('\r'); + do + { + if ( text_symbol(uptr.off) ) { + outbyte(':'); + outbyte('\n'); + } + olduptr = uptr; + openstring(line); + idone = puti(); + line[stringpos()] = 0; + closestring(); + newuptr = uptr; + uptr = olduptr; + column = outssegaddr(&uptr); + while (uptr.off != newuptr.off) + { + outh8(get8()); + column += 2; + } + maxcol = bits32 ? 24 : 16; + while (column < maxcol) + { + outtab(); + column += 8; + } + outtab(); + outstr(line); + outbyte('\n'); + } + while (!idone); /* eat all prefixes */ + return TRUE; +} + + +PRIVATE u8_t get8() +{ +/* get 8 bits current instruction pointer and advance pointer */ + + u8_t temp; + + temp = peek_byte(uptr.off + uptr.base); + ++uptr.off; + return temp; +} + +PRIVATE u16_t get16() +{ +/* get 16 bits from current instruction pointer and advance pointer */ + + u16_t temp; + + temp = peek_word(uptr.off + uptr.base); + uptr.off += 2; + return temp; +} + +PRIVATE u32_t get32() +{ +/* get 32 bits from current instruction pointer and advance pointer */ + + u32_t temp; + + temp = peek_dword(uptr.off + uptr.base); + uptr.off += 4; + return temp; +} + + +PRIVATE int outsegaddr(addr) +struct address_s *addr; +{ +/* print segmented address */ + + int bytes_printed; + + bytes_printed = 2; + bytes_printed = outsegreg(addr->base); + if (bytes_printed > 4) + outbyte('+'); + else + outbyte(':'); + ++bytes_printed; + if (addr->off >= 0x10000) + { + outh32(addr->off); + return bytes_printed + 8; + } + outh16((u16_t) addr->off); + return bytes_printed + 4; +} + +PRIVATE int outssegaddr(addr) +struct address_s *addr; +{ +/* print 32 bit segmented address and 2 spaces */ + + int bytes_printed; + + bytes_printed = outsegaddr(addr); + outspace(); + outspace(); + return bytes_printed + 2; +} + +PRIVATE u8_t peek_byte(addr) +off_t addr; +{ + return (u8_t) peek_dword(addr) & 0xFF; /* 8 bits only */ +} + +PRIVATE u16_t peek_word(addr) +off_t addr; +{ + return (u16_t) peek_dword(addr); +} diff --git a/commands/mdb/mdbexp.c b/commands/mdb/mdbexp.c new file mode 100644 index 000000000..91bfaaff6 --- /dev/null +++ b/commands/mdb/mdbexp.c @@ -0,0 +1,157 @@ +/* + * mdbexp.c - MINIX expresion parser + * + * Written by Bruce D. Szablak + * + * This free software is provided for non-commerical use. No warrantee + * of fitness for any use is implied. You get what you pay for. Anyone + * may make modifications and distribute them, but please keep this header + * in the distribution. + */ + +#include "mdb.h" +#include +#include +#include +#include +#include "proto.h" + +FORWARD _PROTOTYPE(long value , (char *s , char **s_p , int *seg_p )); +FORWARD _PROTOTYPE(long lookup , (char *s , char **s_p , int *seg_p )); + +#define idchar(c) (isalpha(c) || isdigit(c) || (c) == '_') + +/* + * Get an expression for mdb + */ +PUBLIC char *getexp(buf, exp_p, seg_p) +char *buf; +int *seg_p; +long *exp_p; +{ + long v = 0L; + + buf = skip(buf); + if ((isalpha(*buf) && (isspace(buf[1]) || buf[1] == ';')) + || *buf == '\n' + || *buf == ';' + || *buf == '/' + || *buf == '!' + || *buf == '?' + || *buf == '@' + || *buf == '#') { + *exp_p = 0L; + return buf; + } + v = value(buf, &buf, seg_p); + buf = skip(buf); + if (*buf == '+') + v += value(skip(buf + 1), &buf, seg_p); + else if (*buf == '-') + v -= value(skip(buf + 1), &buf, seg_p); + *exp_p = v; + return skip(buf); +} + +/* + * Get value + * + * \c escaped characters + * digits number + * $xx registers + * \n 0L + * then calls lookup for symbols + */ +PRIVATE long value(s, s_p, seg_p) +char *s, **s_p; +int *seg_p; +{ + long k; + + if (*s == '\'') { /* handle character constants here */ + *s_p = s + 2; + return s[1]; + } + if (*s == '-' || isdigit(*s)) + return strtol(s, s_p, 0); + if (*s == '$') { + k = reg_addr(s + 1); + *s_p = s + 3; + return get_reg(curpid, k); + k = reg_addr(s + 1); + *s_p = s + 3; + return get_reg(curpid, k); + } + if (*s == '\n') { + *s_p = s + 1; + return 0L; + } + return lookup(s, s_p, seg_p); +} + +/* + * Lookup symbol - return value + * Handle special cases: _start T: D: S: + * then call symbolvalue() + */ +PRIVATE long lookup(s, s_p, seg_p) +char *s, **s_p; +int *seg_p; +{ + long value; + char c; + int l; + + for (l = 1; idchar(s[l]); ++l) {} + c = s[l]; + s[l] = 0; + + if (strcmp("_start", s) == 0) { + *seg_p = T; + if (c == ':') c = '+'; + *(*s_p = s + 6) = c; + return st_addr; + } + if (strcmp("T", s) == 0) { + *seg_p = T; + if (c == ':') c = '+'; + *(*s_p = s + 1) = c; + return st_addr; + } + if (strcmp("D", s) == 0) { + *seg_p = D; + if (c == ':') c = '+'; + *(*s_p = s + 1) = c; + return sd_addr; + } + if (strcmp("S", s) == 0) { + *seg_p = S; + if (c == ':') c = '+'; + *(*s_p = s + 1) = c; + return sk_addr; + } + + if ((value = symbolvalue(s, TRUE)) != 0L) { + *seg_p = T; + *(*s_p = s + l) = c; + return value; + } + + if ((value = symbolvalue(s, FALSE)) != 0L) { + *seg_p = D; + *(*s_p = s + l) = c; + return value; + } + + Printf("%s: ", s); + mdb_error("symbol not found\n"); +} + +/* Skip spaces */ +PUBLIC char *skip(s) +register char *s; +{ + while (isspace(*s)) ++s; + return *s ? s : s - 1; +} + diff --git a/commands/mdb/misc.c b/commands/mdb/misc.c new file mode 100644 index 000000000..f1c732479 --- /dev/null +++ b/commands/mdb/misc.c @@ -0,0 +1,289 @@ +/* + * misc.c for mdb + */ + +#include "mdb.h" +#include +#include +#include +#include +#define ptrace mdbtrace +#include +#include "proto.h" + +FORWARD _PROTOTYPE( void pr_ascii , (long val , int size )); + +/* Print ascii */ +PRIVATE void pr_ascii(val, size) +long val; +int size; +{ + int i; + int v; + int sh; + +#ifdef BYTES_SWAPPED + sh = 8 * size; +#else + sh = 0; +#endif + + for (i = 0; i < size; i++) { + v = (int) (val >> sh) & 0xFF; +#ifdef BYTES_SWAPPED + sh -= 8; +#else + sh += 8; +#endif + Printf(isprint(v) ? "%c" : "\\%03o", v); + } + Printf("\n"); +} + +/* Dump stack */ +PUBLIC void dump_stack(cnt) +long cnt; +{ + vir_bytes v, vi; + long val, sp; + int num, size, nmode; + + size = INTSIZE; /* size of stack element */ + num = (int) cnt; + if (num <= 0) num = 0; + if (num > sk_size) num = (int) sk_size / size; + nmode = num; /* Save mode */ + + /* Get current SP */ + sp = get_reg(curpid, reg_addr("sp")); + + /* Starting address is top of stack seg -1 */ + vi = (vir_bytes) sk_addr + (vir_bytes) sk_size - size; + + /* Ending address */ + v = (vir_bytes) end_addr; + if (nmode == 0) v = MAX(v, sp); + + Printf("Stack Dump SP=%*lx\nAddr\tHex\tAscii\n", 2 * size, sp); + do { + val = (ptrace(T_GETDATA, curpid, (long) vi, 0L) >> SHIFT(size)) + & MASK(size); + Printf("%*lx\t", 2 * ADDRSIZE, (vi >> SHIFT(ADDRSIZE)) + & MASK(ADDRSIZE)); + Printf("%*lx\t", 2 * size, val); + pr_ascii(val, size); + num -= 1; + vi -= size; + } while (vi >= v && (nmode ? num > 0 : 1)); + +} + + +/* Get file size */ +PUBLIC off_t file_size(fd) +int fd; +{ +struct stat st; + + if(fstat(fd,&st) <0 ) { + Printf("Cannot stat\n"); + return 0L; + } + else + return st.st_size; +} + +/* Print help page */ +PUBLIC void help_page() +{ + outstr("\nHelp for mdb. For more details, type 'command ?'\n"); + outstr("!#\t- Shell escape / Set Variable or register\n"); + outstr("Tt\t- Current call / Backtrace all\n"); + outstr("/nsf\t- Display for n size s with format f\n"); + outstr("Xx [n]\t- Disasm / & display reg for n instructions\n"); + outstr("Rr a\t- Run / with arguments a\n"); + outstr("Cc [n]\t- Continue with current signal / no signal n times\n"); + outstr("Ii [n]\t- Single step with / no signal for n instructions\n"); + outstr("Mm t n\t- Trace until / Stop when modified t type for n instructions\n"); + outstr("k \t- Kill traced process\n"); + outstr("Bb\t- Display / Set Break-pt\n"); + outstr("Dd\t- Delete all / one break-points\n"); + outstr("P\t- Toggle Paging\n"); + outstr("Ll name\t- Log to file name / and to standard output\n"); +#ifdef DEBUG + outstr("Vv\t- Version info / Toggle debug flag\n"); +#else + outstr("V\t- Version info\n"); +#endif + outstr("e [t]\t- List symbols for type t\n"); + outstr("y\t- Print segment mappings\n"); + outstr("s [n]\t- Dump stack for n words\n"); +#if SYSCALLS_SUPPORT + outstr("z [a]\t- Trace syscalls with address a\n"); +#endif + outstr("? \t- Help - this screen\n"); + outstr("@ file\t- Execute commands from file\n"); + outstr("Qq\t- Quit / and kill traced process\n"); +#ifdef DEBUG + outstr("Usage: mdb -x debug-level [-Ll]logfile exec-file core-file @command-file\n"); +#else + outstr("Usage: mdb [-Ll]logfile exec-file core-file @command-file\n"); +#endif + outstr(" mdb [-fc] file\n"); +} + +PUBLIC void version_info() +{ + Printf("\nmdb version %s.%d for Minix", MDBVERSION, MDBBUILD ); + Printf(" %s.%s", OS_RELEASE, OS_VERSION); +#ifdef MINIX_PC +#ifdef __i386 + Printf(" (32-bit)"); +#else + Printf(" (16-bit)"); +#endif +#endif +#ifdef MINIX_ST + Printf("-ST"); +#endif + Printf("\n"); +} + +/* Print help message on command */ +PUBLIC void help_on(h) +int h; +{ + + switch (h) { + case '/': + outstr("
/nsf\t- Display for n items of size s with format f from address\n"); + outstr("\t n defaults to 1\n"); + outstr("\t s defaults to size of int\n"); + outstr("\t can be b for byte h for short l for long\n"); + outstr("\t f defaults to d for decimal\n"); + outstr("\t can be x X o d D c s or u as in printf\n"); + outstr("\t y treat value as address\n"); + outstr("\t i disasm\n"); + break; + case '@': + outstr("@ file\t- Execute commands from file\n"); + break; + case '#': + outstr("#
cs value\t- Set Variable(s) at address to value\n"); + outstr("\t\t\t for c count and size s\n"); + outstr("\t\t\t b for byte h for short or l for long\n"); + outstr("\t\t\t Count or size must be specified\n"); + outstr("# $xx value\t\t- Set register $xx to value\n"); + break; + case 'C': + outstr("C [n]\t- Continue with curent signal n times\n"); + outstr("\t n defaults to 1\n"); + break; + case 'c': + outstr("c [n]\t- Continue with no signal n times\n"); + outstr("\t n defaults to 1\n"); + break; + case 'e': + outstr("e [t]\t- List symbols for type t\n"); + break; + case 's': + outstr("s [n]\t- Dump stack for n words\n"); + outstr("\t n defaults to whole stack\n"); + break; + case 'I': + outstr("I n\t- Single step with signal for n instructions n defaults to 1\n"); + break; + case 'i': + outstr("i n\t- Single step with no signal for n instructions n defaults to 1\n"); + break; + case 'M': + case 'm': + if ( h == 'M') + outstr("
M t n\t- Trace until\n"); + else + outstr("
m t n\t- Stop when\n"); + outstr("\t\t
is modified t type for n instructions\n"); + outstr("\t\tn defaults to 1\n"); + outstr("\t\tb for byte h for short l for long defaults to size of int\n"); + break; + case 'T': + outstr("T\t- Display current call\n"); + break; + case 't': + outstr("t\t- Backtrace all calls\n"); + break; + case '!': + outstr("![command]\t- Shell escape or spawn command\n"); + break; + case 'R': + outstr("R\t- Run the exec-file\n"); + break; + case 'r': + outstr("r [arguments]\t- Run the exec-file with arguments\n"); + break; + case 'k': + outstr("k\t- Kill traced process\n"); + break; + case 'B': + outstr("B\t- Display all the Break points\n"); + break; + case 'b': + outstr("
b [commands]\t- Set Break-pt at address\n"); + outstr("\t\t\t commands will be executed by mdb at break-pt\n"); + break; + case 'D': + outstr("D\t- Delete all break-points\n"); + break; + case 'd': + outstr("
d\t- Delete one break-point at address\n"); + break; + case 'q': + outstr("q\t- Quit mdb (and kill traced program)\n"); + break; + case 'Q': + outstr("Q\t- Quit mdb immediately\n"); + break; + case 'P': + outstr("P\t- Toggle Paging\n"); + outstr("\t Defaults is OFF\n"); + break; + case 'L': + outstr("L name\t- Log to file name\n"); + outstr("L\t- Reset output to standard output\n"); + break; + case 'l': + outstr("l name\t- Log to file name and standard output\n"); + outstr("l\t- Reset output to standard output\n"); + outstr("\t Defaults to none\n"); + break; +#ifdef DEBUG + case 'v': + outstr("v\t- Toggle debug flag\n"); + break; +#endif + case 'V': + outstr("V\t- Print Version Information for mdb\n"); + break; + case 'X': + outstr("
X [n] [offset]\t- Disasm for n instructions\n"); + outstr("\t\t\t Starting at address+offset\n"); + break; + case 'x': + outstr("
x [n] offset\t- Disasm & display registers for n instructions\n"); + outstr("\t\t\t Starting at address+offset\n"); + break; + case 'y': + outstr("y\t- Print segment mappings\n"); + break; +#if SYSCALLS_SUPPORT + case 'z': + outstr("z [address]\t- Trace system calls using address\n"); + outstr("\t\t If the exec-file has symbols, mdb looks for __sendrec\n"); + break; +#endif + default: + Printf("No help on command '%c' is available\n",h); + break; + } +} + diff --git a/commands/mdb/proto.h b/commands/mdb/proto.h new file mode 100644 index 000000000..0017522a3 --- /dev/null +++ b/commands/mdb/proto.h @@ -0,0 +1,105 @@ +/* + * proto.h for mdb + */ + +/* core.c */ + +_PROTOTYPE( void prtmap, (void) ); +_PROTOTYPE( unsigned long core_init, (char *filename) ); +_PROTOTYPE( unsigned long file_init, (char *filename) ); +_PROTOTYPE( long read_core, (int req, long addr, long data) ); + +/* mdb.c */ + +_PROTOTYPE( void mdb_error, (char *s) ); +_PROTOTYPE( long breakpt , (long addr , char *cmd )); +_PROTOTYPE( void tstart , (int req , int verbose , int val , int cnt )); + +/* io.c */ + +_PROTOTYPE( char *get_cmd , (char *cbuf, int csize) ); +_PROTOTYPE( void openin , (char *s )); +_PROTOTYPE( void logging, (int c, char *name) ); +_PROTOTYPE( void do_error, (char *message) ); +_PROTOTYPE( int Printf, (const char *format, ...)); +_PROTOTYPE( void outbyte, (int byte) ); +_PROTOTYPE( void outcomma, (void) ); +_PROTOTYPE( void outh8, (unsigned num) ); +_PROTOTYPE( void outh16, (unsigned num) ); +_PROTOTYPE( void outh32, (unsigned num) ); +_PROTOTYPE( void outh4, (unsigned num) ); +_PROTOTYPE( void outspace, (void) ); +_PROTOTYPE( void outstr, (char *s) ); +_PROTOTYPE( void outtab, (void) ); +_PROTOTYPE( void outustr, (char *s) ); +_PROTOTYPE( void closestring, (void) ); +_PROTOTYPE( int mytolower, (int ch) ); +_PROTOTYPE( void openstring, (char *string) ); +_PROTOTYPE( int stringpos, (void) ); +_PROTOTYPE( int stringtab, (void) ); + +/* mdbdis86.c */ + +_PROTOTYPE( long dasm, (long addr, int count, int symflg) ); + +/* mdbexp.c */ + +_PROTOTYPE( char *getexp, (char *buf, long *exp_p, int *seg_p) ); +_PROTOTYPE( char *skip, (char *s) ); + +/* kernel.c */ +_PROTOTYPE( long get_reg, (int pid, long k) ); +_PROTOTYPE( void set_reg, (int pid, long k, long value) ); +_PROTOTYPE( long reg_addr, (char *s) ); +_PROTOTYPE( int disp_regs, (void) ); +_PROTOTYPE( int outsegreg, (off_t num) ); +_PROTOTYPE( void update , (void)); +_PROTOTYPE( void disp_maps , (void)); + +/* misc.c */ + +_PROTOTYPE( void dump_stack, (long count) ); +_PROTOTYPE( off_t file_size, (int fd) ); +_PROTOTYPE( void help_on, (int h) ); +_PROTOTYPE( void version_info, (void) ); +_PROTOTYPE( void help_page, (void) ); + +#if EXTRA_SYMBOLS +/* gnu_sym.c */ +_PROTOTYPE( void gnu_init, (char *filename) ); +_PROTOTYPE( long gnu_symbolvalue, (char *name, int is_text ) ); +_PROTOTYPE( void gnu_symbolic, (off_t value, int separator) ); +_PROTOTYPE( void gnu_listsym, (int tchar) ); +_PROTOTYPE( int gnu_text_symbol, (off_t value) ); +_PROTOTYPE( int gnu_finds_pc, (off_t pc) ); +_PROTOTYPE( int gnu_finds_data, (off_t off, int data_seg) ); +#endif /* EXTRA_SYMBOLS */ + +/* sym.c */ +_PROTOTYPE( void syminit, (char *filename) ); +_PROTOTYPE( long symbolvalue, (char *name, int is_text ) ); +_PROTOTYPE( void printhex, (off_t v) ); +_PROTOTYPE( void symbolic, (off_t value, int separator) ); +_PROTOTYPE( void listsym, (char *cmd) ); +_PROTOTYPE( int text_symbol, (off_t value) ); +_PROTOTYPE( int finds_pc, (off_t pc) ); +_PROTOTYPE( int finds_data, (off_t off, int data_seg) ); + +/* trace.c */ +_PROTOTYPE( long mdbtrace, (int req, int pid, long addr, long data) ); +_PROTOTYPE( u32_t peek_dword, (off_t addr)); + +#if SYSCALLS_SUPPORT + +/* syscalls.c */ +_PROTOTYPE( void start_syscall, (long addr) ); +_PROTOTYPE( void do_syscall, (long addr) ); + +/* decode.c */ +_PROTOTYPE( void decode_message, (unsigned addr) ); +_PROTOTYPE( void decode_result, (void) ); + +/* ioctl.c */ +_PROTOTYPE( void decode_ioctl, (int sr, message *m) ); + +#endif /* SYSCALLS_SUPPORT */ diff --git a/commands/mdb/ptrace.2 b/commands/mdb/ptrace.2 new file mode 100644 index 000000000..4c3e1b6c0 --- /dev/null +++ b/commands/mdb/ptrace.2 @@ -0,0 +1,87 @@ +.TH PTRACE 2 +.SH NAME +ptrace \- ptrace system call. +.SH SYNOPSIS +.ft B +.nf +.sp +#include + +long ptrace( int req, pid_t pid, long addr, long data) + +.fi +.ft P +.SH DESCRIPTION +.sp +Ptrace(2) is called with following arguments: +.sp +.br +req +request +.br +pid +process id +.br +addr +address +.br +data +data +.br +.SH REQUESTS +.sp +.I +T_STOP +stop the process. +.br +.I +T_OK +enable tracing by parent for this process. +.br +.I +T_GETINS +return value from instruction space +.br +.I +T_GETDATA +return value from data space. +.br +.I +T_GETUSER +return value from process table. See proc.h in kernel. +.br +.I +T_SETINS +set value from instruction space. +.br +.I +T_SETDATA +set value from data space. +.br +.I +T_SETUSER +set value in process table. +.br +.I +T_RESUME +resume execution. +.br +.I +T_EXIT +exit. Turn off tracing. +.br +.I +T_STEP +set trace bit to enable single step. +.SH "SEE ALSO" +.sp +mdb(1) +.SH DIAGNOSTICS +.sp +errno is set by ptrace(). +.SH FILES +.sp +/usr/src/kernel/proc.h for process table info. + + + diff --git a/commands/mdb/sample b/commands/mdb/sample new file mode 100644 index 000000000..b04edf9e1 --- /dev/null +++ b/commands/mdb/sample @@ -0,0 +1,9 @@ +r 10 +y +__sendrec b +B +c +x 2 +t +q + diff --git a/commands/mdb/sym.c b/commands/mdb/sym.c new file mode 100644 index 000000000..32a7390ef --- /dev/null +++ b/commands/mdb/sym.c @@ -0,0 +1,546 @@ +/* + * sym.c for mdb + */ + +#include "mdb.h" +#include +#include +#include +#include +#include +#include +#include "proto.h" + +#if GNU_SUPPORT +#define ZMAGIC 0413 +#define NMAGIC 0410 +#define QMAGIC 0314 +#endif + +struct symtab_s +{ + struct nlist *start; + struct nlist *end; + int text; + int data; + unsigned nsym; +}; + +PRIVATE struct symtab_s symtab; +PRIVATE int type_of_exec; + +FORWARD _PROTOTYPE( int check_exec, (struct exec *hdr) ); +FORWARD _PROTOTYPE( void sortsyms , (struct nlist *array , struct nlist *top )); +FORWARD _PROTOTYPE( int symeq , (char *t , struct nlist *sp )); +FORWARD _PROTOTYPE( int symprefix , (char *t , struct nlist *sp )); +FORWARD _PROTOTYPE( struct nlist *findsname, (char *name, int is_text, int allflag) ); +FORWARD _PROTOTYPE( void outsym, (struct nlist *sp, off_t off) ); +FORWARD _PROTOTYPE( struct nlist *findsval, (off_t value, int where) ); + +PUBLIC void syminit( filename ) +char *filename; +{ + int fd; + struct exec header; + register struct symtab_s *tp; + + tp = &symtab; + if ( (fd = open( filename, O_RDONLY)) < 0) { + fprintf(stderr, "Couldn't open %s.\n", filename); + perror(filename); + exit(1); + } + + if( read( fd, (char *) &header, sizeof header ) != sizeof header ) + { + fprintf(stderr, "Couldn't read %d bytes from %s.\n", sizeof(header), filename); + close( fd ); + exit(1); + } + type_of_exec = check_exec(&header); + +#if EXTRA_SYMBOLS + if ( type_of_exec == GNU_SYMBOLS) { + close(fd); + gnu_init(filename); + return; + } +#endif + + /* For MINIX EXEC */ + if ( lseek( fd, A_SYMPOS( header ), 0 ) != A_SYMPOS( header ) ) + { + do_error( "mdb - reading header" ); + close( fd ); + exit(1); + } + if ( (int) header.a_syms < 0 || + (unsigned) header.a_syms != header.a_syms || + (tp->start = (struct nlist *) malloc( (unsigned) header.a_syms )) + == (struct nlist *) NULL && + header.a_syms != 0 ) + { + Printf("mdb: no room for symbol table" ); + close( fd ); + return; + } + if ( read( fd, (char *) tp->start, (int) header.a_syms ) < 0 ) + { + do_error( "mdb - reading symbol table" ); + close( fd ); + return; + } + close( fd ); + tp->nsym = (unsigned) header.a_syms / sizeof (struct nlist); + tp->end = tp->start + tp->nsym; + tp->text = 0x07; + tp->data = 0x0F; + + /* sort on value only, name search not used much and storage a problem */ + Printf("Sorting %d MINIX symbols ....", tp->nsym ); + sortsyms( tp->start, tp->end ); + Printf("\n"); +} + +/* Check exec file + * return type of exec + * or exit + */ +PRIVATE int check_exec(hdr) +struct exec *hdr; +{ +long magic; + + /* Check MAGIC number */ + if (hdr->a_magic[0] != A_MAGIC0 || hdr->a_magic[1] != A_MAGIC1) { +#if GNU_SUPPORT + memcpy(&magic, hdr, sizeof(long)); + /* Clear bits */ + magic &= 0xFFFF; + + if ( magic == ZMAGIC || magic == QMAGIC ) { + is_separate = FALSE; + return GNU_SYMBOLS; + } + if ( magic == NMAGIC ) { + is_separate = TRUE; + return GNU_SYMBOLS; + } +#endif + Printf("mdb: invalid magic number in exec header - %02x %02x\n", + hdr->a_magic[0], + hdr->a_magic[1]); + exit(1); + } + + /* Check CPU */ +#if (CHIP == INTEL) +#if (_WORD_SIZE == 4) + if (hdr->a_cpu != A_I80386) +#else + if (hdr->a_cpu != A_I8086) +#endif +#endif +#if (CHIP == M68000) + if (hdr->a_cpu != A_M68K) +#endif + { + Printf("mdb: invalid cpu in exec header - %04x\n", + hdr->a_cpu); + exit(1); + } + + is_separate = FALSE; +#ifdef MINIX_PC + if (hdr->a_flags & A_SEP) + is_separate = TRUE; +#endif +/* + * A_EXEC is not being set by current cc + * It was set in Minix 1.5.0 + */ +#if 0 + /* Check flags - separate I & D or not */ + if (hdr->a_flags & A_EXEC) + is_separate = FALSE; + else { + Printf("mdb: object file not exec %04x\n", + hdr->a_flags); + exit(1); + } +#endif + return MINIX_SYMBOLS; +} + + +PUBLIC long symbolvalue( name, is_text ) +char *name; +int is_text; +{ +register struct nlist *sp; + +#if EXTRA_SYMBOLS + if ( type_of_exec == GNU_SYMBOLS ) + return gnu_symbolvalue( name, is_text ); +#endif + + /* For MINIX EXEC */ + sp = findsname(name, is_text, 0); + if (sp != NULL) + return sp->n_value; + else + return 0L; +} + +PRIVATE struct nlist *findsname( name, is_text, allflag ) +char *name; +int is_text; +int allflag; +{ + char *s; + unsigned char sclass; + int schar; + char *send; + register struct nlist *sp; + register struct symtab_s *tp; + + tp = &symtab; + if ( allflag ) + { + /* find and print all matching symbols */ + for ( sp = tp->start; sp < tp->end; ++sp ) + { + if ( symprefix( name, sp ) ) + { + sp = sp; + for ( s = sp->n_name, send = s + sizeof sp->n_name; + *s != 0 && s < send; ++s ) + outbyte( *s ); + for ( ; s <= send; ++s ) + outspace(); + switch( sp->n_sclass & N_SECT ) + { + case N_ABS: schar = 'a'; break; + case N_TEXT: schar = 't'; break; + case N_DATA: schar = 'd'; break; + case N_BSS: schar = 'b'; break; + default: schar = '?'; break; + } + if ( (sp->n_sclass & N_CLASS) == C_EXT && schar != '?' ) + schar += 'A' - 'a'; + outbyte( schar ); + outspace(); +#if (_WORD_SIZE == 2) + outh16( (u16_t) sp->n_value ); +#else + outh32( sp->n_value ); +#endif + outbyte('\n'); + } + } + } + else + { + /* find symbol by dumb linear search */ + for ( sp = tp->start; sp < tp->end; ++sp ) + { + sclass = sp->n_sclass & N_SECT; + if ( (is_text && sclass == N_TEXT || + !is_text && (sclass == N_DATA || sclass == N_BSS)) && + symeq( name, sp ) ) + return sp; + } + } + return NULL; +} + +PRIVATE struct nlist *findsval( value, where ) +off_t value; +int where; +{ + int left; + int middle; + int right; + unsigned char sclass; + register struct nlist *sp; + register struct symtab_s *tp; + + tp = &symtab; + + /* find last symbol with value <= desired one by binary search */ + for ( left = 0, right = tp->nsym - 1; left <= right; ) + { + middle = (left + right) / 2; + sp = tp->start + middle; + if ( value < sp->n_value ) + right = middle - 1; + else + left = middle + 1; + } + if ( right >= 0 ) + /* otherwise tp->start + right may wrap around to > tp->start !! */ + for ( sp = tp->start + right; sp >= tp->start; --sp ) + { + if ( (sp->n_sclass & N_CLASS) != C_EXT ) continue; + sclass = sp->n_sclass & N_SECT; + if ( (where == CSEG && sclass == N_TEXT || + where != CSEG && (sclass == N_DATA || sclass == N_BSS)) ) + return sp; + } + return NULL; +} + + +PUBLIC void printhex(v) +off_t v; +{ + if ( v >= 65536L ) + outh32( v ); + else if ( v >= 256 ) + outh16( (u16_t) v ); + else + outh8( (u8_t) v ); +} + + +PRIVATE void outsym( sp, off ) +struct nlist *sp; +off_t off; +{ + register char *s; + char *send; + + for ( s = sp->n_name, send = s + sizeof sp->n_name; *s != 0 && s < send; ++s ) + outbyte( *s ); + if ( (off -= sp->n_value) != 0 ) + { + outbyte( '+' ); + printhex(off); + } +} + +/* shell sort symbols on value */ + +PRIVATE void sortsyms( array, top ) +struct nlist *array; +struct nlist *top; +{ + int gap; + int i; + int j; + register struct nlist *left; + register struct nlist *right; + struct nlist swaptemp; + int size; + + size = top - array; + /* choose gaps according to Knuth V3 p95 */ + for ( gap = 1, i = 4; (j = 3 * i + 1) < size; gap = i, i = j ) + ; + do + { + for ( j = gap; j < size; ++j ) + for ( i = j - gap; i >= 0; i -= gap ) + { + left = array + i; + right = array + (i + gap); + if ( (off_t) left->n_value <= + right->n_value ) + break; + swaptemp = *left; + *left = *right; + *right = swaptemp; + } + } + while ( (gap /= 3) != 0 ); +} + +PUBLIC void symbolic( value, separator ) +off_t value; +int separator; +{ + register struct nlist *sp; + long off; + +#if EXTRA_SYMBOLS + if ( type_of_exec == GNU_SYMBOLS ) { + gnu_symbolic( value, separator ); + return; + } +#endif + + /* For MINIX EXEC */ + + if (value < st_addr || value > end_addr) { + outstr("0x"); + printhex(value); + outbyte(separator); + return; + } + + if ( (sp = findsval( value, CSEG )) != NULL ) + { + outsym( sp, value ); + } + else if ( (sp = findsval( value, DSEG )) != NULL ) + { + outsym( sp, value ); + } + else + { + outstr("_start"); + off = value - st_addr; + if ( off != 0 ) + { + outbyte( '+' ); + printhex(off); + } + } + outbyte( separator ); +} + + +PRIVATE int symeq( t, sp ) +register char *t; +struct nlist *sp; +{ + return strncmp( t, sp->n_name, sizeof sp->n_name ) == 0; +} + +PRIVATE int symprefix( t, sp ) +register char *t; +struct nlist *sp; +{ + register char *s; + char *send; + + for ( ; *t == '_'; ++t ) + ; + for ( s = sp->n_name, send = s + sizeof sp->n_name; + s < send && *s == '_'; ++s ) + ; + return strncmp( s, t, (size_t)(send - s) ) == 0; +} + + + +/* list all symbols - test for selection criteria */ + +PUBLIC void listsym(cmd) +char *cmd; +{ + register struct symtab_s *tp; + register struct nlist *sp; + char *s; + char *send; + char schar; + char tchar; + + /* set selection */ + cmd = skip(cmd+1); + if( *cmd == '\n' || *cmd == ';' ) + tchar = '*'; + else + tchar = *cmd; + +#if EXTRA_SYMBOLS + if ( type_of_exec == GNU_SYMBOLS ) { + gnu_listsym(tchar); + return; + } +#endif + + /* For MINIX EXEC */ + + tp = &symtab; + for ( sp = tp->start; sp < tp->end; ++sp ) + { + switch( sp->n_sclass & N_SECT ) + { + case N_ABS: schar = 'a'; break; + case N_TEXT: schar = 't'; break; + case N_DATA: schar = 'd'; break; + case N_BSS: schar = 'b'; break; + default: schar = '?'; break; + } + + if ( (sp->n_sclass & N_CLASS) == C_EXT && schar != '?' ) + schar += 'A' - 'a'; + + /* check for selection */ + if ( tchar != '*' && schar != tchar) + continue; + + /* print symbol type and value */ + for ( s = sp->n_name, send = s + sizeof sp->n_name; + *s != 0 && s < send; ++s ) outbyte( *s ); + for ( ; s <= send; ++s ) outspace(); + outbyte( schar ); + outspace(); +#if (_WORD_SIZE == 2) + outh16( (u16_t) sp->n_value ); +#else + outh32( sp->n_value ); +#endif + outbyte('\n'); + } +} + + +PUBLIC int text_symbol(value) +off_t value; +{ +struct nlist *sp; + +#if EXTRA_SYMBOLS + if ( type_of_exec == GNU_SYMBOLS ) + return gnu_text_symbol(value); +#endif + + if ((sp = findsval(value, CSEG)) != NULL && sp->n_value == value) + { + outsym(sp, value); + return TRUE; + } + else + return FALSE; +} + +PUBLIC int finds_data(off,data_seg) +off_t off; +int data_seg; +{ +struct nlist *sp; + +#if EXTRA_SYMBOLS + if ( type_of_exec == GNU_SYMBOLS ) + return gnu_finds_data(off,data_seg); +#endif + + if ((sp = findsval(off, data_seg)) != NULL) + { + outsym(sp, off); + return TRUE; + } + else + return FALSE; +} + +PUBLIC int finds_pc(pc) +off_t pc; +{ +struct nlist *sp; + +#if EXTRA_SYMBOLS + if ( type_of_exec == GNU_SYMBOLS ) + return gnu_finds_pc(pc); +#endif + + if ((sp = findsval(pc, CSEG)) != NULL) + { + outsym(sp, pc); + return TRUE; + } + else + return FALSE; +} diff --git a/commands/mdb/syscalls.c b/commands/mdb/syscalls.c new file mode 100644 index 000000000..89862c1a7 --- /dev/null +++ b/commands/mdb/syscalls.c @@ -0,0 +1,85 @@ +/* + * syscall.c for mdb + */ +#include "mdb.h" +#ifdef SYSCALLS_SUPPORT +#include +#include +#include +#include "proto.h" + +#define SYSCALL_NAME "__sendrec" +#ifdef __i386 +#define SYSCALL_OFFSET 0xF +#define SYSCALL_OLD 0x21CD +#else +#define SYSCALL_OFFSET 0xE +#define SYSCALL_OLD 0x20CD +#endif + +PRIVATE long intaddr; + +PUBLIC void start_syscall(addr) +long addr; +{ +long old; + + syscalls = FALSE; + + if ( addr == 0 ) { + intaddr = symbolvalue( SYSCALL_NAME, TRUE ); + if ( intaddr == 0 ) + return; + intaddr += SYSCALL_OFFSET; + } + else { + intaddr = addr; + Printf("Using %lx as syscall address\n",addr); + } + + old = breakpt(intaddr,"\n"); + + /* Check instruction */ + if ( (old & 0xFFFF) == SYSCALL_OLD) + syscalls = TRUE; + +} + +PUBLIC void do_syscall(addr) +long addr; +{ + unsigned reg_ax,reg_bx; + + if ( addr != intaddr ) return; + + Printf("syscall to "); + + reg_ax = get_reg(curpid,reg_addr("AX")); + + switch (reg_ax) { + case 0: Printf(" MM "); + break; + case 1: Printf(" FS "); + break; + case 2: Printf(" INET "); + break; + default: Printf("Invalid dest = %d", reg_ax); + exit(0); + } + + + reg_bx = get_reg(curpid,reg_addr("BX")); + decode_message(reg_bx); + + /* Single step */ + tstart(T_STEP, 0, 0, 1); + + /* Check return code */ + reg_ax = get_reg(curpid,reg_addr("AX")); + if ( reg_ax != 0 ) + Printf("syscall failed AX=%d\n",reg_ax); + else + decode_result(); +} + +#endif /* SYSCALLS_SUPPORT */ diff --git a/commands/mdb/trace.c b/commands/mdb/trace.c new file mode 100644 index 000000000..66aae9299 --- /dev/null +++ b/commands/mdb/trace.c @@ -0,0 +1,51 @@ +/* + * trace.c for mdb + */ + +#include "mdb.h" +#include +#include +#include "proto.h" + +/* mdbtrace() + * Call ptrace and check for error if debugging running process + * Otherwise read 'core' file + */ +PUBLIC long mdbtrace(req, pid, addr, data) +int req, pid; +long addr, data; +{ + long val; + int i; + int segment; + +#ifdef DEBUG + if (debug) Printf("ptrace: req=%d pid=%d addr=%lx data=%lx\n", + req, pid, addr, data); +#endif + + if (corepid < 0) + { + errno = 0; + /* Call normal ptrace and check for error */ + val = ptrace(req, pid, addr, data); + if (errno != 0) { + do_error("mdb ptrace error "); + mdb_error("\n"); + } +#ifdef DEBUG + if (debug) Printf("ptrace: val=>%lx\n", val); +#endif + return val; + } + else + return read_core(req, addr, data); +} + +/* Used by disassembler */ +PUBLIC u32_t peek_dword(addr) +off_t addr; +{ + return mdbtrace(T_GETINS, curpid, addr, 0L); +} + -- 2.44.0