diff options
-rw-r--r-- | gdb/ChangeLog | 40 | ||||
-rw-r--r-- | gdb/Makefile.in | 47 | ||||
-rw-r--r-- | gdb/alpha-tdep.c | 1 | ||||
-rw-r--r-- | gdb/arm-linux-tdep.c | 1 | ||||
-rw-r--r-- | gdb/arm-tdep.c | 1 | ||||
-rw-r--r-- | gdb/ax.h | 2 | ||||
-rw-r--r-- | gdb/config/i386/tm-symmetry.h | 1 | ||||
-rw-r--r-- | gdb/config/i960/tm-i960.h | 2 | ||||
-rw-r--r-- | gdb/config/m88k/tm-m88k.h | 1 | ||||
-rw-r--r-- | gdb/defs.h | 58 | ||||
-rw-r--r-- | gdb/doublest.c | 627 | ||||
-rw-r--r-- | gdb/doublest.h | 87 | ||||
-rw-r--r-- | gdb/expression.h | 1 | ||||
-rw-r--r-- | gdb/findvar.c | 96 | ||||
-rw-r--r-- | gdb/i386-tdep.c | 1 | ||||
-rw-r--r-- | gdb/i387-tdep.c | 1 | ||||
-rw-r--r-- | gdb/ia64-tdep.c | 1 | ||||
-rw-r--r-- | gdb/parse.c | 1 | ||||
-rw-r--r-- | gdb/parser-defs.h | 2 | ||||
-rw-r--r-- | gdb/rs6000-tdep.c | 1 | ||||
-rw-r--r-- | gdb/sh-tdep.c | 1 | ||||
-rw-r--r-- | gdb/stabsread.c | 1 | ||||
-rw-r--r-- | gdb/top.c | 1 | ||||
-rw-r--r-- | gdb/utils.c | 505 | ||||
-rw-r--r-- | gdb/valarith.c | 1 | ||||
-rw-r--r-- | gdb/valprint.c | 1 | ||||
-rw-r--r-- | gdb/value.h | 2 | ||||
-rw-r--r-- | gdb/values.c | 1 |
28 files changed, 806 insertions, 679 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 9ecd7db..f9edf01 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,43 @@ +2001-07-31 Andrew Cagney <ac131313@redhat.com> + + * defs.h (HOST_FLOAT_FORMAT, HOST_DOUBLE_FORMAT) + (HOST_FLOAT_FORMAT, HOST_DOUBLE_FORMAT) + (HOST_LONG_DOUBLE_FORMAT, DOUBLEST) + (floatformat_to_doublest, floatformat_from_doublest) + (floatformat_is_negative, floatformat_is_nan) + (floatformat_mantissa, store_floating) + (extract_floating): Move declaration from here. + * doublest.h: To here. New file. + * utils.c (get_field, floatformat_to_doublest, put_field) + (ldfrexp, floatformat_from_doublest, floatformat_is_negative) + (floatformat_is_nan, floatformat_mantissa) + (FLOATFORMAT_CHAR_BIT): Move from here. + * doublest.c: To here. New file. + * findvar.c (store_floating, extract_floating): Move from here. + * doublest.c: To here. + * Makefile.in (SFILES): Add doublest.c. + (COMMON_OBS): Add doublest.o. + (doublest.o): Specify dependencies. + (doublest_h): Define. + + * config/m88k/tm-m88k.h: Include "doublest.h". + * config/i960/tm-i960.h: Ditto. + * config/i386/tm-symmetry.h: Ditto. + * rs6000-tdep.c, valarith.c: Ditto. + * valprint.c, stabsread.c, sh-tdep.c: Ditto. + * ia64-tdep.c, i387-tdep.c, i386-tdep.c: Ditto. + * values.c, arm-tdep.c, arm-linux-tdep.c: Ditto. + * alpha-tdep.c, ax.h, expression.h: Ditto. + * sh-tdep.c, parse.c, top.c, value.h: Ditto. + + * Makefile.in (arm-tdep.o): Add $(doublest_h). + (i386-tdep.o, i387-tdep.o, ia64-tdep.o): Ditto. + (rs6000-tdep.o, stabsread.o, valarith.o): Ditto. + (values.o, valprint.o, arm-linux-tdep.o): Ditto. + (alpha-tdep.o, ax_h, parse.o, top.o, value_h): Ditto. + (parser_defs_h): Ditto. + (expression_h): Add $(doublest_h) and $(symtab_h). + 2001-08-01 Andrew Cagney <ac131313@redhat.com> * Makefile.in: Sort header definitions. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 40a65fc..14544ed 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -541,7 +541,7 @@ SFILES = ax-general.c ax-gdb.c bcache.c blockframe.c breakpoint.c \ tui/tuiStack.c tui/tuiStack.h tui/tuiWin.c tui/tuiWin.h \ tui/tui-file.h tui/tui-file.c tui/tui-out.c tui/tui-hooks.c \ ui-file.h ui-file.c \ - frame.c \ + frame.c doublest.c \ gnu-v2-abi.c gnu-v3-abi.c hpacc-abi.c cp-abi.c LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c @@ -579,7 +579,7 @@ nm_h = @nm_h@ annotate_h = annotate.h $(symtab_h) $(gdbtypes_h) arch_utils_h = arch-utils.h -ax_h = ax.h +ax_h = ax.h $(doublest_h) breakpoint_h = breakpoint.h $(frame_h) $(value_h) call_cmds_h = call-cmds.h cli_cmds_h = $(srcdir)/cli/cli-cmds.h @@ -593,9 +593,10 @@ completer_h = completer.h cp_abi_h = cp-abi.h dcache_h = dcache.h defs_h = defs.h $(xm_h) $(tm_h) $(nm_h) config.status config.h gdbarch.h ui-file.h +doublest_h = doublest.h $(floatformat_h) event_loop_h = event-loop.h event_top_h = event-top.h -expression_h = expression.h +expression_h = expression.h $(doublest_h) $(symtab_h) frame_h = frame.h gdb_h = gdb.h gdb_string_h = gdb_string.h @@ -606,7 +607,7 @@ gdbtypes_h = gdbtypes.h inf_loop_h = inf-loop.h inferior_h = inferior.h $(breakpoint_h) memattr_h = memattr.h -parser_defs_h = parser-defs.h +parser_defs_h = parser-defs.h $(doublest_h) regcache_h = regcache.h remote_h = remote.h remote_utils_h = remote-utils.h $(target_h) @@ -616,7 +617,7 @@ target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h) top_h = top.h tracepoint_h = tracepoint.h ui_out_h = ui-out.h -value_h = value.h $(symtab_h) $(gdbtypes_h) $(expression_h) +value_h = value.h $(symtab_h) $(gdbtypes_h) $(expression_h) $(doublest_h) version_h = version.h # Header files that need to have srcdir added. Note that in the cases @@ -693,7 +694,9 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \ c-valprint.o cp-valprint.o ch-valprint.o f-valprint.o m2-valprint.o \ nlmread.o serial.o mdebugread.o os9kread.o top.o utils.o \ ui-file.o \ - frame.o \ + frame.o doublest.o \ + ui-file.o \ + frame.o doublest.o \ gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o OBS = $(COMMON_OBS) $(ANNOTATE_OBS) @@ -1201,8 +1204,8 @@ alpha-nat.o: alpha-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) $(target_h) \ $(regcache_h) alpha-tdep.o: alpha-tdep.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ - $(inferior_h) $(symtab_h) $(dis_asm_h) $(gdb_string_h) linespec.h \ - $(regcache_h) + $(inferior_h) $(symtab_h) $(dis-asm.h) $(gdb_string_h) linespec.h \ + $(regcache_h) $(doublest_h) annotate.o: annotate.c $(defs_h) $(annotate_h) $(value_h) $(target_h) $(gdbtypes_h) @@ -1210,10 +1213,10 @@ arm-linux-nat.o: arm-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \ $(gdb_string_h) $(regcache_h) arm-linux-tdep.o: arm-linux-tdep.c $(defs_h) $(target_h) $(value_h) \ - $(gdbtypes_h) $(floatformat_h) $(regcache_h) + $(gdbtypes_h) $(floatformat_h) $(regcache_h) $(doublest_h) arm-tdep.o: arm-tdep.c $(gdbcmd_h) $(gdbcore_h) $(inferior_h) $(defs_h) \ - $(gdbcore_h) $(regcache_h) + $(gdbcore_h) $(regcache_h) $(doublest_h) bcache.o: bcache.c bcache.h $(defs_h) @@ -1237,6 +1240,9 @@ c-typeprint.o: c-typeprint.c c-lang.h $(defs_h) $(expression_h) \ c-valprint.o: c-valprint.c $(defs_h) $(expression_h) $(gdbtypes_h) \ language.h $(symtab_h) valprint.h $(value_h) $(cp_abi_h) +doublest.o: doublest.c $(defs_h) $(doublest_h) $(floatformat_h) \ + gdb_assert.h gdb_string.h + f-lang.o: f-lang.c f-lang.h $(defs_h) $(expression_h) $(gdbtypes_h) \ language.h $(parser_defs_h) $(symtab_h) $(gdb_string_h) @@ -1522,7 +1528,8 @@ i386gnu-nat.o: gnu-nat.h i386-tdep.o: i386-tdep.c $(defs_h) $(gdb_string_h) $(frame_h) \ $(inferior_h) $(gdbcore_h) $(target_h) $(floatformat_h) \ - $(symtab_h) $(gdbcmd_h) $(command_h) $(arch_utils_h) $(regcache_h) + $(symtab_h) $(gdbcmd_h) $(command_h) $(arch_utils_h) $(regcache_h) \ + $(doublest_h) i386-nat.o: i386-nat.c $(defs_h) $(breakpoint_h) $(command_h) $(gdbcmd_h) @@ -1561,7 +1568,7 @@ i386-linux-tdep.o: i386-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) \ i386v4-nat.o: i386v4-nat.c $(defs_h) $(regcache_h) i387-tdep.o: i387-tdep.c $(floatformat_h) $(defs_h) $(gdbcore_h) \ - $(inferior_h) language.h $(regcache_h) + $(inferior_h) language.h $(regcache_h) $(doublest_h) i960-tdep.o: i960-tdep.c $(floatformat_h) $(defs_h) $(expression_h) \ $(frame_h) $(gdbtypes_h) $(symtab_h) $(value_h) $(gdbcore_h) \ @@ -1574,7 +1581,7 @@ ia64-linux-tdep.o: ia64-linux-tdep.c $(defs_h) $(arch_utils_h) ia64-tdep.o: ia64-tdep.c $(defs_h) $(inferior_h) $(symfile_h) $(gdbcore_h) \ $(arch_utils_h) $(floatformat_h) objfiles.h \ - $(INCLUDE_DIR)/elf/common.h $(regcache_h) + $(INCLUDE_DIR)/elf/common.h $(regcache_h) $(doublest_h) infcmd.o: infcmd.c $(defs_h) environ.h $(gdbcmd_h) $(gdbcore_h) \ $(inferior_h) $(target_h) language.h $(symfile_h) $(gdb_string_h) \ @@ -1771,7 +1778,7 @@ hp-symtab-read.o: hp-symtab-read.c hpread.h $(bfd_h) buildsym.h complaints.h \ parse.o: parse.c $(command_h) $(defs_h) $(expression_h) $(frame_h) \ $(gdbtypes_h) language.h $(parser_defs_h) $(symtab_h) $(value_h) \ - $(gdb_string_h) linespec.h + $(gdb_string_h) linespec.h $(doublest_h) ppc-bdm.o: ppc-bdm.c $(defs_h) $(gdbcore_h) $(gdb_string_h) $(frame_h) \ $(inferior_h) $(bfd_h) $(symfile_h) $(target_h) $(gdbcmd_h) \ @@ -1956,7 +1963,7 @@ serial.o: serial.c $(defs_h) serial.h $(gdb_string_h) sh-tdep.o: sh-tdep.c $(bfd_h) $(dis_asm_h) \ $(srcdir)/../opcodes/sh-opc.h $(defs_h) $(expression_h) $(frame_h) \ $(gdbcmd_h) $(gdbtypes_h) $(symtab_h) $(value_h) $(arch_utils_h) \ - $(regcache_h) + $(regcache_h) $(doublest_h) sh3-rom.o: sh3-rom.c monitor.h $(bfd_h) gdb_wait.h $(defs_h) $(gdbcmd_h) \ $(inferior_h) $(target_h) serial.h terminal.h $(arch_utils_h) \ @@ -1995,7 +2002,7 @@ dsrec.o: dsrec.c $(defs_h) srec.h stabsread.o: stabsread.c $(bfd_h) $(INCLUDE_DIR)/aout/stab.def \ $(INCLUDE_DIR)/aout/stab_gnu.h buildsym.h complaints.h $(defs_h) \ $(gdbtypes_h) objfiles.h stabsread.h $(symfile_h) $(symtab_h) \ - $(gdb_string_h) + $(gdb_string_h) $(doublest_h) stack.o: stack.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) $(inferior_h) \ language.h $(target_h) $(gdb_string_h) $(ui_out_h) @@ -2050,7 +2057,7 @@ top.o: top.c top.h $(bfd_h) $(getopt_h) $(readline_headers) call-cmds.h \ $(cli_cmds_h) $(cli_script_h) $(cli_setshow_h) \ $(defs_h) $(gdbcmd_h) $(inferior_h) language.h \ $(remote_utils_h) $(gdb_string_h) $(event_loop_h) $(event_top_h) \ - $(completer_h) $(version_h) $(ui_out_h) \ + $(completer_h) $(version_h) $(ui_out_h) $(doublest_h) \ serial.h typeprint.o: typeprint.c $(defs_h) $(expression_h) $(gdbcmd_h) \ @@ -2069,18 +2076,18 @@ utils.o: utils.c $(bfd_h) $(defs_h) $(expression_h) $(gdbcmd_h) \ valarith.o: valarith.c $(bfd_h) $(defs_h) $(expression_h) \ $(gdbtypes_h) language.h $(symtab_h) $(target_h) $(value_h) \ - $(gdb_string_h) + $(gdb_string_h) $(doublest_h) valops.o: valops.c $(defs_h) $(gdbcore_h) $(inferior_h) $(target_h) \ $(gdb_string_h) $(regcache_h) $(cp_abi_h) valprint.o: valprint.c $(defs_h) $(expression_h) $(gdbcmd_h) \ $(gdbcore_h) $(gdbtypes_h) language.h $(symtab_h) $(target_h) \ - $(value_h) $(gdb_string_h) valprint.h + $(value_h) $(gdb_string_h) valprint.h $(doublest_h) values.o: values.c $(defs_h) $(expression_h) $(frame_h) $(gdbcmd_h) \ $(gdbcore_h) $(gdbtypes_h) $(symtab_h) $(target_h) $(value_h) \ - $(gdb_string_h) scm-lang.h + $(gdb_string_h) scm-lang.h $(doublest_h) vax-tdep.o: vax-tdep.c $(OP_INCLUDE)/vax.h $(defs_h) $(symtab_h) diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c index aa0eb5d..c420cb5 100644 --- a/gdb/alpha-tdep.c +++ b/gdb/alpha-tdep.c @@ -32,6 +32,7 @@ #include "gdb_string.h" #include "linespec.h" #include "regcache.h" +#include "doublest.h" /* FIXME: Some of this code should perhaps be merged with mips-tdep.c. */ diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index 05c186a..6faf85b 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -26,6 +26,7 @@ #include "gdbcore.h" #include "frame.h" #include "regcache.h" +#include "doublest.h" /* For arm_linux_skip_solib_resolver. */ #include "symtab.h" diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index fc8991c..e9fe7c7 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -30,6 +30,7 @@ #include "dis-asm.h" /* For register flavors. */ #include <ctype.h> /* for isupper () */ #include "regcache.h" +#include "doublest.h" /* Each OS has a different mechanism for accessing the various registers stored in the sigcontext structure. @@ -21,6 +21,8 @@ #ifndef AGENTEXPR_H #define AGENTEXPR_H +#include "doublest.h" /* For DOUBLEST. */ + /* It's sometimes useful to be able to debug programs that you can't really stop for more than a fraction of a second. To this end, the user can specify a tracepoint (like a breakpoint, but you don't diff --git a/gdb/config/i386/tm-symmetry.h b/gdb/config/i386/tm-symmetry.h index 30b6e24..602568d 100644 --- a/gdb/config/i386/tm-symmetry.h +++ b/gdb/config/i386/tm-symmetry.h @@ -25,6 +25,7 @@ #define TM_SYMMETRY_H 1 #include "regcache.h" +#include "doublest.h" /* I don't know if this will work for cross-debugging, even if you do get a copy of the right include file. */ diff --git a/gdb/config/i960/tm-i960.h b/gdb/config/i960/tm-i960.h index fb85674..ab42620 100644 --- a/gdb/config/i960/tm-i960.h +++ b/gdb/config/i960/tm-i960.h @@ -25,6 +25,8 @@ #define I80960 #endif +#include "doublest.h" + /* Hook for the SYMBOL_CLASS of a parameter when decoding DBX symbol information. In the i960, parameters can be stored as locals or as args, depending on the type of the debug record. diff --git a/gdb/config/m88k/tm-m88k.h b/gdb/config/m88k/tm-m88k.h index 077ec32..bb47fa0 100644 --- a/gdb/config/m88k/tm-m88k.h +++ b/gdb/config/m88k/tm-m88k.h @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "doublest.h" #include "regcache.h" /* g++ support is not yet included. */ @@ -1255,64 +1255,6 @@ extern void store_address (void *, int, LONGEST); extern void store_typed_address (void *buf, struct type *type, CORE_ADDR addr); -/* Setup definitions for host and target floating point formats. We need to - consider the format for `float', `double', and `long double' for both target - and host. We need to do this so that we know what kind of conversions need - to be done when converting target numbers to and from the hosts DOUBLEST - data type. */ - -/* This is used to indicate that we don't know the format of the floating point - number. Typically, this is useful for native ports, where the actual format - is irrelevant, since no conversions will be taking place. */ - -extern const struct floatformat floatformat_unknown; - -#if HOST_BYTE_ORDER == BIG_ENDIAN -#ifndef HOST_FLOAT_FORMAT -#define HOST_FLOAT_FORMAT &floatformat_ieee_single_big -#endif -#ifndef HOST_DOUBLE_FORMAT -#define HOST_DOUBLE_FORMAT &floatformat_ieee_double_big -#endif -#else /* LITTLE_ENDIAN */ -#ifndef HOST_FLOAT_FORMAT -#define HOST_FLOAT_FORMAT &floatformat_ieee_single_little -#endif -#ifndef HOST_DOUBLE_FORMAT -#define HOST_DOUBLE_FORMAT &floatformat_ieee_double_little -#endif -#endif - -#ifndef HOST_LONG_DOUBLE_FORMAT -#define HOST_LONG_DOUBLE_FORMAT &floatformat_unknown -#endif - -/* Use `long double' if the host compiler supports it. (Note that this is not - necessarily any longer than `double'. On SunOS/gcc, it's the same as - double.) This is necessary because GDB internally converts all floating - point values to the widest type supported by the host. - - There are problems however, when the target `long double' is longer than the - host's `long double'. In general, we'll probably reduce the precision of - any such values and print a warning. */ - -#ifdef HAVE_LONG_DOUBLE -typedef long double DOUBLEST; -#else -typedef double DOUBLEST; -#endif - -extern void floatformat_to_doublest (const struct floatformat *, - char *, DOUBLEST *); -extern void floatformat_from_doublest (const struct floatformat *, - DOUBLEST *, char *); - -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); /* From valops.c */ diff --git a/gdb/doublest.c b/gdb/doublest.c new file mode 100644 index 0000000..80548e7 --- /dev/null +++ b/gdb/doublest.c @@ -0,0 +1,627 @@ +/* Floating point routines for GDB, the GNU debugger. + Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* Support for converting target fp numbers into host DOUBLEST format. */ + +/* XXX - This code should really be in libiberty/floatformat.c, + however configuration issues with libiberty made this very + difficult to do in the available time. */ + +#include "defs.h" +#include "doublest.h" +#include "floatformat.h" +#include "gdb_assert.h" +#include "gdb_string.h" +#include <math.h> /* ldexp */ + +/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not + going to bother with trying to muck around with whether it is defined in + a system header, what we do if not, etc. */ +#define FLOATFORMAT_CHAR_BIT 8 + +static unsigned long get_field (unsigned char *, + enum floatformat_byteorders, + unsigned int, unsigned int, unsigned int); + +/* Extract a field which starts at START and is LEN bytes long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static unsigned long +get_field (unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len) +{ + unsigned long result; + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + if (order == floatformat_little || order == floatformat_littlebyte_bigword) + { + /* 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 + with what happens if bit 0 doesn't start on a byte boundary. + I.e, we need to properly handle the case where total_len is + not evenly divisible by 8. So we compute ``excess'' which + represents the number of bits from the end of our starting + byte needed to get to bit 0. */ + int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT); + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) + - ((start + len + excess) / FLOATFORMAT_CHAR_BIT); + cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT) + - FLOATFORMAT_CHAR_BIT; + } + else + { + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + } + if (cur_bitshift > -FLOATFORMAT_CHAR_BIT) + result = *(data + cur_byte) >> (-cur_bitshift); + else + result = 0; + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little || order == floatformat_littlebyte_bigword) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while (cur_bitshift < len) + { + result |= (unsigned long)*(data + cur_byte) << cur_bitshift; + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little || order == floatformat_littlebyte_bigword) + ++cur_byte; + else + --cur_byte; + } + if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT) + /* Mask out bits which are not part of the field */ + result &= ((1UL << len) - 1); + return result; +} + +/* Convert from FMT to a DOUBLEST. + FROM is the address of the extended float. + Store the DOUBLEST in *TO. */ + +void +floatformat_to_doublest (const struct floatformat *fmt, char *from, + DOUBLEST *to) +{ + unsigned char *ufrom = (unsigned char *) from; + DOUBLEST dto; + long exponent; + unsigned long mant; + unsigned int mant_bits, mant_off; + 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 = (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; + } + } + + 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 + (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. */ + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + dto = 0.0; + + special_exponent = exponent == 0 || exponent == fmt->exp_nan; + +/* Don't bias NaNs. Use minimum exponent for denorms. For simplicity, + we don't check for zero as the exponent doesn't matter. */ + if (!special_exponent) + exponent -= fmt->exp_bias; + else if (exponent == 0) + exponent = 1 - fmt->exp_bias; + + /* Build the result algebraically. Might go infinite, underflow, etc; + who cares. */ + +/* If this format uses a hidden bit, explicitly add it in now. Otherwise, + increment the exponent by one to account for the integer bit. */ + + if (!special_exponent) + { + if (fmt->intbit == floatformat_intbit_no) + dto = ldexp (1.0, exponent); + else + exponent++; + } + + while (mant_bits_left > 0) + { + mant_bits = min (mant_bits_left, 32); + + mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits); + + dto += ldexp ((double) mant, exponent - mant_bits); + exponent -= mant_bits; + mant_off += mant_bits; + mant_bits_left -= mant_bits; + } + + /* Negate it if negative. */ + if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) + dto = -dto; + *to = dto; +} + +static void put_field (unsigned char *, enum floatformat_byteorders, + unsigned int, + unsigned int, unsigned int, unsigned long); + +/* Set a field which starts at START and is LEN bytes long. DATA and + TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ +static void +put_field (unsigned char *data, enum floatformat_byteorders order, + unsigned int total_len, unsigned int start, unsigned int len, + unsigned long stuff_to_put) +{ + unsigned int cur_byte; + int cur_bitshift; + + /* Start at the least significant part of the field. */ + if (order == floatformat_little || order == floatformat_littlebyte_bigword) + { + int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT); + cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) + - ((start + len + excess) / FLOATFORMAT_CHAR_BIT); + cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT) + - FLOATFORMAT_CHAR_BIT; + } + else + { + cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; + cur_bitshift = + ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; + } + if (cur_bitshift > -FLOATFORMAT_CHAR_BIT) + { + *(data + cur_byte) &= + ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) + << (-cur_bitshift)); + *(data + cur_byte) |= + (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); + } + cur_bitshift += FLOATFORMAT_CHAR_BIT; + if (order == floatformat_little || order == floatformat_littlebyte_bigword) + ++cur_byte; + else + --cur_byte; + + /* Move towards the most significant part of the field. */ + while (cur_bitshift < len) + { + if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) + { + /* This is the last byte. */ + *(data + cur_byte) &= + ~((1 << (len - cur_bitshift)) - 1); + *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); + } + else + *(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) + ++cur_byte; + else + --cur_byte; + } +} + +#ifdef HAVE_LONG_DOUBLE +/* Return the fractional part of VALUE, and put the exponent of VALUE in *EPTR. + The range of the returned value is >= 0.5 and < 1.0. This is equivalent to + frexp, but operates on the long double data type. */ + +static long double ldfrexp (long double value, int *eptr); + +static long double +ldfrexp (long double value, int *eptr) +{ + long double tmp; + int exp; + + /* Unfortunately, there are no portable functions for extracting the exponent + of a long double, so we have to do it iteratively by multiplying or dividing + by two until the fraction is between 0.5 and 1.0. */ + + if (value < 0.0l) + value = -value; + + tmp = 1.0l; + exp = 0; + + if (value >= tmp) /* Value >= 1.0 */ + while (value >= tmp) + { + tmp *= 2.0l; + exp++; + } + else if (value != 0.0l) /* Value < 1.0 and > 0.0 */ + { + while (value < tmp) + { + tmp /= 2.0l; + exp--; + } + tmp *= 2.0l; + exp++; + } + + *eptr = exp; + return value / tmp; +} +#endif /* HAVE_LONG_DOUBLE */ + + +/* The converse: convert the DOUBLEST *FROM to an extended float + and store where TO points. Neither FROM nor TO have any alignment + restrictions. */ + +void +floatformat_from_doublest (CONST struct floatformat *fmt, DOUBLEST *from, + char *to) +{ + DOUBLEST dfrom; + int exponent; + DOUBLEST mant; + unsigned int mant_bits, mant_off; + int mant_bits_left; + unsigned char *uto = (unsigned char *) to; + + memcpy (&dfrom, from, sizeof (dfrom)); + memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1) + / FLOATFORMAT_CHAR_BIT); + if (dfrom == 0) + return; /* Result is zero */ + if (dfrom != dfrom) /* Result is NaN */ + { + /* From is NaN */ + put_field (uto, fmt->byteorder, 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, + 32, 1); + return; + } + + /* If negative, set the sign bit. */ + if (dfrom < 0) + { + put_field (uto, fmt->byteorder, 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, + 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); +#else + mant = frexp (dfrom, &exponent); +#endif + + put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len, + exponent + fmt->exp_bias - 1); + + mant_bits_left = fmt->man_len; + mant_off = fmt->man_start; + while (mant_bits_left > 0) + { + unsigned long mant_long; + mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; + + mant *= 4294967296.0; + mant_long = ((unsigned long) mant) & 0xffffffffL; + mant -= mant_long; + + /* If the integer bit is implicit, then we need to discard it. + If we are discarding a zero, we should be (but are not) creating + a denormalized number which means adjusting the exponent + (I think). */ + if (mant_bits_left == fmt->man_len + && fmt->intbit == floatformat_intbit_no) + { + mant_long <<= 1; + mant_long &= 0xffffffffL; + mant_bits -= 1; + } + + 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. */ + mant_long >>= 32 - mant_bits; + } + + put_field (uto, fmt->byteorder, fmt->totalsize, + mant_off, mant_bits, mant_long); + 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; + } + } +} + +/* 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; +} + + + +/* Extract a floating-point number from a target-order byte-stream at ADDR. + Returns the value as type DOUBLEST. + + If the host and target formats agree, we just copy the raw data into the + appropriate type of variable and return, letting the host increase precision + as necessary. Otherwise, we call the conversion routine and let it do the + dirty work. */ + +DOUBLEST +extract_floating (void *addr, int len) +{ + DOUBLEST dretval; + + if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT) + { + if (HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT) + { + float retval; + + memcpy (&retval, addr, sizeof (retval)); + return retval; + } + else + floatformat_to_doublest (TARGET_FLOAT_FORMAT, addr, &dretval); + } + else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT) + { + if (HOST_DOUBLE_FORMAT == TARGET_DOUBLE_FORMAT) + { + double retval; + + memcpy (&retval, addr, sizeof (retval)); + return retval; + } + else + floatformat_to_doublest (TARGET_DOUBLE_FORMAT, addr, &dretval); + } + else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT) + { + if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT) + { + DOUBLEST retval; + + memcpy (&retval, addr, sizeof (retval)); + return retval; + } + else + floatformat_to_doublest (TARGET_LONG_DOUBLE_FORMAT, addr, &dretval); + } + else + { + error ("Can't deal with a floating point number of %d bytes.", len); + } + + return dretval; +} + +void +store_floating (void *addr, int len, DOUBLEST val) +{ + if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT) + { + if (HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT) + { + float floatval = val; + + memcpy (addr, &floatval, sizeof (floatval)); + } + else + floatformat_from_doublest (TARGET_FLOAT_FORMAT, &val, addr); + } + else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT) + { + if (HOST_DOUBLE_FORMAT == TARGET_DOUBLE_FORMAT) + { + double doubleval = val; + + memcpy (addr, &doubleval, sizeof (doubleval)); + } + else + floatformat_from_doublest (TARGET_DOUBLE_FORMAT, &val, addr); + } + else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT) + { + if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT) + memcpy (addr, &val, sizeof (val)); + else + floatformat_from_doublest (TARGET_LONG_DOUBLE_FORMAT, &val, addr); + } + else + { + error ("Can't deal with a floating point number of %d bytes.", len); + } +} diff --git a/gdb/doublest.h b/gdb/doublest.h new file mode 100644 index 0000000..8e39196 --- /dev/null +++ b/gdb/doublest.h @@ -0,0 +1,87 @@ +/* Floating point definitions for GDB. + Copyright 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, + 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef DOUBLEST_H +#define DOUBLEST_H + +/* Setup definitions for host and target floating point formats. We need to + consider the format for `float', `double', and `long double' for both target + and host. We need to do this so that we know what kind of conversions need + to be done when converting target numbers to and from the hosts DOUBLEST + data type. */ + +/* This is used to indicate that we don't know the format of the floating point + number. Typically, this is useful for native ports, where the actual format + is irrelevant, since no conversions will be taking place. */ + +#include "floatformat.h" /* For struct floatformat */ + +extern const struct floatformat floatformat_unknown; + +#if HOST_BYTE_ORDER == BIG_ENDIAN +#ifndef HOST_FLOAT_FORMAT +#define HOST_FLOAT_FORMAT &floatformat_ieee_single_big +#endif +#ifndef HOST_DOUBLE_FORMAT +#define HOST_DOUBLE_FORMAT &floatformat_ieee_double_big +#endif +#else /* LITTLE_ENDIAN */ +#ifndef HOST_FLOAT_FORMAT +#define HOST_FLOAT_FORMAT &floatformat_ieee_single_little +#endif +#ifndef HOST_DOUBLE_FORMAT +#define HOST_DOUBLE_FORMAT &floatformat_ieee_double_little +#endif +#endif + +#ifndef HOST_LONG_DOUBLE_FORMAT +#define HOST_LONG_DOUBLE_FORMAT &floatformat_unknown +#endif + +/* Use `long double' if the host compiler supports it. (Note that this is not + necessarily any longer than `double'. On SunOS/gcc, it's the same as + double.) This is necessary because GDB internally converts all floating + point values to the widest type supported by the host. + + There are problems however, when the target `long double' is longer than the + host's `long double'. In general, we'll probably reduce the precision of + any such values and print a warning. */ + +#ifdef HAVE_LONG_DOUBLE +typedef long double DOUBLEST; +#else +typedef double DOUBLEST; +#endif + +extern void floatformat_to_doublest (const struct floatformat *, + char *, DOUBLEST *); +extern void floatformat_from_doublest (const struct floatformat *, + DOUBLEST *, char *); + +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); + +#endif diff --git a/gdb/expression.h b/gdb/expression.h index 1320643..0fbab03 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -23,6 +23,7 @@ #include "symtab.h" /* Needed for "struct block" type. */ +#include "doublest.h" /* Needed for DOUBLEST. */ /* Definitions for saved C expressions. */ diff --git a/gdb/findvar.c b/gdb/findvar.c index 28a8ce0..0ba9392 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -288,102 +288,6 @@ store_typed_address (void *buf, struct type *type, CORE_ADDR addr) - -/* Extract a floating-point number from a target-order byte-stream at ADDR. - Returns the value as type DOUBLEST. - - If the host and target formats agree, we just copy the raw data into the - appropriate type of variable and return, letting the host increase precision - as necessary. Otherwise, we call the conversion routine and let it do the - dirty work. */ - -DOUBLEST -extract_floating (void *addr, int len) -{ - DOUBLEST dretval; - - if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT) - { - if (HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT) - { - float retval; - - memcpy (&retval, addr, sizeof (retval)); - return retval; - } - else - floatformat_to_doublest (TARGET_FLOAT_FORMAT, addr, &dretval); - } - else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT) - { - if (HOST_DOUBLE_FORMAT == TARGET_DOUBLE_FORMAT) - { - double retval; - - memcpy (&retval, addr, sizeof (retval)); - return retval; - } - else - floatformat_to_doublest (TARGET_DOUBLE_FORMAT, addr, &dretval); - } - else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT) - { - if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT) - { - DOUBLEST retval; - - memcpy (&retval, addr, sizeof (retval)); - return retval; - } - else - floatformat_to_doublest (TARGET_LONG_DOUBLE_FORMAT, addr, &dretval); - } - else - { - error ("Can't deal with a floating point number of %d bytes.", len); - } - - return dretval; -} - -void -store_floating (void *addr, int len, DOUBLEST val) -{ - if (len * TARGET_CHAR_BIT == TARGET_FLOAT_BIT) - { - if (HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT) - { - float floatval = val; - - memcpy (addr, &floatval, sizeof (floatval)); - } - else - floatformat_from_doublest (TARGET_FLOAT_FORMAT, &val, addr); - } - else if (len * TARGET_CHAR_BIT == TARGET_DOUBLE_BIT) - { - if (HOST_DOUBLE_FORMAT == TARGET_DOUBLE_FORMAT) - { - double doubleval = val; - - memcpy (addr, &doubleval, sizeof (doubleval)); - } - else - floatformat_from_doublest (TARGET_DOUBLE_FORMAT, &val, addr); - } - else if (len * TARGET_CHAR_BIT == TARGET_LONG_DOUBLE_BIT) - { - if (HOST_LONG_DOUBLE_FORMAT == TARGET_LONG_DOUBLE_FORMAT) - memcpy (addr, &val, sizeof (val)); - else - floatformat_from_doublest (TARGET_LONG_DOUBLE_FORMAT, &val, addr); - } - else - { - error ("Can't deal with a floating point number of %d bytes.", len); - } -} - /* Return a `value' with the contents of register REGNUM in its virtual format, with the type specified by REGISTER_VIRTUAL_TYPE. diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index d8cfe0f..c55757e 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -32,6 +32,7 @@ #include "command.h" #include "arch-utils.h" #include "regcache.h" +#include "doublest.h" #include "gdb_assert.h" diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c index 66b6dc0..275a1e2 100644 --- a/gdb/i387-tdep.c +++ b/gdb/i387-tdep.c @@ -28,6 +28,7 @@ #include "floatformat.h" #include "regcache.h" #include "gdb_assert.h" +#include "doublest.h" /* FIXME: Eliminate the next two functions when we have the time to diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c index 64fa35e..2a01809 100644 --- a/gdb/ia64-tdep.c +++ b/gdb/ia64-tdep.c @@ -26,6 +26,7 @@ #include "arch-utils.h" #include "floatformat.h" #include "regcache.h" +#include "doublest.h" #include "objfiles.h" #include "elf/common.h" /* for DT_PLTGOT value */ diff --git a/gdb/parse.c b/gdb/parse.c index 2edc6d7..1c4324b 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -46,6 +46,7 @@ #include "symfile.h" /* for overlay functions */ #include "inferior.h" /* for NUM_PSEUDO_REGS. NOTE: replace with "gdbarch.h" when appropriate. */ +#include "doublest.h" /* Symbols which architectures can redefine. */ diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index c254b62..cf85399 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -24,6 +24,8 @@ #if !defined (PARSER_DEFS_H) #define PARSER_DEFS_H 1 +#include "doublest.h" + struct std_regs { char *name; diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index d1a81e6..6f5ade6 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -31,6 +31,7 @@ #include "objfiles.h" #include "arch-utils.h" #include "regcache.h" +#include "doublest.h" #include "bfd/libbfd.h" /* for bfd_default_set_arch_mach */ #include "coff/internal.h" /* for libcoff.h */ diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index 52ec8e8..0c7ff68 100644 --- a/gdb/sh-tdep.c +++ b/gdb/sh-tdep.c @@ -39,6 +39,7 @@ #include "arch-utils.h" #include "floatformat.h" #include "regcache.h" +#include "doublest.h" #include "solib-svr4.h" diff --git a/gdb/stabsread.c b/gdb/stabsread.c index 169f1f9..00857e0 100644 --- a/gdb/stabsread.c +++ b/gdb/stabsread.c @@ -43,6 +43,7 @@ #include "complaints.h" #include "demangle.h" #include "language.h" +#include "doublest.h" #include <ctype.h> @@ -40,6 +40,7 @@ #include "top.h" #include "version.h" #include "serial.h" +#include "doublest.h" /* readline include files */ #include <readline/readline.h> diff --git a/gdb/utils.c b/gdb/utils.c index 82d010b..ba73d8d 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -2326,511 +2326,6 @@ initialize_utils (void) #ifdef SIGWINCH_HANDLER_BODY SIGWINCH_HANDLER_BODY #endif - -/* Support for converting target fp numbers into host DOUBLEST format. */ - -/* XXX - This code should really be in libiberty/floatformat.c, however - configuration issues with libiberty made this very difficult to do in the - available time. */ - -#include "floatformat.h" -#include <math.h> /* ldexp */ - -/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not - going to bother with trying to muck around with whether it is defined in - a system header, what we do if not, etc. */ -#define FLOATFORMAT_CHAR_BIT 8 - -static unsigned long get_field (unsigned char *, - enum floatformat_byteorders, - unsigned int, unsigned int, unsigned int); - -/* Extract a field which starts at START and is LEN bytes long. DATA and - TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ -static unsigned long -get_field (unsigned char *data, enum floatformat_byteorders order, - unsigned int total_len, unsigned int start, unsigned int len) -{ - unsigned long result; - unsigned int cur_byte; - int cur_bitshift; - - /* Start at the least significant part of the field. */ - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - { - /* 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 - with what happens if bit 0 doesn't start on a byte boundary. - I.e, we need to properly handle the case where total_len is - not evenly divisible by 8. So we compute ``excess'' which - represents the number of bits from the end of our starting - byte needed to get to bit 0. */ - int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT); - cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - - ((start + len + excess) / FLOATFORMAT_CHAR_BIT); - cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT) - - FLOATFORMAT_CHAR_BIT; - } - else - { - cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; - cur_bitshift = - ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; - } - if (cur_bitshift > -FLOATFORMAT_CHAR_BIT) - result = *(data + cur_byte) >> (-cur_bitshift); - else - result = 0; - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - ++cur_byte; - else - --cur_byte; - - /* Move towards the most significant part of the field. */ - while (cur_bitshift < len) - { - result |= (unsigned long)*(data + cur_byte) << cur_bitshift; - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - ++cur_byte; - else - --cur_byte; - } - if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT) - /* Mask out bits which are not part of the field */ - result &= ((1UL << len) - 1); - return result; -} - -/* Convert from FMT to a DOUBLEST. - FROM is the address of the extended float. - Store the DOUBLEST in *TO. */ - -void -floatformat_to_doublest (const struct floatformat *fmt, char *from, - DOUBLEST *to) -{ - unsigned char *ufrom = (unsigned char *) from; - DOUBLEST dto; - long exponent; - unsigned long mant; - unsigned int mant_bits, mant_off; - 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 = (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; - } - } - - 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 - (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. */ - - mant_bits_left = fmt->man_len; - mant_off = fmt->man_start; - dto = 0.0; - - special_exponent = exponent == 0 || exponent == fmt->exp_nan; - -/* Don't bias NaNs. Use minimum exponent for denorms. For simplicity, - we don't check for zero as the exponent doesn't matter. */ - if (!special_exponent) - exponent -= fmt->exp_bias; - else if (exponent == 0) - exponent = 1 - fmt->exp_bias; - - /* Build the result algebraically. Might go infinite, underflow, etc; - who cares. */ - -/* If this format uses a hidden bit, explicitly add it in now. Otherwise, - increment the exponent by one to account for the integer bit. */ - - if (!special_exponent) - { - if (fmt->intbit == floatformat_intbit_no) - dto = ldexp (1.0, exponent); - else - exponent++; - } - - while (mant_bits_left > 0) - { - mant_bits = min (mant_bits_left, 32); - - mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, - mant_off, mant_bits); - - dto += ldexp ((double) mant, exponent - mant_bits); - exponent -= mant_bits; - mant_off += mant_bits; - mant_bits_left -= mant_bits; - } - - /* Negate it if negative. */ - if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) - dto = -dto; - *to = dto; -} - -static void put_field (unsigned char *, enum floatformat_byteorders, - unsigned int, - unsigned int, unsigned int, unsigned long); - -/* Set a field which starts at START and is LEN bytes long. DATA and - TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ -static void -put_field (unsigned char *data, enum floatformat_byteorders order, - unsigned int total_len, unsigned int start, unsigned int len, - unsigned long stuff_to_put) -{ - unsigned int cur_byte; - int cur_bitshift; - - /* Start at the least significant part of the field. */ - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - { - int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT); - cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - - ((start + len + excess) / FLOATFORMAT_CHAR_BIT); - cur_bitshift = ((start + len + excess) % FLOATFORMAT_CHAR_BIT) - - FLOATFORMAT_CHAR_BIT; - } - else - { - cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; - cur_bitshift = - ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; - } - if (cur_bitshift > -FLOATFORMAT_CHAR_BIT) - { - *(data + cur_byte) &= - ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) - << (-cur_bitshift)); - *(data + cur_byte) |= - (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); - } - cur_bitshift += FLOATFORMAT_CHAR_BIT; - if (order == floatformat_little || order == floatformat_littlebyte_bigword) - ++cur_byte; - else - --cur_byte; - - /* Move towards the most significant part of the field. */ - while (cur_bitshift < len) - { - if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) - { - /* This is the last byte. */ - *(data + cur_byte) &= - ~((1 << (len - cur_bitshift)) - 1); - *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); - } - else - *(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) - ++cur_byte; - else - --cur_byte; - } -} - -#ifdef HAVE_LONG_DOUBLE -/* Return the fractional part of VALUE, and put the exponent of VALUE in *EPTR. - The range of the returned value is >= 0.5 and < 1.0. This is equivalent to - frexp, but operates on the long double data type. */ - -static long double ldfrexp (long double value, int *eptr); - -static long double -ldfrexp (long double value, int *eptr) -{ - long double tmp; - int exp; - - /* Unfortunately, there are no portable functions for extracting the exponent - of a long double, so we have to do it iteratively by multiplying or dividing - by two until the fraction is between 0.5 and 1.0. */ - - if (value < 0.0l) - value = -value; - - tmp = 1.0l; - exp = 0; - - if (value >= tmp) /* Value >= 1.0 */ - while (value >= tmp) - { - tmp *= 2.0l; - exp++; - } - else if (value != 0.0l) /* Value < 1.0 and > 0.0 */ - { - while (value < tmp) - { - tmp /= 2.0l; - exp--; - } - tmp *= 2.0l; - exp++; - } - - *eptr = exp; - return value / tmp; -} -#endif /* HAVE_LONG_DOUBLE */ - - -/* The converse: convert the DOUBLEST *FROM to an extended float - and store where TO points. Neither FROM nor TO have any alignment - restrictions. */ - -void -floatformat_from_doublest (CONST struct floatformat *fmt, DOUBLEST *from, - char *to) -{ - DOUBLEST dfrom; - int exponent; - DOUBLEST mant; - unsigned int mant_bits, mant_off; - int mant_bits_left; - unsigned char *uto = (unsigned char *) to; - - memcpy (&dfrom, from, sizeof (dfrom)); - memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1) - / FLOATFORMAT_CHAR_BIT); - if (dfrom == 0) - return; /* Result is zero */ - if (dfrom != dfrom) /* Result is NaN */ - { - /* From is NaN */ - put_field (uto, fmt->byteorder, 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, - 32, 1); - return; - } - - /* If negative, set the sign bit. */ - if (dfrom < 0) - { - put_field (uto, fmt->byteorder, 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, - 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); -#else - mant = frexp (dfrom, &exponent); -#endif - - put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len, - exponent + fmt->exp_bias - 1); - - mant_bits_left = fmt->man_len; - mant_off = fmt->man_start; - while (mant_bits_left > 0) - { - unsigned long mant_long; - mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; - - mant *= 4294967296.0; - mant_long = ((unsigned long) mant) & 0xffffffffL; - mant -= mant_long; - - /* If the integer bit is implicit, then we need to discard it. - If we are discarding a zero, we should be (but are not) creating - a denormalized number which means adjusting the exponent - (I think). */ - if (mant_bits_left == fmt->man_len - && fmt->intbit == floatformat_intbit_no) - { - mant_long <<= 1; - mant_long &= 0xffffffffL; - mant_bits -= 1; - } - - 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. */ - mant_long >>= 32 - mant_bits; - } - - put_field (uto, fmt->byteorder, fmt->totalsize, - mant_off, mant_bits, mant_long); - 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; - } - } -} - -/* 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. */ diff --git a/gdb/valarith.c b/gdb/valarith.c index aaa393f..d421a02 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -28,6 +28,7 @@ #include "target.h" #include "language.h" #include "gdb_string.h" +#include "doublest.h" #include <math.h> /* Define whether or not the C operator '/' truncates towards zero for diff --git a/gdb/valprint.c b/gdb/valprint.c index 49c6cb8..3feb915 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -33,6 +33,7 @@ #include "annotate.h" #include "valprint.h" #include "floatformat.h" +#include "doublest.h" #include <errno.h> diff --git a/gdb/value.h b/gdb/value.h index 8b1d18f..5db5f11 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -23,6 +23,8 @@ #if !defined (VALUE_H) #define VALUE_H 1 +#include "doublest.h" + /* * The structure which defines the type of a value. It should never * be possible for a program lval value to survive over a call to the inferior diff --git a/gdb/values.c b/gdb/values.c index 5f7468c..c41afb5 100644 --- a/gdb/values.c +++ b/gdb/values.c @@ -32,6 +32,7 @@ #include "language.h" #include "scm-lang.h" #include "demangle.h" +#include "doublest.h" /* Prototypes for exported functions. */ |