[PATCH V3 1/2] ABI changes for MPX.

Walfred Tedeschi
2016-01-13T12:40:20Z

Code reflects what is presented in the ABI document:
https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
Here new class POINTER was added. GDB code is modified to mirror
this new class. (page 134)

In addition to that set bound registers to INIT state (access to
all memory) before performing the inferior function call.

2016-01-13 Walfred Tedeschi <walfred.tedeschi@intel.com>

* amd64-tdep.c (amd64_reg_class): Add new class AMD64_POINTER.
(amd64_merge_classes): Add AMD64_POINTER to merging classes rules.
(amd64_classify): Add AMD64_POINTER.
(amd64_return_value): Add AMD64_POINTER.
(amd64_push_arguments): Add new AMD64_POINTER class.
(amd64_push_dummy_call): Set bound registers to INIT state before
performing the call.

gdb/doc/ChangeLog:

* gdb.texinfo (Intel Memory Protection Extension): Add entry for
inferior function calls for MPX.

---
gdb/amd64-tdep.c | 44 +++++++++++++++++++++++++++++++++++---------
gdb/doc/gdb.texinfo | 8 ++++++++
2 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 6096ce9..732e91b 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -461,6 +461,7 @@ amd64_pseudo_register_write (struct gdbarch *gdbarch,

enum amd64_reg_class
{
+ AMD64_POINTER,
AMD64_INTEGER,
AMD64_SSE,
AMD64_SSEUP,
@@ -492,18 +493,22 @@ amd64_merge_classes (enum amd64_reg_class class1, enum amd64_reg_class class2)
if (class1 == AMD64_MEMORY || class2 == AMD64_MEMORY)
return AMD64_MEMORY;

- /* Rule (d): If one of the classes is INTEGER, the result is INTEGER. */
+ /* Rule (d): If one of the classes is POINTER, the result is POINTER. */
+ if (class1 == AMD64_POINTER || class2 == AMD64_POINTER)
+ return AMD64_POINTER;
+
+ /* Rule (e): If one of the classes is INTEGER, the result is INTEGER. */
if (class1 == AMD64_INTEGER || class2 == AMD64_INTEGER)
return AMD64_INTEGER;

- /* Rule (e): If one of the classes is X87, X87UP, COMPLEX_X87 class,
+ /* Rule (f): If one of the classes is X87, X87UP, COMPLEX_X87 class,
MEMORY is used as class. */
if (class1 == AMD64_X87 || class1 == AMD64_X87UP
|| class1 == AMD64_COMPLEX_X87 || class2 == AMD64_X87
|| class2 == AMD64_X87UP || class2 == AMD64_COMPLEX_X87)
return AMD64_MEMORY;

- /* Rule (f): Otherwise class SSE is used. */
+ /* Rule (g): Otherwise class SSE is used. */
return AMD64_SSE;
}

@@ -636,14 +641,17 @@ amd64_classify (struct type *type, enum amd64_reg_class theclass[2])

theclass[0] = theclass[1] = AMD64_NO_CLASS;

+ /* Pointer and reference are of the POINTER class. */
+ if (code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
+ theclass[0] = AMD64_POINTER;
+
/* Arguments of types (signed and unsigned) _Bool, char, short, int,
long, long long, and pointers are in the INTEGER class. Similarly,
range types, used by languages such as Ada, are also in the INTEGER
class. */
- if ((code == TYPE_CODE_INT || code == TYPE_CODE_ENUM
+ else if ((code == TYPE_CODE_INT || code == TYPE_CODE_ENUM
|| code == TYPE_CODE_BOOL || code == TYPE_CODE_RANGE
- || code == TYPE_CODE_CHAR
- || code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
+ || code == TYPE_CODE_CHAR)
&& (len == 1 || len == 2 || len == 4 || len == 8))
theclass[0] = AMD64_INTEGER;

@@ -693,6 +701,7 @@ amd64_classify (struct type *type, enum amd64_reg_class theclass[2])
amd64_classify_aggregate (type, theclass);
}

+
static enum return_value_convention
amd64_return_value (struct gdbarch *gdbarch, struct value *function,
struct type *type, struct regcache *regcache,
@@ -770,8 +779,9 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
switch (theclass[i])
{
case AMD64_INTEGER:
- /* 3. If the class is INTEGER, the next available register
- of the sequence %rax, %rdx is used. */
+ case AMD64_POINTER:
+ /* 3. If the class is INTEGER or POINTER, the next available
+ register of the sequence %rax, %rdx is used. */
regnum = integer_regnum[integer_reg++];
break;

@@ -876,7 +886,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
this argument. */
for (j = 0; j < 2; j++)
{
- if (theclass[j] == AMD64_INTEGER)
+ if (theclass[j] == AMD64_INTEGER || theclass[j] == AMD64_POINTER)
needed_integer_regs++;
else if (theclass[j] == AMD64_SSE)
needed_sse_regs++;
@@ -907,6 +917,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs,

switch (theclass[j])
{
+ case AMD64_POINTER:
case AMD64_INTEGER:
regnum = integer_regnum[integer_reg++];
break;
@@ -966,8 +977,23 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
int struct_return, CORE_ADDR struct_addr)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_byte buf[8];

+ /* When MPX is enabled, all bnd registers have to be initialized
+ before the call. This avoids an undesired bound violation
+ during the function's execution. */
+
+ if (I387_BND0R_REGNUM (tdep) > 0)
+ {
+ gdb_byte bnd_buf[16];
+ int i;
+
+ memset (bnd_buf, 0, 16);
+ for (i = 0; i < I387_BND0R_REGNUM (tdep); i++)
+ regcache_raw_write (regcache, I387_BND0R_REGNUM (tdep) + i, bnd_buf);
+ }
+
/* Pass arguments. */
sp = amd64_push_arguments (regcache, nargs, args, sp, struct_return);

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b82f3c6..ccde84a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22064,6 +22064,14 @@ whose bounds are to be changed, @var{lbound} and @var{ubound} are new values
for lower and upper bounds respectively.
@end table

+While calling functions from the debugger, of an Intel MPX enabled program,
+boundary registers have to be set to the INIT state before performing the
+call, to avoid boundary violations while performing the call. A bound is
+defined to be in the INIT state when the pointer associated to that boundary
+can access the whole memory, in this case the register bound register
+associated to it has value 0, e.g. if the register associated is bnd0raw
+its value will be @{0x0, 0x0@}.
+
@node Alpha
@subsection Alpha

--
2.1.4