* Makefile.in (init.c): don't try to scan mswin for _initialize
[binutils-gdb.git] / gdb / utils.c
index 37a6ec9acf198418a7eb3d720294243bca9d7914..a2699d6f9f471b96d65fc71d42c18acd84ab023f 100644 (file)
@@ -1,5 +1,5 @@
 /* General utility routines for GDB, the GNU debugger.
-   Copyright 1986, 1989, 1990, 1991, 1992, 1995 Free Software Foundation, Inc.
+   Copyright 1986, 89, 90, 91, 92, 95, 1996 Free Software Foundation, Inc.
 
 This file is part of GDB.
 
@@ -18,11 +18,6 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
-#if !defined(__GO32__) && !defined(__WIN32__) && !defined(MPW)
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <pwd.h>
-#endif
 #ifdef ANSI_PROTOTYPES
 #include <stdarg.h>
 #else
@@ -77,7 +72,8 @@ set_width_command PARAMS ((char *, int, struct cmd_list_element *));
 /* Chain of cleanup actions established with make_cleanup,
    to be executed if an error happens.  */
 
-static struct cleanup *cleanup_chain;
+static struct cleanup *cleanup_chain; /* cleaned up after a failed command */
+static struct cleanup *final_cleanup_chain; /* cleaned up when gdb exits */
 
 /* Nonzero if we have job control. */
 
@@ -138,15 +134,31 @@ struct cleanup *
 make_cleanup (function, arg)
      void (*function) PARAMS ((PTR));
      PTR arg;
+{
+    return make_my_cleanup (&cleanup_chain, function, arg);
+}
+
+struct cleanup *
+make_final_cleanup (function, arg)
+     void (*function) PARAMS ((PTR));
+     PTR arg;
+{
+    return make_my_cleanup (&final_cleanup_chain, function, arg);
+}
+struct cleanup *
+make_my_cleanup (pmy_chain, function, arg)
+     struct cleanup **pmy_chain;
+     void (*function) PARAMS ((PTR));
+     PTR arg;
 {
   register struct cleanup *new
     = (struct cleanup *) xmalloc (sizeof (struct cleanup));
-  register struct cleanup *old_chain = cleanup_chain;
+  register struct cleanup *old_chain = *pmy_chain;
 
-  new->next = cleanup_chain;
+  new->next = *pmy_chain;
   new->function = function;
   new->arg = arg;
-  cleanup_chain = new;
+  *pmy_chain = new;
 
   return old_chain;
 }
@@ -157,11 +169,26 @@ make_cleanup (function, arg)
 void
 do_cleanups (old_chain)
      register struct cleanup *old_chain;
