guile: fix make-value with pointer type

Calling the `make-value' procedure with an integer value and a pointer
type for the #:type argument triggers a failed assertion in
`get_unsigned_type_max', as that function doesn't consider pointers to
be an unsigned type. This commit fixes the issue by adding a separate
code path for pointers.

As previously suggested, range checking is done using a new helper
function in gdbtypes.

gdb/ChangeLog:

2021-07-30  George Barrett  <bob@bob131.so>

	* gdbtypes.h (get_pointer_type_max): Add declaration.
	* gdbtypes.c (get_pointer_type_max): Add definition for new
	helper function.
	* guile/scm-math.c (vlscm_convert_typed_number): Add code path
	for handling conversions to pointer types without failing an
	assert.

gdb/testsuite/ChangeLog:

2021-07-30  George Barrett  <bob@bob131.so>

	* gdb.guile/scm-math.exp (test_value_numeric_ops): Add test
	for creating pointers with make-value.
	(test_make_pointer_value, test_pointer_numeric_range): Add
	test procedures containing checks for integer-to-pointer
	validation.

Change-Id: I9994dd1c848840a3d995f745e6d72867732049f0
This commit is contained in:
George Barrett
2021-07-30 01:12:18 +10:00
committed by Simon Marchi
parent c3c1e6459f
commit b5b591a865
4 changed files with 71 additions and 2 deletions

View File

@ -1924,6 +1924,21 @@ get_signed_type_minmax (struct type *type, LONGEST *min, LONGEST *max)
*max = ((ULONGEST) 1 << (n - 1)) - 1; *max = ((ULONGEST) 1 << (n - 1)) - 1;
} }
/* Return the largest value representable by pointer type TYPE. */
CORE_ADDR
get_pointer_type_max (struct type *type)
{
unsigned int n;
type = check_typedef (type);
gdb_assert (type->code () == TYPE_CODE_PTR);
gdb_assert (TYPE_LENGTH (type) <= sizeof (CORE_ADDR));
n = TYPE_LENGTH (type) * TARGET_CHAR_BIT;
return ((((CORE_ADDR) 1 << (n - 1)) - 1) << 1) | 1;
}
/* Internal routine called by TYPE_VPTR_FIELDNO to return the value of /* Internal routine called by TYPE_VPTR_FIELDNO to return the value of
cplus_stuff.vptr_fieldno. cplus_stuff.vptr_fieldno.

View File

@ -2523,6 +2523,8 @@ extern ULONGEST get_unsigned_type_max (struct type *);
extern void get_signed_type_minmax (struct type *, LONGEST *, LONGEST *); extern void get_signed_type_minmax (struct type *, LONGEST *, LONGEST *);
extern CORE_ADDR get_pointer_type_max (struct type *);
/* * Resolve all dynamic values of a type e.g. array bounds to static values. /* * Resolve all dynamic values of a type e.g. array bounds to static values.
ADDR specifies the location of the variable the type is bound to. ADDR specifies the location of the variable the type is bound to.
If TYPE has no dynamic properties return TYPE; otherwise a new type with If TYPE has no dynamic properties return TYPE; otherwise a new type with

View File

@ -524,8 +524,7 @@ vlscm_convert_typed_number (const char *func_name, int obj_arg_pos, SCM obj,
int type_arg_pos, SCM type_scm, struct type *type, int type_arg_pos, SCM type_scm, struct type *type,
struct gdbarch *gdbarch, SCM *except_scmp) struct gdbarch *gdbarch, SCM *except_scmp)
{ {
if (is_integral_type (type) if (is_integral_type (type))
|| type->code () == TYPE_CODE_PTR)
{ {
if (type->is_unsigned ()) if (type->is_unsigned ())
{ {
@ -556,6 +555,19 @@ vlscm_convert_typed_number (const char *func_name, int obj_arg_pos, SCM obj,
return value_from_longest (type, gdbscm_scm_to_longest (obj)); return value_from_longest (type, gdbscm_scm_to_longest (obj));
} }
} }
else if (type->code () == TYPE_CODE_PTR)
{
CORE_ADDR max = get_pointer_type_max (type);
if (!scm_is_unsigned_integer (obj, 0, max))
{
*except_scmp
= gdbscm_make_out_of_range_error (func_name,
obj_arg_pos, obj,
_("value out of range for type"));
return NULL;
}
return value_from_pointer (type, gdbscm_scm_to_ulongest (obj));
}
else if (type->code () == TYPE_CODE_FLT) else if (type->code () == TYPE_CODE_FLT)
return value_from_host_double (type, scm_to_double (obj)); return value_from_host_double (type, scm_to_double (obj));
else else

View File

@ -137,6 +137,15 @@ proc test_value_numeric_ops {} {
gdb_test "gu (print (value-sub b a))" \ gdb_test "gu (print (value-sub b a))" \
"= 3" "subtract two pointer values" "= 3" "subtract two pointer values"
# Test pointer creation.
gdb_test_no_output "gu (define void-pointer-type (type-pointer (arch-void-type (current-arch))))"
gdb_scm_test_silent_cmd "gu (define null-pointer (make-value 0 #:type void-pointer-type))" \
"test make-value with pointer type"
gdb_test "gu (print null-pointer)" "= 0x0"
gdb_test "gu (print (equal? (value-type null-pointer) void-pointer-type))" \
"= #t"
# Test some invalid operations. # Test some invalid operations.
gdb_test_multiple "gu (print (value-add i '()))" "catch error in guile type conversion" { gdb_test_multiple "gu (print (value-add i '()))" "catch error in guile type conversion" {
@ -237,6 +246,36 @@ proc test_value_numeric_ranges {} {
} }
} }
# Helper routine for test_pointer_numeric_range.
proc test_make_pointer_value { size } {
set max [get_max_uint $size]
set max_hex [string repeat "f" [expr "$size / 4"]]
gdb_test "gu (print (make-value $max #:type void-pointer-type))" \
"= 0x$max_hex" "test make-value void* max"
gdb_test "gu (print (make-value 0 #:type void-pointer-type))" \
"= 0x0" "test make-value void* 0"
gdb_test "gu (print (make-value (+ $max 1) #:type void-pointer-type))" \
"ERROR.*Out of range.*" "test make-value void* max+1"
gdb_test "gu (print (make-value -1 #:type void-pointer-type))" \
"ERROR.*Out of range.*" "test make-value void* -1"
}
proc test_pointer_numeric_range {} {
# We can't assume anything about sizeof (void*) on the target.
# Keep it simple for now, this will cover everything important for
# the major targets.
set pointer_size [get_sizeof "void*" 0]
if { $pointer_size == 4 } {
test_make_pointer_value 32
}
if { $pointer_size == 8 } {
test_make_pointer_value 64
}
}
proc test_value_boolean {} { proc test_value_boolean {} {
# Note: Boolean values print as 0,1 because they are printed in the # Note: Boolean values print as 0,1 because they are printed in the
# current language (in this case C). # current language (in this case C).
@ -305,5 +344,6 @@ if ![gdb_guile_runto_main] {
test_value_numeric_ops test_value_numeric_ops
test_value_numeric_ranges test_value_numeric_ranges
test_pointer_numeric_range
test_value_boolean test_value_boolean
test_value_compare test_value_compare