1 /* Common Linux target-dependent functionality for AArch64 MTE 2 3 Copyright (C) 2021-2023 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 void 25 aarch64_mte_pack_tags (gdb::byte_vector &tags) 26 { 27 /* Nothing to pack? */ 28 if (tags.empty ()) 29 return; 30 31 /* If the tags vector has an odd number of elements, add another 32 zeroed-out element to make it even. This facilitates packing. */ 33 if ((tags.size () % 2) != 0) 34 tags.emplace_back (0); 35 36 for (int unpacked = 0, packed = 0; unpacked < tags.size (); 37 unpacked += 2, packed++) 38 tags[packed] = (tags[unpacked + 1] << 4) | tags[unpacked]; 39 40 /* Now we have half the size. */ 41 tags.resize (tags.size () / 2); 42 } 43 44 /* See arch/aarch64-mte-linux.h */ 45 46 void 47 aarch64_mte_unpack_tags (gdb::byte_vector &tags, bool skip_first) 48 { 49 /* Nothing to unpack? */ 50 if (tags.empty ()) 51 return; 52 53 /* An unpacked MTE tags vector will have twice the number of elements 54 compared to an unpacked one. */ 55 gdb::byte_vector unpacked_tags (tags.size () * 2); 56 57 int unpacked = 0, packed = 0; 58 59 if (skip_first) 60 { 61 /* We are not interested in the first unpacked element, just discard 62 it. */ 63 unpacked_tags[unpacked] = (tags[packed] >> 4) & 0xf; 64 unpacked++; 65 packed++; 66 } 67 68 for (; packed < tags.size (); unpacked += 2, packed++) 69 { 70 unpacked_tags[unpacked] = tags[packed] & 0xf; 71 unpacked_tags[unpacked + 1] = (tags[packed] >> 4) & 0xf; 72 } 73 74 /* Update the original tags vector. */ 75 tags = std::move (unpacked_tags); 76 } 77 78 /* See arch/aarch64-mte-linux.h */ 79 80 size_t 81 aarch64_mte_get_tag_granules (CORE_ADDR addr, size_t len, size_t granule_size) 82 { 83 /* An empty range has 0 tag granules. */ 84 if (len == 0) 85 return 0; 86 87 /* Start address */ 88 CORE_ADDR s_addr = align_down (addr, granule_size); 89 /* End address */ 90 CORE_ADDR e_addr = align_down (addr + len - 1, granule_size); 91 92 /* We always have at least 1 granule because len is non-zero at this 93 point. */ 94 return 1 + (e_addr - s_addr) / granule_size; 95 } 96 97 /* See arch/aarch64-mte-linux.h */ 98 99 CORE_ADDR 100 aarch64_mte_make_ltag_bits (CORE_ADDR value) 101 { 102 return value & AARCH64_MTE_LOGICAL_MAX_VALUE; 103 } 104 105 /* See arch/aarch64-mte-linux.h */ 106 107 CORE_ADDR 108 aarch64_mte_make_ltag (CORE_ADDR value) 109 { 110 return (aarch64_mte_make_ltag_bits (value) 111 << AARCH64_MTE_LOGICAL_TAG_START_BIT); 112 } 113 114 /* See arch/aarch64-mte-linux.h */ 115 116 CORE_ADDR 117 aarch64_mte_set_ltag (CORE_ADDR address, CORE_ADDR tag) 118 { 119 /* Remove the existing tag. */ 120 address &= ~aarch64_mte_make_ltag (AARCH64_MTE_LOGICAL_MAX_VALUE); 121 122 /* Return the new tagged address. */ 123 return address | aarch64_mte_make_ltag (tag); 124 } 125 126 /* See arch/aarch64-mte-linux.h */ 127 128 CORE_ADDR 129 aarch64_mte_get_ltag (CORE_ADDR address) 130 { 131 CORE_ADDR ltag_addr = address >> AARCH64_MTE_LOGICAL_TAG_START_BIT; 132 return aarch64_mte_make_ltag_bits (ltag_addr); 133 } 134