aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog15
-rw-r--r--gdb/doublest.c211
2 files changed, 146 insertions, 80 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 918ecdd..8357edb 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,18 @@
+2004-12-05 Richard Earnshaw <rearnsha@arm.com>
+
+ * doublest.c (FLOATFORMAT_LARGEST_BYTES): New define.
+ (get_field, put_field): Assert that the format is one we can handle.
+ Simplify logic accordingly.
+ (floatformat_normalize_byteorder): New function.
+ (convert_floatformat_to_doublest): Use floatformat_normalize_byteorder
+ to normalize and select modified byte order. Pass modified byte order
+ to get_field.
+ (floatformat_is_negative, floatformat_is_nan, floatformat_mantissa):
+ Likewise.
+ (convert_doublest_to_floatformat): Select an appropriate intermediate
+ byte order if necessary. Always convert to the final format before
+ returning.
+
2004-12-04 Daniel Jacobowitz <dan@debian.org>
PR tui/1703
diff --git a/gdb/doublest.c b/gdb/doublest.c
index 82441b6..b36cbd7 100644
--- a/gdb/doublest.c
+++ b/gdb/doublest.c
@@ -40,6 +40,10 @@
a system header, what we do if not, etc. */
#define FLOATFORMAT_CHAR_BIT 8
+/* The number of bytes that the largest floating-point type that we
+ can convert to doublest will need. */
+#define FLOATFORMAT_LARGEST_BYTES 16
+
static unsigned long get_field (unsigned char *,
enum floatformat_byteorders,
unsigned int, unsigned int, unsigned int);
@@ -54,8 +58,11 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
unsigned int cur_byte;
int cur_bitshift;
+ /* Caller must byte-swap words before calling this routine. */
+ gdb_assert (order == floatformat_little || order == floatformat_big);
+
/* Start at the least significant part of the field. */
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
{
/* We start counting from the other end (i.e, from the high bytes
rather than the low bytes). As such, we need to be concerned
@@ -81,7 +88,7 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
else
result = 0;
cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
@@ -99,8 +106,6 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
case floatformat_big:
--cur_byte;
break;
- case floatformat_littlebyte_bigword:
- break;
}
}
if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
@@ -109,6 +114,40 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
return result;
}
+/* Normalize the byte order of FROM into TO. If no normalization is needed
+ then FMT->byteorder is returned and TO is not changed; otherwise the format
+ of the normalized form in TO is returned. */
+static enum floatformat_byteorders
+floatformat_normalize_byteorder (const struct floatformat *fmt,
+ const void *from, void *to)
+{
+ const unsigned char *swapin;
+ unsigned char *swapout;
+ int words;
+
+ if (fmt->byteorder == floatformat_little
+ || fmt->byteorder == floatformat_big)
+ return fmt->byteorder;
+
+ gdb_assert (fmt->byteorder == floatformat_littlebyte_bigword);
+
+ words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
+ words >>= 2;
+
+ swapout = (unsigned char *)to;
+ swapin = (const unsigned char *)from;
+
+ while (words-- > 0)
+ {
+ *swapout++ = swapin[3];
+ *swapout++ = swapin[2];
+ *swapout++ = swapin[1];
+ *swapout++ = swapin[0];
+ swapin += 4;
+ }
+ return floatformat_big;
+}
+
/* Convert from FMT to a DOUBLEST.
FROM is the address of the extended float.
Store the DOUBLEST in *TO. */
@@ -125,51 +164,19 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
unsigned int mant_bits, mant_off;
int mant_bits_left;
int special_exponent; /* It's a NaN, denorm or zero */
+ enum floatformat_byteorders order;
+ unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+
+ gdb_assert (fmt->totalsize
+ <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
- /* 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;
+ order = floatformat_normalize_byteorder (fmt, ufrom, newfrom);
- if (newfrom == NULL)
- {
- newfrom = (unsigned char *) 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;
- }
- }
+ if (order != fmt->byteorder)
+ ufrom = newfrom;
- exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- fmt->exp_start, fmt->exp_len);
+ exponent = get_field (ufrom, order, fmt->totalsize, fmt->exp_start,
+ fmt->exp_len);
/* Note that if exponent indicates a NaN, we can't really do anything useful
(not knowing if the host has NaN's, or how to build one). So it will
end up as an infinity or something close; that is OK. */
@@ -207,8 +214,7 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
{
mant_bits = min (mant_bits_left, 32);
- mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits);
+ mant = get_field (ufrom, order, fmt->totalsize, mant_off, mant_bits);
dto += ldexp ((double) mant, exponent - mant_bits);
exponent -= mant_bits;
@@ -217,7 +223,7 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
}
/* Negate it if negative. */
- if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
+ if (get_field (ufrom, order, fmt->totalsize, fmt->sign_start, 1))
dto = -dto;
*to = dto;
}
@@ -236,8 +242,11 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
unsigned int cur_byte;
int cur_bitshift;
+ /* Caller must byte-swap words before calling this routine. */
+ gdb_assert (order == floatformat_little || order == floatformat_big);
+
/* Start at the least significant part of the field. */
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
{
int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
cur_byte = (total_len / FLOATFORMAT_CHAR_BIT)
@@ -260,7 +269,7 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
(stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
}
cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
@@ -279,7 +288,7 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
*(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
& ((1 << FLOATFORMAT_CHAR_BIT) - 1));
cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+ if (order == floatformat_little)
++cur_byte;
else
--cur_byte;
@@ -347,6 +356,10 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
unsigned int mant_bits, mant_off;
int mant_bits_left;
unsigned char *uto = (unsigned char *) to;
+ enum floatformat_byteorders order = fmt->byteorder;
+
+ if (order == floatformat_littlebyte_bigword)
+ order = floatformat_big;
memcpy (&dfrom, from, sizeof (dfrom));
memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1)
@@ -356,30 +369,30 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
if (dfrom != dfrom) /* Result is NaN */
{
/* From is NaN */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+ put_field (uto, order, fmt->totalsize, fmt->exp_start,
fmt->exp_len, fmt->exp_nan);
/* Be sure it's not infinity, but NaN value is irrel */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
+ put_field (uto, order, fmt->totalsize, fmt->man_start,
32, 1);
- return;
+ goto finalize_byteorder;
}
/* If negative, set the sign bit. */
if (dfrom < 0)
{
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
+ put_field (uto, order, fmt->totalsize, fmt->sign_start, 1, 1);
dfrom = -dfrom;
}
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,
+ put_field (uto, order, 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,
+ put_field (uto, order, fmt->totalsize, fmt->man_start,
fmt->man_len, 0);
- return;
+ goto finalize_byteorder;
}
#ifdef HAVE_LONG_DOUBLE
@@ -388,7 +401,7 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
mant = frexp (dfrom, &exponent);
#endif
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
+ put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len,
exponent + fmt->exp_bias - 1);
mant_bits_left = fmt->man_len;
@@ -429,23 +442,31 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
mant_long >>= 32 - mant_bits;
}
- put_field (uto, fmt->byteorder, fmt->totalsize,
+ put_field (uto, order, fmt->totalsize,
mant_off, mant_bits, mant_long);
mant_off += mant_bits;
mant_bits_left -= mant_bits;
}
- if (fmt->byteorder == floatformat_littlebyte_bigword)
+
+ finalize_byteorder:
+ /* Do we need to byte-swap the words in the result? */
+ if (order != fmt->byteorder)
{
- int count;
- unsigned char *swaplow = uto;
- unsigned char *swaphigh = uto + 4;
+ int words;
+ unsigned char *curword = uto;
unsigned char tmp;
- for (count = 0; count < 4; count++)
+ words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
+ words >>= 2;
+ while (words-- > 0)
{
- tmp = *swaplow;
- *swaplow++ = *swaphigh;
- *swaphigh++ = tmp;
+ tmp = curword[0];
+ curword[0] = curword[3];
+ curword[3] = tmp;
+ tmp = curword[1];
+ curword[1] = curword[2];
+ curword[2] = tmp;
+ curword += 4;
}
}
}
@@ -457,8 +478,19 @@ int
floatformat_is_negative (const struct floatformat *fmt, char *val)
{
unsigned char *uval = (unsigned char *) val;
+ enum floatformat_byteorders order;
+ unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+
gdb_assert (fmt != NULL);
- return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
+ gdb_assert (fmt->totalsize
+ <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+
+ order = floatformat_normalize_byteorder (fmt, uval, newfrom);
+
+ if (order != fmt->byteorder)
+ uval = newfrom;
+
+ return get_field (uval, order, fmt->totalsize, fmt->sign_start, 1);
}
/* Check if VAL is "not a number" (NaN) for FMT. */
@@ -471,14 +503,23 @@ floatformat_is_nan (const struct floatformat *fmt, char *val)
unsigned long mant;
unsigned int mant_bits, mant_off;
int mant_bits_left;
-
+ enum floatformat_byteorders order;
+ unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+
gdb_assert (fmt != NULL);
+ gdb_assert (fmt->totalsize
+ <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+
+ order = floatformat_normalize_byteorder (fmt, uval, newfrom);
+
+ if (order != fmt->byteorder)
+ uval = newfrom;
if (! fmt->exp_nan)
return 0;
- exponent = get_field (uval, fmt->byteorder, fmt->totalsize,
- fmt->exp_start, fmt->exp_len);
+ exponent = get_field (uval, order, fmt->totalsize, fmt->exp_start,
+ fmt->exp_len);
if (exponent != fmt->exp_nan)
return 0;
@@ -490,8 +531,7 @@ floatformat_is_nan (const struct floatformat *fmt, char *val)
{
mant_bits = min (mant_bits_left, 32);
- mant = get_field (uval, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits);
+ mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
/* If there is an explicit integer bit, mask it off. */
if (mant_off == fmt->man_start
@@ -521,17 +561,29 @@ floatformat_mantissa (const struct floatformat *fmt, char *val)
int mant_bits_left;
static char res[50];
char buf[9];
+ enum floatformat_byteorders order;
+ unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+
+ gdb_assert (fmt != NULL);
+ gdb_assert (fmt->totalsize
+ <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+
+ order = floatformat_normalize_byteorder (fmt, uval, newfrom);
+
+ if (order != fmt->byteorder)
+ uval = newfrom;
+
+ if (! fmt->exp_nan)
+ return 0;
/* Make sure we have enough room to store the mantissa. */
- gdb_assert (fmt != NULL);
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);
+ mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
sprintf (res, "%lx", mant);
@@ -540,8 +592,7 @@ floatformat_mantissa (const struct floatformat *fmt, char *val)
while (mant_bits_left > 0)
{
- mant = get_field (uval, fmt->byteorder, fmt->totalsize,
- mant_off, 32);
+ mant = get_field (uval, order, fmt->totalsize, mant_off, 32);
sprintf (buf, "%08lx", mant);
strcat (res, buf);