mdb.c

Go to the documentation of this file.
00001 /*
00002  * mdb.c - MINIX program debugger
00003  *
00004  * Written by Bruce D. Szablak
00005  *
00006  * This free software is provided for non-commerical use. No warrantee
00007  * of fitness for any use is implied. You get what you pay for. Anyone
00008  * may make modifications and distribute them, but please keep this header
00009  * in the distribution.
00010  */
00011 
00012 /*
00013  * Originally ported to MINIX-PC and MINIX-386 by Bruce Evans.
00014  * NB: the original sym.c and mdbdis86.c come from his 'db'
00015  *
00016  * Added by Philip Murton:
00017  *
00018  *  2.0         'Core' file functions
00019  *  2.1         Support for GNU exec
00020  *  2.2         Changes for Minix 1.6.x Beta
00021  *  2.3         Changes for Minix 1.7.0 and trace syscalls
00022  *  2.4         Changes for Minix 1.7.2 and clean up
00023  *  2.5.1       Add better help 
00024  *  2.5.2       Added io.c for logging options
00025  *  2.5.3       Minor changes and tested with Minix 1.7.4
00026  *  2.5.4       Command arguments processing improved (Thanks to Will Rose)
00027  *  2.6.0       Final Version for MINIX CD (Sept/96)
00028  */
00029 
00030 #define _MAIN_MDB
00031 #include "mdb.h"
00032 
00033 #include <minix/type.h>
00034 
00035 #include <stdio.h>
00036 #include <signal.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039 #include <unistd.h>
00040 #include <ctype.h>
00041 #include <errno.h>
00042 #include <sys/wait.h>
00043 #define ptrace mdbtrace
00044 #include <sys/ptrace.h>
00045 #include <setjmp.h>
00046 #include "proto.h"
00047 
00048 #include <kernel/const.h>
00049 #include <kernel/type.h>
00050 #include <kernel/proc.h>
00051 
00052 /* buffer for proc and pointer to proc */
00053 extern struct proc *prc;
00054 
00055 #define MAXLINE 128
00056 #define MAXARG  20
00057 
00058 PRIVATE unsigned long lastexp = 0L;     /* last expression and segment */
00059 PRIVATE int lastseg = NOSEG;
00060 PRIVATE char *prog;             /* prog name */
00061 PRIVATE char sbuf[MAXLINE];
00062 PRIVATE char cbuf[MAXLINE];
00063 PRIVATE char *cmd;              /* current command   */
00064 PRIVATE char *cmdstart;         /* start of command  */
00065 PRIVATE jmp_buf mainlp;
00066 
00067 
00068 struct b_pnt {
00069   struct b_pnt *nxt, *prv;
00070   long addr;
00071   long oldval;
00072   char cmd[1];
00073 } *b_head, *curpnt;
00074 
00075 _PROTOTYPE( void main , (int argc, char *argv[]));
00076 
00077 FORWARD _PROTOTYPE( void cleanup , (void));
00078 FORWARD _PROTOTYPE( void freepnt , (struct b_pnt *pnt ));
00079 FORWARD _PROTOTYPE( void findbpnt , (int verbose ));
00080 FORWARD _PROTOTYPE( int exebpnt , (int restart ));
00081 FORWARD _PROTOTYPE( void catch , (int sig ));
00082 FORWARD _PROTOTYPE( int run , (char *name , char *argstr , int tflg ));
00083 FORWARD _PROTOTYPE( int dowait , (void));
00084 FORWARD _PROTOTYPE( void backtrace , (int all ));
00085 FORWARD _PROTOTYPE( void modify , (long addr , int cnt , int verbose , int size ));
00086 FORWARD _PROTOTYPE( void display , (long addr , int req ));
00087 FORWARD _PROTOTYPE( void fill , (long addr , int req ));
00088 FORWARD _PROTOTYPE( void dorun , (char *cmd ));
00089 FORWARD _PROTOTYPE( void not_for_core , (void));
00090 FORWARD _PROTOTYPE( void command , (void));
00091 
00092 
00093 PRIVATE void cleanup()
00094 {
00095   curpid = 0;
00096   curpnt = NULL;
00097   while (b_head) freepnt(b_head);
00098 }
00099 
00100 PRIVATE void findbpnt(verbose)
00101 int verbose;
00102 {
00103   for (curpnt = b_head; curpnt; curpnt = curpnt->nxt) {
00104         if (curpnt->addr == PC_MEMBER(prc) - BREAKPOINT_ADVANCE) {
00105                 ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval);
00106                 ptrace(T_SETUSER, curpid, PC_OFF, curpnt->addr);
00107 #if     SYSCALLS_SUPPORT
00108                 if( syscalls ) 
00109                         do_syscall(curpnt->addr);
00110                 else if (curpnt->cmd[0] != '\n')
00111 #else
00112                 if (curpnt->cmd[0] != '\n')
00113 #endif
00114                         cmd = strcpy(cbuf, curpnt->cmd);
00115                 else if (verbose)
00116                         Printf("Breakpoint hit.\n");
00117                 return;
00118         }
00119   }
00120   if (verbose) Printf("Unknown breakpoint hit.\n");
00121 }
00122 
00123 PRIVATE int exebpnt(restart)
00124 int restart;
00125 {
00126   ptrace(T_STEP, curpid, 0L, (long) restart);
00127   if (dowait() == 0) return TRUE;
00128   ptrace(T_SETINS, curpid, curpnt->addr, BREAK(curpnt->oldval));
00129   curpnt = NULL;
00130   return FALSE;
00131 }
00132 
00133 
00134 PRIVATE void freepnt(pnt)
00135 struct b_pnt *pnt;
00136 {
00137   if (pnt->prv)
00138         pnt->prv->nxt = pnt->nxt;
00139   else
00140         b_head = pnt->nxt;
00141   if (pnt->nxt) pnt->nxt->prv = pnt->prv;
00142   if (curpid > 0) ptrace(T_SETINS, curpid, pnt->addr, pnt->oldval);
00143   free(pnt);
00144   if (pnt == curpnt) curpnt = NULL;
00145 }
00146 
00147 
00148 PUBLIC long breakpt(addr, cmd)
00149 long addr;
00150 char *cmd;
00151 {
00152   struct b_pnt *new;
00153 
00154   if (curpid <= 0) {
00155         Printf("No active process.\n");
00156         return 0L;
00157   }
00158   for (new = b_head; new; new = new->nxt)
00159         if (new->addr == addr) {
00160                 Printf("Breakpoint already exists here.\n");
00161                 return 0L;
00162         }
00163   new = (struct b_pnt *) malloc(sizeof(struct b_pnt) + strlen(cmd));
00164   if (new == NULL) {
00165         Printf("No room for new breakpoint.\n");
00166         return 0L;
00167   }
00168   new->nxt = b_head;
00169   new->prv = 0;
00170   if (b_head) b_head->prv = new;
00171   b_head = new;
00172   new->addr = addr;
00173   strcpy(new->cmd, cmd);
00174   new->oldval = ptrace(T_GETINS, curpid, addr, 0L);
00175   ptrace(T_SETINS, curpid, addr, BREAK(new->oldval));
00176   if (ptrace(T_GETINS, curpid, addr, 0L) != BREAK(new->oldval)) {
00177         do_error("Can't set breakpoint");
00178         freepnt(new);
00179         return 0L;
00180   }
00181   return new->oldval;
00182 }
00183 
00184 PRIVATE void catch(sig)
00185 int sig;
00186 {
00187   signal(sig, catch);
00188   if (sig == SIGINT || sig == SIGQUIT) return;
00189   tstart(T_EXIT, 0, sig, 0);
00190   exit(0);
00191 }
00192 
00193 
00194 PRIVATE int dowait()
00195 {
00196   int stat;
00197 
00198   if (corepid > 0) return cursig = 0;
00199   while (wait(&stat) != curpid) {};
00200   if ( WIFEXITED(stat) ) {
00201         if (WEXITSTATUS(stat) != 127) 
00202                 Printf("child exited with status %d\n", WEXITSTATUS(stat));
00203         cleanup();
00204         return 0;
00205   }
00206   if ( WIFSIGNALED(stat) ) {
00207         Printf("child terminated by signal %d\n", WTERMSIG(stat) );
00208         if (_LOW(stat) & 0x80) Printf("(core dumped)\n");
00209         cleanup();
00210         return 0;
00211   }
00212   return cursig = WSTOPSIG(stat);
00213 }
00214 
00215 
00216 
00217 PUBLIC void tstart(req, verbose, val, cnt)
00218 int req, verbose, val, cnt;
00219 {
00220   if (curpid == 0) {
00221         if (verbose) Printf("No active process.\n");
00222         return;
00223   }
00224   if (req == T_EXIT) {
00225         ptrace(T_EXIT, curpid, 0L, (long) val);
00226         dowait();
00227         return;
00228   }
00229   if (cnt == 0) cnt = 1;
00230   do {
00231         if (curpnt) {
00232                 if (exebpnt(val)) return;
00233                 if (req == T_RESUME) cnt++;
00234                 val = 0;
00235         } else {
00236                 ptrace(req, curpid, 0L, (long) val);
00237                 if (dowait() == 0) return;
00238                 val = 0;
00239                 switch (cursig) {
00240                     case SIGEMT:        /* breakpoint */
00241                         update();
00242                         findbpnt(cnt <= 1);
00243                         break;
00244                     case SIGTRAP:       /* trace trap? */
00245                         if (req == T_STEP) break;
00246                     default:            /* signal */
00247                         val = cursig;
00248                         break;
00249                 }
00250         }
00251   }
00252   while (--cnt > 0);
00253   update();
00254   if ( verbose ) dasm((long) PC_MEMBER(prc), 1, 1);
00255 }
00256 
00257 PRIVATE int run(name, argstr, tflg)
00258 char *name, *argstr;
00259 int tflg;
00260 {
00261   int procid;
00262   char *argv[MAXARG], *inf = NULL, *outf = NULL;
00263   int argc;
00264 
00265   if ((procid = fork()) == 0) {
00266         /* trace me */
00267         if (tflg) ptrace(T_OK, 0, 0L, 0L); 
00268         argv[0] = name;
00269         for (argc = 1;;) {
00270                 argstr = skip(argstr);
00271                 if (*argstr == '\n' || *argstr == ';') {
00272                         argv[argc] = 0;
00273                         if (inf) freopen(inf, "r", stdin);
00274                         if (outf) freopen(outf, "w", stdout);
00275                         if (tflg) {
00276                                 execv(name, argv);
00277                                 do_error("execv");
00278                         } else {
00279                                 execvp(name, argv);
00280                                 do_error("execvp");
00281                         }
00282                         exit(127);
00283                 }
00284                 if (*argstr == '<')
00285                         inf = argstr + 1;
00286                 else if (*argstr == '>')
00287                         outf = argstr + 1;
00288                 else if (argc == MAXARG) {
00289                         Printf("Too many arguments.\n");
00290                         exit(127);
00291                 } else
00292                         argv[argc++] = argstr;
00293                 while (!isspace(*argstr)) argstr++;
00294                 if (*argstr == '\n') argstr[1] = '\n', argstr[2] = 0;
00295                 *argstr++ = 0;
00296         }
00297   }
00298   if (procid < 0) do_error("Fork failed.\n");
00299   return procid;
00300 }
00301 
00302 
00303 PRIVATE void dorun(cmd)
00304 char *cmd;
00305 {
00306   if (curpid = run(prog, cmd, 1)) {
00307         if (dowait()) {
00308                 ptrace(T_SETUSER, curpid, BP_OFF, 0L);
00309                 update();
00310                 Printf("Process stopped.\n");
00311         }
00312   }
00313 }
00314 
00315 /* 
00316  * backtrace - inspect the stack
00317  */ 
00318 PRIVATE void backtrace(all)
00319 int all;
00320 {
00321   unsigned long pc, bp, off, val, obp;
00322 
00323   if (curpid <= 0) {
00324         Printf("No process.\n");
00325         return;
00326   }
00327   pc = get_reg(curpid,PC_OFF);
00328   bp = get_reg(curpid,BP_OFF);
00329   if (bp == 0) {
00330         Printf("No active frame.\n");
00331         return;
00332   }
00333   errno = 0;
00334   do {
00335         symbolic(pc, '(');
00336         pc = (ptrace(T_GETDATA, curpid, bp + ADDRSIZE, 0L)
00337               >> SHIFT(ADDRSIZE)) & MASK(ADDRSIZE);
00338         off = ptrace(T_GETINS, curpid, pc, 0L);
00339 #ifdef  DEBUG
00340         if(debug)
00341             Printf("Return address %lx Value %lx\n",pc,off);
00342 #endif
00343         obp = bp;
00344         bp += 2 * ADDRSIZE;
00345 
00346         /* Check for various instruction used to restore the stack. 
00347          * Should gives us the number of arguments.
00348          * This is obvious dependent on interal features of the 
00349          * compiler used.
00350          */ 
00351         if (ADDQ(off)) off = ADDQ_CNT(off) + bp;
00352 #ifdef __mc68000__
00353         else if (LEA(off))
00354                 off = LEA_DISP(off) + bp;
00355 #endif
00356         else if (ADDA(off))
00357                 off = ADDA_CNT(ptrace(T_GETINS, curpid, pc + 2, 0L)) + bp;
00358 #if (CHIP == INTEL)
00359         else if (INCSP2(off))
00360                 off = bp + 2*INTSIZE;
00361         else if (POPBX2(off))
00362                 off = bp + 2*INTSIZE;
00363         else if (POPCX2(off))
00364                 off = bp + 2*INTSIZE;
00365         else if (POPBX(off))
00366                 off = bp + INTSIZE;
00367         else if (POPCX(off))
00368                 off = bp + INTSIZE;
00369 #endif
00370         else
00371                 goto skiplp;
00372 
00373 #ifdef DEBUG
00374         if (debug) 
00375             Printf("Number of arguments: %d\n",(off-bp)/INTSIZE);
00376 #endif
00377 
00378         for (;;) {
00379                 if (errno) return;
00380                 val = (ptrace(T_GETDATA, curpid, bp, 0L)
00381                        >> SHIFT(INTSIZE)) & MASK(INTSIZE);
00382                 Printf("0x%0*lx", 2 * INTSIZE, val);
00383                 bp += INTSIZE;
00384                 if (bp >= off) break;
00385                 Printf(",");
00386         }
00387 
00388 skiplp:
00389         Printf(")\n");
00390         bp = (long) ( (reg_t) ptrace(T_GETDATA, curpid, obp, 0L) );
00391 #ifdef  DEBUG
00392         if(debug)
00393                 Printf("Old BP %lx New %lx\n",obp,bp);
00394 #endif
00395   }
00396   while (all && (reg_t) bp);
00397 }
00398 
00399 PRIVATE void modify(addr, cnt, verbose, size)
00400 long addr;
00401 int cnt, verbose, size;
00402 {
00403   long curval, off;
00404 
00405   if (curpid == 0) {
00406         Printf("No active process.\n");
00407         return;
00408   }
00409   curval = ptrace(T_GETDATA, curpid, addr, 0L) & MASK(size);
00410   do {
00411         if (cursig == SIGTRAP) cursig = 0;
00412         if (verbose) {
00413                 off = get_reg(curpid, PC_OFF);
00414                 dasm(off, 1, 0);
00415         }
00416         if (curpnt && exebpnt(cursig))
00417                 return;
00418         else {
00419                 ptrace(T_STEP, curpid, addr, 0L);
00420                 switch (dowait()) {
00421                     case 0:
00422                         return;
00423                     case SIGEMT:
00424                         update();
00425                         findbpnt(0);
00426                         break;
00427                 }
00428         }
00429         if (curval != ptrace(T_GETDATA, curpid, addr, 0L) & MASK(size)) {
00430                 Printf("Modification detected\n");
00431                 break;
00432         }
00433   }
00434   while (--cnt);
00435   update();
00436   dasm((long) PC_MEMBER(prc), 1, 1);
00437   return;
00438 }
00439 
00440 PRIVATE void display(addr, req)
00441 long addr;
00442 int req;
00443 {
00444   int count, size, out, shift;
00445   long val, msk;
00446   char fmt;
00447 
00448   if (curpid == 0) {
00449         Printf("No active process\n");
00450         return;
00451   }
00452   if (req == T_GETDATA && seg == T) req = T_GETINS;
00453   count = strtol(cmd, &cmd, 0);
00454   if (count == 0) count = 1;
00455   cmd = skip(cmd);
00456   if (*cmd == 'i' || *cmd == 'I') {
00457         dasm(addr, count, *cmd == 'i');
00458         return;
00459   }
00460   if (*cmd == 'y') {
00461         symbolic(addr, '\n');
00462         return;
00463   }
00464   switch (*cmd++) {
00465       case 'b': size = sizeof(char);    break;
00466       case 'h': size = sizeof(short);   break;
00467       case 'l': size = sizeof(long);    break;
00468       default:  
00469         size = sizeof(int);
00470         --cmd;
00471         break;
00472   }
00473   switch (fmt = *cmd) {
00474       case 'X':
00475       case 'D': 
00476         size = sizeof(long);
00477         break;
00478       case 's':
00479         addr = ptrace(req, curpid, addr, 0L);
00480         req = T_GETDATA;
00481       /* Fallthrough */ 
00482       case 'a': 
00483       case 'c':
00484         size = sizeof(char);    
00485         break;
00486   }
00487   out = 0;
00488   msk = MASK(size);
00489   shift = SHIFT(size);
00490   do {
00491         val = (ptrace(req, curpid, addr, 0L) >> shift) & msk;
00492         if (out == 0) Printf("\n0x%0*lx: ", 2 * ADDRSIZE,
00493                        (addr >> SHIFT(ADDRSIZE)) & MASK(ADDRSIZE));
00494         switch (fmt) {
00495             case 'c':
00496                 Printf(isprint((int) (UCHAR(val))) ? "   %c " : "\\%03o ",
00497                                         (int) (UCHAR(val)));
00498                 if (++out == 8) out = 0;
00499                 break;
00500             case 'u':
00501                 Printf("%12lu ", val);
00502                 if (++out == 4) out = 0;
00503                 break;
00504             case 'x':
00505             case 'X':
00506                 Printf("%*lx ", 2 * size, val);
00507                 if (++out == (size == 4 ? 4 : 8)) out = 0;
00508                 break;
00509             case 'o':
00510                 Printf("%*lo ", 3 * size, val);
00511                 if (++out == (size == 4 ? 4 : 8)) out = 0;
00512                 break;
00513             case 's':
00514             case 'a':
00515                 if (val)
00516                         Printf("%c",val);
00517                 else
00518                         goto exitlp;
00519                 if (++out == 64) out = 0;
00520                 break;
00521             default:
00522             case 'd':
00523             case 'D':
00524                 Printf("%12ld ", val);
00525                 if (++out == 4) out = 0;
00526                 break;
00527         }
00528         addr += size;
00529   }
00530   while (--count > 0 || fmt == 's' || fmt == 'a');
00531 exitlp:
00532   Printf("\n");
00533 }
00534 
00535 PRIVATE void fill(addr, req)
00536 long addr;
00537 int req;
00538 {
00539   int count, size, shift;
00540   long val, msk, nval;
00541 
00542   if (curpid == 0) {
00543         Printf("No active process\n");
00544         return;
00545   }
00546   
00547   if (req == T_GETDATA && seg == T) {
00548         req = T_GETINS;
00549         Printf("mdb: warning - modifying text\n");
00550   }
00551   count = strtol(cmd, &cmd, 0);
00552   if ( count == 0 ) count = 1;
00553   switch (*cmd++) {
00554       case 'b': size = sizeof(char);    break;
00555       case 'h': size = sizeof(short);   break;
00556       case 'l': size = sizeof(long);    break;
00557       default:
00558         size = sizeof(int);
00559         --cmd;
00560         break;
00561   }
00562   shift = SHIFT(size);
00563   msk = MASK(size);
00564   cmd = getexp(cmd, &nval, &seg);
00565 
00566 #ifdef DEBUG
00567   if (debug)
00568         Printf("Filling for Count=%d Size=%d val=%lx\n",count,size,nval);
00569 #endif
00570 
00571   nval <<= shift;
00572   do {
00573         val = ptrace(req, curpid, addr, 0L) | (nval & msk);
00574         val &= (nval | ~msk);
00575         ptrace(req + 3, curpid, addr, val);
00576         addr += size;
00577   }
00578   while (--count > 0);
00579 }
00580 
00581 PRIVATE void not_for_core()
00582 {
00583   if (corepid > 0)
00584         mdb_error("Illegal command for 'core' file\n");
00585 }
00586 
00587 PRIVATE void command()
00588 {
00589   char c, *p;
00590   int i;
00591   int size;
00592   int stat;
00593   long exp, lj, lk;
00594   struct b_pnt *bp;
00595 
00596   seg = NOSEG;          /* don't restrict segment expressions are in */
00597   cmdstart = cmd = skip(cmd);
00598   cmd = getexp(cmd, &exp, &seg);
00599 
00600   if (cmd == cmdstart) {        
00601         /* Not an expression */
00602         if (corepid < 0) {      /* default to pc for running processs */
00603                 seg = T;
00604                 exp = PC_MEMBER(prc);
00605         } else {
00606                 seg = lastseg;
00607                 exp = lastexp;
00608         }
00609 
00610         /* Is it a help command */
00611         cmd = skip(cmd+1);
00612         if (*cmd == '?') {
00613                 help_on(*cmdstart);
00614                 *cmd = '\n';
00615                 return;
00616         }
00617         else
00618                 cmd = cmdstart;
00619   }
00620 
00621   if (seg == NOSEG) seg = T;    /* Absolute becomes Text */
00622   lastexp = exp;                /* save last expression  */
00623   lastseg = seg;
00624 #ifdef DEBUG
00625   if(debug)
00626         Printf("Current address 0x%0*lx and segment %d\n",  2 * ADDRSIZE, exp, seg);
00627 
00628 #endif
00629 
00630   /* Check commands */
00631   switch (c = *cmd++) {
00632       case 'r':         /* illegal for 'core' files */
00633       case 'R':
00634       case 'k':
00635       case 'B':
00636       case 'd':
00637       case 'D':         not_for_core(); 
00638                         break;
00639 
00640       case 'b':         /* illegal for 'core' files     */
00641       case 'c':         /* Otherwise run process first  */
00642       case 'C':
00643       case 'm':
00644       case 'M':
00645 #if     SYSCALLS_SUPPORT
00646       case 'z':
00647 #endif
00648       case 'i':
00649       case 'I':         not_for_core();
00650                         if (curpid <= 0) dorun("\n");
00651                         break;
00652 
00653       case 's':         if (curpid <= 0) dorun("\n");
00654                         break;
00655         
00656       default:          break;
00657   }
00658 
00659   switch (c) {
00660       case '!':         /* escape to shell */
00661         if (cmd == cmdstart + 1) {
00662                 cmd = skip(cmd);
00663                 if (*cmd == '\n' || *cmd == ';') {
00664                         i = run("/bin/sh", "\n", 0);
00665                 } else {
00666                         for (p = cmd + 1; *p && !isspace(*p); p++) {
00667                         };
00668                         *p++ = 0;
00669                         i = run(cmd, *p ? p : "\n", 0);
00670                 }
00671                 if (i > 0) while (wait(&stat) != i) {};
00672                 break;
00673         }
00674         if (corepid > 0) longjmp(mainlp, 0);
00675         break;
00676       case 'T':         /* top line of backtrace */
00677         backtrace(0);
00678         break;
00679       case 't':         /* back trace */
00680         backtrace(1);
00681         break;
00682       case '/':         /* print variable value */
00683         display(exp, T_GETDATA);
00684         break;
00685       case 'x':         /* print registers and instruction */
00686         if (disp_regs()) break;
00687         /* FALLTHROUGH */
00688       case 'X':         /* print instruction - X n [, n] */
00689         lj = strtol(cmd, &cmd, 0);
00690         lk = 0;
00691         if (*cmd != '\0') 
00692                 lk = strtol(++cmd, &cmd, 0);
00693         if (curpid > 0)
00694                 dasm(exp + lk, lj ? lj : 1, 1);
00695         else
00696                 Printf("No active process.\n");
00697         break;
00698       case 'R':         /* run program with no args */
00699       case 'r':         /* run program with args (possibly defaulted) */
00700         tstart(T_EXIT, 0, 0, 0);
00701         if (c == 'r') {
00702                 cmd = skip(cmd);
00703                 if (*cmd == '\n' || *cmd == ';')
00704                         cmd = sbuf;
00705                 else
00706                         strcpy(sbuf, cmd);
00707         } else {
00708                 cmd = "\n";
00709         }
00710         dorun(cmd);
00711         break;
00712       case 'c':         /* continue program - ignore signal */
00713         cursig = 0;
00714       case 'C':         /* continue program - handle signal */
00715         i = 0;
00716         if (seg == T && curpnt == 0 && cmd != cmdstart + 1) {
00717                 breakpt(exp, "\n");
00718                 curpnt = b_head;
00719                 ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval);
00720                 i = 1;
00721         }
00722         tstart(T_RESUME, 1, cursig, (int) strtol(cmd, &cmd, 0));
00723         /* remove temporary bp */
00724         if (i) freepnt(b_head);
00725         if (cursig == SIGEMT) return;
00726         if (curpid) Printf("Process stopped by signal %d\n", cursig);
00727         break;
00728       case 'i':         /* single step - ignore signal */
00729         tstart(T_STEP, 1, 0, (int) strtol(cmd, &cmd, 0));
00730         break;
00731       case 'I':         /* single step - handle signal */
00732         tstart(T_STEP, 1, cursig, (int) strtol(cmd, &cmd, 0));
00733         break;
00734       case 'm':         /* single step until location modified */
00735       case 'M':         /* single step until location modified - verbose */
00736         cmd = skip(cmd);
00737         switch (*cmd++) {
00738             case 'b':   size = sizeof(char);    break;
00739             case 'h':   size = sizeof(short);   break;
00740             case 'l':   size = sizeof(long);    break;
00741             default:
00742                 size = sizeof(int);
00743                 --cmd;
00744                 break;
00745         }
00746         modify(exp, (int) strtol(cmd, &cmd, 0), c == 'M', size);
00747         break;
00748       case 'k':         /* kill current program */
00749         tstart(T_EXIT, 1, 0, 0);
00750         break;
00751       case 'b':         /* set a breakpoint at the given line */
00752 #ifdef  MINIX_PC
00753         if (seg != T || exp > end_addr ) {
00754 #else
00755         if (seg != T || exp < st_addr || exp > et_addr ) {
00756 #endif  
00757                 Printf("Address not in text space.\n");
00758                 return;
00759         }
00760         breakpt(exp, skip(cmd));
00761         cmd = "\n";
00762         return;
00763       case 'B':         /* print list of currently active breakpoints */
00764         for (i = 1, bp = b_head; bp; bp = bp->nxt, i++) {
00765                 Printf("%2d: ", i);
00766                 symbolic((long) bp->addr, '\t');
00767                 Printf("(0x%lx)\t- %s", bp->addr, bp->cmd);
00768         }
00769         break;
00770       case 'd':         /* delete breakpoint */
00771         if (seg == T) {
00772                 for (bp = b_head; bp && bp->addr != exp; bp = bp->nxt);
00773                 if (bp) {
00774                         freepnt(bp);
00775                         break;
00776                 }
00777         }
00778         Printf("No such breakpoint.\n");
00779         break;
00780       case 'D':         /* delete all breakpoints */
00781         while (b_head) freepnt(b_head);
00782         break;
00783       case 's':
00784         dump_stack( strtol(cmd, &cmd, 0) );
00785         break;
00786       case 'P':
00787         paging = !paging;
00788         if (paging) Printf("Paging is ON\n");
00789         break;
00790       case 'l':
00791       case 'L':
00792         logging(c,skip(cmd));
00793         break;
00794 #if     SYSCALLS_SUPPORT
00795       case 'z':
00796         start_syscall( strtol(cmd, &cmd, 0) );
00797         if ( syscalls ) 
00798                 Printf("Break point set - use the 'c n' command\n");
00799         break;
00800 #endif
00801       case 'q':         /* quit */
00802         tstart(T_EXIT, 0, 0, 0);
00803         logging(c,cmd);
00804       case 'Q':
00805         exit(0);        
00806         break;
00807       case '\n':
00808       case ';':
00809         if (isdigit(*cmdstart))
00810                 symbolic(exp, '\n');
00811         else
00812                 Printf("0x%0*lx\n", 2 * ADDRSIZE, exp);
00813         --cmd;
00814         break;
00815 #ifdef  DEBUG
00816       case 'v':         /* toggle debug */
00817         debug = !debug;
00818         if (debug) Printf("Debug flag ON\n");
00819         break;
00820 #endif
00821       case 'e':         /* list symbols */
00822         listsym(cmd);
00823         break;
00824       case 'y':         /* print mapping */
00825         prtmap();
00826         break;
00827       case '?':         /* print help */
00828         help_page();
00829         break;
00830       case 'V':         /* print version info */
00831         version_info();
00832         break;
00833       case '@':         /* command file  */
00834         cmd = skip(cmd);
00835         openin(cmd);
00836         *cmd = '\n';
00837         return;
00838       case '#':         /* set register or variable */
00839         cmd = skip(cmd + 1);
00840         if (*cmd == '$') {
00841                 cmd++;
00842                 i = reg_addr(cmd); 
00843                 set_reg(curpid, i, strtol(cmd+2, &cmd, 0) );
00844                 update();
00845                 break;
00846         }
00847         cmd = getexp(cmd, &exp, &seg);
00848         fill(exp, T_GETDATA);
00849         break;
00850       default:  
00851         help_page();
00852         break;
00853   }
00854   while (*cmd != '\n' && *cmd != ';') ++cmd;
00855   if (*cmd == ';') cmd = skip(cmd + 1);
00856 }
00857 
00858 PUBLIC void mdb_error(s)
00859 char *s;
00860 {
00861   Printf("%s",s);
00862   longjmp(mainlp, 0);
00863 }
00864 
00865 PUBLIC void main(argc, argv)
00866 int argc;
00867 char *argv[];
00868 {
00869   int i, c;
00870   char *p, *q, *r;
00871   int opt_c = FALSE;    /* load core file */
00872   int opt_f = FALSE;    /* load object file */
00873   int opt_l = FALSE;    /* log to file */
00874   int opt_L = FALSE;    /* log to file and screen */
00875 
00876 
00877   prc = (struct proc *) lbuf;
00878   strcpy(sbuf, "\n");
00879   corepid = -1; /* set to indicate none */
00880   prog = p = q = r = NULL;
00881 
00882   if ( argc == 1 )
00883   {
00884         help_page();
00885         exit(0);
00886   }
00887 
00888   /* Possible combinations of arguments:
00889    * A single file name:
00890    *    If the name is 'core', the coreonly flag is set.
00891    * The -c flag: examine a core file.
00892    *    One filename is required with this flag.
00893    * The -f flag: examine an object file.
00894    *    One file name is required with this flag.
00895    * The -L or -l flag: write to a log file.
00896    *    One file name is required with these flags.
00897    * The -x flag: turn on debugging.
00898    *    Used for debugging, and followed by an integer
00899    *    argument which is the debugging level.
00900    *
00901    * If any files remain on the argument list, the first
00902    * file is an executable, and the second a core file.
00903    * If any filename starts with '@' it is assumed to
00904    * to be a command file.  Only one command file is
00905    * loaded.
00906    */
00907 
00908   /* check for default file name and fake out getopt */
00909   if (strcmp(argv[1], "core") == 0) {
00910         for (i = argc ; i > 1 ; i--)
00911                 argv[i] = argv[i - 1];
00912         argv[i] = "-c";
00913         argc++;
00914   }
00915 
00916   /* parse options */
00917   opterr = 0;
00918   while ((i = getopt(argc, argv, "c:f:L:l:x:")) != EOF) {
00919         switch (i & 0377) {
00920         case 'c':               /* examine a core file */
00921                 if (opt_c == TRUE || opt_f == TRUE) {
00922                         help_page();
00923                         exit(1);
00924                 }
00925                 p = optarg;
00926                 opt_c = TRUE;
00927                 break;
00928         case 'f':               /* examine an object file */
00929                 if (opt_c == TRUE || opt_f == TRUE) {
00930                         help_page();
00931                         exit(1);
00932                 }
00933                 p = optarg;
00934                 opt_f = TRUE;
00935                 break;
00936         case 'l':               /* start logging */
00937                 if (opt_l == TRUE || opt_L == TRUE) {
00938                         help_page();
00939                         exit(1);
00940                 }
00941                 opt_l = TRUE;
00942                 logging(i, optarg);
00943                 break;
00944         case 'L':               /* start logging */
00945                 if (opt_l == TRUE || opt_L == TRUE) {
00946                         help_page();
00947                         exit(1);
00948                 }
00949                 opt_L = TRUE;
00950                 logging(i, optarg);
00951                 break;
00952 #ifdef DEBUG
00953         case 'x':               /* set debug level */
00954                 debug = atoi(optarg);
00955                 break;
00956 #endif
00957         case '?':               /* default arguments arrive here */
00958         default:
00959                 help_page();
00960                 exit(1);
00961         }
00962   }
00963 
00964   /* can't cope without filenames */
00965   if (!opt_c && !opt_f && optind >= argc) {
00966         help_page();
00967         exit(1);
00968   }
00969 
00970   /* any remaining arguments are (optional) file names */
00971   for (i = optind ; i < argc ; i++) {
00972         if (*argv[i] == '@') {                  /* command file */
00973                 if (r == NULL) r = argv[i] + 1;
00974         }
00975         /* you can't combine a -c or -f object file and a core file */
00976         else if (!opt_c && !opt_f && p == NULL) p = argv[i];
00977         else if (q == NULL) q = argv[i];        /* core file */
00978   }
00979 
00980   /* initialise stuff - fairly tricky logic */
00981   coreonly = opt_c;
00982   fileonly = opt_f;
00983   /* when examining files, prog == NULL */
00984   if (!opt_c && !opt_f) {
00985         prog = p;
00986         syminit(prog);
00987   }
00988 
00989   /* file_init is called for non-core files. 
00990    * It is very similar to core_init. It opens the file and set
00991    * various pointers so that we can read it using the same routines
00992    * as a core file. 
00993    * NB: Currently there is no special provision to handle object files.
00994    */
00995 
00996   /* A comment from Will Rose:
00997    * It would be nice to have
00998    * symbol tables available when reading a core
00999    * or a.out, either as part of the executable or
01000    * as a separate file.
01001    * At least three separate types of file structure
01002    * may be used by mdb - core files, a.out files, and
01003    * object files (which may have several flavours).
01004    * A set of routines is needed for each type, with
01005    * a function switch table initialised  when mdb is
01006    * started up.
01007    */
01008 
01009   if (opt_c) lastexp = core_init(p);
01010   if (opt_f) lastexp = file_init(p);
01011   if (q != NULL) lastexp = core_init(q);
01012   if (r != NULL) openin(r);
01013   for (i = 1; i < _NSIG; i++) signal(i, catch);
01014 
01015   setjmp(mainlp);
01016 
01017   while (get_cmd( cbuf, MAXLINE ) != NULL) {
01018         if (strlen(cbuf) == sizeof(cbuf) - 1) {
01019                 Printf("Command line too long.\n");
01020                 continue;
01021         }
01022         cmd = cbuf;
01023         command();
01024         while (*cmd != '\n') command();
01025   }
01026   tstart(T_EXIT, 0, 0, 0);
01027   exit(0);
01028 }

Generated on Fri Apr 14 22:56:59 2006 for minix by  doxygen 1.4.6