From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29117 invoked by alias); 30 Sep 2014 07:39:19 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 29105 invoked by uid 89); 30 Sep 2014 07:39:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mga01.intel.com Received: from mga01.intel.com (HELO mga01.intel.com) (192.55.52.88) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 30 Sep 2014 07:39:16 +0000 Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga101.fm.intel.com with ESMTP; 30 Sep 2014 00:39:14 -0700 X-ExtLoop1: 1 Received: from irvmail001.ir.intel.com ([163.33.26.43]) by FMSMGA003.fm.intel.com with ESMTP; 30 Sep 2014 00:30:09 -0700 Received: from ulvlx001.iul.intel.com (ulvlx001.iul.intel.com [172.28.207.17]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id s8U7aPgP012613; Tue, 30 Sep 2014 08:36:25 +0100 Received: from ulvlx001.iul.intel.com (localhost [127.0.0.1]) by ulvlx001.iul.intel.com with ESMTP id s8U7aPvU024606; Tue, 30 Sep 2014 09:36:25 +0200 Received: (from wtedesch@localhost) by ulvlx001.iul.intel.com with œ id s8U7aP33024601; Tue, 30 Sep 2014 09:36:25 +0200 From: Walfred Tedeschi To: vladimir@codesourcery.com Cc: gdb-patches@sourceware.org, Walfred Tedeschi Subject: [PATCH] Add support for bound table in the Intel MPX context. Date: Tue, 30 Sep 2014 07:39:00 -0000 Message-Id: <1412062583-24571-1-git-send-email-walfred.tedeschi@intel.com> X-IsSubscribed: yes X-SW-Source: 2014-09/txt/msg00869.txt.bz2 In order to investigate the contents of the MPX boundary table two new commands are added to GDB. "mpx-info-bounds" and "mpx-set-bounds" are used to display and set values on the MPX bound table. 2014-08-12 Mircea Gherzan Walfred Tedeschi * i386-tdep.c (MPX_BASE_MASK, MPX_BD_MASK, MPX_BT_MASK, MPX_BD_MASK_32, MPX_BT_MASK_32): New macros. (i386_mpx_set_bounds): New function that implements the "mpx set-bounds" command. (i386_mpx_enabled) Helper function to test MPX availability. (i386_mpx_bd_base) Helper function to calculate the base directory address. (i386_mpx_get_bt_entry) Helper function to access a bound table entry. (i386_mpx_print_bounds) Effectively display bound information. (_initialize_i386_tdep): Add new commands to commands list. * NEWS: List new commands for MPX support. testsuite: * gdb.arch/i386-mpx-map.c: New file. * gdb.arch/i386-mpx-map.exp: New File. doc: * gdb.texinfo: Add documentation about "mpx-info-bounds" and "mpx-set-bounds" --- gdb/doc/gdb.texinfo | 10 ++ gdb/i386-tdep.c | 227 ++++++++++++++++++++++++++++++++ gdb/i386-tdep.h | 3 + gdb/testsuite/gdb.arch/i386-mpx-map.c | 86 ++++++++++++ gdb/testsuite/gdb.arch/i386-mpx-map.exp | 80 +++++++++++ 5 files changed, 406 insertions(+) create mode 100644 gdb/testsuite/gdb.arch/i386-mpx-map.c create mode 100644 gdb/testsuite/gdb.arch/i386-mpx-map.exp diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 026706a..62283c8 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21482,6 +21482,16 @@ be returned in a register. @kindex show struct-convention Show the current setting of the convention to return @code{struct}s from functions. + +@item mpx-info-bound @var{pointer storage} +@kindex mpx-info-bound +Displays the bounds of a pointer given its storage. + +@item mpx-set-bound @var{storage} @var{lbound} @var{ubound} +@kindex mpx-set-bound +Set the bounds of a pointer in the map given its storage. This command takes +three parameters @var{storage} is the pointers storage and @var{lbound} and +@var{ubound} are lower and upper bounds new values respectivelly. @end table @subsubsection Intel(R) @dfn{Memory Protection Extensions} (MPX). diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 1e68505..b92139d 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -8619,6 +8619,225 @@ i386_coff_osabi_sniffer (bfd *abfd) } +/* Show the MPX bounds for the given array/pointer. */ + +#define MPX_BASE_MASK (~(ULONGEST)0xfff) + +static unsigned long +i386_mpx_bd_base (void) +{ + struct regcache *rcache; + struct gdbarch_tdep *tdep; + ULONGEST ret; + enum register_status stat; + struct gdb_exception except; + + rcache = get_current_regcache (); + tdep = gdbarch_tdep (get_regcache_arch (rcache)); + + stat = regcache_raw_read_unsigned (rcache, tdep->bndcfgu_regnum, &ret); + + if (stat != REG_VALID) + error (_("BNDCFGU register invalid, read status %d."), stat); + + return ret & MPX_BASE_MASK; +} + +/* Check if the current target is MPX enabled. */ + +int +i386_mpx_enabled (void) +{ + const struct gdbarch_tdep *tdep = gdbarch_tdep (get_current_arch ()); + const struct target_desc *tdesc = tdep->tdesc; + + /* Try MPX registers. */ + return (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.mpx") != NULL); +} + +#define MPX_BD_MASK 0xfffffff00000ULL /* select bits [47:20] */ +#define MPX_BT_MASK 0x0000000ffff8 /* select bits [19:3] */ +#define MPX_BD_MASK_32 0xfffff000 /* select bits [31:12] */ +#define MPX_BT_MASK_32 0x00000ffc /* select bits [11:2] */ + +/* Pure pointer math for 64 bit address translation. */ +static CORE_ADDR +i386_mpx_get_bt_entry (CORE_ADDR ptr, CORE_ADDR bd_base) +{ + ULONGEST offset1; + ULONGEST offset2; + ULONGEST mpx_bd_mask, bd_ptr_r_shift, bd_ptr_l_shift; + ULONGEST bt_mask, bt_select_r_shift, bt_select_l_shift; + CORE_ADDR bd_entry_addr; + CORE_ADDR bt_addr; + CORE_ADDR bd_entry; + + struct gdbarch *gdbarch = get_current_arch (); + int ret = 0; + if (gdbarch_ptr_bit (gdbarch) == 64) + { + mpx_bd_mask = MPX_BD_MASK; + bd_ptr_r_shift = 20; + bd_ptr_l_shift = 3; + bt_select_r_shift = 3; + bt_select_l_shift = 5; + bt_mask = MPX_BT_MASK; + } + else + { + mpx_bd_mask = MPX_BD_MASK_32; + bd_ptr_r_shift = 12; + bd_ptr_l_shift = 2; + bt_select_r_shift = 2; + bt_select_l_shift = 4; + bt_mask = MPX_BT_MASK_32; + } + + offset1 = ((ptr & mpx_bd_mask) >> bd_ptr_r_shift) << bd_ptr_l_shift; + + bd_entry_addr = bd_base + offset1; + + ret = target_read_memory (bd_entry_addr, (gdb_byte *) &bd_entry, + sizeof (bd_entry)); + + if (ret) + error (_("Cannot read bounds directory entry at 0x%lx."), + (long) bd_entry_addr); + + if ((bd_entry & 0x1) == 0) + error (_("Invalid bounds directory entry at 0x%lx."), + (long) bd_entry_addr); + + bt_addr = bd_entry & ~bt_select_r_shift; + + offset2 = ((ptr & bt_mask) >> bt_select_r_shift) << bt_select_l_shift; + + return bt_addr + offset2; +} + + +static void +i386_mpx_print_bounds (const CORE_ADDR bt_entry[]) +{ + struct ui_out *uiout = current_uiout; + long long int size; + struct gdbarch *gdbarch = get_current_arch (); + CORE_ADDR onecompl = ~((CORE_ADDR) 0); + int bounds_in_map = ((~bt_entry[1] == 0 && bt_entry[0] == onecompl) ? 1 : 0); + + if (bounds_in_map == 1) + { + ui_out_text (uiout, "Null bounds on map:"); + ui_out_text (uiout, " pointer value = "); + ui_out_field_core_addr (uiout, "pointer-value", gdbarch, bt_entry[2]); + ui_out_text (uiout, "."); + ui_out_text (uiout, "\n"); + } + else + { + ui_out_text (uiout, "{lbound = "); + ui_out_field_core_addr (uiout, "lower-bound", gdbarch, bt_entry[0]); + ui_out_text (uiout, ", ubound = "); + + /* The upper bound is stored in 1's complement. */ + ui_out_field_core_addr (uiout, "upper-bound", gdbarch, ~bt_entry[1]); + ui_out_text (uiout, "}: pointer value = "); + ui_out_field_core_addr (uiout, "pointer-value", gdbarch, bt_entry[2]); + ui_out_text (uiout, ", size = "); + /* In case the bounds are 0x0 and 0xffff... the difference will be -1. + -1 represents in this sense full memory access, and there is no need + one to the size. */ + size = ((long long int) ~bt_entry[1] - (long long int) bt_entry[0]); + size = (size > -1 ? size + 1 : size); + ui_out_field_fmt (uiout, "size", "%lld", size); + + ui_out_text (uiout, ", metadata = "); + ui_out_field_core_addr (uiout, "metadata", gdbarch, bt_entry[3]); + ui_out_text (uiout, "\n"); + } +} + +static void +i386_mpx_info_bounds (char *args, int from_tty) +{ + CORE_ADDR bd_base = 0; + CORE_ADDR addr; + CORE_ADDR bt_entry_addr = 0; + CORE_ADDR bt_entry[4]; + int ret; + + if (!i386_mpx_enabled ()) + error (_("MPX not supported on this target.")); + + if (!args) + error (_("Address of pointer variable expected.")); + + addr = parse_and_eval_address (args); + + bd_base = i386_mpx_bd_base (); + bt_entry_addr = i386_mpx_get_bt_entry (addr, bd_base); + + ret = target_read_memory (bt_entry_addr, (gdb_byte *) bt_entry, + sizeof (bt_entry)); + if (ret) + error (_("Cannot read bounds table entry at %lx."), bt_entry_addr); + + i386_mpx_print_bounds (bt_entry); +} + +static void +i386_mpx_set_bounds (char *args, int from_tty) +{ + CORE_ADDR bd_base = 0; + CORE_ADDR addr, lower, upper; + CORE_ADDR bt_entry_addr = 0; + CORE_ADDR bt_entry[4]; + int ret; + char *addr_str, *lower_str, *upper_str, *tmp; + + if (!i386_mpx_enabled ()) + error ("MPX not supported on this target."); + + if (!args) + error ("Address of pointer variable expected."); + + addr_str = strtok (args, " "); + if (!addr_str) + error ("Missing address of the pointer in the command."); + + lower_str = strtok (NULL, " "); + if (!lower_str) + error ("Missing lower bound in the command."); + + upper_str = strtok (NULL, " "); + if (!upper_str) + error ("Missing upper bound in the command."); + + addr = parse_and_eval_address (addr_str); + lower = parse_and_eval_address (lower_str); + upper = parse_and_eval_address (upper_str); + + bd_base = i386_mpx_bd_base (); + bt_entry_addr = i386_mpx_get_bt_entry (addr, bd_base); + + ret = target_read_memory (bt_entry_addr, (gdb_byte *) bt_entry, + sizeof (bt_entry)); + if (ret) + error ("Cannot read bounds table entry at 0x%lx", (long) bt_entry_addr); + + bt_entry[0] = (uint64_t) lower; + bt_entry[1] = ~(uint64_t) upper; + + ret = target_write_memory (bt_entry_addr, (gdb_byte *) bt_entry, + sizeof (bt_entry)); + + if (ret) + error ("Cannot write bounds table entry at 0x%lx", (long) bt_entry_addr); + else + i386_mpx_print_bounds (bt_entry); +} + + /* Provide a prototype to silence -Wmissing-prototypes. */ void _initialize_i386_tdep (void); @@ -8649,6 +8868,14 @@ is \"default\"."), NULL, /* FIXME: i18n: */ &setlist, &showlist); + add_cmd ("mpx-info-bounds", no_class, i386_mpx_info_bounds, + "show the memory bounds for a given array/pointer storage.", + &cmdlist); + + add_cmd ("mpx-set-bounds", no_class, i386_mpx_set_bounds, + "set the memory bounds for a given array/pointer storage", + &cmdlist); + gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour, i386_coff_osabi_sniffer); diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h index e0950a3..42da850 100644 --- a/gdb/i386-tdep.h +++ b/gdb/i386-tdep.h @@ -434,4 +434,7 @@ extern int i386_stap_is_single_operand (struct gdbarch *gdbarch, extern int i386_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p); +int +i386_mpx_enabled (void); + #endif /* i386-tdep.h */ diff --git a/gdb/testsuite/gdb.arch/i386-mpx-map.c b/gdb/testsuite/gdb.arch/i386-mpx-map.c new file mode 100644 index 0000000..441131a --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-mpx-map.c @@ -0,0 +1,86 @@ +/* Test program for MPX map allocated bounds. + + Copyright 2014 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 3 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, see . */ + +#include +#include + +#include "x86-cpuid.h" + +#ifndef NOINLINE +#define NOINLINE __attribute__ ((noinline)) +#endif + +#define SIZE 5 + +typedef int T; + +unsigned int have_mpx (void) NOINLINE; + +unsigned int NOINLINE +have_mpx (void) +{ + unsigned int eax, ebx, ecx, edx; + + if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) + return 0; + + if ((ecx & bit_OSXSAVE) == bit_OSXSAVE) + { + if (__get_cpuid_max (0, NULL) < 7) + return 0; + + __cpuid_count (7, 0, eax, ebx, ecx, edx); + + if ((ebx & bit_MPX) == bit_MPX) + return 1; + else + return 0; + } + return 0; +} + +void +foo (T * p) +{ + T *x; +#if defined __GNUC__ && !defined __INTEL_COMPILER + __bnd_store_ptr_bounds (p, &p); +#endif + x = p + SIZE - 1; +#if defined __GNUC__ && !defined __INTEL_COMPILER + __bnd_store_ptr_bounds (x, &x); +#endif + return; /* after-assign */ +} + +int +main (void) +{ + if (have_mpx ()) + { + T *a = NULL; + a = calloc (SIZE, sizeof (T)); /* after-decl */ +#if defined __GNUC__ && !defined __INTEL_COMPILER + __bnd_store_ptr_bounds (a, &a); +#endif + foo (a); /* after-alloc */ + free (a); + } + return 0; +} diff --git a/gdb/testsuite/gdb.arch/i386-mpx-map.exp b/gdb/testsuite/gdb.arch/i386-mpx-map.exp new file mode 100644 index 0000000..539e1dd --- /dev/null +++ b/gdb/testsuite/gdb.arch/i386-mpx-map.exp @@ -0,0 +1,80 @@ +# Copyright 2014 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. , +# +# +# 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 3 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, see . + +if { ![istarget i?86-*-*] && ![istarget x86_64-*-* ] } { + verbose "Skipping x86 MPX tests." + return +} + +standard_testfile + +set comp_flags "-fmpx -I${srcdir}/../nat/" + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} \ + [list debug nowarnings additional_flags=${comp_flags}]] } { + return -1 +} + +if ![runto_main] { + untested "could not run to main" + return -1 +} + +set supports_mpx 0 +set test "probe MPX support" +send_gdb "print have_mpx ()\r" + +gdb_test_multiple "print have_mpx()" $test { + -re ".. = 1\r\n$gdb_prompt $" { + pass $test + set supports_mpx 1 + } + -re ".. = 0\r\n$gdb_prompt $" { + pass $test + } +} + +if { !$supports_mpx } { + unsupported "processor does not support MPX" + return +} + +gdb_breakpoint [ gdb_get_line_number "after-decl" ] +gdb_breakpoint [ gdb_get_line_number "after-alloc" ] +gdb_breakpoint [ gdb_get_line_number "after-assign" ] + +gdb_test "mpx-info-bounds 0x0" "Invalid bounds directory entry at 0x\[0-9a-fA-F\]+." "NULL address of the pointer" + +gdb_continue_to_breakpoint "after-decl" ".*after-decl.*" +#gdb_test "mpx-info-bounds a" "Invalid bounds directory entry at 0x\[0-9a-fA-F\]+." "pointer instead of pointer address" +# Fix size + +gdb_test "mpx-info-bounds &a" "Null bounds on map: pointer value = 0x0+." "address of a NULL pointer" + +gdb_continue_to_breakpoint "after-alloc" ".*after-alloc.*" +gdb_test "mpx-info-bounds &a" "Null bounds on map: pointer value = 0x\[0-9a-fA-F\]+." "pointer after allocation" + +# +gdb_continue_to_breakpoint "after-assign" ".*after-assign.*" +gdb_test "mpx-info-bounds &x" "\\\{lbound = 0x\[0-9a-fA-F\]+, ubound = 0x\[0-9a-fA-F\]+\\\}: pointer value = 0x\[0-9a-fA-F\]+, size = -1, metadata = 0x0+." "pointer after assignment" +gdb_test "mpx-set-bounds 0x0 0x1 0x2" "Invalid bounds directory entry at 0x\[0-9a-fA-F\]+." "mpx-set-bounds: NULL address of the pointer" +# +gdb_test "mpx-set-bounds &x 0xcafebabe 0xdeadbeef" " +\\\{lbound = 0x0*cafebabe, ubound = 0x0*deadbeef\\\}: pointer value = 0x\[0-9a-fA-F\]+, size = 330236978, metadata = 0x0+." "mpx-set-bounds: set bounds for a valid pointer address" +# +gdb_test "mpx-info-bounds &x" "\\\{lbound = 0x0*cafebabe, ubound = 0x0*deadbeef\\\}: pointer value = 0x\[0-9a-fA-F\]+, size = 330236978, metadata = 0x0+." "mpx-set-bounds: bounds map entry after mpx-set-bounds" -- 1.9.1