home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_GEN / FSDB091A.ZIP / FULLSCR.C < prev    next >
C/C++ Source or Header  |  1994-03-14  |  57KB  |  2,149 lines

  1. /* ---------------------------------------------------------------------- */
  2. /*              FULL SCREEN DEBUGGER                  */
  3. /*                                      */
  4. /* Copyright 1994 by Morten Welinder, terra@diku.dk              */
  5. /* ---------------------------------------------------------------------- */
  6. /*
  7.  
  8. This debugger is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2, or (at your option)
  11. any later version.
  12.  
  13. This debugger is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with djgpp; see the file COPYING.     If not, write to
  20. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21. /* ---------------------------------------------------------------------- */
  22. #define FULLSCR_VERSION 0.91
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include <pc.h>
  28. #include <dos.h>
  29. #include <dpmi.h>
  30. #include <go32.h>
  31. #include <keys.h>
  32. #define K_BackTab 0x10f
  33. #define K_ELeft 0x24b
  34. #include <setjmp.h>
  35. #define far
  36. #include "ed.h"
  37. #define A_black 0
  38. #include "syms.h"
  39. #include "paging.h"
  40. #include "unassmbl.h"
  41. #include "npx.h"
  42. /* ---------------------------------------------------------------------- */
  43. /* Information about the initialization state of the debugger.    Actually
  44.    I'm not sure that longjmp should ever be permitted.    */
  45. int can_longjmp = 0;
  46. jmp_buf debugger_jmpbuf;
  47.  
  48. /* Display information.     */
  49. static int debug_screen_p;
  50. static char *user_screen_save, *debug_screen_save;
  51. static unsigned char screen_attr;
  52. static unsigned char screen_attr_normal;
  53. static unsigned char screen_attr_source;
  54. static unsigned char screen_attr_focus;
  55. static unsigned char screen_attr_break;
  56. static unsigned char screen_attr_message;
  57. static unsigned char screen_attr_error;
  58. static int cols;
  59. static int rows;
  60. static int toplines, bottomlines;
  61.  
  62. /* Information about panes.  */
  63. #define PANECOUNT 9
  64. static int pane, pane_positions[PANECOUNT], pane_pos;
  65. static word32 data_dump_origin, data_dump_last, data_dump_size;
  66. static word32 code_dump_origin, code_dump_last;
  67. static word32 *code_pane_pos, *stack_dump_pos;
  68. static int stack_dump_origin, stack_dump_last, stack_dump_more;
  69. static int breakpoint_origin;
  70. static char **whereis_pane_text;
  71. static int whereis_text_count, whereis_origin;
  72. static int code_pane_active;
  73. static int npx_pane_active;
  74. static int stack_pane_active;
  75. static int info_pane_active;
  76. static int whereis_pane_active;
  77.  
  78. /* Odds and ends.  */
  79. #define MAXINSTLEN 16
  80. static int first_step;
  81. static word32 main_entry;
  82. static char *read_buffer;
  83. NPX npx; /* non-static because declared so in "npx.h" */
  84. static void redraw (int);
  85. static char hexchars[] = "0123456789abcdef";
  86. /* ---------------------------------------------------------------------- */
  87. /* The presentation order of registers in the register pane.  The three
  88.    tables must of course match.     */
  89.  
  90. static char *regs_names[] = {
  91.   "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
  92.   "cs",     "ds",    "es",  "fs",  "gs",  "ss",
  93.   "eip", "flg" };
  94.  
  95. static word32 *regs_addr[] = {
  96.   &a_tss.tss_eax, &a_tss.tss_ebx, &a_tss.tss_ecx, &a_tss.tss_edx,
  97.   &a_tss.tss_esi, &a_tss.tss_edi, &a_tss.tss_ebp, &a_tss.tss_esp,
  98.   (word32 *)&a_tss.tss_cs, (word32 *)&a_tss.tss_ds,
  99.   (word32 *)&a_tss.tss_es, (word32 *)&a_tss.tss_fs,
  100.   (word32 *)&a_tss.tss_gs, (word32 *)&a_tss.tss_ss,
  101.   &a_tss.tss_eip, &a_tss.tss_eflags };
  102.  
  103. /* g: general, !: special, s: segment, f: flags, \0: end-of-table */
  104. static char regs_type[] = "ggggggg!ssssss!f";
  105. /* ---------------------------------------------------------------------- */
  106. /* Breakpoint data.  When breakpoints are actually put into the cpu debug
  107.    registers, data breakpoints have first priority.  Any code breakpoints
  108.    left over are set by patching the code to contain "Int 3".  */
  109. typedef enum { BP_Code = 0, BP_Write = 1, BP_Read = 3 } BP_TYPE;
  110.  
  111. typedef struct
  112. {
  113.   word32 addr;
  114.   BP_TYPE type;
  115.   unsigned char length;          /* 1, 2, or 4 bytes */
  116.   unsigned char saved;
  117.   unsigned char savedbyte;    /* Patched-away byte. */
  118. } BP_ENTRY;
  119.  
  120. static int breakpoint_count;
  121. static BP_ENTRY *breakpoint_table;
  122. static unsigned char int03 = 0xcc;
  123. /* ---------------------------------------------------------------------- */
  124. /* Store the contents of the NPX in the global variable `npx'.  */
  125. static void
  126. save_npx (void)
  127. {
  128. asm(                  "\n\
  129.     inb    $0xa0,%al      \n\
  130.     testb    $0x20,%al      \n\
  131.     jz    Lfclex_done    \n\
  132.     xorl    %eax,%eax      \n\
  133.     outb    %al,$0xf0      \n\
  134.     movb    $0x20,%al      \n\
  135.     outb    %al,$0xa0      \n\
  136.     outb    %al,$0x20      \n\
  137. Lfclex_done:               \n\
  138.     movl    $_npx, %eax    \n\
  139.     fnsave    (%eax)           \n\
  140.     fwait               "
  141.     );
  142. }
  143. /* ---------------------------------------------------------------------- */
  144. /* Reload the contents of the NPX from the global variable `npx'.  */
  145. static void
  146. load_npx (void)
  147. {
  148. asm(                                       "\n\
  149.     movl    $_npx, %eax                        \n\
  150. /*    movb    $0,4(%eax)  */        /* clear pending exceptions */    \n\
  151.     frstor    (%eax)                            "
  152.     );
  153. /* At least on my 486 there is no need to clear pending exceptions.  */
  154. }
  155. /* ---------------------------------------------------------------------- */
  156. inline static void
  157. put (int x, int y, unsigned char *txt)
  158. {
  159.   unsigned char *p
  160.     = (unsigned char *)(debug_screen_save + 3) + 2 * (cols * y + x);
  161.   while (*txt)
  162.     *p++ = *txt++,
  163.     *p++ = screen_attr;
  164. }
  165. /* ---------------------------------------------------------------------- */
  166. inline static void
  167. putl (int x, int y, int l, unsigned char *txt)
  168. {
  169.   unsigned char *p
  170.     = (unsigned char *)(debug_screen_save + 3) + 2 * (cols * y + x);
  171.   while (*txt && l > 0)
  172.     *p++ = *txt++,
  173.     *p++ = screen_attr,
  174.     l--;
  175.   while (l-- > 0)
  176.     *p++ = ' ',
  177.     *p++ = screen_attr;
  178. }
  179. /* ---------------------------------------------------------------------- */
  180. inline static void
  181. draw (int x, int y, unsigned char ch, int delta, int count)
  182. {
  183.   short unsigned *p
  184.     = (short unsigned *)(debug_screen_save + 3) + (cols * y + x);
  185.   short unsigned attrch = ((unsigned)screen_attr << 8) + ch;
  186.   while (count--)
  187.     *p = attrch,
  188.     p += delta;
  189. }
  190. /* ---------------------------------------------------------------------- */
  191. static void
  192. highlight (int x, int y, int len)
  193. {
  194.   unsigned short *p
  195.     = (unsigned short *)(debug_screen_save + 4) + (cols * y + x);
  196.   while (len--)
  197.     *(unsigned char *)p = screen_attr,
  198.     p++;
  199. }
  200. /* ---------------------------------------------------------------------- */
  201. static void
  202. frame (int x1, int y1, int x2, int y2)
  203. {
  204.   draw (x1 + 1, y1, '─', 1,    x2 - x1 - 1);
  205.   draw (x1 + 1, y2, '─', 1,    x2 - x1 - 1);
  206.   draw (x1, y1 + 1, '│', cols, y2 - y1 - 1);
  207.   draw (x2, y1 + 1, '│', cols, y2 - y1 - 1);
  208.   put (x1, y1, "┌");
  209.   put (x2, y1, "┐");
  210.   put (x1, y2, "└");
  211.   put (x2, y2, "┘");
  212. }
  213. /* ---------------------------------------------------------------------- */
  214. static void
  215. put_screen (char *screen)
  216. {
  217.   switch (*screen++)
  218.     {
  219.     case 0:
  220.       /* Text screen.  */
  221.       ScreenSetCursor (screen[0], screen[1]);
  222.       ScreenUpdate (screen + 2);
  223.       break;
  224.     }
  225. }
  226. /* ---------------------------------------------------------------------- */
  227. static char *
  228. get_screen ()
  229. {
  230.   char *p;
  231.   int r, c;
  232.  
  233.   p = malloc (cols * rows * 2 + 3);
  234.   ScreenGetCursor (&r, &c);
  235.   p[0] = 0;
  236.   p[1] = r;
  237.   p[2] = c;
  238.   ScreenRetrieve (p + 3);
  239.   return p;
  240. }
  241. /* ---------------------------------------------------------------------- */
  242. /* Display the debugger screen (if not already displayed).  */
  243. static void
  244. debug_screen ()
  245. {
  246.   if (!debug_screen_p)
  247.     {
  248.       user_screen_save = get_screen ();
  249.       put_screen (debug_screen_save);
  250.       debug_screen_p = 1;
  251.     }
  252. }
  253. /* ---------------------------------------------------------------------- */
  254. /* Display the user screen (if not already displayed).  */
  255. static void
  256. user_screen ()
  257. {
  258.   if (debug_screen_p)
  259.     {
  260.       put_screen (user_screen_save);
  261.       free (user_screen_save);
  262.       debug_screen_p = 0;
  263.     }
  264. }
  265. /* ---------------------------------------------------------------------- */
  266. /* Reportedly, `sleep' & `gettimeofday' are buggy under Dpmi -- emulate.  */
  267. static int
  268. mysleep (int secs)
  269. {
  270.   struct time now;
  271.   unsigned now100, then100;
  272.  
  273.   gettime (&now);
  274.   then100
  275.     = ((now.ti_hour * 60 + now.ti_min) * 60 + now.ti_sec + secs) * 100
  276.       + now.ti_hund;
  277.   do
  278.     {
  279.       gettime (&now);
  280.       now100 = ((now.ti_hour * 60 + now.ti_min) * 60 + now.ti_sec) * 100
  281.     + now.ti_hund;
  282.       if (now100 < 100 || bioskey (1))
  283.     break; /* Day turnover */
  284.     }
  285.   while (now100 < then100);
  286.   return 0;
  287. }
  288. /* ---------------------------------------------------------------------- */
  289. /* Display a message in CLASS using FMT and ... as printf parameters.
  290.    The class determines the colour of the message and for how long time
  291.    it is displayed.  */
  292.  
  293. typedef enum { CL_Info, CL_Msg, CL_Error } CL_TYPE;
  294.  
  295. static void
  296. message (CL_TYPE class, char *fmt, ...)
  297. {
  298.   char *save, *buf = alloca (cols);
  299.   unsigned char saveattr = screen_attr;
  300.   int len, y = rows / 2;
  301.  
  302.   vsprintf (buf, fmt, (&fmt) + 1);
  303.   len = strlen (buf);
  304.   save = debug_screen_save;
  305.   debug_screen_save = get_screen ();
  306.   switch (class)
  307.     {
  308.     case CL_Error:
  309.       screen_attr = screen_attr_error;
  310.       break;
  311.     default:
  312.       screen_attr = screen_attr_message;
  313.     }
  314.   frame (1, y - 1, cols - 2, y + 1);
  315.   draw (2, y, ' ', 1, cols - 4);
  316.   put ((cols - len) / 2, y, buf);
  317.   screen_attr = saveattr;
  318.   put_screen (debug_screen_save);
  319.   switch (class)
  320.     {
  321.     case CL_Info:
  322.       mysleep (2);
  323.       break;
  324.     case CL_Msg:
  325.     case CL_Error:
  326.       (void) getxkey ();
  327.     }
  328.   free (debug_screen_save);
  329.   debug_screen_save = save;
  330.   put_screen (debug_screen_save);
  331. }
  332. /* ---------------------------------------------------------------------- */
  333. /* Read a string from the keyboard to `read_buffer'.  The entry is started
  334.    with STARTTEXT.  */
  335. static int
  336. read_string (char *starttext)
  337. {
  338.   char *save;
  339.   int key, esc, pos, leave = 0, y = rows / 2;
  340.  
  341.   save = debug_screen_save;
  342.   debug_screen_save = get_screen ();
  343.   strcpy (read_buffer, starttext);
  344.   pos = strlen (read_buffer);
  345.  
  346.   frame (1, y - 1, cols - 2, y + 1);
  347.   do
  348.     {
  349.       draw (2, y, ' ', 1, cols - 4);
  350.       put (3, y, read_buffer);
  351.       pos = strlen (read_buffer);
  352.       put_screen (debug_screen_save);
  353.       ScreenSetCursor (y, 3 + pos);
  354.       key = getxkey ();
  355.       switch (key)
  356.     {
  357.     case K_Return:
  358.       leave = 1;
  359.       esc = 0;
  360.       break;
  361.     case K_Escape:
  362.       leave = 1;
  363.       esc = 1;
  364.       read_buffer[0] = '\0';
  365.       break;
  366.     case K_BackSpace:
  367.       if (pos > 0)
  368.         read_buffer[--pos] = '\0';
  369.       break;
  370.     default:
  371.       if (key >= ' ' && key <= 0xff && pos <= cols - 7)
  372.         {
  373.           read_buffer[pos++] = key & 0xff;
  374.           read_buffer[pos] = '\0';
  375.         }
  376.     }
  377.     }
  378.   while (!leave);
  379.   free (debug_screen_save);
  380.   debug_screen_save = save;
  381.   put_screen (debug_screen_save);
  382.   return esc;
  383. }
  384. /* ---------------------------------------------------------------------- */
  385. static int
  386. eval (char *expr, int *okp)
  387. {
  388.   word32 sym;
  389.  
  390.   sym = syms_name2val (expr);
  391.   if (undefined_symbol)
  392.     {
  393.       message (CL_Error, "Expression not understood");
  394.       return *okp = 0;
  395.     }
  396.   else
  397.     {
  398.       *okp = 1;
  399.       return (int) sym;
  400.     }
  401. }
  402. /* ---------------------------------------------------------------------- */
  403. static int
  404. read_eval (int *okp, char *starttext)
  405. {
  406.   *okp = !read_string (starttext);
  407.   if (*okp && read_buffer[0] != '\0')
  408.     return eval (read_buffer, okp);
  409.   else
  410.     return *okp = 0;
  411. }
  412. /* ---------------------------------------------------------------------- */
  413. static int
  414. valid_addr (word32 vaddr, int len)
  415. {
  416.   int a;
  417.  
  418.   if (vaddr >= 0xffffffffl - len)
  419.     return 0;
  420.   len--;
  421.   for (a = 0; a < MAX_AREA; a++)
  422.     if ((vaddr + len <= areas[a].last_addr) && (vaddr >= areas[a].first_addr))
  423.       return 1;
  424.   return 0;
  425. }
  426. /* ---------------------------------------------------------------------- */
  427. inline static int
  428. valid_instaddr (word32 vaddr)
  429. {
  430.   return valid_addr (vaddr, MAXINSTLEN);
  431. }
  432. /* ---------------------------------------------------------------------- */
  433. /* Set physical breakpoint registers from virtual ones.     */
  434. static void
  435. activate_breakpoints (void)
  436. {
  437.   int b, no;
  438.   BP_ENTRY *bep;
  439.  
  440.   no = 0;
  441.   edi.dr[7] = 0;
  442.   /* First handle data breakpoints.  */
  443.   for (b = 0, bep = breakpoint_table; b < breakpoint_count; b++, bep++)
  444.     if (no <= 3 && bep->type != BP_Code)
  445.       {
  446.     bep->saved = 0;
  447.     edi.dr[7] |= ((bep->type + ((bep->length - 1) << 2)) << (16 + 4 * no)
  448.               | (2 << (2 * no)));
  449.     edi.dr[no] = bep->addr + edi.app_base;
  450.     no++;
  451.       }
  452.  
  453.   /* Now handle code breakpoint.  */
  454.   for (b = 0, bep = breakpoint_table; b < breakpoint_count; b++, bep++)
  455.     if (bep->type == BP_Code)
  456.       if (no <= 3)
  457.     {
  458.       bep->saved = 0;
  459.       edi.dr[7] |= ((BP_Code << (16 + 4 * no)) | (2 << (2 * no)));
  460.       edi.dr[no] = bep->addr + edi.app_base;
  461.       no++;
  462.       edi.dr[7] |= 0x00000300L;  /* For 386s we set GE & LE bits.  */
  463.     }
  464.       else
  465.     {
  466.       bep->saved = valid_addr (bep->addr, 1);
  467.       if (bep->saved)
  468.         {
  469.           read_child (bep->addr, &bep->savedbyte, 1);
  470.           write_child (bep->addr, &int03, 1);
  471.         }
  472.     }
  473. }
  474. /* ---------------------------------------------------------------------- */
  475. /* Un-patch code.  */
  476. static void
  477. deactivate_breakpoints (void)
  478. {
  479.   int b;
  480.   BP_ENTRY *bep;
  481.  
  482.   for (b = 0, bep = breakpoint_table; b < breakpoint_count; b++, bep++)
  483.     if (bep->saved)
  484.       write_child (bep->addr, &bep->savedbyte, 1);
  485. }
  486. /* ---------------------------------------------------------------------- */
  487. static int
  488. get_breakpoint (BP_TYPE type, int length, word32 addr)
  489. {
  490.   int b;
  491.  
  492.   for (b = 0; b < breakpoint_count; b++)
  493.     if (breakpoint_table[b].type == type
  494.     && breakpoint_table[b].length == length
  495.     && breakpoint_table[b].addr == addr)
  496.       return b;
  497.   return -1;
  498. }
  499. /* ---------------------------------------------------------------------- */
  500. static void
  501. reset_breakpoint (int b)
  502. {
  503.   breakpoint_table[b] = breakpoint_table[--breakpoint_count];
  504.   breakpoint_table
  505.     = realloc (breakpoint_table, breakpoint_count * sizeof (BP_ENTRY));
  506. }
  507. /* ---------------------------------------------------------------------- */
  508. static int
  509. set_breakpoint (BP_TYPE type, int length, word32 addr)
  510. {
  511.   int b;
  512.  
  513.   b = breakpoint_count;
  514.   breakpoint_table
  515.     = realloc (breakpoint_table, ++breakpoint_count * sizeof (BP_ENTRY));
  516.   breakpoint_table[b].addr = addr;
  517.   breakpoint_table[b].type = type;
  518.   breakpoint_table[b].length = length;
  519.   return b;
  520. }
  521. /* ---------------------------------------------------------------------- */
  522. /* From ORIGIN skip COUNT instructions forward (positive count) or
  523.    backwards (negative count).    Backwards skipping cannot be assumed to
  524.    be working 100% perfectly, but in the presense of debug information
  525.    it is probably very, very close.
  526.  
  527.    This function works poorly close to the extremes of segments.  */
  528.  
  529. static int
  530. code_skip (int origin, int count)
  531. {
  532.   int len, *next, i, j, k, instcount, done, leave;
  533.   char *state, *inst, *source;
  534.  
  535.   if (count >= 0)
  536.     {
  537.       while (count-- > 0)
  538.     if (valid_instaddr (origin))
  539.       {
  540.         (void) unassemble_proper (origin, &len);
  541.         origin += len;
  542.       }
  543.     else
  544.       origin ++;
  545.       return origin;
  546.     }
  547.   else
  548.     {
  549.       count = -count;
  550.       instcount = MAXINSTLEN * (count + 16) + 1;
  551.       next = alloca (instcount * sizeof (int));
  552.       memset (next, 0, instcount * sizeof (int));
  553.       state = alloca (instcount * sizeof (char));
  554.       memset (state, 0, instcount * sizeof (char));
  555.  
  556.       done = 0;
  557.       do
  558.     {
  559.       for (i = 0; i < 2 * count; i++)
  560.         {
  561.           done++;
  562.           j = origin - done;
  563.           if (valid_instaddr (j))
  564.         {
  565.           inst = unassemble_proper (j, &len);
  566.           source = unassemble_source (j);
  567.           next[done] = j + len;
  568.           if (source)
  569.             {
  570.               leave = 0;
  571.               k = done;
  572.               while (j < origin && state[k] == 0 && !leave)
  573.             {
  574.               state[j++,k--] = 2;
  575.               while (len-- > 1)
  576.                 state[j++,k--] = 3;
  577.               /* Since code and data is "never" mixed in 32 bit
  578.                  code we don't need this.  */
  579. #if 0
  580.               leave = (strncmp (inst, "jmp", 3) == 0
  581.                    || strncmp (inst, "ret", 3) == 0
  582.                    || strncmp (inst, "iret", 4) == 0);
  583. #endif
  584.               if (!leave)
  585.                 inst = unassemble_proper (j, &len);
  586.             }
  587.             }
  588.         }
  589.           else
  590.         {
  591.           state[done] = 2;
  592.           next[done] = j + 1;
  593.         }
  594.         }
  595.       j = 1;
  596.       k = count;
  597.       while (k > 0 && j <= done && state[j] >= 2)
  598.         if (state[j++] == 2)
  599.           k--;
  600.     }
  601.       while (k > 0 && done + 2 * count <= instcount);
  602.       if (k == 0)
  603.     return origin - j + 1;
  604.       else
  605.     {
  606.       i = origin;
  607.       k = 0;
  608.       while (count > 0 && k <= done)
  609.         {
  610.           leave = 0;
  611.           j = MAXINSTLEN;
  612.           while (!leave && j > 1)
  613.         if (j + k <= done && next[j + k] == i)
  614.           leave = 1;
  615.         else
  616.           j--;
  617.           if (!leave)
  618.         i--, k++;
  619.           else
  620.         i -= j, k += j;
  621.           count--;
  622.         }
  623.       return i;
  624.     }
  625.     }
  626. }
  627. /* ---------------------------------------------------------------------- */
  628. static void
  629. code_pane_goto (word32 v)
  630. {
  631.   int i = 0;
  632.  
  633.   if (v >= code_dump_origin && v <= code_dump_last)
  634.     {
  635.       while (code_pane_pos[i] < v)
  636.     i++;
  637.       if (code_pane_pos [i] == code_pane_pos[i+1])
  638.     i++;
  639.     }
  640.   else
  641.     {
  642.       code_dump_origin = v;
  643.       if (valid_instaddr (v) && unassemble_source (v) != NULL)
  644.     i++;
  645.     }
  646.   if (pane == 0)
  647.     pane_pos = i;
  648.   else
  649.     pane_positions[0] = i;
  650. }
  651. /* ---------------------------------------------------------------------- */
  652. inline static void
  653. go (int bp)
  654. {
  655.   if (bp) activate_breakpoints ();
  656.   run_child ();
  657.   if (bp) deactivate_breakpoints ();
  658. }
  659. /* ---------------------------------------------------------------------- */
  660. static void
  661. step (int kind)
  662. {
  663.   int i, b, len, terminated, int03hit, refmem;
  664.   char *inst;
  665.  
  666.   switch (kind)
  667.     {
  668.     case 0:
  669.       inst = unassemble_proper (a_tss.tss_eip, &len);
  670.       if (strcmp (inst, "popf") == 0 || strcmp (inst, "pushf") == 0)
  671.     kind = 1;  /* Push the right value of eflags (no trace flag).  */
  672.       break;
  673.     case 1:
  674.       if (first_step)
  675.     kind = 3;
  676.       else
  677.     {
  678.       inst = unassemble_proper (a_tss.tss_eip, &len);
  679.       if (strncmp (inst, "loop", 4)
  680.           && strncmp (inst, "call", 4)
  681.           && strncmp (inst, "int", 3) )
  682.         kind = 0;
  683.       break;
  684.     }
  685.     }
  686.   switch (kind)
  687.     {
  688.     case 0: /* "Trace" */
  689.       a_tss.tss_eflags |= 0x0100;
  690.       edi.dr[7] = 0;
  691.       refmem = strchr (inst, '[') != 0;
  692.       if (refmem)
  693.     /* Assume that all access to code and stack segments are safe.
  694.        This should hold unless you do something extra-ordinary dirty.  */
  695.     if (((a_tss.tss_ds == a_tss.tss_cs) || (a_tss.tss_ds == a_tss.tss_ss))
  696.         &&
  697.         ((a_tss.tss_es == a_tss.tss_cs) || (a_tss.tss_es == a_tss.tss_ss))
  698.         &&
  699.         ((a_tss.tss_fs == a_tss.tss_cs) || (a_tss.tss_fs == a_tss.tss_ss)
  700.          || (strstr (inst, "fs:") == 0))
  701.         &&
  702.         ((a_tss.tss_gs == a_tss.tss_cs) || (a_tss.tss_gs == a_tss.tss_ss)
  703.          || (strstr (inst, "gs:") == 0)))
  704.       refmem = 0;
  705.       if (refmem)
  706.     user_screen ();
  707.       go (0);
  708.       a_tss.tss_eflags &= ~0x0100;
  709.       break;
  710.     case 1: /* "Step Over" */
  711.       user_screen ();
  712.       b = set_breakpoint (BP_Code, 0, a_tss.tss_eip + len);
  713.       go (1);
  714.       reset_breakpoint (b);
  715.       break;
  716.     case 2: /* "Run" */
  717.       user_screen ();
  718.       go (1);
  719.       break;
  720.     case 3: /* "Run to `_main'" */
  721.       b = set_breakpoint (BP_Code, 0, main_entry);
  722.       user_screen ();
  723.       go (1);
  724.       reset_breakpoint (b);
  725.     }
  726.   first_step = 0;
  727.   i = a_tss.tss_irqn;
  728.   terminated = (i == 0x21) && (a_tss.tss_eax & 0xff00) == 0x4c00;
  729.   int03hit = (i == 0x03) && get_breakpoint (BP_Code, 0, a_tss.tss_eip) != -1;
  730.   if (terminated)
  731.     a_tss.tss_eip -= 2;     /* point back to Int 21h */
  732.   else if (int03hit)
  733.     a_tss.tss_eip--;     /* point back to Int 3 */
  734.   code_pane_goto (a_tss.tss_eip);
  735.   debug_screen ();
  736.   redraw (0);
  737.   if (terminated)
  738.     message (CL_Msg, "Program terminated normally, exit code is %d",
  739.          (word8)a_tss.tss_eax);
  740.   else if (i == 1 || int03hit)
  741.     {
  742.       int b, no;
  743.  
  744.       no = -1;
  745.       for (b = 0; no == -1 && b <= 3; b++)
  746.     if ((edi.dr[6] & (1 << b)) && (edi.dr[7] & (3 << (b * 2))))
  747.       no = b;
  748.       if (no != -1)
  749.     no = get_breakpoint ((edi.dr[7] >> (16 + 4 * no)) & 3,
  750.                  ((edi.dr[7] >> (18 + 4 * no)) & 3) + 1,
  751.                  edi.dr[no] - edi.app_base);
  752.       else if (int03hit)
  753.     no = get_breakpoint (BP_Code, 0, a_tss.tss_eip);
  754.       if (no != -1)
  755.     switch (breakpoint_table[no].type)
  756.       {
  757.       case BP_Code:
  758.         message (CL_Info, "Code breakpoint hit");
  759.         break;
  760.       case BP_Write:
  761.         message (CL_Msg, "Data write breakpoint at 0x%08lx triggered by previous instruction",
  762.              breakpoint_table[no].addr);
  763.         break;
  764.       case BP_Read:
  765.         message (CL_Msg, "Data read/write breakpoint at 0x%08lx triggered by previous instruction",
  766.              breakpoint_table[no].addr);
  767.         break;
  768.       }
  769.     }
  770.   else if (i == 0x79)
  771.     message (CL_Info, "Keyboard interrupt");
  772.   else if (i == 0x75)
  773.     {
  774.       char *reason;
  775.  
  776.       save_npx ();
  777.       if ((npx.status & 0x0241) == 0x0241)
  778.     reason = "stack overflow";
  779.       else if ((npx.status & 0x0241) == 0x0041)
  780.     reason = "stack underflow";
  781.       else if (npx.status & 1)
  782.     reason = "invalid operation";
  783.       else if (npx.status & 2)
  784.     reason = "denormal operand";
  785.       else if (npx.status & 4)
  786.     reason = "divide by zero";
  787.       else if (npx.status & 8)
  788.     reason = "overflow";
  789.       else if (npx.status & 16)
  790.     reason = "underflow";
  791.       else if (npx.status & 32)
  792.     reason = "loss of precision";
  793.       else
  794.     reason = "?";
  795.       message (CL_Error,
  796.            "Numeric Exception (%s) at eip=0x%08lx", reason, npx.eip);
  797.       load_npx ();
  798.     }
  799.   else if (i == 8 || (i >= 10 && i <= 14))
  800.     message (CL_Error, "Exception %d (0x%02x) occurred, error code=%#lx",
  801.          i, i, a_tss.tss_error);
  802.   else
  803.     message (CL_Error, "Exception %d (0x%02x) occurred", i, i);
  804. }
  805. /* ---------------------------------------------------------------------- */
  806. static void
  807. redraw (int first)
  808. {
  809.   char *buf = alloca (cols);
  810.  
  811.   debug_screen ();
  812.   screen_attr = ScreenAttrib = screen_attr_normal;
  813.  
  814.   if (first)
  815.     {
  816.       int y = toplines + 1, x1 = cols - 18, x2 = cols - 5, x3 = 46;
  817.  
  818.       frame (0, 0, cols - 1, rows - 1);
  819.       frame (x2, 0, cols - 1, y);
  820.       frame (x1, 0, x2, y);
  821.       frame (x3, y, cols - 1, rows - 1);
  822.       frame (0, y, x3, rows - 1);
  823.  
  824.       put (x2, 0, "┬");
  825.       put (x2, y, "┴");
  826.       put (0, y, "├");
  827.       put (cols - 1, y, "┤");
  828.       put (x1, 0, "┬");
  829.       put (x1, y, "┴");
  830.       put (x3, y, "┬");
  831.       put (x3, rows - 1, "┴");
  832.     }
  833.  
  834.   {
  835.     /* Show register status */
  836.     int reg, x = cols - 17, y = 1, width = 12;
  837.  
  838.     for (reg = 0; regs_type[reg]; reg++)
  839.       {
  840.     if (regs_type[reg] == 's')
  841.       sprintf (buf, " %s %04x",
  842.            regs_names[reg],
  843.            *(unsigned short *)(regs_addr[reg]));
  844.     else
  845.       sprintf (buf, "%s %08lx",
  846.            regs_names[reg],
  847.            *(regs_addr[reg]));
  848.     putl (x, y++, width, buf);
  849.       }
  850.     while (y <= toplines)
  851.       putl (x, y++, width, "");
  852.   }
  853.  
  854.   {
  855.     /* Show flags status */
  856.     int f, x = cols - 4, y = 1, width = 3;
  857.     static char flags[] = "c?p?a?zn?ido????";
  858.  
  859.     for (f = 0; flags[f]; f++)
  860.       if (flags[f] != '?')
  861.     {
  862.       sprintf (buf, "%c=%d", flags[f], (int)((a_tss.tss_eflags >> f) & 1));
  863.       put (x, y++, buf);
  864.     }
  865.     while (y <= toplines)
  866.       putl (x, y++, width, "");
  867.   }
  868.  
  869.   {
  870.     /* Show breakpoints */
  871.     int b, x = 47, y = toplines + 2, width = cols - 48;
  872.     char *name;
  873.     int32 delta;
  874.  
  875.     for (b = breakpoint_origin;
  876.      b < breakpoint_origin + bottomlines / 2 && b < breakpoint_count;
  877.      b++)
  878.       {
  879.     switch (breakpoint_table[b].type)
  880.       {
  881.       case BP_Code:
  882.         sprintf (buf, "Execute: %08lx",
  883.              breakpoint_table[b].addr);
  884.         break;
  885.       case BP_Write:
  886.         sprintf (buf, "Data write: %08lx, %d",
  887.              breakpoint_table[b].addr, breakpoint_table[b].length);
  888.         break;
  889.       case BP_Read:
  890.         sprintf (buf, "Data read: %08lx, %d",
  891.              breakpoint_table[b].addr, breakpoint_table[b].length);
  892.         break;
  893.       }
  894.     putl (x, y++, width, buf);
  895.  
  896.     name = syms_val2name (breakpoint_table[b].addr, &delta);
  897.     if (name[0] != '0')
  898.       if (delta && strlen (name) < width)
  899.         sprintf (buf, " %s+%#lx", name, delta);
  900.       else
  901.         sprintf (buf, " %-*s", width, name);
  902.     else
  903.       buf[0] = '\0';
  904.     putl (x, y++, width , buf);
  905.       }
  906.     if (breakpoint_count == 0)
  907.       putl (x, y++, width, "No breakpoints");
  908.     while (y < rows - 1)
  909.       putl (x, y++, width, "");
  910.   }
  911.  
  912.   {
  913.     /* Show data dump */
  914.     word32 p = data_dump_origin;
  915.     int b, x, y = toplines + 2, ok, width = 45;
  916.     unsigned char data[8], xpos[8];
  917.  
  918.     for (x = 0; x < 8; x++)
  919.       xpos[x] = 10
  920.     + ((data_dump_size == 1) ? (x * 3) :
  921.        ((data_dump_size == 2) ? ((x / 2) * 5 + (~x & 1) * 2) :
  922.         ((x / 4) * 9 + (~x & 3) * 2)));
  923.  
  924.     while (y < rows - 1)
  925.       {
  926.     if ((ok = valid_addr (p, 8)))
  927.       read_child (p, data, 8);
  928.  
  929.     sprintf (buf, "%08lx: %35s", p, "");
  930.     for (x = 0; x < 8; x++)
  931.       if (ok || valid_addr (p + x, 1))
  932.         {
  933.           if (!ok) read_child (p + x, data + x, 1);
  934.           buf[xpos[x]] = hexchars[data[x] >> 4];
  935.           buf[xpos[x] + 1] = hexchars[data[x] & 0xf];
  936.           buf[37 + x] = (data[x] ? data[x] : '.');
  937.         }
  938.       else
  939.         buf[xpos[x]] = buf[xpos[x + 1]] = buf[37 + x] = '?';
  940.     putl (1, y, width, buf);
  941.     
  942.     screen_attr = screen_attr_break;
  943.     for (x = 0; x < 8; x++)
  944.       for (b = 0; b < breakpoint_count; b++)
  945.         if (breakpoint_table[b].type != BP_Code
  946.         && p + x >= breakpoint_table[b].addr
  947.         && p + x < (breakpoint_table[b].addr 
  948.                 + breakpoint_table[b].length))
  949.           {
  950.         highlight (xpos[x] + 1, y, 2);
  951.         highlight (38 + x, y, 1);
  952.           }
  953.     screen_attr = screen_attr_normal;
  954.     p += 8;
  955.     y++;
  956.       }
  957.     data_dump_last = p - 1;
  958.   }
  959.  
  960.   if (code_pane_active)
  961.   {
  962.     /* Show code dump */
  963.     word32 p = code_dump_origin, width = cols - 19;
  964.     int y = 1, len, source = 0;
  965.     char *txt;
  966.  
  967.     while (y <= toplines)
  968.       {
  969.     source = !source;
  970.     code_pane_pos[y - 1] = p;
  971.     if (source)
  972.       {
  973.         txt = unassemble_source (p);
  974.         if (txt)
  975.           {
  976.         screen_attr = screen_attr_source;
  977.         putl (1, y++, width, txt);
  978.           }
  979.       }
  980.     else
  981.       {
  982.         if (valid_instaddr (p))
  983.           txt = unassemble_proper (p, &len);
  984.         else
  985.           txt = "?", len = 1;
  986.         sprintf (buf, "%08lx%c%s",
  987.              p,
  988.              p == a_tss.tss_eip ? 16 : ' ',
  989.              txt);
  990.         screen_attr =
  991.           (get_breakpoint (BP_Code, 0, p) == -1
  992.            ? screen_attr_normal : screen_attr_break);
  993.         putl (1, y++, width, buf);
  994.         p += len;
  995.       }
  996.       }
  997.     code_pane_pos[y - 1] = p + 1;
  998.     code_dump_last = p - 1;
  999.     screen_attr = screen_attr_normal;
  1000.   }
  1001.  
  1002.   if (npx_pane_active)
  1003.   {
  1004.     /* Show npx dump */
  1005.     int i, y = 1, width = cols - 19;
  1006.     static char *rtype[] = { "Near", "-Inf", "+Inf", "Zero" };
  1007.  
  1008.     save_npx ();
  1009.     sprintf (buf,
  1010.          "Control: %04lx PR=%s UN=%s OV=%s ZD=%s DN=%s IV=%s Rnd=%s",
  1011.          npx.control & 0xffff,
  1012.          (npx.control & (1 << 5)) ? "N" : "Y",
  1013.          (npx.control & (1 << 4)) ? "N" : "Y",
  1014.          (npx.control & (1 << 3)) ? "N" : "Y",
  1015.          (npx.control & (1 << 2)) ? "N" : "Y",
  1016.          (npx.control & (1 << 1)) ? "N" : "Y",
  1017.          (npx.control & (1 << 0)) ? "N" : "Y",
  1018.          rtype[(npx.control >> 10) & 3]);
  1019.     putl (1, y++, width, buf);
  1020.     sprintf (buf,
  1021.          "Status:  %04lx PR=%s UN=%s OV=%s ZD=%s DN=%s IV=%s ST=%s",
  1022.          npx.status & 0xffff,
  1023.          (npx.status & (1 << 5)) ? "Y" : "N",
  1024.          (npx.status & (1 << 4)) ? "Y" : "N",
  1025.          (npx.status & (1 << 3)) ? "Y" : "N",
  1026.          (npx.status & (1 << 2)) ? "Y" : "N",
  1027.          (npx.status & (1 << 1)) ? "Y" : "N",
  1028.          (npx.status & (1 << 0)) ? "Y" : "N",
  1029.          (npx.status & (1 << 6)) ? "Y" : "N");
  1030.     putl (1, y++, width, buf);
  1031.     sprintf (buf, "%19sC3=%d C2=%d C1=%d C0=%d",
  1032.          "",
  1033.          (npx.status & (1 << 14)) != 0,
  1034.          (npx.status & (1 << 10)) != 0,
  1035.          (npx.status & (1 <<  9)) != 0,
  1036.          (npx.status & (1 <<  8)) != 0);
  1037.     putl (1, y++, width, buf);
  1038.  
  1039.     for (i = 0; i < 8; i++)
  1040.       {
  1041.     /* We assume that `long double' is the same type as npx.reg[i].
  1042.        It would be sensible to check that the sizes match, but they
  1043.        don't!  For alignment reasons, `sizeof (long double)' is 12.     */
  1044.     long double d;
  1045.     int tag;
  1046.     int tos = (npx.status >> 11) & 7;
  1047.     int exp = (int)npx.reg[i].exponent - 16382;
  1048.     char *dstr = alloca (30);
  1049.  
  1050.     dstr[0] = (npx.reg[i].sign) ? '-' : '+';
  1051.     dstr[1] = '\0';
  1052.     tag = (npx.tag >> (((i + tos) & 7) * 2)) & 3;
  1053.     switch (tag)
  1054.       {
  1055.       case 0:
  1056.         if (abs (exp) < 1000)
  1057.           {
  1058.         d = *((long double*)(npx.reg + i));
  1059.         /* sprintf does not (djgpp 1.11m3) handle long doubles.     */
  1060.         sprintf(dstr,"%+.16g", (double) d);
  1061.           }
  1062.         else
  1063.           sprintf (dstr, "Valid, %s, and %s",
  1064.                npx.reg[i].sign ? "negative" : "positive",
  1065.                exp > 0 ? "huge" : "tiny");
  1066.         break;
  1067.       case 1:
  1068.         strcat (dstr, "Zero");
  1069.         break;
  1070.       case 2:
  1071.         if (npx.reg[i].exponent == 0x7fff)
  1072.           if (npx.reg[i].sig3 == 0x8000
  1073.           && npx.reg[i].sig2 == 0x0000
  1074.           && npx.reg[i].sig1 == 0x0000
  1075.           && npx.reg[i].sig0 == 0x0000)
  1076.         strcat (dstr, "Inf");
  1077.           else
  1078.         strcat (dstr, "NaN");
  1079.         else
  1080.           dstr = "Special";
  1081.         break;
  1082.       case 3:
  1083.         dstr = "Empty";
  1084.         break;
  1085.       }
  1086.     sprintf (buf, "st(%d): %d %04x %04x%04x%04x%04x %s",
  1087.          i,
  1088.          npx.reg[i].sign, npx.reg[i].exponent,
  1089.          npx.reg[i].sig3, npx.reg[i].sig2,
  1090.          npx.reg[i].sig1, npx.reg[i].sig0,
  1091.          dstr);
  1092.     putl (1, y++, width, buf);
  1093.       }
  1094.     while (y <= toplines)
  1095.       putl (1, y++, width, "");
  1096.     load_npx ();
  1097.   }
  1098.  
  1099.   if (stack_pane_active)
  1100.   {
  1101.     /* Show stack dump */
  1102.     int line, y = 1, no = -stack_dump_origin, width = cols - 19;
  1103.     unsigned char eipcode[4];
  1104.     word32 delta, v = a_tss.tss_ebp;
  1105.     word32 vaddr = a_tss.tss_eip;
  1106.  
  1107.     stack_dump_more = 0;
  1108.     while (valid_instaddr (vaddr))
  1109.       {
  1110.     if (no++ >= 0)
  1111.       if (y > toplines)
  1112.         {
  1113.           stack_dump_more = 1;
  1114.           break;
  1115.         }
  1116.       else
  1117.         {
  1118.           char *symaddr, *sourceaddr, *sourcefile;
  1119.           int len;
  1120.  
  1121.           symaddr = syms_val2name (vaddr, &delta);
  1122.           sourcefile = syms_val2line (vaddr, &line, 0);
  1123.           if (sourcefile)
  1124.         sprintf (sourceaddr = alloca (cols + strlen (sourcefile)),
  1125.              ", line %d in file %s", line, sourcefile);
  1126.           else if (delta)
  1127.         sprintf (sourceaddr = alloca (cols), "%+ld", (long) delta);
  1128.           else
  1129.         sourceaddr = "";
  1130.           len = 15 + strlen (symaddr) + strlen (sourceaddr);
  1131.           if (len >= cols)
  1132.         buf = alloca (len);
  1133.           sprintf (buf, "%08lx: %s%s", vaddr, symaddr, sourceaddr);
  1134.           stack_dump_pos[stack_dump_last = y - 1] = vaddr;
  1135.           putl (1, y++, width, buf);
  1136.         }
  1137.  
  1138.     read_child (vaddr, eipcode, 3);
  1139.     /* We look directly at the bit pattern instead of using disassembly;
  1140.        the bit patterns are those generated by gcc.     In general we
  1141.        cannot expect to be able to follow a non-gcc stack anyway.  */
  1142.     if ((eipcode[0] == 0x55 && eipcode[1] == 0x89 && eipcode[2] == 0xe5)
  1143.         || eipcode[0] == 0xc3)
  1144.       {
  1145.         /* In this case where we are looking at `Push Ebp//Mov Ebp,Esp'
  1146.            or `Ret', only the return address is on the stack; I believe
  1147.            this only to happen in the innermost activation record.    */
  1148.         if (valid_addr (a_tss.tss_esp, 4))
  1149.           read_child (a_tss.tss_esp, &vaddr, 4);
  1150.         else
  1151.           break;
  1152.       }
  1153.     else
  1154.       {
  1155.         if (eipcode[0] == 0x89 && eipcode[1] == 0xe5)
  1156.           /* When looking at `Mov Esp,Ebp' the next stack frame is on
  1157.          the stack and pointed to by the stack pointer.     We are
  1158.          actually in the same situation after `Mov Esp,Ebp' which
  1159.          is generated by gcc with the -m486 option.  This case is,
  1160.          however, handled perfectly by using the base pointer.    */
  1161.           v = a_tss.tss_esp;
  1162.         if (v >= a_tss.tss_esp && v < 0x80000000L && valid_addr (v, 8))
  1163.           {
  1164.         read_child (v + 4, &vaddr, 4);
  1165.         read_child (v, &v, 4);
  1166.           }
  1167.         else
  1168.           break;
  1169.       }
  1170.       }
  1171.     while (y <= toplines)
  1172.       putl (1, y++, width, "");
  1173.   }
  1174.  
  1175.   if (info_pane_active)
  1176.   {
  1177.     /* Show info */
  1178.     int y = 1, width = cols - 19;
  1179.     long ul;
  1180.     char *s;
  1181.     _go32_dpmi_meminfo info;
  1182.     _go32_dpmi_registers regs;
  1183.  
  1184.     sprintf (buf, "Debugger version ............: %.2f %s",
  1185.          FULLSCR_VERSION,
  1186.          FULLSCR_VERSION < 1.00 ? "beta" : "");
  1187.     putl (1, y++, width, buf);
  1188.     _go32_dpmi_get_free_memory_information (&info);
  1189.     switch (_go32_info_block.run_mode)
  1190.       {
  1191.       case _GO32_RUN_MODE_RAW:
  1192.     s = "Raw";
  1193.     break;
  1194.       case _GO32_RUN_MODE_XMS:
  1195.     s = "Xms";
  1196.     break;
  1197.       case _GO32_RUN_MODE_VCPI:
  1198.     s = "Vcpi";
  1199.     break;
  1200.       case _GO32_RUN_MODE_DPMI:
  1201.     s = alloca (20);
  1202.     sprintf (s, "Dpmi %d.%02x",
  1203.          _go32_info_block.run_mode_info >> 8,
  1204.          _go32_info_block.run_mode_info & 0xff);
  1205.     break;
  1206.       default:
  1207.     s = "Unknown";
  1208.       }
  1209.     sprintf (buf, "Running mode ................: %s", s);
  1210.     putl (1, y++, width, buf);
  1211.     putl (1, y++, width, "");
  1212.  
  1213.     ul = info.total_physical_pages;
  1214.     if (ul > 0)
  1215.       {
  1216.     ul <<= 12;
  1217.     sprintf (buf, "Total physical memory .......: %lu KB", ul >> 10);
  1218.     putl (1, y++, width, buf);
  1219.       }
  1220.     ul = info.available_physical_pages
  1221.       ? info.available_physical_pages << 12
  1222.     : info.available_memory;
  1223.     sprintf (buf, "Remaining physical memory ...: %lu KB", ul >> 10);
  1224.     putl (1, y++, width, buf);
  1225.     ul = info.available_memory;
  1226.     sprintf (buf, "Remaining virtual memory ....: %lu KB", ul >> 10);
  1227.     putl (1, y++, width, buf);
  1228.     ul = info.free_linear_space << 12;
  1229.     if (ul >= 0)
  1230.       {
  1231.     sprintf (buf, "Free linear space ...........: %ld KB", ul >> 10);
  1232.     putl (1, y++, width, buf);
  1233.       }
  1234.     /* Remember that Dos memory is only made available of direct request;
  1235.        using 0xffff does not count as a request.  */
  1236.     regs.h.ah = 0x48;
  1237.     regs.x.bx = 0xffff;
  1238.     regs.x.ss = regs.x.sp = 0;
  1239.     _go32_dpmi_simulate_int (0x21, ®s);
  1240.     ul = regs.x.bx << 4;
  1241.     sprintf (buf, "Free dos memory .............: %ld %s",
  1242.          ul > 8192 ? ul >> 10 : ul,
  1243.          ul > 8192 ? "KB"      : "Bytes");
  1244.     putl (1, y++, width, buf);
  1245.     putl (1, y++, width, "");
  1246.     sprintf (buf, "Ctrl-C checking .............: %s",
  1247.          getcbrk () ? "On" : "Off");
  1248.     putl (1, y++, width, buf);
  1249.     putl (1, y++, width, "");
  1250.  
  1251.     sprintf (buf, "Program text ................: %08lx - %08lx",
  1252.          areas[A_text].first_addr, areas[A_text].last_addr);
  1253.     putl (1, y++, width, buf);
  1254.     sprintf (buf, "Program data ................: %08lx - %08lx",
  1255.          areas[A_data].first_addr, areas[A_data].last_addr);
  1256.     putl (1, y++, width, buf);
  1257.     sprintf (buf, "Program bss .................: %08lx - %08lx",
  1258.          areas[A_bss].first_addr, areas[A_bss].last_addr);
  1259.     putl (1, y++, width, buf);
  1260.     sprintf (buf, "Program stack ...............: %08lx - %08lx",
  1261.          areas[A_stack].first_addr, areas[A_stack].last_addr);
  1262.     putl (1, y++, width, buf);
  1263.  
  1264.     while (y <= toplines)
  1265.       putl (1, y++, width, "");
  1266.   }
  1267.  
  1268.   if (whereis_pane_active)
  1269.   {
  1270.     /* Show result of last whereis command */
  1271.     int y = 1, width = cols - 19, i = whereis_origin;
  1272.  
  1273.     while (y <= toplines)
  1274.       if (i < whereis_text_count)
  1275.     putl (1, y++, width, whereis_pane_text[i++]);
  1276.       else
  1277.     putl (1, y++, width, "");
  1278.   }
  1279.  
  1280.   {
  1281.     /* Highlight focus */
  1282.     screen_attr = screen_attr_focus;
  1283.  
  1284.     switch (pane)
  1285.       {
  1286.       case 6: /* Stack */
  1287.     if (pane_pos > stack_dump_last)
  1288.       pane_pos = stack_dump_last;
  1289.     /* Fall through */
  1290.       case 0: /* Code */
  1291.       case 5: /* NPX */
  1292.     highlight (1, pane_pos + 1, cols - 19);
  1293.     break;
  1294.       case 1: /* Registers */
  1295.     highlight (cols - 17, pane_pos + 1, 12);
  1296.     break;
  1297.       case 2: /* Flags */
  1298.     highlight (cols - 4, pane_pos + 1, 3);
  1299.     break;
  1300.       case 3: /* Breakpoints */
  1301.     if (breakpoint_origin >= breakpoint_count)
  1302.       breakpoint_origin = breakpoint_count ? breakpoint_count - 1 : 0;
  1303.     if (breakpoint_origin + pane_pos >= breakpoint_count)
  1304.       pane_pos = breakpoint_count - breakpoint_origin;
  1305.     highlight (47, toplines + 2 + 2 * pane_pos, cols - 48);
  1306.     highlight (47, toplines + 3 + 2 * pane_pos, cols - 48);
  1307.     break;
  1308.       case 4: /* Data */
  1309.     {
  1310.       int x = pane_pos & 7, y = pane_pos >> 3;
  1311.  
  1312.       highlight (38 + x, toplines + 2 + y, data_dump_size);
  1313.       switch (data_dump_size)
  1314.         {
  1315.         case 1:
  1316.           highlight (11 + 3 * x, toplines + 2 + y, 2);
  1317.           break;
  1318.         case 2:
  1319.           highlight (11 + 5 * (x >> 1), toplines + 2 + y, 4);
  1320.           break;
  1321.         case 4:
  1322.           highlight (11 + 9 * (x >> 2), toplines + 2 + y, 8);
  1323.           break;
  1324.         }
  1325.     }
  1326.     break;
  1327.       case 8: /* Whereis */
  1328.     if (whereis_text_count)
  1329.       highlight (1, pane_pos + 1, cols - 19);
  1330.     break;
  1331.       }
  1332.   }
  1333.  
  1334.   put_screen (debug_screen_save);
  1335. }
  1336. /* ---------------------------------------------------------------------- */
  1337. static void
  1338. initialize ()
  1339. {
  1340.   int i;
  1341.  
  1342.   debug_screen_p = 0;
  1343.   cols = ScreenCols ();
  1344.   rows = ScreenRows ();
  1345.   if (cols < 80 || rows < 25)
  1346.     {
  1347.       fprintf (stderr, "\nDebugger error:\n\
  1348. There are only %d columns and %d rows\n\
  1349. in this display mode.\n\
  1350. The debugger needs at least\n\
  1351. 80 columns and 25 rows.\n",
  1352.            cols, rows);
  1353.       exit (1);
  1354.     }
  1355.   toplines = (rows / 2) + 4;
  1356.   bottomlines = rows - 3 - toplines;
  1357.   read_buffer = malloc (cols + 10);
  1358.   code_pane_pos = malloc ((toplines + 2) * sizeof (word32));
  1359.   stack_dump_pos = malloc ((toplines + 2) * sizeof (word32));
  1360.  
  1361.   debug_screen_save = get_screen ();
  1362.   debug_screen_save[1] = debug_screen_save[2] = 0;  /* Patch cursor pos.  */
  1363.  
  1364.   pane = 0;
  1365.   pane_pos = 0;
  1366.   for (i = 0; i < PANECOUNT; i++) pane_positions[i] = 0;
  1367.   data_dump_origin = areas[A_data].first_addr;
  1368.   data_dump_size = 1;
  1369.   code_dump_origin = a_tss.tss_eip;
  1370.   stack_dump_origin = 0;
  1371.   breakpoint_origin = 0;
  1372.   breakpoint_count = 0;
  1373.   breakpoint_table = malloc (breakpoint_count * sizeof (BP_ENTRY));
  1374.   whereis_origin = 0;
  1375.   whereis_text_count = 0;
  1376.   whereis_pane_text = malloc (whereis_text_count * sizeof (char *));
  1377.  
  1378.   code_pane_active = 1;
  1379.   npx_pane_active = stack_pane_active = info_pane_active
  1380.     = whereis_pane_active = 0;
  1381.  
  1382.   switch (ScreenMode ())
  1383.     {
  1384.     case 2:
  1385.     case 7:
  1386.       /* Mono */
  1387.       screen_attr_normal   = (A_black << 4) + A_grey;
  1388.       screen_attr_source   = screen_attr_normal;
  1389.       screen_attr_focus       = (A_grey  << 4) + A_black;
  1390.       screen_attr_break       = (A_black << 4) + A_white;
  1391.       screen_attr_message  = (A_grey  << 4) + A_white;
  1392.       screen_attr_error       = (A_grey  << 4) + A_white;
  1393.       break;
  1394.     default:
  1395.       /* Colour */
  1396.       screen_attr_normal   = (A_cyan  << 4) + A_blue;
  1397.       screen_attr_source   = (A_cyan  << 4) + A_black;
  1398.       screen_attr_focus       = (A_blue  << 4) + A_white;
  1399.       screen_attr_break       = (A_red   << 4) + A_white;
  1400.       screen_attr_message  = (A_green << 4) + A_white;
  1401.       screen_attr_error       = (A_red   << 4) + A_white;
  1402.     }
  1403.   redraw (1);
  1404.   message (CL_Info, "Sally Full Screen Debugger");
  1405. }
  1406. /* ---------------------------------------------------------------------- */
  1407. static void
  1408. code_pane_command (int key)
  1409. {
  1410.   int b;
  1411.  
  1412.   switch (key)
  1413.     {
  1414.     case K_Up:
  1415.     case K_EUp:
  1416.       if (pane_pos > 0)
  1417.     pane_pos--;
  1418.       else
  1419.     code_pane_goto (code_skip (code_dump_origin, -1));
  1420.       break;
  1421.     case K_Down:
  1422.     case K_EDown:
  1423.       if (pane_pos < toplines - 1)
  1424.     pane_pos++;
  1425.       else
  1426.     code_dump_origin =
  1427.       code_pane_pos[0] == code_pane_pos[1]
  1428.         ? code_pane_pos[2] : code_pane_pos[1];
  1429.       break;
  1430.     case K_PageUp:
  1431.     case K_EPageUp:
  1432.       code_dump_origin = code_skip (code_dump_origin, -toplines);
  1433.       break;
  1434.     case K_PageDown:
  1435.     case K_EPageDown:
  1436.       code_dump_origin = code_dump_last + 1;
  1437.       break;
  1438.     case K_Control_Left:
  1439.     case K_Control_ELeft:
  1440.       code_dump_origin--;
  1441.       break;
  1442.     case K_Control_Right:
  1443.     case K_Control_ERight:
  1444.       code_dump_origin++;
  1445.       break;
  1446.     case K_F2:
  1447.       b = get_breakpoint (BP_Code, 0, code_pane_pos[pane_pos]);
  1448.       if (b != -1)
  1449.     reset_breakpoint (b);
  1450.       else
  1451.     set_breakpoint (BP_Code, 0, code_pane_pos[pane_pos]);
  1452.       break;
  1453.     case K_F4:
  1454.       b = set_breakpoint (BP_Code, 0, code_pane_pos[pane_pos]);
  1455.       step (2);
  1456.       reset_breakpoint (b);
  1457.       break;
  1458.     case K_Control_O:
  1459.       code_pane_goto (a_tss.tss_eip);
  1460.       break;
  1461.     case K_Control_N:
  1462.       a_tss.tss_eip = code_pane_pos[pane_pos];
  1463.       break;
  1464.     case K_Control_G:
  1465.       {
  1466.     int ok, res;
  1467.     res = read_eval (&ok, "");
  1468.     if (ok)
  1469.       code_pane_goto (res);
  1470.     break;
  1471.       }
  1472.     }
  1473.   redraw (0);
  1474. }
  1475. /* ---------------------------------------------------------------------- */
  1476. static void
  1477. register_pane_command (int key)
  1478. {
  1479.   switch (key)
  1480.     {
  1481.     case K_Left:
  1482.     case K_ELeft:
  1483.     case K_Up:
  1484.     case K_EUp:
  1485.       if (pane_pos > 0) pane_pos--;
  1486.       break;
  1487.     case K_Right:
  1488.     case K_ERight:
  1489.     case K_Down:
  1490.     case K_EDown:
  1491.       if (regs_type[pane_pos + 1]) pane_pos++;
  1492.       break;
  1493.     default:
  1494.       if (key >= ' ' && key < 127)
  1495.     {
  1496.       int res, ok;
  1497.       char s[2];
  1498.  
  1499.       s[0] = key; s[1] = '\0';
  1500.       res = read_eval (&ok, key == '=' ? "" : s);
  1501.       if (ok)
  1502.         switch (regs_type[pane_pos])
  1503.           {
  1504.           case 's':
  1505.         *(unsigned short *)(regs_addr[pane_pos]) = res & 0xffff;
  1506.         break;
  1507.           case 'f':
  1508.         a_tss.tss_eflags = (a_tss.tss_eflags & ~0xed5) | (res & 0xed5);
  1509.         break;
  1510.           default:
  1511.         *regs_addr[pane_pos] = res;
  1512.           }
  1513.     }
  1514.     }
  1515.   redraw (0);
  1516. }
  1517. /* ---------------------------------------------------------------------- */
  1518. static void
  1519. flag_pane_command (int key)
  1520. {
  1521.   static unsigned flagbits[] =
  1522.     { 0x0001, 0x0004, 0x0010, 0x0040, 0x0080, 0x0200, 0x0400, 0x0800 };
  1523.  
  1524.   switch (key)
  1525.     {
  1526.     case K_Space:
  1527.     case '+':
  1528.     case '-':
  1529.     case 't':
  1530.     case 'T':
  1531.       a_tss.tss_eflags ^= flagbits[pane_pos];
  1532.       break;
  1533.     case '1':
  1534.     case 's':
  1535.     case 'S':
  1536.       a_tss.tss_eflags |= flagbits[pane_pos];
  1537.       break;
  1538.     case '0':
  1539.     case 'r':
  1540.     case 'R':
  1541.       a_tss.tss_eflags &= ~flagbits[pane_pos];
  1542.       break;
  1543.     case K_Left:
  1544.     case K_ELeft:
  1545.     case K_Up:
  1546.     case K_EUp:
  1547.       if (pane_pos > 0) pane_pos--;
  1548.       break;
  1549.     case K_Right:
  1550.     case K_ERight:
  1551.     case K_Down:
  1552.     case K_EDown:
  1553.       if (pane_pos < 7) pane_pos++;
  1554.       break;
  1555.     }
  1556.   redraw (0);
  1557. }
  1558. /* ---------------------------------------------------------------------- */
  1559. static void
  1560. breakpoint_pane_command (int key)
  1561. {
  1562.   int b = breakpoint_count ? pane_pos + breakpoint_origin : -1;
  1563.   int last = breakpoint_count && (b == breakpoint_count - 1);
  1564.  
  1565.   switch (key)
  1566.     {
  1567.     case K_Delete:
  1568.     case K_EDelete:
  1569.     case K_Control_C:
  1570.       if (b != -1)
  1571.     reset_breakpoint (b);
  1572.       if (!last)
  1573.     break;
  1574.       /* else fall through */
  1575.     case K_Left:
  1576.     case K_ELeft:
  1577.     case K_Up:
  1578.     case K_EUp:
  1579.       if (pane_pos > 0)
  1580.     pane_pos--;
  1581.       else
  1582.     if (breakpoint_origin > 0)
  1583.       breakpoint_origin--;
  1584.       break;
  1585.     case K_Right:
  1586.     case K_ERight:
  1587.     case K_Down:
  1588.     case K_EDown:
  1589.       if (!last)
  1590.     if (pane_pos < bottomlines / 2 - 1)
  1591.       pane_pos++;
  1592.     else
  1593.       breakpoint_origin++;
  1594.       break;
  1595.     case K_Control_G:
  1596.     case K_Return:
  1597.       if (b != -1)
  1598.     if (breakpoint_table[b].type == BP_Code)
  1599.       code_pane_goto (breakpoint_table[b].addr);
  1600.       break;
  1601.     }
  1602.   redraw (0);
  1603. }
  1604. /* ---------------------------------------------------------------------- */
  1605. static void
  1606. data_pane_command (int key)
  1607. {
  1608.   word32 v = data_dump_origin + pane_pos;
  1609.   BP_TYPE t;
  1610.   int b;
  1611.  
  1612.   switch (key)
  1613.     {
  1614.     case K_Up:
  1615.     case K_EUp:
  1616.       if (pane_pos >= 8)
  1617.     pane_pos -= 8;
  1618.       else
  1619.     data_dump_origin -= 8;
  1620.       break;
  1621.     case K_Down:
  1622.     case K_EDown:
  1623.       if (v + 8 <= data_dump_last)
  1624.     pane_pos += 8;
  1625.       else
  1626.     data_dump_origin += 8;
  1627.       break;
  1628.     case K_Left:
  1629.     case K_ELeft:
  1630.       if (pane_pos > 0)
  1631.     pane_pos -= data_dump_size;
  1632.       else
  1633.     data_dump_origin -= 8, pane_pos = 8 - data_dump_size;
  1634.       break;
  1635.     case K_Right:
  1636.     case K_ERight:
  1637.       if (v + data_dump_size <= data_dump_last)
  1638.     pane_pos += data_dump_size;
  1639.       else
  1640.     data_dump_origin += 8, pane_pos -= (8 - data_dump_size);
  1641.       break;
  1642.     case K_PageUp:
  1643.     case K_EPageUp:
  1644.       data_dump_origin -= (data_dump_last + 1 - data_dump_origin);
  1645.       break;
  1646.     case K_PageDown:
  1647.     case K_EPageDown:
  1648.       data_dump_origin = data_dump_last + 1;
  1649.       break;
  1650.     case K_Control_Left:
  1651.     case K_Control_ELeft:
  1652.       data_dump_origin--;
  1653.       break;
  1654.     case K_Control_Right:
  1655.     case K_Control_ERight:
  1656.       data_dump_origin++;
  1657.       break;
  1658.     case K_Control_S:
  1659.       data_dump_origin = a_tss.tss_esp;
  1660.       pane_pos = 0;
  1661.       break;
  1662.     case K_Control_C:
  1663.       data_dump_origin = a_tss.tss_eip;
  1664.       data_dump_size = 1;
  1665.       pane_pos = 0;
  1666.       break;
  1667.     case K_Control_B:
  1668.       data_dump_size = 1;
  1669.       break;
  1670.     case K_Control_W:
  1671.       data_dump_size = 2;
  1672.       break;
  1673.     case K_Control_L:
  1674.       data_dump_size = 4;
  1675.       break;
  1676.     case K_Alt_F2:
  1677.     case K_F2:
  1678.       t = key == K_F2 ? BP_Write : BP_Read;
  1679.       b = get_breakpoint (t, data_dump_size, v);
  1680.       if (b == -1)
  1681.     set_breakpoint (t, data_dump_size, v);
  1682.       else
  1683.     reset_breakpoint (b);
  1684.       break;
  1685.     case K_Control_G:
  1686.       {
  1687.     int ok, res;
  1688.     res = read_eval (&ok, "");
  1689.     if (ok)
  1690.       {
  1691.         data_dump_origin = res;
  1692.         pane_pos = 0;
  1693.       }
  1694.     break;
  1695.       }
  1696.     default:
  1697.       if (key >= ' ' && key < 127)
  1698.     {
  1699.       int res, ok, bad = 0;
  1700.       char s[2], *p, *p0, q;
  1701.  
  1702.       s[0] = key; s[1] = '\0';
  1703.       if (!read_string (key == '=' ? "" : s))
  1704.         {
  1705.           p = read_buffer;
  1706.           do
  1707.         {
  1708.           while (*p == ' ') p++;
  1709.           switch (*p)
  1710.             {
  1711.             case '\0':
  1712.               break;
  1713.             case '\'':
  1714.             case '"':
  1715.               if (data_dump_size != 1)
  1716.             {
  1717.               *p = 0;
  1718.               message (CL_Error,
  1719.                    "Strings must be entered in byte mode");
  1720.               break;
  1721.             }
  1722.               q = *p++;
  1723.               p0 = p;
  1724.               while (*p != q && *p) p++;
  1725.               if (*p)
  1726.             {
  1727.               while (p0 != p)
  1728.                 {
  1729.                   if (valid_addr (v, 1))
  1730.                 write_child (v, p0, 1);
  1731.                   else
  1732.                 bad = 1;
  1733.                   p0++, v++;
  1734.                 }
  1735.               if (q == '"')
  1736.                 {
  1737.                   if (valid_addr (v, 1))
  1738.                 write_child (v, s + 1, 1);
  1739.                   else
  1740.                 bad = 1;
  1741.                   v++;
  1742.                 }
  1743.               p++;
  1744.             }
  1745.               else
  1746.             message (CL_Error, "String constant not terminated");
  1747.               break;
  1748.             default:
  1749.               p0 = p;
  1750.               while (*p != ',' && *p) p++;
  1751.               q = *p;
  1752.               *p = 0;
  1753.               res = eval (p0, &ok);
  1754.               if (ok)
  1755.             {
  1756.               *p = q;
  1757.               if (valid_addr (v, data_dump_size))
  1758.                 write_child (v, &res, data_dump_size);
  1759.               else
  1760.                 bad = 1;
  1761.               v += data_dump_size;
  1762.             }
  1763.             }
  1764.           if (*p == ',') p++;
  1765.         }
  1766.           while (*p);
  1767.           if (bad)
  1768.         message (CL_Error, "Part of the data could not be written");
  1769.         }
  1770.     }
  1771.     }
  1772.   pane_pos &= ~(data_dump_size - 1);
  1773.   redraw (0);
  1774. }
  1775. /* ---------------------------------------------------------------------- */
  1776. static void
  1777. npx_pane_command (int key)
  1778. {
  1779.   int reg = pane_pos - 3, rotreg, tag;
  1780.   int regp = (reg >= 0);
  1781.  
  1782.   save_npx ();
  1783.   if (regp)
  1784.     {
  1785.       rotreg = (reg + (npx.status >> 11)) & 7;
  1786.       tag = (npx.tag >> (rotreg * 2)) & 3;
  1787.     }
  1788.  
  1789.   switch (key)
  1790.     {
  1791.     case K_Left:
  1792.     case K_ELeft:
  1793.     case K_Up:
  1794.     case K_EUp:
  1795.       if (pane_pos > 0) pane_pos--;
  1796.       break;
  1797.     case K_Right:
  1798.     case K_ERight:
  1799.     case K_Down:
  1800.     case K_EDown:
  1801.       if (pane_pos < 10) pane_pos++;
  1802.       break;
  1803.     case K_Control_C:
  1804.     case K_Control_E:
  1805.     case K_Delete:
  1806.     case K_EDelete:
  1807.       if (regp)
  1808.     {
  1809.       tag = 3;
  1810.       memset (&npx.reg[reg], 0, sizeof (NPXREG));
  1811.     }
  1812.       break;
  1813.     case K_Control_Z:
  1814.       if (regp)
  1815.     {
  1816.       tag = 1;
  1817.       memset (&npx.reg[reg], 0, sizeof (NPXREG));
  1818.     }
  1819.       break;
  1820.     case K_Control_N:
  1821.       if (regp)
  1822.     npx.reg[reg].sign = !npx.reg[reg].sign;
  1823.       break;
  1824.     default:
  1825.       if (regp && key >= ' ' && key < 127)
  1826.     {
  1827.       char s[2], *endp, *p;
  1828.       double d;
  1829.  
  1830.       s[0] = key; s[1] = '\0';
  1831.       if (!read_string (key == '=' ? "" : s) && read_buffer[0] != '\0')
  1832.         {
  1833.           p = read_buffer;
  1834.           while (*p == ' ')
  1835.         p++;
  1836.           if (*p == '\0')
  1837.         break;
  1838.           strlwr (p);
  1839.           if (strcmp (p, "+inf") == 0
  1840.           || strcmp (p, "inf") == 0
  1841.           || strcmp (p, "-inf") == 0)
  1842.         {
  1843.           tag = 2;
  1844.           npx.reg[reg].exponent = 0x7fff;
  1845.           npx.reg[reg].sig3 = 0x8000;
  1846.           npx.reg[reg].sig2
  1847.             = npx.reg[reg].sig1
  1848.               = npx.reg[reg].sig0 = 0;
  1849.           npx.reg[reg].sign = (*p == '-');
  1850.         }
  1851.           else
  1852.         {
  1853.           d = strtod (p, &endp);
  1854.           if (*p != '\0' && *endp)
  1855.             message (CL_Error, "Expression not understood");
  1856.           else
  1857.             {
  1858.               tag = (d == 0.0);
  1859.               *((long double *)(npx.reg + reg)) = (long double) d;
  1860.               npx.reg[reg].sign = (*p == '-'); /* for -Zero */
  1861.             }
  1862.         }
  1863.         }
  1864.     }
  1865.     }
  1866.   if (regp)
  1867.     npx.tag = (npx.tag & ~(3 << (rotreg * 2))) | (tag << (rotreg * 2));
  1868.   load_npx ();
  1869.   redraw (0);
  1870. }
  1871. /* ---------------------------------------------------------------------- */
  1872. static void
  1873. stack_pane_command (int key)
  1874. {
  1875.   switch (key)
  1876.     {
  1877.     case K_Left:
  1878.     case K_ELeft:
  1879.     case K_Up:
  1880.     case K_EUp:
  1881.       if (pane_pos > 0)
  1882.     pane_pos--;
  1883.       else
  1884.     if (stack_dump_origin)
  1885.       stack_dump_origin--;
  1886.       break;
  1887.     case K_Right:
  1888.     case K_ERight:
  1889.     case K_Down:
  1890.     case K_EDown:
  1891.       if (pane_pos < stack_dump_last)
  1892.     pane_pos++;
  1893.       else
  1894.     if (stack_dump_more)
  1895.       stack_dump_origin++;
  1896.       break;
  1897.     case K_Return:
  1898.       code_pane_goto (stack_dump_pos[pane_pos]);
  1899.       stack_pane_active = 0;
  1900.       code_pane_active = 1;
  1901.       pane = 0;
  1902.       break;
  1903.     }
  1904.   redraw (0);
  1905. }
  1906. /* ---------------------------------------------------------------------- */
  1907. static void
  1908. info_pane_command (int key)
  1909. {
  1910.   /* No keys recognized.  */
  1911.   redraw (0);
  1912. }
  1913. /* ---------------------------------------------------------------------- */
  1914. static void
  1915. fullscr_listwild_handler (word32 addr, char typ, char *name,
  1916.               char *filename, int linenum)
  1917. {
  1918.   char *s;
  1919.  
  1920.   s = alloca (cols + strlen (name) + (filename ? strlen (filename) : 0));
  1921.   sprintf (s, "0x%08lx %c %s", addr, typ, name);
  1922.   if (filename)
  1923.     sprintf (s + strlen (s), ", line %d of %s", linenum, filename);
  1924.   whereis_pane_text = realloc (whereis_pane_text,
  1925.                    (++whereis_text_count) * sizeof (char *));
  1926.   whereis_pane_text[whereis_text_count - 1] = strdup (s);
  1927. }
  1928.  
  1929. static void
  1930. whereis_pane_command (int key)
  1931. {
  1932.   int no = whereis_origin + pane_pos;
  1933.  
  1934.   switch (key)
  1935.     {
  1936.     case K_Left:
  1937.     case K_ELeft:
  1938.     case K_Up:
  1939.     case K_EUp:
  1940.       if (pane_pos > 0)
  1941.     pane_pos--;
  1942.       else
  1943.     if (whereis_origin)
  1944.       whereis_origin--;
  1945.       break;
  1946.     case K_Right:
  1947.     case K_ERight:
  1948.     case K_Down:
  1949.     case K_EDown:
  1950.       if (no < whereis_text_count - 1)
  1951.     if (pane_pos < toplines - 1)
  1952.       pane_pos++;
  1953.     else
  1954.       whereis_origin++;
  1955.       break;
  1956.     case K_Home:
  1957.     case K_EHome:
  1958.       pane_pos = whereis_origin = 0;
  1959.       break;
  1960.     case K_End:
  1961.     case K_EEnd:
  1962.       if (whereis_text_count > toplines)
  1963.     {
  1964.       whereis_origin = whereis_text_count - toplines;
  1965.       pane_pos = toplines - 1;
  1966.     }
  1967.       else
  1968.     {
  1969.       whereis_origin = 0;
  1970.       pane_pos = whereis_text_count ? whereis_text_count - 1 : 0;
  1971.     }
  1972.       break;
  1973.     case K_PageDown:
  1974.     case K_EPageDown:
  1975.       if (whereis_origin + toplines < whereis_text_count)
  1976.     {
  1977.       whereis_origin += toplines;
  1978.       if (whereis_origin + pane_pos >= whereis_text_count)
  1979.         pane_pos = whereis_text_count - 1 - whereis_origin;
  1980.     }
  1981.       break;
  1982.     case K_PageUp:
  1983.     case K_EPageUp:
  1984.       if (whereis_origin > toplines)
  1985.     whereis_origin -= toplines;
  1986.       else
  1987.     whereis_origin = pane_pos = 0;
  1988.       break;
  1989.     case K_Return:
  1990.       if (whereis_text_count)
  1991.     {
  1992.       char *endp, typ;
  1993.       unsigned long ul;
  1994.  
  1995.       typ = whereis_pane_text[no][11];
  1996.       ul = strtoul (whereis_pane_text[no], &endp, 16);
  1997.       switch (toupper (typ))
  1998.         {
  1999.         case 'T':
  2000.           code_pane_goto (ul);
  2001.           whereis_pane_active = 0;
  2002.           code_pane_active = 1;
  2003.           pane = 0;
  2004.           break;
  2005.         case 'B':
  2006.         case 'D':
  2007.           data_dump_origin = ul;
  2008.           pane_positions[4] = 0;
  2009.           break;
  2010.         }
  2011.     }
  2012.       break;
  2013.     default:
  2014.       if (key >= ' ' && key < 127)
  2015.     {
  2016.       char s[2], *p;
  2017.  
  2018.       s[0] = key; s[1] = '\0';
  2019.       if (!read_string (key == '=' ? "" : s) && read_buffer[0] != '\0')
  2020.         {
  2021.           while (whereis_text_count > 0)
  2022.         free (whereis_pane_text[--whereis_text_count]);
  2023.           whereis_pane_text = realloc (whereis_pane_text, 0);
  2024.  
  2025.           p = read_buffer;
  2026.           while (*p == ' ') p++;
  2027.           syms_listwild (p, &fullscr_listwild_handler);
  2028.           pane_pos = whereis_origin = 0;
  2029.           if (whereis_text_count >= 10)
  2030.         message (CL_Info, "There were %d symbols that matched",
  2031.              whereis_text_count);
  2032.         }
  2033.     }
  2034.     }
  2035.   redraw (0);
  2036. }
  2037. /* ---------------------------------------------------------------------- */
  2038. void
  2039. debugger(void)
  2040. {
  2041.   int oldpane;
  2042.   static void (*keyhandlers[PANECOUNT])(int) =
  2043.     {
  2044.       &code_pane_command,       /* 0 */
  2045.       ®ister_pane_command,       /* 1 */
  2046.       &flag_pane_command,       /* 2 */
  2047.       &breakpoint_pane_command,       /* 3 */
  2048.       &data_pane_command,       /* 4 */
  2049.       &npx_pane_command,       /* 5 */
  2050.       &stack_pane_command,       /* 6 */
  2051.       &info_pane_command,       /* 7 */
  2052.       &whereis_pane_command       /* 8 */
  2053.     };
  2054.  
  2055.   main_entry = syms_name2val ("_main");
  2056.   first_step = !undefined_symbol;
  2057.   initialize ();
  2058.   can_longjmp = 1;
  2059.   setjmp (debugger_jmpbuf);
  2060.   oldpane = -1;
  2061.  
  2062.   while (1)
  2063.     {
  2064.       int key;
  2065.  
  2066.       if (pane < 1 || pane > 4)
  2067.     pane = code_pane_active ? 0
  2068.       : (npx_pane_active ? 5
  2069.          : (stack_pane_active ? 6
  2070.         : (info_pane_active ? 7
  2071.            : (whereis_pane_active ? 8
  2072.               : (abort (), -1)))));
  2073.       if (pane == oldpane)
  2074.     pane_positions[pane] = pane_pos;
  2075.       else
  2076.     {
  2077.       pane_pos = pane_positions[pane];
  2078.       oldpane = pane;
  2079.       redraw (0);
  2080.     }
  2081.       key = getxkey ();
  2082.       switch (key)
  2083.     {
  2084.     case K_Tab:
  2085.       if (pane < 1 || pane > 4)
  2086.         pane = 1;
  2087.       else
  2088.         pane++;
  2089.       break;
  2090.     case K_BackTab:
  2091.       if (pane < 1 || pane > 4)
  2092.         pane = 4;
  2093.       else
  2094.         pane--;
  2095.       break;
  2096.     case K_Alt_C:
  2097.     case K_Alt_I:
  2098.     case K_Alt_N:
  2099.     case K_Alt_S:
  2100.     case K_Alt_W:
  2101.       code_pane_active = (key == K_Alt_C);
  2102.       info_pane_active = (key == K_Alt_I);
  2103.       npx_pane_active = (key == K_Alt_N);
  2104.       stack_pane_active = (key == K_Alt_S);
  2105.       whereis_pane_active = (key == K_Alt_W);
  2106.       oldpane = -1; /* Force redraw.  */
  2107.       break;
  2108.     case K_Alt_X:
  2109.       user_screen ();
  2110.       can_longjmp = 0;
  2111.       return;
  2112.     case K_Alt_F5:
  2113.       user_screen ();
  2114.       (void) getxkey ();
  2115.       debug_screen ();
  2116.       break;
  2117.     case K_Alt_E:
  2118.       {
  2119.         int res, ok;
  2120.  
  2121.         res = read_eval (&ok, "");
  2122.         if (ok)
  2123.           message (CL_Msg, "\"%s\" -> %d (0x%08lx)",
  2124.                read_buffer, res, (word32) res);
  2125.         break;
  2126.       }
  2127.     case K_F7:
  2128.       step (0);
  2129.       break;
  2130.     case K_F8:
  2131.       step (1);
  2132.       break;
  2133.     case K_F9:
  2134.       step (2);
  2135.       break;
  2136.     default:
  2137.       keyhandlers[pane] (key);
  2138.     }
  2139.     }
  2140. }
  2141. /* ----------------------------------------------------------------------
  2142.    It's a mystery to me --- the game commences
  2143.    for the usual fee --- plus expenses
  2144.    confidential information --- it's in a diary
  2145.    this is my investigation --- it's not a public inquiry
  2146.  
  2147.    -- Mark Knopfler, "Private Investigations"
  2148. ---------------------------------------------------------------------- */
  2149.