diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 44 | ||||
-rw-r--r-- | gdb/Makefile.in | 7 | ||||
-rw-r--r-- | gdb/dfp.c | 299 | ||||
-rw-r--r-- | gdb/dfp.h | 9 | ||||
-rw-r--r-- | gdb/eval.c | 4 | ||||
-rw-r--r-- | gdb/valarith.c | 132 | ||||
-rw-r--r-- | gdb/valops.c | 20 | ||||
-rw-r--r-- | gdb/value.c | 23 | ||||
-rw-r--r-- | gdb/value.h | 5 |
9 files changed, 510 insertions, 33 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 66d677e..9052e28 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,47 @@ +2008-01-07 Thiago Jung Bauermann <bauerman@br.ibm.com> + + * Makefile.in (dfp.o): Depend on expression.h, gdbtypes.h and value.h. + (valarith.o): Depend on dfp.h. + (valops.o): Likewise. + * dfp.c: Include expression.h, gdbtypes.h, value.h and dfp.h. + (set_decnumber_context): New function. + (decimal_check_errors): Likewise. + (decimal_from_number): Likewise. + (decimal_to_number): Likewise. + (decimal_from_string): Use set_decnumber_context and + decimal_check_errors. + (decimal_from_integral): New function. + (decimal_from_floating): Likewise. + (decimal_to_double): Likewise. + (promote_decimal): Likewise. + (decimal_binop): Likewise. + (decimal_is_zero): Likewise. + (decimal_compare): Likewise. + (decimal_convert): Likewise. + * dfp.h (decimal_from_integral): New prototype. + (decimal_from_floating): Likewise. + (decimal_to_double): Likewise. + (decimal_binop): Likewise. + (decimal_is_zero): Likewise. + (decimal_compare): Likewise. + (decimal_convert): Likewise. + * eval.c (evaluate_subexp_standard): Remove expect_type argument from + call to value_from_decfloat. + * valarith.c: Include dfp.h. + (value_args_as_decimal): New function. + (value_binop): Add if block to handle TYPE_CODE_DECFLOAT values. + (value_logical_not): Likewise. + (value_equal): Likewise. + (value_less): Likewise. + (value_pos): Likewise. + (value_neg): Formatting fix. + * valops.c: Include dfp.h. + (value_cast): Add if block to handle TYPE_CODE_DECFLOAT values. + * value.c (unpack_long): Add case to handle TYPE_CODE_DECFLOAT. + (unpack_double): Add if block to handle TYPE_CODE_DECFLOAT. + (value_from_decfloat): Remove expect_type argument. + * value.h (value_from_decfloat): Update prototype. + 2008-01-07 Vladimir Prus <vladimir@codesourcery.com> Ignore change in name of dynamic linker during diff --git a/gdb/Makefile.in b/gdb/Makefile.in index ab3c3ff..45c3d29 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2046,7 +2046,8 @@ dsrec.o: dsrec.c $(defs_h) $(serial_h) $(srec_h) $(gdb_assert_h) \ dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \ $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_h) \ $(command_h) $(gdbcmd_h) $(gdb_string_h) -dfp.o: dfp.c $(defs_h) $(dfp_h) $(decimal128_h) $(decimal64_h) $(decimal32_h) +dfp.o: dfp.c $(defs_h) $(expression_h) $(gdbtypes_h) $(value_h) $(dfp_h) \ + $(decimal128_h) $(decimal64_h) $(decimal32_h) dwarf2expr.o: dwarf2expr.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) \ $(gdbcore_h) $(elf_dwarf2_h) $(dwarf2expr_h) dwarf2-frame.o: dwarf2-frame.c $(defs_h) $(dwarf2expr_h) $(elf_dwarf2_h) \ @@ -2910,12 +2911,12 @@ v850-tdep.o: v850-tdep.c $(defs_h) $(frame_h) $(frame_base_h) $(trad_frame_h) \ $(regcache_h) $(dis_asm_h) $(osabi_h) valarith.o: valarith.c $(defs_h) $(value_h) $(symtab_h) $(gdbtypes_h) \ $(expression_h) $(target_h) $(language_h) $(gdb_string_h) \ - $(doublest_h) $(infcall_h) + $(doublest_h) $(dfp_h) $(infcall_h) valops.o: valops.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) $(frame_h) \ $(inferior_h) $(gdbcore_h) $(target_h) $(demangle_h) $(language_h) \ $(gdbcmd_h) $(regcache_h) $(cp_abi_h) $(block_h) $(infcall_h) \ $(dictionary_h) $(cp_support_h) $(gdb_string_h) $(gdb_assert_h) \ - $(cp_support_h) $(observer_h) + $(cp_support_h) $(observer_h) $(dfp_h) valprint.o: valprint.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(value_h) $(gdbcore_h) $(gdbcmd_h) $(target_h) $(language_h) \ $(annotate_h) $(valprint_h) $(floatformat_h) $(doublest_h) \ @@ -18,6 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "defs.h" +#include "expression.h" +#include "gdbtypes.h" +#include "value.h" +#include "dfp.h" /* The order of the following headers is important for making sure decNumber structure is large enough to hold decimal128 digits. */ @@ -50,6 +54,89 @@ match_endianness (const gdb_byte *from, int len, gdb_byte *to) return; } +/* Helper function to get the appropriate libdecnumber context for each size + of decimal float. */ +static void +set_decnumber_context (decContext *ctx, int len) +{ + switch (len) + { + case 4: + decContextDefault (ctx, DEC_INIT_DECIMAL32); + break; + case 8: + decContextDefault (ctx, DEC_INIT_DECIMAL64); + break; + case 16: + decContextDefault (ctx, DEC_INIT_DECIMAL128); + break; + } + + ctx->traps = 0; +} + +/* Check for errors signaled in the decimal context structure. */ +static void +decimal_check_errors (decContext *ctx) +{ + /* An error here could be a division by zero, an overflow, an underflow or + an invalid operation (from the DEC_Errors constant in decContext.h). + Since GDB doesn't complain about division by zero, overflow or underflow + errors for binary floating, we won't complain about them for decimal + floating either. */ + if (ctx->status & DEC_IEEE_854_Invalid_operation) + { + /* Leave only the error bits in the status flags. */ + ctx->status &= DEC_IEEE_854_Invalid_operation; + error (_("Cannot perform operation: %s"), decContextStatusToString (ctx)); + } +} + +/* Helper function to convert from libdecnumber's appropriate representation + for computation to each size of decimal float. */ +static void +decimal_from_number (const decNumber *from, gdb_byte *to, int len) +{ + decContext set; + + set_decnumber_context (&set, len); + + switch (len) + { + case 4: + decimal32FromNumber ((decimal32 *) to, from, &set); + break; + case 8: + decimal64FromNumber ((decimal64 *) to, from, &set); + break; + case 16: + decimal128FromNumber ((decimal128 *) to, from, &set); + break; + } +} + +/* Helper function to convert each size of decimal float to libdecnumber's + appropriate representation for computation. */ +static void +decimal_to_number (const gdb_byte *from, int len, decNumber *to) +{ + switch (len) + { + case 4: + decimal32ToNumber ((decimal32 *) from, to); + break; + case 8: + decimal64ToNumber ((decimal64 *) from, to); + break; + case 16: + decimal128ToNumber ((decimal128 *) from, to); + break; + default: + error (_("Unknown decimal floating point type.\n")); + break; + } +} + /* Convert decimal type to its string representation. LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and 16 bytes for decimal128. */ @@ -59,6 +146,7 @@ decimal_to_string (const gdb_byte *decbytes, int len, char *s) gdb_byte dec[16]; match_endianness (decbytes, len, dec); + switch (len) { case 4: @@ -85,21 +173,17 @@ decimal_from_string (gdb_byte *decbytes, int len, const char *string) decContext set; gdb_byte dec[16]; + set_decnumber_context (&set, len); + switch (len) { case 4: - decContextDefault (&set, DEC_INIT_DECIMAL32); - set.traps = 0; decimal32FromString ((decimal32 *) dec, string, &set); break; case 8: - decContextDefault (&set, DEC_INIT_DECIMAL64); - set.traps = 0; decimal64FromString ((decimal64 *) dec, string, &set); break; case 16: - decContextDefault (&set, DEC_INIT_DECIMAL128); - set.traps = 0; decimal128FromString ((decimal128 *) dec, string, &set); break; default: @@ -109,5 +193,208 @@ decimal_from_string (gdb_byte *decbytes, int len, const char *string) match_endianness (dec, len, decbytes); + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + return 1; } + +/* Converts a value of an integral type to a decimal float of + specified LEN bytes. */ +void +decimal_from_integral (struct value *from, gdb_byte *to, int len) +{ + LONGEST l; + gdb_byte dec[16]; + decNumber number; + struct type *type; + + type = check_typedef (value_type (from)); + + if (TYPE_LENGTH (type) > 4) + /* libdecnumber can convert only 32-bit integers. */ + error (_("Conversion of large integer to a decimal floating type is not supported.")); + + l = value_as_long (from); + + if (TYPE_UNSIGNED (type)) + decNumberFromUInt32 (&number, (unsigned int) l); + else + decNumberFromInt32 (&number, (int) l); + + decimal_from_number (&number, dec, len); + match_endianness (dec, len, to); +} + +/* Converts a value of a float type to a decimal float of + specified LEN bytes. + + This is an ugly way to do the conversion, but libdecnumber does + not offer a direct way to do it. */ +void +decimal_from_floating (struct value *from, gdb_byte *to, int len) +{ + char *buffer; + int ret; + + ret = asprintf (&buffer, "%.30Lg", value_as_double (from)); + if (ret < 0) + error (_("Error in memory allocation for conversion to decimal float.")); + + decimal_from_string (to, len, buffer); + + free (buffer); +} + +/* Converts a decimal float of LEN bytes to a double value. */ +DOUBLEST +decimal_to_double (const gdb_byte *from, int len) +{ + char buffer[MAX_DECIMAL_STRING]; + + /* This is an ugly way to do the conversion, but libdecnumber does + not offer a direct way to do it. */ + decimal_to_string (from, len, buffer); + return strtod (buffer, NULL); +} + +/* Check if operands have the same size and convert them to the + biggest of the two if necessary. */ +static int +promote_decimal (gdb_byte *x, int len_x, gdb_byte *y, int len_y) +{ + int len_result; + decNumber number; + + if (len_x < len_y) + { + decimal_to_number (x, len_x, &number); + decimal_from_number (&number, x, len_y); + len_result = len_y; + } + else if (len_x > len_y) + { + decimal_to_number (y, len_y, &number); + decimal_from_number (&number, y, len_x); + len_result = len_x; + } + else + len_result = len_x; + + return len_result; +} + +/* Perform operation OP with operands X and Y and store value in RESULT. + If LEN_X and LEN_Y are not equal, RESULT will have the size of the biggest + of the two, and LEN_RESULT will be set accordingly. */ +void +decimal_binop (enum exp_opcode op, const gdb_byte *x, int len_x, + const gdb_byte *y, int len_y, gdb_byte *result, int *len_result) +{ + decContext set; + decNumber number1, number2, number3; + gdb_byte dec1[16], dec2[16], dec3[16]; + + match_endianness (x, len_x, dec1); + match_endianness (y, len_y, dec2); + + *len_result = promote_decimal (dec1, len_x, dec2, len_y); + + /* Both operands are of size *len_result from now on. */ + + decimal_to_number (dec1, *len_result, &number1); + decimal_to_number (dec2, *len_result, &number2); + + set_decnumber_context (&set, *len_result); + + switch (op) + { + case BINOP_ADD: + decNumberAdd (&number3, &number1, &number2, &set); + break; + case BINOP_SUB: + decNumberSubtract (&number3, &number1, &number2, &set); + break; + case BINOP_MUL: + decNumberMultiply (&number3, &number1, &number2, &set); + break; + case BINOP_DIV: + decNumberDivide (&number3, &number1, &number2, &set); + break; + case BINOP_EXP: + decNumberPower (&number3, &number1, &number2, &set); + break; + default: + internal_error (__FILE__, __LINE__, + _("Unknown decimal floating point operation.")); + break; + } + + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + + decimal_from_number (&number3, dec3, *len_result); + + match_endianness (dec3, *len_result, result); +} + +/* Returns true if X (which is LEN bytes wide) is the number zero. */ +int +decimal_is_zero (const gdb_byte *x, int len) +{ + decNumber number; + gdb_byte dec[16]; + + match_endianness (x, len, dec); + decimal_to_number (dec, len, &number); + + return decNumberIsZero (&number); +} + +/* Compares two numbers numerically. If X is less than Y then the return value + will be -1. If they are equal, then the return value will be 0. If X is + greater than the Y then the return value will be 1. */ +int +decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y) +{ + decNumber number1, number2, result; + decContext set; + gdb_byte dec1[16], dec2[16]; + int len_result; + + match_endianness (x, len_x, dec1); + match_endianness (y, len_y, dec2); + + len_result = promote_decimal (dec1, len_x, dec2, len_y); + + decimal_to_number (dec1, len_result, &number1); + decimal_to_number (dec2, len_result, &number2); + + set_decnumber_context (&set, len_result); + + decNumberCompare (&result, &number1, &number2, &set); + + /* Check for errors in the DFP operation. */ + decimal_check_errors (&set); + + if (decNumberIsNaN (&result)) + error (_("Comparison with an invalid number (NaN).")); + else if (decNumberIsZero (&result)) + return 0; + else if (decNumberIsNegative (&result)) + return -1; + else + return 1; +} + +/* Convert a decimal value from a decimal type with LEN_FROM bytes to a + decimal type with LEN_TO bytes. */ +void +decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to, + int len_to) +{ + decNumber number; + + decimal_to_number (from, len_from, &number); + decimal_from_number (&number, to, len_to); +} @@ -31,5 +31,14 @@ extern void decimal_to_string (const gdb_byte *, int, char *); extern int decimal_from_string (gdb_byte *, int, const char *); +extern void decimal_from_integral (struct value *from, gdb_byte *to, int len); +extern void decimal_from_floating (struct value *from, gdb_byte *to, int len); +extern DOUBLEST decimal_to_double (const gdb_byte *from, int len); +extern void decimal_binop (enum exp_opcode, const gdb_byte *, int, + const gdb_byte *, int, gdb_byte *, int *); +extern int decimal_is_zero (const gdb_byte *x, int len); +extern int decimal_compare (const gdb_byte *x, int len_x, const gdb_byte *y, int len_y); +extern void decimal_convert (const gdb_byte *from, int len_from, gdb_byte *to, + int len_to); #endif @@ -458,8 +458,8 @@ evaluate_subexp_standard (struct type *expect_type, case OP_DECFLOAT: (*pos) += 3; - return value_from_decfloat (expect_type, exp->elts[pc + 1].type, - exp->elts[pc + 2].decfloatconst); + return value_from_decfloat (exp->elts[pc + 1].type, + exp->elts[pc + 2].decfloatconst); case OP_VAR_VALUE: (*pos) += 3; diff --git a/gdb/valarith.c b/gdb/valarith.c index 1454196..05ab8a1 100644 --- a/gdb/valarith.c +++ b/gdb/valarith.c @@ -28,6 +28,7 @@ #include "language.h" #include "gdb_string.h" #include "doublest.h" +#include "dfp.h" #include <math.h> #include "infcall.h" @@ -741,6 +742,62 @@ value_concat (struct value *arg1, struct value *arg2) } +/* Obtain decimal value of arguments for binary operation, converting from + other types if one of them is not decimal floating point. */ +static void +value_args_as_decimal (struct value *arg1, struct value *arg2, + gdb_byte *x, int *len_x, gdb_byte *y, int *len_y) +{ + struct type *type1, *type2; + + type1 = check_typedef (value_type (arg1)); + type2 = check_typedef (value_type (arg2)); + + /* At least one of the arguments must be of decimal float type. */ + gdb_assert (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT + || TYPE_CODE (type2) == TYPE_CODE_DECFLOAT); + + if (TYPE_CODE (type1) == TYPE_CODE_FLT + || TYPE_CODE (type2) == TYPE_CODE_FLT) + /* The DFP extension to the C language does not allow mixing of + * decimal float types with other float types in expressions + * (see WDTR 24732, page 12). */ + error (_("Mixing decimal floating types with other floating types is not allowed.")); + + /* Obtain decimal value of arg1, converting from other types + if necessary. */ + + if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT) + { + *len_x = TYPE_LENGTH (type1); + memcpy (x, value_contents (arg1), *len_x); + } + else if (is_integral_type (type1)) + { + *len_x = TYPE_LENGTH (type2); + decimal_from_integral (arg1, x, *len_x); + } + else + error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1), + TYPE_NAME (type2)); + + /* Obtain decimal value of arg2, converting from other types + if necessary. */ + + if (TYPE_CODE (type2) == TYPE_CODE_DECFLOAT) + { + *len_y = TYPE_LENGTH (type2); + memcpy (y, value_contents (arg2), *len_y); + } + else if (is_integral_type (type2)) + { + *len_y = TYPE_LENGTH (type1); + decimal_from_integral (arg2, y, *len_y); + } + else + error (_("Don't know how to convert from %s to %s."), TYPE_NAME (type1), + TYPE_NAME (type2)); +} /* Perform a binary operation on two operands which have reasonable representations as integers or floats. This includes booleans, @@ -759,14 +816,55 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op) type1 = check_typedef (value_type (arg1)); type2 = check_typedef (value_type (arg2)); - if ((TYPE_CODE (type1) != TYPE_CODE_FLT && !is_integral_type (type1)) + if ((TYPE_CODE (type1) != TYPE_CODE_FLT + && TYPE_CODE (type1) != TYPE_CODE_DECFLOAT && !is_integral_type (type1)) || - (TYPE_CODE (type2) != TYPE_CODE_FLT && !is_integral_type (type2))) + (TYPE_CODE (type2) != TYPE_CODE_FLT + && TYPE_CODE (type2) != TYPE_CODE_DECFLOAT && !is_integral_type (type2))) error (_("Argument to arithmetic operation not a number or boolean.")); - if (TYPE_CODE (type1) == TYPE_CODE_FLT + if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT || - TYPE_CODE (type2) == TYPE_CODE_FLT) + TYPE_CODE (type2) == TYPE_CODE_DECFLOAT) + { + struct type *v_type; + int len_v1, len_v2, len_v; + gdb_byte v1[16], v2[16]; + gdb_byte v[16]; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + switch (op) + { + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + case BINOP_EXP: + decimal_binop (op, v1, len_v1, v2, len_v2, v, &len_v); + break; + + default: + error (_("Operation not valid for decimal floating point number.")); + } + + if (TYPE_CODE (type1) != TYPE_CODE_DECFLOAT) + /* If arg1 is not a decimal float, the type of the result is the type + of the decimal float argument, arg2. */ + v_type = type2; + else if (TYPE_CODE (type2) != TYPE_CODE_DECFLOAT) + /* Same logic, for the case where arg2 is not a decimal float. */ + v_type = type1; + else + /* len_v is equal either to len_v1 or to len_v2. the type of the + result is the type of the argument with the same length as v. */ + v_type = (len_v == len_v1)? type1 : type2; + + val = value_from_decfloat (v_type, v); + } + else if (TYPE_CODE (type1) == TYPE_CODE_FLT + || + TYPE_CODE (type2) == TYPE_CODE_FLT) { /* FIXME-if-picky-about-floating-accuracy: Should be doing this in target format. real.c in GCC probably has the necessary @@ -1177,6 +1275,8 @@ value_logical_not (struct value *arg1) if (TYPE_CODE (type1) == TYPE_CODE_FLT) return 0 == value_as_double (arg1); + else if (TYPE_CODE (type1) == TYPE_CODE_DECFLOAT) + return decimal_is_zero (value_contents (arg1), TYPE_LENGTH (type1)); len = TYPE_LENGTH (type1); p = value_contents (arg1); @@ -1255,6 +1355,16 @@ value_equal (struct value *arg1, struct value *arg2) DOUBLEST d = value_as_double (arg1); return d == value_as_double (arg2); } + else if ((code1 == TYPE_CODE_DECFLOAT || is_int1) + && (code2 == TYPE_CODE_DECFLOAT || is_int2)) + { + gdb_byte v1[16], v2[16]; + int len_v1, len_v2; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + return decimal_compare (v1, len_v1, v2, len_v2) == 0; + } /* FIXME: Need to promote to either CORE_ADDR or LONGEST, whichever is bigger. */ @@ -1319,6 +1429,16 @@ value_less (struct value *arg1, struct value *arg2) DOUBLEST d = value_as_double (arg1); return d < value_as_double (arg2); } + else if ((code1 == TYPE_CODE_DECFLOAT || is_int1) + && (code2 == TYPE_CODE_DECFLOAT || is_int2)) + { + gdb_byte v1[16], v2[16]; + int len_v1, len_v2; + + value_args_as_decimal (arg1, arg2, v1, &len_v1, v2, &len_v2); + + return decimal_compare (v1, len_v1, v2, len_v2) == -1; + } else if (code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_PTR) return value_as_address (arg1) < value_as_address (arg2); @@ -1350,6 +1470,8 @@ value_pos (struct value *arg1) if (TYPE_CODE (type) == TYPE_CODE_FLT) return value_from_double (type, value_as_double (arg1)); + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT) + return value_from_decfloat (type, value_contents (arg1)); else if (is_integral_type (type)) { /* Perform integral promotion for ANSI C/C++. FIXME: What about @@ -1382,7 +1504,7 @@ value_neg (struct value *arg1) int len = TYPE_LENGTH (type); gdb_byte decbytes[16]; /* a decfloat is at most 128 bits long */ - memcpy(decbytes, value_contents(arg1), len); + memcpy (decbytes, value_contents (arg1), len); if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE) decbytes[len-1] = decbytes[len - 1] | 0x80; diff --git a/gdb/valops.c b/gdb/valops.c index d7b49ea..bb4814f 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -36,6 +36,7 @@ #include "infcall.h" #include "dictionary.h" #include "cp-support.h" +#include "dfp.h" #include <errno.h> #include "gdb_string.h" @@ -338,7 +339,8 @@ value_cast (struct type *type, struct value *arg2) code2 = TYPE_CODE_INT; scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT - || code2 == TYPE_CODE_ENUM || code2 == TYPE_CODE_RANGE); + || code2 == TYPE_CODE_DECFLOAT || code2 == TYPE_CODE_ENUM + || code2 == TYPE_CODE_RANGE); if (code1 == TYPE_CODE_STRUCT && code2 == TYPE_CODE_STRUCT @@ -357,6 +359,22 @@ value_cast (struct type *type, struct value *arg2) } if (code1 == TYPE_CODE_FLT && scalar) return value_from_double (type, value_as_double (arg2)); + else if (code1 == TYPE_CODE_DECFLOAT && scalar) + { + int dec_len = TYPE_LENGTH (type); + gdb_byte dec[16]; + + if (code2 == TYPE_CODE_FLT) + decimal_from_floating (arg2, dec, dec_len); + else if (code2 == TYPE_CODE_DECFLOAT) + decimal_convert (value_contents (arg2), TYPE_LENGTH (type2), + dec, dec_len); + else + /* The only option left is an integral type. */ + decimal_from_integral (arg2, dec, dec_len); + + return value_from_decfloat (type, dec); + } else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM || code1 == TYPE_CODE_RANGE) && (scalar || code2 == TYPE_CODE_PTR diff --git a/gdb/value.c b/gdb/value.c index bb27625..5fc1276 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -982,6 +982,7 @@ value_as_double (struct value *val) error (_("Invalid floating value found in program.")); return foo; } + /* Extract a value as a C pointer. Does not deallocate the value. Note that val's type may not actually be a pointer; value_as_long handles all the cases. */ @@ -1127,6 +1128,11 @@ unpack_long (struct type *type, const gdb_byte *valaddr) case TYPE_CODE_FLT: return extract_typed_floating (valaddr, type); + case TYPE_CODE_DECFLOAT: + /* libdecnumber has a function to convert from decimal to integer, but + it doesn't work when the decimal number has a fractional part. */ + return decimal_to_double (valaddr, len); + case TYPE_CODE_PTR: case TYPE_CODE_REF: /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure @@ -1184,6 +1190,8 @@ unpack_double (struct type *type, const gdb_byte *valaddr, int *invp) return extract_typed_floating (valaddr, type); } + else if (code == TYPE_CODE_DECFLOAT) + return decimal_to_double (valaddr, len); else if (nosign) { /* Unsigned -- be sure we compensate for signed LONGEST. */ @@ -1643,23 +1651,12 @@ value_from_double (struct type *type, DOUBLEST num) } struct value * -value_from_decfloat (struct type *expect_type, struct type *type, - gdb_byte decbytes[16]) +value_from_decfloat (struct type *type, const gdb_byte *dec) { struct value *val = allocate_value (type); - int len = TYPE_LENGTH (type); - if (expect_type) - { - int expect_len = TYPE_LENGTH (expect_type); - char decstr[MAX_DECIMAL_STRING]; - int real_len; - - decimal_to_string (decbytes, len, decstr); - decimal_from_string (decbytes, expect_len, decstr); - } + memcpy (value_contents_raw (val), dec, TYPE_LENGTH (type)); - memcpy (value_contents_raw (val), decbytes, len); return val; } diff --git a/gdb/value.h b/gdb/value.h index d9627c2..7e1ccaf 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -280,9 +280,8 @@ extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num); extern struct value *value_from_longest (struct type *type, LONGEST num); extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr); extern struct value *value_from_double (struct type *type, DOUBLEST num); -extern struct value *value_from_decfloat (struct type *expect_type, - struct type *type, - gdb_byte decbytes[16]); +extern struct value *value_from_decfloat (struct type *type, + const gdb_byte *decbytes); extern struct value *value_from_string (char *string); extern struct value *value_at (struct type *type, CORE_ADDR addr); |