home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / debug / fsdb / fullscr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-24  |  96.3 KB  |  3,666 lines

  1. /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  2. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  3. /* ------------------------------------------------------------------------- */
  4. /*                FULL SCREEN DEBUGGER                 */
  5. /*                                         */
  6. /* Copyright 1994 by Morten Welinder, terra@diku.dk                 */
  7. /* ------------------------------------------------------------------------- */
  8. /*
  9.  
  10. This debugger is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 2, or (at your option)
  13. any later version.
  14.  
  15. This debugger is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. GNU General Public License for more details.
  19.  
  20. You should have received a copy of the GNU General Public License
  21. along with djgpp; see the file COPYING.     If not, write to
  22. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  23. /* ------------------------------------------------------------------------- */
  24. #define FULLSCR_VERSION 1.00
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include <bios.h>
  31. #include <dos.h>
  32. #include <dpmi.h>
  33. #include <go32.h>
  34. #include <keys.h>
  35. #include <setjmp.h>
  36. #include <unistd.h>
  37. #include "ed.h"
  38. #include <debug/syms.h>
  39. #include "unassmbl.h"
  40. #include "screen.h"
  41. /* ------------------------------------------------------------------------- */
  42. /* Information about the initialization state of the debugger.    Actually
  43.    I'm not sure that longjmp should ever be permitted.    */
  44. int can_longjmp = 0;
  45. jmp_buf debugger_jmpbuf;
  46.  
  47. /* Information about panes.  */
  48. #define PANECOUNT 16
  49. enum bool {
  50.   PANE_CODE = 0,
  51.   PANE_REGISTER = 1,
  52.   PANE_FLAG = 2,
  53.   PANE_BREAKPOINT = 3,
  54.   PANE_DATA = 4,
  55.   PANE_NPX = 5,
  56.   PANE_STACK = 6,
  57.   PANE_INFO = 7,
  58.   PANE_WHEREIS = 8,
  59.   PANE_GDT = 9,
  60.   PANE_IDT = 10,
  61.   PANE_LDT = 11,
  62.   PANE_HELP = 12,
  63.   PANE_MODULE = 13,
  64.   PANE_SOURCE = 14,
  65.   PANE_WATCH = 15};
  66.  
  67. static int pane, ulpane, dlpane, pane_positions[PANECOUNT], pane_pos;
  68. static word32 code_dump_origin, code_dump_last;
  69. static word32 *code_pane_pos;
  70. static int register_pane_origin;
  71. static int flag_pane_origin;
  72. static word32 data_dump_origin, data_dump_last, data_dump_size;
  73. static int npx_pane_origin;
  74. static int stack_dump_origin, stack_dump_last, stack_dump_more;
  75. static word32 *stack_dump_pos;
  76. static int breakpoint_origin;
  77. static char **whereis_pane_text;
  78. static int whereis_text_count, whereis_pane_origin;
  79. static int gdt_pane_origin;
  80. static int idt_pane_origin;
  81. static int ldt_pane_origin;
  82. static int help_pane_origin;
  83. static int module_text_count, module_pane_origin;
  84. static char **module_pane_text;
  85. static int *module_line_numbers;
  86. static int source_text_count, source_pane_origin;
  87. static char **source_pane_text, *source_pane_module;
  88. static int watch_text_count, watch_pane_origin;
  89. static char **watch_pane_text;
  90.  
  91. static int code_pane_active;
  92. static int register_pane_active;
  93. static int flag_pane_active;
  94. static int breakpoint_pane_active;
  95. static int data_pane_active;
  96. static int npx_pane_active;
  97. static int stack_pane_active;
  98. static int info_pane_active;
  99. static int whereis_pane_active;
  100. static int gdt_pane_active;
  101. static int idt_pane_active;
  102. static int ldt_pane_active;
  103. static int help_pane_active;
  104. static int module_pane_active;
  105. static int source_pane_active;
  106. static int watch_pane_active;
  107.  
  108. /* Odds and ends.  */
  109. #define MAXINSTLEN 16
  110. static int first_step;
  111. static word32 main_entry;
  112. static NPX npx;
  113. static void redraw (int);
  114. static const char hexchars[] = "0123456789abcdef";
  115. static int dpmi;
  116. static int terminated;
  117. char *setupfilename;
  118. extern int evaluate (char *, long *, char **);
  119.  
  120. /* Pseudo-keys.  */
  121. #define PK_Redraw 0x2ff
  122. #define PK_Control_I 0x2fe
  123.  
  124. #define MIN(x,y) ((x) <= (y) ? (x) : (y))
  125. #define MAX(x,y) ((x) >= (y) ? (x) : (y))
  126. /* ------------------------------------------------------------------------- */
  127. /* Description of which types of selectors that are valid in which contexts.
  128.    Type #i is valid if the i-th bit is set.  */
  129.  
  130. static word32 allowed_descriptors[] = {
  131.   0xffffdafeL,   /* GDT */
  132.   0x0000c0e0L,   /* IDT */
  133.   0xffffdafaL};  /* LDT */
  134. /* ------------------------------------------------------------------------- */
  135. static char *helptext[] = {
  136.   "Welcome to Sally Full Screen Debugger!",
  137.   "",
  138.   "This program is copyright 1994-1996 by Morten Welinder.",
  139.   "For further copyright information, including other parties'",
  140.   "claims, please read the manual.",
  141.   "",
  142.   "",
  143.   "The following keys are globally defined:",
  144.   "",
  145.   "Alt-C      : Select code (disassembly) pane.",
  146.   "Alt-E      : Evaluate expression.",
  147.   "Alt-G      : Select GDT pane.",
  148.   "Alt-H      : Select help pane.",
  149.   "Alt-I      : Select IDT pane.",
  150.   "Alt-L      : Select LDT pane.",
  151.   "Alt-M      : Select module pane.",
  152.   "Alt-N      : Select numeric processor (fpu) pane.",
  153.   "Alt-S      : Select stack pane.",
  154.   "Alt-W      : Select where-is (symbol list) pane.",
  155.   "Alt-X      : Exit right away.",
  156.   "Tab        : Select next pane.",
  157.   "BackTab    : Select previous pane.",
  158.   "F1         : Select help pane (alias for Alt-H).",
  159.   "C-F4       : Evaluate expression (alias for Alt-E).",
  160.   "Alt-F5     : Show debugged program's screen.",
  161.   "F7         : Execute single instruction.",
  162.   "C-F7       : Add watch.",
  163.   "F8         : Execute till next instruction.",
  164.   "F9         : Run program.",
  165.   "F10        : Select pane via menu.",
  166.   "Alt-F10    : Misc. functions.",
  167.   "\030,\031,\033,\032    : Move focus up/down/left/right one step.",
  168.   "Alt-\030,Alt-\031: Move horizontal split up/down.",
  169.   "PgUp,PgDn  : Move focus up/down one page.",
  170.   "Home,End   : Move focus to beginning/end of pane.",
  171.   "",
  172.   "",
  173.   "",
  174.   "Expressions can use",
  175.   "",
  176.   "* numbers     : Decimal, hex, and octal is supported.",
  177.   "* operators   : More or less the full C set (not counting",
  178.   "                the assignment operators) is supported.",
  179.   "* parentheses : For grouping.",
  180.   "* symbols     : The value is the address of the symbol.  An",
  181.   "                initial underscore may be omitted if that",
  182.   "                name is not used for another symbol.",
  183.   "* registers   : 8-, 16-, and 32-bit registers are supported.",
  184.   "                If there is a symbol with the same name as a",
  185.   "                register then a `%' must be prepended to the",
  186.   "                name.",
  187.   "* `expr:size' : Reduces the operand to `size' bytes.",
  188.   "* `[expr]'    : Evaluates to the 32-bit value at that",
  189.   "                address.",
  190.   "",
  191.   "All evaluation is done with 32-bit signed values, except",
  192.   "shifts which use unsigned values.",
  193.   "",
  194.   "",
  195.   "",
  196.   "Code pane keys:",
  197.   "",
  198.   "F2         : Set breakpoint.",
  199.   "F4         : Run to instruction at focus.",
  200.   "Return     : Go to source.",
  201.   "C-\033,C-\032    : Start disassembly one byte earlier/later.",
  202.   "C-g        : Go to specified address.",
  203.   "C-n        : Set eip to instruction at cursor.",
  204.   "C-o        : Go to origin, i.e., current eip.",
  205.   "",
  206.   "",
  207.   "",
  208.   "Register pane keys:",
  209.   "",
  210.   "C-d        : Decrement register.",
  211.   "C-i        : Increment register.",
  212.   "C-n        : Negate register.",
  213.   "C-z        : Zero register.",
  214.   "=          : Enter new expression for register.",
  215.   "",
  216.   "",
  217.   "",
  218.   "Flag pane keys:",
  219.   "",
  220.   "Space      : Toggle flag.",
  221.   "1,s        : Set flag.",
  222.   "0,r        : Reset flag.",
  223.   "",
  224.   "Only the user flags are listed.  These are:",
  225.   "",
  226.   "Flag   Name         0 means    1 means",
  227.   "-----------------------------------------",
  228.   "c      Carry        none       carry",
  229.   "p      Parity       odd        even",
  230.   "a      Auxiliary    clear      half-carry",
  231.   "z      Zero         nonzero    zero",
  232.   "s      Sign         positive   negative",
  233.   "i      Interrupt    disabled   enabled",
  234.   "d      Direction    down       up",
  235.   "o      Overflow     none       overflow",
  236.   "",
  237.   "",
  238.   "",
  239.   "Breakpoint pane keys:",
  240.   "",
  241.   "Delete     : Delete breakpoint.",
  242.   "Enter      : Edit condition and trigger count.",
  243.   "C-g        : Go to code affected by breakpoint.",
  244.   "",
  245.   "For code breakpoints you can enter a condition and a",
  246.   "count controling when the breakpoint is triggered.",
  247.   "",
  248.   "",
  249.   "",
  250.   "Data pane keys:",
  251.   "",
  252.   "C-\033,C-\032    : Start data display one byte earlier/later.",
  253.   "C-b        : Display data as bytes.",
  254.   "C-c        : Go to the the current instruction.",
  255.   "C-g        : Go to specified address.",
  256.   "C-l        : Display data as 32-bit words (`longs').",
  257.   "C-s        : Go to the stack.",
  258.   "C-w        : Display data as 16-bit words.",
  259.   "F2         : Set data write breakpoint at focus.",
  260.   "Alt-F2     : Set data read/write breakpoint at focus.",
  261.   "=          : Enter new value or string.",
  262.   "",
  263.   "",
  264.   "",
  265.   "Numeric processor pane keys:",
  266.   "",
  267.   "C-e        : Empty register.",
  268.   "C-z        : Zero register.",
  269.   "C-n        : Negate register.",
  270.   "=          : Enter new value for register.",
  271.   "",
  272.   "",
  273.   "",
  274.   "Stack pane keys:",
  275.   "",
  276.   "Enter      : Go to code.",
  277.   "",
  278.   "",
  279.   "",
  280.   "Where-is pane keys:",
  281.   "",
  282.   "Enter      : Go to code/data.",
  283.   "=          : Enter new search expression.",
  284.   "",
  285.   "",
  286.   "",
  287.   "Module pane keys:",
  288.   "",
  289.   "Enter      : Show source for module.",
  290.   "",
  291.   "",
  292.   "",
  293.   "Source pane keys:",
  294.   "",
  295.   "F2         : Set breakpoint.",
  296.   "F4         : Run to instruction at focus.",
  297.   "F8         : Execute till next line or function return.",
  298.   "Enter      : Show code for line.",
  299.   "",
  300.   "",
  301.   "",
  302.   "Watch pane keys:",
  303.   "",
  304.   "Delete     : Delete watch.",
  305.   "=          : Add watch."
  306. };
  307. /* ------------------------------------------------------------------------- */
  308. /* This information guards the display of descriptors.  */
  309.  
  310. struct {
  311.   word16 limit __attribute__ ((packed));
  312.   word32 base __attribute__ ((packed));
  313. } gdtlinear, idtlinear, ldtlinear;
  314.  
  315. #ifndef V2DBG
  316. static char *gdtnames[g_num] = {
  317.   "NULL", "gdt", "idt", "rcode",
  318.   "rdata", "pcode", "pdata", "core",
  319.   "bios data", "arena data", "ctss", "active tss",
  320.   "page tss", "int tss", "rc32", "grdr",
  321.   "vcpi code", "(vcpi res. 0)", "(vcpi res. 1)", "vect 0x74",
  322.   "vect 0x78", "vect 0x79", "altc", "debug cs",
  323.   "debug ds", "debug tss", "rtss", "arena code",
  324.   "vesa funcions" };
  325. #endif
  326. /* ------------------------------------------------------------------------- */
  327. /* The presentation order of registers in the register pane.  The three
  328.    tables must, of course, match.  */
  329.  
  330. static char *regs_names[] = {
  331.   "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
  332.   "cs",     "ds",    "es",  "fs",  "gs",  "ss",
  333.   "eip", "flg" };
  334.  
  335. static word32 *regs_addr[] = {
  336.   &a_tss.tss_eax, &a_tss.tss_ebx, &a_tss.tss_ecx, &a_tss.tss_edx,
  337.   &a_tss.tss_esi, &a_tss.tss_edi, &a_tss.tss_ebp, &a_tss.tss_esp,
  338.   (word32 *)&a_tss.tss_cs, (word32 *)&a_tss.tss_ds,
  339.   (word32 *)&a_tss.tss_es, (word32 *)&a_tss.tss_fs,
  340.   (word32 *)&a_tss.tss_gs, (word32 *)&a_tss.tss_ss,
  341.   &a_tss.tss_eip, &a_tss.tss_eflags };
  342.  
  343. /* g: general, !: special, s: segment, f: flags, \0: end-of-table */
  344. static char regs_type[] = "ggggggg!ssssss!f";
  345. /* ------------------------------------------------------------------------- */
  346. /* The presentation order of flags in the flags pane.  The two tables must,
  347.    of course, match.  */
  348.  
  349. static char flag_names[] = "cpaznido";
  350.  
  351. static unsigned flag_bits[] =
  352. { 0x0001, 0x0004, 0x0010, 0x0040, 0x0080, 0x0200, 0x0400, 0x0800 };
  353. /* ------------------------------------------------------------------------- */
  354. /* Breakpoint data.  When breakpoints are actually put into the cpu debug
  355.    registers, data breakpoints have first priority.  Any code breakpoints
  356.    left over are set by patching the code to contain "Int 3".  */
  357.  
  358. typedef enum { BP_Code = 0, BP_Write = 1, BP_Read = 3 } BP_TYPE;
  359.  
  360. typedef struct
  361. {
  362.   word32 addr;                /* Linear address of breakpoint.  */
  363.   int count;                  /* #hits left before code bp triggers.  */
  364.   char *condition;            /* Condition for code breakpoints.  */
  365.   BP_TYPE type;               /* What kind of breakpoint?  */
  366.   unsigned char length;          /* 1, 2, or 4 bytes.  */
  367.   unsigned char saved;        /* Non-zero for code bps using int 0x03.  */
  368.   unsigned char savedbyte;    /* Patched-away byte.  */
  369.   unsigned char disabled;     /* Non-zero means don't put into cpu regs.  */
  370.   unsigned char temporary;    /* A temporary like those used for F4.  */
  371. } BP_ENTRY;
  372.  
  373. static int breakpoint_count;
  374. static BP_ENTRY *breakpoint_table;
  375. static unsigned char int03 = 0xcc;
  376. /* ------------------------------------------------------------------------- */
  377. #ifndef xmalloc
  378. extern void *xmalloc (size_t);
  379. extern void *xrealloc (void *, size_t);
  380.  
  381. char *
  382. strdup (const char *_s)
  383. {
  384.   char *res = xmalloc (strlen (_s) + 1);
  385.   strcpy (res, _s);
  386.   return res;
  387. }
  388. #endif
  389. /* ------------------------------------------------------------------------- */
  390. /* Store the contents of the NPX in the global variable `npx'.  */
  391.  
  392. static inline void
  393. save_npx (void)
  394. {
  395.   asm ("inb    $0xa0, %%al
  396.     testb    $0x20, %%al
  397.     jz    1f
  398.     xorl    %%al, %%al
  399.     outb    %%al, $0xf0
  400.     movb    $0x20, %%al
  401.     outb    %%al, $0xa0
  402.     outb    %%al, $0x20
  403. 1:
  404.     fnsave    %0
  405.     fwait"
  406.        : "=m" (npx)
  407.        : /* No input */
  408.        : "%eax");
  409. }
  410. /* ------------------------------------------------------------------------- */
  411. /* Reload the contents of the NPX from the global variable `npx'.  */
  412.  
  413. static inline void
  414. load_npx (void)
  415. {
  416.   asm ("frstor %0" : "=m" (npx));
  417. }
  418. /* ------------------------------------------------------------------------- */
  419. /* Evaluate EXPR and return the result.  Set OKP to 1 if and if only the
  420.    expression was sucessfully evaluated.  Display an error message if not.  */
  421.  
  422. static int
  423. eval (char *expr, int *okp)
  424. {
  425.   word32 sym;
  426.   int err;
  427.   char *errtxt;
  428.  
  429.   if ((err = evaluate (expr, &sym, &errtxt)))
  430.     message (CL_Error, "%s", errtxt);
  431.   *okp = !err;
  432.   return (int) sym;
  433. }
  434. /* ------------------------------------------------------------------------- */
  435. /* Read an expression and evaluate it.  */
  436.  
  437. static int
  438. read_eval (int *okp, char *starttext)
  439. {
  440.   *okp = !read_string (starttext);
  441.   if (*okp && read_buffer[0] != '\0')
  442.     return eval (read_buffer, okp);
  443.   else
  444.     return *okp = 0;
  445. }
  446. /* ------------------------------------------------------------------------- */
  447. /* Try to read memory using dpmi tricks.  Return 1 if ok.  */
  448.  
  449. static int
  450. dpmi_readmem (word32 physaddr, void *buf, unsigned len)
  451. {
  452.   union REGS regs;
  453.   int ok = 0;
  454.  
  455.   regs.w.ax = 0x0000;
  456.   regs.w.cx = 1;
  457.   int86 (0x31, ®s, ®s);
  458.   if (!regs.w.cflag)
  459.     {
  460.       word16 sel = regs.w.ax;
  461.       regs.w.ax = 0x0007;
  462.       regs.w.bx = sel;
  463.       regs.w.cx = physaddr >> 16;
  464.       regs.w.dx = (word16)physaddr;
  465.       int86 (0x31, ®s, ®s);
  466.       if (!regs.w.cflag)
  467.     {
  468.       regs.w.ax = 0x0008;
  469.       regs.w.bx = sel;
  470.       regs.w.cx = len >> 16;
  471.       regs.w.dx = (word16)len;
  472.       int86 (0x31, ®s, ®s);
  473.       if (!regs.w.cflag)
  474.         {
  475.           movedata (sel, 0, _go32_my_ds (), (unsigned)buf, len);
  476.           ok = 1;
  477.         }
  478.     }
  479.       regs.w.ax = 0x0001;
  480.       regs.w.bx = sel;
  481.       int86 (0x31, ®s, ®s);
  482.     }
  483.   return ok;
  484. }
  485. /* ------------------------------------------------------------------------- */
  486. /* Get a descriptor from TABLE, entry NO, to DESCR.  Return its type, or
  487.    -1 in case of failure.  */
  488.  
  489. static int
  490. getdescriptor (word32 tablebase, int no, void *descr)
  491. {
  492.   word32 phys;
  493.  
  494.   phys = tablebase + no * 8;
  495.   if (phys + sizeof (GDT_S) <= 0x100000l)
  496.     dosmemget (phys, 8, descr);
  497.   else if (dpmi && dpmi_readmem (phys, descr, 8))
  498.     /* Nothing.  */;
  499.   else
  500.     return -1;
  501.   return ((GDT_S *)descr)->stype & 0x1f;
  502. }
  503. /* ------------------------------------------------------------------------- */
  504. /* At BUF place the textual representation of DESCR.  */
  505.  
  506. static void
  507. describedescriptor (char *buf, void *descr, int table)
  508. {
  509.   IDT *idtp = (IDT *)descr;
  510.   GDT_S *gdtp = (GDT_S *)descr;
  511.   int typ = gdtp->stype & 0x1f;
  512.   word32 limit = ((gdtp->lim1 & 0x0f) << 16) | gdtp->lim0;
  513.  
  514.   if (gdtp->lim1 & 0x80)
  515.     limit = (limit << 12) | 0xfff;
  516.  
  517.   if ((gdtp->stype & 0x80) == 0)
  518.     sprintf (buf, "Not present.");
  519.   else if (((allowed_descriptors[table] >> typ) & 1) == 0)
  520.     sprintf (buf, "Invalid in context (%02x)", typ);
  521.   else
  522.     switch (typ)
  523.       {
  524.       case 0x01:
  525.       case 0x03:
  526.     sprintf (buf, "16-bit TSS  %s",
  527.          typ & 2 ? " (busy)" : "");
  528.     break;
  529.       case 0x02:
  530.     sprintf (buf, "LDT %02x%02x%04x+%08lx",
  531.          gdtp->base2, gdtp->base1, gdtp->base0, limit);
  532.     break;
  533.       case 0x04:
  534.     sprintf (buf, "16-bit Call Gate.");
  535.     break;
  536.       case 0x05:
  537.     sprintf (buf, "Task Gate, TSS=%04x",
  538.          (unsigned) idtp->selector);
  539.     break;
  540.       case 0x06:
  541.     sprintf (buf, "16-bit Interrupt Gate");
  542.     break;
  543.       case 0x07:
  544.     sprintf (buf, "16-bit Trap Gate");
  545.     break;
  546.       case 0x09:
  547.       case 0x0b:
  548.     sprintf (buf, "32-bit TSS  %02x%02x%04x+%08lx%s",
  549.          (unsigned) gdtp->base2,
  550.          (unsigned) gdtp->base1,
  551.          (unsigned) gdtp->base0,
  552.          limit,
  553.          typ & 2 ? " (busy)" : "");
  554.     break;
  555.       case 0x0c:
  556.     sprintf (buf, "32-bit Call Gate, %04x:%04x%04x (%d)",
  557.          (unsigned) idtp->selector,
  558.          (unsigned) idtp->offset1, (unsigned) idtp->offset0,
  559.          gdtp->base1 & 0x0f);
  560.     break;
  561.       case 0x0e:
  562.     sprintf (buf, "32-bit Interrupt Gate, %04x:%04x%04x",
  563.          (unsigned) idtp->selector,
  564.          (unsigned) idtp->offset1, (unsigned) idtp->offset0);
  565.     break;
  566.       case 0x0f:
  567.     sprintf (buf, "32-bit Trap Gate, %04x:%04x%04x",
  568.          (unsigned) idtp->selector,
  569.          (unsigned) idtp->offset1, (unsigned) idtp->offset0);
  570.     break;
  571.       case 0x10 ... 0x17:
  572.     sprintf (buf,
  573.          "%s-bit data %02x%02x%04x+%08lx %s %s %s",
  574.          gdtp->lim1 & 0x40 ? "32" : "16",
  575.          gdtp->base2, gdtp->base1, gdtp->base0,
  576.          limit,
  577.          typ & 0x04 ? "E\031" : "E\030",
  578.          typ & 0x02 ? "RW" : "RO",
  579.          typ & 0x01 ? "A+" : "A-");
  580.     break;
  581.       case 0x18 ... 0x1f:
  582.     sprintf (buf,
  583.          "%s-bit code %02x%02x%04x+%08lx %s %s %s",
  584.          gdtp->lim1 & 0x40 ? "32" : "16",
  585.          gdtp->base2, gdtp->base1, gdtp->base0,
  586.          limit,
  587.          typ & 0x04 ? "C+" : "C-",
  588.          typ & 0x02 ? "R+" : "R-",
  589.          typ & 0x01 ? "A+" : "A-");
  590.     break;
  591.       case 0x00:
  592.       case 0x08:
  593.       case 0x0a:
  594.       case 0x0d:
  595.     sprintf (buf, "Invalid (%02x)", typ);
  596.     break;
  597.       default:
  598.     sprintf (buf, "Invalid (%02x)", typ);
  599.       }
  600. }
  601. /* ------------------------------------------------------------------------- */
  602. static void
  603. show_tss (void *descr)
  604. {
  605.   GDT_S *gdtp = (GDT_S *)descr;
  606.   word32 base = (gdtp->base2 << 24) | (gdtp->base1 << 16) | (gdtp->base0);
  607.   word32 limit = ((gdtp->lim1 & 0x0f) << 16) | gdtp->lim0;
  608.   int y = 1, width = cols - 19;
  609.   char buf[80];
  610.   TSS tss;
  611.  
  612.   if (gdtp->lim1 & 0x80)
  613.     limit = (limit << 12) | 0xfff;
  614.  
  615.   sprintf (buf, "Tss at %08lx+%08lx", base, limit);
  616.   putl (1, y++, width, buf);
  617.   putl (1, y++, width, "");
  618.   if (limit < 0x67)
  619.     putl (1, y++, width, "Invalid length");
  620.   else
  621.     {
  622.       int ok;
  623.  
  624.       if (base + sizeof (tss) <= 0x100000l)
  625.     {
  626.       dosmemget (base, sizeof (tss), &tss);
  627.       ok = 1;
  628.     }
  629.       else if (dpmi && dpmi_readmem (base, &tss, sizeof (tss)))
  630.     ok = 1;
  631.       else
  632.     {
  633.       ok = 0;
  634.       putl (1, y++, width, "Read failure.");
  635.     }
  636.  
  637.       if (ok)
  638.     {
  639.       sprintf (buf, "s0=%04x:%08lx   s1=%04x:%08lx   s1=%04x:%08lx",
  640.            tss.tss_ss0, tss.tss_esp0,
  641.            tss.tss_ss1, tss.tss_esp1,
  642.            tss.tss_ss2, tss.tss_esp2);
  643.       putl (1, y++, width, buf);
  644.       sprintf (buf, "ldt=%04x   link=%04x   trap=%s   io=%04x",
  645.            tss.tss_ldt,
  646.            tss.tss_back_link,
  647.            tss.tss_trap ? "Yes" : "No",
  648.            tss.tss_iomap);
  649.       putl (1, y++, width, buf);
  650.       putl (1, y++, width, "");
  651.       sprintf (buf, "ds=%04x   es=%04x   fs=%04x   gs=%04x",
  652.            tss.tss_ds, tss.tss_es, tss.tss_fs, tss.tss_gs);
  653.       putl (1, y++, width, buf);
  654.       putl (1, y++, width, "");
  655.       sprintf (buf, "eax=%08lx   ebx=%08lx   ecx=%08lx   edx=%08lx",
  656.            tss.tss_eax, tss.tss_ebx, tss.tss_ecx, tss.tss_edx);
  657.       putl (1, y++, width, buf);
  658.       sprintf (buf, "esi=%08lx   edi=%08lx   ebp=%08lx   flg=%08lx",
  659.            tss.tss_esi, tss.tss_edi, tss.tss_ebp, tss.tss_eflags);
  660.       putl (1, y++, width, buf);
  661.       sprintf (buf, "cs:eip=%04x:%08lx   ss:esp=%04x:%08lx",
  662.            tss.tss_cs, tss.tss_eip, tss.tss_ss, tss.tss_esp);
  663.       putl (1, y++, width, buf);
  664.       putl (1, y++, width, "");
  665. #ifndef V2DBG
  666.       if (!dpmi)
  667.         {
  668.           /* From here on it is go32 specific information.  */
  669.           sprintf (buf, "cr2=%08lx   error=%08lx   irqn=%02x",
  670.                tss.tss_cr2, tss.tss_error, tss.tss_irqn);
  671.           putl (1, y++, width, buf);
  672.         }
  673. #endif
  674.     }
  675.     }
  676.  
  677.   while (y < toplines)
  678.     putl (1, y++, width, "");
  679.   putl (1, y++, width, "Press Enter");
  680.   put_screen (debug_screen_save);
  681.   (void) getxkey ();
  682. }
  683. /* ------------------------------------------------------------------------- */
  684. /* Check that it is valid to access at ADDR, LENGTH bytes.  Two adjacent
  685.    areas will not be considered as one area (this is a bug).  */
  686.  
  687. int
  688. valid_addr (word32 vaddr, int len)
  689. {
  690. #ifdef V2DBG
  691.   if (vaddr < 0x1000) return 0;
  692.   if (vaddr >= 0xffffffffl - len) return 0;
  693.   if (vaddr + len > __dpmi_get_segment_limit (_my_ds ())) return 0;
  694.   return 1;
  695. #else
  696.   int a;
  697.  
  698.   if (vaddr >= 0xffffffffl - len)
  699.     return 0;
  700.   len--;
  701.   for (a = 0; a < MAX_AREA; a++)
  702.     if ((vaddr + len <= areas[a].last_addr) && (vaddr >= areas[a].first_addr))
  703.       return 1;
  704.   if (!dpmi && vaddr >= 0xe0000000l && vaddr + len <= 0xe0100000l)
  705.     return 1; /* Remapped core.  */
  706.   return 0;
  707. #endif
  708. }
  709. /* ------------------------------------------------------------------------- */
  710. /* Check that it is valid to access child address ADDR as an instruction.  */
  711.  
  712. inline static int
  713. valid_instaddr (word32 vaddr)
  714. {
  715.   return valid_addr (vaddr, MAXINSTLEN);
  716. }
  717. /* ------------------------------------------------------------------------- */
  718. /* Set physical breakpoint registers from virtual ones.     Only the first
  719.    four data breakpoints are honoured.  When the debug registers are
  720.    full, extra code breakpoints are set by patching "Int 3" into the
  721.    code.  */
  722.  
  723. static void
  724. activate_breakpoints (void)
  725. {
  726.   int b, no;
  727.   BP_ENTRY *bep;
  728.  
  729.   no = 0;
  730.   edi.dr[7] = 0;
  731.   /* First handle data breakpoints.  */
  732.   for (b = 0, bep = breakpoint_table; b < breakpoint_count; b++, bep++)
  733.     if (!bep->disabled && no <= 3 && bep->type != BP_Code)
  734.       {
  735.     bep->saved = 0;
  736.     edi.dr[7] |= ((bep->type + ((bep->length - 1) << 2)) << (16 + 4 * no)
  737.               | (2 << (2 * no)));
  738.     edi.dr[no] = bep->addr + edi.app_base;
  739.     no++;
  740.       }
  741.  
  742.   /* Now handle code breakpoint.  */
  743.   for (b = 0, bep = breakpoint_table; b < breakpoint_count; b++, bep++)
  744.     if (!bep->disabled && bep->type == BP_Code)
  745.       if (no <= 3)
  746.     {
  747.       bep->saved = 0;
  748.       edi.dr[7] |= ((BP_Code << (16 + 4 * no)) | (2 << (2 * no)));
  749.       edi.dr[no] = bep->addr + edi.app_base;
  750.       no++;
  751.       edi.dr[7] |= 0x00000300L;  /* For 386s we set GE & LE bits.  */
  752.     }
  753.       else
  754.     {
  755.       bep->saved = valid_addr (bep->addr, 1);
  756.       if (bep->saved)
  757.         {
  758.           read_child (bep->addr, &bep->savedbyte, 1);
  759.           write_child (bep->addr, &int03, 1);
  760.         }
  761.     }
  762. }
  763. /* ------------------------------------------------------------------------- */
  764. /* Un-patch code.  This means restore the instruction under any "Int 3"
  765.    that was patched-in by previous function.  */
  766.  
  767. static void
  768. deactivate_breakpoints (void)
  769. {
  770.   int b;
  771.   BP_ENTRY *bep;
  772.  
  773.   for (b = 0, bep = breakpoint_table; b < breakpoint_count; b++, bep++)
  774.     if (!bep->disabled && bep->saved)
  775.       write_child (bep->addr, &bep->savedbyte, 1);
  776. }
  777. /* ------------------------------------------------------------------------- */
  778. /* Get the serial number of a breakpoint of TYPE and LENGTH at ADDR.  Return
  779.    -1 if no such breakpoint is set.  */
  780.  
  781. static int
  782. get_breakpoint (BP_TYPE type, int length, word32 addr)
  783. {
  784.   int b;
  785.  
  786.   for (b = 0; b < breakpoint_count; b++)
  787.     if (breakpoint_table[b].type == type
  788.     && breakpoint_table[b].length == length
  789.     && breakpoint_table[b].addr == addr)
  790.       return b;
  791.   return -1;
  792. }
  793. /* ------------------------------------------------------------------------- */
  794. /* Delete breakpoint number B.  */
  795.  
  796. static void
  797. reset_breakpoint (int b)
  798. {
  799.   if (breakpoint_table[b].condition)
  800.     free (breakpoint_table[b].condition);
  801.   breakpoint_table[b] = breakpoint_table[--breakpoint_count];
  802.   breakpoint_table
  803.     = xrealloc (breakpoint_table, breakpoint_count * sizeof (BP_ENTRY));
  804. }
  805. /* ------------------------------------------------------------------------- */
  806. /* Set a breakpoint of TYPE and LENGTH at ADDR and return the serial number
  807.    of the new breakpoint.  */
  808.  
  809. static int
  810. set_breakpoint (BP_TYPE type, int length, word32 addr)
  811. {
  812.   int b;
  813.  
  814.   b = breakpoint_count;
  815.   breakpoint_table
  816.     = xrealloc (breakpoint_table, ++breakpoint_count * sizeof (BP_ENTRY));
  817.   bzero (breakpoint_table + b, sizeof (BP_ENTRY));
  818.   breakpoint_table[b].addr = addr;
  819.   breakpoint_table[b].type = type;
  820.   breakpoint_table[b].length = length;
  821.   return b;
  822. }
  823. /* ------------------------------------------------------------------------- */
  824. static void
  825. select_source_file (char *file)
  826. {
  827.   if (source_pane_module == 0 || strcmp (file, source_pane_module))
  828.     {
  829.       int i, no;
  830.  
  831.       while (source_text_count)
  832.     free (source_pane_text[--source_text_count]);
  833.  
  834.       for (no = 0;
  835.        no < module_text_count && strcmp (file, module_pane_text[no]);
  836.        no++)
  837.     /* Nothing */;
  838.  
  839.       if (no < module_text_count)
  840.     {
  841.       char buf[1000];
  842.       int lineno;
  843.  
  844.       source_text_count = file_line_count (file) + 1;
  845.       source_pane_text
  846.         = xrealloc (source_pane_text,
  847.             source_text_count * sizeof (char *));
  848.       source_pane_module = file;
  849.       source_pane_text[0] = (char *)xmalloc (20 + strlen (file));
  850.       sprintf (source_pane_text[0],
  851.            "Module %s:", source_pane_module);
  852.       for (lineno = 1; lineno < source_text_count; lineno++)
  853.         {
  854.           buf[0] = 0;
  855.           put_source_line (2, source_pane_module, lineno, buf);
  856.           source_pane_text[lineno] = strdup (buf);
  857.         }
  858.       i = toplines - 3;
  859.       source_pane_origin = module_line_numbers [no] - i;
  860.       if (source_pane_origin < 0)
  861.         i += source_pane_origin,
  862.         source_pane_origin = 0;
  863.     }
  864.       else
  865.     {
  866.       source_pane_text = xrealloc (source_pane_text, 0);
  867.       source_pane_module = 0;
  868.       source_text_count = source_pane_origin = i = 0;
  869.     }
  870.       pane_positions[PANE_SOURCE] = i;
  871.       if (pane == PANE_SOURCE) pane_pos = i;
  872.     }
  873. }
  874. /* ------------------------------------------------------------------------- */
  875. /* From ORIGIN skip COUNT instructions forward (positive count) or
  876.    backwards (negative count).    Backwards skipping cannot be assumed to
  877.    be working 100% perfectly, but in the presense of debug information
  878.    it is probably very, very close.
  879.  
  880.    This function works poorly close to the extremes of segments.  */
  881.  
  882. static int
  883. code_skip (int origin, int count)
  884. {
  885.   int len, *next, i, j, k, instcount, done, leave;
  886.   char *state, *inst, *source;
  887.  
  888.   if (count >= 0)
  889.     {
  890.       while (count-- > 0)
  891.     if (valid_instaddr (origin))
  892.       {
  893.         (void) unassemble_proper (origin, &len);
  894.         origin += len;
  895.       }
  896.     else
  897.       origin ++;
  898.       return origin;
  899.     }
  900.   else
  901.     {
  902.       count = -count;
  903.       instcount = MAXINSTLEN * (count + 16) + 1;
  904.       next = alloca (instcount * sizeof (int));
  905.       memset (next, 0, instcount * sizeof (int));
  906.       state = alloca (instcount * sizeof (char));
  907.       memset (state, 0, instcount * sizeof (char));
  908.  
  909.       done = 0;
  910.       do
  911.     {
  912.       for (i = 0; i < 2 * count; i++)
  913.         {
  914.           done++;
  915.           j = origin - done;
  916.           if (valid_instaddr (j))
  917.         {
  918.           inst = unassemble_proper (j, &len);
  919.           source = unassemble_source (j);
  920.           next[done] = j + len;
  921.           if (source)
  922.             {
  923.               leave = 0;
  924.               k = done;
  925.               while (j < origin && state[k] == 0 && !leave)
  926.             {
  927.               state[j++,k--] = 2;
  928.               while (len-- > 1)
  929.                 state[j++,k--] = 3;
  930.               /* Since code and data is "never" mixed in 32 bit
  931.                  code we don't need this.  */
  932. #if 0
  933.               leave = (strncmp (inst, "jmp", 3) == 0
  934.                    || strncmp (inst, "ret", 3) == 0
  935.                    || strncmp (inst, "iret", 4) == 0);
  936. #endif
  937.               if (!leave)
  938.                 inst = unassemble_proper (j, &len);
  939.             }
  940.             }
  941.         }
  942.           else
  943.         {
  944.           state[done] = 2;
  945.           next[done] = j + 1;
  946.         }
  947.         }
  948.       j = 1;
  949.       k = count;
  950.       while (k > 0 && j <= done && state[j] >= 2)
  951.         if (state[j++] == 2)
  952.           k--;
  953.     }
  954.       while (k > 0 && done + 2 * count <= instcount);
  955.       if (k == 0)
  956.     return origin - j + 1;
  957.       else
  958.     {
  959.       i = origin;
  960.       k = 0;
  961.       while (count > 0 && k <= done)
  962.         {
  963.           leave = 0;
  964.           j = MAXINSTLEN;
  965.           while (!leave && j > 1)
  966.         if (j + k <= done && next[j + k] == i)
  967.           leave = 1;
  968.         else
  969.           j--;
  970.           if (!leave)
  971.         i--, k++;
  972.           else
  973.         i -= j, k += j;
  974.           count--;
  975.         }
  976.       return i;
  977.     }
  978.     }
  979. }
  980. /* ------------------------------------------------------------------------- */
  981. /* Make the disassembly in the code pane include the instruction starting
  982.    at ADDR.  The display is scrolled if necessary.  Do the same for the
  983.    source pane, if possible.  */
  984.  
  985. static void
  986. code_pane_goto (word32 v)
  987. {
  988.   int i, line;
  989.   char *file;
  990.  
  991.   if (v >= code_dump_origin && v <= code_dump_last)
  992.     {
  993.       i = 0;
  994.       while (code_pane_pos[i] < v)
  995.     i++;
  996.       if (code_pane_pos [i] == code_pane_pos[i+1])
  997.     i++;
  998.     }
  999.   else
  1000.     {
  1001.       code_dump_origin = v;
  1002.       i = (valid_instaddr (v) && unassemble_source (v) != NULL);
  1003.     }
  1004.   pane_positions[PANE_CODE] = i;
  1005.   if (pane == PANE_CODE) pane_pos = i;
  1006.  
  1007.   file = syms_val2line (v, &line, 0);
  1008.   if (file)
  1009.     {
  1010.       select_source_file (file);
  1011.       if (source_pane_origin <= line && line < source_pane_origin + toplines)
  1012.     i = line - source_pane_origin;
  1013.       else
  1014.     source_pane_origin = line, i = 0;
  1015.       pane_positions[PANE_SOURCE] = i;
  1016.       if (pane == PANE_SOURCE) pane_pos = i;
  1017.     }
  1018. }
  1019. /* ------------------------------------------------------------------------- */
  1020. static word32
  1021. find_source_line (int line, int offset)
  1022. {
  1023.   word32 addr;
  1024.  
  1025.   if (source_pane_module)
  1026.     for (; offset; offset--, line++)
  1027.       if ((addr = syms_line2val (source_pane_module, line)))
  1028.     return addr;
  1029.   return 0;
  1030. }
  1031. /* ------------------------------------------------------------------------- */
  1032. /* Let the child process run freely (or rather as freely as debug registers
  1033.    and breakpoints decide.  */
  1034.  
  1035. inline static void
  1036. go (int bp)
  1037. {
  1038.   if (bp) activate_breakpoints ();
  1039.   run_child ();
  1040.   if (bp) deactivate_breakpoints ();
  1041. }
  1042. /* ------------------------------------------------------------------------- */
  1043. /* Let the child process loose in the specified way.  Try to optimize for
  1044.    reduced swapping of screens.  */
  1045.  
  1046. typedef enum { R_Step, R_Step1, R_Over, R_Run, R_RunMain } KIND_TYPE;
  1047.  
  1048. static void
  1049. step (KIND_TYPE kind)
  1050. {
  1051.   int i, b, no, len, int03hit;
  1052.   char *inst = 0;
  1053.   int tracing = (kind == R_Step1);
  1054.   word32 final = -1;
  1055.  
  1056.   switch (kind)
  1057.     {
  1058.     case R_Step1:
  1059.       kind = R_Step;
  1060.       /* Fall through.  */
  1061.     case R_Step:
  1062.       inst = unassemble_proper (a_tss.tss_eip, &len);
  1063.       if (strcmp (inst, "popf") == 0 || strcmp (inst, "pushf") == 0)
  1064.     {
  1065.       kind = R_Over;  /* Push the right value of flags (no trace flag).  */
  1066.       final = a_tss.tss_eip + len;
  1067.     }
  1068.       break;
  1069.     case R_Over:
  1070.       if (first_step)
  1071.     kind = R_RunMain;
  1072.       else
  1073.     {
  1074.       inst = unassemble_proper (a_tss.tss_eip, &len);
  1075.       if (strncmp (inst, "loop", 4)
  1076.           && strncmp (inst, "call", 4)
  1077.           && strncmp (inst, "int", 3) )
  1078.         kind = R_Step;
  1079.       else
  1080.         final = a_tss.tss_eip + len;
  1081.     }
  1082.       break;
  1083.     default:
  1084.       /* Nothing.  */
  1085.     }
  1086.  
  1087.  retry:
  1088.   /* A free run at a non-disabled breakpoint is bad.  */
  1089.   if (kind != R_Step)
  1090.     {
  1091.       int again = 1;
  1092.  
  1093.       while (again && (b = get_breakpoint (BP_Code, 0, a_tss.tss_eip)) != -1)
  1094.     {
  1095.       breakpoint_table[b].disabled++;
  1096.       step (R_Step1);
  1097.       breakpoint_table[b].disabled--;
  1098.       again = !terminated && a_tss.tss_irqn == 1 && final != a_tss.tss_eip;
  1099.     }
  1100.     }
  1101.  
  1102.   switch (kind)
  1103.     {
  1104.     case R_Step1: /* Can't happen, but keeps gcc happy.  */
  1105.     case R_Step:
  1106.       /* If we are referencing memory we should swap-in the user screen.  */
  1107.       if (strchr (inst, '['))
  1108.     /* Assume that all access to code and stack segments are safe.
  1109.        This should hold unless you do something extra-ordinarily dirty.  */
  1110.     if (((a_tss.tss_ds == a_tss.tss_cs) || (a_tss.tss_ds == a_tss.tss_ss))
  1111.         &&
  1112.         ((a_tss.tss_es == a_tss.tss_cs) || (a_tss.tss_es == a_tss.tss_ss))
  1113.         &&
  1114.         ((a_tss.tss_fs == a_tss.tss_cs) || (a_tss.tss_fs == a_tss.tss_ss)
  1115.          || (strstr (inst, "fs:") == 0))
  1116.         &&
  1117.         ((a_tss.tss_gs == a_tss.tss_cs) || (a_tss.tss_gs == a_tss.tss_ss)
  1118.          || (strstr (inst, "gs:") == 0)))
  1119.       /* Nothing.  */;
  1120.     else
  1121.       user_screen ();
  1122.       a_tss.tss_eflags |= 0x0100;
  1123.       edi.dr[7] = 0;
  1124.       go (0);
  1125.       a_tss.tss_eflags &= ~0x0100;
  1126.       break;
  1127.     case R_Over:
  1128.       user_screen ();
  1129.       b = set_breakpoint (BP_Code, 0, final);
  1130.       go (1);
  1131.       reset_breakpoint (b);
  1132.       break;
  1133.     case R_Run:
  1134.       user_screen ();
  1135.       go (1);
  1136.       break;
  1137.     case R_RunMain:
  1138.       b = set_breakpoint (BP_Code, 0, main_entry);
  1139.       user_screen ();
  1140.       go (1);
  1141.       reset_breakpoint (b);
  1142.       break;
  1143.     }
  1144.   first_step = 0;
  1145.   i = a_tss.tss_irqn;
  1146.   if ((terminated = (i == 0x21) && (a_tss.tss_eax & 0xff00) == 0x4c00))
  1147.     a_tss.tss_eip -= 2;     /* point back to Int 21h */
  1148.   if ((int03hit = (i == 0x03)
  1149.        && get_breakpoint (BP_Code, 0, a_tss.tss_eip - 1) != -1))
  1150.     a_tss.tss_eip--;  /* point back to Int 3 */
  1151.   if (tracing) return;
  1152.  
  1153.   /* Find out whether a breakpoint stopped us.  */
  1154.   no = -1;
  1155.   if (i == 1 || int03hit)
  1156.     {
  1157.       BP_ENTRY *bep;
  1158.  
  1159.       for (b = 0; b <= 3; b++)
  1160.     if ((edi.dr[6] & (1 << b)) && (edi.dr[7] & (3 << (b * 2))))
  1161.       {
  1162.         no = get_breakpoint (((edi.dr[7] >> (16 + 4 * b)) & 3),
  1163.                  ((edi.dr[7] >> (18 + 4 * b)) & 3) + 1,
  1164.                  edi.dr[b] - edi.app_base);
  1165.         break;
  1166.       }
  1167.       if (no == -1)
  1168.     no = get_breakpoint (BP_Code, 0, a_tss.tss_eip);
  1169.  
  1170.       bep = breakpoint_table + no;
  1171.       if (no != -1 && bep->type == BP_Code)
  1172.     {
  1173.       if (bep->condition)
  1174.         {
  1175.           char *errtxt;
  1176.           word32 val;
  1177.  
  1178.           if (evaluate (bep->condition, &val, &errtxt))
  1179.         {
  1180.           message (CL_Error, "Hit breakpoint with invalid condition");
  1181.           goto error;
  1182.         }
  1183.           if (val == 0)
  1184.         /* We hit a breakpoint, but its condition is not satisfied.*/
  1185.         goto retry;
  1186.         }
  1187.       if (--(bep->count) > 0)
  1188.         /* We hit a breakpoint but it is not yet mature.  */
  1189.         goto retry;
  1190.       bep->count = 0;
  1191.     }
  1192.     error:
  1193.     }
  1194.  
  1195.   code_pane_goto (a_tss.tss_eip);
  1196.   debug_screen ();
  1197.   redraw (0);
  1198.   while (kbhit ())
  1199.     (void) getxkey ();
  1200.  
  1201.   if (terminated)
  1202.     message (CL_Msg, "Program terminated normally, exit code is %d",
  1203.          (word8) a_tss.tss_eax);
  1204.   else if (i == 1 || int03hit)
  1205.     {
  1206.       if (no != -1)
  1207.     switch (breakpoint_table[no].type)
  1208.       {
  1209.       case BP_Code:
  1210.         if (!breakpoint_table[no].temporary)
  1211.           if (breakpoint_table[no].condition)
  1212.         message (CL_Msg, "Condition \"%s\" satisfied",
  1213.              breakpoint_table[no].condition);
  1214.           else
  1215.         message (CL_Info, "Code breakpoint hit");
  1216.         break;
  1217.       case BP_Write:
  1218.         message (CL_Msg, "Data write breakpoint at 0x%08lx triggered by previous instruction",
  1219.              breakpoint_table[no].addr);
  1220.         break;
  1221.       case BP_Read:
  1222.         message (CL_Msg, "Data read/write breakpoint at 0x%08lx triggered by previous instruction",
  1223.              breakpoint_table[no].addr);
  1224.         break;
  1225.       }
  1226.       else if (i == 1 && (edi.dr[6] & (1 << 13)))
  1227.     message (CL_Error, "User program used debug registers");
  1228.       else if (i == 1 && (edi.dr[6] & (1 << 15)))
  1229.     message (CL_Error, "Task switch caused debug exception");
  1230.       else if (i == 3 && !int03hit)
  1231.     message (CL_Error, "Unexpected Int 3 hit");
  1232.     }
  1233.   else if (i == 0x79 || i == 0x09)
  1234.     message (CL_Info, "Keyboard interrupt");
  1235.   else if (i == 0x75)
  1236.     {
  1237.       char *reason;
  1238.  
  1239.       save_npx ();
  1240.       if ((npx.status & 0x0241) == 0x0241)
  1241.     reason = "stack overflow";
  1242.       else if ((npx.status & 0x0241) == 0x0041)
  1243.     reason = "stack underflow";
  1244.       else if (npx.status & 1)
  1245.     reason = "invalid operation";
  1246.       else if (npx.status & 2)
  1247.     reason = "denormal operand";
  1248.       else if (npx.status & 4)
  1249.     reason = "divide by zero";
  1250.       else if (npx.status & 8)
  1251.     reason = "overflow";
  1252.       else if (npx.status & 16)
  1253.     reason = "underflow";
  1254.       else if (npx.status & 32)
  1255.     reason = "loss of precision";
  1256.       else
  1257.     reason = "?";
  1258.       message (CL_Error, "Numeric Exception (%s) at eip=0x%08lx",
  1259.            reason, npx.eip);
  1260.       load_npx ();
  1261.     }
  1262.   else if (i == 8 || (i >= 10 && i <= 14) || i == 17)
  1263.     message (CL_Error, "Exception %d (0x%02x) occurred, error code=%#lx",
  1264.          i, i, a_tss.tss_error);
  1265.   else
  1266.     message (CL_Error, "Exception %d (0x%02x) occurred", i, i);
  1267. }
  1268. /* ------------------------------------------------------------------------- */
  1269. /* Assuming EIP, ESP, and EBP as values for the obvious registers, track
  1270.    back one stack from.  Return non-zero on success.  */
  1271.  
  1272. static int
  1273. stack_trace (word32 *eip, word32 *esp, word32 *ebp)
  1274. {
  1275.   /* We look directly at the bit pattern instead of using disassembly;
  1276.      the bit patterns are those generated by gcc.  In general we
  1277.      cannot expect to be able to follow a non-gcc stack anyway.  */
  1278.   unsigned char eipcode[4];
  1279.  
  1280.   if (!valid_instaddr (*eip))
  1281.     return 0;
  1282.  
  1283.   read_child (*eip, eipcode, 3);
  1284.   if ((eipcode[0] == 0x55 && eipcode[1] == 0x89 && eipcode[2] == 0xe5)
  1285.       || eipcode[0] == 0xc3)
  1286.     {
  1287.       /* In this case where we are looking at `Push Ebp//Mov Ebp,Esp'
  1288.      or `Ret', only the return address is on the stack; I believe
  1289.      this only to happen in the innermost activation record.  */
  1290.       if (!valid_addr (*esp, 4))
  1291.     return 0;
  1292.       read_child (*esp, eip, 4);
  1293.       *esp += 4;
  1294.       return 1;
  1295.     }
  1296.   else
  1297.     {
  1298.       if (! (eipcode[0] == 0x89 && eipcode[1] == 0xe5))
  1299.      /* We are *not* looking at `Mov Ebp,Esp'.  */
  1300.     if (*ebp < 0x80000000UL && *ebp >= *esp && valid_addr (*ebp, 8))
  1301.       *esp = *ebp;
  1302.     else
  1303.       return 0;
  1304.       else
  1305.     if (!valid_addr (*esp, 8))
  1306.       return 0;
  1307.       read_child (*esp, ebp, 4);
  1308.       *esp += 4;
  1309.       read_child (*esp, eip, 4);
  1310.       *esp += 4;
  1311.       return 1;
  1312.     }
  1313. }
  1314. /* ------------------------------------------------------------------------- */
  1315. /* Trace execution path until a source point is reached, execution jumps,
  1316.    or LEVEL call levels is processed.  */
  1317.  
  1318. static word32
  1319. trace_till_source (word32 eip, int level, int mustmove)
  1320. {
  1321.   char *inst;
  1322.   unsigned char eipcode[5];
  1323.   int len;
  1324.   int line;
  1325.  
  1326.   while (valid_instaddr (eip) && (mustmove || !syms_val2line (eip, &line, 1)))
  1327.     {
  1328.       signed long offset;
  1329.       word32 try;
  1330.  
  1331.       mustmove = 0;
  1332.       read_child (eip, eipcode, 5);
  1333.       switch (eipcode[0])
  1334.     {
  1335.     case 0xea:
  1336.       offset = *((signed char *)(eipcode + 1));
  1337.       try = eip + 2 + offset;
  1338.       if (offset >= 0)
  1339.         {
  1340.           eip = try;
  1341.           continue;
  1342.         }
  1343.       break;
  1344.     case 0xe8:
  1345.       offset = *((signed long *)(eipcode + 1));
  1346.       try = eip + 5 + offset;
  1347.       if (offset >= 0)
  1348.         {
  1349.           eip = try;
  1350.           continue;
  1351.         }
  1352.       break;
  1353.     case 0xe9:
  1354.       offset = *((signed long *)(eipcode + 1));
  1355.       try = eip + 5 + offset;
  1356.       break;
  1357.     default:
  1358.       try = 0;
  1359.     }
  1360.  
  1361.       if (try && level && syms_val2line (try, &line, 0))
  1362.     {
  1363.       try = trace_till_source (try, level - 1, 0);
  1364.       if (try) return try;
  1365.     }
  1366.  
  1367.       inst = unassemble_proper (eip, &len);
  1368.       if (strncmp (inst, "ret", 3)
  1369.       && strncmp (inst, "call", 4)
  1370.       && strncmp (inst, "int", 3)
  1371.       && strncmp (inst, "iret", 4)
  1372.       && strncmp (inst, "loop", 4)
  1373.       && inst[0] != 'j')
  1374.     eip += len;
  1375.       else
  1376.     break;
  1377.     }
  1378.   if (syms_val2line (eip, &line, 1))
  1379.     return eip;
  1380.   else
  1381.     return 0;
  1382. }
  1383. /* ------------------------------------------------------------------------- */
  1384. /* Redraw all active panes.  If FIRST then also redraw the frames.  */
  1385.  
  1386. static void
  1387. redraw (int first)
  1388. {
  1389.   char *buf = alloca (cols);
  1390.  
  1391.   debug_screen ();
  1392.   screen_attr = ScreenAttrib = screen_attr_normal;
  1393.  
  1394.   if (first)
  1395.     {
  1396.       int y = toplines + 1, x1 = cols - 18, x2 = cols - 5, x3 = 46;
  1397.  
  1398.       frame (0, 0, cols - 1, rows - 1);
  1399.       frame (x2, 0, cols - 1, y);
  1400.       frame (x1, 0, x2, y);
  1401.       frame (x3, y, cols - 1, rows - 1);
  1402.       frame (0, y, x3, rows - 1);
  1403.  
  1404.       put (x2, 0, "┬");
  1405.       put (x2, y, "â”´");
  1406.       put (0, y, "├");
  1407.       put (cols - 1, y, "┤");
  1408.       put (x1, 0, "┬");
  1409.       put (x1, y, "â”´");
  1410.       put (x3, y, "┬");
  1411.       put (x3, rows - 1, "â”´");
  1412.     }
  1413.  
  1414.   {
  1415.     /* Show register status */
  1416.     int reg, x = cols - 17, y = 1, width = 12;
  1417.  
  1418.     for (reg = register_pane_origin; y <= toplines && regs_type[reg]; reg++)
  1419.       {
  1420.     if (regs_type[reg] == 's')
  1421.       sprintf (buf, " %s %04x",
  1422.            regs_names[reg],
  1423.            *(unsigned short *)(regs_addr[reg]));
  1424.     else
  1425.       sprintf (buf, "%s %08lx",
  1426.            regs_names[reg],
  1427.            *(regs_addr[reg]));
  1428.     putl (x, y++, width, buf);
  1429.       }
  1430.     while (y <= toplines)
  1431.       putl (x, y++, width, "");
  1432.   }
  1433.  
  1434.   {
  1435.     /* Show flags status */
  1436.     int f, x = cols - 4, y = 1, width = 3;
  1437.  
  1438.     for (f = flag_pane_origin; y <= toplines && flag_names[f]; f++)
  1439.       {
  1440.     sprintf (buf, "%c=%d",
  1441.          flag_names[f],
  1442.          (a_tss.tss_eflags & flag_bits[f]) != 0);
  1443.     put (x, y++, buf);
  1444.       }
  1445.     while (y <= toplines)
  1446.       putl (x, y++, width, "");
  1447.   }
  1448.  
  1449.   {
  1450.     /* Show breakpoints */
  1451.     int b, x = 47, y = toplines + 2, width = cols - 48;
  1452.     char *name;
  1453.     int32 delta;
  1454.  
  1455.     for (b = breakpoint_origin;
  1456.      b < breakpoint_origin + bottomlines / 2 && b < breakpoint_count;
  1457.      b++)
  1458.       {
  1459.     switch (breakpoint_table[b].type)
  1460.       {
  1461.       case BP_Code:
  1462.         sprintf (buf, "Execute: %08lx",
  1463.              breakpoint_table[b].addr);
  1464.         break;
  1465.       case BP_Write:
  1466.         sprintf (buf, "Data write: %08lx, %d",
  1467.              breakpoint_table[b].addr, breakpoint_table[b].length);
  1468.         break;
  1469.       case BP_Read:
  1470.         sprintf (buf, "Data read: %08lx, %d",
  1471.              breakpoint_table[b].addr, breakpoint_table[b].length);
  1472.         break;
  1473.       }
  1474.     putl (x, y++, width, buf);
  1475.  
  1476.     name = syms_val2name (breakpoint_table[b].addr, &delta);
  1477.     if (name[0] != '0')
  1478.       if (delta && strlen (name) < width)
  1479.         sprintf (buf, " %s+%#lx", name, delta);
  1480.       else
  1481.         sprintf (buf, " %-*s", width, name);
  1482.     else
  1483.       buf[0] = '\0';
  1484.     putl (x, y++, width , buf);
  1485.       }
  1486.     if (breakpoint_count == 0)
  1487.       putl (x, y++, width, "No breakpoints");
  1488.     while (y < rows - 1)
  1489.       putl (x, y++, width, "");
  1490.   }
  1491.  
  1492.   if (data_pane_active)
  1493.     {
  1494.       /* Show data dump */
  1495.       word32 p = data_dump_origin;
  1496.       int b, x, y = toplines + 2, ok, width = 45;
  1497.       unsigned char data[8], xpos[8];
  1498.  
  1499.       for (x = 0; x < 8; x++)
  1500.     xpos[x] = 10
  1501.       + ((data_dump_size == 1) ? (x * 3) :
  1502.          ((data_dump_size == 2) ? ((x / 2) * 5 + (~x & 1) * 2) :
  1503.           ((x / 4) * 9 + (~x & 3) * 2)));
  1504.  
  1505.       while (y < rows - 1)
  1506.     {
  1507.       if ((ok = valid_addr (p, 8)))
  1508.         read_child (p, data, 8);
  1509.  
  1510.       sprintf (buf, "%08lx: %35s", p, "");
  1511.       for (x = 0; x < 8; x++)
  1512.         if (ok || valid_addr (p + x, 1))
  1513.           {
  1514.         if (!ok) read_child (p + x, data + x, 1);
  1515.         buf[xpos[x]] = hexchars[data[x] >> 4];
  1516.         buf[xpos[x] + 1] = hexchars[data[x] & 0xf];
  1517.         buf[37 + x] = (data[x] ? data[x] : '.');
  1518.           }
  1519.         else
  1520.           buf[xpos[x]] = buf[xpos[x] + 1] = buf[37 + x] = '?';
  1521.       putl (1, y, width, buf);
  1522.  
  1523.       screen_attr = screen_attr_break;
  1524.       for (x = 0; x < 8; x++)
  1525.         for (b = 0; b < breakpoint_count; b++)
  1526.           if (breakpoint_table[b].type != BP_Code
  1527.           && p + x >= breakpoint_table[b].addr
  1528.           && p + x < (breakpoint_table[b].addr
  1529.                   + breakpoint_table[b].length))
  1530.         {
  1531.           highlight (xpos[x] + 1, y, 2);
  1532.           highlight (38 + x, y, 1);
  1533.         }
  1534.       screen_attr = screen_attr_normal;
  1535.       p += 8;
  1536.       y++;
  1537.     }
  1538.       data_dump_last = p - 1;
  1539.     }
  1540.  
  1541.   if (code_pane_active)
  1542.   {
  1543.     /* Show code dump */
  1544.     word32 p = code_dump_origin, width = cols - 19;
  1545.     int y = 1, len, source = 0;
  1546.     char *txt;
  1547.  
  1548.     while (y <= toplines)
  1549.       {
  1550.     source = !source;
  1551.     code_pane_pos[y - 1] = p;
  1552.     if (source)
  1553.       {
  1554.         txt = unassemble_source (p);
  1555.         if (txt)
  1556.           {
  1557.         screen_attr = screen_attr_source;
  1558.         putl (1, y++, width, txt);
  1559.           }
  1560.       }
  1561.     else
  1562.       {
  1563.         if (valid_instaddr (p))
  1564.           txt = unassemble_proper (p, &len);
  1565.         else
  1566.           txt = "?", len = 1;
  1567.         sprintf (buf, "%08lx%c%s",
  1568.              p,
  1569.              p == a_tss.tss_eip ? 16 : ' ',
  1570.              txt);
  1571.         screen_attr =
  1572.           (get_breakpoint (BP_Code, 0, p) == -1
  1573.            ? screen_attr_normal : screen_attr_break);
  1574.         putl (1, y++, width, buf);
  1575.         p += len;
  1576.       }
  1577.       }
  1578.     code_pane_pos[y - 1] = p + 1;
  1579.     code_dump_last = p - 1;
  1580.     screen_attr = screen_attr_normal;
  1581.   }
  1582.  
  1583.   if (npx_pane_active)
  1584.   {
  1585.     /* Show npx dump */
  1586.     int i, y = 1, width = cols - 19;
  1587.     static char *rtype[] = { "Near", "-Inf", "+Inf", "Zero" };
  1588.  
  1589.     save_npx ();
  1590.     sprintf (buf,
  1591.          "Control: %04lx PR=%s UN=%s OV=%s ZD=%s DN=%s IV=%s Rnd=%s",
  1592.          npx.control & 0xffff,
  1593.          (npx.control & (1 << 5)) ? "N" : "Y",
  1594.          (npx.control & (1 << 4)) ? "N" : "Y",
  1595.          (npx.control & (1 << 3)) ? "N" : "Y",
  1596.          (npx.control & (1 << 2)) ? "N" : "Y",
  1597.          (npx.control & (1 << 1)) ? "N" : "Y",
  1598.          (npx.control & (1 << 0)) ? "N" : "Y",
  1599.          rtype[(npx.control >> 10) & 3]);
  1600.     putl (1, y++, width, buf);
  1601.     sprintf (buf,
  1602.          "Status:  %04lx PR=%s UN=%s OV=%s ZD=%s DN=%s IV=%s ST=%s",
  1603.          npx.status & 0xffff,
  1604.          (npx.status & (1 << 5)) ? "Y" : "N",
  1605.          (npx.status & (1 << 4)) ? "Y" : "N",
  1606.          (npx.status & (1 << 3)) ? "Y" : "N",
  1607.          (npx.status & (1 << 2)) ? "Y" : "N",
  1608.          (npx.status & (1 << 1)) ? "Y" : "N",
  1609.          (npx.status & (1 << 0)) ? "Y" : "N",
  1610.          (npx.status & (1 << 6)) ? "Y" : "N");
  1611.     putl (1, y++, width, buf);
  1612.     sprintf (buf, "%19sC3=%d C2=%d C1=%d C0=%d",
  1613.          "",
  1614.          (npx.status & (1 << 14)) != 0,
  1615.          (npx.status & (1 << 10)) != 0,
  1616.          (npx.status & (1 <<  9)) != 0,
  1617.          (npx.status & (1 <<  8)) != 0);
  1618.     if (y <= toplines) putl (1, y++, width, buf);
  1619.  
  1620.     for (i = 0; y <= toplines && i < 8; i++)
  1621.       {
  1622.     /* We assume that `long double' is the same type as npx.reg[i].
  1623.        It would be sensible to check that the sizes match, but they
  1624.        don't!  For alignment reasons, `sizeof (long double)' is 12.     */
  1625.     long double d;
  1626.     int tag;
  1627.     int tos = (npx.status >> 11) & 7;
  1628.     int exp = (int)npx.reg[i].exponent - 16382;
  1629.     char *dstr = alloca (30);
  1630.  
  1631.     dstr[0] = (npx.reg[i].sign) ? '-' : '+';
  1632.     dstr[1] = '\0';
  1633.     tag = (npx.tag >> (((i + tos) & 7) * 2)) & 3;
  1634.     switch (tag)
  1635.       {
  1636.       case 0:
  1637.         if (abs (exp) < 1000)
  1638.           {
  1639.         d = *((long double*)(npx.reg + i));
  1640.         /* sprintf does not (djgpp 1.11m3) handle long doubles.     */
  1641.         sprintf(dstr,"%+.16g", (double) d);
  1642.           }
  1643.         else
  1644.           sprintf (dstr, "Valid, %s, and %s",
  1645.                npx.reg[i].sign ? "negative" : "positive",
  1646.                exp > 0 ? "huge" : "tiny");
  1647.         break;
  1648.       case 1:
  1649.         strcat (dstr, "Zero");
  1650.         break;
  1651.       case 2:
  1652.         if (npx.reg[i].exponent == 0x7fff)
  1653.           if (npx.reg[i].sig3 == 0x8000
  1654.           && npx.reg[i].sig2 == 0x0000
  1655.           && npx.reg[i].sig1 == 0x0000
  1656.           && npx.reg[i].sig0 == 0x0000)
  1657.         strcat (dstr, "Inf");
  1658.           else
  1659.         strcat (dstr, "NaN");
  1660.         else
  1661.           dstr = "Special";
  1662.         break;
  1663.       case 3:
  1664.         dstr = "Empty";
  1665.         break;
  1666.       }
  1667.     sprintf (buf, "st(%d): %d %04x %04x%04x%04x%04x %s",
  1668.          i,
  1669.          npx.reg[i].sign, npx.reg[i].exponent,
  1670.          npx.reg[i].sig3, npx.reg[i].sig2,
  1671.          npx.reg[i].sig1, npx.reg[i].sig0,
  1672.          dstr);
  1673.     putl (1, y++, width, buf);
  1674.       }
  1675.     while (y <= toplines)
  1676.       putl (1, y++, width, "");
  1677.     load_npx ();
  1678.   }
  1679.  
  1680.   if (stack_pane_active)
  1681.   {
  1682.     /* Show stack dump */
  1683.     int y = 1, no = -stack_dump_origin, width = cols - 19;
  1684.     word32 delta;
  1685.     word32 ebp = a_tss.tss_ebp;
  1686.     word32 esp = a_tss.tss_esp;
  1687.     word32 eip = a_tss.tss_eip;
  1688.  
  1689.     stack_dump_more = 0;
  1690.     while (valid_instaddr (eip))
  1691.       {
  1692.     if (no++ >= 0)
  1693.       if (y > toplines)
  1694.         {
  1695.           stack_dump_more = 1;
  1696.           break;
  1697.         }
  1698.       else
  1699.         {
  1700.           char *symaddr, *sourceaddr, *sourcefile;
  1701.           int line, len;
  1702.  
  1703.           symaddr = syms_val2name (eip, &delta);
  1704.           sourcefile = syms_val2line (eip, &line, 0);
  1705.           if (sourcefile)
  1706.         {
  1707.           sourceaddr = alloca (cols + strlen (sourcefile));
  1708.           sprintf (sourceaddr, ", line %d in file %s",
  1709.                line, sourcefile);
  1710.         }
  1711.           else if (delta)
  1712.         {
  1713.           sourceaddr = alloca (cols);
  1714.           sprintf (sourceaddr, "%+ld", (long) delta);
  1715.         }
  1716.           else
  1717.         sourceaddr = "";
  1718.           len = 15 + strlen (symaddr) + strlen (sourceaddr);
  1719.           if (len >= cols)
  1720.         buf = alloca (len);
  1721.           sprintf (buf, "%08lx: %s%s", eip, symaddr, sourceaddr);
  1722.           stack_dump_pos[stack_dump_last = y - 1] = eip;
  1723.           putl (1, y++, width, buf);
  1724.         }
  1725.  
  1726.     if (!stack_trace (&eip, &esp, &ebp))
  1727.       break;
  1728.       }
  1729.     while (y <= toplines)
  1730.       putl (1, y++, width, "");
  1731.   }
  1732.  
  1733.   if (info_pane_active)
  1734.   {
  1735.     /* Show info */
  1736.     int y = 1, width = cols - 19;
  1737.     long ul;
  1738.     char *s;
  1739.     _go32_dpmi_meminfo info;
  1740.     _go32_dpmi_registers regs;
  1741.  
  1742. #define OUT(s) if (y <= toplines) putl (1, y++, width, (s));
  1743.  
  1744.     sprintf (buf, "Debugger version ............: %.2f %s",
  1745.          FULLSCR_VERSION,
  1746.          FULLSCR_VERSION < 1.00 ? "beta" : "");
  1747.     OUT (buf);
  1748.     switch (_go32_info_block.run_mode)
  1749.       {
  1750.       case _GO32_RUN_MODE_RAW:
  1751.     s = "Raw";
  1752.     break;
  1753.       case _GO32_RUN_MODE_XMS:
  1754.     s = "Xms";
  1755.     break;
  1756.       case _GO32_RUN_MODE_VCPI:
  1757.     s = "Vcpi";
  1758.     break;
  1759.       case _GO32_RUN_MODE_DPMI:
  1760.     s = alloca (20);
  1761.     sprintf (s,
  1762. #ifdef V2DBG
  1763.          "Dpmi %d.%02d",
  1764. #else
  1765.          "Dpmi %d.%02x",
  1766. #endif
  1767.          _go32_info_block.run_mode_info >> 8,
  1768.          _go32_info_block.run_mode_info & 0xff);
  1769.     break;
  1770.       default:
  1771.     s = "Unknown";
  1772.       }
  1773.     sprintf (buf, "Running mode ................: %s", s);
  1774.     OUT (buf);
  1775.     sprintf (buf, "Protection ring .............: %d (in %s)",
  1776.          a_tss.tss_cs & 3,
  1777.          (a_tss.tss_cs & 4) ? "LDT" : "GDT");
  1778.     OUT (buf);
  1779.     asm volatile ("pushfl ; popl %0" : "=g" (ul));
  1780.     sprintf (buf, "I/O protected ...............: %s",
  1781.          (a_tss.tss_cs & 3) > ((ul >> 12) & 3)
  1782.          ? "Yes" : "No");
  1783.     OUT (buf);
  1784.     sprintf (buf, "Ctrl-C checking .............: %s",
  1785.          getcbrk () ? "On" : "Off");
  1786.     OUT (buf);
  1787.     OUT ("");
  1788.  
  1789.     _go32_dpmi_get_free_memory_information (&info);
  1790.     ul = info.total_physical_pages;
  1791.     if (ul > 0)
  1792.       {
  1793.     ul <<= 12;
  1794.     sprintf (buf, "Total physical memory .......: %lu KB", ul >> 10);
  1795.     OUT (buf);
  1796.       }
  1797.     ul = info.available_physical_pages
  1798.       ? info.available_physical_pages << 12
  1799.     : info.available_memory;
  1800.     sprintf (buf, "Remaining physical memory ...: %lu KB", ul >> 10);
  1801.     OUT (buf);
  1802.     ul = info.available_memory;
  1803.     sprintf (buf, "Remaining virtual memory ....: %lu KB", ul >> 10);
  1804.     OUT (buf);
  1805.     ul = info.free_linear_space << 12;
  1806.     if (ul >= 0)
  1807.       {
  1808.     sprintf (buf, "Free linear space ...........: %ld KB", ul >> 10);
  1809.     OUT (buf);
  1810.       }
  1811.     /* Recall that Dos memory is only made available of direct request;
  1812.        using 0xffff does not count as a request.  */
  1813.     regs.h.ah = 0x48;
  1814.     regs.x.bx = 0xffff;
  1815.     regs.x.ss = regs.x.sp = 0;
  1816.     _go32_dpmi_simulate_int (0x21, ®s);
  1817.     ul = regs.x.bx << 4;
  1818.     sprintf (buf, "Free dos memory .............: %ld %s",
  1819.          ul > 8192 ? ul >> 10 : ul,
  1820.          ul > 8192 ? "KB"      : "Bytes");
  1821.     OUT (buf);
  1822.     OUT ("");
  1823.  
  1824. #ifndef V2DBG
  1825.     sprintf (buf, "Program text ................: %08lx - %08lx",
  1826.          areas[A_text].first_addr, areas[A_text].last_addr);
  1827.     OUT (buf);
  1828.     sprintf (buf, "Program data ................: %08lx - %08lx",
  1829.          areas[A_data].first_addr, areas[A_data].last_addr);
  1830.     OUT (buf);
  1831.     sprintf (buf, "Program bss .................: %08lx - %08lx",
  1832.          areas[A_bss].first_addr, areas[A_bss].last_addr);
  1833.     OUT (buf);
  1834.     sprintf (buf, "Program stack ...............: %08lx - %08lx",
  1835.          areas[A_stack].first_addr, areas[A_stack].last_addr);
  1836.     OUT (buf);
  1837. #endif
  1838. #undef OUT
  1839.  
  1840.     while (y <= toplines)
  1841.       putl (1, y++, width, "");
  1842.   }
  1843.  
  1844.   if (whereis_pane_active)
  1845.   {
  1846.     /* Show result of last whereis command */
  1847.     int y = 1, width = cols - 19, i = whereis_pane_origin;
  1848.  
  1849.     if (whereis_text_count == 0)
  1850.       putl (1, y++, width, "(No symbols matched on last search)");
  1851.     while (y <= toplines)
  1852.       if (i < whereis_text_count)
  1853.     putl (1, y++, width, whereis_pane_text[i++]);
  1854.       else
  1855.     putl (1, y++, width, "");
  1856.   }
  1857.  
  1858.   if (gdt_pane_active || idt_pane_active || ldt_pane_active)
  1859.   {
  1860.     /* Show descriptor info.  */
  1861.     int y = 1, width = cols - 19, i;
  1862.     char *buf1;
  1863.     GDT_S descr;
  1864.     int typ, count;
  1865.     word32 base;
  1866.  
  1867.     if (gdt_pane_active)
  1868.       {
  1869.     typ = 0;
  1870.     count = (gdtlinear.limit + 1) / 8;
  1871.     base = gdtlinear.base;
  1872.     i = gdt_pane_origin;
  1873.       }
  1874.     else if (idt_pane_active)
  1875.       {
  1876.     typ = 1;
  1877.     count = MIN((idtlinear.limit + 1) / 8, 0x100);
  1878.     base = idtlinear.base;
  1879.     i = idt_pane_origin;
  1880.       }
  1881.     else if (ldt_pane_active)
  1882.       {
  1883.     int ldt;
  1884.     word32 limit;
  1885.  
  1886.     asm volatile
  1887.       ("xorl  %%eax,%%eax
  1888.         sldt  %%ax
  1889.         movl  %%eax,%0"
  1890.        : "=r" ((int)(ldt))
  1891.        : /* no inputs.  */
  1892.        : "%eax");
  1893.  
  1894.     if (ldt / 8 == 0)
  1895.       {
  1896.         ldtlinear.base = ldtlinear.limit = 0;
  1897.         putl (1, y++, width, "There is no local descriptor table.");
  1898.       }
  1899.     else
  1900.       {
  1901.         /* We can always get the limit with the `lsl' instruction, but
  1902.            there seems to be no other way of getting the base.  */
  1903.         if (getdescriptor (gdtlinear.base, ldt / 8, &descr) != 2)
  1904.           putl (1, y++, width, "LDT is present, but unreadable.");
  1905.         else
  1906.           {
  1907.         base = ldtlinear.base = descr.base0
  1908.           | ((word32)descr.base1 << 16)
  1909.             | ((word32)descr.base2 << 24);
  1910.         limit = ((descr.lim1 & 0x0f) << 16) | descr.lim0;
  1911.         if (descr.lim1 & 0x80)
  1912.           limit = (limit << 12) | 0xfff;
  1913.         ldtlinear.limit = (limit > 0xffff) ? 0xffff : limit;
  1914.           }
  1915.       }
  1916.     typ = 2;
  1917.     base = ldtlinear.base;
  1918.     count = (ldtlinear.limit + 1) / 8;
  1919.     i = ldt_pane_origin;
  1920.       }
  1921.     else
  1922.       abort ();
  1923.  
  1924.     while (y <= toplines)
  1925.       if (i < count)
  1926.     {
  1927.       if (i == 0 && typ == 0)
  1928.         buf1 = "(null entry)";
  1929.       else
  1930.         {
  1931.           if (getdescriptor (base, i, &descr) < 0)
  1932.         buf1 = "Read failure.";
  1933.           else
  1934.         {
  1935.           buf1 = alloca (80);
  1936.           describedescriptor (buf1, &descr, typ);
  1937.         }
  1938.         }
  1939.       if (typ == 1)
  1940.         sprintf (buf, "%02x: %s", i, buf1);
  1941.       else if (dpmi || typ == 2)
  1942.         sprintf (buf, "%03x: %s",
  1943.              i * 8 | (typ ? ((a_tss.tss_cs & 3) | 4) : 0),
  1944.              buf1);
  1945. #ifndef V2DBG
  1946.       else
  1947.         sprintf (buf, "%02x: %-13s %s",
  1948.              i * 8,
  1949.              i < g_num ? gdtnames[i] : "?",
  1950.              buf1);
  1951. #endif
  1952.       putl (1, y++, width, buf);
  1953.       i++;
  1954.     }
  1955.       else
  1956.     putl (1, y++, width, "");
  1957.   }
  1958.  
  1959.   if (help_pane_active)
  1960.   {
  1961.     /* Show help info.  */
  1962.     int y = 1, width = cols - 19, i = help_pane_origin;
  1963.     int count = sizeof (helptext) / sizeof (char *);
  1964.  
  1965.     while (y <= toplines)
  1966.       if (i < count)
  1967.     putl (1, y++, width, helptext[i++]);
  1968.       else
  1969.     putl (1, y++, width, "");
  1970.   }
  1971.  
  1972.   if (module_pane_active)
  1973.   {
  1974.     int y = 1, width = cols - 19, i = module_pane_origin;
  1975.  
  1976.     while (y <= toplines)
  1977.       if (i < module_text_count)
  1978.     putl (1, y++, width, module_pane_text[i++]);
  1979.       else
  1980.     putl (1, y++, width, "");
  1981.   }
  1982.  
  1983.   if (source_pane_active)
  1984.   {
  1985.     int y = 1, width = cols - 19, i = source_pane_origin;
  1986.  
  1987.     if (source_text_count == 0)
  1988.       putl (1, y++, width, "(No module selected)");
  1989.     while (y <= toplines)
  1990.       {
  1991.     screen_attr = screen_attr_source;
  1992.     if (i < source_text_count)
  1993.       {
  1994.         word32 addr = find_source_line (i, 1);
  1995.         char *buf;
  1996.  
  1997.         buf = source_pane_text[i++];
  1998.         if (addr)
  1999.           {
  2000.         if (get_breakpoint (BP_Code, 0, addr) != -1)
  2001.           screen_attr = screen_attr_break;
  2002.         if (addr == a_tss.tss_eip && strlen (buf) > 6)
  2003.           {
  2004.             char *newbuf = alloca (strlen (buf) + 1);
  2005.             buf = strcpy (newbuf, buf);
  2006.             buf[5] = 16;
  2007.           }
  2008.           }
  2009.         putl (1, y++, width, buf);
  2010.       }
  2011.     else
  2012.       putl (1, y++, width, "");
  2013.       }
  2014.     screen_attr = screen_attr_normal;
  2015.   }
  2016.  
  2017.   if (watch_pane_active)
  2018.   {
  2019.     int y = toplines + 2, width = 45, i = watch_pane_origin;
  2020.  
  2021.     if (watch_text_count == 0)
  2022.       putl (1, y++, width, "(No watches specified)");
  2023.     while (y - (toplines + 1) <= bottomlines)
  2024.       if (i < watch_text_count)
  2025.     {
  2026.       word32 val;
  2027.       char *errtxt, *valtxt, *exprtxt;
  2028.       int l;
  2029.  
  2030.       if (evaluate (watch_pane_text[i], &val, &errtxt))
  2031.         {
  2032.           valtxt = errtxt;
  2033.           if (strlen (errtxt) > width - 5)
  2034.         {
  2035.           valtxt = alloca (width - 4);
  2036.           strncpy (valtxt, errtxt, width - 4);
  2037.           valtxt[width - 5] = 0;
  2038.         }
  2039.         }
  2040.       else
  2041.         {
  2042.           valtxt = alloca (30);
  2043.           sprintf (valtxt, "%ld (%08lx)", val, val);
  2044.         }
  2045.       l = width - strlen (valtxt) - 3;
  2046.       exprtxt = alloca (l + 1);
  2047.       strncpy (exprtxt, watch_pane_text[i], l + 1);
  2048.       if (exprtxt[l])
  2049.         exprtxt[l - 3] = exprtxt[l - 2] = exprtxt[l - 1] = '.',
  2050.         exprtxt[l] = 0;
  2051.       sprintf (buf, "%s \032 %s", exprtxt, valtxt);
  2052.       putl (1, y++, width, buf);
  2053.       i++;
  2054.     }
  2055.       else
  2056.     putl (1, y++, width, "");
  2057.   }
  2058.  
  2059.   {
  2060.     /* Highlight focus */
  2061.     screen_attr = screen_attr_focus;
  2062.  
  2063.     switch (pane)
  2064.       {
  2065.       case PANE_STACK:
  2066.     pane_pos = MIN (pane_pos, stack_dump_last);
  2067.     /* Fall through */
  2068.       case PANE_CODE:
  2069.       case PANE_NPX:
  2070.       case PANE_GDT:
  2071.       case PANE_IDT:
  2072.       case PANE_LDT:
  2073.       case PANE_HELP:
  2074.       case PANE_SOURCE:
  2075.       case PANE_MODULE:
  2076.       case PANE_WHEREIS:
  2077.     pane_pos = MIN (pane_pos, toplines - 1);
  2078.     highlight (1, pane_pos + 1, cols - 19);
  2079.     break;
  2080.       case PANE_REGISTER:
  2081.     pane_pos = MIN (pane_pos, toplines - 1);
  2082.     highlight (cols - 17, pane_pos + 1, 12);
  2083.     break;
  2084.       case PANE_FLAG:
  2085.     pane_pos = MIN (pane_pos, toplines - 1);
  2086.     highlight (cols - 4, pane_pos + 1, 3);
  2087.     break;
  2088.       case PANE_BREAKPOINT:
  2089.     {
  2090.       int y;
  2091.       if (breakpoint_origin >= breakpoint_count)
  2092.         breakpoint_origin = breakpoint_count ? breakpoint_count - 1 : 0;
  2093.       if (breakpoint_origin + pane_pos >= breakpoint_count)
  2094.         pane_pos = breakpoint_count - breakpoint_origin;
  2095.       y = 2 * pane_pos;
  2096.       if (y + 1 < bottomlines)
  2097.         {
  2098.           highlight (47, toplines + 2 + y++, cols - 48);
  2099.           highlight (47, toplines + 2 + y++, cols - 48);
  2100.         }
  2101.     }
  2102.     break;
  2103.       case PANE_DATA:
  2104.     {
  2105.       int x = pane_pos & 7, y = pane_pos >> 3;
  2106.       int width1 = 2 * data_dump_size;
  2107.       int shift = data_dump_size >> 1;  /* log2 really.  */
  2108.  
  2109.       if (y < bottomlines)
  2110.         {
  2111.           highlight (38 + x, toplines + 2 + y, data_dump_size);
  2112.           highlight (11 + (width1 + 1) * (x >> shift),
  2113.              toplines + 2 + y, width1);
  2114.         }
  2115.     }
  2116.     break;
  2117.       case PANE_WATCH:
  2118.     pane_pos = MIN (pane_pos, bottomlines - 1);
  2119.     highlight (1, toplines + 2 + pane_pos, 45);
  2120.     break;
  2121.       }
  2122.     screen_attr = screen_attr_normal;
  2123.   }
  2124.  
  2125.   put_screen (debug_screen_save);
  2126. }
  2127. /* ------------------------------------------------------------------------- */
  2128. /* Initialize the display structures.  Unless FIRSTTIME free the old
  2129.    dynamically allocated structures.  */
  2130.  
  2131. void
  2132. initdisplay (int firsttime)
  2133. {
  2134.   init_screen ();
  2135.   if (firsttime)
  2136.     debug_screen_p = 0;
  2137.   else
  2138.     {
  2139.       free (read_buffer);
  2140.       free (code_pane_pos);
  2141.       free (stack_dump_pos);
  2142.       free (debug_screen_save);
  2143.     }
  2144.  
  2145.   read_buffer = xmalloc (cols + 10);
  2146.   code_pane_pos = xmalloc ((toplines + 2) * sizeof (word32));
  2147.   stack_dump_pos = xmalloc ((toplines + 2) * sizeof (word32));
  2148.   debug_screen_save = get_screen ();
  2149.   redraw (1);
  2150.   if (!dual_monitor_p)
  2151.     {
  2152.       /* Patch cursor pos.  */
  2153.       debug_screen_save[1] = debug_screen_save[2] = 0;
  2154.     }
  2155. }
  2156. /* ------------------------------------------------------------------------- */
  2157. static void
  2158. setup_save (int dummy)
  2159. {
  2160.   FILE *f;
  2161.   int i;
  2162.  
  2163.   f = fopen (setupfilename, "wt");
  2164.   if (f)
  2165.     {
  2166.       fprintf (f, "# Sally Full Screen Debugger version %.2f\n",
  2167.            FULLSCR_VERSION);
  2168.       fprintf (f, "\n[Colours]\n");
  2169.       fprintf (f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
  2170.            screen_attr_normal,
  2171.            screen_attr_source,
  2172.            screen_attr_focus,
  2173.            screen_attr_break,
  2174.            screen_attr_message,
  2175.            screen_attr_error,
  2176.            screen_attr_menu,
  2177.            screen_attr_menufocus,
  2178.            screen_attr_editframe,
  2179.            screen_attr_edittxt,
  2180.            screen_attr_editfield,
  2181.            screen_attr_editfocus);
  2182.       if (breakpoint_count > 0)
  2183.     {
  2184.       BP_ENTRY *bep = breakpoint_table;
  2185.       fprintf (f, "\n[Breakpoints]\n%d\n", breakpoint_count);
  2186.       for (i = 0; i < breakpoint_count; i++, bep++)
  2187.         {
  2188.           char *name, *buf;
  2189.           word32 delta;
  2190.  
  2191.           name = syms_val2name (bep->addr, &delta);
  2192.           if (delta)
  2193.         {
  2194.           buf = alloca (strlen (name) + 20);
  2195.           sprintf (buf, "%s%+ld", name, delta);
  2196.         }
  2197.           else
  2198.         buf = name;
  2199.           fprintf (f, "%d %s %d %d %d %s\n",
  2200.                bep->type,
  2201.                buf,
  2202.                bep->count,
  2203.                bep->length,
  2204.                bep->disabled,
  2205.                bep->condition ? : "");
  2206.         }
  2207.     }
  2208.       fclose (f);
  2209.     }
  2210.   else
  2211.     message (CL_Error, "Cannot write to file \"%s\"", setupfilename);
  2212. }
  2213. /* ------------------------------------------------------------------------- */
  2214. static void
  2215. setup_restore (int booting)
  2216. {
  2217.   FILE *f = 0;
  2218.   char *err = "Corrupted setup file";
  2219.  
  2220.   f = fopen (setupfilename, "rt");
  2221.   if (f)
  2222.     {
  2223.       char version[5], myversion[5], section[21];
  2224.  
  2225.       if (fscanf (f, "# Sally Full Screen Debugger version %4s", version) != 1)
  2226.     goto error;
  2227.       sprintf (myversion, "%.2f", FULLSCR_VERSION);
  2228.       if (strcmp (version, myversion))
  2229.     {
  2230.       err = "Setup file is from a different debugger version";
  2231.       goto error;
  2232.     }
  2233.  
  2234.       while (fscanf (f, "\n[%20s\n", section) == 1)
  2235.     {
  2236.       if (stricmp (section, "Colours]") == 0)
  2237.         {
  2238.           int a[12];
  2239.           if (fscanf (f, "%d %d %d %d %d %d %d %d %d %d %d %d",
  2240.               a + 0, a + 1, a + 2, a + 3, a + 4, a + 5,
  2241.               a + 6, a + 7, a + 8, a + 9, a + 10, a + 11) != 12)
  2242.         goto error;
  2243.           screen_attr_normal = a[0];
  2244.           screen_attr_source = a[1];
  2245.           screen_attr_focus = a[2];
  2246.           screen_attr_break = a[3];
  2247.           screen_attr_message = a[4];
  2248.           screen_attr_error = a[5];
  2249.           screen_attr_menu = a[6];
  2250.           screen_attr_menufocus = a[7];
  2251.           screen_attr_editframe = a[8];
  2252.           screen_attr_edittxt = a[9];
  2253.           screen_attr_editfield = a[10];
  2254.           screen_attr_editfocus = a[11];
  2255.         }
  2256.       else if (stricmp (section, "Breakpoints]") == 0)
  2257.         {
  2258.           int b, count;
  2259.           char addr[1000], cond[1000];
  2260.           word32 res;
  2261.           char *errtxt;
  2262.  
  2263.           if (fscanf (f, "%d", &count) != 1)
  2264.         goto error;
  2265.           while (count-- > 0)
  2266.         {
  2267.           int a[4];
  2268.           if (fscanf (f, "%d %999s %d %d %d",
  2269.                   a + 0, addr, a + 1, a + 2, a + 3) != 5)
  2270.             goto error;
  2271.           fgets (cond, sizeof (cond), f);
  2272.           if (evaluate (addr, &res, &errtxt))
  2273.             if (booting)
  2274.               fprintf (stderr,
  2275.                    "Ignoring out-of-date breakpoint at %s.\n",
  2276.                    addr);
  2277.             else
  2278.               message (CL_Error,
  2279.                    "Ignoring out-of-date breakpoint at %s",
  2280.                    addr);
  2281.           else
  2282.             {
  2283.               b = set_breakpoint (a[0], a[2], res);
  2284.               breakpoint_table[b].count = a[1];
  2285.               breakpoint_table[b].disabled = a[3];
  2286.               breakpoint_table[b].condition
  2287.             = cond[0] ? strdup (cond) : 0;
  2288.             }
  2289.         }
  2290.         }
  2291.       else
  2292.         goto error;
  2293.     }
  2294.       fclose (f);
  2295.       return;
  2296.     }
  2297.   else
  2298.     err = "Cannot read setup file";
  2299.  
  2300.  error:
  2301.   if (f) fclose (f);
  2302.   if (booting)
  2303.     fprintf (stderr, "%s.\n", err);
  2304.   else
  2305.     message (CL_Error, err);
  2306. }
  2307. /* ------------------------------------------------------------------------- */
  2308. static void
  2309. initialize_module ()
  2310. {
  2311.   char *s;
  2312.   int i;
  2313.  
  2314.   module_text_count = 1;
  2315.   module_pane_text = xmalloc (module_text_count * sizeof (char *));
  2316.   module_line_numbers = xmalloc (module_text_count * sizeof (int));
  2317.   i = 0;
  2318.   s = syms_module (i++);
  2319.   while (s)
  2320.   {
  2321.     if (strcmp ("fake", s) && cache_fopen (s) != NULL)
  2322.       {
  2323.     module_pane_text
  2324.       = xrealloc (module_pane_text, ++module_text_count * sizeof (char *));
  2325.     module_line_numbers
  2326.       = xrealloc (module_line_numbers, module_text_count * sizeof (int));
  2327.     module_pane_text[module_text_count - 1] = strdup (s);
  2328.     module_line_numbers[module_text_count - 1] = 1;
  2329.       }
  2330.     s = syms_module (i++);
  2331.   }
  2332.   if (module_text_count == 1)
  2333.     module_pane_text[0] = strdup ("No modules with debug information.");
  2334.   else
  2335.     {
  2336.       module_pane_text[0] = strdup ("Modules listing:");
  2337.       pane_positions[PANE_MODULE] = 1;
  2338.     }
  2339.   module_line_numbers[0] = 1;
  2340.   source_pane_module = 0;
  2341. }
  2342. /* ---------------------------------------------------------------------- */
  2343. /* Select a pane, i.e., make it active.  */
  2344. static void
  2345. select_pane (int p)
  2346. {
  2347.   pane_positions[pane] = pane_pos;
  2348.  
  2349.   register_pane_active   = 1 || (p == PANE_REGISTER);
  2350.   flag_pane_active       = 1 || (p == PANE_FLAG);
  2351.   breakpoint_pane_active = 1 || (p == PANE_BREAKPOINT);
  2352.   switch (p)
  2353.     {
  2354.     case PANE_REGISTER:
  2355.     case PANE_FLAG:
  2356.     case PANE_BREAKPOINT:
  2357.       break;
  2358.     case PANE_DATA:
  2359.     case PANE_WATCH:
  2360.       dlpane = p;
  2361.       data_pane_active       = (p == PANE_DATA);
  2362.       watch_pane_active      = (p == PANE_WATCH);
  2363.       break;
  2364.     default:
  2365.       ulpane = p;
  2366.       code_pane_active       = (p == PANE_CODE);
  2367.       npx_pane_active        = (p == PANE_NPX);
  2368.       stack_pane_active      = (p == PANE_STACK);
  2369.       info_pane_active       = (p == PANE_INFO);
  2370.       whereis_pane_active    = (p == PANE_WHEREIS);
  2371.       gdt_pane_active        = (p == PANE_GDT);
  2372.       idt_pane_active        = (p == PANE_IDT);
  2373.       ldt_pane_active        = (p == PANE_LDT);
  2374.       help_pane_active       = (p == PANE_HELP);
  2375.       module_pane_active     = (p == PANE_MODULE);
  2376.       source_pane_active     = (p == PANE_SOURCE);
  2377.       break;
  2378.     }
  2379.   pane = p;
  2380.   pane_pos = pane_positions[pane];
  2381. }
  2382. /* ------------------------------------------------------------------------- */
  2383. /* Initialize all data structures.  */
  2384.  
  2385. static void
  2386. initialize ()
  2387. {
  2388.   int i;
  2389.  
  2390.   terminated = 0;
  2391.   dpmi = (_go32_info_block.run_mode == _GO32_RUN_MODE_DPMI);
  2392.   asm volatile ("sgdt (_gdtlinear)");
  2393.   asm volatile ("sidt (_idtlinear)");
  2394.  
  2395.   pane = PANE_CODE;
  2396.   pane_pos = 0;
  2397.   for (i = 0; i < PANECOUNT; i++) pane_positions[i] = 0;
  2398.   select_pane (PANE_DATA);
  2399.   select_pane (PANE_CODE);
  2400.  
  2401.   data_dump_origin = areas[A_data].first_addr;
  2402.   data_dump_size = 1;
  2403.   code_dump_origin = a_tss.tss_eip;
  2404.   register_pane_origin = 0;
  2405.   flag_pane_origin = 0;
  2406.   npx_pane_origin = 0;
  2407.   stack_dump_origin = 0;
  2408.   breakpoint_origin = 0;
  2409.   breakpoint_count = 0;
  2410.   breakpoint_table = xmalloc (breakpoint_count * sizeof (BP_ENTRY));
  2411.   whereis_pane_origin = 0;
  2412.   whereis_text_count = 0;
  2413.   whereis_pane_text = xmalloc (whereis_text_count * sizeof (char *));
  2414.   gdt_pane_origin = 0;
  2415.   ldt_pane_origin = 0;
  2416.   idt_pane_origin = 0;
  2417.   help_pane_origin = 0;
  2418.   module_pane_origin = 0;
  2419.   initialize_module ();
  2420.   source_pane_origin = 0;
  2421.   source_text_count = 0;
  2422.   source_pane_text = xmalloc (source_text_count * sizeof (char *));
  2423.   watch_pane_origin = 0;
  2424.   watch_text_count = 0;
  2425.   watch_pane_text = xmalloc (watch_text_count * sizeof (char *));
  2426.  
  2427.   init_colours ();
  2428.   if (access (setupfilename, R_OK) == 0)
  2429.     setup_restore (1);
  2430.   initdisplay (1);
  2431.   message (CL_Info, "Sally Full Screen Debugger");
  2432. }
  2433. /* ------------------------------------------------------------------------- */
  2434. static void
  2435. shell (int dummy)
  2436. {
  2437.   ScreenAttrib = 7;
  2438.   ScreenClear ();
  2439.   system ("");
  2440. }
  2441. /* ------------------------------------------------------------------------- */
  2442. /* Standard movement commands, a common way to handle a number of keys:
  2443.    up, down, left right, home, end, pgup, pgdn.  */
  2444.  
  2445. static int
  2446. standardmovement (int key, int count, int lines, int *origin)
  2447. {
  2448.   int zero = 0;
  2449.   int res = 1, no;
  2450.  
  2451.   if (origin == 0) origin = &zero;
  2452.   no = pane_pos + *origin;
  2453.   switch (key)
  2454.     {
  2455.     case K_Left:
  2456.     case K_ELeft:
  2457.     case K_Up:
  2458.     case K_EUp:
  2459.       if (pane_pos > 0)
  2460.     pane_pos--;
  2461.       else if (*origin > 0)
  2462.     (*origin)--;
  2463.       break;
  2464.     case K_Right:
  2465.     case K_ERight:
  2466.     case K_Down:
  2467.     case K_EDown:
  2468.       if (no < count - 1)
  2469.     if (pane_pos == lines - 1)
  2470.       (*origin)++;
  2471.     else
  2472.       pane_pos++;
  2473.       break;
  2474.     case K_Home:
  2475.     case K_EHome:
  2476.       pane_pos = (*origin) = 0;
  2477.       break;
  2478.     case K_End:
  2479.     case K_EEnd:
  2480.       if (count > lines)
  2481.     pane_pos = lines - 1, *origin = count - lines;
  2482.       else
  2483.     pane_pos = count ? count - 1 : 0, *origin = 0;
  2484.       break;
  2485.     case K_PageUp:
  2486.     case K_EPageUp:
  2487.       if (*origin == 0)
  2488.     pane_pos = 0;
  2489.       else
  2490.     if (*origin >= lines)
  2491.       *origin -= lines;
  2492.     else
  2493.       pane_pos -= (lines - *origin), *origin = 0;
  2494.       break;
  2495.     case K_PageDown:
  2496.     case K_EPageDown:
  2497.       if (*origin + lines >= count)
  2498.     pane_pos = count ? count - 1 - *origin : 0;
  2499.       else
  2500.     *origin += lines;
  2501.       break;
  2502.     case PK_Redraw:
  2503.       break;
  2504.     default:
  2505.       res = 0;
  2506.     }
  2507.   pane_pos = MAX (pane_pos, 0);
  2508.   no = pane_pos + *origin;
  2509.   if (pane_pos >= lines)
  2510.     {
  2511.       *origin = no - lines + 1;
  2512.       pane_pos = lines - 1;
  2513.     }
  2514.   if (no >= count)
  2515.     {
  2516.       if (*origin >= count)
  2517.     *origin = pane_pos = 0;
  2518.       else
  2519.     pane_pos -= (no + 1 - count);
  2520.     }
  2521.   return res;
  2522. }
  2523. /* ------------------------------------------------------------------------- */
  2524. /* Handle commands local to the code pane.  */
  2525.  
  2526. static void
  2527. code_pane_command (int key)
  2528. {
  2529.   int b;
  2530.  
  2531.   switch (key)
  2532.     {
  2533.     case PK_Redraw:
  2534.       if (code_pane_pos[pane_pos] <= code_dump_last)
  2535.     break;
  2536.       /* Fall through.  */
  2537.     case K_Up:
  2538.     case K_EUp:
  2539.       if (pane_pos > 0)
  2540.     pane_pos--;
  2541.       else
  2542.     code_pane_goto (code_skip (code_dump_origin, -1));
  2543.       break;
  2544.     case K_Down:
  2545.     case K_EDown:
  2546.       if (pane_pos < toplines - 1)
  2547.     pane_pos++;
  2548.       else
  2549.     code_dump_origin =
  2550.       code_pane_pos[0] == code_pane_pos[1]
  2551.         ? code_pane_pos[2] : code_pane_pos[1];
  2552.       break;
  2553.     case K_PageUp:
  2554.     case K_EPageUp:
  2555.       code_dump_origin = code_skip (code_dump_origin, -toplines);
  2556.       break;
  2557.     case K_PageDown:
  2558.     case K_EPageDown:
  2559.       code_dump_origin = code_dump_last + 1;
  2560.       break;
  2561.     case K_Control_Left:
  2562.     case K_Control_ELeft:
  2563.       code_dump_origin--;
  2564.       break;
  2565.     case K_Control_Right:
  2566.     case K_Control_ERight:
  2567.       code_dump_origin++;
  2568.       break;
  2569.     case K_F2:
  2570.       b = get_breakpoint (BP_Code, 0, code_pane_pos[pane_pos]);
  2571.       if (b != -1)
  2572.     reset_breakpoint (b);
  2573.       else
  2574.     set_breakpoint (BP_Code, 0, code_pane_pos[pane_pos]);
  2575.       break;
  2576.     case K_F4:
  2577.       b = set_breakpoint (BP_Code, 0, code_pane_pos[pane_pos]);
  2578.       breakpoint_table[b].temporary = 1;
  2579.       step (R_Run);
  2580.       reset_breakpoint (b);
  2581.       break;
  2582.     case K_Control_O:
  2583.       code_pane_goto (a_tss.tss_eip);
  2584.       break;
  2585.     case K_Control_N:
  2586.       a_tss.tss_eip = code_pane_pos[pane_pos];
  2587.       break;
  2588.     case K_Control_G:
  2589.       {
  2590.     int ok, res;
  2591.     res = read_eval (&ok, "");
  2592.     if (ok)
  2593.       code_pane_goto (res);
  2594.       }
  2595.       break;
  2596.     case K_Return:
  2597.       {
  2598.     code_pane_goto (code_pane_pos[pane_pos]);
  2599.     if (source_pane_module)
  2600.       select_pane (PANE_SOURCE);
  2601.       }
  2602.       break;
  2603.     }
  2604.   redraw (0);
  2605. }
  2606. /* ------------------------------------------------------------------------- */
  2607. static word32
  2608. register_set (int reg, int rel, word32 val)
  2609. {
  2610.   switch (regs_type[reg])
  2611.     {
  2612.     case 's':
  2613.       if (rel) val += *(unsigned short *)(regs_addr[reg]);
  2614.       return *(unsigned short *)(regs_addr[reg]) = (unsigned short)val;
  2615.     case 'f':
  2616.       if (rel) val += *(regs_addr[reg]);
  2617.       return a_tss.tss_eflags = (a_tss.tss_eflags & ~0xed5) | (val & 0xed5);
  2618.     default:
  2619.       if (rel) val += *(regs_addr[reg]);
  2620.       return *regs_addr[reg] = val;
  2621.     }
  2622. }
  2623.  
  2624. /* Handle commands local to the register pane.  */
  2625.  
  2626. static void
  2627. register_pane_command (int key)
  2628. {
  2629.   int no = register_pane_origin + pane_pos;
  2630.  
  2631.   if (!standardmovement (key, sizeof (regs_type) - 1,
  2632.              toplines, ®ister_pane_origin))
  2633.     switch (key)
  2634.       {
  2635.       case K_Control_D:
  2636.     (void) register_set (no, 1, -1);
  2637.     break;
  2638.       case PK_Control_I:
  2639.     (void) register_set (no, 1, +1);
  2640.     break;
  2641.       case K_Control_N:
  2642.     (void) register_set (no, 0, -register_set (no, 1, 0));
  2643.     break;
  2644.       case K_Control_Z:
  2645.     (void) register_set (no, 0, 0);
  2646.     break;
  2647.       case ' ' ... '~':
  2648.     {
  2649.       int res, ok;
  2650.       char s[2];
  2651.  
  2652.       s[0] = key; s[1] = '\0';
  2653.       res = read_eval (&ok, key == '=' ? "" : s);
  2654.       if (ok)
  2655.         (void) register_set (no, 0, res);
  2656.     }
  2657.       }
  2658.   redraw (0);
  2659. }
  2660. /* ------------------------------------------------------------------------- */
  2661. /* Handle commands local to the flag pane.  */
  2662.  
  2663. static void
  2664. flag_pane_command (int key)
  2665. {
  2666.   int no = flag_pane_origin + pane_pos;
  2667.  
  2668.   if (!standardmovement (key, 8, toplines, &flag_pane_origin))
  2669.     switch (key)
  2670.       {
  2671.       case K_Space:
  2672.       case '+':
  2673.       case '-':
  2674.       case 't':
  2675.       case 'T':
  2676.     a_tss.tss_eflags ^= flag_bits[no];
  2677.     break;
  2678.       case '1':
  2679.       case 's':
  2680.       case 'S':
  2681.     a_tss.tss_eflags |= flag_bits[no];
  2682.     break;
  2683.       case '0':
  2684.       case 'r':
  2685.       case 'R':
  2686.     a_tss.tss_eflags &= ~flag_bits[no];
  2687.     break;
  2688.       }
  2689.   redraw (0);
  2690. }
  2691. /* ------------------------------------------------------------------------- */
  2692. /* Handle commands local to the breakpoint pane.  */
  2693.  
  2694. static void
  2695. breakpoint_pane_command (int key)
  2696. {
  2697.   int b = breakpoint_count ? pane_pos + breakpoint_origin : -1;
  2698.   int last = breakpoint_count && (b == breakpoint_count - 1);
  2699.   BP_ENTRY *bep = breakpoint_table + b;
  2700.  
  2701.   switch (key)
  2702.     {
  2703.     case K_Home:
  2704.     case K_EHome:
  2705.     case PK_Redraw:
  2706.       breakpoint_origin = pane_pos = 0;
  2707.       break;
  2708.     case K_Delete:
  2709.     case K_EDelete:
  2710.     case K_Control_C:
  2711.       if (b != -1)
  2712.     reset_breakpoint (b);
  2713.       if (!last)
  2714.     break;
  2715.       /* else fall through */
  2716.     case K_Left:
  2717.     case K_ELeft:
  2718.     case K_Up:
  2719.     case K_EUp:
  2720.       if (pane_pos > 0)
  2721.     pane_pos--;
  2722.       else
  2723.     if (breakpoint_origin > 0)
  2724.       breakpoint_origin--;
  2725.       break;
  2726.     case K_Right:
  2727.     case K_ERight:
  2728.     case K_Down:
  2729.     case K_EDown:
  2730.       if (!last)
  2731.     if (pane_pos < bottomlines / 2 - 1)
  2732.       pane_pos++;
  2733.     else
  2734.       breakpoint_origin++;
  2735.       break;
  2736.     case K_Control_G:
  2737.       if (b != -1)
  2738.     if (bep->type == BP_Code)
  2739.       {
  2740.         code_pane_goto (bep->addr);
  2741.         if (pane != PANE_CODE && pane != PANE_SOURCE)
  2742.           select_pane (source_pane_module ? PANE_SOURCE : PANE_CODE);
  2743.       }
  2744.       break;
  2745.     case K_Return:
  2746.       if (b != -1 && bep->type == BP_Code)
  2747.     {
  2748.       int i;
  2749.       long delta;
  2750.       char *name;
  2751.  
  2752.       static EDIT_ITEM bpedit[] = {
  2753.         {"Address ....: ", 0},
  2754.         {"Condition ..: ", 0},
  2755.         {"Count ......: ", 0},
  2756.         {0, 0}};
  2757.  
  2758.       for (i = 0; bpedit[i].txt; i++) bpedit[i].data = alloca (cols);
  2759.  
  2760.       name = syms_val2name (bep->addr, &delta);
  2761.       if (delta)
  2762.         sprintf (bpedit[0].data, "%s%+ld", name, delta);
  2763.       else
  2764.         strcpy (bpedit[0].data, name);
  2765.       strcpy (bpedit[1].data, bep->condition ? : "");
  2766.       if (bep->count)
  2767.         sprintf (bpedit[2].data, "%d", bep->count);
  2768.       else
  2769.         bpedit[2].data[0] = 0;
  2770.  
  2771.       if (edit ("Edit Breakpoint Data", bpedit, 1))
  2772.         {
  2773.           char *errtxt;
  2774.           long newcount, newaddr;
  2775.           int bad = 0;
  2776.  
  2777.           /* Remove leading space on items.  */
  2778.           for (i = 0; bpedit[i].txt; i++)
  2779.         while (isspace (bpedit[i].data[0])) bpedit[i].data++;
  2780.  
  2781.           if (evaluate (bpedit[0].data, &newaddr, &errtxt))
  2782.         {
  2783.           message (CL_Error, "Address not understood.");
  2784.           bad = 1;
  2785.         }
  2786.           if (bpedit[2].data[0] == 0)
  2787.         newcount = 0;
  2788.           else if (evaluate (bpedit[2].data, &newcount, &errtxt))
  2789.         {
  2790.           message (CL_Error, "Count not understood.");
  2791.           bad = 1;
  2792.         }
  2793.  
  2794.           if (!bad)
  2795.         {
  2796.           bep->addr = newaddr;
  2797.           free (bep->condition);
  2798.           bep->condition
  2799.             = bpedit[1].data[0] ? strdup (bpedit[1].data) : 0;
  2800.           bep->count = newcount;
  2801.         }
  2802.         }
  2803.     }
  2804.       break;
  2805.     }
  2806.   redraw (0);
  2807. }
  2808. /* ------------------------------------------------------------------------- */
  2809. /* Handle commands local to the data pane.  */
  2810.  
  2811. static void
  2812. data_pane_command (int key)
  2813. {
  2814.   word32 v = data_dump_origin + pane_pos;
  2815.   BP_TYPE t;
  2816.   int b;
  2817.  
  2818.   switch (key)
  2819.     {
  2820.     case PK_Redraw:
  2821.       while (v > data_dump_last)
  2822.     {
  2823.       v -= 8;
  2824.       pane_pos -= 8;
  2825.     }
  2826.       break;
  2827.     case K_Up:
  2828.     case K_EUp:
  2829.       if (pane_pos >= 8)
  2830.     pane_pos -= 8;
  2831.       else
  2832.     data_dump_origin -= 8;
  2833.       break;
  2834.     case K_Down:
  2835.     case K_EDown:
  2836.       if (v + 8 <= data_dump_last)
  2837.     pane_pos += 8;
  2838.       else
  2839.     data_dump_origin += 8;
  2840.       break;
  2841.     case K_Left:
  2842.     case K_ELeft:
  2843.       if (pane_pos > 0)
  2844.     pane_pos -= data_dump_size;
  2845.       else
  2846.     data_dump_origin -= 8, pane_pos = 8 - data_dump_size;
  2847.       break;
  2848.     case K_Right:
  2849.     case K_ERight:
  2850.       if (v + data_dump_size <= data_dump_last)
  2851.     pane_pos += data_dump_size;
  2852.       else
  2853.     data_dump_origin += 8, pane_pos -= (8 - data_dump_size);
  2854.       break;
  2855.     case K_PageUp:
  2856.     case K_EPageUp:
  2857.       data_dump_origin -= (data_dump_last + 1 - data_dump_origin);
  2858.       break;
  2859.     case K_PageDown:
  2860.     case K_EPageDown:
  2861.       data_dump_origin = data_dump_last + 1;
  2862.       break;
  2863.     case K_Control_Left:
  2864.     case K_Control_ELeft:
  2865.       data_dump_origin--;
  2866.       break;
  2867.     case K_Control_Right:
  2868.     case K_Control_ERight:
  2869.       data_dump_origin++;
  2870.       break;
  2871.     case K_Control_S:
  2872.       data_dump_origin = a_tss.tss_esp;
  2873.       pane_pos = 0;
  2874.       break;
  2875.     case K_Control_C:
  2876.       data_dump_origin = a_tss.tss_eip;
  2877.       data_dump_size = 1;
  2878.       pane_pos = 0;
  2879.       break;
  2880.     case K_Control_B:
  2881.       data_dump_size = 1;
  2882.       break;
  2883.     case K_Control_W:
  2884.       data_dump_size = 2;
  2885.       break;
  2886.     case K_Control_L:
  2887.       data_dump_size = 4;
  2888.       break;
  2889.     case K_Alt_F2:
  2890.     case K_F2:
  2891.       t = key == K_F2 ? BP_Write : BP_Read;
  2892.       b = get_breakpoint (t, data_dump_size, v);
  2893.       if (b == -1)
  2894.     set_breakpoint (t, data_dump_size, v);
  2895.       else
  2896.     reset_breakpoint (b);
  2897.       break;
  2898.     case K_Control_G:
  2899.       {
  2900.     int ok, res;
  2901.     res = read_eval (&ok, "");
  2902.     if (ok)
  2903.       {
  2904.         data_dump_origin = res;
  2905.         pane_pos = 0;
  2906.       }
  2907.     break;
  2908.       }
  2909.     case ' ' ... '~':
  2910.       {
  2911.     int res, ok, bad = 0;
  2912.     char s[2], *p, *p0, q;
  2913.  
  2914.     s[0] = key; s[1] = '\0';
  2915.     if (!read_string (key == '=' ? "" : s))
  2916.       {
  2917.         p = read_buffer;
  2918.         do
  2919.           {
  2920.         while (*p == ' ') p++;
  2921.         switch (*p)
  2922.           {
  2923.           case '\0':
  2924.             break;
  2925.           case '\'':
  2926.           case '"':
  2927.             if (data_dump_size != 1)
  2928.               {
  2929.             *p = 0;
  2930.             message (CL_Error,
  2931.                  "Strings must be entered in byte mode");
  2932.             break;
  2933.               }
  2934.             q = *p++;
  2935.             p0 = p;
  2936.             while (*p != q && *p) p++;
  2937.             if (*p)
  2938.               {
  2939.             while (p0 != p)
  2940.               {
  2941.                 if (valid_addr (v, 1))
  2942.                   write_child (v, p0, 1);
  2943.                 else
  2944.                   bad = 1;
  2945.                 p0++, v++;
  2946.               }
  2947.             if (q == '"')
  2948.               {
  2949.                 if (valid_addr (v, 1))
  2950.                   write_child (v, s + 1, 1);
  2951.                 else
  2952.                   bad = 1;
  2953.                 v++;
  2954.               }
  2955.             p++;
  2956.               }
  2957.             else
  2958.               message (CL_Error, "String constant not terminated");
  2959.             break;
  2960.           default:
  2961.             p0 = p;
  2962.             while (*p != ',' && *p) p++;
  2963.             q = *p;
  2964.             *p = 0;
  2965.             res = eval (p0, &ok);
  2966.             if (ok)
  2967.               {
  2968.             *p = q;
  2969.             if (valid_addr (v, data_dump_size))
  2970.               write_child (v, &res, data_dump_size);
  2971.             else
  2972.               bad = 1;
  2973.             v += data_dump_size;
  2974.               }
  2975.           }
  2976.         if (*p == ',') p++;
  2977.           }
  2978.         while (*p);
  2979.         if (bad)
  2980.           message (CL_Error, "Part of the data could not be written");
  2981.       }
  2982.       }
  2983.     }
  2984.   pane_pos &= ~(data_dump_size - 1);
  2985.   redraw (0);
  2986. }
  2987. /* ------------------------------------------------------------------------- */
  2988. /* Handle commands local to the npx pane.  */
  2989.  
  2990. static void
  2991. npx_pane_command (int key)
  2992. {
  2993.   int base = 3;
  2994.   int no = npx_pane_origin + pane_pos;
  2995.   int reg = no - base, rotreg, tag;
  2996.   int regp = (reg >= 0);
  2997.  
  2998.   save_npx ();
  2999.   rotreg = (reg + (npx.status >> 11)) & 7;
  3000.   tag = (npx.tag >> (rotreg * 2)) & 3;
  3001.  
  3002.   if (!standardmovement (key, base + 8, toplines, &npx_pane_origin))
  3003.     switch (key)
  3004.       {
  3005.       case K_Control_C:
  3006.       case K_Control_E:
  3007.       case K_Delete:
  3008.       case K_EDelete:
  3009.     if (regp)
  3010.       {
  3011.         tag = 3;
  3012.         memset (&npx.reg[reg], 0, sizeof (NPXREG));
  3013.       }
  3014.     break;
  3015.       case K_Control_Z:
  3016.     if (regp)
  3017.       {
  3018.         tag = 1;
  3019.         memset (&npx.reg[reg], 0, sizeof (NPXREG));
  3020.       }
  3021.     break;
  3022.       case K_Control_N:
  3023.     if (regp)
  3024.       npx.reg[reg].sign = !npx.reg[reg].sign;
  3025.     break;
  3026.       case ' ' ... '~':
  3027.     if (regp)
  3028.       {
  3029.         char s[2], *endp, *p;
  3030.         double d;
  3031.  
  3032.         s[0] = key; s[1] = '\0';
  3033.         if (!read_string (key == '=' ? "" : s) && read_buffer[0] != '\0')
  3034.           {
  3035.         p = read_buffer;
  3036.         while (*p == ' ')
  3037.           p++;
  3038.         if (*p == '\0')
  3039.           break;
  3040.         strlwr (p);
  3041.         if (strcmp (p, "+inf") == 0
  3042.             || strcmp (p, "inf") == 0
  3043.             || strcmp (p, "-inf") == 0)
  3044.           {
  3045.             tag = 2;
  3046.             npx.reg[reg].exponent = 0x7fff;
  3047.             npx.reg[reg].sig3 = 0x8000;
  3048.             npx.reg[reg].sig2
  3049.               = npx.reg[reg].sig1
  3050.             = npx.reg[reg].sig0 = 0;
  3051.             npx.reg[reg].sign = (*p == '-');
  3052.           }
  3053.         else
  3054.           {
  3055.             d = strtod (p, &endp);
  3056.             if (*p != '\0' && *endp)
  3057.               message (CL_Error, "Expression not understood");
  3058.             else
  3059.               {
  3060.             tag = (d == 0.0);
  3061.             *((long double *)(npx.reg + reg)) = (long double) d;
  3062.             npx.reg[reg].sign = (*p == '-'); /* for -Zero */
  3063.               }
  3064.           }
  3065.           }
  3066.       }
  3067.       }
  3068.   if (regp)
  3069.     npx.tag = (npx.tag & ~(3 << (rotreg * 2))) | (tag << (rotreg * 2));
  3070.   load_npx ();
  3071.   redraw (0);
  3072. }
  3073. /* ------------------------------------------------------------------------- */
  3074. /* Handle commands local to the stack pane.  */
  3075.  
  3076. static void
  3077. stack_pane_command (int key)
  3078. {
  3079.   switch (key)
  3080.     {
  3081.     case K_PageDown:
  3082.     case K_EPageDown:
  3083.     case K_End:
  3084.     case K_EEnd:
  3085.       {
  3086.     int i;
  3087.  
  3088.     if (key == K_End || key == K_EEnd)
  3089.       i = 10000;  /* As good as we get.  */
  3090.     else
  3091.       i = toplines;
  3092.     while (i-- > 0 && (pane_pos < stack_dump_last || stack_dump_more))
  3093.       if (pane_pos < stack_dump_last)
  3094.         pane_pos++;
  3095.       else
  3096.         {
  3097.           (void) standardmovement (K_Down,
  3098.                        pane_pos + stack_dump_origin + 2,
  3099.                        toplines, &stack_dump_origin);
  3100.           redraw (0);
  3101.         }
  3102.     break;
  3103.       }
  3104.     case K_Return:
  3105.       code_pane_goto (stack_dump_pos[pane_pos]);
  3106.       select_pane (PANE_CODE);
  3107.       break;
  3108.     default:
  3109.       {
  3110.     int more = pane_pos < stack_dump_last || stack_dump_more;
  3111.     (void) standardmovement (key, pane_pos + stack_dump_origin + 1 + more,
  3112.                  toplines, &stack_dump_origin);
  3113.     break;
  3114.       }
  3115.     }
  3116.   redraw (0);
  3117. }
  3118. /* ------------------------------------------------------------------------- */
  3119. /* Handle commands local to the info pane.  */
  3120.  
  3121. static void
  3122. info_pane_command (int key)
  3123. {
  3124.   /* No keys recognized.  */
  3125.   redraw (0);
  3126. }
  3127. /* ------------------------------------------------------------------------- */
  3128. /* Handle the insertion of a new symbol.  */
  3129.  
  3130. static void
  3131. fullscr_listwild_handler (word32 addr, char typ, char *name,
  3132.               char *filename, int linenum)
  3133. {
  3134.   char *s;
  3135.  
  3136.   s = alloca (cols + strlen (name) + (filename ? strlen (filename) : 0));
  3137.   sprintf (s, "0x%08lx %c %s", addr, typ, name);
  3138.   if (filename)
  3139.     sprintf (s + strlen (s), ", line %d of %s", linenum, filename);
  3140.   whereis_pane_text = xrealloc (whereis_pane_text,
  3141.                 (++whereis_text_count) * sizeof (char *));
  3142.   whereis_pane_text[whereis_text_count - 1] = strdup (s);
  3143. }
  3144.  
  3145. /* Handle commands local to the whereis pane.  */
  3146.  
  3147. static void
  3148. whereis_pane_command (int key)
  3149. {
  3150.   int no = whereis_pane_origin + pane_pos;
  3151.  
  3152.   if (!standardmovement (key, whereis_text_count,
  3153.              toplines, &whereis_pane_origin))
  3154.     switch (key)
  3155.       {
  3156.       case K_Return:
  3157.     if (whereis_text_count)
  3158.       {
  3159.         char *endp, typ;
  3160.         unsigned long ul;
  3161.  
  3162.         typ = whereis_pane_text[no][11];
  3163.         ul = strtoul (whereis_pane_text[no], &endp, 16);
  3164.         switch (toupper (typ))
  3165.           {
  3166.           case 'T':
  3167.         code_pane_goto (ul);
  3168.         select_pane (PANE_CODE);
  3169.         break;
  3170.           case 'B':
  3171.           case 'D':
  3172.         data_dump_origin = ul;
  3173.         pane_positions[PANE_DATA] = 0;
  3174.         break;
  3175.           }
  3176.       }
  3177.     break;
  3178.       case ' ' ... '~':
  3179.     {
  3180.       char s[2], *p;
  3181.  
  3182.       s[0] = key; s[1] = '\0';
  3183.       if (!read_string (key == '=' ? "" : s) && read_buffer[0] != '\0')
  3184.         {
  3185.           while (whereis_text_count > 0)
  3186.         free (whereis_pane_text[--whereis_text_count]);
  3187.           whereis_pane_text = xrealloc (whereis_pane_text, 0);
  3188.  
  3189.           p = read_buffer;
  3190.           while (*p == ' ') p++;
  3191.           syms_listwild (p, &fullscr_listwild_handler);
  3192.           pane_pos = whereis_pane_origin = 0;
  3193.           if (whereis_text_count >= 10)
  3194.         message (CL_Info, "There were %d symbols that matched",
  3195.              whereis_text_count);
  3196.         }
  3197.     }
  3198.       }
  3199.   redraw (0);
  3200. }
  3201. /* ------------------------------------------------------------------------- */
  3202. /* Handle commands local to the GDT/IDT/LDT panes.  */
  3203.  
  3204. static void
  3205. gildt_pane_command (int key)
  3206. {
  3207.   int i, typ, no, count, *originp;
  3208.   GDT_S descr;
  3209.   word32 base;
  3210.  
  3211.   if (gdt_pane_active)
  3212.     typ = 0,
  3213.     count = (gdtlinear.limit + 1) / 8,
  3214.     base = gdtlinear.base,
  3215.     originp = &gdt_pane_origin;
  3216.   else if (idt_pane_active)
  3217.     typ = 1,
  3218.     count = MIN ((idtlinear.limit + 1) / 8, 0x100),
  3219.     base = idtlinear.base,
  3220.     originp = &idt_pane_origin;
  3221.   else if (ldt_pane_active)
  3222.     typ = 2,
  3223.     count = (ldtlinear.limit + 1) / 8,
  3224.     base = ldtlinear.base,
  3225.     originp = &ldt_pane_origin;
  3226.   else
  3227.     abort ();
  3228.  
  3229.   no = pane_pos + *originp;
  3230.   if (!standardmovement (key, count, toplines, originp))
  3231.     switch (key)
  3232.       {
  3233.       case K_Return:
  3234.     i = getdescriptor (base, no, &descr);
  3235.     if (i >= 0 && ((allowed_descriptors[typ] >> i) & 1))
  3236.       switch (i)
  3237.         {
  3238.         case 0x09:
  3239.         case 0x0b:
  3240.           show_tss (&descr);
  3241.           break;
  3242.         default:
  3243.         }
  3244.     break;
  3245.       }
  3246.   redraw (0);
  3247. }
  3248. /* ------------------------------------------------------------------------- */
  3249. /* Handle commands local to the help pane.  */
  3250.  
  3251. static void
  3252. help_pane_command (int key)
  3253. {
  3254.   (void) standardmovement (key, sizeof (helptext) / sizeof (char *),
  3255.                toplines, &help_pane_origin);
  3256.   redraw (0);
  3257. }
  3258. /* ------------------------------------------------------------------------- */
  3259. /* Handle commands local to the module pane.  */
  3260.  
  3261. static void
  3262. module_pane_command (int key)
  3263. {
  3264.   int no = module_pane_origin + pane_pos;
  3265.  
  3266.   if (!standardmovement (key, module_text_count,
  3267.              toplines, &module_pane_origin))
  3268.     switch (key)
  3269.       {
  3270.       case K_Return:
  3271.     if (no)
  3272.       {
  3273.         select_source_file (module_pane_text[no]);
  3274.         select_pane (PANE_SOURCE);
  3275.       }
  3276.     break;
  3277.       }
  3278.   redraw (0);
  3279. }
  3280. /* ------------------------------------------------------------------------- */
  3281. /* Handle commands local to the source pane.  */
  3282.  
  3283. static void
  3284. source_pane_command (int key)
  3285. {
  3286.   word32 addr;
  3287.   int b;
  3288.   int no = source_pane_origin + pane_pos;
  3289.  
  3290.   if (!standardmovement (key, source_text_count,
  3291.              toplines, &source_pane_origin))
  3292.     switch (key)
  3293.       {
  3294.       case K_F2:
  3295.     addr = find_source_line (no, 4);
  3296.     if (addr)
  3297.       {
  3298.         b = get_breakpoint (BP_Code, 0, addr);
  3299.         if (b != -1)
  3300.           reset_breakpoint (b);
  3301.         else
  3302.           set_breakpoint (BP_Code, 0, addr);
  3303.       }
  3304.     break;
  3305.       case K_F4:
  3306.     addr = find_source_line (no, 4);
  3307.     if (addr)
  3308.       {
  3309.         b = set_breakpoint (BP_Code, 0, addr);
  3310.         breakpoint_table[b].temporary = 1;
  3311.         step (R_Run);
  3312.         reset_breakpoint (b);
  3313.       }
  3314.     break;
  3315.       case K_F7:
  3316.       case K_F8:
  3317.     if (valid_instaddr (a_tss.tss_eip))
  3318.       {
  3319.         int line, b2, b3;
  3320.         word32 ebp = a_tss.tss_ebp;
  3321.         word32 esp = a_tss.tss_esp;
  3322.         word32 eip = a_tss.tss_eip;
  3323.  
  3324.         code_pane_goto (eip);
  3325.         no = source_pane_origin + pane_pos;
  3326.         b3 = b2 = b = -1;
  3327.  
  3328.         /* Statically next source line.  */
  3329.         addr = find_source_line (no + 1, 10);
  3330.         if (!addr)
  3331.           addr = trace_till_source (eip, 0, 1);
  3332.         if (addr)
  3333.           {
  3334.         b2 = set_breakpoint (BP_Code, 0, addr);
  3335.         breakpoint_table[b2].temporary++;
  3336.           }
  3337.  
  3338.         /* Dynamically next source line.  */
  3339.         if (key == K_F7 && (addr = trace_till_source (eip, 10, 1)))
  3340.           {
  3341.         b3 = set_breakpoint (BP_Code, 0, addr);
  3342.         breakpoint_table[b3].temporary++;
  3343.           }
  3344.  
  3345.         /* Caller.  */
  3346.         if (stack_trace (&eip, &esp, &ebp))
  3347.           {
  3348.         if ((addr = trace_till_source (eip, 10, 0)))
  3349.           eip = addr;
  3350.         b = set_breakpoint (BP_Code, 0, eip);
  3351.         breakpoint_table[b].temporary++;
  3352.           }
  3353.         step (R_Run);
  3354.         if (b != -1) reset_breakpoint (b);
  3355.         if (b2 != -1) reset_breakpoint (b2);
  3356.         if (b3 != -1) reset_breakpoint (b3);
  3357.         if (!syms_val2line (a_tss.tss_eip, &line, 1))
  3358.           select_pane (PANE_CODE);
  3359.       }
  3360.     break;
  3361.       case K_Return:
  3362.     if (no)
  3363.       {
  3364.         word32 addr;
  3365.  
  3366.         /* Not all lines have line numbers so we scan a range.  */
  3367.         addr = find_source_line (no, 10);
  3368.         if (addr)
  3369.           {
  3370.         code_pane_goto (addr);
  3371.         select_pane (PANE_CODE);
  3372.         break;
  3373.           }
  3374.         else
  3375.           message (CL_Msg,
  3376.                "There is no line number information for this line.");
  3377.       }
  3378.     break;
  3379.       }
  3380.   module_line_numbers [module_pane_origin + pane_positions[PANE_MODULE]]
  3381.     = pane_pos;
  3382.   redraw (0);
  3383. }
  3384. /* ------------------------------------------------------------------------- */
  3385. /* Handle commands local to the watch pane.  */
  3386.  
  3387. static void
  3388. watch_pane_command (int key)
  3389. {
  3390.   int no = source_pane_origin + pane_pos;
  3391.  
  3392.   if (!standardmovement (key, watch_text_count,
  3393.              toplines, &watch_pane_origin))
  3394.     switch (key)
  3395.       {
  3396.       case K_Delete:
  3397.       case K_EDelete:
  3398.     free (watch_pane_text [no]);
  3399.     watch_pane_text[no] = watch_pane_text[--watch_text_count];
  3400.     watch_pane_text
  3401.       = xrealloc (watch_pane_text, watch_text_count * sizeof (char *));
  3402.     if (no == watch_text_count)
  3403.       (void) standardmovement (K_Up, watch_text_count,
  3404.                    toplines, &watch_pane_origin);
  3405.     break;
  3406.       case K_Insert:
  3407.       case K_EInsert:
  3408.     key = '=';
  3409.     /* Fall through.  */
  3410.       case ' ' ... '~':
  3411.     {
  3412.       char s[2];
  3413.  
  3414.       s[0] = key; s[1] = '\0';
  3415.       if (!read_string (key == '=' ? "" : s) && read_buffer[0] != '\0')
  3416.         {
  3417.           watch_pane_text
  3418.         = xrealloc (watch_pane_text,
  3419.                 ++watch_text_count * sizeof (char *));
  3420.           watch_pane_text[watch_text_count - 1] = strdup (read_buffer);
  3421.         }
  3422.     }
  3423.       }
  3424.   redraw (0);
  3425. }
  3426. /* ------------------------------------------------------------------------- */
  3427. /* This is the entry point of the debugger.  */
  3428.  
  3429. void
  3430. debugger(void)
  3431. {
  3432.   int oldpane;
  3433.   static void (*keyhandlers[PANECOUNT])(int) =
  3434.     {
  3435.       &code_pane_command,       /* 0 */
  3436.       ®ister_pane_command,       /* 1 */
  3437.       &flag_pane_command,       /* 2 */
  3438.       &breakpoint_pane_command,       /* 3 */
  3439.       &data_pane_command,       /* 4 */
  3440.       &npx_pane_command,       /* 5 */
  3441.       &stack_pane_command,       /* 6 */
  3442.       &info_pane_command,       /* 7 */
  3443.       &whereis_pane_command,       /* 8 */
  3444.       &gildt_pane_command,       /* 9 */
  3445.       &gildt_pane_command,       /* 10 */
  3446.       &gildt_pane_command,       /* 11 */
  3447.       &help_pane_command,       /* 12 */
  3448.       &module_pane_command,       /* 13 */
  3449.       &source_pane_command,       /* 14 */
  3450.       &watch_pane_command       /* 15 */
  3451.     };
  3452.  
  3453.   main_entry = syms_name2val ("_main");
  3454.   first_step = !undefined_symbol;
  3455.   initialize ();
  3456.   can_longjmp = 1;
  3457.   if (setjmp (debugger_jmpbuf))
  3458.     {
  3459.       static MENU_ITEM badmemmenu[] = {
  3460.     {"Abort -- exit debugger immediately.", 0, 0},
  3461.     {"Resume -- this may re-trigger the fault.", 0, 0},
  3462.     {0, 0, 0}};
  3463.       static int focus = 0;
  3464.  
  3465.       if (menu ("Debugger was denied access to some memory",
  3466.         badmemmenu, &focus) == 1)
  3467.     abort ();
  3468.     }
  3469.   oldpane = -1;
  3470.  
  3471.   while (1)
  3472.     {
  3473.       int key;
  3474.  
  3475.       if (pane == oldpane)
  3476.     pane_positions[pane] = pane_pos;
  3477.       else
  3478.     {
  3479.       pane_pos = pane_positions[pane];
  3480.       oldpane = pane;
  3481.       redraw (0);
  3482.     }
  3483.       key = getxkey ();
  3484.       if (key == K_Tab && (bioskey (2) & 4))
  3485.     key = PK_Control_I;  /* Control pressed.  */
  3486.       switch (key)
  3487.     {
  3488.     case K_Tab:
  3489.       switch (pane)
  3490.         {
  3491.         case PANE_DATA:
  3492.         case PANE_WATCH:
  3493.           pane = ulpane; break;
  3494.         case PANE_BREAKPOINT:
  3495.           pane = dlpane; break;
  3496.         case PANE_REGISTER:
  3497.         case PANE_FLAG:
  3498.           pane++; break;
  3499.         default:
  3500.           pane = PANE_REGISTER;
  3501.         }
  3502.       break;
  3503.     case K_BackTab:
  3504.       switch (pane)
  3505.         {
  3506.         case PANE_REGISTER:
  3507.           pane = ulpane; break;
  3508.         case PANE_FLAG:
  3509.         case PANE_BREAKPOINT:
  3510.           pane--; break;
  3511.         case PANE_DATA:
  3512.         case PANE_WATCH:
  3513.           pane = PANE_BREAKPOINT; break;
  3514.         default:
  3515.           pane = dlpane;
  3516.         }
  3517.       break;
  3518.     case K_Alt_C:
  3519.       select_pane (PANE_CODE);
  3520.       break;
  3521.     case K_Alt_G:
  3522.       select_pane (PANE_GDT);
  3523.       break;
  3524.     case K_Alt_H:
  3525.     case K_F1:
  3526.       select_pane (PANE_HELP);
  3527.       break;
  3528.     case K_Alt_I:
  3529.       select_pane (PANE_IDT);
  3530.       break;
  3531.     case K_Alt_L:
  3532.       select_pane (PANE_LDT);
  3533.       break;
  3534.     case K_Alt_M:
  3535.       select_pane (PANE_MODULE);
  3536.       break;
  3537.     case K_Alt_N:
  3538.       select_pane (PANE_NPX);
  3539.       break;
  3540.     case K_Alt_S:
  3541.       select_pane (PANE_STACK);
  3542.       break;
  3543.     case K_Alt_W:
  3544.       select_pane (PANE_WHEREIS);
  3545.       break;
  3546.     case K_Alt_X:
  3547.       user_screen ();
  3548.       can_longjmp = 0;
  3549.       return;
  3550.     case K_Alt_F5:
  3551.       user_screen ();
  3552.       (void) getxkey ();
  3553.       debug_screen ();
  3554.       break;
  3555.     case K_Alt_EUp:
  3556.       if (toplines > 2)
  3557.         {
  3558.           toplines--, bottomlines++;
  3559.           redraw (1);
  3560.           keyhandlers[pane] (PK_Redraw);
  3561.         }
  3562.       break;
  3563.     case K_Alt_EDown:
  3564.       if (bottomlines > 2)
  3565.         {
  3566.           toplines++, bottomlines--;
  3567.           redraw (1);
  3568.           keyhandlers[pane] (PK_Redraw);
  3569.         }
  3570.       break;
  3571.     case K_Alt_E:
  3572.     case K_Control_F4:
  3573.       {
  3574.         int res, ok;
  3575.  
  3576.         res = read_eval (&ok, "");
  3577.         if (ok)
  3578.           message (CL_Msg, "\"%s\" -> %d (0x%08lx)",
  3579.                read_buffer, res, (word32) res);
  3580.         break;
  3581.       }
  3582.     case K_Control_F7:
  3583.       select_pane (PANE_WATCH);
  3584.       watch_pane_command (K_Insert);
  3585.       break;
  3586.     case K_F7:
  3587.       if (pane == PANE_SOURCE)
  3588.         source_pane_command (key);
  3589.       else
  3590.         step (R_Step);
  3591.       break;
  3592.     case K_F8:
  3593.       if (!first_step && pane == PANE_SOURCE)
  3594.         source_pane_command (key);
  3595.       else
  3596.         step (R_Over);
  3597.       break;
  3598.     case K_F9:
  3599.       step (R_Run);
  3600.       break;
  3601.     case K_F10:
  3602.       {
  3603.         static int focus = 0;
  3604.         static MENU_ITEM panemenu[] = {
  3605.           {"Help",                        &select_pane, PANE_HELP},
  3606.           {"Disassembly",                 &select_pane, PANE_CODE},
  3607.           {"Source Code",                 &select_pane, PANE_SOURCE},
  3608.           {"Modules",                     &select_pane, PANE_MODULE},
  3609.           {"C Stack",                     &select_pane, PANE_STACK},
  3610.           {"Symbol List",                 &select_pane, PANE_WHEREIS},
  3611.           {"Numeric Processor",           &select_pane, PANE_NPX},
  3612.           {"Watches",                     &select_pane, PANE_WATCH},
  3613.           {"System Info",                 &select_pane, PANE_INFO},
  3614.           {"Data Dump",                   &select_pane, PANE_DATA},
  3615.           {"Register",                    &select_pane, PANE_REGISTER},
  3616.           {"Flags",                       &select_pane, PANE_FLAG},
  3617.           {"Breakpoints",                 &select_pane, PANE_BREAKPOINT},
  3618.           {"Global Descriptor Table",     &select_pane, PANE_GDT},
  3619.           {"Interrupt Descriptor Table",  &select_pane, PANE_IDT},
  3620.           {"Local Descriptor Table",      &select_pane, PANE_LDT},
  3621.           {0, 0, 0}};
  3622.  
  3623.         (void) menu ("Select Pane", panemenu, &focus);
  3624.       }
  3625.       break;
  3626.     case K_Alt_F10:
  3627.       {
  3628.         static int focus = 0;
  3629.         static MENU_ITEM funcmenu[] = {
  3630.           {"25 Lines",                    &screen_mode, 25},
  3631.           {"28 Lines",                    &screen_mode, 28},
  3632.           {"50 Lines",                    &screen_mode, 50},
  3633.           {"Silence Speaker",             &sound, 0},
  3634.           {"Shell",                       &shell, 0},
  3635.           {"Edit Colours",                &edit_colours, 0},
  3636.           {"Save Setup",                  &setup_save, 0},
  3637.           {"Restore Setup",               &setup_restore, 0},
  3638.           {0, 0, 0}};
  3639.  
  3640.         switch (menu ("Select Function", funcmenu, &focus))
  3641.           {
  3642.           case 0:
  3643.           case 1:
  3644.           case 3:
  3645.         initdisplay (0);
  3646.         break;
  3647.           case -1:
  3648.         /* Nothing.  */
  3649.           }
  3650.         redraw (0);
  3651.       }
  3652.       break;
  3653.     default:
  3654.       keyhandlers[pane] (key);
  3655.     }
  3656.     }
  3657. }
  3658. /* -------------------------------------------------------------------------
  3659.    It's a mystery to me --- the game commences
  3660.    for the usual fee --- plus expenses
  3661.    confidential information --- it's in a diary
  3662.    this is my investigation --- it's not a public inquiry
  3663.  
  3664.    -- Mark Knopfler, "Private Investigations"
  3665. ------------------------------------------------------------------------- */
  3666.