1 /* Copyright 2013-2019 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]);