GNU Binutils with patches for OS216
Révision | e5f4e60d4955ba94516ef91d86f0f429a2c12612 (tree) |
---|---|
l'heure | 2020-06-26 01:23:38 |
Auteur | Luis Machado <luis.machado@lina...> |
Commiter | Luis Machado |
AArch64: Implement memory tagging target methods for AArch64
The patch implements the memory tagging target hooks for AArch64, so we
can handle MTE.
gdb/ChangeLog:
YYYY-MM-DD Luis Machado <luis.machado@linaro.org>
* Makefile.in (ALL_64_TARGET_OBS): Add arch/aarch64-mte-linux.o.
(HFILES_NO_SRCDIR): Add arch/aarch64-mte-linux.h and
nat/aarch64-mte-linux-ptrace.h.
* aarch64-linux-nat.c: Include nat/aarch64-mte-linux-ptrace.h.
(aarch64_linux_nat_target) <supports_memory_tagging>: New method
override.
<fetch_memtags>: New method override.
<store_memtags>: New method override.
(aarch64_linux_nat_target::supports_memory_tagging): New method.
(aarch64_linux_nat_target::fetch_memtags): New method.
(aarch64_linux_nat_target::store_memtags): New method.
* arch/aarch64-mte-linux.c: New file.
* arch/aarch64-mte-linux.h: Include gdbsupport/common-defs.h.
(MTE_GRANULE_SIZE): Define.
(get_tag_granules): New prototype.
* configure.nat (NATDEPFILES): Add nat/aarch64-mte-linux-ptrace.o.
* configure.tgt (aarch64*-*-linux*): Add arch/aarch64-mte-linux.o.
* nat/aarch64-mte-linux-ptrace.c: New file.
* nat/aarch64-mte-linux-ptrace.h: New file.
@@ -680,6 +680,7 @@ ALL_64_TARGET_OBS = \ | ||
680 | 680 | amd64-windows-tdep.o \ |
681 | 681 | arch/aarch64.o \ |
682 | 682 | arch/aarch64-insn.o \ |
683 | + arch/aarch64-mte-linux.o \ | |
683 | 684 | arch/amd64.o \ |
684 | 685 | ia64-linux-tdep.o \ |
685 | 686 | ia64-tdep.o \ |
@@ -52,6 +52,8 @@ | ||
52 | 52 | |
53 | 53 | #include "arch/aarch64-mte-linux.h" |
54 | 54 | |
55 | +#include "nat/aarch64-mte-linux-ptrace.h" | |
56 | + | |
55 | 57 | #ifndef TRAP_HWBKPT |
56 | 58 | #define TRAP_HWBKPT 0x0004 |
57 | 59 | #endif |
@@ -102,6 +104,16 @@ public: | ||
102 | 104 | override; |
103 | 105 | |
104 | 106 | struct gdbarch *thread_architecture (ptid_t) override; |
107 | + | |
108 | + bool supports_memory_tagging () override; | |
109 | + | |
110 | + /* Read memory allocation tags from memory via PTRACE. */ | |
111 | + int fetch_memtags (CORE_ADDR address, size_t len, | |
112 | + gdb::byte_vector &tags) override; | |
113 | + | |
114 | + /* Write allocation tags to memory via PTRACE. */ | |
115 | + int store_memtags (CORE_ADDR address, size_t len, | |
116 | + const gdb::byte_vector &tags) override; | |
105 | 117 | }; |
106 | 118 | |
107 | 119 | static aarch64_linux_nat_target the_aarch64_linux_nat_target; |
@@ -1011,6 +1023,36 @@ aarch64_linux_nat_target::thread_architecture (ptid_t ptid) | ||
1011 | 1023 | return gdbarch_find_by_info (info); |
1012 | 1024 | } |
1013 | 1025 | |
1026 | +/* Implement the "supports_memory_tagging" target_ops method. */ | |
1027 | + | |
1028 | +bool | |
1029 | +aarch64_linux_nat_target::supports_memory_tagging () | |
1030 | +{ | |
1031 | + return (linux_get_hwcap2 (this) & HWCAP2_MTE) != 0; | |
1032 | +} | |
1033 | + | |
1034 | +/* Implement the "fetch_memtags" target_ops method. */ | |
1035 | + | |
1036 | +int | |
1037 | +aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len, | |
1038 | + gdb::byte_vector &tags) | |
1039 | +{ | |
1040 | + int tid = inferior_ptid.lwp (); | |
1041 | + | |
1042 | + return aarch64_mte_fetch_memtags (tid, address, len, tags); | |
1043 | +} | |
1044 | + | |
1045 | +/* Implement the "store_memtags" target_ops method. */ | |
1046 | + | |
1047 | +int | |
1048 | +aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len, | |
1049 | + const gdb::byte_vector &tags) | |
1050 | +{ | |
1051 | + int tid = inferior_ptid.lwp (); | |
1052 | + | |
1053 | + return aarch64_mte_store_memtags (tid, address, len, tags); | |
1054 | +} | |
1055 | + | |
1014 | 1056 | /* Define AArch64 maintenance commands. */ |
1015 | 1057 | |
1016 | 1058 | static void |
@@ -0,0 +1,34 @@ | ||
1 | +/* Common Linux target-dependent functionality for AArch64 MTE | |
2 | + | |
3 | + Copyright (C) 2020 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GDB. | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 3 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | + | |
20 | +#include "arch/aarch64-mte-linux.h" | |
21 | + | |
22 | +/* See arch/aarch64-mte-linux.h */ | |
23 | + | |
24 | +int | |
25 | +get_tag_granules (CORE_ADDR addr, size_t len, unsigned int granule_size) | |
26 | +{ | |
27 | + /* Start address */ | |
28 | + CORE_ADDR s_addr = align_down (addr, granule_size); | |
29 | + /* End address */ | |
30 | + CORE_ADDR e_addr = align_down (addr + len, granule_size); | |
31 | + | |
32 | + /* We always have at least 1 granule. */ | |
33 | + return 1 + (e_addr - s_addr) / granule_size; | |
34 | +} |
@@ -20,6 +20,8 @@ | ||
20 | 20 | #ifndef ARCH_AARCH64_LINUX_H |
21 | 21 | #define ARCH_AARCH64_LINUX_H |
22 | 22 | |
23 | +#include "gdbsupport/common-defs.h" | |
24 | + | |
23 | 25 | /* Feature check for Memory Tagging Extension. */ |
24 | 26 | #ifndef HWCAP2_MTE |
25 | 27 | #define HWCAP2_MTE (1 << 18) |
@@ -28,4 +30,12 @@ | ||
28 | 30 | /* The MTE regset consists of 2 registers of 64-bit size. */ |
29 | 31 | #define AARCH64_LINUX_SIZEOF_MTE (2 * 64) |
30 | 32 | |
33 | +/* We have one tag per 16 bytes of memory. */ | |
34 | +#define MTE_GRANULE_SIZE 16 | |
35 | + | |
36 | +/* Return the number of tag granules in the memory range | |
37 | + [ADDR, ADDR + LEN) given GRANULE_SIZE. */ | |
38 | +extern int get_tag_granules (CORE_ADDR addr, size_t len, | |
39 | + unsigned int granule_size); | |
40 | + | |
31 | 41 | #endif /* ARCH_AARCH64_LINUX_H */ |
@@ -236,7 +236,8 @@ case ${gdb_host} in | ||
236 | 236 | NATDEPFILES="${NATDEPFILES} aarch64-linux-nat.o \ |
237 | 237 | aarch32-linux-nat.o nat/aarch64-linux-hw-point.o \ |
238 | 238 | nat/aarch64-linux.o \ |
239 | - nat/aarch64-sve-linux-ptrace.o" | |
239 | + nat/aarch64-sve-linux-ptrace.o \ | |
240 | + nat/aarch64-mte-linux-ptrace.o" | |
240 | 241 | ;; |
241 | 242 | arm) |
242 | 243 | # Host: ARM based machine running GNU/Linux |
@@ -124,6 +124,7 @@ aarch64*-*-freebsd*) | ||
124 | 124 | aarch64*-*-linux*) |
125 | 125 | # Target: AArch64 linux |
126 | 126 | gdb_target_obs="aarch64-linux-tdep.o arch/aarch64.o\ |
127 | + arch/aarch64-mte-linux.o \ | |
127 | 128 | arch/arm.o arch/arm-linux.o arch/arm-get-next-pcs.o \ |
128 | 129 | arm-tdep.o arm-linux-tdep.o \ |
129 | 130 | glibc-tdep.o linux-tdep.o solib-svr4.o \ |
@@ -0,0 +1,195 @@ | ||
1 | +/* Common Linux native ptrace code for AArch64 MTE. | |
2 | + | |
3 | + Copyright (C) 2020 Free Software Foundation, Inc. | |
4 | + | |
5 | + This file is part of GDB. | |
6 | + | |
7 | + This program is free software; you can redistribute it and/or modify | |
8 | + it under the terms of the GNU General Public License as published by | |
9 | + the Free Software Foundation; either version 3 of the License, or | |
10 | + (at your option) any later version. | |
11 | + | |
12 | + This program is distributed in the hope that it will be useful, | |
13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + GNU General Public License for more details. | |
16 | + | |
17 | + You should have received a copy of the GNU General Public License | |
18 | + along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | + | |
20 | +#include "gdbsupport/common-defs.h" | |
21 | +#include "gdbsupport/byte-vector.h" | |
22 | + | |
23 | +#include "arch/aarch64.h" | |
24 | +#include "arch/aarch64-mte-linux.h" | |
25 | +#include "nat/aarch64-linux.h" | |
26 | +#include "nat/aarch64-mte-linux-ptrace.h" | |
27 | + | |
28 | +#include "linux-ptrace.h" | |
29 | +#include <sys/uio.h> | |
30 | + | |
31 | +/* Helper function to display various possible errors when reading | |
32 | + MTE tags. */ | |
33 | + | |
34 | +static void | |
35 | +aarch64_mte_linux_peek_error (int error) | |
36 | +{ | |
37 | + switch (error) | |
38 | + { | |
39 | + case EIO: | |
40 | + perror_with_name (_("PEEKMTETAGS not supported")); | |
41 | + break; | |
42 | + case EFAULT: | |
43 | + perror_with_name (_("Couldn't fetch allocation tags")); | |
44 | + break; | |
45 | + case EOPNOTSUPP: | |
46 | + perror_with_name (_("PROT_ME not enabled for requested address")); | |
47 | + default: | |
48 | + perror_with_name (_("Unknown MTE error")); | |
49 | + break; | |
50 | + } | |
51 | +} | |
52 | + | |
53 | +/* Helper function to display various possible errors when writing | |
54 | + MTE tags. */ | |
55 | + | |
56 | +static void | |
57 | +aarch64_mte_linux_poke_error (int error) | |
58 | +{ | |
59 | + switch (error) | |
60 | + { | |
61 | + case EIO: | |
62 | + perror_with_name (_("POKEMTETAGS not supported")); | |
63 | + break; | |
64 | + case EFAULT: | |
65 | + perror_with_name (_("Couldn't store allocation tags")); | |
66 | + break; | |
67 | + case EOPNOTSUPP: | |
68 | + perror_with_name (_("PROT_ME not enabled for requested address")); | |
69 | + default: | |
70 | + perror_with_name (_("Unknown MTE error")); | |
71 | + break; | |
72 | + } | |
73 | +} | |
74 | + | |
75 | +/* Helper to prepare a vector of tags to be passed on to the kernel. The | |
76 | + main purpose of this function is to optimize the number of calls to | |
77 | + ptrace if we're writing too many tags at once, like a pattern fill | |
78 | + request. | |
79 | + | |
80 | + Return a vector of tags of up to MAX_SIZE size, containing the tags that | |
81 | + must be passed on to the kernel. GRANULES is the number of tag granules to | |
82 | + be modified. */ | |
83 | + | |
84 | +static gdb::byte_vector | |
85 | +prepare_tag_vector (size_t granules, const gdb::byte_vector &tags, | |
86 | + size_t max_size) | |
87 | +{ | |
88 | + gdb::byte_vector t (0); | |
89 | + | |
90 | + if (granules == 0) | |
91 | + return t; | |
92 | + | |
93 | + gdb_assert (tags.size () > 0 && max_size > 0); | |
94 | + | |
95 | + if (granules > TAGS_MAX_SIZE) | |
96 | + t.resize (TAGS_MAX_SIZE); | |
97 | + else | |
98 | + t.resize (granules); | |
99 | + | |
100 | + size_t tag_count = tags.size (); | |
101 | + | |
102 | + for (size_t i = 0; i < t.size (); i++) | |
103 | + t[i] = tags[i % tag_count]; | |
104 | + | |
105 | + return t; | |
106 | +} | |
107 | + | |
108 | +/* See nat/aarch64-mte-linux-ptrace.h */ | |
109 | + | |
110 | +int | |
111 | +aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len, | |
112 | + gdb::byte_vector &tags) | |
113 | +{ | |
114 | + size_t ntags = get_tag_granules (address, len, MTE_GRANULE_SIZE); | |
115 | + gdb_byte tagbuf[ntags]; | |
116 | + | |
117 | + struct iovec iovec; | |
118 | + iovec.iov_base = tagbuf; | |
119 | + iovec.iov_len = ntags; | |
120 | + | |
121 | + tags.clear (); | |
122 | + bool done_reading = false; | |
123 | + | |
124 | + /* The kernel may return less tags than we requested. Loop until we've read | |
125 | + all the requested tags or until we get an error. */ | |
126 | + while (!done_reading) | |
127 | + { | |
128 | + /* Attempt to read ntags allocation tags from the kernel. */ | |
129 | + if (ptrace (PTRACE_PEEKMTETAGS, tid, address, &iovec) < 0) | |
130 | + aarch64_mte_linux_peek_error (errno); | |
131 | + | |
132 | + /* Make sure the kernel returned at least one tag. */ | |
133 | + if (iovec.iov_len <= 0) | |
134 | + { | |
135 | + tags.clear (); | |
136 | + return 1; | |
137 | + } | |
138 | + | |
139 | + /* Copy the tags the kernel returned. */ | |
140 | + for (size_t i = 0; i < iovec.iov_len; i++) | |
141 | + tags.push_back (tagbuf[i]); | |
142 | + | |
143 | + /* Are we done reading tags? */ | |
144 | + if (tags.size () == ntags) | |
145 | + done_reading = true; | |
146 | + else | |
147 | + { | |
148 | + address += iovec.iov_len * MTE_GRANULE_SIZE; | |
149 | + iovec.iov_len = ntags - iovec.iov_len; | |
150 | + } | |
151 | + } | |
152 | + return 0; | |
153 | +} | |
154 | + | |
155 | +/* See nat/aarch64-mte-linux-ptrace.h */ | |
156 | + | |
157 | +int | |
158 | +aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len, | |
159 | + const gdb::byte_vector &tags) | |
160 | +{ | |
161 | + if (tags.size () == 0) | |
162 | + return 0; | |
163 | + | |
164 | + /* Get the number of tags we need to write. */ | |
165 | + size_t ntags = get_tag_granules (address, len, MTE_GRANULE_SIZE); | |
166 | + | |
167 | + gdb::byte_vector t = prepare_tag_vector (ntags, tags, TAGS_MAX_SIZE); | |
168 | + gdb::byte_vector tags_left = tags; | |
169 | + | |
170 | + /* Write all the tags, TAGS_MAX_SIZE blocks at a time. */ | |
171 | + while (t.size () != 0) | |
172 | + { | |
173 | + struct iovec iovec; | |
174 | + iovec.iov_base = t.data (); | |
175 | + iovec.iov_len = t.size (); | |
176 | + | |
177 | + /* Request the kernel to update the allocation tags. */ | |
178 | + if (ptrace (PTRACE_POKEMTETAGS, tid, address, &iovec) < 0) | |
179 | + aarch64_mte_linux_poke_error (errno); | |
180 | + | |
181 | + /* Make sure the kernel wrote at least one tag. */ | |
182 | + if (iovec.iov_len <= 0) | |
183 | + return 1; | |
184 | + | |
185 | + /* Update the tag vector based on how many tags the kernel actually | |
186 | + wrote. */ | |
187 | + auto it = tags_left.begin (); | |
188 | + tags_left.erase (it, it + iovec.iov_len - 1); | |
189 | + address += iovec.iov_len * MTE_GRANULE_SIZE; | |
190 | + ntags -= iovec.iov_len; | |
191 | + t = prepare_tag_vector (ntags, tags_left, TAGS_MAX_SIZE); | |
192 | + } | |
193 | + | |
194 | + return 0; | |
195 | +} |
@@ -30,4 +30,21 @@ | ||
30 | 30 | #define PTRACE_POKEMTETAGS 34 |
31 | 31 | #endif |
32 | 32 | |
33 | +/* Maximum number of tags to pass at once to the kernel. */ | |
34 | +#define TAGS_MAX_SIZE 4096 | |
35 | + | |
36 | +/* Read the allocation tags from memory range [ADDRESS, ADDRESS + LEN) | |
37 | + into TAGS. | |
38 | + | |
39 | + Return 0 if successful and non-zero otherwise. */ | |
40 | +extern int aarch64_mte_fetch_memtags (int tid, CORE_ADDR address, size_t len, | |
41 | + gdb::byte_vector &tags); | |
42 | + | |
43 | +/* Write the TAGS allocation tags to the memory range | |
44 | + [ADDRESS, ADDRESS + LEN). | |
45 | + | |
46 | + Return 0 if successful and non-zero otherwise. */ | |
47 | +extern int aarch64_mte_store_memtags (int tid, CORE_ADDR address, size_t len, | |
48 | + const gdb::byte_vector &tags); | |
49 | + | |
33 | 50 | #endif /* NAT_AARCH64_MTE_LINUX_PTRACE_H */ |