bds@lzaz.ATT.COM (B.SZABLAK) (03/30/89)
>mdb ( on minix-st only ) disassembles the instructions b??.s wrong: >It thinks always the long (medium ?) form is used. >Patch, compile, and this works. >(but there are some more bugs -- i will try to fix ) >Klamer Schutte (.signature at end) Thanks for the fix! Here is an updated version of mdb which is ATARI specific but might be a good start for some PC enthusiast. Note: requires the ptrace system call. ------------------------------------cut here---------------------------------- echo x - mdb.1 gres '^X' '' > mdb.1 << '/' XCOMMAND X mdb(1) - MINIX Debugger X XINVOCATION X mdb [<executable> [<link file>]] X XEXPLANATION X Mdb provides a means of debugging minix programs. It supports symbolic X debugging if a "link file" exists; the link file is the output of the X ACK linker: ld. The arguments to mdb are: X X <executable> - The MINIX executable file. Defaults to "a.out". X <link file> - The MINIX link file. Defaults to none. X X Once started, mdb will display a command prompt: '*'. A command may X be entered in the following form: X X [<expression>][<command> [<argument>]] X X <expression> is a symbolic expression representing a location X in memory or a register, and should be in the form: X X [<value> [+|- <value>]] X X A <value> may be a symbol, a register, or a constant. X The symbol may be any external symbol found in the link file, or "_start" X if no link file is specified. "_start" represents the beginning address X of the program. A register is specified by a '$' followed by the X register's name, while a constant may be either an octal, decimal or hex X unsigned long integer expressed using standard C notation (no 'L' suffix X should be used). A character constant is represented by a single quote X followed by the character. X X Not all commands use an address, but those that do have a default X value of the current program counter with the exception of the continue X command: 'c' and 'C'. Not all commands use an argument X list, but those that do default to an empty list. If the argument X contains a semi-colon (';'), then except for the breakpoint X command ('b') the string following the semi-colon is assumed to be a X new command. X X Following is the list of valid commands. When mdb is first started, X no process is active. Most of the following commands require an active X process which may be created using the run ('r') command. X X ! - If the exclaimation point begins the command line then the X MINIX program that follows it is executed. The default X command is "/bin/sh". Note: full path names are required. X X Example: * !vi mdb.c X X If the expression preceeding the exclaimation point is a X valid data address, then the arguments specify how to modify X its contents. The argument is to be in the form: X [<constant>] [<size>] [<expression>] X and are interpreted as: "fill the data space starting at the X specified address with <constant> values given by <expression> X and are of size byte ('b'), half word ('h', i.e. short), X or long word ('l')." The default value of constant is 1, of X size is 'h', and of expression is 0. X X Example: * _buf ! 20b 'a X X T - This command prints the current active function in the program with X its arguments. X X Example: * T X X t - This command prints the current function invocation X heirarchy with their arguments. X X Example: * t X X / - This command prints the values starting at the address X specified. The argument is to be in the form: X [<constant>][<size>][<format>] X format may have the values: X a - Displays characters until a zero value is found X (<constant> and <size> are ignored). X c - Displays <constant> values as characters. X d - Displays <constant> values as signed decimal numbers. X i - Disassembles <constant> instructions (<size> ignored). X I - Disassembles <constant> instructions (<size> ignored). X o - Displays <constant> vlaues as octal numbers. X s - Displays characters until a zero value is found X starting at the address contained at the location X specified (<constant> and <size> are ignored). X u - Displays <constant> vlaues as unsigned decimal numbers. X x - Displays <constant> vlaues as hexadecimal numbers. X X Example: * $a6-2/hx X X x - This command prints the registers and the instructions X starting at the specified address. An optional constant X argument limits the number of instructions printed. X X Example: * x X X X - This command prints the instructions starting at the specified X address. An optional constant argument limits the number of X instructions printed. X X Example: * _start X 10 X X R - This command starts a process using the executable given X as mbd's first argument. The process will have no arguments X and will be stopped prior to executing any instructions. X X Example: * R X X r - This command starts a process using the executable given X as mbd's first argument. The process will be given the X arguments on the command line up to the first semi-colon. X If no arguments are specifed, then the arguments supplied X with the last 'r' command are used. The processes' standard X input and output may be redirected. The process will be X stopped prior to executing any instructions. X X Example: * r 3 <input >output X X C - This command results in the stopped process being restarted X with a pending signal specfied by the constant argument. X A breakpoint is placed at the address specified if one is X not already there, and if placed it is deleted when the X process stops for any reason. No default address is assumed. X X Example: * C 2 X X c - This command results in the stopped process being restarted X with all pending signals canceled. A breakpoint is placed X at the address specified if one is not already there, and X if placed it is deleted when the process stops for any reason. X No default address is assumed. X X Example: * _func+4 c X X I - This command results in the stopped process executing X instructions in single step mode. The number of instructions X executed is given in the constant argument. The signal X that stopped the process will be sent when execution begins. X X Example: * I 10 X X X i - This command results in the stopped process executing X instructions in single step mode. The number of instructions X executed is given in the constant argument. All pending X signals are canceled before execution begins. X X Example: * i 10 X X M - This command results in the stopped process resuming X execution until the long word at the location specified by the X address is modified or until the number of instructions X specified in the obtional constant argument are executed. X The default number is 65,536. Each executed instruction is X displayed prior to execution. X X Example: * _var M 100 X X m - This command results in the stopped process resuming X execution until the long word at the location specified by the X address is modified or until the number of instructions X specified in the obtional constant argument are executed. X The default number is 65,536. X X Example: * _var m X X k - This command results in the current active process being X terminated. X X Example: * k X X B - This command results in all the currently active breakpoints X being listed. X X Example: * B X X b - This command results in a breakpoint being placed at the X location specified by the address in program space. The X string that follows the command contains the command(s) that X are executed when the breakpoint is hit. It is recommended X that breakpoints be placed at an offset of 4 bytes from the X function entry point to permit a valid frame to be set up X for back-tracing. X X Example: * _func+4 b t;_var/lx X X d - This command results in the breakpoint at the address X specified being deleted. X X Example: * _func+4 d X X D - This command results in all breakpoints being deleted. X X Example: * D X X q - This command results in the currently active process being X terminated and mdb exiting. X X Example: * q X XRESULTS X Mdb's exit status is always zero. X XREFERENCES X ptrace(2) / echo x - user.h gres '^X' '' > user.h << '/' X#include "h/type.h" X#include "h/const.h" X#include "kernel/type.h" X#include "kernel/const.h" X#undef printf X Xstruct proc { X#ifdef i8088 X int p_reg[NR_REGS]; /* process' registers */ X#endif X#ifdef ATARI_ST X long p_reg[NR_REGS]; /* process' registers */ X#endif X int *p_sp; /* stack pointer */ X struct pc_psw p_pcpsw; /* pc and psw as pushed by interrupt */ X#ifdef i8088 X int *p_splimit; /* lowest legal stack value */ X#endif X#ifdef ATARI_ST X int *p_splow; /* lowest observed stack value */ X int p_trap; /* trap type (only low byte) */ X#endif X int p_flags; /* P_SLOT_FREE, SENDING, RECEIVING, etc. */ X struct mem_map p_map[NR_SEGS];/* memory map */ X#ifdef ATARI_ST X phys_clicks p_shadow; /* set if shadowed process image */ X int p_nflips; /* statistics */ X char p_physio; /* cannot be (un)shadowed now if set */ X#endif X int p_pid; /* process id passed in from MM */ X X real_time user_time; /* user time in ticks */ X real_time sys_time; /* sys time in ticks */ X real_time child_utime; /* cumulative user time of children */ X real_time child_stime; /* cumulative sys time of children */ X real_time p_alarm; /* time of next alarm in ticks, or 0 */ X X struct proc *p_callerq; /* head of list of procs wishing to send */ X struct proc *p_sendlink; /* link to next proc wishing to send */ X message *p_messbuf; /* pointer to message buffer */ X int p_getfrom; /* from whom does process want to receive? */ X X struct proc *p_nextready; /* pointer to next ready process */ X int p_pending; /* bit map for pending signals 1-16 */ X}; / echo x - strtol.c gres '^X' '' > strtol.c << '/' Xlong Xstrtol(s, p, base) X char *s, **p; X{ X long r; X int sign, digit, hexlow, hexup, c; X X r = 0L; X sign = 0; X while (*s == ' ' || *s == '\t') ++s; X if (*s == '-') X { X sign = 1; X ++s; X } X if (base == 0) X { X if (*s == '0') base = (s[1] == 'x' || s[1] == 'X') ? 16 : 8; X else base = 10; X } X if (*s == '0' && (s[1] == 'x' || s[1] == 'X') && base == 16) s += 2; X digit = (base <= 10) ? (base + '0' - 1) : '9'; X hexlow = 'a' + base - 10; X hexup = 'A' + base - 10; X for (c = *s ; ; c = *++s) X { X if (c >= '0' && c <= digit) c = c - '0'; X else if (c >= 'a' && c < hexlow) c = c - 'a' + 10; X else if (c >= 'A' && c < hexup) c = c - 'A' + 10; X else X { X if (p != 0) *p = s; X return sign ? -r : r; X } X r = r * base + c; X } X}/ echo x - makefile gres '^X' '' > makefile << '/' XCFLAGS=-DATARI_ST -I/usr/src -T/usr/tmp XOBJS=mdb.o mdbexp.o mdbdis.o strtol.o XLD=/usr/lib/ld XCV=/usr/lib/cv XLIB=/usr/lib/libc.a /usr/lib/end.o X Xmdb: $(OBJS) X $(LD) -o $*.out -c /usr/lib/crtso.o $(OBJS) $(LIB) X $(CV) $*.out $@ X chmem =10000 $@ / echo x - out.h gres '^X' '' > out.h << '/' X/* X * (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands. X * See the copyright notice in the file "../Copyright". X */ X/* X * output format for ACK assemblers X */ X#ifndef ushort X#define ushort unsigned short X#endif ushort X Xstruct outhead { X ushort oh_magic; /* magic number */ X ushort oh_stamp; /* version stamp */ X ushort oh_flags; /* several format flags */ X ushort oh_nsect; /* number of outsect structures */ X ushort oh_nrelo; /* number of outrelo structures */ X ushort oh_nname; /* number of outname structures */ X long oh_nemit; /* sum of all os_flen */ X long oh_nchar; /* size of string area */ X}; X X#define O_MAGIC 0x0201 /* magic number of output file */ X#define O_STAMP 0 /* version stamp */ X#define MAXSECT 64 /* Maximum number of sections */ X X#define HF_LINK 0x0004 /* unresolved references left */ X#define HF_8086 0x0008 /* os_base specially encoded */ X Xstruct outsect { X long os_base; /* startaddress in machine */ X long os_size; /* section size in machine */ X long os_foff; /* startaddress in file */ X long os_flen; /* section size in file */ X long os_lign; /* section alignment */ X}; X Xstruct outrelo { X char or_type; /* type of reference */ X char or_sect; /* referencing section */ X ushort or_nami; /* referenced symbol index */ X long or_addr; /* referencing address */ X}; X Xstruct outname { X union { X char *on_ptr; /* symbol name (in core) */ X long on_off; /* symbol name (in file) */ X } on_u; X#define on_mptr on_u.on_ptr X#define on_foff on_u.on_off X ushort on_type; /* symbol type */ X ushort on_desc; /* debug info */ X long on_valu; /* symbol value */ X}; X X/* X * relocation type bits X */ X#define RELSZ 0x07 /* relocation length */ X#define RELO1 1 /* 1 byte */ X#define RELO2 2 /* 2 bytes */ X#define RELO4 4 /* 4 bytes */ X#define RELPC 0x08 /* pc relative */ X#define RELBR 0x10 /* High order byte lowest address. */ X#define RELWR 0x20 /* High order word lowest address. */ X X/* X * section type bits and fields X */ X#define S_TYP 0x007F /* undefined, absolute or relative */ X#define S_EXT 0x0080 /* external flag */ X#define S_ETC 0x7F00 /* for symbolic debug, bypassing 'as' */ X X/* X * S_TYP field values X */ X#define S_UND 0x0000 /* undefined item */ X#define S_ABS 0x0001 /* absolute item */ X#define S_MIN 0x0002 /* first user section */ X#define S_MAX S_TYP /* last user section */ X X/* X * S_ETC field values X */ X#define S_SCT 0x0100 /* section names */ X#define S_LIN 0x0200 /* hll source line item */ X#define S_FIL 0x0300 /* hll source file item */ X#define S_MOD 0x0400 /* ass source file item */ X#define S_COM 0x1000 /* Common name. */ X X/* X * structure format strings X */ X#define SF_HEAD "22222244" X#define SF_SECT "44444" X#define SF_RELO "1124" X#define SF_NAME "4224" X X/* X * structure sizes (bytes in file; add digits in SF_*) X */ X#define SZ_HEAD 20 X#define SZ_SECT 20 X#define SZ_RELO 8 X#define SZ_NAME 12 X X/* X * file access macros X */ X#define BADMAGIC(x) ((x).oh_magic!=O_MAGIC) X#define OFF_SECT(x) SZ_HEAD X#define OFF_EMIT(x) (OFF_SECT(x) + ((long)(x).oh_nsect * SZ_SECT)) X#define OFF_RELO(x) (OFF_EMIT(x) + (x).oh_nemit) X#define OFF_NAME(x) (OFF_RELO(x) + ((long)(x).oh_nrelo * SZ_RELO)) X#define OFF_CHAR(x) (OFF_NAME(x) + ((long)(x).oh_nname * SZ_NAME)) /
bds@lzaz.ATT.COM (B.SZABLAK) (03/30/89)
/* * mdb.c - MINIX program debugger * * Written by Bruce D. Szablak * * This free software is provided for non-commerical use. No warrantee * of fitness for any use is implied. You get what you pay for. Anyone * may make modifications and distribute them, but please keep this header * in the distribution. */ #define T_OK 0 #define T_GETINS 1 #define T_GETDATA 2 #define T_GETUSER 3 #define T_SETINS 4 #define T_SETDATA 5 #define T_SETUSER 6 #define T_RESUME 7 #define T_EXIT 8 #define T_STEP 9 #include "stdio.h" #include "signal.h" #include "ctype.h" #include "setjmp.h" #include "user.h" #include "sgtty.h" struct proc *prc; #define BP_REG 14 #define MAXLINE 120 #define REG(r) ((long)&((struct proc *)0)->p_reg[r]) #define PC ((long)&((struct proc *)0)->p_pcpsw.pc) #define MAXB 10 #define MAXP 3 #define MAXARG 20 #define SIZ (1 + sizeof(struct proc)/sizeof(long)) #define MAXLINE 120 long ptrace(), strtol(), reg_addr(), lbuf[SIZ], saddr, eaddr, dasm(); int curpid, cursig; char *strcpy(), *prog, sbuf[MAXLINE], cbuf[MAXLINE], *cmd, *addr_to_name(), *getexp(), *cmdstart; jmp_buf mainlp; struct sgttyb in_gttyb, sv_gttyb; /* initial and saved */ struct tchars in_chars, sv_chars; extern errno; struct b_pnt { struct b_pnt *nxt, *prv; long addr; long oldval; char cmd[1]; } *b_head, *curpnt; cleanup() { curpid = 0; curpnt = 0; while (b_head) freepnt(b_head); } dowait() { int stat, ls, hs; while (wait(&stat) != curpid) {}; ls = stat & 0xFF; hs = (stat >> 8) & 0xFF; if (ls == 0) { if (hs != 127) printf("child exited with status %d\n", hs); cleanup(); return 0; } if (hs == 0) { printf("child terminated by signal %d\n", ls & 0x7F); if (ls & 0x80) printf("(core dumped)\n"); cleanup(); return 0; } return cursig = hs; } update(dotty) { int i; if (dotty) { ioctl(0, TIOCGETP, &sv_gttyb); ioctl(0, TIOCGETC, &sv_chars); ioctl(0, TIOCSETP, &in_gttyb); ioctl(0, TIOCSETC, &in_chars); } for (i = 0; i < (SIZ-1); i++) { lbuf[i] = ptrace(T_GETUSER, curpid, (long)(i*sizeof(long)),0L); } saddr = (long)prc->p_map[T].mem_vir << CLICK_SHIFT; eaddr = (long)(prc->p_map[D].mem_vir + prc->p_map[D].mem_len) << CLICK_SHIFT; } findbpnt(verbose) { for (curpnt = b_head; curpnt; curpnt = curpnt->nxt) { if (curpnt->addr == prc->p_pcpsw.pc) { ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); if (curpnt->cmd[0] != '\n') cmd = strcpy(cbuf, curpnt->cmd); else if (verbose) printf("Breakpoint hit.\n"); return; } } if (verbose) printf("Unknown breakpoint hit.\n"); } disp_regs() { int i; if (curpid <= 0) { printf("No active process.\n"); return 1; } printf("\npc=%lx psw=%x\n\n",(long)prc->p_pcpsw.pc, prc->p_pcpsw.psw); printf( " 0 1 2 3 4 5 6 7\nD"); for (i = 0; i < 8; i++) printf(" %08lx", prc->p_reg[i]); printf("\nA"); for (; i < NR_REGS; i++) printf(" %08lx", prc->p_reg[i]); printf(" %08lx\n\n", (long)prc->p_sp); return 0; } char * skip(s) register char *s; { while (isspace(*s)) ++s; return *s ? s : s-1; } endcmd() { while (*cmd != '\n' && *cmd != ';') ++cmd; } #define BREAK(l) (0xA0000000 | ((l) & 0xFFFF)) exebpnt(restart) { ptrace(T_STEP, curpid, 0L, (long)restart); if (dowait() == 0) return 1; ptrace(T_SETINS, curpid, curpnt->addr, BREAK(curpnt->oldval)); curpnt = 0; return 0; } tstart(req, verbose, val, cnt) { if (curpid == 0) { if (verbose) printf("No active process.\n"); return; } if (req == T_EXIT) { ptrace(T_EXIT, curpid, 0L, (long)val); dowait(); return; } if (cnt==0) cnt = 1; ioctl(0, TIOCSETP, &sv_gttyb); ioctl(0, TIOCSETC, &sv_chars); do { if (curpnt) { if (exebpnt(val)) return; if (req == T_RESUME) cnt++; val = 0; } else { ptrace(req, curpid, 0L, (long)val); if (dowait() == 0) return; val = 0; switch (cursig) { case SIGEMT: /* breakpoint */ update(0); findbpnt(cnt <= 1); break; case SIGTRAP: /* trace trap? */ if (req == T_STEP) break; default: /* signal */ val = cursig; break; } } } while (--cnt > 0); update(1); dasm((long)prc->p_pcpsw.pc, 1, 1); } catch(sig) { signal(sig, catch); if (sig == SIGINT || sig == SIGQUIT) return; tstart(T_EXIT, 0, sig, 0); exit(0); } run(name, argstr, tflg) char *name, *argstr; { int procid; if( (procid = fork()) == 0 ) { char *argv[MAXARG], *inf = 0, *outf = 0; int argc; if (tflg && ptrace(T_OK, 0, 0L, 0L) < 0) { perror("ptrace"); exit(127); } argv[0] = name; for (argc = 1; ; ) { argstr = skip(argstr); if (*argstr == '\n' || *argstr == ';') { extern char **environ; argv[argc] = 0; if (inf) freopen(inf, "r", stdin); if (outf) freopen(outf, "w", stdout); execve(name, argv, environ); perror("execv"); exit( 127 ); } if (*argstr == '<') inf = argstr+1; else if (*argstr == '>') outf = argstr+1; else if (argc == MAXARG) { printf("Too many arguments.\n"); exit(127); } else argv[argc++] = argstr; while (!isspace(*argstr)) argstr++; if (*argstr == '\n') argstr[1] = '\n', argstr[2] = 0; *argstr++ = 0; } } if (procid < 0) { printf("Fork failed.\n"); } return procid; } #define ADDQ(l) (((l >> 16) & 0xF13F) == 0x500F) #define ADDQ_CNT(l) ((((l >> 25) - 1) & 7) + 1) #define LEA(l) ((l >> 16) == 0x4FEF) #define LEA_DISP(l) ((long)(int)l) #define ADDA(l) ((int)(l >> 16) == 0xDFFC) backtrace(all) { char sep; long pc, bp, off, val, obp; if (curpid <= 0) { printf("No process.\n"); return; } pc = prc->p_pcpsw.pc; bp = prc->p_reg[BP_REG]; if (bp == 0) { printf("No active frame.\n"); return; } errno = 0; do { symbolic(pc, '('); pc = ptrace(T_GETDATA, curpid, bp+4, 0L); off = ptrace(T_GETDATA, curpid, pc, 0L); obp = bp; bp += 2*sizeof(val); if (ADDQ(off)) off = ADDQ_CNT(off) + bp; else if (LEA(off)) off = LEA_DISP(off) + bp; else if (ADDA(off)) off = ptrace(T_GETDATA, curpid, pc+2, 0L) + bp; else goto skiplp; for (;;) { if (errno) return; val = ptrace(T_GETDATA, curpid, bp, 0L) >> 16; printf("0x%04x", (int)val); bp += sizeof(int); if (bp >= off) break; putc(',', stdout); } skiplp: fputs(")\n", stdout); bp = ptrace(T_GETDATA, curpid, obp, 0L); } while (all && bp); } freepnt(pnt) struct b_pnt *pnt; { if (pnt->prv) pnt->prv->nxt = pnt->nxt; else b_head = pnt->nxt; if (pnt->nxt) pnt->nxt->prv = pnt->prv; if (curpid > 0) ptrace(T_SETINS, curpid, pnt->addr, pnt->oldval); free(pnt); if (pnt == curpnt) curpnt = 0; } breakpt(addr, cmd) long addr; char *cmd; { char *s; struct b_pnt *new, *malloc(); int lng; if (curpid <= 0) { printf("No active process.\n"); return; } for (new = b_head; new; new=new->nxt) if (new->addr == addr) { printf("Breakpoint already exists here.\n"); return; } new = malloc(sizeof(struct b_pnt) + strlen(cmd)); if (new == 0) { printf("No room.\n"); return; } new->nxt = b_head; new->prv = 0; if (b_head) b_head->prv = new; b_head = new; new->addr = addr; strcpy(new->cmd, cmd); new->oldval = ptrace(T_GETINS, curpid, addr, 0L); ptrace(T_SETINS, curpid, addr, BREAK(new->oldval)); if (ptrace(T_GETINS, curpid, addr, 0L) != BREAK(new->oldval)) { perror("Can't set breakpoint"); freepnt(new); } } modify(addr, cnt, verbose) long addr; { long curval, off; if (curpid == 0) { printf("No active process.\n"); return; } curval = ptrace(T_GETDATA, curpid, addr, 0L); ioctl(0, TIOCSETP, &sv_gttyb); ioctl(0, TIOCSETC, &sv_chars); do { if (cursig == SIGTRAP) cursig = 0; if (verbose) { off = ptrace(T_GETUSER, curpid, PC, 0L); dasm(off, 1, 0); } if (curpnt && exebpnt(cursig)) return; else { ptrace(T_STEP, curpid, addr, 0L); switch (dowait()) { case 0: return; case SIGEMT: update(0); findbpnt(0); break; } } if (curval != ptrace(T_GETDATA, curpid, addr, 0L)) { printf("Modification detected\n"); break; } } while (--cnt); update(1); dasm(prc->p_pcpsw.pc, 1, 1); return; } display(addr, req) long addr; { int count, size, out, shift; long val, msk; char fmt; if (curpid == 0) { printf("No active process\n"); return; } count = strtol(cmd, &cmd, 0); if (count == 0) count = 1; if (*cmd == 'i' || *cmd == 'I') { if (req == T_GETUSER) { printf("Can't disassemble a register's contents.\n"); longjmp(mainlp); } dasm(addr, count, *cmd == 'i'); return; } switch (*cmd++) { case 'b': size = sizeof(char); break; case 'h': size = sizeof(short); break; case 'l': size = sizeof(long); break; default : size = sizeof(int); --cmd; break; } switch (fmt = *cmd) { case 'c': count *= size; size = sizeof(char); break; case 's': addr = ptrace(req, curpid, addr, 0L); req = T_GETDATA; case 'a': size = sizeof(char); break; } out = 0; msk = size == sizeof(long) ? 0xFFFFFFFF : (1L << (8*size)) - 1; shift = 32 - 8*size; do { val = (ptrace(req, curpid, addr, 0L) >> shift) & msk; if (out == 0) printf("\n0x%08lx: ", addr); switch (fmt) { case 'c': printf(isprint(val) ? " %c " : "\\%03o ", (char)val); if (++out == 8) out = 0; break; case 'u': printf("%12lu ", val); if (++out == 4) out = 0; break; case 'x': printf("%*lx ", 2*size, val); if (++out == (size == 4 ? 4 : 8)) out = 0; break; case 'o': printf("%*lo ", 3*size, val); if (++out == (size == 4 ? 4 : 8)) out = 0; break; case 's': case 'a': if (val) fputc((char)val, stdout); else goto exitlp; if (++out == 64) out = 0; break; default: case 'd': printf("%12ld ", val); if (++out == 4) out = 0; break; } addr += size; } while (--count > 0 || fmt == 's' || fmt == 'a'); exitlp: fputc('\n', stdout); } fill(addr, req) long addr; { int count, size, shift, seg; long val, msk, nval; char fmt; if (curpid == 0) { printf("No active process\n"); return; } count = strtol(cmd, &cmd, 0); switch (*cmd++) { case 'b': size = sizeof(char); break; case 'h': size = sizeof(short); break; case 'l': size = sizeof(long); break; default : size = sizeof(int); --cmd; break; } shift = 32 - 8*size; msk = (0x80000000 >> 8*size); cmd = getexp(cmd, &nval, &seg); nval <<= shift; do { val = ptrace(req, curpid, addr, 0L) | (nval & msk); val &= (nval | ~msk); ptrace(req+3, curpid, addr, val); addr += size; } while (--count>0); } command(savestr) char *savestr; { char c, *p; int i, seg; long exp; struct b_pnt *bp; seg = S; /* don't restrict segment expressions are in */ cmdstart = cmd = skip(cmd); cmd = getexp(cmd, &exp, &seg); if (exp == 0) { seg = T; exp = prc->p_pcpsw.pc; } switch (c = *cmd++) { case '!': /* escape to shell OR set variable to value */ if (cmd == cmdstart+1) { cmd = skip(cmd); if (*cmd == '\n' || *cmd == ';') { i = run("/bin/sh", "\n", 0); } else { for (p=cmd+1; *p && !isspace(*p); p++) {}; *p++ = 0; i = run(cmd, *p ? p : "\n", 0); } if (i > 0) while (wait(&seg) != i) {}; break; } if (seg == 'T') { printf("Can only modify data variables.\n"); break; } fill(exp, T_GETDATA); break; case 'T': /* top line of backtrace */ backtrace(0); break; case 't': /* back trace */ backtrace(1); break; case '/': /* print variable value */ display(exp, T_GETDATA); break; case 'x': /* print registers and instruction */ if (disp_regs()) break; /*FALLTHROUGH*/ case 'X': /* print instruction */ i = strtol(cmd, &cmd, 0); if (curpid > 0) dasm(exp, i ? i : 1, 1); else printf("No active process.\n"); break; case 'R': /* run program with no args */ case 'r': /* run program with args (possibly defaulted) */ tstart(T_EXIT, 0, 0, 0); if (c == 'r') { cmd = skip(cmd); if (*cmd == '\n' || *cmd == ';') cmd = sbuf; else strcpy(sbuf, cmd); } else { cmd = "\n"; } if (curpid = run(prog, cmd, 1)) { if (dowait()) { ptrace(T_SETUSER, curpid, REG(BP_REG), 0L); update(1); printf("Process stopped.\n"); } } break; case 'c': /* continue program - ignore signal */ cursig = 0; case 'C': /* continue program - handle signal */ i = 0; if (seg == T && curpnt == 0 && cmd != cmdstart+1) { breakpt(exp, "\n"); curpnt = b_head; ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); i = 1; } tstart(T_RESUME, 1, cursig, (int)strtol(cmd, &cmd, 0)); if (i) /* remove temporary bp */ { freepnt(b_head); } if (cursig == SIGEMT) return; if (curpid) printf("Process stopped by signal %d\n", cursig); break; case 'i': /* single step - ignore signal */ tstart(T_STEP, 1, 0, (int)strtol(cmd, &cmd, 0)); break; case 'I': /* single step - handle signal */ tstart(T_STEP, 1, cursig, (int)strtol(cmd, &cmd, 0)); break; case 'm': /* single step until location modified */ case 'M': /* single step until location modified - verbose */ modify(exp, (int)strtol(cmd, &cmd, 0), c == 'M'); break; case 'k': /* kill current program */ tstart(T_EXIT, 1, 0, 0); break; case 'b': /* set a breakpoint at the given line */ if (seg == D) { printf("Address not in text space.\n"); return; } breakpt(exp, skip(cmd)); cmd = "\n"; return; case 'B': /* print list of currently active breakpoints */ for (i = 1, bp = b_head; bp; bp=bp->nxt, i++) { p = addr_to_name(bp->addr - saddr, &exp); printf("%2d: %s+0x%lx (0x%lx) - %s", i, p, exp, bp->addr, bp->cmd); } break; case 'd': /* delete breakpoint */ if (seg == T) { for (bp = b_head; bp && --exp; bp=bp->nxt) {}; if (bp) { freepnt(bp); break; } } printf("No such breakpoint.\n"); break; case 'D': /* delete all breakpoints */ while(b_head) freepnt(b_head); break; case 'q': /* quit */ tstart(T_EXIT, 0, 0, 0L, 0); exit(0); case '\n': case ';': if (isdigit(*cmdstart)) symbolic(exp, '\n'); else printf("0x%lx\n", exp); --cmd; break; case 'v': printf("MDB version 1.0\n"); break; case '$': cmdstart = cmd; cmd = skip(cmd+2); if (*cmd == '!') { cmd++; fill(reg_addr(cmdstart), T_GETUSER); break; } if (*skip(cmd+2) == '/') { cmd++; display(reg_addr(cmdstart), T_GETUSER); break; } /*FALLTHROUGH*/ default: printf("Unknown command.\n"); break; } while (*cmd != '\n' && *cmd != ';') ++cmd; if (*cmd == ';') cmd = skip(cmd+1); } main(argc, argv) char *argv[]; { int i; prc = lbuf; ioctl(0, TIOCGETP, &in_gttyb); ioctl(0, TIOCGETC, &in_chars); for (i = 1; i < NSIG; i++) signal(i, catch); strcpy(sbuf, "\n"); prog = argc > 1 ? argv[1] : "a.out"; if (argc > 2) getsyms(argv[2]); setjmp(&mainlp); while ((printf("* "), fflush(stdout), fgets(cbuf, sizeof(cbuf), stdin)) != EOF) { if (strlen(cbuf) == sizeof(cbuf)-1) { printf("Command line too long.\n"); continue; } cmd = cbuf; command(); while (*cmd != '\n') command(); } tstart(T_EXIT, 0, 0, 0); exit(0); }
bds@lzaz.ATT.COM (B.SZABLAK) (03/30/89)
/* * mdbdis.c - MINIX program disassembler * * 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 <stdio.h> #define BYTE 0 #define WORD 1 #define LONG 2 #define BFIELD(w,b,l) (((w) >> ((b)-(l)+1)) & (int)((1L<<(l))-1)) #define BTST(w,b) ((w) & (1 << (b))) char opwfmt[] = "%s.%c\t"; #define OPI(s,w) printf(opwfmt, s, w) char size[] = "bwl"; char *cc[] = {"ra", "f", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" }; char *bitop[] = { "btst", "bchg", "bclr", "bset" }; char *imedop[] = { "ori", "andi", "subi", "addi", "?", "eori", "cmpi" }; char *misc1[] = { "negx", "clr", "neg", "not" }; char *misc2[] = { "reset", "nop", "stop", "rte", "??", "rts", "trapv", "rtr" }; char *shf[] = { "as", "ls", "rox", "ro" }; char *fmts[] = { "d%d", "a%d", "(a%d)", "(a%d)+", "-(a%d)" }; extern curpid; extern char *addr_to_name(); extern long saddr, eaddr; long gaddr, gbuf, ptrace(); int gempty, gisize, gjmp; short gword() { if (gempty) { gempty = 0; gbuf = ptrace(1, curpid, gaddr, 0L); gaddr += 2; return gbuf >> 16; } gempty = 1; gaddr += 2; return gbuf; } long glong() { gempty = 1; gbuf = ptrace(1, curpid, gaddr, 0L); gaddr += 4; return gbuf; } reladdr(sep) char sep; { int d = gword(); symbolic(gaddr + d - 2, sep); } movem(from, predec, rmsk) { int b, f = 0; if (!from) putc(',', stdout); for (b = 16; b--; rmsk >>= 1) { if (rmsk & 1) { if (f) putc('/', stdout); else f = 1; if (predec) printf("%c%d", b>7 ? 'a' : 'd', b % 8); else printf("%c%d", b>7 ? 'd' : 'a', 7 - b % 8); } } if (from) putc(',', stdout); } op1(mode,reg) { int d; char *s; long l; if (mode < 5) { printf(fmts[mode], reg); return; } if (mode == 5) { printf("%d(a%d)", gword(), reg); return; } if (mode == 6) { d = gword(); printf("%d(a%d,%c%d.%c)", BFIELD(d,7,8) | (BTST(d,7) ? 0xFF00 : 0), reg, BTST(d,15) ? 'a' : 'd', BFIELD(d,14,3), BTST(d,11) ? 'l' : 'w'); return; } switch (reg) { case 0: printf("%d.w", gword()); break; case 1: symbolic(glong(), '\0'); break; case 2: l = gaddr; printf("%d(pc) {", d = gword()); symbolic(l+d, '}'); break; case 3: d = gword(); printf("%d(pc,%c%d.%c)", BFIELD(d,7,8) | (BTST(d,7) ? 0xFF00 : 0), BTST(d,15) ? 'a' : 'd', BFIELD(d,14,3), BTST(d,11) ? 'l' : 'w'); break; case 4: putc('#', stdout); if (gisize == LONG) symbolic(glong(), '\0'); else if (gisize == BYTE) printf("%d", (char)gword()); else printf("%d", gword()); break; case 5: printf("sr"); break; } } op2(f,m1,r1,m2,r2) /* f set means order passed, clear reverses order */ { if (f) op1(m1,r1); else op1(m2,r2); putc(',',stdout); if (f) op1(m2,r2); else op1(m1,r1); } opmode(op, opm, reg, m, r) char *op; { OPI(op, size[gisize=BFIELD(opm,1,2)]); op2(BTST(opm,2),0,reg,m,r); } long dasm(addr,cnt, symflg) long addr; { int tflg = 0; register unsigned int w, m1, m2, r1, r2, op; char ds; gaddr = addr; gempty = 1; while (tflg || cnt--) { tflg = 0; if (symflg) symbolic(gaddr, '\t'); else printf("0x%lx ", gaddr); w = gword(); m1 = BFIELD(w,8,3); m2 = BFIELD(w,5,3); r1 = BFIELD(w,11,3); r2 = BFIELD(w,2,3); op = BFIELD(w,15,4); switch (op) { case 0x0: if (m2 == 1) { OPI("movep", BTST(w,6) ? 'l' : 'w'); op2(BTST(w,7),0,r1,5,r2); break; } if (BTST(w,8)) { OPI(bitop[BFIELD(w,7,2)], m2 ? 'b' : 'l'); op2(1,0,r1,m2,r2); break; } if (r2 == 4) { OPI(bitop[BFIELD(w,7,2)], m2 ? 'b' : 'l'); gisize = WORD; op2(1,7,4,m2,r2); break; } OPI(imedop[r1],size[gisize = m1]); op2(1,7,4,m2,r2); break; case 0x1: gisize = BYTE; goto domove; case 0x2: gisize = LONG; goto domove; case 0x3: gisize = WORD; domove: OPI("move", size[gisize]); op2(1,m2,r2,m1,r1); break; case 0x4: if (BTST(w,8)) { if (BTST(w,6)) { printf("lea\t"); op1(m2,r2); printf(",a%d", r1); break; } printf("chk\t"); op1(m2,r2); printf(",d%d", r1); break; } if (r1 < 4) { if (m1 == 3) { printf("move\t"); gisize = WORD; if (r1 == 0) printf("sr,"); op1(m2,r2); if (r1 == 2) printf(",ccr"); if (r1 == 3) printf(",sr"); break; } OPI(misc1[r1], size[m1]); op1(m2,r2); break; } else if (r1 == 4) { switch(m1) { case 0: printf("nbcd\t"); break; case 1: printf(m2 ? "pea\t" : "swap\t"); break; case 2: case 3: OPI(m2 ? "movem" : "ext", BTST(w,6) ? 'l' : 'w'); if (m2) movem(1,m2==4, gword()); break; } op1(m2,r2); break; } if (r1 == 5) { if (m1 == 3) printf("tas\t"); else OPI("tst", size[m1]); op1(m2,r2); break; } if (r1 == 6) { OPI("movem", BTST(w,6) ? 'l' : 'w'); op = gword(); op1(m2,r2); movem(0,m2==4,op); break; } if (BTST(w,7)) { printf(BTST(w,6) ? "jmp\t" : "jsr\t"); op1(m2,r2); break; } switch (m2) { case 0: case 1: printf("trap\t#%d", BFIELD(w,3,4)); tflg = 1; break; case 2: printf("link\ta%d,#%d", r2, gword()); break; case 3: printf("unlk\ta%d", r2); break; case 4: printf("move.l a%d,usp", r2); break; case 5: printf("move.l usp,a%d", r2); break; case 6: printf(misc2[r2]); break; } break; case 0x5: if (BFIELD(w,7,2) == 3) { op = BFIELD(w,11,4); if (m2 == 1) { printf("db%s\td%d,",cc[op], r2); reladdr('\0'); } else { printf("s%s\t",cc[op]); op1(m2,r2); } } else { printf("%sq.%c\t#%d,",BTST(w,8)?"sub":"add", size[BFIELD(w,7,2)], ((r1 - 1) & 7) + 1); op1(m2,r2); } break; case 0x6: ds = BFIELD(w,7,8); printf("b%s.%c\t", cc[BFIELD(w,11,4)], ds ? 's' : 'w'); if (ds) symbolic(gaddr+ds,'\0'); else reladdr('\0'); break; case 0x7: printf("moveq\t#%d,d%d",BFIELD(w,7,8),r1); break; case 0x8: if (m1 == 3 || m1 == 7) { printf("div%c\t", BTST(w,8) ? 's' : 'u'); op2(0,0,r1,m2,r2); } else if (m1 == 4 && (m2 == 1 || m2 == 0)) { printf(m2 ? "sbcd\t-(a%d),-(a%d)" : "sbcd\td%d,d%d", r2, r1); } else { opmode("or",m1,r1,m2,r2); } break; case 0x9: case 0xD: if ((m2 == 0 || m2 == 1) && m1 > 3 && m1 < 7) { OPI(op == 9 ? "subx" : "addx", size[BFIELD(w,7,2)]); m2 <<= 2; op2(1,m2,r2,m2,r1); } else if (m1 == 3 || m1 == 7) { gisize = m1 == 3 ? WORD : LONG; OPI(op==9 ? "sub" : "add", size[gisize]); op2(1,m2,r2,1,r1); } else { opmode(op==9 ? "sub" : "add",m1,r1,m2,r2); } break; case 0xB: if (BTST(w,8)) { if (m2 == 1) { OPI("cmpm", size[BFIELD(w,7,2)]); printf("(a%d)+,(a%d)+",r2,r1); } else { opmode("eor",m1,r1,m2,r2); } } else { opmode("cmp",m1,r1,m2,r2); } break; case 0xC: if (m1 == 3 || m1 == 7) { printf("mul%c\t", m1==7 ? 's' : 'u'); op2(0,0,r1,m2,r2); } else if (m1 == 4 && (m2 == 1 || m2 == 0)) { printf(m2 ? "abcd\t-(a%d),-(a%d)" : "abcd\td%d,d%d", r2, r1); } else if (m1 == 5) { op = BTST(w,3) ? 'a' : 'd'; printf("exg\t%c%d,%c%d",op,r1,op,r2); } else if (m1 == 6) { printf("exg\td%d,a%d",r1,r2); } else { opmode("and",m1,r1,m2,r2); } break; case 0xE: if (BFIELD(w,7,2) == 3) { printf("%s%c.w\t",shf[BFIELD(w,10,2)], BTST(w,8) ? 'l' : 'r'); op1(m2,r2); } else { printf("%s%c.%c\t",shf[BFIELD(w,4,2)], BTST(w,8) ? 'l' : 'r', size[BFIELD(w,7,2)]); if (BTST(w,5)) { op2(1,0,r1,0,r2); } else { printf("#%d,",r1); op1(0,r2); } } break; case 0xA: case 0xF: printf("%x", w); break; } putc('\n',stdout); } return gaddr; }