1 /* Copyright (C) 1999-2023 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
18 #include <elf-read-prop.h>
20 /* This code is a heavily simplified version of the readelf program
21 that's part of the current binutils development version. For architectures
22 which need to handle both 32bit and 64bit ELF libraries, this file is
23 included twice for each arch size. */
25 /* check_ptr checks that a pointer is in the mmaped file and doesn't
28 #define check_ptr(ptr) \
31 if ((void *)(ptr) < file_contents \
32 || (void *)(ptr) > (file_contents+file_length)) \
34 error (0, 0, _("file %s is truncated\n"), file_name); \
40 /* Returns 0 if everything is ok, != 0 in case of error. */
42 process_elf_file (const char *file_name, const char *lib, int *flag,
43 unsigned int *isa_level, char **soname, void *file_contents,
47 unsigned int dynamic_addr;
49 char *program_interpreter;
51 ElfW(Ehdr) *elf_header;
52 ElfW(Phdr) *elf_pheader, *segment;
53 ElfW(Dyn) *dynamic_segment, *dyn_entry;
54 char *dynamic_strings;
56 elf_header = (ElfW(Ehdr) *) file_contents;
58 if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
62 if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
63 error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
64 else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
65 error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
67 error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
72 if (elf_header->e_type != ET_DYN)
74 error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
79 /* Get information from elf program header. */
80 elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
81 check_ptr (elf_pheader);
83 /* The library is an elf library. */
84 *flag = FLAG_ELF_LIBC6;
86 /* The default ISA level is 0. */
91 program_interpreter = NULL;
92 for (i = 0, segment = elf_pheader;
93 i < elf_header->e_phnum; i++, segment++)
97 switch (segment->p_type)
101 error (0, 0, _("more than one dynamic segment\n"));
103 dynamic_addr = segment->p_offset;
104 dynamic_size = segment->p_filesz;
108 program_interpreter = (char *) (file_contents + segment->p_offset);
109 check_ptr (program_interpreter);
111 case PT_GNU_PROPERTY:
112 /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes
113 in 32-bit objects and to 8 bytes in 64-bit objects. Skip
114 notes with incorrect alignment. */
115 if (segment->p_align == (__ELF_NATIVE_CLASS / 8))
117 const ElfW(Nhdr) *note = (const void *) (file_contents
118 + segment->p_offset);
119 const ElfW(Addr) size = segment->p_filesz;
120 const ElfW(Addr) align = segment->p_align;
122 const ElfW(Addr) start = (ElfW(Addr)) (uintptr_t) note;
123 unsigned int last_type = 0;
125 while ((ElfW(Addr)) (uintptr_t) (note + 1) - start < size)
127 /* Find the NT_GNU_PROPERTY_TYPE_0 note. */
128 if (note->n_namesz == 4
129 && note->n_type == NT_GNU_PROPERTY_TYPE_0
130 && memcmp (note + 1, "GNU", 4) == 0)
132 /* Check for invalid property. */
133 if (note->n_descsz < 8
134 || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
137 /* Start and end of property array. */
138 unsigned char *ptr = (unsigned char *) (note + 1) + 4;
139 unsigned char *ptr_end = ptr + note->n_descsz;
143 unsigned int type = *(unsigned int *) ptr;
144 unsigned int datasz = *(unsigned int *) (ptr + 4);
146 /* Property type must be in ascending order. */
147 if (type < last_type)
151 if ((ptr + datasz) > ptr_end)
156 /* Target specific property processing.
158 false: Continue processing the properties.
159 true : Stop processing the properties.
161 if (read_gnu_property (isa_level, type,
165 /* Check the next property item. */
166 ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
168 while ((ptr_end - ptr) >= 8);
170 /* Only handle one NT_GNU_PROPERTY_TYPE_0. */
174 note = ((const void *) note
175 + ELF_NOTE_NEXT_OFFSET (note->n_namesz,
189 /* Now we can read the dynamic sections. */
190 if (dynamic_size == 0)
193 dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
194 check_ptr (dynamic_segment);
196 /* Find the string table. */
197 dynamic_strings = NULL;
198 for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
201 check_ptr (dyn_entry);
202 if (dyn_entry->d_tag == DT_STRTAB)
204 /* Find the file offset of the segment containing the dynamic
206 ElfW(Off) loadoff = -1;
207 for (i = 0, segment = elf_pheader;
208 i < elf_header->e_phnum; i++, segment++)
210 if (segment->p_type == PT_LOAD
211 && dyn_entry->d_un.d_val >= segment->p_vaddr
212 && (dyn_entry->d_un.d_val - segment->p_vaddr
213 < segment->p_filesz))
215 loadoff = segment->p_vaddr - segment->p_offset;
219 if (loadoff == (ElfW(Off)) -1)
225 dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val
227 check_ptr (dynamic_strings);
232 if (dynamic_strings == NULL)
235 /* Now read the DT_SONAME entries. */
236 for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
239 if (dyn_entry->d_tag == DT_SONAME)
241 char *name = dynamic_strings + dyn_entry->d_un.d_val;
243 *soname = xstrdup (name);