1 /* Copyright 2013-2014 Free Software Foundation, Inc.
3 This file is part of GDB.
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.
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.
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/>. */
26 unsigned char e_ident[16];
44 unsigned char e_ident[16];
89 enum { ELFCLASS32 = 1,
90 ELFCLASS64 = 2 } ei_class;
93 #define ELFBUF_EHDR_LEN(elf) \
94 ((elf)->ei_class == ELFCLASS32 ? sizeof (Elf32_Ehdr) : \
97 #define ELFBUF_EHDR(elf, memb) \
98 ((elf)->ei_class == ELFCLASS32 ? \
99 ((Elf32_Ehdr *) (elf)->buf)->memb \
100 : ((Elf64_Ehdr *) (elf)->buf)->memb)
102 #define ELFBUF_PHDR_LEN(elf) \
103 ((elf)->ei_class == ELFCLASS32 ? sizeof (Elf32_Phdr) : \
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)
114 exit_with_msg(const char *fmt, ...)
120 vfprintf (stderr, fmt, ap);
125 fputs (": ", stderr);
129 fputc ('\n', stderr);
134 read_file (unsigned char **buf_ptr, size_t *len_ptr, FILE *fp)
139 unsigned char *buf = malloc (size);
141 while ((chunk = fread (buf + len, 1, size - len, fp)) == size - len)
145 buf = realloc (buf, size);
153 write_file (unsigned char *buf, size_t len, FILE *fp)
155 fwrite (buf, 1, len, fp);
159 elfbuf_init_from_file (struct elfbuf *elf, const char *path)
161 FILE *fp = fopen (path, "rb");
166 exit_with_msg ("%s", path);
168 read_file (&buf, &len, fp);
171 /* Validate ELF identification. */
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);
180 elf->ei_class = buf[4];
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);
188 if (ELFBUF_EHDR (elf, e_phentsize) != ELFBUF_PHDR_LEN (elf))
189 exit_with_msg ("%s: inconsistent ELF header", path);
193 elfbuf_write_to_file (struct elfbuf *elf, const char *path)
195 FILE *fp = fopen (path, "wb");
198 exit_with_msg ("%s", path);
200 write_file (elf->buf, elf->len, fp);
204 /* In the auxv note starting at OFFSET with size LEN, mask the hwcap
205 field using the HWCAP_MASK. */
208 elfbuf_handle_auxv (struct elfbuf *elf, size_t offset, size_t len,
209 unsigned long hwcap_mask)
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]);
217 for (i = 0; i < len / entry_size; i++)
219 uint64_t auxv_type = elf->ei_class == ELFCLASS32 ?
220 auxv32[2 * i] : auxv64[2 * i];
227 if (elf->ei_class == ELFCLASS32)
228 auxv32[2 * i + 1] &= (uint32_t) hwcap_mask;
230 auxv64[2 * i + 1] &= (uint64_t) hwcap_mask;
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. */
239 elfbuf_handle_note_segment (struct elfbuf *elf, size_t offset, size_t len,
240 unsigned note_type, unsigned long hwcap_mask)
244 while (pos + 12 < len)
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);
250 if (desc_pos > len || next_pos > len)
251 exit_with_msg ("%s: corrupt notes data", elf->path);
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],
263 elfbuf_handle_core_notes (struct elfbuf *elf, unsigned note_type,
264 unsigned long hwcap_mask)
268 if (ELFBUF_EHDR (elf, e_type) != 4)
269 exit_with_msg ("%s: not a core file", elf->path);
271 /* Iterate over program headers. */
272 for (ph_idx = 0; ph_idx != ELFBUF_EHDR (elf, e_phnum); ph_idx++)
274 size_t offset = ELFBUF_PHDR (elf, ph_idx, p_offset);
275 size_t filesz = ELFBUF_PHDR (elf, ph_idx, p_filesz);
277 if (offset > elf->len || filesz > elf->len - offset)
278 exit_with_msg ("%s: unexpected end of data", elf->path);
280 /* Deal with NOTE segments only. */
281 if (ELFBUF_PHDR (elf, ph_idx, p_type) != 4)
283 elfbuf_handle_note_segment (elf, offset, filesz, note_type,
289 main (int argc, char *argv[])
292 unsigned long hwcap_mask = 0;
300 if (sscanf (argv[3], "%u", ¬e_type) != 1)
301 exit_with_msg ("%s: bad command line arguments\n", argv[0]);
305 if (sscanf (argv[4], "%lu", &hwcap_mask) != 1)
306 exit_with_msg ("%s: bad command line arguments\n", argv[0]);
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]);