+{
+    do_my_cleanups (&cleanup_chain, old_chain);
+}
+
+void
+do_final_cleanups (old_chain)
+     register struct cleanup *old_chain;
+{
+    do_my_cleanups (&final_cleanup_chain, old_chain);
+}
+
+void
+do_my_cleanups (pmy_chain, old_chain)
+     register struct cleanup **pmy_chain;
+     register struct cleanup *old_chain;
 {
   register struct cleanup *ptr;
-  while ((ptr = cleanup_chain) != old_chain)
+  while ((ptr = *pmy_chain) != old_chain)
     {
-      cleanup_chain = ptr->next;       /* Do this first incase recursion */
+      *pmy_chain = ptr->next;  /* Do this first incase recursion */
       (*ptr->function) (ptr->arg);
       free (ptr);
     }
@@ -173,11 +200,26 @@ do_cleanups (old_chain)
 void
 discard_cleanups (old_chain)
      register struct cleanup *old_chain;
+{
+    discard_my_cleanups (&cleanup_chain, old_chain);
+}
+
+void
+discard_final_cleanups (old_chain)
+     register struct cleanup *old_chain;
+{
+    discard_my_cleanups (&final_cleanup_chain, old_chain);
+}
+
+void
+discard_my_cleanups (pmy_chain, old_chain)
+     register struct cleanup **pmy_chain;
+     register struct cleanup *old_chain;
 {
   register struct cleanup *ptr;
-  while ((ptr = cleanup_chain) != old_chain)
+  while ((ptr = *pmy_chain) != old_chain)
     {
-      cleanup_chain = ptr->next;
+      *pmy_chain = ptr->next;
       free ((PTR)ptr);
     }
 }
@@ -186,9 +228,22 @@ discard_cleanups (old_chain)
 struct cleanup *
 save_cleanups ()
 {
-  struct cleanup *old_chain = cleanup_chain;
+    return save_my_cleanups (&cleanup_chain);
+}
 
-  cleanup_chain = 0;
+struct cleanup *
+save_final_cleanups ()
+{
+    return save_my_cleanups (&final_cleanup_chain);
+}
+
+struct cleanup *
+save_my_cleanups (pmy_chain)
+    struct cleanup **pmy_chain;
+{
+  struct cleanup *old_chain = *pmy_chain;
+
+  *pmy_chain = 0;
   return old_chain;
 }
 
@@ -197,7 +252,22 @@ void
 restore_cleanups (chain)
      struct cleanup *chain;
 {
-  cleanup_chain = chain;
+    restore_my_cleanups (&cleanup_chain, chain);
+}
+
+void
+restore_final_cleanups (chain)
+     struct cleanup *chain;
+{
+    restore_my_cleanups (&final_cleanup_chain, chain);
+}
+
+void
+restore_my_cleanups (pmy_chain, chain)
+     struct cleanup **pmy_chain;
+     struct cleanup *chain;
+{
+  *pmy_chain = chain;
 }
 
 /* This function is useful for cleanups.
@@ -258,7 +328,7 @@ warning_begin ()
 /* VARARGS */
 void
 #ifdef ANSI_PROTOTYPES
-warning (char *string, ...)
+warning (const char *string, ...)
 #else
 warning (va_alist)
      va_dcl
@@ -303,9 +373,10 @@ error_begin ()
    The first argument STRING is the error message, used as a fprintf string,
    and the remaining args are passed as arguments to it.  */
 
-#ifdef ANSI_PROTOTYPES
+/* VARARGS */
 NORETURN void
-error (char *string, ...)
+#ifdef ANSI_PROTOTYPES
+error (const char *string, ...)
 #else
 void
 error (va_alist)
@@ -448,7 +519,7 @@ safe_strsignal (signo)
    as the file name for which the error was encountered.
    Then return to command level.  */
 
-void
+NORETURN void
 perror_with_name (string)
      char *string;
 {
@@ -536,60 +607,65 @@ quit ()
 }
 
 
-#if defined(__GO32__)||defined(WINGDB)
+#if defined(__GO32__)
 
 /* In the absence of signals, poll keyboard for a quit.
    Called from #define QUIT pollquit() in xm-go32.h. */
 
 void
-pollquit()
+notice_quit()
 {
   if (kbhit ())
-    {
-      int k = getkey ();
-      if (k == 1) {
+    switch (getkey ())
+      {
+      case 1:
        quit_flag = 1;
-       quit();
-      }
-      else if (k == 2) {
-       immediate_quit = 1;
-       quit ();
+       break;
+      case 2:
+       immediate_quit = 2;
+       break;
+      default:
+       /* We just ignore it */
+       /* FIXME!! Don't think this actually works! */
+       fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n");
+       break;
       }
-      else 
-       {
-         /* We just ignore it */
-         fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n");
-       }
-    }
 }
 
+#elif defined(_MSC_VER) /* should test for wingdb instead? */
+
+/*
+ * Windows translates all keyboard and mouse events 
+ * into a message which is appended to the message 
+ * queue for the process.
+ */
 
-#endif
-#if defined(__GO32__)||defined(WINGDB)
 void notice_quit()
 {
-  if (kbhit ())
-    {
-      int k = getkey ();
-      if (k == 1) {
-       quit_flag = 1;
-      }
-      else if (k == 2)
-       {
-         immediate_quit = 1;
-       }
-      else 
-       {
-         fprintf_unfiltered (gdb_stderr, "CTRL-A to quit, CTRL-B to quit harder\n");
-       }
-    }
+  int k = win32pollquit();
+  if (k == 1)
+    quit_flag = 1;
+  else if (k == 2)
+    immediate_quit = 1;
 }
-#else
+
+#else /* !defined(__GO32__) && !defined(_MSC_VER) */
+
 void notice_quit()
 {
   /* Done by signals */
 }
-#endif
+
+#endif /* !defined(__GO32__) && !defined(_MSC_VER) */
+
+void
+pollquit()
+{
+  notice_quit ();
+  if (quit_flag || immediate_quit)
+    quit ();
+}
+
 /* Control C comes here */
 
 void
@@ -619,19 +695,15 @@ request_quit (signo)
 \f
 /* Memory management stuff (malloc friends).  */
 
-#if defined (NO_MMALLOC)
-
 /* Make a substitute size_t for non-ANSI compilers. */
 
-#ifdef _AIX
-#include <stddef.h>
-#else /* Not AIX */
-#ifndef __STDC__
+#ifndef HAVE_STDDEF_H
 #ifndef size_t
 #define size_t unsigned int
 #endif
 #endif
-#endif /* Not AIX */
+
+#if defined (NO_MMALLOC)
 
 PTR
 mmalloc (md, size)
@@ -788,7 +860,7 @@ xmrealloc (md, ptr, size)
 
 PTR
 xmalloc (size)
-     long size;
+     size_t size;
 {
   return (xmmalloc ((PTR) NULL, size));
 }
@@ -798,7 +870,7 @@ xmalloc (size)
 PTR
 xrealloc (ptr, size)
      PTR ptr;
-     long size;
+     size_t size;
 {
   return (xmrealloc ((PTR) NULL, ptr, size));
 }
@@ -1326,7 +1398,9 @@ void
 gdb_flush (stream)
      FILE *stream;
 {
-  if (flush_hook)
+  if (flush_hook
+      && (stream == gdb_stdout
+         || stream == gdb_stderr))
     {
       flush_hook (stream);
       return;
@@ -1876,14 +1950,14 @@ initialize_utils ()
   
   /* These defaults will be used if we are unable to get the correct
      values from termcap.  */
-#if defined(__GO32__) || defined(__WIN32__)
+#if defined(__GO32__)
   lines_per_page = ScreenRows();
   chars_per_line = ScreenCols();
 #else  
   lines_per_page = 24;
   chars_per_line = 80;
 
-#ifndef MPW
+#if !defined (MPW) && !defined (_WIN32)
   /* No termcap under MPW, although might be cool to do something
      by looking at worksheet or console window sizes. */
   /* Initialize the screen height and width from termcap.  */
@@ -1998,13 +2072,13 @@ get_field (data, order, total_len, start, len)
 
   /* Start at the least significant part of the field.  */
   cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
-  if (order == floatformat_little)
+  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
     cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
   cur_bitshift =
     ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
   result = *(data + cur_byte) >> (-cur_bitshift);
   cur_bitshift += FLOATFORMAT_CHAR_BIT;
-  if (order == floatformat_little)
+  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
     ++cur_byte;
   else
     --cur_byte;
@@ -2021,7 +2095,7 @@ get_field (data, order, total_len, start, len)
       else
        result |= *(data + cur_byte) << cur_bitshift;
       cur_bitshift += FLOATFORMAT_CHAR_BIT;
-      if (order == floatformat_little)
+      if (order == floatformat_little || order == floatformat_littlebyte_bigword)
        ++cur_byte;
       else
        --cur_byte;
@@ -2047,6 +2121,48 @@ floatformat_to_doublest (fmt, from, to)
   int mant_bits_left;
   int special_exponent;                /* It's a NaN, denorm or zero */
 
+  /* If the mantissa bits are not contiguous from one end of the
+     mantissa to the other, we need to make a private copy of the
+     source bytes that is in the right order since the unpacking
+     algorithm assumes that the bits are contiguous.
+
+     Swap the bytes individually rather than accessing them through
+     "long *" since we have no guarantee that they start on a long
+     alignment, and also sizeof(long) for the host could be different
+     than sizeof(long) for the target.  FIXME: Assumes sizeof(long)
+     for the target is 4. */
+
+  if (fmt -> byteorder == floatformat_littlebyte_bigword)
+    {
+      static unsigned char *newfrom;
+      unsigned char *swapin, *swapout;
+      int longswaps;
+
+      longswaps = fmt -> totalsize / FLOATFORMAT_CHAR_BIT;
+      longswaps >>= 3;
+      
+      if (newfrom == NULL)
+       {
+         newfrom = xmalloc (fmt -> totalsize);
+       }
+      swapout = newfrom;
+      swapin = ufrom;
+      ufrom = newfrom;
+      while (longswaps-- > 0)
+       {
+         /* This is ugly, but efficient */
+         *swapout++ = swapin[4];
+         *swapout++ = swapin[5];
+         *swapout++ = swapin[6];
+         *swapout++ = swapin[7];
+         *swapout++ = swapin[0];
+         *swapout++ = swapin[1];
+         *swapout++ = swapin[2];
+         *swapout++ = swapin[3];
+         swapin += 8;
+       }
+    }
+
   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
                        fmt->exp_start, fmt->exp_len);
   /* Note that if exponent indicates a NaN, we can't really do anything useful
@@ -2116,7 +2232,7 @@ put_field (data, order, total_len, start, len, stuff_to_put)
 
   /* Start at the least significant part of the field.  */
   cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
-  if (order == floatformat_little)
+  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
     cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
   cur_bitshift =
     ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
@@ -2125,7 +2241,7 @@ put_field (data, order, total_len, start, len, stuff_to_put)
   *(data + cur_byte) |=
     (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
   cur_bitshift += FLOATFORMAT_CHAR_BIT;
-  if (order == floatformat_little)
+  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
     ++cur_byte;
   else
     --cur_byte;
@@ -2144,7 +2260,7 @@ put_field (data, order, total_len, start, len, stuff_to_put)
        *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
                              & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
       cur_bitshift += FLOATFORMAT_CHAR_BIT;
-      if (order == floatformat_little)
+      if (order == floatformat_little || order == floatformat_littlebyte_bigword)
        ++cur_byte;
       else
        --cur_byte;
@@ -2220,7 +2336,7 @@ floatformat_from_doublest (fmt, from, to)
   memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
   if (dfrom == 0)
     return;                    /* Result is zero */
-  if (dfrom != dfrom)
+  if (dfrom != dfrom)          /* Result is NaN */
     {
       /* From is NaN */
       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
@@ -2238,7 +2354,16 @@ floatformat_from_doublest (fmt, from, to)
       dfrom = -dfrom;
     }
 
-  /* How to tell an infinity from an ordinary number?  FIXME-someday */
+  if (dfrom + dfrom == dfrom && dfrom != 0.0)  /* Result is Infinity */
+    {
+      /* Infinity exponent is same as NaN's.  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, fmt->exp_nan);
+      /* Infinity mantissa is all zeroes.  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
+                fmt->man_len, 0);
+      return;
+    }
 
 #ifdef HAVE_LONG_DOUBLE
   mant = ldfrexp (dfrom, &exponent);
@@ -2267,10 +2392,11 @@ floatformat_from_doublest (fmt, from, to)
       if (mant_bits_left == fmt->man_len
          && fmt->intbit == floatformat_intbit_no)
        {
-         mant_long &= 0x7fffffff;
+         mant_long <<= 1;
          mant_bits -= 1;
        }
-      else if (mant_bits < 32)
+
+      if (mant_bits < 32)
        {
          /* The bits we want are in the most significant MANT_BITS bits of
             mant_long.  Move them to the least significant.  */
@@ -2282,4 +2408,151 @@ floatformat_from_doublest (fmt, from, to)
       mant_off += mant_bits;
       mant_bits_left -= mant_bits;
     }
+  if (fmt -> byteorder == floatformat_littlebyte_bigword)
+    {
+      int count;
+      unsigned char *swaplow = uto;
+      unsigned char *swaphigh = uto + 4;
+      unsigned char tmp;
+
+      for (count = 0; count < 4; count++)
+       {
+         tmp = *swaplow;
+         *swaplow++ = *swaphigh;
+         *swaphigh++ = tmp;
+       }
+    }
+}
+
+/* temporary storage using circular buffer */
+#define NUMCELLS 16
+#define CELLSIZE 32
+static char*
+get_cell()
+{
+  static char buf[NUMCELLS][CELLSIZE];
+  static int cell=0;
+  if (++cell>=NUMCELLS) cell=0;
+  return buf[cell];
+}
+
+/* print routines to handle variable size regs, etc.
+
+   FIXME: Note that t_addr is a bfd_vma, which is currently either an
+   unsigned long or unsigned long long, determined at configure time.
+   If t_addr is an unsigned long long and sizeof (unsigned long long)
+   is greater than sizeof (unsigned long), then I believe this code will
+   probably lose, at least for little endian machines.  I believe that
+   it would also be better to eliminate the switch on the absolute size
+   of t_addr and replace it with a sequence of if statements that compare
+   sizeof t_addr with sizeof the various types and do the right thing,
+   which includes knowing whether or not the host supports long long.
+   -fnf
+
+ */
+
+static int thirty_two = 32;    /* eliminate warning from compiler on 32-bit systems */
+
+char* 
+paddr(addr)
+  t_addr addr;
+{
+  char *paddr_str=get_cell();
+  switch (sizeof(t_addr))
+    {
+      case 8:
+        sprintf (paddr_str, "%08lx%08lx",
+               (unsigned long) (addr >> thirty_two), (unsigned long) (addr & 0xffffffff));
+       break;
+      case 4:
+        sprintf (paddr_str, "%08lx", (unsigned long) addr);
+       break;
+      case 2:
+        sprintf (paddr_str, "%04x", (unsigned short) (addr & 0xffff));
+       break;
+      default:
+        sprintf (paddr_str, "%lx", (unsigned long) addr);
+    }
+  return paddr_str;
+}
+
+char* 
+preg(reg)
+  t_reg reg;
+{
+  char *preg_str=get_cell();
+  switch (sizeof(t_reg))
+    {
+      case 8:
+        sprintf (preg_str, "%08lx%08lx",
+               (unsigned long) (reg >> thirty_two), (unsigned long) (reg & 0xffffffff));
+       break;
+      case 4:
+        sprintf (preg_str, "%08lx", (unsigned long) reg);
+       break;
+      case 2:
+        sprintf (preg_str, "%04x", (unsigned short) (reg & 0xffff));
+       break;
+      default:
+        sprintf (preg_str, "%lx", (unsigned long) reg);
+    }
+  return preg_str;
+}
+
+char*
+paddr_nz(addr)
+  t_addr addr;
+{
+  char *paddr_str=get_cell();
+  switch (sizeof(t_addr))
+    {
+      case 8:
+       {
+         unsigned long high = (unsigned long) (addr >> thirty_two);
+         if (high == 0)
+           sprintf (paddr_str, "%lx", (unsigned long) (addr & 0xffffffff));
+         else
+           sprintf (paddr_str, "%lx%08lx",
+                   high, (unsigned long) (addr & 0xffffffff));
+         break;
+       }
+      case 4:
+        sprintf (paddr_str, "%lx", (unsigned long) addr);
+       break;
+      case 2:
+        sprintf (paddr_str, "%x", (unsigned short) (addr & 0xffff));
+       break;
+      default:
+        sprintf (paddr_str,"%lx", (unsigned long) addr);
+    }
+  return paddr_str;
+}
+
+char*
+preg_nz(reg)
+  t_reg reg;
+{
+  char *preg_str=get_cell();
+  switch (sizeof(t_reg))
+    {
+      case 8:
+       {
+         unsigned long high = (unsigned long) (reg >> thirty_two);
+         if (high == 0)
+           sprintf (preg_str, "%lx", (unsigned long) (reg & 0xffffffff));
+         else
+           sprintf (preg_str, "%lx%08lx",
+                   high, (unsigned long) (reg & 0xffffffff));
+         break;
+       }
+      case 4:
+        sprintf (preg_str, "%lx", (unsigned long) reg);
+       break;
+      case 2:
+        sprintf (preg_str, "%x", (unsigned short) (reg & 0xffff));
+       break;
+      default:
+        sprintf (preg_str, "%lx", (unsigned long) reg);
+    }
+  return preg_str;
 }