import of mdb (minix debugger), some ptrace and signals unbreaking
seem to have made it work (runtime debugging and core reading).
This commit is contained in:
parent
693c7abe2a
commit
5e3b213f05
25 changed files with 6673 additions and 0 deletions
|
@ -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) $@
|
||||
|
|
38
commands/mdb/Dist
Normal file
38
commands/mdb/Dist
Normal file
|
@ -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
|
||||
|
25
commands/mdb/MDB.TXT
Normal file
25
commands/mdb/MDB.TXT
Normal file
|
@ -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
|
||||
|
130
commands/mdb/Makefile
Normal file
130
commands/mdb/Makefile
Normal file
|
@ -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
|
||||
|
32
commands/mdb/README
Normal file
32
commands/mdb/README
Normal file
|
@ -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
|
||||
|
||||
|
297
commands/mdb/a.out.h
Normal file
297
commands/mdb/a.out.h
Normal file
|
@ -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__ */
|
394
commands/mdb/core.c
Normal file
394
commands/mdb/core.c
Normal file
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* core.c for mdb
|
||||
*
|
||||
* reads information from 'core' file
|
||||
* Partly derived from 'adb' by D. Dugger.
|
||||
*/
|
||||
#include <pm/const.h>
|
||||
|
||||
#include "mdb.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include <pm/type.h>
|
||||
#include <pm/mproc.h>
|
||||
|
||||
#include <kernel/const.h>
|
||||
#include <kernel/type.h>
|
||||
#include <kernel/proc.h>
|
||||
|
||||
/* 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");
|
||||
}
|
||||
}
|
||||
|
360
commands/mdb/decode.c
Normal file
360
commands/mdb/decode.c
Normal file
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
* decode.c for mdb -- decodes a Minix system call
|
||||
*/
|
||||
#include "mdb.h"
|
||||
#ifdef SYSCALLS_SUPPORT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#define ptrace mdbtrace
|
||||
#include <sys/ptrace.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/callnr.h>
|
||||
#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 */
|
76
commands/mdb/gnu_load.c
Normal file
76
commands/mdb/gnu_load.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* gnu_load for mdb.c
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <gnu/a.out.h>
|
||||
|
||||
_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;
|
||||
}
|
365
commands/mdb/gnu_sym.c
Normal file
365
commands/mdb/gnu_sym.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#if GNU_SUPPORT
|
||||
#include <gnu/a.out.h>
|
||||
#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 */
|
303
commands/mdb/io.c
Normal file
303
commands/mdb/io.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* io.c for mdb
|
||||
* all the i/o is here
|
||||
* NB: Printf()
|
||||
*/
|
||||
#include "mdb.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#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;
|
||||
}
|
||||
|
146
commands/mdb/ioctl.c
Normal file
146
commands/mdb/ioctl.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* ioctl.c for mdb -- decode an IOCTL system call
|
||||
*/
|
||||
#include "mdb.h"
|
||||
#ifdef SYSCALLS_SUPPORT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/callnr.h>
|
||||
#include <minix/com.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sgtty.h>
|
||||
#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 */
|
249
commands/mdb/kernel.c
Normal file
249
commands/mdb/kernel.c
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* kernel.c for mdb
|
||||
*/
|
||||
|
||||
#include "mdb.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define ptrace mdbtrace
|
||||
#include <sys/ptrace.h>
|
||||
#include "proto.h"
|
||||
|
||||
#include <kernel/const.h>
|
||||
#include <kernel/type.h>
|
||||
#include <kernel/proc.h>
|
||||
|
||||
/* 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
|
154
commands/mdb/mdb.1
Normal file
154
commands/mdb/mdb.1
Normal file
|
@ -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
|
1028
commands/mdb/mdb.c
Normal file
1028
commands/mdb/mdb.c
Normal file
File diff suppressed because it is too large
Load diff
182
commands/mdb/mdb.h
Normal file
182
commands/mdb/mdb.h
Normal file
|
@ -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 <minix/config.h>
|
||||
#include <ansi.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <minix/const.h>
|
||||
#include <minix/type.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <minix/ipc.h>
|
||||
#include <timers.h>
|
||||
|
||||
#undef printf /* defined as printk in <minix/const.h> */
|
||||
|
||||
#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
|
||||
|
1564
commands/mdb/mdbdis86.c
Normal file
1564
commands/mdb/mdbdis86.c
Normal file
File diff suppressed because it is too large
Load diff
157
commands/mdb/mdbexp.c
Normal file
157
commands/mdb/mdbexp.c
Normal file
|
@ -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 <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
|
289
commands/mdb/misc.c
Normal file
289
commands/mdb/misc.c
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* misc.c for mdb
|
||||
*/
|
||||
|
||||
#include "mdb.h"
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#define ptrace mdbtrace
|
||||
#include <sys/ptrace.h>
|
||||
#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("<address> /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("# <address> 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("<address> M t n\t- Trace until\n");
|
||||
else
|
||||
outstr("<address> m t n\t- Stop when\n");
|
||||
outstr("\t\t<address> 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("<address> 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("<address> 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("<address> X [n] [offset]\t- Disasm for n instructions\n");
|
||||
outstr("\t\t\t Starting at address+offset\n");
|
||||
break;
|
||||
case 'x':
|
||||
outstr("<address> 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;
|
||||
}
|
||||
}
|
||||
|
105
commands/mdb/proto.h
Normal file
105
commands/mdb/proto.h
Normal file
|
@ -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 */
|
87
commands/mdb/ptrace.2
Normal file
87
commands/mdb/ptrace.2
Normal file
|
@ -0,0 +1,87 @@
|
|||
.TH PTRACE 2
|
||||
.SH NAME
|
||||
ptrace \- ptrace system call.
|
||||
.SH SYNOPSIS
|
||||
.ft B
|
||||
.nf
|
||||
.sp
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
9
commands/mdb/sample
Normal file
9
commands/mdb/sample
Normal file
|
@ -0,0 +1,9 @@
|
|||
r 10
|
||||
y
|
||||
__sendrec b
|
||||
B
|
||||
c
|
||||
x 2
|
||||
t
|
||||
q
|
||||
|
546
commands/mdb/sym.c
Normal file
546
commands/mdb/sym.c
Normal file
|
@ -0,0 +1,546 @@
|
|||
/*
|
||||
* sym.c for mdb
|
||||
*/
|
||||
|
||||
#include "mdb.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <a.out.h>
|
||||
#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;
|
||||
}
|
85
commands/mdb/syscalls.c
Normal file
85
commands/mdb/syscalls.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* syscall.c for mdb
|
||||
*/
|
||||
#include "mdb.h"
|
||||
#ifdef SYSCALLS_SUPPORT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ptrace.h>
|
||||
#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 */
|
51
commands/mdb/trace.c
Normal file
51
commands/mdb/trace.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* trace.c for mdb
|
||||
*/
|
||||
|
||||
#include "mdb.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/ptrace.h>
|
||||
#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);
|
||||
}
|
||||
|
Loading…
Reference in a new issue