From 39424bef9143202f0b7fc25b73c81db580eb253c Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Wed, 7 Mar 2001 16:09:03 +0000 Subject: [PATCH] * defs.h: Provide prototypes for floatformat_is_negative, floatformat_is_nan and floatformat_mantissa. * utils.c: Include "gdb_assert.h". (floatformat_is_negative): New function. (floatformat_is_nan): New function. (floatformat_mantissa): New function. * valprint.c: Include "floatformat.h". (print_floating): Get rid of the Linux-specific TARGET_ANALYZE_FLOATING macro and rewrite NaN detection with the help these new functions. Print NaN's in a format conforming to ISO C99. --- gdb/ChangeLog | 14 +++++++ gdb/defs.h | 6 ++- gdb/utils.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++ gdb/valprint.c | 106 ++++++++++++++----------------------------------- 4 files changed, 149 insertions(+), 78 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e3737d75602..32e592f6a64 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2001-03-07 Mark Kettenis + + * defs.h: Provide prototypes for floatformat_is_negative, + floatformat_is_nan and floatformat_mantissa. + * utils.c: Include "gdb_assert.h". + (floatformat_is_negative): New function. + (floatformat_is_nan): New function. + (floatformat_mantissa): New function. + * valprint.c: Include "floatformat.h". + (print_floating): Get rid of the Linux-specific + TARGET_ANALYZE_FLOATING macro and rewrite NaN detection with the + help these new functions. Print NaN's in a format conforming to + ISO C99. + 2001-03-07 Eli Zaretskii * top.c (init_main): Make `set history file name' complete on file diff --git a/gdb/defs.h b/gdb/defs.h index 6974fe28507..c6a4637c4d6 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -1124,8 +1124,12 @@ extern void floatformat_to_doublest (const struct floatformat *, char *, DOUBLEST *); extern void floatformat_from_doublest (const struct floatformat *, DOUBLEST *, char *); -extern DOUBLEST extract_floating (void *, int); +extern int floatformat_is_negative (const struct floatformat *, char *); +extern int floatformat_is_nan (const struct floatformat *, char *); +extern char *floatformat_mantissa (const struct floatformat *, char *); + +extern DOUBLEST extract_floating (void *, int); extern void store_floating (void *, int, DOUBLEST); /* On some machines there are bits in addresses which are not really diff --git a/gdb/utils.c b/gdb/utils.c index df6046a93e6..5ece78ded48 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -21,6 +21,7 @@ Boston, MA 02111-1307, USA. */ #include "defs.h" +#include "gdb_assert.h" #include #include "gdb_string.h" #include "event-top.h" @@ -2741,6 +2742,106 @@ floatformat_from_doublest (CONST struct floatformat *fmt, DOUBLEST *from, } } +/* Check if VAL (which is assumed to be a floating point number whose + format is described by FMT) is negative. */ + +int +floatformat_is_negative (const struct floatformat *fmt, char *val) +{ + unsigned char *uval = (unsigned char *) val; + + return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1); +} + +/* Check if VAL is "not a number" (NaN) for FMT. */ + +int +floatformat_is_nan (const struct floatformat *fmt, char *val) +{ + unsigned char *uval = (unsigned char *) val; + long exponent; + unsigned long mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + + if (! fmt->exp_nan) + return 0; + + exponent = get_field (uval, fmt->byteorder, fmt->totalsize, + fmt->exp_start, fmt->exp_len); + + if (exponent != fmt->exp_nan) + return 0; + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + mant = get_field (uval, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits); + + /* If there is an explicit integer bit, mask it off. */ + if (mant_off == fmt->man_start + && fmt->intbit == floatformat_intbit_yes) + mant &= ~(1 << (mant_bits - 1)); + + if (mant) + return 1; + + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + return 0; +} + +/* Convert the mantissa of VAL (which is assumed to be a floating + point number whose format is described by FMT) into a hexadecimal + and store it in a static string. Return a pointer to that string. */ + +char * +floatformat_mantissa (const struct floatformat *fmt, char *val) +{ + unsigned char *uval = (unsigned char *) val; + unsigned long mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + static char res[50]; + char buf[9]; + + /* Make sure we have enough room to store the mantissa. */ + gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2); + + mant_off = fmt->man_start; + mant_bits_left = fmt->man_len; + mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32; + + mant = get_field (uval, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits); + + sprintf (res, "%lx", mant); + + mant_off += mant_bits; + mant_bits_left -= mant_bits; + + while (mant_bits_left > 0) + { + mant = get_field (uval, fmt->byteorder, fmt->totalsize, + mant_off, 32); + + sprintf (buf, "%08lx", mant); + strcat (res, buf); + + mant_off += 32; + mant_bits_left -= 32; + } + + return res; +} + /* print routines to handle variable size regs, etc. */ /* temporary storage using circular buffer */ diff --git a/gdb/valprint.c b/gdb/valprint.c index 2a80b9c7c0a..ccd4542eb07 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -32,6 +32,7 @@ #include "language.h" #include "annotate.h" #include "valprint.h" +#include "floatformat.h" #include @@ -538,92 +539,39 @@ longest_to_int (LONGEST arg) return (rtnval); } - -/* Print a floating point value of type TYPE, pointed to in GDB by VALADDR, - on STREAM. */ +/* Print a floating point value of type TYPE, pointed to in GDB by + VALADDR, on STREAM. */ void print_floating (char *valaddr, struct type *type, struct ui_file *stream) { DOUBLEST doub; int inv; + const struct floatformat *fmt = &floatformat_unknown; unsigned len = TYPE_LENGTH (type); - /* Check for NaN's. Note that this code does not depend on us being - on an IEEE conforming system. It only depends on the target - machine using IEEE representation. This means (a) - cross-debugging works right, and (2) IEEE_FLOAT can (and should) - be non-zero for systems like the 68881, which uses IEEE - representation, but is not IEEE conforming. */ - if (IEEE_FLOAT) - { - unsigned long low, high; - /* Is the sign bit 0? */ - int nonnegative; - /* Is it is a NaN (i.e. the exponent is all ones and - the fraction is nonzero)? */ - int is_nan; - - /* For lint, initialize these two variables to suppress warning: */ - low = high = nonnegative = 0; - if (len == 4) - { - /* It's single precision. */ - /* Assume that floating point byte order is the same as - integer byte order. */ - low = extract_unsigned_integer (valaddr, 4); - nonnegative = ((low & 0x80000000) == 0); - is_nan = ((((low >> 23) & 0xFF) == 0xFF) - && 0 != (low & 0x7FFFFF)); - low &= 0x7fffff; - high = 0; - } - else if (len == 8) - { - /* It's double precision. Get the high and low words. */ + /* FIXME: kettenis/2001-01-20: The check for IEEE_FLOAT is probably + still necessary since GDB by default assumes that the target uses + the IEEE 754 representation for its floats and doubles. Of + course this is all crock and should be cleaned up. */ - /* Assume that floating point byte order is the same as - integer byte order. */ - if (TARGET_BYTE_ORDER == BIG_ENDIAN) - { - low = extract_unsigned_integer (valaddr + 4, 4); - high = extract_unsigned_integer (valaddr, 4); - } - else - { - low = extract_unsigned_integer (valaddr, 4); - high = extract_unsigned_integer (valaddr + 4, 4); - } - nonnegative = ((high & 0x80000000) == 0); - is_nan = (((high >> 20) & 0x7ff) == 0x7ff - && !((((high & 0xfffff) == 0)) && (low == 0))); - high &= 0xfffff; - } - else - { -#ifdef TARGET_ANALYZE_FLOATING - TARGET_ANALYZE_FLOATING; -#else - /* Extended. We can't detect extended NaNs for this target. - Also note that currently extendeds get nuked to double in - REGISTER_CONVERTIBLE. */ - is_nan = 0; -#endif - } + if (len == TARGET_FLOAT_BIT / TARGET_CHAR_BIT && IEEE_FLOAT) + fmt = TARGET_FLOAT_FORMAT; + else if (len == TARGET_DOUBLE_BIT / TARGET_CHAR_BIT && IEEE_FLOAT) + fmt = TARGET_DOUBLE_FORMAT; + else if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT) + fmt = TARGET_LONG_DOUBLE_FORMAT; - if (is_nan) - { - /* The meaning of the sign and fraction is not defined by IEEE. - But the user might know what they mean. For example, they - (in an implementation-defined manner) distinguish between - signaling and quiet NaN's. */ - if (high) - fprintf_filtered (stream, "-NaN(0x%lx%.8lx)" + !!nonnegative, - high, low); - else - fprintf_filtered (stream, "-NaN(0x%lx)" + nonnegative, low); - return; - } + if (floatformat_is_nan (fmt, valaddr)) + { + if (floatformat_is_negative (fmt, valaddr)) + fprintf_filtered (stream, "-"); + fprintf_filtered (stream, "nan("); + fprintf_filtered (stream, local_hex_format_prefix ()); + fprintf_filtered (stream, floatformat_mantissa (fmt, valaddr)); + fprintf_filtered (stream, local_hex_format_suffix ()); + fprintf_filtered (stream, ")"); + return; } doub = unpack_double (type, valaddr, &inv); @@ -633,6 +581,9 @@ print_floating (char *valaddr, struct type *type, struct ui_file *stream) return; } + /* FIXME: kettenis/2001-01-20: The following code makes too much + assumptions about the host and target floating point format. */ + if (len < sizeof (double)) fprintf_filtered (stream, "%.9g", (double) doub); else if (len == sizeof (double)) @@ -641,7 +592,8 @@ print_floating (char *valaddr, struct type *type, struct ui_file *stream) #ifdef PRINTF_HAS_LONG_DOUBLE fprintf_filtered (stream, "%.35Lg", doub); #else - /* This at least wins with values that are representable as doubles */ + /* This at least wins with values that are representable as + doubles. */ fprintf_filtered (stream, "%.17g", (double) doub); #endif } -- 2.30.2