* Makefile.in (init.c): don't try to scan mswin for _initialize
[binutils-gdb.git] / gdb / utils.c
index abb7d11ded114e47fdc15838c37fe69c6bed19f7..a2699d6f9f471b96d65fc71d42c18acd84ab023f 100644 (file)
@@ -72,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. */
 
@@ -133,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;
 }
@@ -152,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);
     }
@@ -168,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);
     }
 }
@@ -181,9 +228,22 @@ discard_cleanups (old_chain)
 struct cleanup *
 save_cleanups ()
 {
-  struct cleanup *old_chain = cleanup_chain;
+    return save_my_cleanups (&cleanup_chain);
+}
+
+struct cleanup *
+save_final_cleanups ()
+{
+    return save_my_cleanups (&final_cleanup_chain);
+}
 
-  cleanup_chain = 0;
+struct cleanup *
+save_my_cleanups (pmy_chain)
+    struct cleanup **pmy_chain;
+{
+  struct cleanup *old_chain = *pmy_chain;
+
+  *pmy_chain = 0;
   return old_chain;
 }
 
@@ -192,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.
@@ -253,7 +328,7 @@ warning_begin ()
 /* VARARGS */
 void
 #ifdef ANSI_PROTOTYPES
-warning (char *string, ...)
+warning (const char *string, ...)
 #else
 warning (va_alist)
      va_dcl
@@ -298,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)
@@ -394,10 +470,8 @@ fatal_dump_core (va_alist)
   fprintf_unfiltered (gdb_stderr, "\n");
   va_end (args);
 
-#ifndef _WIN32
   signal (SIGQUIT, SIG_DFL);
   kill (getpid (), SIGQUIT);
-#endif
   /* We should never get here, but just in case...  */
   exit (1);
 }
@@ -445,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;
 {
@@ -533,68 +607,65 @@ quit ()
 }
 
 
-#if defined(__GO32__) || defined(_WIN32)
+#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 ())
-    {
-#ifndef _WIN32
-      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");
-       }
-#else
-      abort ();
-#endif
-    }
 }
 
+#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(_WIN32)
 void notice_quit()
 {
-  if (kbhit ())
-    {
-#ifndef _WIN32
-      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");
-       }
-#else
-      abort ();
-#endif
-    }
+  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
@@ -1327,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;
@@ -1884,7 +1957,7 @@ initialize_utils ()
   lines_per_page = 24;
   chars_per_line = 80;
 
-#if !defined MPW && !defined _WIN32
+#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.  */
@@ -1999,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;
@@ -2022,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;
@@ -2048,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
@@ -2117,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;
@@ -2126,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;
@@ -2145,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;
@@ -2221,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,
@@ -2239,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);
@@ -2284,21 +2408,51 @@ 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 MAXCELLS 16
+#define NUMCELLS 16
 #define CELLSIZE 32
-char* 
+static char*
 get_cell()
 {
-  static char buf[MAXCELLS][CELLSIZE];
+  static char buf[NUMCELLS][CELLSIZE];
   static int cell=0;
-  if (++cell>MAXCELLS) cell=0;
+  if (++cell>=NUMCELLS) cell=0;
   return buf[cell];
 }
 
-/* print routines to handle variable size regs, etc */
+/* 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;
@@ -2307,17 +2461,17 @@ paddr(addr)
   switch (sizeof(t_addr))
     {
       case 8:
-        sprintf(paddr_str,"%08x%08x",
-               (unsigned long)(addr>>32),(unsigned long)(addr&0xffffffff));
+        sprintf (paddr_str, "%08lx%08lx",
+               (unsigned long) (addr >> thirty_two), (unsigned long) (addr & 0xffffffff));
        break;
       case 4:
-        sprintf(paddr_str,"%08x",(unsigned long)addr);
+        sprintf (paddr_str, "%08lx", (unsigned long) addr);
        break;
       case 2:
-        sprintf(paddr_str,"%04x",(unsigned short)(addr&0xffff));
+        sprintf (paddr_str, "%04x", (unsigned short) (addr & 0xffff));
        break;
       default:
-        sprintf(paddr_str,"%x",addr);
+        sprintf (paddr_str, "%lx", (unsigned long) addr);
     }
   return paddr_str;
 }
@@ -2330,18 +2484,75 @@ preg(reg)
   switch (sizeof(t_reg))
     {
       case 8:
-        sprintf(preg_str,"%08x%08x",
-               (unsigned long)(reg>>32),(unsigned long)(reg&0xffffffff));
+        sprintf (preg_str, "%08lx%08lx",
+               (unsigned long) (reg >> thirty_two), (unsigned long) (reg & 0xffffffff));
        break;
       case 4:
-        sprintf(preg_str,"%08x",(unsigned long)reg);
+        sprintf (preg_str, "%08lx", (unsigned long) reg);
        break;
       case 2:
-        sprintf(preg_str,"%04x",(unsigned short)(reg&0xffff));
+        sprintf (preg_str, "%04x", (unsigned short) (reg & 0xffff));
        break;
       default:
-        sprintf(preg_str,"%x",reg);
+        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;
+}