1 /* Copyright 2013-2023 Free Software Foundation, Inc. 2 3 This file is part of GDB. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include <errno.h> 19 #include <stdarg.h> 20 #include <stdint.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 24 typedef struct 25 { 26 unsigned char e_ident[16]; 27 uint16_t e_type; 28 uint16_t e_machine; 29 uint32_t e_version; 30 uint32_t e_entry; 31 uint32_t e_phoff; 32 uint32_t e_shoff; 33 uint32_t e_flags; 34 uint16_t e_ehsize; 35 uint16_t e_phentsize; 36 uint16_t e_phnum; 37 uint16_t e_shentsize; 38 uint16_t e_shnum; 39 uint16_t e_shstrndx; 40 } Elf32_Ehdr; 41 42 typedef struct 43 { 44 unsigned char e_ident[16]; 45 uint16_t e_type; 46 uint16_t e_machine; 47 uint32_t e_version; 48 uint64_t e_entry; 49 uint64_t e_phoff; 50 uint64_t e_shoff; 51 uint32_t e_flags; 52 uint16_t e_ehsize; 53 uint16_t e_phentsize; 54 uint16_t e_phnum; 55 uint16_t e_shentsize; 56 uint16_t e_shnum; 57 uint16_t e_shstrndx; 58 } Elf64_Ehdr; 59 60 typedef struct 61 { 62 uint32_t p_type; 63 uint32_t p_offset; 64 uint32_t p_vaddr; 65 uint32_t p_paddr; 66 uint32_t p_filesz; 67 uint32_t p_memsz; 68 uint32_t p_flags; 69 uint32_t p_align; 70 } Elf32_Phdr; 71 72 typedef struct 73 { 74 uint32_t p_type; 75 uint32_t p_flags; 76 uint64_t p_offset; 77 uint64_t p_vaddr; 78 uint64_t p_paddr; 79 uint64_t p_filesz; 80 uint64_t p_memsz; 81 uint64_t p_align; 82 } Elf64_Phdr; 83 84 struct elfbuf 85 { 86 const char *path; 87 unsigned char *buf; 88 size_t len; 89 enum { ELFCLASS32 = 1, 90 ELFCLASS64 = 2 } ei_class; 91 }; 92 93 #define ELFBUF_EHDR_LEN(elf) \ 94 ((elf)->ei_class == ELFCLASS32 ? sizeof (Elf32_Ehdr) : \ 95 sizeof (Elf64_Ehdr)) 96 97 #define ELFBUF_EHDR(elf, memb) \ 98 ((elf)->ei_class == ELFCLASS32 ? \ 99 ((Elf32_Ehdr *) (elf)->buf)->memb \ 100 : ((Elf64_Ehdr *) (elf)->buf)->memb) 101 102 #define ELFBUF_PHDR_LEN(elf) \ 103 ((elf)->ei_class == ELFCLASS32 ? sizeof (Elf32_Phdr) : \ 104 sizeof (Elf64_Phdr)) 105 106 #define ELFBUF_PHDR(elf, idx, memb) \ 107 ((elf)->ei_class == ELFCLASS32 ? \ 108 ((Elf32_Phdr *) &(elf)->buf[((Elf32_Ehdr *)(elf)->buf) \ 109 ->e_phoff])[idx].memb \ 110 : ((Elf64_Phdr *) &(elf)->buf[((Elf64_Ehdr *)(elf)->buf) \ 111 ->e_phoff])[idx].memb) 112 113 static void 114 exit_with_msg(const char *fmt, ...) 115 { 116 va_list ap; 117 118 fflush (stdout); 119 va_start (ap, fmt); 120 vfprintf (stderr, fmt, ap); 121 va_end (ap); 122 123 if (errno) 124 { 125 fputs (": ", stderr); 126 perror (NULL); 127 } 128 else 129 fputc ('\n', stderr); 130 exit (1); 131 } 132 133 static void 134 read_file (unsigned char **buf_ptr, size_t *len_ptr, FILE *fp) 135 { 136 size_t len = 0; 137 size_t size = 1024; 138 size_t chunk; 139 unsigned char *buf = malloc (size); 140 141 while ((chunk = fread (buf + len, 1, size - len, fp)) == size - len) 142 { 143 len = size; 144 size *= 2; 145 buf = realloc (buf, size); 146 } 147 len += chunk; 148 *buf_ptr = buf; 149 *len_ptr = len; 150 } 151 152 static void 153 write_file (unsigned char *buf, size_t len, FILE *fp) 154 { 155 fwrite (buf, 1, len, fp); 156 } 157 158 static void 159 elfbuf_init_from_file (struct elfbuf *elf, const char *path) 160 { 161 FILE *fp = fopen (path, "rb"); 162 unsigned char *buf; 163 size_t len; 164 165 if (fp == NULL) 166 exit_with_msg ("%s", path); 167 168 read_file (&buf, &len, fp); 169 fclose (fp); 170 171 /* Validate ELF identification. */ 172 if (len < 16 173 || buf[0] != 0x7f || buf[1] != 0x45 || buf[2] != 0x4c || buf[3] != 0x46 174 || buf[4] < 1 || buf[4] > 2 || buf[5] < 1 || buf[5] > 2) 175 exit_with_msg ("%s: unsupported or invalid ELF file", path); 176 177 elf->path = path; 178 elf->buf = buf; 179 elf->len = len; 180 elf->ei_class = buf[4]; 181 182 if (ELFBUF_EHDR_LEN (elf) > len 183 || ELFBUF_EHDR (elf, e_phoff) > len 184 || ELFBUF_EHDR (elf, e_phnum) > ((len - ELFBUF_EHDR (elf, e_phoff)) 185 / ELFBUF_PHDR_LEN (elf)) ) 186 exit_with_msg ("%s: unexpected end of data", path); 187 188 if (ELFBUF_EHDR (elf, e_phentsize) != ELFBUF_PHDR_LEN (elf)) 189 exit_with_msg ("%s: inconsistent ELF header", path); 190 } 191 192 static void 193 elfbuf_write_to_file (struct elfbuf *elf, const char *path) 194 { 195 FILE *fp = fopen (path, "wb"); 196 197 if (fp == NULL) 198 exit_with_msg ("%s", path); 199 200 write_file (elf->buf, elf->len, fp); 201 fclose (fp); 202 } 203 204 /* In the auxv note starting at OFFSET with size LEN, mask the hwcap 205 field using the HWCAP_MASK. */ 206 207 static void 208 elfbuf_handle_auxv (struct elfbuf *elf, size_t offset, size_t len, 209 unsigned long hwcap_mask) 210 { 211 size_t i; 212 uint32_t *auxv32 = (uint32_t *) (elf->buf + offset); 213 uint64_t *auxv64 = (uint64_t *) auxv32; 214 size_t entry_size = elf->ei_class == ELFCLASS32 ? 215 sizeof (auxv32[0]) : sizeof (auxv64[0]); 216 217 for (i = 0; i < len / entry_size; i++) 218 { 219 uint64_t auxv_type = elf->ei_class == ELFCLASS32 ? 220 auxv32[2 * i] : auxv64[2 * i]; 221 222 if (auxv_type == 0) 223 break; 224 if (auxv_type != 16) 225 continue; 226 227 if (elf->ei_class == ELFCLASS32) 228 auxv32[2 * i + 1] &= (uint32_t) hwcap_mask; 229 else 230 auxv64[2 * i + 1] &= (uint64_t) hwcap_mask; 231 } 232 } 233 234 /* In the note segment starting at OFFSET with size LEN, make notes 235 with type NOTE_TYPE unrecognizable by GDB. Also, mask the hwcap 236 field of any auxv notes using the HWCAP_MASK. */ 237 238 static void 239 elfbuf_handle_note_segment (struct elfbuf *elf, size_t offset, size_t len, 240 unsigned note_type, unsigned long hwcap_mask) 241 { 242 size_t pos = 0; 243 244 while (pos + 12 < len) 245 { 246 uint32_t *note = (uint32_t *) (elf->buf + offset + pos); 247 size_t desc_pos = pos + 12 + ((note[0] + 3) & ~3); 248 size_t next_pos = desc_pos + ((note[1] + 3) & ~3); 249 250 if (desc_pos > len || next_pos > len) 251 exit_with_msg ("%s: corrupt notes data", elf->path); 252 253 if (note[2] == note_type) 254 note[2] |= 0xff000000; 255 else if (note[2] == 6 && hwcap_mask != 0) 256 elfbuf_handle_auxv (elf, offset + desc_pos, note[1], 257 hwcap_mask); 258 pos = next_pos; 259 } 260 } 261 262 static void 263 elfbuf_handle_core_notes (struct elfbuf *elf, unsigned note_type, 264 unsigned long hwcap_mask) 265 { 266 unsigned ph_idx; 267 268 if (ELFBUF_EHDR (elf, e_type) != 4) 269 exit_with_msg ("%s: not a core file", elf->path); 270 271 /* Iterate over program headers. */ 272 for (ph_idx = 0; ph_idx != ELFBUF_EHDR (elf, e_phnum); ph_idx++) 273 { 274 size_t offset = ELFBUF_PHDR (elf, ph_idx, p_offset); 275 size_t filesz = ELFBUF_PHDR (elf, ph_idx, p_filesz); 276 277 if (offset > elf->len || filesz > elf->len - offset) 278 exit_with_msg ("%s: unexpected end of data", elf->path); 279 280 /* Deal with NOTE segments only. */ 281 if (ELFBUF_PHDR (elf, ph_idx, p_type) != 4) 282 continue; 283 elfbuf_handle_note_segment (elf, offset, filesz, note_type, 284 hwcap_mask); 285 } 286 } 287 288 int 289 main (int argc, char *argv[]) 290 { 291 unsigned note_type; 292 unsigned long hwcap_mask = 0; 293 struct elfbuf elf; 294 295 if (argc < 4) 296 { 297 abort (); 298 } 299 300 if (sscanf (argv[3], "%u", ¬e_type) != 1) 301 exit_with_msg ("%s: bad command line arguments\n", argv[0]); 302 303 if (argc >= 5) 304 { 305 if (sscanf (argv[4], "%lu", &hwcap_mask) != 1) 306 exit_with_msg ("%s: bad command line arguments\n", argv[0]); 307 } 308 309 elfbuf_init_from_file (&elf, argv[1]); 310 elfbuf_handle_core_notes (&elf, note_type, hwcap_mask); 311 elfbuf_write_to_file (&elf, argv[2]); 312 313 return 0; 314 } 315